Skip to content

Commit

Permalink
Prevent prototype pollution
Browse files Browse the repository at this point in the history
  • Loading branch information
eivindfjeldstad committed Feb 22, 2020
1 parent 2d9fa82 commit 774e4b0
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 12 deletions.
36 changes: 31 additions & 5 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,21 @@
* @api public
*/

exports.set = function (obj, path, val) {
exports.set = function(obj, path, val) {
var segs = path.split('.');
var attr = segs.pop();
var src = obj;

for (var i = 0; i < segs.length; i++) {
var seg = segs[i];
if (!isSafe(obj, seg)) return src;
obj[seg] = obj[seg] || {};
obj = obj[seg];
}

obj[attr] = val;
if (isSafe(obj, attr)) {
obj[attr] = val;
}

return src;
};
Expand All @@ -33,7 +36,7 @@ exports.set = function (obj, path, val) {
* @api public
*/

exports.get = function (obj, path) {
exports.get = function(obj, path) {
var segs = path.split('.');
var attr = segs.pop();

Expand All @@ -55,19 +58,42 @@ exports.get = function (obj, path) {
* @api public
*/

exports.delete = function (obj, path) {
exports.delete = function(obj, path) {
var segs = path.split('.');
var attr = segs.pop();

for (var i = 0; i < segs.length; i++) {
var seg = segs[i];
if (!obj[seg]) return;
if (!isSafe(obj, seg)) return;
obj = obj[seg];
}

if (!isSafe(obj, attr)) return;

if (Array.isArray(obj)) {
obj.splice(path, 1);
obj.splice(attr, 1);
} else {
delete obj[attr];
}
};

function isSafe(obj, prop) {
if (isObject(obj)) {
return obj[prop] === undefined || hasOwnProperty(obj, prop);
}

if (Array.isArray(obj)) {
return !isNaN(parseInt(prop, 10));
}

return false;
}

function hasOwnProperty(obj, prop) {
return Object.prototype.hasOwnProperty.call(obj, prop);
}

function isObject(obj) {
return Object.prototype.toString.call(obj) === '[object Object]';
}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"publishConfig": {
"access": "public"
},
"version": "1.0.2",
"version": "1.0.3",
"description": "Get and set object properties with dot notation",
"main": "index.js",
"scripts": {
Expand Down
39 changes: 33 additions & 6 deletions test/index.js
Original file line number Diff line number Diff line change
@@ -1,33 +1,60 @@
var assert = require('assert');
var dot = require('..');

var tests = module.exports = {
'test set': function () {
var tests = (module.exports = {
'test set': function() {
var obj = {};
var ret = dot.set(obj, 'cool.aid', 'rocks');
assert(obj.cool.aid === 'rocks');
assert(obj === ret);
},

'test get': function () {
'test get': function() {
var obj = {};
obj.cool = {};
obj.cool.aid = 'rocks';
var value = dot.get(obj, 'cool.aid');
assert(value === 'rocks');
},

'test delete': function () {
'test delete': function() {
var obj = {};
obj.cool = {};
obj.cool.aid = 'rocks';
obj.cool.hello = ['world'];
dot.delete(obj, 'cool.aid');
dot.delete(obj, 'cool.hello.0');
assert(!obj.cool.hasOwnProperty('aid'))
assert(!obj.cool.hasOwnProperty('aid'));
assert(obj.cool.hello.length == 0);
},

'test prototype pollution': function() {
var obj = {};
obj.cool = {};
obj.cool.aid = 'rocks';
obj.cool.hello = ['world'];
dot.set(obj, '__proto__', 'test');
dot.set(obj, '__proto__.toString', 'test');
dot.set(obj, 'toString', 'test');
dot.set(obj, 'cool.hello.__proto__', 'test');
dot.set(obj, 'cool.hello.__proto__.toString', 'test');
dot.set(obj, 'cool.hello.toString', 'test');
assert(obj.__proto__ === {}.__proto__);
assert(obj.toString === Object.prototype.toString);
assert(obj.cool.hello.__proto__ === [].__proto__);
assert(obj.cool.hello.toString === Array.prototype.toString);
dot.delete(obj, '__proto__.toString', 'test');
dot.delete(obj, '__proto__', 'test');
dot.delete(obj, 'toString', 'test');
dot.delete(obj, 'cool.hello.__proto__.toString', 'test');
dot.delete(obj, 'cool.hello.__proto__', 'test');
dot.delete(obj, 'cool.hello.toString', 'test');
assert(obj.__proto__ === {}.__proto__);
assert(obj.toString === Object.prototype.toString);
assert(obj.cool.hello.__proto__ === [].__proto__);
assert(obj.cool.hello.toString === Array.prototype.toString);
}
}
});

for (var t in tests) {
tests[t]();
Expand Down

0 comments on commit 774e4b0

Please # to comment.