VYPR
advisoryPublished May 31, 2026· 1 source

Nine Critical and High-Severity Sandbox Escape CVEs Disclosed in vm2 Node.js Library

Nine vulnerabilities, including three critical sandbox escapes, were disclosed in the vm2 Node.js library on May 29, 2026, with novel attack vectors via WebAssembly JSPI and Promise species.

On May 29, 2026, nine security vulnerabilities in the vm2 Node.js sandbox library were disclosed within a one-hour window, spanning critical sandbox escapes, builtin denylist bypasses, and proxy-trap logic flaws. The batch includes three CVEs rated critical and three rated high, making it one of the most significant disclosure events for the library since the CVE-2023-37903 patch saga. vm2 is widely used to run untrusted JavaScript in isolated environments on Node.js servers, and these flaws collectively demonstrate that the sandbox's security boundaries remain porous across multiple attack surfaces.

Three of the disclosed CVEs carry a critical severity rating and represent direct sandbox escape paths to arbitrary code execution on the host. CVE-2026-47210 exploits a novel vector involving WebAssembly JavaScript Promise Integration (JSPI). On runtimes where WebAssembly.promising and WebAssembly.Suspending are available, a JSPI-backed Promise can reach Promise.prototype.finally() through a species bypass, allowing sandboxed code to escape into the host process. This is the first documented vm2 escape leveraging the JSPI API surface.

CVE-2026-47208 describes a sandbox breakout through the Promise species mechanism. The localPromise constructor in vm2 was changed to call this.then(undefined, eater) for rejected promise handling, but this opened a path for attackers to write code that escapes the sandbox and executes arbitrary commands on the host system. CVE-2026-47131 chains Buffer.call.call({}.__lookupGetter__, Buffer, "__proto__") and Buffer.call.call({}.__lookupSetter__, Buffer, "__proto__") with Node.js's ERR_INVALID_ARG_TYPE Error to obtain the host's TypeError constructor, which then enables full sandbox escape and arbitrary code execution.

CVE-2026-47137 is a direct bypass of the fix for CVE-2023-37903 (GHSA-8hg8-63c5-gwmx). The original patch introduced a check in nodevm.js at line 263 that blocks the combination nesting: true with require: false. However, the check uses strict equality (options.require === false), which is trivially bypassed by simply omitting the require option entirely. When require is undefined, the check passes, and the sandbox can be configured with nesting: true without explicit require restrictions, enabling full remote code execution. This CVE is rated critical.

CVE-2026-47140 (critical) targets the builtin denylist. While vm2 blocks dangerous builtins such as module, worker_threads, cluster, vm, repl, and inspector, the denylist misses process and inspector/promises. Both can be used from sandboxed code to reach host-side execution primitives, bypassing the sandbox entirely. CVE-2026-47139 (high) addresses a bypass of network builtin exclusions. vm2 supports excluding public network builtins (http, https, http2, net, dgram, tls, dns, dns/promises) from the wildcard builtin option. However, Node.js also exposes underscored internal HTTP builtins such as _http_client and _http_server, which are not blocked and can be used to reach the network layer.

CVE-2026-47141 (severity not rated but functionally significant) reveals that NodeVM exposes process-wide observability builtins — diagnostics_channel, async_hooks, and perf_hooks — when allowed through require.builtin. These modules are process-wide, not sandbox-local, meaning sandboxed code can leak host process and HTTP request data. CVE-2026-47209 (high) identifies a flaw in the BaseHandler.set trap in bridge.js (line 1231). The trap ignores the receiver parameter and unconditionally writes to the host target object, enabling host object property injection via the prototype chain. CVE-2026-47135 (high) combines two weaknesses: vm2's Symbol.for override in setup-sandbox.js only intercepts 2 of 9 dangerous Node.js cross-realm symbols, and the bridge's set/defineProperty/deleteProperty traps have no isDangerousCrossRealmSymbol key check.

As of the disclosure date, users of vm2 should treat all versions prior to the forthcoming patched release as vulnerable to one or more of these CVEs. Given the critical severity of multiple escape vectors — especially CVE-2026-47210 (JSPI), CVE-2026-47208 (Promise species), CVE-2026-47140 (process/inspector/promises), and CVE-2026-47137 (patch bypass) — immediate mitigation is essential. Users who cannot immediately patch should consider disabling async support, restricting require.builtin to an empty allowlist, and avoiding the nesting: true configuration entirely.

This disclosure event underscores a recurring theme in sandbox security: each patch creates new surface for bypasses, and the complexity of Node.js's runtime — with its internal modules, Promise mechanics, WebAssembly integration, and Proxy semantics — provides an ever-expanding attack surface. For teams running vm2 in production to isolate untrusted code, this batch of CVEs serves as a stark reminder that sandboxing is not a set-and-forget security control.

Synthesized by Vypr AI