diff --git a/src/nodes/html.ts b/src/nodes/html.ts index f6f4ea7..cda2835 100644 --- a/src/nodes/html.ts +++ b/src/nodes/html.ts @@ -705,10 +705,12 @@ export default class HTMLElement extends Node { } const attrs = {} as RawAttributes; if (this.rawAttrs) { - const re = /([a-zA-Z()[\]#@$.?:][a-zA-Z0-9-._:()[\]#]*)(?:\s*=\s*((?:'[^']*')|(?:"[^"]*")|\S+))?/g; + const re = /([_a-zA-Z()[\]#@$.?:][a-zA-Z0-9-._:()[\]#]*)(?:\s*=\s*((?:'[^']*')|(?:"[^"]*")|\S+))?/g; let match: RegExpExecArray; while ((match = re.exec(this.rawAttrs))) { const key = match[1]; + // Reject `__proto__` to prevent prototype pollution (issue #129) + if (key === '__proto__') continue; let val = match[2] || null; if (val && (val[0] === `'` || val[0] === `"`)) val = val.slice(1, val.length - 1); attrs[key] = attrs[key] || val; diff --git a/test/tests/issues/129.js b/test/tests/issues/129.js index 2be789c..2f63d0b 100755 --- a/test/tests/issues/129.js +++ b/test/tests/issues/129.js @@ -5,6 +5,7 @@ describe('Prototype pollution', () => { it('prevents prototype pollution', () => { const root = parse(''); should(root.firstChild.attributes.polluted).not.be.ok(); - should(root.firstChild.attributes.hasOwnProperty('proto__')).be.ok(); + should(Object.prototype.polluted).not.be.ok(); + should(root.firstChild.attributes.hasOwnProperty('__proto__')).not.be.ok(); }); }); diff --git a/test/tests/issues/206.js b/test/tests/issues/206.js new file mode 100644 index 0000000..3f5a9b7 --- /dev/null +++ b/test/tests/issues/206.js @@ -0,0 +1,18 @@ +const { parse } = require('@test/test-target'); + +// see: https://github.com/taoqf/node-html-parser/issues/206 +describe('attributes starting with an underscore', function () { + it('keeps the leading underscore in the attribute name', function () { + const root = parse('
t
'); + const div = root.firstChild; + div.getAttribute('_foo').should.eql('bar'); + div.getAttribute('_ngcontent-c1').should.eql('x'); + div.toString().should.eql('
t
'); + }); + it('supports the hyperscript "_" attribute', function () { + const root = parse(''); + const button = root.firstChild; + button.getAttribute('_').should.eql('on click toggle .red'); + button.toString().should.eql(''); + }); +});