vm2 is a JavaScript sandboxing library for Node.js that lets a host application run untrusted or third-party code inside an isolated context, with the goal of blocking that code from reaching the filesystem, network, or the rest of the process. For years it was the default answer to "how do I safely eval a plugin, a user script, or an untrusted npm package inside my Node app" — plugin systems, code-execution playgrounds, and CI tools all reached for it. Then a series of sandbox-escape vulnerabilities, several of them critical, showed that the isolation vm2 promised was never as strong as it looked, and the project was formally deprecated in 2023. This post covers what vm2 did, why it became popular, its security history, and what to use instead.
What is vm2 and why did teams use it?
vm2 is an npm package that wraps Node.js's built-in vm module to provide a more restrictive execution context for running untrusted code. Node's native vm module (accessed via vm.createContext() or new vm.Script()) creates a separate global object but was never designed as a security boundary — Node's own documentation warns that vm is not a security mechanism for running untrusted code. vm2 was built specifically to fill that gap: it intercepted access to Node's built-in modules, wrapped require() calls, proxied global objects, and tried to prevent common escape techniques like reaching the host's process object or walking the prototype chain back out to the real global scope. That made it attractive for a specific, common problem — plugin architectures where third-party authors submit JavaScript that needs to run inside your Node process, low-code platforms, online code-execution sandboxes, and CI/CD tools that evaluate configuration or templates written by users. At its peak, vm2 saw millions of weekly downloads and was embedded inside several well-known developer tools and PaaS platforms as their untrusted-code execution layer.
What sandbox-escape vulnerabilities did vm2 have?
vm2 accumulated a string of critical sandbox-escape CVEs between 2021 and 2023, each showing a different way to break out of its isolation and execute arbitrary code on the host. CVE-2023-32314 and CVE-2023-32315 affected the vm2 inspector/debugger integration, allowing an attacker to escape the sandbox via crafted error stack traces and gain access to the host's require function. CVE-2023-37903 followed months later with another sandbox-escape path through error handling that again let attacker-controlled code reach outside the sandbox. Earlier, CVE-2021-23555 (prototype pollution leading to sandbox escape) and CVE-2022-36067, nicknamed "Sandbreak," scored a CVSS of 10.0 — a maximum-severity rating — because it let untrusted code inside the vm2 sandbox execute arbitrary shell commands on the host by abusing how vm2 handled JavaScript's asynchronous stack trace preparation (Error.prepareStackTrace). The recurring theme across all of these: JavaScript's dynamic, reflective nature gives an attacker many indirect paths to host objects — error objects, promises, generators, proxies — and vm2 kept patching individual paths rather than the underlying model.
Why was vm2 deprecated?
vm2 was deprecated in 2023 after its maintainers concluded that patch-by-patch fixes couldn't keep pace with the rate new sandbox-escape techniques were discovered. The project's own README and advisories acknowledged the pattern: each CVE closed one specific escape route, but the fundamental problem — trying to build a hard security boundary on top of a single-process, single-heap JavaScript runtime that was never designed for it — kept producing new ones. Node's own vm module documentation says the same thing directly: it is not a sandbox, and running truly untrusted code safely requires actual process isolation, not in-process context switching. After deprecation, the vm2 npm package stopped receiving security fixes, meaning any application still depending on it inherited every unpatched and future escape technique with no vendor fix coming.
What should you use instead of vm2 for running untrusted code?
The maintainers and the wider Node.js community converged on isolate-based and process-based isolation as the replacement, since neither has the shared-heap weakness that made vm2's escapes possible. isolated-vm uses V8 isolates — the same primitive that separates tabs in Chrome — to give each execution context its own heap and garbage collector, which closes off entire classes of prototype-pollution and object-reference escapes. For workloads that can tolerate the overhead, actual OS-level isolation — a separate container, a microVM (Firecracker, gVisor), or a subprocess with a locked-down seccomp/AppArmor profile and no network access — provides a real security boundary instead of a language-level approximation of one. If your application still imports vm2 directly or transitively through another package, treat it the same way you'd treat any dependency with no upstream security fixes: plan a migration, don't wait for a patch that isn't coming, and use software composition analysis to find every place it's pulled into your dependency tree, including indirectly through plugin frameworks.
FAQ
Is vm2 still safe to use?
No. vm2 is deprecated and no longer receives security patches, and its own history shows multiple maximum-severity sandbox escapes discovered years apart from each other. Any code still depending on it should be treated as running untrusted code with no real isolation.
What is Sandbreak (CVE-2022-36067)?
Sandbreak is the nickname for CVE-2022-36067, a critical (CVSS 10.0) vm2 sandbox-escape vulnerability that let code running inside the sandbox execute arbitrary commands on the host machine by abusing how vm2 handled async stack trace preparation.
Does Node.js's built-in vm module have the same problems?
Node's vm module is the foundation vm2 was built on, and Node's own documentation explicitly states it is not a security mechanism for running untrusted code — it provides a separate global context, not an isolation boundary, so the underlying risk is the same or worse without a wrapper.
How do I find out if my app depends on vm2?
Run a full dependency tree scan, since vm2 is often pulled in transitively by plugin frameworks, low-code tools, or testing libraries rather than being a direct dependency. An SCA scan against your manifest and lockfile will surface it even several layers deep.
How Safeguard Helps
Safeguard's SCA engine flags deprecated and vulnerable packages like vm2 wherever they appear in your dependency graph — direct or transitive — and correlates the finding against the specific CVEs your installed version is exposed to, rather than just alerting on the package name. Where a maintained replacement exists, Safeguard's remediation guidance points to it directly so teams migrating off vm2 aren't left guessing at what to adopt instead.