Skip to content

Commit 7895b94

Browse files
jportnerljharb
authored andcommitted
[Fix] parse: Fix parsing when the global Object prototype is frozen
1 parent 9dca37f commit 7895b94

3 files changed

Lines changed: 39 additions & 3 deletions

File tree

lib/parse.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,8 @@ var isoSentinel = 'utf8=%26%2310003%3B'; // encodeURIComponent('✓')
4949
var charsetSentinel = 'utf8=%E2%9C%93'; // encodeURIComponent('✓')
5050

5151
var parseValues = function parseQueryStringValues(str, options) {
52-
var obj = {};
52+
var obj = { __proto__: null };
53+
5354
var cleanStr = options.ignoreQueryPrefix ? str.replace(/^\?/, '') : str;
5455
var limit = options.parameterLimit === Infinity ? undefined : options.parameterLimit;
5556
var parts = cleanStr.split(options.delimiter, limit);

package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,13 @@
4040
"eslint": "=8.8.0",
4141
"evalmd": "^0.0.19",
4242
"for-each": "^0.3.3",
43+
"has-override-mistake": "^1.0.0",
44+
"has-property-descriptors": "^1.0.0",
4345
"has-symbols": "^1.0.3",
4446
"iconv-lite": "^0.5.1",
4547
"in-publish": "^2.0.1",
4648
"mkdirp": "^0.5.5",
49+
"mock-property": "^1.0.0",
4750
"npmignore": "^0.3.0",
4851
"nyc": "^10.3.2",
4952
"object-inspect": "^1.12.3",

test/parse.js

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
'use strict';
22

33
var test = require('tape');
4-
var qs = require('../');
5-
var utils = require('../lib/utils');
4+
var hasPropertyDescriptors = require('has-property-descriptors')();
65
var iconv = require('iconv-lite');
6+
var mockProperty = require('mock-property');
7+
var hasOverrideMistake = require('has-override-mistake')();
78
var SaferBuffer = require('safer-buffer').Buffer;
89

10+
var qs = require('../');
11+
var utils = require('../lib/utils');
12+
913
test('parse()', function (t) {
1014
t.test('parses a simple string', function (st) {
1115
st.deepEqual(qs.parse('0=foo'), { 0: 'foo' });
@@ -601,6 +605,34 @@ test('parse()', function (t) {
601605
st.end();
602606
});
603607

608+
t.test('does not crash when the global Object prototype is frozen', { skip: !hasPropertyDescriptors || !hasOverrideMistake }, function (st) {
609+
// We can't actually freeze the global Object prototype as that will interfere with other tests, and once an object is frozen, it
610+
// can't be unfrozen. Instead, we add a new non-writable property to simulate this.
611+
st.teardown(mockProperty(Object.prototype, 'frozenProp', { value: 'foo', nonWritable: true, nonEnumerable: true }));
612+
613+
st['throws'](
614+
function () {
615+
var obj = {};
616+
obj.frozenProp = 'bar';
617+
},
618+
// node < 6 has a different error message
619+
/^TypeError: Cannot assign to read only property 'frozenProp' of (?:object '#<Object>'|#<Object>)/,
620+
'regular assignment of an inherited non-writable property throws'
621+
);
622+
623+
var parsed;
624+
st.doesNotThrow(
625+
function () {
626+
parsed = qs.parse('frozenProp', { allowPrototypes: false });
627+
},
628+
'parsing a nonwritable Object.prototype property does not throw'
629+
);
630+
631+
st.deepEqual(parsed, {}, 'bare "frozenProp" results in {}');
632+
633+
st.end();
634+
});
635+
604636
t.test('params starting with a closing bracket', function (st) {
605637
st.deepEqual(qs.parse(']=toString'), { ']': 'toString' });
606638
st.deepEqual(qs.parse(']]=toString'), { ']]': 'toString' });

0 commit comments

Comments
 (0)