TL; DR
El 14 de septiembre de 2025, los investigadores identificaron Shai Hulud, un gusano autorreplicante escondido en su interior paquetes npm, convirtiendo una actualización de dependencia rutinaria en una a gran escala ataque a la cadena de suministro. Visto por primera vez en el @ctrl/tinycolor Paquete de Daniel dos Santos Pereira: Shai-Hulud recopila Secretos, los exfiltra a través de repositorios y flujos de trabajo de GitHub y se republica en el registro utilizando credenciales robadas. En cuestión de días, el número de paquetes infectados pasó de docenas a cientos, lo que confirma que... Shaihulud No es simplemente otro troyano, sino un gusano diseñado para propagarse automáticamente por el ecosistema npm.
Repercusiones: Cualquier desarrollador o ejecutor de CI que instale paquetes npm públicos está en riesgo.
Acciones inmediatas: bloquear versiones conocidas, cambiar a instalaciones solo de archivo de bloqueo, rotar tokens npm y GitHub, auditar flujos de trabajo y monitorear indicadores de compromiso (IoC).
¿Qué sucedió?
El Ataque a la cadena de suministro de Shai-Hulud en paquetes npm es uno de los incidentes más disruptivos de los últimos tiempos. A diferencia de los troyanos aislados, este gusano combina... Robo de credenciales, exfiltración automatizada y autorreplicaciónEn consecuencia, el tiempo de infección se redujo de semanas a solo horas.
Para los equipos de DevOps, la lección es clara: si cada instalación puede ejecutar código, entonces cada actualización de dependencia es un punto de violación potencial.
Posible vector inicial y credenciales específicas
Análisis temprano Indica que el ataque probablemente comenzó con credenciales robadasPor ejemplo, campañas de phishing que suplantan npm login Es posible que las solicitudes de MFA hayan capturado tokens de desarrollador. Una vez que los atacantes lograron establecerse, el gusano se propagó integrándose en paquetes npm y robando más Secretos de:
- archivos de configuración de npm como
.npmrc, que a menudo contienen tokens de publicación. - Variables de entorno y configuraciones con PAT de GitHub y CI/CD Secretos.
- Puntos finales de metadatos en la nube (AWS, GCP, Azure) que generan credenciales de corta duración para el movimiento lateral.
Por lo tanto, el robo de credenciales se convirtió en la plataforma de lanzamiento. Con tokens npm válidos y GitHub Secretos, Shai-Hulud pudo autorreplicarse en múltiples paquetes y repositorios sin esfuerzo humano adicional.
Impacto ejecutivo del ataque a la cadena de suministro de Shai-Hulud
Shai-Hulud sigue activo hoy en día. Este gusano acelera el impacto. Lo que antes tardaba semanas con un troyano ahora se desarrolla en horas. Como resultado, La propagación es más rápida y más difícil de contener. Avanza mediante:
- Robo de tokens de publicación de npm y secretos de GitHub.
- Republicarse en otros paquetes npm.
- Agregar flujos de trabajo de GitHub Actions maliciosos para persistencia.
Quién se ve afectado:
Cualquier equipo que instale paquetes npm públicos está expuesto. Además, los desarrolladores con tokens npm o de GitHub en caché se enfrentan a un alto riesgo. Los ejecutores de CI que usan Secretos de amplio alcance también son vulnerables.
Riesgo del negocio
El impacto comercial crece rápidamente. Los tokens robados pueden provocar la apropiación de cuentas, el secuestro de paquetes e incluso el uso indebido de la nube. Además, la persistencia en los flujos de trabajo de GitHub dificulta la limpieza. Por lo tanto,Los equipos deben tratar Shai-Hulud como un incidente en curso, no como uno cerrado.
Cómo funciona el ataque a la cadena de suministro Shai-Hulud en paquetes npm
Objetivos y motivos del atacante
La campaña se optimiza para tres cosas:
- El primer objetivo es robar credenciales a gran escala Desde computadoras portátiles de desarrolladores y ejecutores de integración continua (CI). Esto incluye tokens de publicación de npm, tokens de GitHub y credenciales en la nube. De hecho, múltiples análisis confirman la recolección sistemática de datos de Secreto, como la ejecución de TruffleHog y la consulta de puntos finales de metadatos en la nube.
- El segundo objetivo es propagarse automáticamente Abusando de los derechos de publicación de los mantenedores comprometidos. Como resultado, una plataforma se expande rápidamente a muchas, ya que aparecen nuevas versiones infectadas de otros paquetes sin intervención humana adicional.
- El tercer objetivo es Persistir y exfiltrarse de forma fiable A través de la infraestructura de GitHub, los atacantes crean un repositorio público llamado "Shai-Hulud" con un doble base64. datos.json, y además implantan un flujo de trabajo que serializa ${{ toJSON(Secretos) }} y lo publica en un webhook estático.
La probable recompensa incluye acceso duradero a los registros y al código fuente, un rápido movimiento lateral hacia cuentas en la nube y la opción de instrumentalizar aún más la cadena de suministro. Los informes públicos muestran que los repositorios privados se convirtieron en públicos con... "-migración" sufijo, que aumenta la exposición y el impulso de los datos
Dentro de la carga útil de Shai-Hulud: paquete.js en paquetes npm
Los barcos Shai-Hulud son grande, empaquetado en Webpack y muy minimizado Archivo JavaScript (paquete.js, alrededor de 3–3.7 MB) que se ejecuta desde un postinstalación enganchar package.json. Como consecuencia, Cada instalación activa la carga útil automáticamente. Este diseño oculta los identificadores, comprime el flujo de control y concentra toda la lógica en un único artefacto que se ejecuta durante la instalación. Los analistas confirman sistemáticamente la agrupación de Webpack, el tamaño inusual de los archivos y la ejecución durante la instalación.
Rasgos de ofuscación y antianálisis que verás en las muestras:
- Gráfico de módulo minimizado con identificadores de módulo numéricos, comentarios dispersos y un flujo de control simplificado. Además, Esta estructura hace que la revisión manual sea extremadamente difícil.
- Ocultación de cadenas mediante capas base64 y ayudantes de construcción. Por ejemplo, La codificación y decodificación base64 repetidas suelen aparecer alrededor de las rutinas de exfiltración.
- Despacho dinámico atravesar eval-patrones de estilo y cuerpos de funciones generados, lo que permite que el código cambie el comportamiento en tiempo de ejecución.
- Filtrado del sistema operativo preferir la ejecución de Linux y macOS, particularmente en ejecutores CI y computadoras portátiles para desarrolladores.
Desde un punto de vista funcional, el paquete es modular. Los informes describen módulos para el descubrimiento del sistema operativo, escaneos del sistema de archivos y Git Secreto, acceso al SDK en la nube, operaciones de la API de GitHub y un motor de propagación que edita otros paquetes propiedad del responsable. De hecho, StepSecurity y ReversingLabs destacan una función que actualiza automáticamente los paquetes con el gancho malicioso.
Ejecución en tiempo de instalación en Shai-Hulud: cómo los paquetes npm activan el gusano
El ataque comienza cuando La postinstalación ejecuta el nodo paquete.js. En este punto, el script inicializa y descomprime el estado de trabajo en la memoria, preparando el escenario para el funcionamiento completo del gusano.
Descubrimiento y cosecha
- La carga útil vuelca process.env y escanea los archivos locales en busca de secretos de alta entropía y prefijos de token. Además, amplía la cobertura ejecutando TruffleHog.
- Consulta los puntos finales de metadatos de la nube para recopilar credenciales de corta duración. Por ejemplo, llamadas a
169.254.169.254en AWS ometadata.google.internalLos GCP suelen aparecer en huéspedes infectados. - En consecuencia, cualquier credencial encontrada se vuelve inmediatamente utilizable para publicar nuevos paquetes npm o impulsar flujos de trabajo de GitHub.
exfiltración
- El gusano crea un nuevo repositorio de GitHub llamado Shai Hulud y escribe un doble codificado en base64
data.jsonCon detalles de la plataforma, volcados de entorno y Secretos. Como se puede ver, este comportamiento ruidoso es fácil de detectar si los defensores saben dónde buscar. - También planta un flujo de trabajo de GitHub Actions, a menudo en una rama llamada Shai-hulud, que serializa
${{ toJSON(Secretos) }}y publica los datos en un webhook estático. Además, este flujo de trabajo persiste hasta que alguien lo elimine activamente.
Propagación
- Con cualquier token npm detectado, la carga útil enumera todos los paquetes propiedad del mantenedor comprometido. Luego, recupera cada archivo tar, inyecta bundle.js y una entrada postinstall, y republica el paquete.
- Como resultado, pueden aparecer docenas de paquetes infectados en cuestión de horas, multiplicando el radio de explosión en todo el ecosistema.
Persistencia y exposición
El gusano mantiene activos los flujos de trabajo maliciosos y, en varios casos, convierte repositorios privados en públicos con un "-migración" Sufijo. En conjunto, esto garantiza que el atacante mantenga su posición y maximice la fuga de datos.
Nota de detección de clave
Este uso inusual de ${{ toJSON(Secretos) }} En los flujos de trabajo de acciones es poco común. De esta manera, las Los equipos deben tratarlo como un indicador de alta señal durante las cacerías.
Patrón de flujo de trabajo desinfectado que debes buscar
Este uso inusual de a JSON(Secretos) En Acciones hay un indicador de alta señal en este incidente.
Pseudocódigo de propagación de alto nivel (seguro, descriptivo)
async function propagate(token, owner) {
const pkgs = await npmApi.listPackages(owner, token);
for (const p of pkgs) {
const tgz = await npmApi.fetchTarball(p, token);
const modified = injectBundleAndPostinstall(tgz); // adds bundle.js + "postinstall"
await npmApi.publish(modified, token); // publishes new malicious version
}
}
Los analistas observaron este bucle a gran escala, lo que explica el rápido salto de docenas a cientos de paquetes infectados.
¿Por qué esto es un gusano en un ecosistema de paquetes?
Un gusano es malware que se propaga por sí solo sin necesidad de intervención manual del operador en cada etapa. En los sistemas operativos, los gusanos suelen aprovechar las vulnerabilidades de la red para propagarse de una máquina a otra. En cambio, Shai-Hulud opera dentro del registro npm. Su ruta de acceso eficiente es a través de... reutilización de credenciales.
El gusano aprovecha los tokens de publicación de npm robados. En cuanto obtiene credenciales válidas, republica las versiones infectadas en otros paquetes propiedad del mismo mantenedor. Posteriormente, esos paquetes son instalados por desarrolladores o ejecutores de CI desprevenidos, y el ciclo se repite.
Por esta razón, los analistas de seguridad, incluidos Lectura oscura, clasificar a Shai-Hulud como un gusano autorreplicante En lugar de un simple troyano o un incidente de typosquatting, la diferencia es importante: un troyano suele comprometer un host, pero un gusano amplifica su impacto automáticamente en todo el ecosistema.
Hoja de trucos sobre cómo funciona
Para resumir el ciclo de vida de Shai-Hulud, aquí hay una estafa:cisEl desglose de sus principales pasos:
- Un paquete con postinstalación está instalado y
bundle.jsejecuta. - La carga útil vuelca las variables de entorno, escanea archivos y el historial de Git, se ejecuta Trufa de cerdoy consulta los servicios de metadatos en la nube. Por lo tanto, cualquier Secreto encontrado resulta inmediatamente útil.
- La exfiltración ocurre de dos maneras: primero, creando un repositorio público llamado Shai Hulud con una codificación doble base64
data.json; segundo, al plantar un flujo de trabajo de GitHub Actions que publique${{ toJSON(Secretos) }}a un webhook. - Usando cualquier token npm robado, el gusano republica todos los demás paquetes propiedad del mantenedor comprometido con el mismo gancho malicioso. De esta forma, la infección se multiplica rápidamente.
- Finalmente, el atacante tiene más secretos, más paquetes para distribuir y persistencia Dentro de cuentas y repositorios de GitHub.
¿Cómo evitar esta clase de ataque, en la práctica?
Shai-Hulud es una llamada de atención. Un gusano que roba tokens y se republica no es un riesgo futuro, está activo en el... ecosistema de paquetes npm Hoy. Para prevenir este tipo de ataque a la cadena de suministroLos equipos necesitan controles que sean programables, automatizados y aplicados directamente en CI/CD pipelines. Estas son las mismas defensas que ya puedes implementar con xygeni.
Detenga los artefactos malos en la puerta
Debes escanear los paquetes npm y los archivos tar antes de que lleguen a los desarrolladores o a los trabajos de integración continua. bundle.js archivos, postinstalación sospechosa hooksLos marcadores de ofuscación sirven como señales de alerta temprana. Además, se aplican períodos de enfriamiento y versiones fijadas en pipelines evita que se consuman automáticamente versiones nuevas y no verificadas.
Endurecer CI/CD por defecto
Guardrails in CI/CD Son esenciales. Rechazan las fusiones o instalaciones que introducen nuevos scripts o binarios. Al mismo tiempo, bloquean los flujos de trabajo que serializan Secretos o intentan publicaciones externas. Los equipos también deberían exigir instalaciones que solo incluyan archivos de bloqueo (npm ci) en todos pipelineDe esta manera, los conjuntos de dependencias siguen siendo reproducibles y seguros.
Reducir el radio de explosión del token
Los secretos no deben convertirse en puntos únicos de fallo. Escanee continuamente el código, las configuraciones y... pipeline salida para credenciales expuestasLos tokens deben tener un alcance limitado, una vida útil corta y rotarse automáticamente al detectar exposición. Como regla general, cualquier token utilizado en un host que haya ejecutado una postinstalación sospechosa debe considerarse comprometido.
Observar el comportamiento del gusano de forma temprana
Detección de anomalías Es clave. Por ejemplo, picos repentinos en los eventos de publicación de npm, nuevos flujos de trabajo que aparecen sin motivo o nuevos repositorios públicos llenos de archivos codificados de forma extraña pueden indicar la actividad de un gusano. Por lo tanto, los equipos deben generar alertas rápidamente y aislar a cualquier mantenedor o ejecutor que muestre estas señales de advertencia.
Arreglar rápidamente sin romper compilaciones
La velocidad y la seguridad deben ir de la mano. Automatizado pull requests Puede reemplazar paquetes npm comprometidos con versiones verificadas. Además, accesibilidad y explotabilidad El análisis garantiza que las actualizaciones se mantengan mínimas y estables. Finalmente, se reconstruyen los ejecutores de CI afectados a partir de imágenes limpias una vez confirmada la exposición, lo que evita que el ataque se propague.
Indicadores de compromiso (IoC)
Al analizar Shai-Hulud, los equipos deben prestar atención a ambos IoC estáticos en archivos y IoC de comportamiento in pipelineEn conjunto, estas señales ayudan a detectar infecciones de forma temprana y a responder antes de que el gusano se propague más.
IoC estáticos
Los siguientes resúmenes SHA-256 coinciden con lo observado bundle.js muestras:
- 46faab8ab153fae6e80e7cca38eab363075bb524edd79e42269217a083628f09
- 81d2a004a1bca6ef87a1caf7d0e0b355ad1764238e40ff6d1b1cb77ad4f595c3
- dc67467a39b70d1cd4c1f7f7a459b35058163592f4a9e8fb4dffcbba98ef210c
Además, esté atento a estos patrones recurrentes:
- A
bundle.jsen la raíz del paquete. "postinstall": "node bundle.js"interiorpackage.json.- Repositorios nombrados Shai Hulud.
- Flujos de trabajo de GitHub que contienen
${{ toJSON(Secretos) }}.
IoC de comportamiento
Más allá de las firmas de archivo, la actividad de los gusanos se revela a través del comportamiento. Por ejemplo:
- Ráfagas repentinas de eventos de publicación de npm por parte de un mantenedor.
- Nuevos flujos de trabajo que envían datos a puntos finales externos.
- Solicitudes POST salientes activadas desde ejecutores de CI.
- Repositorios públicos creados recientemente con blobs codificados.
Cacerías rápidas
# Find postinstall in package.json
grep -R --line-number '"postinstall"' --include="package.json" /path/to/archives
# Detect tarballs with bundle.js
find /path/to/tarballs -name "*.tgz" -print0 \
| xargs -0 -n1 -I{} sh -c 'tar -tf "{}" | grep bundle.js && echo "== {}"'
# Search workflows for toJSON(Secretos)
grep -R --line-number "toJSON(Secretos)" --include="*.yml" .github || true
Conclusión: Lecciones de Shai-Hulud
El Ataque a la cadena de suministro de Shai-Hulud La vulnerabilidad en los paquetes npm muestra la fragilidad actual de la cadena de suministro de software. Este gusano no se limitó a añadir código malicioso: robó tokens, envió datos y se republicó automáticamente. Por ello, el ataque se propagó en cuestión de horas en lugar de semanas.
Para los desarrolladores y los equipos de DevOps, las lecciones son claras:
- Cada instalación ejecuta código. Incluso un paquete npm común puede ocultar un gusano postinstalación.
- Cada token tiene un alto valor. Una vez robado, puede usarse para propagar aún más malware.
- Cada plan pipeline Necesita controles. Sin guardrails En cuanto a dependencias, flujos de trabajo y Secretos, un compromiso puede afectar rápidamente la producción.
Por lo tanto, detener ataques como Shai-Hulud requiere controles automáticos y fáciles de implementar. Los equipos deben escanear los paquetes npm antes de las instalaciones, usar compilaciones con archivos de bloqueo, detectar actividades de publicación extrañas y mantener los tokens con una vida útil corta. Estos pasos ya no son opcionales. En cambio, son la base de la resiliencia en la era moderna. pipelines.
En Xygeni, consideramos el ataque a la cadena de suministro de Shai-Hulud como una advertencia para todo el ecosistema de código abierto. El camino sostenible a seguir es integrar la seguridad de la cadena de suministro directamente en el proceso de desarrollo, en el punto donde se procesan el código, los paquetes npm y... pipelines conectar.
A continuación se muestra la lista completa de paquetes y versiones de npm reportados como comprometidos en Shai-Hulud. Úsela para revisar sus archivos de bloqueo, registros y CI. pipelines para exposición.
Lista de paquetes comprometidos
📦 Vista previa de paquetes npm comprometidos
| Nombre del paquete | Versión | Fecha de publicación |
|---|---|---|
| motor de reglas json simplificado | 0.2.1 | 2025-09-14T17:58:51.203Z |
| piloto aéreo | 0.8.8 | 2025-09-14T18:35:07.600Z |
| gráfico de conocimiento mcp | 1.2.1 | 2025-09-14T18:35:09.494Z |
| jefe de vuelo | 0.3.1 | 2025-09-14T18:35:09.521Z |
| puerta de salto | 0.0.2 | 2025-09-14T18:35:09.651Z |
| tvi-cli | 0.1.5 | 2025-09-14T18:35:10.996Z |
| @thangved/ventana-de-devolución-de-llamada | 1.1.4 | 2025-09-14T20:31:38.479Z |
| @tnf-dev/api | 1.0.8 | 2025-09-14T20:31:39.547Z |
| @tnf-dev/js | 1.0.8 | 2025-09-14T20:31:41.251Z |
| @tnf-dev/mui | 1.0.8 | 2025-09-14T20:31:41.259Z |
| @tnf-dev/núcleo | 1.0.8 | 2025-09-14T20:31:42.728Z |
| @teselagen/tabla-de-reacción | 6.10.20 | 2025-09-14T20:37:08.597Z |
| @hestjs/demo | 0.1.2 | 2025-09-14T20:45:52.348Z |
| @nexe/eslint-config | 0.1.1 | 2025-09-14T20:45:53.625Z |
| @hestjs/eslint-config | 0.1.2 | 2025-09-14T20:45:55.044Z |
| @nexe/administrador de configuración | 0.1.1 | 2025-09-14T20:45:55.066Z |
| @nexe/registrador | 0.1.3 | 2025-09-14T20:45:55.170Z |
| @hestjs/registrador | 0.1.6 | 2025-09-14T20:45:55.197Z |
| @hestjs/validación | 0.1.6 | 2025-09-14T20:45:55.595Z |
| @hestjs/núcleo | 0.2.1 | 2025-09-14T20:45:55.888Z |
➡️ Ver lista completa de paquetes comprometidos
| Nombre del paquete | Versión | Fecha de publicación |
|---|---|---|
| motor de reglas json simplificado | 0.2.1 | 2025-09-14T17:58:51.203Z |
| piloto aéreo | 0.8.8 | 2025-09-14T18:35:07.600Z |
| gráfico de conocimiento mcp | 1.2.1 | 2025-09-14T18:35:09.494Z |
| jefe de vuelo | 0.3.1 | 2025-09-14T18:35:09.521Z |
| puerta de salto | 0.0.2 | 2025-09-14T18:35:09.651Z |
| tvi-cli | 0.1.5 | 2025-09-14T18:35:10.996Z |
| @thangved/ventana-de-devolución-de-llamada | 1.1.4 | 2025-09-14T20:31:38.479Z |
| @tnf-dev/api | 1.0.8 | 2025-09-14T20:31:39.547Z |
| @tnf-dev/js | 1.0.8 | 2025-09-14T20:31:41.251Z |
| @tnf-dev/mui | 1.0.8 | 2025-09-14T20:31:41.259Z |
| @tnf-dev/núcleo | 1.0.8 | 2025-09-14T20:31:42.728Z |
| @teselagen/tabla-de-reacción | 6.10.20 | 2025-09-14T20:37:08.597Z |
| @hestjs/demo | 0.1.2 | 2025-09-14T20:45:52.348Z |
| @nexe/eslint-config | 0.1.1 | 2025-09-14T20:45:53.625Z |
| @hestjs/eslint-config | 0.1.2 | 2025-09-14T20:45:55.044Z |
| @nexe/administrador de configuración | 0.1.1 | 2025-09-14T20:45:55.066Z |
| @nexe/registrador | 0.1.3 | 2025-09-14T20:45:55.170Z |
| @hestjs/registrador | 0.1.6 | 2025-09-14T20:45:55.197Z |
| @hestjs/validación | 0.1.6 | 2025-09-14T20:45:55.595Z |
| @hestjs/núcleo | 0.2.1 | 2025-09-14T20:45:55.888Z |
| @hestjs/cqrs | 0.1.6 | 2025-09-14T20:45:55.966Z |
| @hestjs/escalar | 0.1.7 | 2025-09-14T20:45:56.386Z |
| carga de archivos ng2 | 7.0.3 | 2025-09-15T02:44:29.555Z |
| manejador de notificaciones de condensadores | 0.0.2 | 2025-09-15T04:54:48.431Z |
| complemento de condensador de vonage | 1.0.2 | 2025-09-15T04:54:48.501Z |
| complemento de salud para condensadores | 0.0.2 | 2025-09-15T04:54:48.704Z |
| permisos de capacitorandroid | 0.0.4 | 2025-09-15T04:54:48.753Z |
| kit de llamadas VoIP | 1.0.2 | 2025-09-15T04:54:49.223Z |
| complemento de condensador de ihealth | 1.1.8 | 2025-09-15T04:55:08.113Z |
| @art-ws/común | 2.0.22 | 2025-09-15T05:21:15.411Z |
| @art-ws/config-eslint | 2.0.4 | 2025-09-15T05:21:17.199Z |
| ngx-ws | 1.1.5 | 2025-09-15T05:21:17.514Z |
| @arte-ws/slf | 2.0.15 | 2025-09-15T05:21:17.524Z |
| @art-ws/servidor http | 2.0.21 | 2025-09-15T05:21:17.745Z |
| pm2-gelf-json | 1.0.4 | 2025-09-15T05:21:18.413Z |
| @arte-ws/di | 2.0.28 | 2025-09-15T05:21:18.488Z |
| @art-ws/di-node | 2.0.13 | 2025-09-15T05:21:18.849Z |
| @art-ws/config-ts | 2.0.7 | 2025-09-15T05:21:19.408Z |
| @art-ws/db-context | 2.0.21 | 2025-09-15T05:21:19.814Z |
| @art-ws/openapi | 0.1.9 | 2025-09-15T05:21:19.969Z |
| @art-ws/aplicación web | 1.0.3 | 2025-09-15T05:21:20.383Z |
| @art-ws/ssl-info | 1.0.9 | 2025-09-15T05:21:20.927Z |



