Mini Shai-Hulud golpea openapi-react-query-codegen: 10 versiones maliciosas, npm provenance y por qué TanStack Query no fue comprometido Skip to content

Mini Shai-Hulud golpea openapi-react-query-codegen: 10 versiones maliciosas, npm provenance y por qué TanStack Query no fue comprometido

Análisis verificado del ataque del 28 de agosto de 2026 contra @7nohe/openapi-react-query-codegen: 10 versiones maliciosas, GitHub Actions issue_comment, npm Trusted Publishing, provenance válida, binding.gyp, IOCs, remediación y diferencia respecto a TanStack Query.

Publicado Escrito por Tiempo de lectura 17 min de lectura

Análisis verificado del ataque del 28 de agosto de 2026 contra @7nohe/openapi-react-query-codegen: 10 versiones maliciosas, GitHub Actions issue_comment, npm Trusted Publishing, provenance válida, binding.gyp, IOCs, remediación y diferencia respecto a TanStack Query.

En esta página
  1. 1TL;DR
  2. 2¿Qué ocurrió el 28 de agosto?
  3. 3TanStack Query no fue comprometido
  4. 4¿Qué hace el paquete?
  5. 5¿Qué tan usado era?
  6. 6El ataque comenzó en GitHub Actions
  7. 7Un comentario podía entrar en el release
  8. 8El checkout convirtió input en ejecución
  9. 9id-token: write habilitó Trusted Publishing
  10. 10No fue necesario robar una contraseña
  11. 11Las versiones maliciosas tenían provenance válida
  12. 12Provenance no es detección de malware
  13. 13Primera ruta de ejecución: binding.gyp
  14. 14Segunda ruta: preinstall
  15. 15Las dos prereleases eran distintas
  16. 16Payload principal: 3FWCvzduYZg.js
  17. 17Comportamiento en runtime
  18. 18¿Qué credenciales deben considerarse expuestas?
  19. 19Por qué una dev dependency puede ser crítica
  20. 20Instalar dependencias es una superficie de ejecución
  21. 21¿Fue TeamPCP con certeza?
  22. 22¿Por qué vuelve Mini Shai-Hulud?
  23. 23El ataque de TanStack en mayo fue distinto
  24. 24Query también estuvo limpio en mayo
  25. 25El incidente de mayo tuvo impacto downstream real
  26. 26Agosto vs mayo
  27. 27¿Cómo comprobar exposición?
  28. 28IOCs importantes
  29. 29Remediación
  30. 30Versiones seguras
  31. 31¿Qué corrigió upstream?
  32. 32Cómo endurecer GitHub Actions
  33. 33Cómo endurecer la instalación de dependencias
  34. 34Checklist de producción
  35. 35Veredicto POLPROG

El 28 de agosto de 2026 fue comprometido el paquete npm @7nohe/openapi-react-query-codegen, una herramienta que genera clientes TypeScript y hooks de TanStack Query a partir de esquemas OpenAPI.[1][2][3]

El atacante no necesitó la contraseña npm del maintainer ni un token de publicación de larga duración.

La ruta de entrada estaba en el workflow de release de GitHub Actions.

El repositorio escuchaba eventos:

issue_comment

y un comentario en un pull request con el texto exacto:

npm publish

podía activar el flujo de publicación sin validar correctamente si quien comentaba era maintainer, collaborator o un usuario externo.[1][2]

Después el pipeline:

hacía checkout del código del PR
→ ejecutaba pnpm install
→ tenía id-token: write
→ publicaba mediante npm Trusted Publishing

[1][2]

El resultado fue especialmente relevante: 10 versiones maliciosas se publicaron con npm provenance válida.[1][3]

La lección principal:

La provenance puede demostrar correctamente el origen de un build y, aun así, el build puede ser malicioso.

También hay que corregir un titular engañoso: @tanstack/react-query no fue comprometido en este incidente. El paquete atacado es un generador de código independiente utilizado con TanStack Query.[6][7]

Estado de la información: 31 de agosto de 2026.

TL;DR

PreguntaRespuesta verificada
Paquete comprometido@7nohe/openapi-react-query-codegen
Fecha28 de agosto de 2026
Versiones maliciosas10
Versiones estables maliciosas8
Prereleases maliciosas2
¿@tanstack/react-query comprometido?No
Vector principalWorkflow GitHub Actions issue_comment mal configurado
¿Contraseña de maintainer necesaria?No
¿Long-lived npm token necesario?No
Autoridad de publicaciónid-token: write + npm Trusted Publishing
¿Provenance válida?
¿Provenance = código seguro?No
Rutas de ejecuciónbinding.gyp y, en algunas versiones, preinstall
Payload principal3FWCvzduYZg.js
latest actual3.0.2
SeveridadCritical, CVSS 9.6
CVESin CVE conocido en el advisory al 31 de agosto
FamiliaActividad vinculada/derivada de Mini Shai-Hulud
¿Atribución del operador segura?No
Respuesta prioritariaAislar host y rotar credenciales desde una máquina limpia

¿Qué ocurrió el 28 de agosto?

El advisory GHSA-9pvf-vcx3-x239 enumera 10 versiones maliciosas publicadas aproximadamente entre 20:00 y 20:21 UTC.[1]

Estables:

0.5.4
0.5.5
1.6.3
1.6.4
2.2.1
2.2.2
3.0.3
3.0.4

Prereleases:

0.0.0-365d4eb738d3146583431948d3ba6e27a32556be
0.0.0-ec7876d6c917dad516ba69bbfafc948b834bf0ab

[1][2]

El tag latest apuntó a 3.0.4 desde aproximadamente 20:19:29 UTC hasta cerca de 22:51 UTC, cuando volvió a 3.0.2.[1]

TanStack Query no fue comprometido

Decir:

TanStack Query hacked

es inexacto.

@7nohe/openapi-react-query-codegen es un proyecto independiente que genera código para:

@tanstack/react-query

[6]

No es un paquete oficial TanStack.

Además, el postmortem de TanStack sobre el incidente de mayo también indicó explícitamente que Query no estuvo afectado.[11]

¿Qué hace el paquete?

Genera:

  • clientes API tipados,
  • query keys,
  • queryOptions,
  • infiniteQueryOptions,
  • useQuery,
  • useMutation,
  • helpers de suspense,
  • prefetch y SSR.

[6]

Flujo típico:

OpenAPI schema
↓
codegen
↓
cliente TypeScript
↓
hooks/options de TanStack Query

¿Qué tan usado era?

El 31 de agosto npm mostraba alrededor de 155.000 descargas semanales.[6]

La cifra es dinámica.

Lo importante es que se ejecuta en laptops de desarrolladores y runners CI, entornos donde suelen existir credenciales GitHub, SSH, cloud y deployment.

El ataque comenzó en GitHub Actions

El workflow respondía a:

on:
  issue_comment:
    types: [created]

[1]

La cadena peligrosa fue:

comentario externo
+ sin autorización del actor
+ checkout del PR
+ ejecución del código
+ id-token: write
+ publish

Un comentario podía entrar en el release

Se comprobaba básicamente que el comentario perteneciera a un PR y fuera exactamente npm publish.[1][2]

Faltaba un gate fiable para roles como:

OWNER
MEMBER
COLLABORATOR

Un usuario externo podía alcanzar así el job privilegiado.

El checkout convirtió input en ejecución

El workflow hacía checkout del código del PR y después:

pnpm install

[2]

El contenido controlado por el atacante se ejecutaba dentro de un contexto de release privilegiado.

GitHub desaconseja ejecutar código no confiable de pull requests en workflows con privilegios.[9]

id-token: write habilitó Trusted Publishing

El job tenía:

permissions:
  id-token: write

[1][2]

Es una configuración legítima para npm Trusted Publishing vía OIDC.[10]

El problema fue permitir que código no confiable se ejecutara en un job que podía obtener esa identidad.

No fue necesario robar una contraseña

StepSecurity destaca que no era necesario robar una contraseña npm ni un publish token de larga duración.[2]

Modelo clásico:

robar token → publicar

Modelo actual:

controlar ejecución del workflow confiable
→ obtener identidad legítima
→ publicar

Las versiones maliciosas tenían provenance válida

Las publicaciones pasaron por el workflow real y Trusted Publishing, por lo que tenían provenance válida.[1][3]

La provenance afirmaba correctamente:

este artefacto viene
de este repositorio
mediante este workflow

Pero no garantizaba que el código del PR estuviera autorizado.

Provenance no es detección de malware

Puede probar:

  • origen del build,
  • identidad del workflow,
  • relación con el source,
  • cadena de custodia.

No prueba automáticamente:

  • seguridad del source,
  • autorización del PR,
  • seguridad lógica del workflow,
  • ausencia de malware.

Por tanto:

valid provenance ≠ safe package

[10]

Primera ruta de ejecución: binding.gyp

Algunas versiones no tenían un preinstall visible.[1]

En su lugar añadían:

binding.gyp

Se abusó del evaluador Python de GYP para alcanzar os.system() y ejecutar el payload JavaScript.[1][5]

Buscar únicamente lifecycle scripts no es suficiente.

Segunda ruta: preinstall

Otras versiones estables añadieron:

"preinstall": "node 3FWCvzduYZg.js"

[1][2]

Fueron:

0.5.5
1.6.4
2.2.2
3.0.4

Las primeras versiones estables usaban binding.gyp sin un lifecycle script explícito.[1]

Las dos prereleases eran distintas

Las dos versiones 0.0.0-* tenían un preinstall malicioso, pero:

"files": ["dist"]

dejó fuera los archivos payload del tarball.[1]

Las 10 publicaciones son maliciosas, aunque no sean artefactos técnicamente idénticos.

Payload principal: 3FWCvzduYZg.js

Los tarballs estables incluían:

3FWCvzduYZg.js

de aproximadamente 4,4 a 6,4 MB.[1]

StepSecurity observó que 0.5.4 pasó de unos 41 KB en 0.5.3 a más de 5,6 MB.[2]

Un salto de tamaño así es una anomalía útil para detección.

Comportamiento en runtime

StepSecurity ejecutó las versiones en runners aislados.[2]

Se observó:

Node inicia payload
→ curl descarga Bun
→ Bun se ejecuta desde /tmp/trinnyyyy-*
→ gh auth token
→ Git Credential Manager
→ comprobación ssh/scp
→ enumeración de procesos
→ updater.py temporal

También hubo acceso a GitHub API y sondeo del metadata hostname de Google Cloud.

¿Qué credenciales deben considerarse expuestas?

Si una versión afectada se ejecutó, todas las credenciales accesibles para ese proceso deben considerarse potencialmente expuestas:

GitHub
npm
SSH
cloud
CI/CD
deployment

Eso no significa que todas se hayan robado en todos los hosts.

Por qué una dev dependency puede ser crítica

“Solo es codegen” no reduce el riesgo.

El malware solo necesita ejecutarse durante:

npm install
pnpm install
yarn install

Los entornos de desarrollo y CI suelen contener secretos especialmente valiosos.

Instalar dependencias es una superficie de ejecución

Package managers soportan:

preinstall
install
postinstall
prepare

y también flujos como node-gyp.

La instalación es, en la práctica:

resolución
+
descarga
+
posible ejecución de código

¿Fue TeamPCP con certeza?

JFrog, Socket y otros investigadores conectan el código con Mini Shai-Hulud y variantes relacionadas.[3][4]

Pero la atribución exacta del operador no está demostrada de forma definitiva.

Puede existir reutilización de código, acceso residual o copycats.[4]

¿Por qué vuelve Mini Shai-Hulud?

La familia se centra en robo de credenciales, CI/CD, GitHub, registries y propagación.[12]

Patrón:

comprometer release
→ obtener publish authority
→ publicar paquete aparentemente confiable
→ ejecutarse en developer/CI
→ robar nuevas credenciales

El ataque de TanStack en mayo fue distinto

El 11 de mayo fue comprometido el repositorio Router/Start.[11]

La cadena combinó:

  1. pull_request_target,
  2. cache poisoning,
  3. extracción de token OIDC de memoria del runner.

Resultado:

42 paquetes
84 versiones maliciosas

[11]

Query también estuvo limpio en mayo

TanStack indicó explícitamente que Query no fue una familia comprometida.[11]

Mayo:

Router/Start afectado

Agosto:

codegen externo para Query afectado

El incidente de mayo tuvo impacto downstream real

OpenAI confirmó que dos dispositivos de empleados resultaron afectados por el ataque de mayo.[13]

La empresa describió actividad centrada en credenciales y exfiltración limitada de material de credenciales, sin encontrar evidencia de acceso a datos de usuarios ni compromiso de sistemas de producción o propiedad intelectual.[13]

Agosto vs mayo

Mayo

fork PR
→ pull_request_target
→ cache poisoning
→ release confiable
→ extracción OIDC
→ publish

Agosto

fork PR
→ comentario público "npm publish"
→ workflow privilegiado
→ pnpm install
→ id-token: write
→ Trusted Publishing

[1][2][11]

La ruta de agosto era más simple.

¿Cómo comprobar exposición?

Buscar las 10 versiones en:[1]

package-lock.json
pnpm-lock.yaml
yarn.lock
bun.lock
SBOM
logs CI
dependency caches

No basta con mirar el package.json actual.

IOCs importantes

Indicadores públicos:[1][2][5]

3FWCvzduYZg.js
binding.gyp
is_it_this_simple.js
nu.js
/tmp/trinnyyyy-*/bun
/tmp/*/updater.py

También revisar descargas inesperadas de Bun, gh auth token, llamadas a Git credential manager y node-gyp donde no debería existir native code.

Remediación

Si una versión afectada se ejecutó:[1][2]

1. detener builds
2. aislar host
3. usar máquina limpia
4. rotar credenciales accesibles
5. invalidar sesiones
6. revisar audit logs
7. purgar caches
8. descartar artifacts del runner
9. reconstruir desde un entorno limpio

Versiones seguras

GitHub Advisory señala 3.0.2 como known-good y dice que versiones publicadas antes del 28 de agosto no están afectadas por este incidente.[1]

StepSecurity indica como predecesoras limpias:

0.5.3
1.6.2
2.2.0
3.0.2

[2]

El 31 de agosto npm vuelve a mostrar latest = 3.0.2.[6]

¿Qué corrigió upstream?

Según el advisory:[1]

  • eliminó el trigger issue_comment,
  • movió releases a tag push,
  • revocó el Trusted Publisher npm,
  • rotó tokens de larga duración,
  • restauró latest a 3.0.2,
  • eliminó el dist-tag pre,
  • deprecó las 10 versiones,
  • solicitó su retirada en npm.

Snyk también clasifica el compromiso como Critical, con CVSS 9.6, reforzando la gravedad de la ejecución de código malicioso durante la instalación.[8] También son relevantes las medidas adicionales de hardening aplicadas por TanStack tras el incidente de mayo para caches, workflows y release pipelines.[14]

Cómo endurecer GitHub Actions

  • No ejecutar código de forks en jobs privilegiados.
  • Añadir authorization gates a automatizaciones por comentario.
  • Limitar id-token: write al publish job real.
  • Separar build y publish.
  • Usar trusted trigger o approval.
  • Fijar Actions de terceros a commit SHA.[9]

Cómo endurecer la instalación de dependencias

Controles útiles:

  • lockfiles,
  • frozen installs,
  • minimum release age/cooldown,
  • monitorización de releases,
  • detección de anomalías de tamaño,
  • política de lifecycle scripts,
  • CI sandboxed,
  • restricciones outbound,
  • detección de malware además de CVE,
  • SBOM,
  • credenciales mínimas en runners.

Trusted Publishing sigue siendo útil.[10]

Pero debe combinarse con Trusted Workflow Design.

Checklist de producción

Dependencies

  • Lockfile obligatorio.
  • CI bloquea cambios inesperados.
  • Release cooldown/minimum age.
  • Nuevas versiones no entran directamente en producción.
  • Monitor de cambios de tamaño.
  • Revisión de install scripts.
  • binding.gyp inesperado genera alerta.
  • Malware scanning además de CVE.

GitHub Actions

  • Código de fork nunca se ejecuta con privilegios.
  • issue_comment tiene authorization gate.
  • pull_request_target solo cuando es necesario.
  • GITHUB_TOKEN mínimo.
  • id-token: write solo donde hace falta.
  • Publish requiere trusted trigger.
  • Build y publish separados.
  • Actions fijadas por SHA.
  • La automatización por comentarios tiene un test negativo para usuarios no autorizados.
  • El release workflow nunca hace checkout de código de forks no confiables.

npm

  • Trusted Publisher limitado.
  • Sin long-lived publish tokens innecesarios.
  • Monitorización de publicaciones.
  • Alertas por releases inesperados.
  • Provenance verificada, nunca usada como malware verdict.
  • Runbook para deprecation/revocation.

Runners

  • CI runners efímeros.
  • Secrets mínimos.
  • Cloud credentials de corta duración.
  • SSH keys con scope mínimo.
  • Outbound monitorizado.
  • Dependency install sin acceso global.
  • EDR/runtime monitoring.
  • Aislamiento rápido de host.

Incident response

  • Owner definido.
  • Búsqueda histórica en lockfiles.
  • Purga rápida de CI caches.
  • Invalidación de sesiones.
  • Mapa de credenciales accesibles.
  • Rotación desde máquina limpia.
  • Revisión de npm publishes.
  • Revisión de GitHub audit logs.

Veredicto POLPROG

El compromiso de @7nohe/openapi-react-query-codegen demuestra cómo está cambiando el software supply-chain security.

El atacante no necesitó hackear npm, robar una contraseña de maintainer, romper 2FA ni obtener un token clásico.

Bastó con introducir código no confiable en un workflow que ya tenía autoridad legítima de publicación.

La frontera se desplaza hacia:

CI/CD
workflow triggers
OIDC
release authorization
dependency execution

Segunda lección: provenance.

No falló criptográficamente. Certificó correctamente el origen de un build malicioso.

Tercera lección: precisión.

TanStack Query no fue comprometido.

Fue comprometida una herramienta de terceros de su ecosistema.

Al 31 de agosto, las versiones maliciosas están identificadas, el advisory está publicado, latest volvió a 3.0.2 y el workflow de release fue modificado.[1][6]

La pregunta clave para cualquier equipo JavaScript no es únicamente:

¿Usamos este paquete?

Sino:

¿Puede un input no confiable llegar en nuestro CI/CD a un job con autoridad para publicar?

Si no hay una respuesta inmediata, conviene auditar GitHub Actions.

Mini Shai-Hulud npm supply chain TanStack Query openapi-react-query-codegen GitHub Actions Trusted Publishing OIDC npm provenance DevSecOps

Preguntas frecuentes

¿Fue hackeado TanStack Query?

No.

¿Qué paquete fue comprometido?

@7nohe/openapi-react-query-codegen.

¿Cuántas versiones?

10.

¿Cuándo?

28 de agosto de 2026, principalmente entre 20:00 y 20:21 UTC.

¿Versión actual segura?

3.0.2.

¿Se robó un token npm del maintainer?

No era necesario. Se abusó de Trusted Publishing/OIDC.

¿Por qué había provenance válida?

Porque publicó el workflow legítimo.

¿Provenance no sirve?

Sí sirve para origen, pero no garantiza ausencia de malware.

¿Puede binding.gyp ejecutar código durante npm install?

Sí, y aquí se abusó de node-gyp para ello.

¿Qué hacer tras una instalación afectada?

Aislar host, rotar credenciales desde una máquina limpia, revisar logs y reconstruir.

¿TeamPCP está confirmado?

No con suficiente certeza para afirmarlo de forma definitiva en esta ola.

¿Trusted Publishing está roto?

No en ese sentido simple. El problema fue un workflow inseguro al que el sistema confiaba correctamente.

Fuentes y notas

  1. GitHub Security Advisory, GHSA-9pvf-vcx3-x239, 28 de agosto de 2026, consultado el 31 de agosto de 2026.123456789101112131415161718192021222324
  2. StepSecurity, @7nohe/openapi-react-query-codegen Compromised Through an Exposed npm Publishing Workflow, 28 de agosto de 2026.123456789101112131415
  3. Socket, OpenAPI React Query Codegen Compromised in Mini Shai-Hulud npm Supply Chain Attack, 28 de agosto de 2026.1234
  4. JFrog Security Research, Shai-Hulud Trinitite Hits @7nohe/openapi-react-query-codegen, 30 de agosto de 2026.12
  5. OSV, MAL-2026-15494, 28 de agosto de 2026.12
  6. npm, @7nohe/openapi-react-query-codegen, estado comprobado el 31 de agosto de 2026.123456
  7. npm, @tanstack/react-query, estado comprobado el 31 de agosto de 2026.
  8. Snyk, Embedded Malicious Code affecting @7nohe/openapi-react-query-codegen, 28 de agosto de 2026.
  9. GitHub Docs, Securely using pull_request_target, consultado el 31 de agosto de 2026.12
  10. npm Docs, Trusted publishing for npm packages, consultado el 31 de agosto de 2026.123
  11. TanStack, Postmortem: TanStack npm supply-chain compromise, 11 de mayo de 2026, actualizado el 15 de mayo de 2026.12345
  12. Aikido Security, Mini Shai-Hulud Is Back, 12 de mayo de 2026.
  13. OpenAI, Our response to the TanStack npm supply chain attack, 13 de mayo de 2026, actualizado posteriormente.12
  14. TanStack, Hardening TanStack After the npm Compromise, 12 de mayo de 2026, actualizado el 15 de mayo de 2026.

¿Te ha resultado útil?

Recibe nuevos artículos por email

Un correo breve por cada nuevo artículo de la base de conocimiento. Sin spam, te das de baja con un clic.

Solo usamos tu email para enviar nuevos artículos. Sin compartir con terceros.

Volver a la base de conocimiento