CVE-2026-92956
vm2 3.10.1 through 3.11.6 Sandbox Escape via WebAssembly.compileStreaming
vm2 versions 3.10.1 through 3.11.6 contain a sandbox escape reachable from a default new VM() sandbox when running on Node.js 26. WebAssembly.compileStreaming and WebAssembly.instantiateStreaming can produce a raw host-realm Promise that rejects with a host-realm error object; by controlling Symbol.species via Promise.prototype.finally, sandbox code receives that raw host error, walks from the host error constructor to the host Function constructor, and recovers the real host process object, gaining host Node.js capabilities (e.g. access to host modules such as fs) in the context of the process running the sandbox. No NodeVM, require permission, host object injection, or otherwise unsafe configuration is required. This is a bypass of the fix for GHSA-6j2x-vhqr-qr7q, which removed the JSPI entry points WebAssembly.promising and WebAssembly.Suspending. The issue is fixed in 3.11.7.
Attack profile
How easy it is to exploit
- Attack vector
- Network
- Complexity
- Low
- Privileges needed
- None
- User interaction
- None
What an attacker can affect
- Confidentiality
- High
- Integrity
- High
- Availability
- High
Exploit likelihood
What each source reports
CVE List Score used
10.0
vm2 3.10.1 through 3.11.6 Sandbox Escape via WebAssembly.compileStreaming
vm2 versions 3.10.1 through 3.11.6 contain a sandbox escape reachable from a default new VM() sandbox when running on Node.js 26. WebAssembly.compileStreaming and WebAssembly.instantiateStreaming can produce a raw host-realm Promise that rejects with a host-realm error object; by controlling Symbol.species via Promise.prototype.finally, sandbox code receives that raw host error, walks from the host error constructor to the host Function constructor, and recovers the real host process object, gaining host Node.js capabilities (e.g. access to host modules such as fs) in the context of the process running the sandbox. No NodeVM, require permission, host object injection, or otherwise unsafe configuration is required. This is a bypass of the fix for GHSA-6j2x-vhqr-qr7q, which removed the JSPI entry points WebAssembly.promising and WebAssembly.Suspending. The issue is fixed in 3.11.7.
- Record
CVE-2026-92956- CVSS 4.0
- 10.0 Critical
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H - CVSS 3.1
- 10.0 Critical
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H - Weakness
- CWE-693
- Updated
- 2026-11-02
EUVDEUVD-2026-81605
10.0
vm2 versions 3.10.1 through 3.11.6 contain a sandbox escape reachable from a default new VM() sandbox when running on Node.js 26. WebAssembly.compileStreaming and WebAssembly.instantiateStreaming can produce a raw host-realm Promise that rejects with a host-realm error object; by controlling Symbol.species via Promise.prototype.finally, sandbox code receives that raw host error, walks from the host error constructor to the host Function constructor, and recovers the real host process object, gaining host Node.js capabilities (e.g. access to host modules such as fs) in the context of the process running the sandbox. No NodeVM, require permission, host object injection, or otherwise unsafe configuration is required. This is a bypass of the fix for GHSA-6j2x-vhqr-qr7q, which removed the JSPI entry points WebAssembly.promising and WebAssembly.Suspending. The issue is fixed in 3.11.7.
- Record
EUVD-2026-81605- CVSS 4.0
- 10.0 Critical
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H - Updated
- 2026-11-02
GitHub AdvisoriesGHSA-538q-xxpg-6h4r
10.0
Duplicate Advisory: vm2 sandbox escape via WebAssembly.compileStreaming Promise species bypass
Duplicate Advisory
This advisory has been withdrawn because it is a duplicate of GHSA-wjwh-qqvp-g4p4. This link is maintained to preserve external references.
Original Description
vm2 versions 3.10.1 through 3.11.6 contain a sandbox escape reachable from a default new VM() sandbox when running on Node.js 26. WebAssembly.compileStreaming and WebAssembly.instantiateStreaming can produce a raw host-realm Promise that rejects with a host-realm error object; by controlling Symbol.species via Promise.prototype.finally, sandbox code receives that raw host error, walks from the host error constructor to the host Function constructor, and recovers the real host process object, gaining host Node.js capabilities (e.g. access to host modules such as fs) in the context of the process running the sandbox. No NodeVM, require permission, host object injection, or otherwise unsafe configuration is required. This is a bypass of the fix for GHSA-6j2x-vhqr-qr7q, which removed the JSPI entry points WebAssembly.promising and WebAssembly.Suspending. The issue is fixed in 3.11.7.
- Record
GHSA-538q-xxpg-6h4r- CVSS 4.0
- 10.0 Critical
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X - CVSS 3.1
- 10.0 Critical
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H - Weakness
- CWE-693
- Updated
- 2026-11-02
GitHub AdvisoriesGHSA-wjwh-qqvp-g4p4
10.0
vm2 sandbox escape via WebAssembly.compileStreaming Promise species bypass
Summary
There is a sandbox escape in vm2 3.11.5 / current HEAD when it is used on Node.js 26. The issue is reachable from a default new VM() sandbox. No NodeVM, require permission, host object injection, or intentionally unsafe configuration is required.
The escape is a patch-bypass of the same security invariant addressed by GHSA-6j2x-vhqr-qr7q. The earlier fix removed the JSPI entry points WebAssembly.promising and WebAssembly.Suspending, because those APIs exposed a Promise path whose host-realm Promise.prototype was not intercepted by vm2's Promise hardening or bridge layer.
The same unsafe class remains reachable through WebAssembly.compileStreaming and WebAssembly.instantiateStreaming. On Node 26, these streaming APIs can produce a raw host-realm Promise path that rejects with a host-realm error. By controlling Symbol.species through Promise.prototype.finally, sandbox code can receive that raw host error object, walk from the host error constructor to the host Function constructor, and recover the real host process object.
The proof of concept demonstrates this by first showing that direct access to process, require, and constructor-based escapes are blocked in the same default VM. It then reaches the host process, verifies that the recovered pid matches the parent Node process, and writes a harmless marker file through host fs.
Impact
This is a sandbox escape. In applications that expose vm2 execution to attacker-controlled JavaScript, the issue can become host code execution in the context of the Node.js process running the sandbox.
This is not remote code execution by default. The remote aspect depends on the embedding application. The accurate framing is:
An attacker who can supply JavaScript to a vm2
VMsandbox on Node 26 can break out of the vm2 boundary and obtain host Node.js capabilities.
This matters for services that use vm2 as a security boundary for untrusted JavaScript, including plugin runners, workflow engines, automation platforms, online code runners, browser-automation sandboxes, and AI-agent or user-script execution environments.
The PoC only writes a marker file under the OS temporary directory. That marker is intentionally harmless. The security impact is not the marker itself; the security impact is that sandbox-controlled code obtains the real host process and host modules after the control case proves those capabilities are normally blocked.
Tested versions and configuration
Tested vm2 3.11.5 at commit 7a1f5100b96f48d34e0fe104ab37c0acc5944f92.
The escape reproduced on Node.js 26.2.0. I also tested the same PoC on Node.js 20.20.2, 22.22.3, and 24.15.0; those versions did not recover the host process through this path.
The test case uses the default VM boundary only:
const { VM } = require('./lib/main');
const vm = new VM({ timeout: 8000 });
vm.run(attackerControlledJavaScript);
No NodeVM was used. The sandbox was not given require, process, fs, child_process, host callbacks, or host objects. The PoC only controls the JavaScript string passed to vm.run().
The version dependency appears to be in the final delivery step: on Node 26 the host-realm rejection from WebAssembly.compileStreaming reaches the attacker-controlled finally/Symbol.species capability, while the same path did not become exploitable in my Node 20/22/24 tests. I would still treat the fix as version-independent: sandbox code should not be able to receive this raw host-Promise path from the WebAssembly streaming APIs at all.
Root cause
The security boundary relies on vm2 keeping Promise objects that are reachable from sandbox code in one of two safe shapes:
- Sandbox-realm Promise. The Promise uses the sandbox's Promise prototype chain, so vm2's Promise hardening can pin species and sanitize callbacks.
- Bridge-proxied host Promise. The Promise is a host object crossing through vm2's membrane, so bridge…
- Record
GHSA-wjwh-qqvp-g4p4- CVSS 3.1
- 10.0 Critical
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H - Weakness
- CWE-693, CWE-913
- Updated
- 2026-11-02
NVD
10.0
vm2 versions 3.10.1 through 3.11.6 contain a sandbox escape reachable from a default new VM() sandbox when running on Node.js 26. WebAssembly.compileStreaming and WebAssembly.instantiateStreaming can produce a raw host-realm Promise that rejects with a host-realm error object; by controlling Symbol.species via Promise.prototype.finally, sandbox code receives that raw host error, walks from the host error constructor to the host Function constructor, and recovers the real host process object, gaining host Node.js capabilities (e.g. access to host modules such as fs) in the context of the process running the sandbox. No NodeVM, require permission, host object injection, or otherwise unsafe configuration is required. This is a bypass of the fix for GHSA-6j2x-vhqr-qr7q, which removed the JSPI entry points WebAssembly.promising and WebAssembly.Suspending. The issue is fixed in 3.11.7.
- Record
CVE-2026-92956- CVSS 4.0
- 10.0 Critical
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X - CVSS 3.1
- 10.0 Critical
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H - Weakness
- CWE-693
- Updated
- 2026-11-02
OSV
10.0
vm2 3.10.1 through 3.11.6 Sandbox Escape via WebAssembly.compileStreaming
vm2 versions 3.10.1 through 3.11.6 contain a sandbox escape reachable from a default new VM() sandbox when running on Node.js 26. WebAssembly.compileStreaming and WebAssembly.instantiateStreaming can produce a raw host-realm Promise that rejects with a host-realm error object; by controlling Symbol.species via Promise.prototype.finally, sandbox code receives that raw host error, walks from the host error constructor to the host Function constructor, and recovers the real host process object, gaining host Node.js capabilities (e.g. access to host modules such as fs) in the context of the process running the sandbox. No NodeVM, require permission, host object injection, or otherwise unsafe configuration is required. This is a bypass of the fix for GHSA-6j2x-vhqr-qr7q, which removed the JSPI entry points WebAssembly.promising and WebAssembly.Suspending. The issue is fixed in 3.11.7.
- Record
CVE-2026-92956- CVSS 4.0
- 10.0 Critical
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H - Weakness
- CWE-693
- Updated
- 2026-11-02
Show 4 moreShow less
OSVGHSA-538q-xxpg-6h4r
10.0
Duplicate Advisory: vm2 sandbox escape via WebAssembly.compileStreaming Promise species bypass
Duplicate Advisory
This advisory has been withdrawn because it is a duplicate of GHSA-wjwh-qqvp-g4p4. This link is maintained to preserve external references.
Original Description
vm2 versions 3.10.1 through 3.11.6 contain a sandbox escape reachable from a default new VM() sandbox when running on Node.js 26. WebAssembly.compileStreaming and WebAssembly.instantiateStreaming can produce a raw host-realm Promise that rejects with a host-realm error object; by controlling Symbol.species via Promise.prototype.finally, sandbox code receives that raw host error, walks from the host error constructor to the host Function constructor, and recovers the real host process object, gaining host Node.js capabilities (e.g. access to host modules such as fs) in the context of the process running the sandbox. No NodeVM, require permission, host object injection, or otherwise unsafe configuration is required. This is a bypass of the fix for GHSA-6j2x-vhqr-qr7q, which removed the JSPI entry points WebAssembly.promising and WebAssembly.Suspending. The issue is fixed in 3.11.7.
- Record
GHSA-538q-xxpg-6h4r- CVSS 4.0
- 10.0 Critical
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X - CVSS 3.1
- 10.0 Critical
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H - Weakness
- CWE-693
- Updated
- 2026-11-02
OSVGHSA-wjwh-qqvp-g4p4
10.0
vm2 sandbox escape via WebAssembly.compileStreaming Promise species bypass
Summary
There is a sandbox escape in vm2 3.11.5 / current HEAD when it is used on Node.js 26. The issue is reachable from a default new VM() sandbox. No NodeVM, require permission, host object injection, or intentionally unsafe configuration is required.
The escape is a patch-bypass of the same security invariant addressed by GHSA-6j2x-vhqr-qr7q. The earlier fix removed the JSPI entry points WebAssembly.promising and WebAssembly.Suspending, because those APIs exposed a Promise path whose host-realm Promise.prototype was not intercepted by vm2's Promise hardening or bridge layer.
The same unsafe class remains reachable through WebAssembly.compileStreaming and WebAssembly.instantiateStreaming. On Node 26, these streaming APIs can produce a raw host-realm Promise path that rejects with a host-realm error. By controlling Symbol.species through Promise.prototype.finally, sandbox code can receive that raw host error object, walk from the host error constructor to the host Function constructor, and recover the real host process object.
The proof of concept demonstrates this by first showing that direct access to process, require, and constructor-based escapes are blocked in the same default VM. It then reaches the host process, verifies that the recovered pid matches the parent Node process, and writes a harmless marker file through host fs.
Impact
This is a sandbox escape. In applications that expose vm2 execution to attacker-controlled JavaScript, the issue can become host code execution in the context of the Node.js process running the sandbox.
This is not remote code execution by default. The remote aspect depends on the embedding application. The accurate framing is:
An attacker who can supply JavaScript to a vm2
VMsandbox on Node 26 can break out of the vm2 boundary and obtain host Node.js capabilities.
This matters for services that use vm2 as a security boundary for untrusted JavaScript, including plugin runners, workflow engines, automation platforms, online code runners, browser-automation sandboxes, and AI-agent or user-script execution environments.
The PoC only writes a marker file under the OS temporary directory. That marker is intentionally harmless. The security impact is not the marker itself; the security impact is that sandbox-controlled code obtains the real host process and host modules after the control case proves those capabilities are normally blocked.
Tested versions and configuration
Tested vm2 3.11.5 at commit 7a1f5100b96f48d34e0fe104ab37c0acc5944f92.
The escape reproduced on Node.js 26.2.0. I also tested the same PoC on Node.js 20.20.2, 22.22.3, and 24.15.0; those versions did not recover the host process through this path.
The test case uses the default VM boundary only:
const { VM } = require('./lib/main');
const vm = new VM({ timeout: 8000 });
vm.run(attackerControlledJavaScript);
No NodeVM was used. The sandbox was not given require, process, fs, child_process, host callbacks, or host objects. The PoC only controls the JavaScript string passed to vm.run().
The version dependency appears to be in the final delivery step: on Node 26 the host-realm rejection from WebAssembly.compileStreaming reaches the attacker-controlled finally/Symbol.species capability, while the same path did not become exploitable in my Node 20/22/24 tests. I would still treat the fix as version-independent: sandbox code should not be able to receive this raw host-Promise path from the WebAssembly streaming APIs at all.
Root cause
The security boundary relies on vm2 keeping Promise objects that are reachable from sandbox code in one of two safe shapes:
- Sandbox-realm Promise. The Promise uses the sandbox's Promise prototype chain, so vm2's Promise hardening can pin species and sanitize callbacks.
- Bridge-proxied host Promise. The Promise is a host object crossing through vm2's membrane, so bridge…
- Record
GHSA-wjwh-qqvp-g4p4- CVSS 3.1
- 10.0 Critical
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H - Weakness
- CWE-693, CWE-913
- Updated
- 2026-11-02
OSVCLSA-2026-1791278844 No score
TuxCare security update for vm2 (5 CVEs)
TuxCare rebuilt vm2 to address 5 CVEs. Fixed in 3.11.5-tuxcare.4.
- Record
CLSA-2026-1791278844- Updated
- 2026-11-02
OSVROOT-APP-NPM-CVE-2026-92956 No score
CVE-2026-92956 in vm2 - Patched by Root
Root has patched CVE-2026-92956 in the vm2 package for Root:npm. Multiple fixed versions available.
- Record
ROOT-APP-NPM-CVE-2026-92956- Updated
- 2026-11-02
Affected products
Affected packages
| Package | Affected | Fixed |
|---|---|---|
vm2npm |
3.10.1 to 3.11.6 | 3.11.7 |
vm2TuxCare:npm From an advisory covering 5 CVEs |
3.11.5-tuxcare.0 up to 3.11.5-tuxcare.4, plus listed versions 3.11.53.11.5-tuxcare.13.11.5-tuxcare.23.11.5-tuxcare.3 |
3.11.5-tuxcare.4 |
vm2npm |
3.10.1 up to 3.11.7 | 3.11.7 |
vm2Root:npm |
before 3.11.6-aikido.1 | 3.11.6-aikido.1 |
@rootio/vm2Root:npm |
before 3.11.6-root.io.1 | 3.11.6-root.io.1 |
Public exploits
Links only. Every CVE stores no exploit code.
| Source | Link | Date |
|---|---|---|
| PoC in GitHub | AraxyAI/CVE-2026-92956__vm2__test__20261012 | 2026-10-12 |
History
| Recorded | Changed | Sources |
|---|---|---|
| affected, facts | ||
| affected | ||
| first indexed | CVE List, EUVD, GitHub Advisories, NVD, OSV, PoC in GitHub |
Dates are when Every CVE recorded each change. Upstream dates may differ.
In short
CVE-2026-92956 is a critical vulnerability (CVSS 10.0) in Patriksimek Vm2, published September 17, 2026. Public exploit code exists. EPSS puts the chance of exploitation in the next 30 days at 0.51%, the 43rd percentile. Fixed in vm2 3.11.7.
References
github.com/patriksimek/vm2/security/advisories/GHSA-wjwh-qqvp-g4p4
vulncheck.com/advisories/vm2-3.10.1-through-3.11.6-sandbox-escape-via-webassembly-compilestreaming
nvd.nist.gov/vuln/detail/CVE-2026-92956
github.com/advisories/GHSA-538q-xxpg-6h4r
github.com/patriksimek/vm2/commit/cb85599e4470afa308e7c807b5c6b3ec9bf58b18
github.com/patriksimek/vm2/blob/415339f698f0d52d3c5ad358b12b79c8072d5b4b/lib/setup-sandbox.js
Left out here: the rest of 2 source descriptions. The JSON record has them.