From 85b59f9f0a6ce43e89fc225a319f2c5ec3eef38a Mon Sep 17 00:00:00 2001 From: Matheus Vrech Date: Mon, 2 May 2022 03:55:26 -0300 Subject: [PATCH] Due to wrong regex shvl is still vulnerable to prototype pollution (#36) * fix regex * adding test cases * filter Object keys instead of paths --- index.js | 6 +++--- test.js | 19 +++++++++++++------ 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/index.js b/index.js index 53e25ee..d6a3c62 100644 --- a/index.js +++ b/index.js @@ -1,11 +1,11 @@ -export function get (object, path, def) { +export function get(object, path, def) { return (object = (path.split ? path.split('.') : path).reduce(function (obj, p) { return obj && obj[p] }, object)) === undefined ? def : object; }; export function set (object, path, val, obj) { - return !/^(__proto__|constructor|prototype)$/.test(path) && ((path = path.split ? path.split('.') : path.slice(0)).slice(0, -1).reduce(function (obj, p) { - return obj[p] = obj[p] || {}; + return ((path = path.split ? path.split('.') : path.slice(0)).slice(0, -1).reduce(function (obj, p) { + return (!/^(__proto__|constructor|prototype)$/.test(p))? obj[p] = obj[p] || {} : {}; }, obj = object)[path.pop()] = val), object; }; diff --git a/test.js b/test.js index f428181..a3d93e4 100644 --- a/test.js +++ b/test.js @@ -73,12 +73,19 @@ cases('set({}, key, value)', ({ obj, key, value, expected }) => { "set(obj, 'a.b.c', 'bar')": { key: 'a.b.c', value: 'bar', expected: { a: { b: { c: 'bar' } } }, obj: { a: { b: { c: 'foo' } } } }, "set(obj, 'a.b', 'foo')": { key: 'a.b', value: 'foo', expected: { a: { b: 'foo' } }, obj: { a: { b: undefined } } }, "set(obj, 'a.b', undefined)": { key: 'a.b', value: undefined, expected: { a: { b: undefined } }, obj: { a: { b: 'foo' } } }, - "set(obj, '__proto__', 'foo')": { key: "__proto__", value: "foo", expected: {} }, - "set(obj, 'a.__proto__', 'foo')": { key: "__proto__", value: "foo", expected: { a: undefined } }, - "set(obj, 'constructor', 'foo')": { key: "constructor", value: "foo", expected: {} }, - "set(obj, 'a.constructor', 'foo')": { key: "constructor", value: "foo", expected: { a: undefined } }, - "set(obj, 'prototype', 'foo')": { key: "prototype", value: "foo", expected: {} }, - "set(obj, 'a.prototype', 'foo')": { key: "prototype", value: "foo", expected: { a: undefined } }, + "set(obj, '___proto___.a', 'foo')": { key: '___proto___.a', value: 'foo', expected: { ___proto___: { a: 'foo' } } }, + "set(obj, 'a.constructorx.b', 'foo')": { key: 'a.constructorx.b', value: 'foo', expected: { a: { constructorx: { b: 'foo' } } } }, +}); + +// prevent prototype pollution +cases('get(Object, key)', ({ key, value, test }) => { + shvl.set({}, key, value); + expect(shvl.get(Object, test || key)).toEqual(undefined); +}, { + "set({}, '__proto__.b', 'foo')": { key: '__proto__.b', value: 'foo' }, + "set({}, 'a.__proto__.b', 'foo')": { key: 'a.__proto__.b', value: 'foo' }, + "set({}, 'constructor.prototype.b', 'foo')": { key: 'constructor.prototype.b', value: 'foo'}, + "set({}, 'a.constructor.prototype.b', 'foo')": { key: 'a.constructor.prototype.b', value: 'foo'} }); cases('set(undefined, key, value)', ({ obj, key, value }) => {