Attack ChainAIDerived
Hypothetical attack flow derived from CVE metadata – not a confirmed exploit chain
-
AccessSubmit untrusted JS to vm2 NodeVM
-
Deliveryrequire('node:node:test') resolves host node:test proxy
-
ExploitCall node:test.run() with execArgv --eval=<JS>
-
ExecutionHost spawns unrestricted Node child process
-
ImpactArbitrary code execution outside sandbox
Vulnerability Assessment
| Weakness |
CWE
OWASP Top 10:2025
A06:2025 - Insecure Design
ASVS 5.0
V15 - Secure Coding and Architecture Protection mechanism completeness
|
| Exploitation Conditions | Requires ALL of: (1) the target runs vm2 NodeVM executing untrusted attacker-supplied JavaScript (the vm2 threat model - this is the 'authentication' PR:L represents); (2) the Node.js runtime is version 24 or newer, since only there does module.builtinModules expose the scheme-only 'node:test' key; and (3) the embedder has explicitly enabled the non-default configuration require:{builtin:['node:test']}, which is not a default allowlist. Given those, no user interaction and no further authentication are needed. Limiting factors that reduce realistic exposure: older Node versions are not vulnerable, and applications that do not explicitly allow node:test (the vast majority) are unaffected regardless of Node version. |
| Impact | This is a genuine full sandbox-escape to arbitrary code execution on the host Node process, but its real-world reachability is meaningfully constrained by two hard prerequisites, so it should not be treated as a drop-everything remote-RCE. The vendor CVSS 4.0 vector (AV:N/AC:L/AT:N/PR:L/UI:N with VC:H/VI:H/VA:H and subsequent-system SC:H/SI:H/SA:H = 9.4) reflects the fact that once triggered the attacker fully compromises the host outside the sandbox. However, the description makes clear two limiting gates the vector does not capture: (1) the runtime must be Node.js 24 or newer (older Node does not expose the scheme-only node:test key), and (2) the embedder must explicitly opt into an unusual, non-default configuration that allowlists node:test (require:{builtin:['node:test']}). The PR:L in the vendor vector is best read as the vm2 threat model itself - the attacker is the untrusted JavaScript vm2 is deliberately running - rather than a network authentication credential. No EPSS score, no CISA KEV listing, and no explicitly flagged public exploit are present in the supplied data (a working advisory write-up likely exists in GHSA-qhwx-74w5-xhxq but is not confirmed as weaponized). Net: technically critical impact, real priority for anyone running the exact affected stack, but gated enough (Node 24+ AND a deliberate node:test allowlist AND already accepting untrusted code) that it is not indiscriminately mass-exploitable. Note also that the '3.11.7 fixed' claim sits oddly against the real-world vm2 history (project deprecated in 2023, last widely-known release ~3.9.19) - worth verifying versioning independently. |
| Exploit ScenarioDerived | An application uses vm2's NodeVM on Node.js 24+ to run untrusted user-supplied JavaScript and, unusually, allows the node:test builtin via require:{builtin:['node:test']}. Sandboxed code calls require('node:node:test'), whose double 'node:' prefix is stripped once and resolves to the host node:test proxy; it then invokes node:test.run() with attacker-controlled execArgv containing --eval=<JavaScript>, which the host spawns in a fresh, unrestricted Node process, executing arbitrary code fully outside the sandbox. No public exploit is confirmed in the provided data, though a technical advisory (GHSA-qhwx-74w5-xhxq) likely documents the primitive. |
Get an e-mail when this CVE is exploited, patched or re-scored. Free account.
Alert meAnalysisAIv1 – Sep 17, 2026
Sandbox escape in vm2 3.9.6 through 3.11.6 lets attacker-supplied JavaScript running inside a NodeVM break out and execute arbitrary code in the host Node.js process when three conditions line up: the host runs Node.js 24 or newer, the embedder has explicitly allowlisted the node:test builtin, and the sandboxed code is under attacker control. The bypass exists because vm2's family-based DANGEROUS_BUILTINS check does not recognise Node.js 24's scheme-only 'node:test' key, so the module is placed in the generic host-passthrough loader, and a single 'node:' prefix strip in requireImpl() means require('node:node:test') resolves to that stored key; forwarded node:test.run() calls reach the host implementation, which spawns a separate Node process and honours attacker-supplied execArgv values such as --eval=<JavaScript>. Vendor severity is 9.4 (CVSS 4.0) and our independent assessment scores it CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H, a genuine full sandbox escape to host code execution whose real-world reachability is constrained by the hard Node.js 24+ and non-default node:test allowlist prerequisites; no public exploit identified at time of analysis. Fixed in vm2 3.11.7.
RemediationAI
Upgrade vm2 to 3.11.7, the version in which the bypass is fixed, and validate the change against any NodeVM configuration that references builtins; see the vendor advisory at https://github.com/patriksimek/vm2/security/advisories/GHSA-qhwx-74w5-xhxq for the official guidance. If an immediate upgrade is not possible, the most effective and lowest-cost mitigation is to remove 'node:test' from any require.builtin allowlist so the sandboxed require never reaches the passthrough loader - this fully eliminates the reachable path, with the trade-off that sandboxed code loses legitimately intended access to the node:test module, which is rarely required in a sandbox context. A second option is to keep the host runtime on Node.js 20/22 LTS, where module.builtinModules does not expose the scheme-only 'node:test' key and the flaw is not triggerable, at the cost of forgoing Node.js 24 features and creating version drift. Because a successful escape yields code execution in the host Node process rather than inside the sandbox, harden the host as a compensating control: run the embedding process as a non-root user under a container or OS sandbox with seccomp/apparmor restrictions, drop unnecessary capabilities, and constrain outbound network access, so a breakout does not immediately translate into broader system or lateral compromise. Where the application depends on node:test.run or similar host-spawning helpers, consider blocking or wrapping child-process spawning and refusing caller-controlled execArgv values as a defence-in-depth measure, and monitor for unexpected node child processes or --eval arguments leaving the host application.
Affected VersionsENISA
Affected Packages
Source: OSV (Open Source Vulnerabilities)
Affects your stack
Affects 1 package in npm
Checking this CVE against your own stacks and servers is part of the Basic plan and up.
Technical ContextAI · show details
This is a protection-mechanism failure (CWE-693) in vm2's NodeVM module-loading pipeline rather than a memory-safety or injection bug. vm2 classifies builtins through a family-based allow/deny list (DANGEROUS_BUILTINS) and routes anything it does not recognise into a generic host-passthrough loader; the design assumption was that every enumerable entry in module.builtinModules is a normal family name such as 'fs' or 'node:fs'. Node.js 24 changed that surface by exposing the scheme-only key 'node:test', which matches no family and therefore slips past the deny list and into passthrough. requireImpl() in lib/setup-node-sandbox.js then strips exactly one leading 'node:' prefix before the builtin lookup, so sandbox code calling require('node:node:test') collapses to the stored 'node:test' key and receives a readonly proxy to the host's node:test module. The proxy is not a meaningful restriction for this primitive: invoking node:test.run() is forwarded to the host implementation, which launches a fresh Node process for process-isolated test execution and passes through caller-controlled execArgv, so an argument such as --eval=<JavaScript> runs arbitrary JavaScript in an unrestricted host Node process entirely outside the NodeVM sandbox. Effective exploitation is gated on Node.js 24+ (older runtimes do not expose the scheme-only key in builtinModules) and on the embedder explicitly configuring require:{builtin:['node:test']}, which is not part of any default configuration; sandboxed context carrying the attacker's JavaScript is the other prerequisite, consistent with our assessed CVSS 3.1 vector of AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H.
Know when Vm2 gets its next vulnerability
- Watch products and get an email when something new is published
- Check this CVE against your own stack and servers
- Exploit and PoC references, threat intelligence from 22 sources
No credit card · 7-day full trial
Severity by source
CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H
Sandboxed untrusted code (PR:L) escapes to full host RCE crossing the sandbox boundary (S:C, C/I/A:H); AC:L once the required Node 24+ and node:test allowlist conditions are met.
Primary rating from Vendor (VulnCheck).
CVSS VectorVendor: VulnCheck
Lifecycle Timeline
2DescriptionCVE.org
vm2 versions >= 3.9.6 and <= 3.11.6 are affected by a NodeVM builtin allowlist bypass that permits a sandbox escape on Node.js 24 and newer when the embedder explicitly allows the node:test builtin (e.g. require: { builtin: ['node:test'] }). On Node.js 24+, module.builtinModules exposes the scheme-only key node:test, which is not covered by vm2's family-based DANGEROUS_BUILTINS protection, so it is stored in the generic host-passthrough loader. Because requireImpl() in lib/setup-node-sandbox.js strips a single 'node:' prefix before the builtin lookup, sandbox code calling require('node:node:test') resolves to the stored node:test key and receives a readonly proxy to the host module. Calls to node:test.run() are forwarded to the host implementation, which spawns a separate Node process for process-isolated test execution and passes through attacker-controlled execArgv values; supplying --eval=<JavaScript> therefore executes arbitrary JavaScript in an unrestricted host Node process outside the NodeVM sandbox. Fixed in vm2 3.11.7.
Technical POC Analysis
CWE-693: Protection Mechanism Failure.
Full technical POC analysis - root cause, step-by-step exploitation and patch breakdown - is part of the Pro and Business plans.
Latest POC
1 public PoC link from github
Sign in to open the public PoC links collected for this CVE.
Executive ViewAI
A critical sandbox-escape flaw in the widely embedded vm2 JavaScript library (versions 3.9.6 through 3.11.6) allows attacker-supplied code to break out of its isolation boundary and execute with the full privileges of the host Node.js process, which typically means direct access to application secrets, internal APIs and production systems. The exposure is concentrated: it only materializes where an application runs on Node.js 24 or newer and has explicitly allowlisted the node:test builtin, so leadership should treat any such service that accepts untrusted JavaScript as an internet-reachable code-execution risk. No vendor-issued fix is currently available, making containment and library replacement the only reliable risk-reduction path.
No vendor-released patch identified at time of analysis. Until vm2 is replaced or updated, remove node:test from all vm2 builtin allowlists, block 'node:' prefix handling so require('node:node:test') cannot resolve, restrict hosts to Node.js 22 or earlier where the vulnerable key cannot be reached, run untrusted code in a separate unprivileged container or micro-VM with no host filesystem access, no privileged child-process spawning and no network egress, and monitor for host Node processes launching children with attacker-supplied execArgv values such as --eval.
Threat Intelligence Overview
How this decision was reached
The engine reads each signal below and applies a fixed list of rules from top to bottom. The first rule that matches sets the recommended action – like a statement, every line is shown.
What every action level means
SSVC AssessmentENISA
Priority Score
Attack Technique
Remote Code Execution represents the critical moment when an attacker successfully runs arbitrary code on a target system without physical access.
vm2 is an advanced vm/sandbox for Node.js. Rated critical severity (CVSS 10.0), this vulnerability is remotely exploitab
vm2 is a sandbox that can run untrusted code with Node's built-in modules. Rated critical severity (CVSS 10.0), this vul
vm2 is a sandbox that can run untrusted code with whitelisted Node's built-in modules. Rated critical severity (CVSS 10.
There exists a vulnerability in source code transformer (exception sanitization logic) of vm2 for versions up to 3.9.15,
vm2 is a sandbox that can run untrusted code with whitelisted Node's built-in modules. Rated critical severity (CVSS 10.
This affects the package vm2 before 3.9.4 via a Prototype Pollution attack vector, which can lead to execution of arbitr
Full sandbox escape with arbitrary code execution allows remote attackers to break out of vm2's Node.js sandbox environm
Sandbox escape in vm2 for Node.js allows remote unauthenticated attackers to execute arbitrary commands on the host syst
Sandbox escape in vm2 (patriksimek/vm2) versions prior to 3.11.3 enables remote code execution on the host Node.js proce
Sandbox escape in vm2 Node.js sandbox before 3.10.2 via Promise.prototype.then/catch callback sanitization bypass. PoC a
vm2 is a sandbox that can run untrusted code with whitelisted Node's built-in modules. Rated critical severity (CVSS 9.8
The package vm2 before 3.9.10 are vulnerable to Arbitrary Code Execution due to the usage of prototype lookup for the We
EUVD-2026-81597
GHSA-qhwx-74w5-xhxq
NVD
CVE.org
EPSS
Exploit-DB