CVE-2026-47208: vm2 General Sandbox Breakout
CVE-2026-47208 is one of four maximum-severity sandbox escape vulnerabilities disclosed simultaneously in vm2, the Node.js sandbox library used across the npm ecosystem. With a CVSS v3.1 score of 10.0 (Critical), this vulnerability allows attackers to write code that escapes from the vm2 sandbox and executes arbitrary commands on the host system.
Unlike the other three CVEs in this group (CVE-2026-47131, CVE-2026-47137, CVE-2026-47140) which each identify a specific technical vector, CVE-2026-47208 documents a general sandbox breakout condition — an additional escape mechanism not accounted for by any of the prior fixes. All four vulnerabilities are patched together in vm2 version 3.11.4.
Vulnerability Overview
| Attribute | Value |
|---|---|
| CVE ID | CVE-2026-47208 |
| CVSS Score | 10.0 (Critical) |
| Affected Software | vm2 Node.js sandbox — all versions < 3.11.4 |
| Attack Vector | Local (sandboxed code execution) |
| Authentication Required | None |
| Primary Impact | Sandbox breakout and arbitrary host OS command execution |
| Source | NVD / NIST (published 2026-06-12) |
| Fix | Upgrade to vm2 3.11.4 |
The vm2 Sandbox and Its Security Model
vm2 is built on Node.js's built-in vm module (which uses V8 isolates) and adds a JavaScript proxy-based hardening layer intended to:
- Prevent sandboxed code from accessing host-realm objects
- Control which Node.js modules can be
require()d from inside the sandbox - Intercept property access that might leak host-realm references
The security model relies heavily on JavaScript Proxy objects and careful object wrapping to maintain the boundary between sandbox and host realms.
Why vm2 Is Fundamentally Difficult to Harden
CVE-2026-47208 is representative of a deeper challenge: JavaScript-level sandboxing is not a security boundary. The fundamental reason is that JavaScript's language semantics provide numerous legitimate pathways between execution contexts that are difficult to enumerate and block exhaustively:
- Prototype chains traverse the entire JavaScript realm (see CVE-2026-47131)
- Error constructors carry host-realm type references
- Global built-ins can serve as bridges to the host context
- V8 inspector APIs operate across sandbox boundaries by design
- Proxy handler escape can occur when wrapped objects interact with native C++ code
- WeakRef and FinalizationRegistry behaviors can expose GC-time host callbacks
A pure JavaScript sandbox (as vm2 implements) must intercept every such pathway — a task that becomes harder with every new JavaScript or Node.js feature.
Impact Assessment
| Impact Area | Description |
|---|---|
| Arbitrary OS Command Execution | Sandboxed code can run any host OS command with Node.js process privileges |
| Complete Confidentiality Loss | Host filesystem, secrets, environment variables fully accessible |
| Data Integrity | Attacker can write, modify, or delete files on the host |
| Service Availability | process.exit() or resource exhaustion attacks from within sandbox |
| Lateral Movement | Access to host network, credentials, and infrastructure from sandboxed context |
| Multi-tenant Breach | On SaaS platforms, one tenant's sandboxed code can access another's data |
The CVSS 10.0 score reflects:
- Attack Vector: Local (attacker must be able to run code inside the sandbox — but this is precisely the intended use case)
- Attack Complexity: Low
- Privileges Required: None (within the sandbox context)
- User Interaction: None
- All three impact dimensions: High
Who Is Affected
Directly Vulnerable
- Any Node.js application using vm2 < 3.11.4 to execute untrusted code
- Online code execution platforms (REPLs, coding challenges, CTF platforms)
- SaaS platforms supporting user-defined scripts, plugins, or automations
- CI/CD systems executing user-submitted build scripts
- Configuration systems evaluating JavaScript config files from external sources
Check Your Exposure
# Check direct dependency
npm list vm2
# Check all transitive dependencies
npm ls --all vm2
# Audit for known vulnerabilities
npm audit
# Find all uses of vm2 in your codebase
grep -r "require('vm2')\|require(\"vm2\")\|from 'vm2'\|from \"vm2\"" . \
--include="*.js" --include="*.ts" --include="*.mjs"Remediation
Primary Fix: Upgrade to vm2 3.11.4
# npm
npm install vm2@latest
# yarn
yarn upgrade vm2
# pnpm
pnpm update vm2
# Verify the fix
node -e "const {VM}=require('vm2'); console.log('vm2 version:', require('vm2/package.json').version)"If You Cannot Upgrade Immediately
Temporary mitigations (not a replacement for patching):
-
Wrap vm2 in a container — Run the vm2 process in a Docker container with minimal permissions:
FROM node:20-alpine RUN adduser -D sandboxuser USER sandboxuser # Drop all Linux capabilities, use read-only filesystem -
Apply seccomp profile — Restrict syscalls to what the sandbox legitimately needs:
docker run --security-opt seccomp=/path/to/node-sandbox-seccomp.json myimage -
Use Node.js --experimental-permission (Node.js 20+):
node --experimental-permission \ --allow-fs-read=/tmp/safe \ --allow-child-process=false \ your-script.js -
Rate limit and monitor sandbox executions for anomalous behavior (unexpected syscalls, network connections, file access).
Long-Term: Migrate Away from Pure JavaScript Sandboxing
| Alternative | Mechanism | Security Model |
|---|---|---|
| isolated-vm | V8 isolates via C++ addon | True V8 context isolation; no shared prototype chain |
| Deno | Deno runtime with permissions | OS-level permission model; deny by default |
| Firecracker microVMs | Full VM isolation | Hardware-level isolation; highest security |
| WebAssembly (Wasm) | Linear memory, no DOM/Node access | Memory-safe; no native API access by default |
| Worker Threads + Permissions | Node.js 20+ permission model | Built-in allowlist for fs/network/child-process |
The vm2 Security History: A Pattern of Recurring Escapes
vm2 has a well-documented history of sandbox escape CVEs:
| Year | CVE(s) | Description |
|---|---|---|
| 2021 | CVE-2021-23369 | Template injection sandbox escape |
| 2022 | CVE-2022-36067 | Sandbox escape via prototype pollution |
| 2023 | CVE-2023-29017 | RCE via vm.runInNewContext |
| 2023 | CVE-2023-37903 | Nesting + require combination escape |
| 2026 | CVE-2026-47131/37/40/08 | Four simultaneous escapes, patched in 3.11.4 |
This pattern reflects the fundamental difficulty of implementing a JavaScript-level sandbox. Each patch narrows one escape vector; creative attackers find another.
Related CVEs in This Batch
All four patched in vm2 3.11.4 (2026-06-12):
| CVE | Mechanism |
|---|---|
| CVE-2026-47131 | Buffer prototype hijack via __lookupGetter__ + TypeError |
| CVE-2026-47137 | Strict equality bypass on require: false check |
| CVE-2026-47140 | process and inspector/promises missing from builtin denylist |
| CVE-2026-47208 (this advisory) | General sandbox breakout — arbitrary host command execution |
Key Takeaways
- CVE-2026-47208 is the fourth in a batch of CVSS 10.0 vm2 sandbox escapes — all patched in vm2 3.11.4
- JavaScript-level sandboxing is architecturally fragile; these recurring CVEs demonstrate that pure-JS isolation cannot provide strong security guarantees
- Any application using vm2 < 3.11.4 to execute untrusted code should be considered fully compromised in risk modeling
- Upgrade to vm2 3.11.4 immediately, and evaluate whether the workload requires stronger OS-level isolation
- Run
npm auditto catch downstream packages that may bundle a vulnerable vm2 version