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

Imagen ilustrativa generada con IA

isolated-vm: una falla crítica puede convertir un sandbox de JavaScript en RCE sobre el host

Una vulnerabilidad crítica en la biblioteca de Node.js isolated-vm permite que código JavaScript no confiable provoque el cierre inesperado del proceso

Texto generado por inteligencia artificial, publicado sin revisión humana. Transparencia IA

Una corrupción de memoria rompe el aislamiento entre guest y host

Una vulnerabilidad crítica en la biblioteca de Node.js isolated-vm permite que código JavaScript no confiable provoque el cierre inesperado del proceso host y, en determinadas condiciones, tome el control de su flujo de ejecución.

El problema afecta al código nativo C++ que conecta los objetos JavaScript de V8 con las estructuras de memoria utilizadas por isolated-vm. La falla combina type confusion, corrupción de memoria y una condición de time-of-check/time-of-use (TOCTOU).

El impacto es especialmente grave porque isolated-vm se utiliza precisamente para ejecutar código potencialmente malicioso dentro de isolates de V8. Estos entornos separan el heap, el estado de ejecución y el garbage collector, proporcionando un límite de seguridad sin recurrir necesariamente a contenedores o máquinas virtuales.

El defecto compromete ese límite. El código guest puede llegar a influir en el proceso host, con potencial ejecución remota de código en el host. No se ha informado de evidencias de explotación de la vulnerabilidad en campañas reales.

La vulnerabilidad se detectó el 21 de agosto de 2026. No se conoce ningún identificador CVE asociado al problema.

El defecto se origina en una doble lectura de transferList

El punto de entrada es el mecanismo:

ivm.ExternalCopy(value, { transferList })

ExternalCopy permite serializar datos en un isolate y reconstruirlos en otro. Para transferir grandes ArrayBuffer de forma eficiente, el buffer de origen puede “desvincularse” y su espacio de memoria transferirse al destino.

Sin embargo, durante la construcción de ExternalCopySerialized, isolated-vm analiza transferList dos veces. En el primer recorrido comprueba que cada elemento sea un ArrayBuffer. En el segundo vuelve a obtener los elementos y los convierte sin repetir la comprobación de tipo.

Esta diferencia es decisiva. La lectura de los elementos se realiza mediante Get(), que no se limita a recuperar un valor ya existente: también puede ejecutar accessors de JavaScript, incluidos los index getters.

Por tanto, un getter controlado por el guest puede devolver un ArrayBuffer válido durante la validación y un valor completamente distinto en la segunda lectura. Después, ese nuevo valor se pasa a As<ArrayBuffer>(), que en esta ruta actúa como un cast no comprobado, no como una conversión segura.

Así, la comprobación se realiza sobre un valor, mientras que el uso posterior puede afectar a otro.

Cómo llega el valor validado al código C++

La cadena vulnerable atraviesa varios componentes internos:

  • src/external_copy/serializer.cc, donde transferList se itera dos veces;
  • src/isolate/generic/array.h:42, cuyo iterador lee los elementos mediante array->Get(context, index);
  • src/external_copy/external_copy.cc:397, donde ExternalCopyArrayBuffer::Transfer utiliza el handle considerado erróneamente un ArrayBuffer.

En el segundo recorrido, el handle puede contener un valor que no representa ningún buffer. Aun así, el código intenta realizar operaciones reservadas para un objeto válido, entre ellas:

  • comprobar si el buffer puede desvincularse;
  • obtener su backing store;
  • desvincular el buffer;
  • gestionar el shared_ptr<BackingStore> asociado a la memoria.

Un entero pequeño como 0x41414141 puede ser interpretado por V8 como SMI, es decir, un entero representado directamente en el valor tagged. El código nativo, en cambio, lo trata como si fuera un objeto e intenta desreferenciarlo.

El resultado es una dirección calculada a partir de datos controlados por el atacante. Además, durante la destrucción del shared_ptr, la ruta puede realizar una llamada indirecta mediante un puntero vtable obtenido de esa memoria. Esta condición ofrece una posible primitiva de control-flow hijacking, es decir, de desvío del flujo de ejecución del proceso.

La clasificación técnica incluye CWE-843, acceso a un recurso mediante un tipo incompatible, y CWE-704, interpretación o conversión incorrecta del tipo.

El guest también puede alcanzar la API de forma indirecta

El constructor ExternalCopy se expone en el lado del host, pero el ataque no requiere necesariamente que el host invoque directamente la API con datos ya manipulados.

La clase puede transferirse al guest mediante la opción externalCopy del mecanismo transferable. Basta con que el código no confiable disponga de una sola ivm.Reference. A partir de ella puede obtener el constructor de esta forma:

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

A continuación, el guest puede preparar un transferList que contenga un getter con comportamiento variable. En la primera lectura, el getter devuelve un ArrayBuffer válido y supera la comprobación inicial. En la segunda puede devolver, por ejemplo, 0x41414141.

Por tanto, quedan expuestos los embedders que ejecutan JavaScript no confiable en un isolate y comparten con ese código al menos un objeto ivm.Reference.

También existe un escenario más directo: el código host puede ser vulnerable si pasa a ExternalCopy un array transferList controlable por el usuario. En este caso, no es necesario que el guest posea una referencia transferida.

El PoC demuestra un crash controlable

El proof of concept se verificó con:

  • isolated-vm 7.0.0, instalada desde npm;
  • Node.js 26.5.0;
  • macOS sobre arquitectura arm64.

El problema es reproducible en cualquier plataforma, aunque las direcciones y los detalles del fallo pueden variar.

La ejecución del PoC mediante:

node poc.js

provoca la terminación del proceso host con:

  • señal SIGSEGV;
  • código de salida 139;
  • error en v8::ArrayBuffer::IsDetachable;
  • dirección de fallo 0x4141414100000047.

Este último valor es significativo porque deriva del entero controlado por el guest, interpretado como SMI. Por tanto, no se trata únicamente de una desreferencia nula o de un crash aleatorio.

El crash representa el impacto mínimo demostrado. La misma corrupción puede, en escenarios más complejos, permitir lecturas o escrituras en direcciones elegidas por el atacante y el control del flujo del proceso host. De ahí se deriva el riesgo de evasión del sandbox y ejecución de código en el host.

Versiones corregidas y medidas para administradores

Las correcciones están disponibles en:

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

Quienes utilicen la rama 6 deben actualizar al menos a la 6.2.0; quienes utilicen la rama 7 deben actualizar al menos a la 7.0.1. También conviene revisar las dependencias transitivas que incluyan isolated-vm, especialmente en servicios que ejecuten scripts proporcionados por usuarios, plugins o contenido remoto.

La corrección impide la ejecución de JavaScript durante la operación de copia. De este modo, el contenido de transferList no puede cambiar entre la fase de validación y la del cast.

Las medidas prioritarias son:

  1. actualizar isolated-vm a la versión corregida de la rama utilizada;
  2. inventariar los embedders que ejecuten JavaScript no confiable;
  3. identificar los casos en los que el guest recibe objetos ivm.Reference;
  4. revisar los usos de ExternalCopy con transferList influenciables por la entrada;
  5. reducir, cuando sea posible, el uso compartido de ivm.Reference con código no confiable.

En materia de monitorización, los crashes con SIGSEGV, código 139 y direcciones de fallo anómalas o vinculadas a valores controlados deben analizarse de inmediato. Son indicadores técnicos compatibles con el PoC, pero por sí solos no demuestran una intrusión.

No se conocen indicadores de compromiso basados en red, archivos o procesos. Tampoco se sabe si la vulnerabilidad se ha incorporado al catálogo KEV de CISA, ni constan datos sobre una fecha límite de remediation asociada.

Lee también

Fuentes

Este artículo es una reelaboración original basada en las siguientes fuentes.

Temas relacionadosisolatedfallacríticapuedeconvertirsandboxjavascriptsobre
Volver al inicio