Skip to content

Commit d3bb6fa

Browse files
committed
fix(security): prevent proto pollution in simple assignment
1 parent a990648 commit d3bb6fa

File tree

2 files changed

+23
-6
lines changed

2 files changed

+23
-6
lines changed

src/index.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -208,9 +208,7 @@ function parseComplexParam(queryParams: Object, keys: (string | number)[], value
208208
let keysLastIndex = keys.length - 1;
209209
for (let j = 0; j <= keysLastIndex; j++) {
210210
let key = keys[j] === '' ? (currentParams as any).length : keys[j];
211-
if (key === '__proto__') {
212-
throw new Error('Prototype pollution detected.');
213-
}
211+
preventPollution(key);
214212
if (j < keysLastIndex) {
215213
// The value has to be an array or a false value
216214
// 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 {
267265
if (keysLastIndex) {
268266
parseComplexParam(queryParams, keys, value);
269267
} else {
268+
preventPollution(key);
270269
queryParams[key] = processScalarParam(queryParams[key], value);
271270
}
272271
} else {
@@ -275,3 +274,9 @@ export function parseQueryString(queryString: string): Object {
275274
}
276275
return queryParams;
277276
}
277+
278+
function preventPollution(key: string) {
279+
if (key === '__proto__') {
280+
throw new Error('Prototype pollution detected.');
281+
}
282+
}

test/path.spec.ts

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -337,8 +337,20 @@ describe('query strings', () => {
337337
});
338338
});
339339

340-
it('does not pollute prototype', () => {
341-
const path1 = '__proto__[asdf]=asdf';
342-
assert.throws(() => parseQueryString(path1), 'Prototype pollution detected');
340+
describe('prototype pollution', () => {
341+
it('does not allow __proto__ in AccessKey assignment: "__proto__[asdf]=asdf"', () => {
342+
const path1 = '__proto__[asdf]=asdf';
343+
assert.throws(() => parseQueryString(path1), 'Prototype pollution detected');
344+
});
345+
346+
it('does not attempt on AccessMember like key that has __proto__: "__proto__.asdf=asdf"', () => {
347+
const path1 = '__proto__.asdf=asdf';
348+
assert.doesNotThrow(() => parseQueryString(path1));
349+
});
350+
351+
it('does not allow __proto__ in simple assignment: "__proto__=x&0[xxx]=xxx"', () => {
352+
const path1 = '__proto__=x&0[xxx]=xxx';
353+
assert.throws(() => parseQueryString(path1), 'Prototype pollution detected');
354+
});
343355
});
344356
});

0 commit comments

Comments
 (0)