vm2 Sandbox Escape via inspect Function: Quick Look at CVE-2026-24781 (CVSS 9.8)

A brief summary of CVE-2026-24781, a critical sandbox breakout in the vm2 Node.js sandbox that allows remote code execution on the host system through the inspect function. Covers technical root cause, affected versions, and mitigation guidance.

CVE Analysis

8 min read

ZeroPath CVE Analysis
ZeroPath CVE Analysis

2026-05-04

vm2 Sandbox Escape via inspect Function: Quick Look at CVE-2026-24781 (CVSS 9.8)
Experimental AI-Generated Content

This CVE analysis is an experimental publication that is completely AI-generated. The content may contain errors or inaccuracies and is subject to change as more information becomes available. We are continuously refining our process.

If you have feedback, questions, or notice any errors, please reach out to us.

[email protected]

Introduction

A sandbox breakout in vm2, the popular Node.js sandboxing library, allows an attacker who can execute JavaScript inside a vm2 instance to escape the sandbox entirely and run arbitrary commands on the host operating system. With a CVSS score of 9.8, no required privileges, and a public Proof of Concept already available, CVE-2026-24781 represents a serious risk for any service that evaluates user supplied code using vm2.

vm2 is an open source project designed to run untrusted JavaScript securely within a single Node.js process, mediating access to host objects through a network of ES6 Proxies and whitelisted built in modules. It is widely adopted in platforms that offer server side code evaluation, online coding playgrounds, and automation tools that need to execute user provided scripts. Its position as one of the most downloaded sandboxing libraries on npm makes vulnerabilities in vm2 relevant across a broad swath of the Node.js ecosystem.

Technical Information

Root Cause: Proxy Unwrapping via inspect

The core of CVE-2026-24781 lies in how Node's inspect method logs details of objects. To render object internals, the inspect implementation unwraps proxies. An attacker operating inside the vm2 sandbox can extract these unwrapped values using the this.seen property of the stylize function. This extraction grants direct access to the internal proxy handler of vm2, which contains the sandbox object itself.

Here is where the subtlety matters: because access to the handler is itself wrapped by a vm2 proxy, accessing the sandbox object stored in the proxy handler results in a wrapped sandbox object being passed into the sandbox. The attacker can then write a wrapped host object to the wrapped sandbox object and read the raw host object from the raw sandbox object. This completely bypasses the proxy bridge that vm2 relies on for isolation.

Handler Class Reconstruction

The canonical exploit path takes this proxy leak and escalates it through handler class reconstruction. The sequence works as follows:

  1. The attacker calls p.getPrototypeOf(p) to invoke the handler's own getPrototypeOf trap. This returns the real BaseHandler.prototype, which carries live host functions for .set, .get, and .constructor.

  2. By calling new BaseHandler(attackerObject), the attacker constructs a legitimate handler that wraps attacker controlled state.

  3. The .set trap is then used to plant a host realm proxy of that attacker controlled state into attacker visible memory. This creates a cross realm read and write channel.

  4. With this channel established, the attacker can reach host realm objects and invoke child_process.execSync or equivalent functions to execute arbitrary commands on the host system.

Node Version Dependencies

The exploit's reliability varies across Node.js versions. The leak harvest path uses Buffer.prototype.slice routed through Buffer.prototype.inspect. Node 24 and newer versions tightened argument validation on these methods, which means the harvest path never fires on those versions regardless of whether vm2 is patched. However, tests confirm that the harvest path is fully reachable on Node versions 22 and below, with verified sandbox escapes on Node 18.20.7.

It is important to note that relying on Node version behavior is not a valid mitigation strategy. The v3.11.0 release patched multiple independent sandbox escape vectors, and other exploit paths may not share the same Node version constraints.

Patch Defenses in v3.11.0

The patch introduced in version 3.11.0 implements three independent layers of defense to block handler class reconstruction:

Construction token: A module local Symbol is captured in the createBridge() closure. All handler classes require this token as their first constructor argument and throw a VMError otherwise. This prevents an attacker from constructing a handler even if they obtain a reference to the constructor.

WeakMap guard: The getHandlerObject function explicitly checks if the handler is registered in the handlerToObject WeakMap. This blocks method calls on forged receivers, preventing an attacker from calling .set or .get on a handler they constructed outside the normal code path.

Constructor sentinel rebind: The .constructor property on every handler prototype is replaced with a function that unconditionally throws a VMError. This prevents prototype chain walks from reaching a callable class, cutting off the reconstruction path at its entry point.

Affected Systems and Versions

The vulnerability affects vm2 versions 3.10.3 and earlier. The fix was released in version 3.11.0.

The exploit is confirmed to be reachable on Node.js versions 22 and below, with verified escapes on Node 18.20.7. Node 24 and newer versions have tightened argument validation that prevents the specific Buffer.prototype.inspect harvest path from firing, but this should not be treated as a mitigation.

Organizations running any vm2 version prior to 3.11.0 on any Node.js version should consider themselves affected.

Vendor Security History

The vm2 maintainers have a track record of transparency about the inherent difficulty of in process JavaScript sandboxing. They openly acknowledge that researchers continuously discover new ways to escape the sandbox and actively patch vulnerabilities as they are reported.

The release of version 3.11.0 is notable for the volume of critical issues it addressed simultaneously. The following advisories were all patched in this single release:

GHSA Advisory IDVulnerability DescriptionImpact
GHSA-grj5-jjm8-h35pArray species self return sandbox escapeRCE
GHSA-v37h-5mfm-c47cHandler reconstruction via util.inspect leakRCE
GHSA-qcp4-v2jj-fjx8Trap method on leaked handler with forged targetRCE
GHSA-47x8-96vw-5wg6Cross realm symbol extraction from host objectsRCE
GHSA-55hx-c926-fr95Promise structural leak and sanitisation bypassRCE
GHSA-vwrp-x96c-mhwqHost intrinsic prototype pollution via bridge write trapsPrototype Pollution
GHSA-947f-4v7f-x2v8NodeVM builtin allowlist bypass via host passthroughRCE

Six out of seven advisories carry RCE impact. This concentration of critical sandbox escapes in a single release underscores the fragility of proxy based isolation and reinforces the maintainers' own recommendation that vm2 should never be the sole security boundary for untrusted code execution.

References

Detect & fix
what others miss

Security magnifying glass visualization