Skip to content

Commit

Permalink
fix: prevent __proto__ assignment via implicit string
Browse files Browse the repository at this point in the history
  • Loading branch information
lukeed committed Sep 9, 2024
1 parent 48f14a1 commit 16d6154
Show file tree
Hide file tree
Showing 4 changed files with 23 additions and 6 deletions.
6 changes: 3 additions & 3 deletions readme.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# dset [![CI](https://github.com/lukeed/dset/workflows/CI/badge.svg?branch=master&event=push)](https://github.com/lukeed/dset/actions) [![codecov](https://badgen.net/codecov/c/github/lukeed/dset)](https://codecov.io/gh/lukeed/dset)

> A tiny (194B) utility for safely writing deep Object values~!
> A tiny (197B) utility for safely writing deep Object values~!
For _accessing_ deep object properties, please see [`dlv`](https://github.com/developit/dlv).

Expand All @@ -17,15 +17,15 @@ $ npm install --save dset
There are two "versions" of `dset` available:

#### `dset`
> **Size (gzip):** 194 bytes<br>
> **Size (gzip):** 197 bytes<br>
> **Availability:** [CommonJS](https://unpkg.com/dset/dist/index.js), [ES Module](https://unpkg.com/dset/dist/index.mjs), [UMD](https://unpkg.com/dset/dist/index.min.js)
```js
import { dset } from 'dset';
```

#### `dset/merge`
> **Size (gzip):** 288 bytes<br>
> **Size (gzip):** 307 bytes<br>
> **Availability:** [CommonJS](https://unpkg.com/dset/merge/index.js), [ES Module](https://unpkg.com/dset/merge/index.mjs), [UMD](https://unpkg.com/dset/merge/index.min.js)
```js
Expand Down
2 changes: 1 addition & 1 deletion src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ export function dset(obj, keys, val) {
keys.split && (keys=keys.split('.'));
var i=0, l=keys.length, t=obj, x, k;
while (i < l) {
k = keys[i++];
k = ''+keys[i++];
if (k === '__proto__' || k === 'constructor' || k === 'prototype') break;
t = t[k] = (i === l) ? val : (typeof(x=t[k])===typeof(keys)) ? x : (keys[i]*0 !== 0 || !!~(''+keys[i]).indexOf('.')) ? {} : [];
}
Expand Down
2 changes: 1 addition & 1 deletion src/merge.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export function dset(obj, keys, val) {
keys.split && (keys=keys.split('.'));
var i=0, l=keys.length, t=obj, x, k;
while (i < l) {
k = keys[i++];
k = ''+keys[i++];
if (k === '__proto__' || k === 'constructor' || k === 'prototype') break;
t = t[k] = (i === l) ? merge(t[k],val) : (typeof(x=t[k])===typeof keys) ? x : (keys[i]*0 !== 0 || !!~(''+keys[i]).indexOf('.')) ? {} : [];
}
Expand Down
19 changes: 18 additions & 1 deletion test/suites/pollution.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,23 @@ export default function (dset) {
assert.is(Object.create(null).hello, undefined);
});

pollution('should protect against ["__proto__"] assignment :: implicit string', () => {
let input = { abc: 123 };
let before = input.__proto__;

dset(input, [['__proto__'], 'polluted'], true);

assert.equal(input.__proto__, before);
assert.equal(input, { abc: 123 });

assert.is({}.polluted, undefined);
assert.is(input.polluted, undefined);
assert.is((new Object).polluted, undefined);
assert.is(Object.create(null).polluted, undefined);
});



pollution('should ignore "prototype" assignment', () => {
let input = { a: 123 };
dset(input, 'a.prototype.hello', 'world');
Expand Down Expand Up @@ -85,7 +102,7 @@ export default function (dset) {
});
});

// Test for CVE-2022-25645 - CWE-1321
// Test for CVE-2022-25645 - CWE-1321
pollution('should ignore JSON.parse crafted object with "__proto__" key', () => {
let a = { b: { c: 1 } };
assert.is(a.polluted, undefined);
Expand Down

0 comments on commit 16d6154

Please sign in to comment.