Skip to content

Commit bb4af12

Browse files
andrewmacheretbrettz9
authored andcommitted
fix(security): Fix eval pollution exploit
1 parent a6505eb commit bb4af12

2 files changed

Lines changed: 25 additions & 2 deletions

File tree

‎src/Safe-Script.js‎

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,11 @@ const BLOCKED_PROTO_PROPERTIES = new Set([
4141
]);
4242

4343
// Every function-constructor variant, along with the invocation helpers which
44-
// could otherwise reach them indirectly, e.g., `Function.call(0, 'code')()`
44+
// could otherwise reach them indirectly, e.g., `Function.call(0, 'code')()`,
45+
// plus whichever BLOCKED_PROTO_PROPERTIES names resolve to an own method on
46+
// Object.prototype (e.g. `__defineGetter__`) - an own-property access on a
47+
// shared prototype (`@.prototype.__defineGetter__`) bypasses the
48+
// inherited-only name check below, so those methods need blocking by value.
4549
/** @type {WeakSet<object>} */
4650
const BLOCKED_FUNCTIONS = new WeakSet([
4751
Function,
@@ -55,7 +59,10 @@ const BLOCKED_FUNCTIONS = new WeakSet([
5559
Function.prototype.apply,
5660
Function.prototype.bind,
5761
Reflect.apply,
58-
Reflect.construct
62+
Reflect.construct,
63+
...[...BLOCKED_PROTO_PROPERTIES]
64+
.map((name) => Reflect.get(Object.prototype, name))
65+
.filter((value) => typeof value === 'function')
5966
]);
6067

6168
/**

‎test/test.safe-eval.js‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,22 @@ checkBuiltInVMAndNodeVM(function (vmType, setBuiltInState) {
354354
);
355355
});
356356

357+
for (const method of [
358+
'__defineGetter__', '__defineSetter__', '__lookupGetter__', '__lookupSetter__'
359+
]) {
360+
it(`prototype pollution via ${method} (own-property bypass)`, () => {
361+
const propName = 'jsonpathSafeEvalPollutionTest';
362+
const arg2 = method.includes('define') ? ', @.prototype.toString' : '';
363+
assert.throws(() => {
364+
const path =
365+
`$[?(@.constructor[( @.prototype.${method}('${propName}'${arg2}) )])]`;
366+
jsonpath({path, json: [{b: 1}]});
367+
}, "Function constructor is disabled");
368+
369+
assert.equal(Object.hasOwn(Object.prototype, propName), false);
370+
});
371+
}
372+
357373
it("async/generator function constructors blocked", () => {
358374
const fnJson = {
359375
a: {

0 commit comments

Comments
 (0)