Skip to content

Commit c77b9d2

Browse files
committed
fix: prototype pollution vulnerability + working tests
1 parent 49031e4 commit c77b9d2

File tree

3 files changed

+41
-5
lines changed

3 files changed

+41
-5
lines changed

index.js

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
'use strict';
22

3-
43
/* !
54
* Chai - pathval utility
65
* Copyright(c) 2012-2014 Jake Luer <jake@alogicalparadox.com>
@@ -77,6 +76,13 @@ function parsePath(path) {
7776
var str = path.replace(/([^\\])\[/g, '$1.[');
7877
var parts = str.match(/(\\\.|[^.]+?)+/g);
7978
return parts.map(function mapMatches(value) {
79+
if (
80+
value === 'constructor' ||
81+
value === '__proto__' ||
82+
value === 'prototype'
83+
) {
84+
return {};
85+
}
8086
var regexp = /^\[(\d+)\]$/;
8187
var mArr = regexp.exec(value);
8288
var parsed = null;
@@ -108,7 +114,7 @@ function parsePath(path) {
108114
function internalGetPathValue(obj, parsed, pathDepth) {
109115
var temporaryValue = obj;
110116
var res = null;
111-
pathDepth = (typeof pathDepth === 'undefined' ? parsed.length : pathDepth);
117+
pathDepth = typeof pathDepth === 'undefined' ? parsed.length : pathDepth;
112118

113119
for (var i = 0; i < pathDepth; i++) {
114120
var part = parsed[i];
@@ -119,7 +125,7 @@ function internalGetPathValue(obj, parsed, pathDepth) {
119125
temporaryValue = temporaryValue[part.p];
120126
}
121127

122-
if (i === (pathDepth - 1)) {
128+
if (i === pathDepth - 1) {
123129
res = temporaryValue;
124130
}
125131
}
@@ -153,7 +159,7 @@ function internalSetPathValue(obj, val, parsed) {
153159
part = parsed[i];
154160

155161
// If it's the last part of the path, we set the 'propName' value with the property name
156-
if (i === (pathDepth - 1)) {
162+
if (i === pathDepth - 1) {
157163
propName = typeof part.p === 'undefined' ? part.i : part.p;
158164
// Now we set the property with the name held by 'propName' on object with the desired val
159165
tempObj[propName] = val;
@@ -200,7 +206,10 @@ function getPathInfo(obj, path) {
200206
var parsed = parsePath(path);
201207
var last = parsed[parsed.length - 1];
202208
var info = {
203-
parent: parsed.length > 1 ? internalGetPathValue(obj, parsed, parsed.length - 1) : obj,
209+
parent:
210+
parsed.length > 1 ?
211+
internalGetPathValue(obj, parsed, parsed.length - 1) :
212+
obj,
204213
name: last.p || last.i,
205214
value: internalGetPathValue(obj, parsed),
206215
};

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
"scripts": {
2222
"build": "browserify --standalone pathval -o pathval.js",
2323
"lint": "eslint --ignore-path .gitignore .",
24+
"lint:fix": "npm run lint -- --fix",
2425
"prepublish": "npm run build",
2526
"semantic-release": "semantic-release pre && npm publish && semantic-release post",
2627
"pretest": "npm run lint",

test/index.js

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,4 +218,30 @@ describe('setPathValue', function () {
218218
var valueReturned = pathval.setPathValue(obj, 'hello[2]', 3);
219219
assert(obj === valueReturned);
220220
});
221+
222+
describe('fix prototype pollution vulnerability', function () {
223+
224+
it('exclude constructor', function () {
225+
var obj = {};
226+
assert(typeof obj.constructor === 'function'); // eslint-disable-line
227+
pathval.setPathValue(obj, 'constructor', null);
228+
assert(typeof obj.constructor === 'function'); // eslint-disable-line
229+
});
230+
231+
it('exclude __proto__', function () {
232+
var obj = {};
233+
assert(typeof polluted === 'undefined'); // eslint-disable-line
234+
pathval.setPathValue(obj, '__proto__.polluted', true);
235+
assert(typeof polluted === 'undefined'); // eslint-disable-line
236+
});
237+
238+
it('exclude prototype', function () {
239+
var obj = {};
240+
assert(typeof obj.prototype === 'undefined'); // eslint-disable-line
241+
pathval.setPathValue(obj, 'prototype', true);
242+
assert(typeof obj.prototype === 'undefined'); // eslint-disable-line
243+
});
244+
245+
});
246+
221247
});

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy