Skip to content

Commit 87c1f3c

Browse files
Merge commit from fork
* fix: Disallow `__proto__` keys in more circumstances * remove unflatten tests
1 parent a4a37d2 commit 87c1f3c

File tree

4 files changed

+45
-1
lines changed

4 files changed

+45
-1
lines changed

.changeset/cool-icons-jog.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
'devalue': patch
3+
---
4+
5+
fix: reject `__proto__` keys in malformed `Object` wrapper payloads
6+
7+
This validates the `"Object"` parse path and throws when the wrapped value has an own `__proto__` key.

.changeset/green-candles-talk.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
'devalue': patch
3+
---
4+
5+
fix: disallow `__proto__` keys in null-prototype object parsing
6+
7+
This disallows `__proto__` keys in the `"null"` parse path so null-prototype object hydration cannot carry that key through parse/unflatten.

src/parse.js

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,13 @@ export function unflatten(parsed, revivers) {
118118
break;
119119

120120
case 'Object':
121-
hydrated[index] = Object(value[1]);
121+
const object = Object(value[1]);
122+
123+
if (Object.hasOwn(object, '__proto__')) {
124+
throw new Error('Cannot parse an object with a `__proto__` property');
125+
}
126+
127+
hydrated[index] = object;
122128
break;
123129

124130
case 'BigInt':
@@ -129,6 +135,10 @@ export function unflatten(parsed, revivers) {
129135
const obj = Object.create(null);
130136
hydrated[index] = obj;
131137
for (let i = 1; i < value.length; i += 2) {
138+
if (value[i] === '__proto__') {
139+
throw new Error('Cannot parse an object with a `__proto__` property');
140+
}
141+
132142
obj[value[i]] = hydrate(value[i + 1]);
133143
}
134144
break;

test/test.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -836,6 +836,26 @@ const invalid = [
836836
json: '[{"__proto__":1},{}]',
837837
message: 'Cannot parse an object with a `__proto__` property'
838838
},
839+
{
840+
name: 'prototype pollution via null-prototype object',
841+
json: '[["null","__proto__",1],{}]',
842+
message: 'Cannot parse an object with a `__proto__` property'
843+
},
844+
{
845+
name: 'nested prototype pollution via null-prototype object',
846+
json: '[{"data":1},["null","__proto__",2],{"polluted":3},true]',
847+
message: 'Cannot parse an object with a `__proto__` property'
848+
},
849+
{
850+
name: 'prototype pollution via Object wrapper',
851+
json: '[["Object",{"__proto__":1}],{}]',
852+
message: 'Cannot parse an object with a `__proto__` property'
853+
},
854+
{
855+
name: 'nested prototype pollution via Object wrapper',
856+
json: '[{"wrapped":1},["Object",{"__proto__":2}],{}]',
857+
message: 'Cannot parse an object with a `__proto__` property'
858+
},
839859
{
840860
name: 'bad index',
841861
json: '[{"0":1,"toString":"push"},"hello"]',

0 commit comments

Comments
 (0)