isolated-vm ships a sandbox escape, and the migration story catches up with itself
Tomás Vega
You run untrusted JavaScript inside a sandbox because you are a responsible adult and you have read the incident postmortems. The sandbox is the whole point. It is the line between "customer plugin" and "your production Node process, doing whatever the plugin wants". So what happens when the sandbox itself hands out the keys?
That is the shape of this week's news. Endor Labs disclosed a flaw in isolated-vm, tracked as GHSA-864f-rcv7-6rh4 (CVE assignment pending), that lets code inside the sandbox corrupt memory in the host process and, from there, run whatever it likes. Patches are out in versions 7.0.1 and 6.2.0. Everything below those on either release line is a problem you already have.
The bug, in one paragraph
The escape lives in ExternalCopy, the machinery isolated-vm uses to move data across V8 isolate boundaries. Senior security researcher Cris Staicu describes it as a time-of-check-to-time-of-use flaw in the C++ glue: the ExternalCopy constructor iterates over the transferList option twice, validates each element on the first pass, then transfers each element on the second pass without revalidating. A cooperative attacker inside the sandbox can swap what a slot points at between those two passes. Type confusion. Corrupted host memory. Hijacked control flow. RCE outside the isolate.
Note where this is not. It is not a bug in V8's isolate primitive. It is in the serialization layer bolted on top of it. Which is precisely where sandbox escapes tend to live, because the isolate itself has had thousands of person-years of Chrome-team scrutiny and the glue code has had considerably less.
Why this one hurts more than a normal RCE
Two reasons, and they compound.
First, the audience. isolated-vm exists to run code you do not trust. Every project that pulled it in did so specifically because the threat model assumes the code inside is hostile. When a normal Node dependency has an RCE, the attacker still has to get their code onto your box. Here, the attacker's code being on your box is Tuesday.
Second, who is downstream. DevOps.com lists over a million weekly downloads and names n8n, Mastra, Sim.ai, Activepieces, Screeps, Fly.io, Algolia and TripAdvisor among the users. Some of those are workflow platforms that let end users write JavaScript. Some are edge-compute or search products where "run this snippet" is the entire product. If you build on top of any of them, your effective patch window is however long it takes their team to redeploy.
And there is the migration wrinkle. isolated-vm is where a lot of people landed after vm2 went unmaintained. The whole point of moving was to get out from under an abandoned sandbox with a poor security record. That is still the right move. But it is worth saying plainly: swapping runtimes does not fix the class of bug. The C++ glue between V8 isolates is where these live, and there is no version of Node where "run untrusted JS in-process" stops being a load-bearing trust boundary.
What to patch, and what to check after
Pin to 7.0.1 or 6.2.0 depending on which line you are on, and rebuild anything that vendors a native module. That is the easy part.
The harder part is what runs inside the isolate. Any sandboxed code that executed between the vulnerable version being deployed and the patch landing must be treated as potentially having escaped. That means, at minimum:
- Audit host-process activity around the sandbox for the window where the vulnerable version was live: outbound network to anything the host would not normally talk to, unexpected child processes, filesystem writes outside the tenant's scoped directory.
- Rotate any secret the host process could read. Not the ones the sandbox is supposed to see. The ones on the host side of the boundary: API keys, database credentials, cloud-provider tokens, signing keys.
- If the sandbox was on a build runner, treat the runner as tainted and cycle it. A build runner that hosted an escape does not become clean because you upgraded a dependency.
None of this is fun. All of it is the actual cost of running untrusted code in-process, made visible for a week.
The uncomfortable question
Should you be running untrusted JavaScript in the same OS process as anything you care about, at all? The pragmatic answer is that isolated-vm, patched, is fine for many use cases and dramatically cheaper than a per-tenant Firecracker microVM or a WASM runtime with a real capability boundary. The honest answer is that any in-process sandbox is one C++ glue bug away from being a very expensive child_process.exec.
Patch this week. Then, this quarter, ask whether the next sandbox escape (there will be a next one) is one your architecture can absorb without rotating half your production secrets. If the answer is no, the sandbox is not the boundary. It is a suggestion.
Source: DevOps.com (devops.com)