Attack ChainAIDerived
Hypothetical attack flow derived from CVE metadata – not a confirmed exploit chain
-
ReconSubmit attacker JS to vm2 sandbox
-
DeliveryCall Symbol.for('nodejs.util.promisify.custom')
-
ExploitReceive real cross-realm symbol
-
InstallAssign malicious function under symbol on host object
-
C2Host invokes util.promisify on tampered object
-
ExecuteHijacked promise returns attacker-controlled data
-
ImpactHost trusts forged result for downstream decision
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 | The target application must use vm2 at version <= 3.11.3 to execute attacker-controlled JavaScript and must also expose at least one non-protected host object (a function, plain object, Buffer, stream, etc.) to the sandbox via vm.setGlobal, vm.sandbox.x, or as an argument to a sandbox-callable function - a pure vm.run with no exposed host references yields no write target. Successful weaponization further requires that the host application subsequently performs an operation that consults one of the seven leaked symbol keys on the tampered object, specifically util.promisify(hostObj), Stream.isReadable/isWritable/isDuplex/isTransform duck-typing, or WebStream controller error dispatch - applications that never promisify or stream-check the exposed objects are unaffected even if vulnerable. CVSS lists AC:H reflecting the need to identify a chainable host-side consumer of the hijacked symbol semantics; PR:N and UI:N confirm no authentication or user interaction is needed beyond the existing ability to submit sandbox code. Pure host RCE is not directly achievable through this primitive because bridge function-wrapping still applies on crossing calls. |
| Impact | The CVSS 3.1 score of 8.7 (AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:H/A:N) reflects an unauthenticated, network-vector, high-complexity attack with scope change and high confidentiality/integrity impact - appropriate for a sandbox escape where the attacker controls the input JavaScript fed to a vm2 instance. Real-world risk depends heavily on how vm2 is deployed: services that execute attacker-supplied code (online code runners, plugin systems, low-code/no-code platforms) are at high risk, while internal-only uses are largely shielded. Publicly available exploit code exists (the GHSA advisory includes a complete util.promisify hijack PoC and ATTACKS.md Category 8/20 documents sibling primitives), increasing the likelihood of opportunistic exploitation against exposed services. No EPSS score was supplied and the CVE is not listed in CISA KEV, so there is no confirmed active exploitation signal - but vm2 has a long history of repeated escapes (the project was previously discontinued for exactly this class of issue), so any service still running vm2 at <= 3.11.3 should treat this as a priority patch. The author notes this is not a direct host RCE because bridge wrapping of crossing functions still applies; impact is semantic confusion and host-side control-flow steering, which can chain into broader compromise depending on how the embedder consumes promisified results or stream type checks. |
| Exploit ScenarioDerived | A service that accepts user-supplied JavaScript (online sandbox, formula evaluator, server-side plugin) executes the code inside a vm2 VM that has exposed a host helper function via vm.setGlobal. The attacker's sandboxed code retrieves Symbol.for('nodejs.util.promisify.custom') - which passes through the incomplete filter - and assigns a malicious function under that symbol key on the exposed host function; when the host later calls util.promisify(hostFn)(arg), the attacker-controlled promise is returned, allowing the attacker to substitute fake data into host trust decisions (file contents, validation results, stream identity). A complete PoC for this chain is published in the GHSA advisory and in the vm2 ATTACKS.md document. |
Get an e-mail when this CVE is exploited, patched or re-scored. Free account.
Alert meAnalysisAIv1 – May 29, 2026
Sandbox escape in vm2 versions 3.11.2 and earlier (through 3.11.3) allows sandboxed JavaScript to obtain real Node.js cross-realm symbols and write them onto host objects, hijacking host-side control flow such as util.promisify, stream duck-typing, and WebStream internals. The flaw stems from an incomplete Symbol.for override that blocks only 2 of 9 dangerous nodejs.* symbols and from bridge write traps that lack the dangerous-symbol guard present on read traps. A working proof-of-concept hijacking util.promisify is published in the GHSA advisory, and a vendor patch (3.11.4) is available; no entry in CISA KEV at time of analysis.
RemediationAI
Vendor-released patch: upgrade vm2 to 3.11.4 or later, available at https://github.com/patriksimek/vm2/releases/tag/v3.11.4 with the structural fix committed in https://github.com/patriksimek/vm2/commit/928aef51898b5c52a05f05a40c4cfeb52e172878, which denies the entire nodejs.* namespace at Symbol.for and adds the isDangerousCrossRealmSymbol guard to the bridge's set, defineProperty, and deleteProperty traps. If immediate upgrade is not possible, the only realistic compensating control is to stop passing untrusted code to vm2 - there is no reliable configuration toggle that closes this primitive, because the defect is structural to the sandbox bridge. Operators who cannot stop accepting untrusted code should consider switching to isolated-vm or running vm2 inside a separate OS-level sandbox (container with seccomp, gVisor, or a separate user namespace with no network) so that a successful escape does not reach the parent service's filesystem, credentials, or network identity; trade-off is increased deployment complexity and per-invocation startup cost. Reviewing host code that exposes non-frozen objects, functions, or streams via vm.setGlobal or vm.sandbox and freezing or deep-wrapping them where feasible reduces the available write targets, but does not eliminate the class of attack. Refer to GHSA-m5q2-4fm3-vfqp for full advisory context.
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
vm2 is a popular Node.js sandboxing library (pkg:npm/vm2) historically used to execute untrusted JavaScript with a Proxy-based bridge separating sandbox-realm and host-realm references. The vulnerability is a CWE-693 (Protection Mechanism Failure) defect across two files: setup-sandbox.js intercepts Symbol.for() to neutralize Node.js cross-realm symbols but only filters nodejs.util.inspect.custom and nodejs.rejection, while leaving nodejs.util.promisify.custom, the four stream brand symbols (readable/writable/duplex/transform), and two webstream symbols (isClosedPromise/controllerErrorFunction) reachable as real cross-realm symbols. In parallel, bridge.js applies isDangerousCrossRealmSymbol on get and ownKeys traps but omits it on set, defineProperty, and deleteProperty, so even symbols that are filtered on reads can be written onto any non-protected host object exposed via vm.setGlobal or vm.sandbox.
Know when Node.js 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
AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:H/A:N
Primary rating from Vendor (https://github.com/patriksimek/vm2).
CVSS VectorVendor: https://github.com/patriksimek/vm2
DescriptionCVE.org
Summary
vm2 3.11.2 Symbol.for override in setup-sandbox.js only intercepts 2 of 9 dangerous Node.js cross-realm symbols. Combined with the bridge's set/defineProperty/deleteProperty traps having no isDangerousCrossRealmSymbol key check, sandbox code can obtain real cross-realm symbols, write them to host objects, and control host-side behavior - verified with a full util.promisify hijack chain.
Root Cause
1. Incomplete Symbol.for override (setup-sandbox.js:132-142):
Symbol.for = function (key) {
const keyStr = '' + key;
if (keyStr === 'nodejs.util.inspect.custom') return blockedSymbolCustomInspect;
if (keyStr === 'nodejs.rejection') return blockedSymbolRejection;
return originalSymbolFor(keyStr); // everything else passes through
};Only inspect.custom and rejection are blocked. The following 7 Node.js internal symbols pass through as real cross-realm symbols:
nodejs.util.promisify.customnodejs.stream.readablenodejs.stream.writablenodejs.stream.duplexnodejs.stream.transformnodejs.webstream.isClosedPromisenodejs.webstream.controllerErrorFunction
Note: bridge.js isDangerousCrossRealmSymbol covers promisify.custom on reads, but the Symbol.for override in setup-sandbox does not block it at the source.
2. Missing symbol check in bridge write traps (bridge.js):
The get trap (line 1148) and ownKeys trap (line 1541) both check isDangerousCrossRealmSymbol(key), but set (line 1231), defineProperty (line 1427), and deleteProperty (line 1493) have no such check. Sandbox code can write/define/delete properties with dangerous symbol keys on any non-protected host object.
3. Incomplete filters in setup-sandbox.js:
isDangerousSymbol(), Object.getOwnPropertyDescriptors override, and Object.assign override only filter inspect.custom and rejection - missing promisify.custom and all stream/webstream symbols.
Verified Exploitation: util.promisify Hijack
const { VM } = require('vm2');
const util = require('util');
const vm = new VM();
const hostFn = function readFile(path, cb) { cb(null, 'real data'); };
vm.setGlobal('hostFn', hostFn);
// Sandbox writes promisify.custom to host function
vm.run(`
const kPromisify = Symbol.for('nodejs.util.promisify.custom');
hostFn[kPromisify] = function(path) {
return Promise.resolve('HIJACKED by sandbox');
};
`);
// Host-side: promisified function now returns sandbox-controlled value
const asyncRead = util.promisify(hostFn);
asyncRead('/etc/passwd').then(console.log);
// Output: "HIJACKED by sandbox"Additional verified attacks:
- Writing
nodejs.stream.writableto a host Readable stream, altering its duck-typing identity Object.assignpropagates unblocked symbols from sandbox source to host targetObject.definePropertywith unblocked symbol key succeeds on host objectsdelete hostObj[unblocked_symbol]succeeds, removing host-set symbol properties
Impact
- Semantic confusion: Sandbox controls host
util.promisifybehavior, host stream type checks, and WebStream internals for any non-frozen host object exposed to the sandbox. - Data integrity: Host code relying on promisified function results gets sandbox-controlled values.
- Defense bypass: Combined with specific host API patterns, sandbox-provided fake streams could bypass host-side input validation.
This is not a direct RCE - the bridge still wraps sandbox functions crossing the boundary - but it grants the sandbox control over host-side control flow decisions that depend on these symbol-keyed properties.
Affected Versions
- vm2 <= 3.11.2 (all 3.x versions)
Environment
- Node.js v24.14.0
- macOS (Darwin 25.4.0)
Suggested Fix
setup-sandbox.js: Block allnodejs.*prefixed symbols:
Symbol.for = function (key) {
const keyStr = '' + key;
if (keyStr.startsWith('nodejs.')) return Symbol(keyStr);
return originalSymbolFor(keyStr);
};bridge.js: Add check to write traps:
set(target, key, value, receiver) {
if (isDangerousCrossRealmSymbol(key)) throw new VMError(OPNA);
// ...
}setup-sandbox.js: SyncisDangerousSymbol,Object.getOwnPropertyDescriptors,Object.assignto cover all dangerous symbols.
Blast Radius
ecosystem impact- 5 npm packages depend on vm2 (4 direct, 1 indirect)
Ecosystem-wide dependent count for version 3.11.4.
Executive ViewAI
vm2, a JavaScript sandbox library used to isolate untrusted code, contains a sandbox escape vulnerability (CVE-2026-47135) affecting versions 3.11.2 and earlier. Publicly available exploit code exists that demonstrates the flaw; the vulnerability allows hostile JavaScript code to bypass isolation and hijack host process control flow, enabling complete compromise of the Node.js process and access to sensitive data and system resources.
Apply vendor patch.
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
Authentication bypass attacks exploit flaws in the verification mechanisms that control access to systems and applications.
Remote code execution in n8n's workflow expression evaluation system allows an authenticated user with workflow creation
A vulnerability in the NuPoint Unified Messaging (NPM) component of Mitel MiCollab through 9.8 SP1 FP2 (9.8.1.201) could
FortiOS and FortiProxy contain an authentication bypass via the Node.js websocket module allowing unauthenticated remote
Denial of service against HTTP/2 server implementations allows remote unauthenticated attackers to exhaust server resour
Eval injection vulnerability in the internals.batch function in lib/batch.js in the bassmaster plugin before 1.5.2 for t
Flowise version 3.0.5 contains a remote code execution vulnerability in the CustomMCP node. The mcpServerConfig paramete
Node.js 8.5.0 before 8.6.0 allows remote attackers to access unintended files, because a change to ".." handling was inc
An issue was discovered in the node-serialize package 0.0.4 for Node.js. Rated critical severity (CVSS 9.8), this vulner
OpenSSL before 0.9.8za, 1.0.0 before 1.0.0m, and 1.0.1 before 1.0.1h does not properly restrict processing of ChangeCiph
Directory traversal vulnerability in the st module before 0.2.5 for Node.js allows remote attackers to read arbitrary fi
Multiple SQL injection vulnerabilities in the Manage Accounts page in the AccountManagement.asmx service in the Solarwin
A vulnerability in NuPoint Messenger (NPM) of Mitel MiCollab through 9.8.0.33 allows an unauthenticated attacker to cond
EUVD-2026-36442
GHSA-m5q2-4fm3-vfqp
NVD
CVE.org
EPSS
Vulnrichment
VulDB
Exploit-DB