Terminal mostrando npm audit con cientos de paquetes maliciosos detectados tras el ataque Mini Shai-Hulud
Volver al blog

Mini Shai-Hulud: el peor ataque npm del año

El 11 de mayo de 2026 un worm comprometió 170+ paquetes npm y PyPI incluyendo TanStack Router, Mistral AI SDK y UiPath. 404 versiones maliciosas, OIDC trusted publishing roto, y el primer caso documentado con SLSA provenance válida. Acciones inmediatas para tu proyecto.

El 11 de mayo de 2026, entre las 19:20 y 19:26 UTC — seis minutos — un atacante publicó 84 artefactos npm maliciosos en 42 paquetes del namespace @tanstack, todos firmados con la identidad legítima del pipeline de release de TanStack. Esos seis minutos abrieron la peor crisis de supply chain del ecosistema npm en 2026: más de 170 paquetes comprometidos, 404 versiones maliciosas, y la primera vez en la historia que un paquete malicioso lleva una SLSA provenance válida. Si tu app usa @tanstack/react-router, @tanstack/react-query, el SDK oficial de Mistral AI o cualquiera de los 65 paquetes de UiPath, este post es la guía de respuesta inmediata.

El ataque, bautizado Mini Shai-Hulud por su parecido con la campaña original de septiembre de 2025, no robó credenciales del mantenedor. Hizo algo más sutil y más peligroso: secuestró el runner de GitHub Actions a mitad del workflow oficial, después de que el OIDC ya había firmado la identidad. Para el registry de npm, los paquetes maliciosos fueron publicados por TanStack, no por un atacante. Las defensas tradicionales — 2FA, rotación de tokens, hardware keys — no protegen contra esto. Te explicamos qué pasó, cómo verificar si estás afectado, y qué cambia ahora en la forma de proteger una pipeline de release.

Qué pasó exactamente

La cronología pública, reconstruida a partir de los reportes de Snyk, Wiz y StepSecurity:

  1. Reconocimiento. El atacante (atribuido al grupo TeamPCP por StepSecurity) forkeó el repo TanStack/router en GitHub y estudió el workflow de release.
  2. Trigger del workflow. Abrió un pull request que ejecuta el workflow pull_request_target — un trigger que corre con permisos del repo original, no del fork.
  3. Cache poisoning. El PR malicioso envenenó la caché de GitHub Actions con un pnpm store modificado, conteniendo dependencias troyanizadas.
  4. Ejecución legítima del release. Cuando el mantenedor de TanStack ejecutó el workflow de release oficial — usando OIDC trusted publishing, la “mejor práctica” recomendada por GitHub y npm — el runner restauró la caché envenenada y publicó los paquetes con todas las firmas legítimas.
  5. Worm phase. Una vez instalados los paquetes maliciosos, el postinstall script intentó propagarse: leer tokens de npm del entorno y publicar versiones maliciosas de paquetes del mantenedor afectado.

El punto que hace este ataque histórico es el paso 4. Cualquier validador automático — npm audit, GitHub provenance verify, Snyk, Socket — ve un paquete legítimo. La firma SLSA es válida. El publisher es el correcto. No hay forma técnica de distinguir el paquete malicioso del legítimo desde el lado del consumidor. La detección llegó por análisis manual del código después de que un usuario notó comportamiento raro.

Paquetes confirmados como comprometidos

La lista completa supera los 170. Estos son los de mayor impacto por descargas semanales:

PaqueteVersiones maliciosasDescargas semanalesAcción
@tanstack/react-router1.114.30 a 1.114.3412.7MPinear a 1.114.29 o subir a 1.114.50+
@tanstack/router-core1.114.30 a 1.114.3413M+Mismo rango
@tanstack/react-query5.62.10 a 5.62.1312M+Pinear a 5.62.9 o subir a 5.62.30+
@mistralai/mistralai1.4.0 a 1.4.2240KSubir a 1.4.10+
@uipath/sdk8.x corruptosVariableVerificar con UiPath security advisory
opensearchversiones de mayo 121.3MSubir a la versión post-incidente
guardrails-ai (PyPI)0.5.x80KRevertir a 0.4.x o subir

Lista completa actualizada en el aviso de Snyk y en el repo público de Wiz. Si tu CI corrió npm install o pnpm install entre el 11 y el 13 de mayo de 2026 sobre cualquiera de estos paquetes sin lockfile pineado, asumí que estás comprometido hasta probar lo contrario.

Cómo verificar si tu proyecto está afectado

Tres niveles de verificación, en orden de urgencia:

Paso 1: detectar versiones maliciosas en tu lockfile

npm ls @tanstack/react-router @tanstack/router-core @tanstack/react-query @mistralai/mistralai

Si el output muestra cualquier versión dentro de los rangos comprometidos de la tabla anterior, tenés contaminación local.

Para repos con pnpm o yarn:

pnpm why @tanstack/react-router
yarn why @tanstack/react-router

Paso 2: revisar tu pipeline de CI

Lo más importante: si tu pipeline ejecutó npm install durante la ventana del ataque sobre uno de los paquetes afectados, los secretos del CI quedaron expuestos. Lista mínima a rotar:

  • NPM_TOKEN
  • GITHUB_TOKEN (los que el workflow tuvo acceso, no el default ephemeral)
  • Cualquier variable de entorno con prefijo común (AWS_*, STRIPE_*, DATABASE_URL, claves de Anthropic / OpenAI / Mistral)
  • SSH keys montadas en el runner

GitHub publicó una guía oficial de rotación post-incidente — seguila al pie de la letra.

Paso 3: forensia del entorno local de developers

El payload del worm intentaba persistir en el equipo del developer que instalara los paquetes. Si un dev de tu equipo corrió npm install con uno de los paquetes afectados:

ls -la ~/.npmrc ~/.npm-init.js ~/.bashrc.d/ 2>/dev/null
crontab -l 2>/dev/null

Buscá referencias a binarios que no instalaste vos, jobs cron sospechosos, o líneas extra en archivos de shell. El “destructive daemon” del payload — diseñado para borrar $HOME en caso de detección — fue desactivado a las 48 horas del descubrimiento, pero la persistencia (no la destrucción) puede seguir activa.

Por qué el OIDC trusted publishing falló

GitHub y npm habían empujado “trusted publishing” como la solución definitiva al problema de tokens robados. La idea: en vez de que el mantenedor guarde un NPM_TOKEN en GitHub Secrets, npm valida la identidad del runner de GitHub Actions vía OIDC y le permite publicar sin token persistente. Si el atacante no compromete el repo, no puede publicar.

El ataque de Mini Shai-Hulud demuestra el agujero conceptual: OIDC verifica la identidad del runner, no la integridad del workflow. Si el atacante puede influir en lo que el runner ejecuta — vía cache poisoning, vía dependencias intermediarias, vía cualquier paso que se ejecute antes del npm publish — el OIDC sigue firmando, porque la identidad del runner sigue siendo legítima. La firma final dice “esto fue publicado por el workflow X del repo Y”, lo cual es cierto, pero el contenido fue inyectado por el atacante.

La consecuencia práctica: trusted publishing es necesario pero no suficiente. Tu pipeline también necesita:

  • Pin de versiones de cada acción (incluyendo SHAs, no tags) — actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29, no @v4.
  • Cache desactivado o estrictamente validado en workflows de release.
  • Trigger restringido a tags firmados con GPG, no a PRs ni a branches arbitrarias.
  • Aislamiento del runner — los workflows de release deberían correr en un runner self-hosted distinto al de CI normal, o en GitHub Actions con runs-on: ubuntu-latest pero permission scopes mínimos.
  • Auditoría humana del diff antes del release para releases ≥ 1.0.0 de cualquier paquete con más de 1M de descargas semanales.

Acciones inmediatas para tu equipo en LatAm

Si tu equipo o tu cliente usa Next.js, React, Astro o cualquier stack moderno de JavaScript, hay 70% de probabilidad de que tengas TanStack en el dependency graph aunque no lo hayas instalado directamente — react-query es transitividad común. Las cinco acciones que recomendamos correr hoy mismo:

  1. npm audit --production en todos los proyectos activos. Si aparece algo del listado, no mergees nada hasta tener un fix.
  2. Forzar --frozen-lockfile o --prefer-offline en todos los workflows de CI hasta nueva orden. Esto evita que npm install levante versiones nuevas no validadas.
  3. Rotar secrets del CI si tu pipeline corrió entre el 11 y el 13 de mayo de 2026. No esperes “ver si pasó algo” — los secrets exfiltrados pueden tardar meses en usarse.
  4. Configurar Socket o Snyk como pre-commit hook. Detectan paquetes recién publicados con scripts postinstall sospechosos. No son perfectos pero suben mucho la barra.
  5. Pin de SHA en acciones de GitHub. No @v4. Sí @a5ac7e51b41094c92402da3b24376905380afc29. Renovado manualmente con cada actualización validada.

Para clientes con productos en producción y compliance regulatorio (banca, salud, educación), añadir:

  • Reporte al CSIRT institucional con la lista de paquetes vulnerables y la ventana de exposición.
  • Documentación del incidente en el log de seguridad interno — la LOPDP ecuatoriana requiere notificar incidentes que afecten datos personales dentro de las 72 horas.

El problema sistémico que esto expone

Mini Shai-Hulud no es un evento aislado. Es la tercera generación de ataques de supply chain en npm contando Shai-Hulud original (sept 2025), event-stream (2018), y ua-parser-js (2021). El patrón es claro: cada generación encuentra una nueva capa de la pipeline que las defensas anteriores asumían segura.

La conclusión incómoda: el modelo actual de npm (publish-once-trust-forever, sin verificación independiente del contenido) está estructuralmente roto para paquetes de alto impacto. La solución a largo plazo probablemente sea alguna combinación de:

  • Verificación reproducible: el consumidor reconstruye el paquete desde fuente y compara hashes. Solo viable para paquetes con builds determinísticos.
  • Quórum de mantenedores: dos o más mantenedores firman cada release. Algo así como Maintainer Multi-Sig que NSF está incubando.
  • Period de observación: registries que retienen paquetes nuevos 24-48 horas antes de marcarlos como “stable” para npm install sin flag. Esto solo le sirve a usuarios pacientes.

Mientras tanto, el peso de la defensa cae sobre cada equipo individual. Es injusto y es la realidad. Si tu app maneja datos de usuarios — cualquier app, incluyendo las que parecen “no críticas” — tratá la pipeline de release con la misma seriedad que la pipeline de pagos. La diferencia con un breach por contraseña filtrada es que en este caso el atacante usa tu propia identidad como vector.

Casos análogos en el ecosistema LatAm

Aunque el ataque fue contra repositorios de Estados Unidos y Europa, las víctimas indirectas en LatAm son significativas. Un caso real que estamos viendo en clientes ecuatorianos:

  • E-commerce con Next.js + TanStack Query: el equipo tenía @tanstack/react-query sin pinear en package.json. El CI corrió pnpm install el 12 de mayo a las 03:42 hora Ecuador (UTC-5), traje la versión maliciosa, y desplegó a producción. Los secrets del runner — incluida la credencial de la base de datos PostgreSQL en RDS — quedaron expuestos durante 8 horas hasta que el equipo se enteró del incidente y bloqueó el workflow.
  • App fintech con Mistral AI integrado: 12 horas de exposición. El MISTRAL_API_KEY fue rotado al detectar el incidente; revisión de logs no mostró uso anómalo de la API, pero la incertidumbre obligó a auditar todas las transacciones procesadas durante la ventana.

Estos no son casos hipotéticos. Si tu equipo no tiene una respuesta para “¿qué hacemos cuando un paquete que ya está en producción resulta ser malicioso?”, este incidente es la motivación que faltaba para construir esa respuesta antes del próximo Shai-Hulud — porque va a haber un próximo.

Tabla resumen

PreguntaRespuesta corta
¿Cuándo ocurrió?11 de mayo de 2026, 19:20-19:26 UTC
¿Cuántos paquetes?170+ npm, 2 PyPI, 404 versiones maliciosas
¿Grupo atribuido?TeamPCP (según StepSecurity)
¿Vector principal?Cache poisoning de GitHub Actions vía pull_request_target
¿OIDC trusted publishing falló?Sí, primer caso documentado con SLSA provenance válida
¿Cómo verificar?npm ls sobre los paquetes de la tabla
¿Qué rotar?NPM_TOKEN, GITHUB_TOKEN, secrets del CI durante la ventana
¿Lecciones?Pin de SHA en acciones, cache desactivado en release workflows

Preguntas frecuentes

¿Mi proyecto está afectado si no uso TanStack directamente?
Posiblemente. TanStack Query es dependencia transitiva de muchos starters de Next.js, Remix y React modernos. Verificá con npm ls @tanstack/react-query y npm ls @tanstack/react-router en la raíz de tu repo. Si aparece cualquier versión dentro de los rangos comprometidos (1.114.30-1.114.34 para router, 5.62.10-5.62.13 para query), tu proyecto está afectado independientemente de que lo hayas instalado vos o lo haya traído otra dependencia.
¿Por qué OIDC trusted publishing no protegió contra este ataque?
OIDC verifica que el runner de GitHub Actions que publica es legítimo, pero no verifica que lo que el runner ejecuta es lo que el mantenedor espera. El atacante envenenó la caché del runner antes del paso de publish, así que cuando el workflow legítimo corrió, npm vio una identidad legítima publicando código que el mantenedor no autorizó. Es una distinción sutil pero clave: identidad firmada no es lo mismo que contenido firmado. La defensa requiere pinear cada paso del workflow, no solo el publish final.
¿Cómo rotar correctamente un NPM_TOKEN después del incidente?
Tres pasos: primero, generá un token nuevo en npmjs.com en Settings > Access Tokens, eligiendo el tipo correcto (Automation para CI). Segundo, actualizá el secret de GitHub Actions (Settings > Secrets and variables > Actions) con el nuevo valor. Tercero, y crítico, revocá el token viejo de inmediato desde la misma página de npm — si no lo revocás, sigue siendo válido aunque ya no lo uses. Adicionalmente, revisá los publish logs de tu paquete por publicaciones que no reconozcas.
¿Vale la pena migrar a Deno o Bun por seguridad después de esto?
Migrar de runtime no resuelve el problema raíz, que es la cadena de confianza en el registry. Deno y Bun tienen sus propios registries (deno.land/x, bun's npm-compatible) y sus propios riesgos. La defensa real está en el proceso de release, no en el runtime: pin de SHAs, cache validation, audit humano de releases críticas. Dicho eso, si ya estabas considerando migrar por otras razones (performance, simplicidad), este incidente le agrega un punto a favor.
¿Las herramientas como Snyk, Socket o Dependabot detectan este tipo de ataques?
Parcialmente. Snyk y Socket detectaron Mini Shai-Hulud en 4-6 horas analizando comportamiento postinstall sospechoso, pero no en el momento de la publicación — porque los paquetes pasaban todas las firmas de integridad. Dependabot no detectó nada hasta que las advisories oficiales se publicaron. La lección: estas herramientas son necesarias pero no suficientes. Sumá Socket como pre-install hook para tener detección comportamental antes de que el paquete llegue a tu node_modules.
¿Tengo que reportar este incidente al SRI o a alguna entidad ecuatoriana?
Si tu sistema afectado procesa datos personales bajo la LOPDP (Ley Orgánica de Protección de Datos Personales, vigente desde 2021), sí. El art. 47 obliga a notificar a la Superintendencia de Protección de Datos Personales dentro de 72 horas si hay un incidente que pueda afectar derechos de los titulares. Para sistemas que solo manejan datos internos sin información de clientes, la notificación es interna pero recomendada para audit trail. Consultá con tu equipo legal o un especialista en LOPDP si tenés dudas sobre el threshold de notificación.
¿Qué pasa con apps móviles que usan React Native con TanStack Query?
Si la app móvil se construyó entre el 11 y el 13 de mayo con una versión vulnerable, el bundle compilado contiene el código malicioso. Eso significa que cualquier usuario que tenga esa versión instalada puede ser víctima del worm. Acción inmediata: subir una versión patch a la App Store y Play Store con la dependencia corregida, y notificar a los usuarios para que actualicen. Como mitigación intermedia, considerá usar feature flags o config remoto para desactivar las features que dependen de la librería comprometida hasta que la nueva versión esté distribuida.
¿Cómo me preparo para el próximo ataque de supply chain?
Tres prácticas que mueven la aguja real: primero, pinear todo por SHA — no solo dependencies sino también acciones de GitHub. Es tedioso pero corta el 80% de los vectores. Segundo, separar el runner de release del runner de CI normal — el workflow que publica npm packages no debería compartir contexto con el que ejecuta tests. Tercero, instrumentar tu CI con logging detallado de qué se descarga durante install. Si algo cambia respecto a la última run, alerta humana antes de continuar. No previene todo pero detecta mucho.

Azirgo

¿Listo para construir tu Producto Digital?

Sitios web, apps móviles, software a medida y soluciones blockchain. Cuéntanos qué tienes en mente y armamos un plan claro contigo.

  • Cotización clara en 48 horas
  • Equipo en Ecuador, atención en español
  • Desde un MVP hasta un producto en producción