isolated-vm gives Node.js access to V8's Isolate interface, so an application can run untrusted JavaScript in a separate heap without spinning up a container or a virtual machine. Plenty of platforms that let customers write code use it, precisely because it is cheaper than the alternatives.

EndorLabs found a critical flaw in it. No CVE has been assigned yet. It is fixed in 6.2.0 and 7.0.1.

The bug

It lives in ExternalCopy, the function that copies data between Isolates.

The native C++ binding iterates the transfer_list array twice while optimising the transfer, and the second pass trusts what the first pass saw. In JavaScript, an array element can be defined as a getter — a function that runs on access — and a getter is free to return something different every time it is called.

So guest code defines a getter, lets the first pass see something safe, and hands the second pass something else. The native layer then dereferences a pointer the attacker chose. The route into the host's own objects is ivm.Reference, which is the mechanism by which the host deliberately exposes things to the sandbox.

Outcome: a crash, or control-flow hijack in the host process, which is remote code execution outside the sandbox.

Why this keeps happening

EndorLabs' own description is the general lesson: this layer is written in a memory-unsafe language, manipulates raw V8 handles and backing-store pointers, and re-reads attacker-controlled JavaScript objects in the middle of a security-sensitive operation.

Every word of that is a hazard, and the last clause is the one that generalises. If you read attacker-controlled data twice, you have to assume it changed in between. That is the same defect as MLflow validating a URL and then resolving it again after a redirect, and as Elementor checking a file extension in one loop while a second loop moved the file.

The fix taken here is the right shape: prevent user JavaScript from executing at all during the copy. Remove the opportunity to change the answer rather than trying to detect that it changed.

The uncomfortable part about isolates as a boundary

This is the second time this week that V8 isolates have appeared as a security boundary that needed reinforcement. Cloudflare's own researchers pulled a JWT across isolates in the same process using Spectre, and closed it with hardware memory protection rather than software.

Isolates are a performance construct that the industry has widely adopted as a security construct, because processes are expensive and isolates are nearly free. That trade is often correct. It is not free, and the failures show up in the native glue rather than in V8 itself.

What to do

  • Upgrade to 6.2.0 or 7.0.1. Anything earlier is affected.
  • Work out whether you actually run untrusted code. If your isolates only ever run your own JavaScript, this is not urgent. If customers write the code, it is.
  • Audit any host function passing caller-influenced arrays as a transfer list. That is the direct exposure EndorLabs names.
  • Review what you expose through ivm.Reference. Every reference handed into the sandbox is part of the attack surface, and most are added for convenience.
  • Decide whether an isolate is the right boundary at all. For genuinely hostile code, a process or a microVM costs more and fails differently.

What is not established

  • A CVE identifier. Not yet assigned at the time of writing.
  • Exploitation in the wild. None reported.
  • How many deployments are affected. No usage figures have been published alongside the advisory.