Safeguard
Vulnerability Analysis

CVE-2023-37466: Remote code execution via vm2 sandbox escape

A critical vm2 sandbox escape (CVE-2023-37466) lets untrusted JavaScript break out to achieve remote code execution on the host Node.js process.

Vikram Iyer
Security Researcher
7 min read

In April 2023, security researchers began publishing a string of sandbox-escape vulnerabilities in vm2, one of the most widely used libraries for running untrusted JavaScript inside a supposedly isolated context in Node.js applications. The most severe of these, CVE-2023-37466, allows an attacker who controls code executed inside the vm2 sandbox to break out of that sandbox entirely and run arbitrary code with the full privileges of the host Node.js process — a complete remote code execution (RCE) primitive against any application that uses vm2 to evaluate untrusted or semi-trusted input.

For teams building plugin systems, code-execution playgrounds, CI runners, low-code platforms, or any "run this snippet safely" feature on top of Node.js, vm2 was for years the default answer. CVE-2023-37466 — and the broader pattern of vm2 sandbox escapes discovered alongside it — is why that default answer changed.

What CVE-2023-37466 actually is

vm2 (maintained under the patriksimek/vm2 GitHub project) advertises itself as an "advanced vm/sandbox for Node.js," letting a host application execute untrusted code in a context that cannot reach the surrounding process, filesystem, or network unless explicitly permitted. To make that sandbox usable, vm2 has to let some values — errors, stack traces, certain built-ins — cross the boundary between the sandboxed context and the host context, and it sanitizes those values so a malicious script can't smuggle a live reference to a host-side object out with them.

CVE-2023-37466 is a bypass of that sanitization. The flaw involves vm2's handling of Error.prepareStackTrace, a V8 hook that customizes how stack traces are formatted. Code running inside the vm2 sandbox could manipulate this hook in a way that caused vm2 to hand back a reference to an unsanitized, host-side object instead of the expected sandboxed value. Once an attacker holds a live reference to something in the host realm, they can pivot through Node's constructor chain (the classic constructor.constructor trick used across JavaScript sandbox escapes) to reach Function in the outer context and execute arbitrary code — outside the sandbox, inside the real process.

In practical terms: any application feature that lets a user submit JavaScript to be evaluated by vm2 — a "custom formula" field, a webhook transformation step, a bot scripting interface — could be turned into full RCE against the server running it.

Affected versions and components

  • Component: vm2 npm package (patriksimek/vm2), a Node.js module for sandboxed execution of untrusted JavaScript.
  • Affected versions: vm2 releases prior to the fixed 3.9.x line that addressed this specific prepareStackTrace-based bypass.
  • Fixed in: vm2 3.9.17.
  • Downstream exposure: any Node.js application or platform that depends on vm2 to isolate untrusted code — this includes a long tail of low-code/no-code tools, serverless function runners, CI/CD plugin engines, chatbot and workflow scripting features, and internal developer tools that embedded vm2 as a "safe eval."

It's worth being explicit that CVE-2023-37466 was not an isolated bug. It was one of several vm2 sandbox-escape CVEs disclosed in 2023 (alongside identifiers such as CVE-2023-30547, CVE-2023-32313, and CVE-2023-32314), each one closing a different variant of the same underlying problem: vm2's approach of trying to sanitize every object crossing the sandbox boundary is inherently a whack-a-mole game against V8's introspection surface. That pattern is the real story here — not just one patched bug, but a structural weakness in the sandboxing approach itself.

Severity, exploitability, and KEV status

CVE-2023-37466 was rated Critical, with a CVSS v3.1 base score of 9.8 — reflecting a network-exploitable vulnerability requiring no authentication, no user interaction, and low attack complexity, with complete impact on confidentiality, integrity, and availability once triggered. That scoring lines up with the reality of the bug: any application surface that feeds attacker-influenced code into vm2's run()/Script APIs is directly exploitable, no chaining or social engineering required.

Exploitation here depends heavily on application context — the attacker needs a code path that lets them submit JavaScript for vm2 to execute — so this is not a "scan the internet" mass-exploitation vulnerability in the way a web server RCE might be. That distinction matters for prioritization: it's not currently listed in CISA's Known Exploited Vulnerabilities (KEV) catalog as of this writing, and precise EPSS scoring should be checked against current data rather than assumed, since exploit-prediction scores shift over time. But the absence from KEV should not be read as low risk. For the specific set of products that embed vm2 as a security boundary — which is exactly the use case vm2 was built for — this vulnerability is as close to worst-case as it gets: unauthenticated, low-complexity, full host compromise.

Timeline

  • 2023 (spring): Security researchers begin reporting a series of sandbox-escape bugs in vm2, with the maintainer shipping successive 3.9.x point releases to close each variant.
  • 2023 (mid-year): CVE-2023-37466 is disclosed and assigned, alongside the related CVE-2023-37903, describing further bypasses of vm2's object-sanitization approach via Error.prepareStackTrace and related mechanisms.
  • Fix released: vm2 3.9.17 addresses the prepareStackTrace-based escape described in CVE-2023-37466.
  • Aftermath: Following this cluster of repeated escapes, the vm2 project itself was marked as no longer actively maintained, with maintainers and the wider Node.js security community steering users toward alternative isolation approaches (such as isolated-vm, or process/VM-level isolation) rather than continuing to patch individual sandbox-escape variants.

Remediation steps

  1. Inventory your dependency tree. Don't just check package.json — vm2 is frequently pulled in transitively by plugin frameworks, low-code engines, and internal tooling. Run npm ls vm2 (or your package manager's equivalent) across every service, and check lockfiles, not just declared dependencies.
  2. Upgrade immediately if you're on a pre-3.9.17 release, or confirm you're already on a patched line. Treat this as an emergency patch, not routine maintenance, given the CVSS 9.8 rating and the trivial exploitation path for any app that evaluates user-supplied code.
  3. Re-evaluate whether vm2 should still be in your stack at all. Given that the project is no longer actively maintained and has a track record of repeated sandbox escapes, patching the current CVE does not guarantee the next one won't surface. Plan a migration to a maintained isolation mechanism — isolated-vm, a separate worker process with OS-level sandboxing, a WASM-based interpreter, or a containerized/VM-based execution boundary — for any feature that truly needs to run untrusted code.
  4. Add defense in depth around any code-execution feature, regardless of which sandbox library you use: run untrusted code in a separate, least-privileged process or container; disable network and filesystem access at the OS level; apply strict timeouts and resource limits; and treat "sandbox escape" as a when-not-if risk for any in-process JavaScript sandbox.
  5. Audit for exploitation. If untrusted code execution has been exposed via vm2 in a customer-facing feature, review logs for anomalous outbound connections, spawned child processes, or filesystem access originating from the sandboxing service around the disclosure window.

How Safeguard Helps

CVE-2023-37466 is a textbook case for why software supply chain visibility can't stop at "is this package in my package.json." The vulnerable component here is frequently several layers deep — pulled in by a plugin framework, a low-code builder, or an internal tool nobody remembers wiring up — and it's exactly the kind of dependency that gets missed by point-in-time audits.

Safeguard continuously inventories the actual dependency graph across your services, including transitive dependencies like vm2, and flags known-vulnerable versions the moment a CVE like this is disclosed — not at the next scheduled scan. For a critical, CVSS 9.8, actively-discussed sandbox-escape bug, that speed difference is the gap between patching before an incident and explaining one.

Beyond detection, Safeguard helps teams answer the harder question this CVE raises: is this dependency structurally sound, or does it keep needing patches for the same class of bug? By tracking a package's vulnerability history, maintenance status, and exposure across your real runtime environment — not just its presence in a manifest — Safeguard surfaces components like vm2 that warrant replacement, not just an upgrade, and helps you prioritize remediation based on actual reachability and blast radius rather than CVSS score alone.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.