CVE-2026-93603: vm2 before 3.12.1 Sandbox Escape RCE via Non-Strict Host Function
vm2 through 3.12.0 (fixed in 3.12.1) does not correctly handle a nullish this receiver in the apply trap of its bridge (lib/bridge.js): when sandboxed code calls a host-provided non-strict (sloppy-mode) function without a receiver — e.g. fn(), a detached method, fn.call(), fn.apply(undefined), Reflect.apply(fn, undefined, []), or fn.bind()() — the undefined receiver is passed straight through to the host call, and V8 substitutes the host realm's global object for this. vm2 then wraps and returns that object to the sandbox, giving sandboxed script a live proxy of the host global. This allows a complete sandbox escape: untrusted script can reach process and execute arbitrary code/commands on the host (for example via process.getBuiltinModule('childprocess').execSync). Exploitation requires that the embedding application expose at least one non-strict host function to the sandbox; strict-mode and ES module host functions are not affected.
Affected Software
Remediation
Recommended actions to resolve this vulnerability, in priority order.
- Upgrade
Upgrade
vm2to a version that resolves this vulnerability.Fixed in 3.12.1 - Upgrade
Upgrade
vm2to a version that resolves this vulnerability.Patch Sandbox Escape RCE via Non-Strict Host Function
Event History
Frequently Asked Questions
Which deployments are actually exposed to this issue?
Deployments using vm2 through 3.12.0 are exposed only if the embedding application makes at least one non-strict, sloppy-mode host function available to sandboxed code. Strict-mode host functions and ES module host functions are not affected.
What must an attacker be able to do to exploit it?
An attacker must be able to run untrusted code in the vm2 sandbox and invoke an exposed non-strict host function without a receiver. This can occur through a direct call, a detached method, call() with no receiver, apply(undefined), Reflect.apply() with undefined, or a bound call.
What is the impact after successful exploitation?
The sandboxed code can obtain a live proxy to the host global object, reach process, and execute arbitrary host code or commands. The described example uses process.getBuiltinModule('child_process').execSync.
How can I assess whether my integration is affected before upgrading?
Review every host function exposed to sandboxed code and determine whether any are non-strict functions. An affected call path exists if sandbox code can invoke one of those functions with an undefined receiver, including via receiver-less or detached invocation patterns.