system: OPERATIONAL
← back to all hacks
AGENTS CRITICAL NEW

vm2 sandbox escapes turn agent prompt injection into host RCE

A 2026 wave of escapes in vm2 — the Node.js library many agent frameworks use to run LLM-generated JavaScript — lets a prompt injection break out of the sandbox and run commands on the host.

2026-07-06 // 7 min affects: vm2, nodejs, ai-agent-frameworks, code-execution-sandboxes, llm-generated-code

What is this?

Through the first half of 2026, security researchers disclosed a wave of sandbox-escape vulnerabilities in vm2, a once-popular npm library for running untrusted JavaScript with restrictions such as a limited module allowlist. A first critical escape landed in January 2026 (documented by StepSecurity and Semgrep), and a cluster of more than ten additional identifiers followed on May 4–5, 2026, most scored between CVSS 9.0 and 10.0 (Kodem Security, May 14, 2026).

What makes this a topic for an AI-security site rather than a generic Node.js bug is where vm2 sits. Many AI agent frameworks use vm2 as the isolation layer for executing code the model itself generates. On May 7, 2026 Microsoft Security Research named the resulting structural problem: in agent frameworks where prompts can influence executable logic, a sandbox escape converts a prompt injection into host-level remote code execution — “When prompts become shells.”

How it works

The chain has four stages, and none of them requires a novel exploit — only a known escape primitive and an agent wired to run generated code.

First, untrusted JavaScript reaches vm2. In a plugin or SaaS product the source is user-submitted code. In an agent, the source is the model’s own output: a tool that lets the agent “write and run a script” will happily execute a script an attacker steered it toward through injected instructions in a web page, document, or tool result.

Second, the code triggers a sandbox-boundary abuse. vm2’s isolation is enforced almost entirely in JavaScript — rewriting catch clauses, proxy-bridging objects that cross the boundary, and patching known escape paths one at a time. The 2026 disclosures each defeat that model by a different route: promise-callback sanitization bypass, SuppressedError and other exception-handling abuse, __lookupGetter__ and getPrototypeOf tricks, proxy-unwrap via inspect(), and prototype-pollution chains. They all produce the same outcome — a reference, callback, or property lookup that reaches an object in the host realm.

// Vulnerable shape (illustrative): an agent runs model-generated JS in vm2
const { VM } = require('vm2');
const result = new VM().run(modelGeneratedCode); // [REDACTED] escape primitive runs here

Third comes host-capability access. Once outside the sandbox the code can reach Node’s process object and, from there, child_process, the filesystem, and outbound network. One of the May advisories is precisely an allowlist bypass straight to child_process. Fourth is payload execution: arbitrary shell commands run with the privileges of the Node.js runtime — which in an agent deployment often means access to environment secrets, cloud credentials, and internal network reach.

Why it matters

Prompt injection on its own is usually an output-layer problem: the model says something it shouldn’t. Routed through a vulnerable execution sandbox, the same injection becomes an infrastructure-layer problem: an attacker gets a shell on the box. That is a qualitative change in blast radius, and it is exactly the combination flagged by Microsoft and by the responders tracking the wave.

Two properties make vm2 a bad bet for this job. It has a multi-year history of sandbox escapes, and its maintainer has deprecated the project — so patches are not a reliable stream. And the isolation model has no structural defense against the class; each CVE is a one-off fix for a new primitive, which is why 2026 produced a cluster rather than a single bug. A realistic assumption is that more variants are coming, and the same “prompts become shells” framing will extend to other JavaScript sandboxes as researchers look at them.

The practical exposure question is not “is vm2 installed” (an SCA scan answers that). It is whether an untrusted prompt can reach a dynamic-execution path that runs through vm2 with real tools attached. A web app that evaluates a hardcoded internal script through vm2 and an agent that executes LLM-generated code in vm2 with shell access look identical in a dependency manifest and carry completely different risk.

Defenses

  • Do not treat vm2 (or any in-process JS sandbox) as a security boundary. If you must execute untrusted or model-generated code, layer real isolation underneath it — a separate container, gVisor, or Firecracker — so an escape lands in a disposable, least-privilege environment rather than on your host.
  • Patch, but plan to migrate. Upgrade vm2 to the latest patched release to close the currently-disclosed primitives, and prioritize moving off the deprecated library to an actively maintained approach for untrusted execution.
  • Restrict the agent’s tools. An agent that cannot call child_process, cannot write outside a scratch directory, and cannot reach unallowlisted network destinations cannot turn a sandbox escape into an infrastructure compromise. Tool restriction ships faster than re-architecting the execution model.
  • Strip credentials from the execution context. The Node.js process running untrusted code should not carry AWS/GCP keys, registry tokens, or CI secrets. Use scoped, short-TTL tokens and remove ambient credentials.
  • Monitor at runtime. Hunt for node processes spawning shells or child_process calls, unexpected reads of files like ~/.aws/credentials or /proc/self/environ, and outbound egress from an agent runtime to non-allowlisted domains. The escape happens inside the process, so behavioral telemetry — not just dependency scanning — is what catches it.
  • Map your execution paths. Inventory every service where vm2 appears in the direct or transitive dependency tree, and flag the ones where untrusted or LLM-generated code can actually reach it. That subset is the real exposure.

Status

ItemValue
Affected componentvm2 (Node.js untrusted-JavaScript sandbox), deprecated by maintainer
NatureMultiple sandbox-escape → host RCE flaws
Disclosure windowJan 2026 (CVE-2026-22709) and a May 4–7, 2026 cluster (10+ CVEs, CVSS 9.0–10.0)
AI relevanceAgent frameworks run model-generated JS in vm2 → prompt injection to host RCE
Fixed inPatched vm2 releases up to the 3.11.x line (verify current advisory before deploying)
Reference CVEsCVE-2026-22709, CVE-2026-24118, CVE-2026-24120, CVE-2026-24781, CVE-2026-26332, CVE-2026-26956, CVE-2026-43997, CVE-2026-43999, CVE-2026-44005 (and related May-2026 identifiers)

Key dates: January 26, 2026 — first 2026 escape disclosed. May 4–7, 2026 — cluster of 10+ escapes. May 7, 2026 — Microsoft’s “prompts become shells” analysis of the agent-framework impact.

This article covers a publicly disclosed vulnerability class for defensive purposes and intentionally omits any working exploit code.

Sources