diff --git a/src/index.ts b/src/index.ts index 8282def..a88e4b6 100644 --- a/src/index.ts +++ b/src/index.ts @@ -208,9 +208,7 @@ function parseComplexParam(queryParams: Object, keys: (string | number)[], value let keysLastIndex = keys.length - 1; for (let j = 0; j <= keysLastIndex; j++) { let key = keys[j] === '' ? (currentParams as any).length : keys[j]; - if (key === '__proto__') { - throw new Error('Prototype pollution detected.'); - } + preventPollution(key); if (j < keysLastIndex) { // The value has to be an array or a false value // It can happen that the value is no array if the key was repeated with traditional style like `list=1&list[]=2` @@ -267,6 +265,7 @@ export function parseQueryString(queryString: string): Object { if (keysLastIndex) { parseComplexParam(queryParams, keys, value); } else { + preventPollution(key); queryParams[key] = processScalarParam(queryParams[key], value); } } else { @@ -275,3 +274,9 @@ export function parseQueryString(queryString: string): Object { } return queryParams; } + +function preventPollution(key: string) { + if (key === '__proto__') { + throw new Error('Prototype pollution detected.'); + } +} diff --git a/test/path.spec.ts b/test/path.spec.ts index f4ce35d..6cbdf66 100644 --- a/test/path.spec.ts +++ b/test/path.spec.ts @@ -337,8 +337,20 @@ describe('query strings', () => { }); }); - it('does not pollute prototype', () => { - const path1 = '__proto__[asdf]=asdf'; - assert.throws(() => parseQueryString(path1), 'Prototype pollution detected'); + describe('prototype pollution', () => { + it('does not allow __proto__ in AccessKey assignment: "__proto__[asdf]=asdf"', () => { + const path1 = '__proto__[asdf]=asdf'; + assert.throws(() => parseQueryString(path1), 'Prototype pollution detected'); + }); + + it('does not attempt on AccessMember like key that has __proto__: "__proto__.asdf=asdf"', () => { + const path1 = '__proto__.asdf=asdf'; + assert.doesNotThrow(() => parseQueryString(path1)); + }); + + it('does not allow __proto__ in simple assignment: "__proto__=x&0[xxx]=xxx"', () => { + const path1 = '__proto__=x&0[xxx]=xxx'; + assert.throws(() => parseQueryString(path1), 'Prototype pollution detected'); + }); }); });