CVE-2026-47135

highpriority · track · 0EPSS 0.003 · 19 %ileDEEUUS
grimoire priorityP2 · Scheduled
Exploitable?
—
no known exploitation
Likely / severe?
0.27% (19th) EPSS
CVSS 8.7 · high
Is it mine?
4 products
Check your exposure
Who says so?
4 sources
cnnvd · enisa_euvd · cert_bund · osv

EPSS · 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.

01

cvss

Technical severity, 0–10. One row per scoring source.

8.7
010

base score 0–10 · higher = more severe · hover a vector to decode

v3.18.7highCVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:H/A:Nsecondary · ENISA EU
v3.18.7highCVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:H/A:Nsecondary · security-advisories@github.comexploitability 2.2 · impact 5.8
v3.18.7highCVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:H/A:Nsecondary · OSV
v3.18highCVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:H/A:N/E:Usecondary · CVSS-BT (t0sche)
02

ssvc

A stakeholder decision — act, attend, or track — from exploitation and impact.

Exploitation: none · Automatable: no · Technical Impact: totalcoordinatorcisa_ssvcUS
03

weaknesses

The CWE weakness classes this flaw belongs to.

04

affected products (4)

Products and version ranges known to be affected.

05

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.

06

also known as (3)

Other names and identifiers for this entity.

07

sources

Which sources assert this record, and when.

published 2026-06-12modified 2026-10-26
08

references (10)

External citations — patches, advisories, analysis.

scry

Attackers weaponise vulnerabilities like this against internet-exposed services. See what is exposed on your perimeter with a free passive scan.

Free scan