Safeguard
Vulnerability Analysis

CVE-2023-30547: Sandbox escape via Node custom inspect in...

CVE-2023-30547 lets attackers escape the vm2 Node.js sandbox via a crafted custom inspect method, achieving host code execution. Here's the impact, timeline, and fix.

Vikram Iyer
Security Researcher
8 min read

CVE-2023-30547 is a sandbox-escape vulnerability in vm2, the widely-used Node.js library for running untrusted JavaScript inside an isolated context. The flaw lives in how vm2's Proxy-based sandbox interacts with Node's built-in object-inspection machinery — specifically the custom inspect hook that console.log, util.inspect, and Node's own error-formatting routines call automatically. By defining a crafted Symbol.for('nodejs.util.inspect.custom') method on an object passed across the sandbox boundary, an attacker can get that method invoked with host-level privileges instead of the restricted, proxy-wrapped privileges the sandbox is supposed to enforce. The practical result is arbitrary code execution outside the sandbox, on the host Node.js process — precisely the outcome vm2 exists to prevent.

This is the third in a rapid sequence of critical vm2 sandbox escapes disclosed in 2023 (alongside CVE-2023-29017 and CVE-2023-29199), and it's part of the pattern that eventually led the vm2 maintainers to archive the project and recommend migrating to alternative isolation strategies entirely. If your organization embeds vm2 anywhere — a plugin system, a low-code/no-code rules engine, a CI template evaluator, a chatbot "code execution" feature — this CVE deserves the same urgency as a remote code execution bug in your own code, because that's effectively what it is.

Why this matters: vm2's threat model

vm2 was built to let applications execute untrusted or semi-trusted JavaScript — user-submitted plugins, template expressions, scripting extensions — without giving that code access to the host's file system, network stack, or process object. It does this by running code inside Node's vm module and wrapping the global object and built-ins in Proxies that intercept and restrict access.

The problem, borne out across all three of the 2023 vm2 CVEs, is that Node.js has many internal code paths that reach across the sandbox boundary in ways the Proxy layer doesn't fully anticipate: formatting an uncaught exception, generating a stack trace, or — in this case — inspecting an object for logging. util.inspect (and therefore console.log) checks whether an object implements a custom inspect symbol and, if so, calls it directly. Because that call happens inside host code, a sandboxed object that defines the custom inspect method can smuggle a function reference out of the sandbox and have it executed with the full privileges of the host context, bypassing the Proxy restrictions entirely. This class of bug — a vm2 custom inspect sandbox escape — doesn't require any unusual configuration; it only requires that host code at some point logs, inspects, or serializes an object that originated from (or was returned by) sandboxed code, which is an extremely common pattern in real applications.

Affected versions and components

  • Package: vm2 (npm)
  • Affected: vm2 releases prior to the fix that addressed the custom-inspect escape path, part of the 3.9.x line
  • Fixed in: the maintainers shipped a patched 3.9.x release shortly after the issue was reported; teams should confirm they are on the latest available vm2 release from the official GitHub Security Advisory for this CVE rather than relying on a specific version number, since vm2 pushed several security fixes in close succession that same year
  • Not affected: applications that never expose sandboxed objects to host-side console.log/util.inspect calls are not directly exploitable via this path, but this is a fragile mitigation, not a fix — logging is too common a pattern to rely on avoiding it as a security control

Because vm2 is frequently a transitive dependency — bundled inside templating engines, serverless plugin frameworks, spreadsheet-formula evaluators, and internal "run this snippet" developer tools — many affected organizations don't have vm2 in their direct package.json at all. That's the detail that trips up manual patching efforts.

CVSS, EPSS, and KEV context

CVE-2023-30547, like its sibling vm2 sandbox-escape CVEs from the same period, was tracked as a Critical-severity issue in vulnerability databases, reflecting the fact that successful exploitation grants an attacker code execution on the host outside the isolation boundary the library is designed to provide. As with any sandbox-escape finding, treat the published severity as a floor, not a ceiling: the real-world impact depends entirely on what the host process can do (file system access, credentials, network reach, other tenants' data) once the sandbox is bypassed.

EPSS (Exploit Prediction Scoring System) values for library-specific sandbox escapes like this one tend to shift over time as public proof-of-concept code circulates and as scanners begin fingerprinting the vulnerable pattern — check FIRST.org's EPSS API for the current score rather than relying on a static number in a blog post. As of this writing, CVE-2023-30547 does not appear on CISA's Known Exploited Vulnerabilities (KEV) catalog, meaning there's no confirmed evidence of widespread in-the-wild exploitation tracked by CISA. That is not the same as "safe to ignore" — KEV listing lags real-world abuse, and sandbox-escape bugs in code-execution libraries are exactly the kind of primitive that's valuable to attackers targeting multi-tenant SaaS platforms, CI runners, and plugin marketplaces, even without mass, opportunistic exploitation.

Timeline

  • Early 2023: Researchers begin systematically probing vm2's Proxy-based isolation model after the disclosure of the first sandbox escape in the series (CVE-2023-29017), finding that the underlying architectural gap — host code paths that touch sandboxed objects — has more than one exploitable instance.
  • Spring 2023: CVE-2023-29199 is disclosed, showing a related escape via Node's stack-trace preparation machinery. Shortly after, CVE-2023-30547 is reported, demonstrating the same class of issue through the custom-inspect/console.log code path.
  • Patch released: The vm2 maintainers ship a fix and a corresponding GitHub Security Advisory is published alongside the CVE.
  • Mid-to-late 2023: Additional sandbox-escape reports continue to surface against vm2's architecture. The maintainers ultimately archive the project, stating that vm2's sandboxing approach cannot be made fully secure against this class of issue, and point users toward alternative isolation mechanisms such as isolated-vm or OS/VM-level sandboxing.

The throughline across this timeline is important: this wasn't a single coding mistake patched once and forgotten. It was evidence that vm2's fundamental design — trying to enforce a security boundary with JavaScript Proxies inside a single Node.js process — kept producing new escape primitives. That context should inform your remediation posture below.

Remediation steps

  1. Inventory every path vm2 enters your environment. Don't stop at direct dependencies — check plugin frameworks, templating libraries, formula/rules engines, and internal developer tools that may embed vm2 without it appearing in your top-level manifest.
  2. Upgrade to the patched vm2 release referenced in the official GitHub Security Advisory for CVE-2023-30547 as an immediate stopgap for any deployment you cannot migrate off vm2 quickly.
  3. Plan a migration away from vm2. Given the maintainers' own guidance and the recurring pattern of escapes, treat vm2 as end-of-life for security-sensitive isolation. Evaluate isolated-vm (separate V8 isolate, stronger boundary), or move untrusted code execution out-of-process entirely using containers, gVisor, Firecracker microVMs, or a dedicated serverless execution sandbox.
  4. Add defense in depth regardless of library choice. Run any untrusted-code execution feature under least-privileged OS users, network-isolated containers, and strict resource limits — never rely on a single JavaScript-level sandbox as your only control.
  5. Audit logging and error-handling paths for places where host code calls console.log, util.inspect, or JSON-serializes objects that originated from sandboxed execution, since this is the exact trigger condition for this CVE.
  6. Re-scan after remediation to confirm the vulnerable version is fully removed from both direct and transitive dependency trees, including lockfiles and built container images that may have cached an older resolution.

How Safeguard Helps

Vulnerabilities like CVE-2023-30547 are hard to catch with periodic manual audits precisely because vm2 so often arrives as a transitive dependency buried three or four layers deep in a plugin framework you didn't write. Safeguard's software supply chain security platform is built for exactly this gap:

  • Continuous SCA and SBOM generation surface every instance of vm2 across your codebase and container images — including transitive occurrences pulled in by other packages — so you're not relying on package.json greps to find exposure.
  • Reachability-aware prioritization helps distinguish deployments where the vulnerable custom-inspect code path is actually exercised (e.g., sandboxed objects flow into logging or error handling) from dormant, unreachable instances, so remediation effort goes where risk actually lives.
  • Policy-as-code gating can block builds or merges that introduce known-vulnerable vm2 versions, preventing regressions once you've remediated.
  • Continuous monitoring re-checks your dependency graph as new advisories are published, so if a future vm2-class sandbox escape (or a vulnerability in whatever you migrate to, like isolated-vm) is disclosed, you're alerted automatically instead of discovering it during the next manual audit.
  • Compliance and audit trail support documents remediation timelines for CVEs like this one, which matters when SOC 2 or customer security reviews ask how you track and respond to critical third-party vulnerabilities.

Sandbox-escape bugs are a reminder that "isolation" is a spectrum, not a binary — and that the libraries you trust to enforce it deserve the same continuous scrutiny you apply to your own code. If you're running any form of untrusted-code execution in production, now is a good time to confirm vm2 isn't quietly part of that stack.

Never miss an update

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