From 7d3aee1c9c3c842720506e131de7e181e5c8db68 Mon Sep 17 00:00:00 2001 From: Mick Hansen Date: Thu, 8 Jun 2023 16:51:18 +0200 Subject: [PATCH] rudimentary __proto__ guarding --- README.md | 3 +++ dottie.js | 4 ++++ test/set.test.js | 8 ++++++++ test/transform.test.js | 12 ++++++++++++ 4 files changed, 27 insertions(+) diff --git a/README.md b/README.md index 4d3940f..859e680 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,7 @@ dottie.get(values, ['some.dot.included', 'key']); // returns 'barfoo' *Note: lodash.get() also works fine for this* ### Set value + Sets nested value, creates nested structure if needed ```js @@ -42,6 +43,8 @@ dottie.set(values, 'some.nested.object', someValue, { }); ``` +If you accept arbitrary/user-defined paths to `set` you should call `Object.preventExtensions(values)` first to guard against potential pollution. + ### Transform object Transform object from keys with dottie notation to nested objects diff --git a/dottie.js b/dottie.js index e435093..d5aa55b 100644 --- a/dottie.js +++ b/dottie.js @@ -72,6 +72,7 @@ // Set nested value Dottie.set = function(object, path, value, options) { var pieces = Array.isArray(path) ? path : path.split('.'), current = object, piece, length = pieces.length; + if (pieces[0] === '__proto__') return; if (typeof current !== 'object') { throw new Error('Parent is not an object.'); @@ -140,6 +141,9 @@ if (key.indexOf(options.delimiter) !== -1) { pieces = key.split(options.delimiter); + + if (pieces[0] === '__proto__') break; + piecesLength = pieces.length; current = transformed; diff --git a/test/set.test.js b/test/set.test.js index b0a39aa..9b611da 100644 --- a/test/set.test.js +++ b/test/set.test.js @@ -65,4 +65,12 @@ describe("dottie.set", function () { }); expect(data.foo.bar.baz).to.equal('someValue'); }); + + it('should not attempt to set __proto__', function () { + var data = {}; + + dottie.set(data, '__proto__.pollution', 'polluted'); + + expect(data.__proto__.pollution).to.be.undefined; + }); }); \ No newline at end of file diff --git a/test/transform.test.js b/test/transform.test.js index 461b25b..e2fb6dc 100644 --- a/test/transform.test.js +++ b/test/transform.test.js @@ -145,4 +145,16 @@ describe("dottie.transform", function () { expect(transformed.user.location.city).to.equal('Zanzibar City'); expect(transformed.project.title).to.equal('dottie'); }); + + it("should guard against prototype pollution", function () { + var values = { + 'user.name': 'John Doe', + '__proto__.pollution': 'pollution' + }; + + var transformed = dottie.transform(values); + expect(transformed.user).not.to.equal(undefined); + expect(transformed.user.name).to.equal('John Doe'); + expect(transformed.__proto__.pollution).to.be.undefined; + }); });