Overview
A critical sandbox escape vulnerability (CVE-2026-47686) has been disclosed in vm2, the widely-used open-source JavaScript sandbox for Node.js. The flaw resides in lib/setup-sandbox.js where the handleException() function correctly sanitizes SuppressedError.error, SuppressedError.suppressed, and AggregateError.errors, but fails to sanitize Error.cause. This oversight allows sandbox-contained code to reach a powerful host-side object — such as process — and break out of the sandbox entirely.
The vulnerability carries a CVSS score of 9.9 (Critical) and was disclosed on August 17, 2026.
Vulnerability Details
| Field | Value |
|---|---|
| CVE ID | CVE-2026-47686 |
| Component | vm2 (lib/setup-sandbox.js) |
| Vulnerability Type | Sandbox Escape |
| CVSS Score | 9.9 (Critical) |
| Attack Vector | Network |
| Privileges Required | None |
| User Interaction | None |
| Fixed In | vm2 3.11.6 |
Technical Analysis
Root Cause
The handleException() function in lib/setup-sandbox.js is responsible for sanitizing error objects before they propagate from inside the sandbox to the host environment. The function strips dangerous properties from several error types:
SuppressedError.error— sanitizedSuppressedError.suppressed— sanitizedAggregateError.errors— sanitizedError.cause— NOT sanitized (the vulnerability)
Since Error.cause was added to the JavaScript language specification as a standard chaining mechanism, any Error (or derived class) can carry a .cause property pointing to another object. The sanitization logic didn't account for this property, leaving a path for sandbox code to carry a host-realm object out through error propagation.
Attack Flow
- Sandbox code deliberately constructs or intercepts an error that carries a host-realm object (such as
process) as its.causevalue. - The error escapes the sandboxed context via
handleException(). handleException()strips expected dangerous properties but passes.causethrough untouched.- The caller (in the host context) now holds a reference to the
processobject obtained from within the sandbox. - The attacker leverages
processaccess to execute arbitrary system commands, read environment variables, or exfiltrate data.
Impact
Full sandbox escape with access to the Node.js process object grants:
- Arbitrary command execution —
process.binding('spawn_sync')or similar internals - Environment variable access — secrets, credentials, API keys
- File system access — read/write any file accessible to the Node.js process
- Network access — establish outbound connections, exfiltrate data
Affected Versions
All versions of vm2 prior to 3.11.6 are vulnerable.
Remediation
Immediate Fix
Update vm2 to version 3.11.6 or later:
npm install vm2@latest
# or
yarn add vm2@latestVerification
Confirm the installed version:
node -e "const {version} = require('vm2/package.json'); console.log(version);"Expected output: 3.11.6 or higher.
If Immediate Update is Not Possible
- Disable vm2 usage on any publicly accessible surface until patched.
- Sandbox at the OS level using Docker containers, seccomp profiles, or gVisor rather than relying solely on vm2.
- Audit all error propagation paths in code that calls vm2-sandboxed functions.
Detection
Check for Suspicious Error Objects
Monitor for errors carrying .cause values referencing host-side objects:
// Defensive wrapper — log if .cause escapes sandbox
const { VM } = require('vm2');
const vm = new VM({
sandbox: {},
eval: false,
wasm: false,
});
try {
vm.run(untrustedCode);
} catch (err) {
if (err.cause && typeof err.cause === 'object') {
console.warn('Potential sandbox escape attempt via Error.cause:', err.cause);
}
throw err;
}SIEM / Log Queries
Look for unexpected process.exit() or child_process.exec() calls originating from Node.js processes hosting vm2:
index=app_logs sourcetype=nodejs
| search message="child_process" OR message="process.binding"
| where host_process="*vm2*"Recommendations
- Update vm2 to 3.11.6+ — highest priority action
- Audit all vm2 call sites in your codebase for error propagation patterns
- Add OS-level sandboxing (Docker, seccomp) as defence-in-depth
- Review error handling — never blindly pass caught errors from sandboxed code into production logic
- Pin vm2 version in
package.jsonand enforce via lock file
Timeline
| Date | Event |
|---|---|
| 2026-08-17 | CVE-2026-47686 published to NVD |
| 2026-08-17 | vm2 3.11.6 released with patch |
| 2026-08-18 | Public advisory issued |