isolated-vm, falla critica può trasformare un sandbox JavaScript in RCE sull’host
Vulnerabilities

Illustrative image generated with AI

isolated-vm: Critical flaw can turn a JavaScript sandbox into host RCE

Discover a critical vulnerability in isolated-vm that enables host RCE by breaking JavaScript sandbox boundaries.

Text generated by artificial intelligence, published without human review. AI transparency

Memory corruption breaks the guest–host boundary

A critical vulnerability in the Node.js isolated-vm library allows untrusted JavaScript code to crash the host process and, under favorable conditions, take control of its execution flow.

The issue affects the native C++ code that connects V8 JavaScript objects with the memory structures used by isolated-vm. The flaw combines type confusion, memory corruption, and a time-of-check/time-of-use (TOCTOU) condition.

The impact is particularly serious because isolated-vm is designed to execute potentially hostile code inside V8 isolates. These environments separate the heap, execution state, and garbage collector, providing a security boundary without necessarily relying on containers or virtual machines.

This defect compromises that boundary. Guest code can influence the host process, potentially enabling remote code execution on the host. No evidence has been reported that the vulnerability was exploited in real-world campaigns.

The vulnerability was discovered on August 21, 2026. No CVE identifier is currently known to be associated with the issue.

The flaw stems from reading transferList twice

The entry point is the following mechanism:

ivm.ExternalCopy(value, { transferList })

ExternalCopy serializes data in one isolate and reconstructs it in another. To transfer large ArrayBuffer objects efficiently, the source buffer can be detached and its backing memory passed to the destination.

However, while constructing ExternalCopySerialized, isolated-vm processes transferList twice. During the first pass, it verifies that each element is an ArrayBuffer. During the second, it retrieves the elements again and converts them without repeating the type check.

This difference is critical. Elements are read through Get(), which does not merely retrieve an existing value: it can execute JavaScript accessors, including index getters.

A guest-controlled getter can therefore return a genuine ArrayBuffer during validation and a completely different value during the second read. That new value is then passed to As<ArrayBuffer>(), which in this code path acts as an unchecked cast rather than a safe conversion.

The check therefore applies to one value, while the subsequent use may involve another.

How the checked value reaches the C++ code

The vulnerable path crosses several internal components:

  • src/external_copy/serializer.cc, where transferList is iterated twice;
  • src/isolate/generic/array.h:42, whose iterator reads elements through array->Get(context, index);
  • src/external_copy/external_copy.cc:397, where ExternalCopyArrayBuffer::Transfer uses the handle incorrectly assumed to be an ArrayBuffer.

During the second pass, the handle may contain a value that does not represent a buffer. The code nevertheless performs operations intended for a valid object, including:

  • checking whether the buffer is detachable;
  • retrieving its backing store;
  • detaching the buffer;
  • managing the associated shared_ptr<BackingStore>.

A small integer such as 0x41414141 can be interpreted by V8 as an SMI, an integer represented directly in a tagged value. The native code instead treats it as an object and attempts to dereference it.

The result is an address calculated from attacker-controlled data. In addition, when the shared_ptr is destroyed, the code path may perform an indirect call through a vtable pointer obtained from that memory. This creates a potential primitive for control-flow hijacking, redirecting the host process’s execution flow.

The technical classification includes CWE-843, access of a resource using an incompatible type, and CWE-704, incorrect type conversion or interpretation.

The guest can reach the API indirectly

The ExternalCopy constructor is exposed on the host side, but exploitation does not necessarily require the host to call the API directly with already-manipulated data.

The class can be transferred to the guest through the externalCopy option of the transferable mechanism. The untrusted code only needs access to a single ivm.Reference. It can then obtain the constructor as follows:

const ExternalCopy =
  ref.getSync('anyKey', { externalCopy: true }).constructor;

The guest can then construct a transferList containing a getter with variable behavior. On the first read, the getter returns a valid ArrayBuffer, passing the initial check. On the second, it can return, for example, 0x41414141.

This exposes embedders that execute untrusted JavaScript in an isolate and share at least one ivm.Reference with that code.

A more direct scenario is also possible: host code may be vulnerable if it passes a user-controlled transferList array to ExternalCopy. In that case, the guest does not need to possess a transferred reference.

The PoC demonstrates a controllable crash

The proof of concept was tested with:

  • isolated-vm 7.0.0, installed from npm;
  • Node.js 26.5.0;
  • macOS on arm64 architecture.

The issue is reproducible on any platform, although fault addresses and other details may vary.

Running the PoC with:

node poc.js

terminates the host process with:

  • SIGSEGV;
  • exit code 139;
  • an error in v8::ArrayBuffer::IsDetachable;
  • fault address 0x4141414100000047.

This value is significant because it is derived from the guest-controlled integer, interpreted as an SMI. The result is therefore more than a null dereference or an arbitrary crash.

The demonstrated crash represents the minimum confirmed impact. In more complex scenarios, the same corruption could enable reads from or writes to attacker-chosen addresses and control of the host process’s execution flow. This creates a risk of sandbox escape and code execution on the host.

Fixed versions and administrator guidance

Fixes are available in:

  • isolated-vm 6.2.0;
  • isolated-vm 7.0.1.

Users on the 6.x branch should upgrade to at least 6.2.0; users on the 7.x branch should upgrade to at least 7.0.1. Transitive dependencies that include isolated-vm should also be reviewed, especially in services that execute scripts supplied by users, plugins, or remote content.

The fix prevents JavaScript from executing during the copy operation. As a result, the contents of transferList cannot change between validation and the cast.

Priority actions include:

  1. upgrade isolated-vm to the fixed version for the branch in use;
  2. inventory embedders that execute untrusted JavaScript;
  3. identify cases where the guest receives ivm.Reference objects;
  4. review uses of ExternalCopy with input-influenced transferList values;
  5. reduce, where possible, the sharing of ivm.Reference objects with untrusted code.

From a monitoring perspective, crashes involving SIGSEGV, exit code 139, and abnormal fault addresses or values traceable to attacker-controlled input warrant immediate investigation. These are technical indicators consistent with the PoC, but they do not by themselves prove compromise.

No network-, file-, or process-based indicators of compromise are known. It is also unknown whether the vulnerability has been added to CISA’s KEV catalog, and no associated remediation deadline has been reported.

Read next

Sources

This article is an original reworking based on the sources below.

Related topicsisolated-vmNode.jssandbox escaperemote code executionvulnerabilitytype confusionmemory corruption
Back to home