Compromiso de la cadena de suministro de node-gyp: un gusano de npm que se propaga solo y se oculta en binding.gyp
4 de junio de 2026
0 minutos de lecturaUn ataque a la cadena de suministro se está propagando activamente por el registro de npm al abusar de un archivo que la mayoría de las herramientas de seguridad nunca revisan: binding.gyp. En lugar de depender de los scripts del ciclo de vida preinstall o postinstall, que se monitorean muy de cerca, el malware incluye un archivo binding.gyp manipulado que activa node-gyp para ejecutar automáticamente código controlado por el atacante durante npm install. Snyk está siguiendo el incidente como Compromiso de la cadena de suministro de Node-gyp - junio de 2026, que abarca 57 paquetes afectados y cientos de versiones maliciosas, todas clasificadas como código malicioso integrado con gravedad crítica.
La carga útil roba credenciales de desarrolladores y CI/CD en npm, GitHub, AWS, GCP, Azure, HashiCorp Vault y Kubernetes; las exfiltra mediante repositorios de GitHub controlados por atacantes; inyecta flujos de trabajo de GitHub Actions para persistir, y se propaga por sí misma al volver a publicar paquetes desde cualquier cuenta de mantenedor a la que pueda acceder. StepSecurity, que fue la primera en reportar la campaña, llamó a la técnica de ejecución durante la instalación «Phantom Gyp» y sigue la campaña más amplia como «Miasma», descendiente de la familia de gusanos Shai-Hulud.
Resumen
Tipo de ataque | Gusano de la cadena de suministro mediante cuentas de mantenedores comprometidas |
Técnica novedosa | Ejecución de código durante la instalación mediante |
Seguimiento de Snyk | |
Gravedad | Crítica (código malicioso integrado) |
Fecha del incidente | 3 de junio de 2026 (ola principal); variante anterior de Miasma del 1 de junio de 2026 |
Paquetes comprometidos | 57 paquetes, cientos de versiones maliciosas |
Víctimas con más descargas |
|
Comportamiento del malware | Robo de credenciales, inyección en GitHub Actions, persistencia y propagación del gusano por npm y RubyGems |
Acción inmediata | Fija versiones confiables, ejecuta |
Paquetes afectados
Snyk enumera 57 paquetes afectados. Confirmamos que las versiones maliciosas enumeradas todavía pueden obtenerse del registro público (por ejemplo, las cuatro versiones de @vapi-ai/server-sdk devuelven archivos tar disponibles desde registry.npmjs.org), con fechas de publicación del 3 y 4 de junio de 2026. Las víctimas con más descargas semanales, según las cifras de la API del registro de npm, son:
Paquete | Descargas semanales | Versiones maliciosas |
|---|---|---|
~86,500 (api.npmjs.org) | 0.11.1, 0.11.2, 1.2.1, 1.2.2 | |
~36,900 (api.npmjs.org) | 0.13.1, 1.1.1, 2.2.1, 3.8.5 | |
~5,900 (api.npmjs.org) | 2.26.4, 3.4.3 | |
~280 (api.npmjs.org) | 1.33.3 |
La mayoría de los 57 paquetes se concentra en una sola cuenta de npm. Al consultar el registro, vemos que los 25 paquetes autotel y autotel-* comparten al mantenedor jagreehal, la misma cuenta que publica el ámbito @jagreehal/* y awaitly. Esa concentración en una sola cuenta es exactamente lo que cabría esperar de un gusano que enumera y vuelve a publicar todo lo que puede tocar una cuenta comprometida:
Familia
autotel-*(24 paquetes, másautotel): incluyeautotel-mcp(con versiones desde0.1.14hasta29.0.1),autotel-subscribers,autotel-terminal,autotel-mongoose,autotel-eventcatalog,autotel-devtools,autotel-aws,autotel-cloudflare,autotel-hono,autotel-playwright,autotel-sentry, entre otrosFamilia
eslint-plugin-executable-stories-*(Snyk ya ha cubierto antes el malware en la cadena de suministro de ESLint-plugin npm)Paquetes
@jagreehal/*@evolvconsulting/evolv-coder-lite
Muchos de los números de versión inflados (por ejemplo, que autotel-mcp salte a la serie 29.x o que autotel publique tanto 2.26.4 como 3.4.3 en el mismo minuto del 4 de junio) son efectos de la republicación automatizada del gusano, no lanzamientos legítimos. La lista completa y actualizada continuamente de paquetes y versiones afectadas está en la página del incidente de Snyk.
Un detalle importante para la remediación: en al menos algunos paquetes, la etiqueta de distribución latest se volvió a asignar a una versión limpia (para autotel, latest ahora apunta a 3.4.2, publicada antes de las versiones maliciosas), pero las versiones maliciosas no se han retirado. Al momento de redactar esto, autotel@3.4.3 y autotel@2.26.4 aún devuelven archivos tar disponibles. Una nueva ejecución de npm install autotel podría obtener la versión limpia, mientras que cualquier archivo de bloqueo, versión fijada exacta o dependencia transitiva que haga referencia a una versión maliciosa seguirá descargando el malware. No tomes una etiqueta latest limpia como prueba de que estás a salvo.
Cómo funciona el ataque
La novedad: ejecución durante la instalación mediante binding.gyp
Cuando ejecutas npm install en un paquete que contiene un archivo binding.gyp y no tiene un binario precompilado compatible, npm entrega el paquete a node-gyp y ejecuta node-gyp rebuild para compilar lo que supone que es un complemento nativo de C/C++. Este comportamiento es normal y esperado para cualquier paquete con componentes nativos, y ocurre sin que haya una entrada preinstall o postinstall en ningún lugar de package.json.
La sintaxis de configuración de compilación de GYP admite la expansión de comandos. La forma <!(...) ejecuta un comando de shell durante la fase de configuración y sustituye su salida en la definición de compilación. Los paquetes comprometidos abusan directamente de esta función. Este es el archivo exacto binding.gyp de 157 bytes incluido en @vapi-ai/server-sdk@1.2.2 y autotel@3.4.3 (idéntico byte por byte en los paquetes que inspeccionamos):
La expresión <!(node index.js ...) ejecuta node index.js mientras node-gyp apenas está configurando la compilación, mucho antes de que se ejecute cualquier compilador. El destino "type": "none" significa que no se compila nada, por lo que el efecto secundario de la expansión del comando (ejecutar index.js) es precisamente el objetivo. La salida se redirige a /dev/null para que la instalación parezca normal, y echo stub.c devuelve un nombre de archivo de origen plausible para que gyp continúe sin errores evidentes. El resultado es la ejecución de código arbitrario durante una ejecución rutinaria de npm install.
Es fundamental señalar que package.json en estos archivos tar no contiene scripts preinstall, postinstall, install ni prepare. Las únicas entradas de scripts son tareas de desarrollo habituales (build, lint, test, format), y el paquete ni siquiera declara "gypfile": true. No hay nada en package.json que las herramientas centradas en scripts puedan marcar: basta con que exista un archivo binding.gyp para que npm invoque node-gyp por su cuenta.
La carga útil: un cargador de varias etapas basado en Bun
El archivo index.js que activa binding.gyp es un cargador ofuscado de 4.5 MB. Decodificamos estáticamente las capas externas desde el archivo tar publicado (sin ejecutarlo) y confirmamos la siguiente cadena:
Cifrado César ROT-14. Todo el archivo consiste en un solo
evalsobre una matriz de códigos de caracteres con aproximadamente 1.3 millones de entradas, que se convierte en una cadena y se desplaza 14 posiciones. El contenedor visible es literalmenteeval(function(s,n){return s.replace(/[a-zA-Z]/g,...rotate...)}([...],14)).Capa de autodescifrado AES-128-GCM. La etapa decodificada es una IIFE
asyncque importanode:cryptoy define un descifradoraes-128-gcm(createDecipherivcon una etiqueta de autenticación de 16 bytes), y luego descifra dos bloques de texto cifrado incrustados cuyas claves hexadecimales, IV y etiquetas de autenticación están codificados directamente.Cargador del entorno de ejecución de Bun (bloque de 907 bytes). El primer bloque descifrado detecta el sistema operativo y la arquitectura, luego descarga un binario independiente de Bun v1.3.13 desde las versiones oficiales de GitHub de
oven-sh/buna un directorio temporal y lo ejecuta:
Carga útil principal (bloque de ~649 KB). El segundo bloque descifrado (664,535 bytes) contiene la lógica del ladrón y se ejecuta en el binario de Bun descargado, no en el proceso de Node.js que inició la instalación.
Ejecutar la lógica principal en un binario de Bun descargado, en lugar de en el proceso node que inició la instalación, es una táctica deliberada de evasión: la supervisión limitada a procesos secundarios de Node.js durante npm install no detectará el proceso de Bun que realiza el trabajo real. Esto también explica por qué un análisis de cadenas de texto sin procesar de index.js no encuentra credenciales ni indicadores de C2: ese comportamiento está dentro del bloque que ejecuta Bun. No ejecutamos esa etapa final de Bun, por lo que el catálogo de comportamientos que sigue refleja el análisis reportado públicamente.
Robo de credenciales
Una vez ejecutada, la carga útil busca secretos en los entornos de desarrollo y CI/CD, con estos objetivos:
AWS:
aws_access_key_id/aws_secret_access_keyy el endpoint de metadatos IMDSv2 (169.254.169.254)GCP:
GOOGLE_APPLICATION_CREDENTIALSy claves de cuentas de servicioAzure: tokens de identidad administrada mediante IMDS
GitHub Actions:
ACTIONS_ID_TOKEN_REQUEST_TOKENy extracción de datos de la memoria de los procesos del ejecutorHashiCorp Vault y Kubernetes: tokens de cuentas de servicio obtenidos de rutas estándar.
Administradores de contraseñas: almacenes de 1Password,
passygopass
En GitHub Actions, la carga útil extrae datos de la memoria de los procesos del ejecutor para recuperar secretos enmascarados y dejarlos sin enmascarar, mediante un patrón como este:
El enmascaramiento de secretos de GitHub Actions los oculta en los registros; no los protege de un proceso que pueda leer directamente la memoria del ejecutor. Debes considerar expuesto cualquier secreto al que el ejecutor pueda acceder.
Exfiltración mediante repositorios de GitHub
En vez de usar un dominio C2 fijo, el malware usa GitHub como punto de encuentro y buzón oculto. La actividad se ha vinculado a la cuenta de GitHub liuende501, que al momento de redactar esto aloja 321 repositorios públicos (api.github.com/users/liuende501), en consonancia con el patrón del gusano de crear repositorios mediante programación para recibir datos robados. El proceso:
Encuentra el punto de encuentro al buscar una palabra clave codificada en los commits públicos
Crea sobre la marcha un repositorio con un nombre aleatorio
Sube los datos robados cifrados como
results/results-{timestamp}.jsonEnvía solicitudes a la API con el User-Agent
python-requests/2.31.0
Usar GitHub para exfiltrar datos mezcla el tráfico con la actividad normal de desarrollo y CI, ya que las conexiones salientes a github.com y api.github.com rara vez se bloquean en entornos de compilación.
Propagación del gusano entre ecosistemas
La carga útil se propaga por sí sola y cuenta con motores independientes para cada ecosistema:
Gusano de npm: enumera los paquetes de un mantenedor mediante
registry.npmjs.org/-/v1/search?text=maintainer:{username}, descarga cada objetivo, inyecta el archivo maliciosobinding.gypyindex.js, y vuelve a publicar los paquetes. En consonancia con olas anteriores de esta familia (consulta la cobertura de Snyk sobre TanStack, el primer paquete malicioso documentado de npm que incluía procedencia SLSA válida), el gusano también falsifica atestaciones de procedencia de Sigstore mediante Fulcio y Rekor, para que los paquetes reinfectados parezcan estar firmados legítimamente.Gusano de RubyGems: inyecta lógica equivalente en
extconf.rb, el enlace de compilación de extensiones nativas de RubyGems, y reutiliza el mismo descargador de Bun.extconf.rbcumple en RubyGems una función equivalente a la debinding.gypen npm: es un archivo de compilación que se ejecuta automáticamente y no es un «script» en el sentido de los scripts del ciclo de vida.Envenenamiento de repositorios de GitHub: agrega archivos con puertas traseras a los repositorios en los que los tokens robados tienen permisos de escritura, incluidos hooks de agentes de programación con IA y editores (
.claude/,.cursor/rules/,.vscode/tasks.json) que vuelven a ejecutar la carga útil cuando un desarrollador abre el proyecto.
El alcance entre ecosistemas (npm y RubyGems) y la reutilización de archivos de extensión en tiempo de compilación en ambos son el hilo conductor de esta campaña: encontrar el archivo que se ejecuta automáticamente durante la instalación o compilación, pero que nadie clasifica como un "script".
Análisis del impacto
El alcance directo del ataque incluye cualquier equipo de desarrollador o ejecutor de CI que haya ejecutado npm install y resuelto una de las versiones de paquetes afectadas. Los entornos de CI/CD corren el mayor riesgo, porque el robo de datos de la memoria del ejecutor implica que debe considerarse comprometido todo secreto al que este pueda acceder, no solo los que se pasan como variables de entorno explícitas.
Los equipos de desarrolladores corren un riesgo secundario y más duradero debido a los hooks del editor y del agente de IA, que sobreviven a un simple npm uninstall y vuelven a ejecutar la carga útil en la siguiente sesión.
La probabilidad de que siga propagándose parece menor que en el punto más alto de la campaña: los paquetes afectados se remontan a un pequeño número de cuentas de mantenedores (confirmamos que los 25 paquetes autotel y autotel-* comparten una sola cuenta, jagreehal), y no se han observado lanzamientos nuevos comprometidos recientemente. Aun así, las versiones maliciosas siguen disponibles para instalar desde npm, por lo que el riesgo de exposición persiste para quienes las obtengan, de forma directa o transitiva, antes de que se eliminen por completo.
Detección
Analiza con Snyk. Snyk publicó avisos sobre las versiones afectadas en la Snyk Vulnerability Database y habilitó una página del incidente en security.snyk.io/node-gyp-supply-chain-compromise-june-2026. Analiza tu proyecto:
Para analizar un manifiesto o archivo de bloqueo específico:
Busca la técnica, no solo los nombres de los paquetes. Como la ruta de ejecución es binding.gyp, puedes buscarla independientemente de la lista de paquetes:
Indicadores de red y comportamiento:
Se ejecuta
node-gyp rebuildpara paquetes que no tienen ningún complemento nativo legítimoSe inician procesos secundarios inesperados (
curl,unzip,bun) durantenpm installSe descarga un binario independiente de
bundesde las versiones deoven-sh/bundurante la instalación, aunque nunca hayas solicitado BunLlamadas a la API de GitHub con un User-Agent
python-requests/2.31.0que se originan en un paso de CI que no es un proceso de Python
Mitigación
Si no tienes certeza de si te afectó, considéralo un compromiso confirmado. Los datos recolectados se cifran antes de exfiltrarlos, por lo que no puedes determinar a posteriori qué se robó.
Paso 1: Elimina la persistencia antes de rotar los tokens. Si se instalaron hooks del editor o del agente de IA, elimínalos primero para que no reaccionen a los cambios de credenciales:
Paso 2: Limpia y reinstala con versiones confiables.
--ignore-scripts bloquea el hook implícito de instalación de npm que ejecuta node-gyp rebuild para los paquetes con binding.gyp. Sin embargo, no debe considerarse la única protección: el paquete malicioso aún podría descargarse y descomprimirse, otras herramientas o una ejecución posterior de npm rebuild sin --ignore-scripts podrían compilarlo, y otros administradores de paquetes o flujos de trabajo podrían comportarse de otra manera. La mitigación más segura sigue siendo fijar versiones seguras, eliminar las maliciosas y analizar antes de cualquier paso de compilación.
Paso 3: Rota todas las credenciales a las que pueda acceder un equipo o ejecutor afectado:
Tokens de publicación de npm
Tokens de acceso personal de GitHub y secretos de Actions (con alcance de repositorio y organización)
Claves de acceso de AWS y cualquier rol de IAM accesible desde los ejecutores afectados
Claves de cuentas de servicio de GCP
Entidades de servicio de Azure y alcances de identidad administrada
Tokens de HashiCorp Vault
Tokens de cuentas de servicio de Kubernetes
Cualquier elemento de un almacén de administrador de contraseñas al que se haya apuntado (1Password,
pass,gopass)
Paso 4: Audita GitHub en busca de flujos de trabajo inyectados y repositorios de entrega.
Paso 5: Refuerza tus defensas contra la próxima ola.
Usa por defecto
npm install --ignore-scriptsen CI (es una práctica recomendada para protegerte contra la familia más amplia de ataques durante la instalación) y combínalo con un control de análisisFija las dependencias en versiones exactas con hashes de integridad en el archivo de bloqueo
Considera una política de período de espera del registro que retenga los paquetes publicados en los últimos días antes de permitir que se usen en compilaciones
Aplica el principio de privilegio mínimo al alcance de los tokens de CI/CD para que un solo token robado tenga un impacto limitado
Usa Snyk para monitorear continuamente tu árbol de dependencias y detectar paquetes maliciosos cuando se señalen
La guía de Snyk para prevenir ataques a la cadena de suministro de npm incluye una lista de verificación más amplia.
La perspectiva general: un descendiente de Shai-Hulud
Esta es la ola más reciente del linaje Shai-Hulud / Miasma, una familia de gusanos de npm que se autopropagan y que ha atacado el registro repetidamente desde finales de 2025. Snyk cubrió una ola anterior de Miasma, en junio de 2026, que afectó a paquetes de npm de Red Hat; las descripciones de los repositorios de exfiltración usados en estas olas hacen referencia directa a las campañas anteriores de Shai-Hulud. Cada ola ha reutilizado un programa ladrón ofuscado que funciona en el entorno de ejecución Bun, y lo ha ampliado con nuevos mecanismos de persistencia, nuevas rutas de exfiltración y nuevas formas de ejecutar código automáticamente durante la instalación o compilación. La evolución de ese truco de ejecución automática es lo que conviene tener presente:
Las olas anteriores se basaban en scripts del ciclo de vida
preinstall/postinstallLas olas posteriores agregaron hooks de agentes de programación con IA (
SessionStart) y tareas del IDE al abrir carpetas para mantener la persistenciaEsta ola traslada la ejecución inicial a
binding.gyp/node-gyp(y aextconf.rben RubyGems), archivos de compilación que no son scripts del ciclo de vida
Snyk ha cubierto en detalle olas anteriores de esta familia de campañas:
Un programa ladrón basado en Bun afecta a los paquetes de npm SAP CAP-JS y MBT
Ataque a la cadena de suministro de npm mediante el compromiso de un mantenedor de código abierto
Para conocer la familia de gusanos de la que desciende este incidente:
Investigador de seguridad de Snyk explica el gusano de la cadena de suministro de npm Mini Shai-Hulud y cómo se propaga Mini Shai-Hulud: el ataque más sofisticado a la cadena de suministro de NPM de 2026 (Descripción general de la familia de gusanos Shai-Hulud / Miasma y de cómo se autopropaga)
Para ver una guía práctica sobre cómo encontrar y corregir paquetes comprometidos de esta familia de campañas con Snyk:
Ingeniero de seguridad de Snyk muestra cómo identificar y mitigar paquetes de npm comprometidos por Shai-Hulud con la CLI de Snyk Ataque Shai-Hulud a NPM: mitigación con Snyk - Guía práctica para identificar y mitigar paquetes comprometidos con las herramientas de Snyk.
Para conocer el contexto de cómo el compromiso de un paquete legítimo y confiable encaja en el modelo más amplio de amenazas a la cadena de suministro, la lección de Snyk Learn sobre Compromiso de paquetes legítimos es una buena introducción.
Cronología (UTC)
Fecha | Evento |
|---|---|
1 de junio de 2026 | Una variante anterior de Miasma compromete otro grupo de paquetes de npm (relacionados con Red Hat) |
3 de junio de 2026 | Ola principal: |
3 de junio de 2026 (en adelante) | Se publica el análisis técnico público de la técnica "Phantom Gyp"; Snyk publica avisos y una página del incidente en vivo |
En curso | La investigación continúa; las versiones maliciosas siguen disponibles en npm hasta que se eliminen |
Cobertura de Snyk
Snyk publicó avisos sobre las versiones afectadas en la Snyk Vulnerability Database y mantiene una página del incidente en vivo que enumera los 57 paquetes y sus versiones maliciosas. Los clientes de Snyk pueden usar los análisis de Snyk en todo el SDLC para identificar qué proyectos obtienen versiones afectadas, de forma directa o transitiva, y priorizar la mitigación según el nivel de exposición.
Consulta Snyk Vulnerability DB
Datos confiables e información práctica para ayudarte a desarrollar software de forma segura.
