CVE-2026-47135
highpriority · track · 0EPSS 0.003 · 19 %ileDEEUUSEPSS · scored 2026-10-27
vm2 is an open source vm/sandbox for Node.js. Prior to version 3.11.4, 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. This issue has been patched in version 3.11.4.
cvss
Technical severity, 0–10. One row per scoring source.
base score 0–10 · higher = more severe · hover a vector to decode
ssvc
A stakeholder decision — act, attend, or track — from exploitation and impact.
weaknesses
The CWE weakness classes this flaw belongs to.
affected products (4)
Products and version ranges known to be affected.
advisories (2)
Vendor and ecosystem advisories describing this.
- WID-SEC-W-2026-1583vm2: Mehrere SchwachstellenDeutsch2026-05-18csaf · cert_bundDE
Ein entfernter, anonymer Angreifer kann mehrere Schwachstellen in vm2 ausnutzen, um beliebigen Programmcode auszuführen, Sicherheitsmaßnahmen zu umgehen, Daten zu manipulieren und vertrauliche Informationen offenzulegen.
- GHSA-m5q2-4fm3-vfqpvm2 has a sandbox escape via unblocked cross-realm Symbol.for keys + missing bridge write-trap symbol checks2026-05-29ghsa · osvUS
## 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`): ```js 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.custom` - `nodejs.stream.readable` - `nodejs.stream.writable` - `nodejs.stream.duplex` - `nodejs.stream.transform` - `nodejs.webstream.isClosedPromise` - `nodejs.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 ```js 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.writable` to a host Readable stream, altering its duck-typing identity - `Object.assign` propagates unblocked symbols from sandbox source to host target - `Object.defineProperty` with unblocked symbol key succeeds on host objects - `delete hostObj[unblocked_symbol]` succeeds, removing host-set symbol properties ## Impact - **Semantic confusion**: Sandbox controls host `util.promisify` behavior, 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 1. **`setup-sandbox.js`**: Block all `nodejs.*` prefixed symbols: ```js Symbol.for = function (key) { const keyStr = '' + key; if (keyStr.startsWith('nodejs.')) return Symbol(keyStr); return originalSymbolFor(keyStr); }; ``` 2. **`bridge.js`**: Add check to write traps: ```js set(target, key, value, receiver) { if (isDangerousCrossRealmSymbol(key)) throw new VMError(OPNA); // ... } ``` 3. **`setup-sandbox.js`**: Sync `isDangerousSymbol`, `Object.getOwnPropertyDescriptors`, `Object.assign` to cover all dangerous symbols.
also known as (3)
Other names and identifiers for this entity.
sources
Which sources assert this record, and when.
references (10)
External citations — patches, advisories, analysis.
- https://github.com/patriksimek/vm2/commit/928aef51898b5c52a05f05a40c4cfeb52e172878cnnvd
- https://github.com/patriksimek/vm2/releasesPatchcnnvd
- https://github.com/patriksimek/vm2/releases/tag/v3.11.4cnnvd
- https://github.com/patriksimek/vm2/security/advisories/GHSA-m5q2-4fm3-vfqpcnnvd
- https://github.com/patriksimek/vm2/commit/928aef51898b5c52a05f05a40c4cfeb52e172878enisa_euvd
- https://github.com/patriksimek/vm2/releases/tag/v3.11.4enisa_euvd
- https://github.com/patriksimek/vm2/security/advisories/GHSA-m5q2-4fm3-vfqpenisa_euvd
- https://github.com/patriksimek/vm2/commit/928aef51898b5c52a05f05a40c4cfeb52e172878nvd
Attackers weaponise vulnerabilities like this against internet-exposed services. See what is exposed on your perimeter with a free passive scan.
Free scan