Análisis: Ataque a TanStack, por qué pnpm es más seguro que npm
El 11 de mayo de 2026, la comunidad de desarrollo JavaScript recibió una noticia inquietante: un atacante había logrado publicar 84 versiones maliciosas en 42 paquetes del ecosistema TanStack. El incidente, documentado oficialmente como CVE-2026-45321 y clasificado como severity Critical por el National Vulnerability Database, demostró cómo tres vulnerabilidades conocidas podían encadenarse para comprometer una de las cadenas de suministro de software más utilizadas del ecosistema JavaScript.
El ataque no fue detectado internamente por TanStack. Fue un investigador externo, ashishkurmi de StepSecurity, quien advierte sobre las versiones maliciosas aproximadamente 20 minutos después de su publicación. Este detalle es crucial: la ventana de exposición existiría durante al menos 20 minutos, tiempo más que suficiente para que miles de desarrolladores ejecutaran npm install y acumularan credenciales comprometidas en sus sistemas.
Las tres vulnerabilidades que hicieron posible el ataque
Para comprender el verdadero alcance de este incidente, hay que analizar cómo el atacante logró ejecutar su plan. No se trató de un exploit aislado, sino de una cadena cuidadosamente construida que aprovechaba debilidades conocidas pero raramente protegidas.
1. El patrón pull_request_target
La primera vulnerabilidad reside en la configuración de GitHub Actions. TanStack utilizaba el disparador pull_request_target en su workflow de bundle-size, un patrón conocido como “Pwn Request” que permite a Pull Requests procedentes de forks ejecutar código con acceso al repositorio base. Cuando el atacante abrió un Pull Request desde su fork modificado, el workflow ejecutó código controlado por el atacante en el contexto de la organización TanStack.
Este patrón es especialmente peligroso porque pull_request_target ejecuta el código del fork con los permisos del repositorio base, incluyendo acceso al caché de GitHub Actions. Los desarrolladores a menudo creen que mitigan el riesgo usando pull_request en lugar de pull_request_target, pero en este caso, el workflow utilizaba el primero precisamente para acceder a información del repositorio base.
2. Poisoning del caché de GitHub Actions
La segunda vulnerabilidad explotaba el sistema de caché compartido de GitHub Actions. El atacante logró inyectar código malicioso en el caché de pnpm que sería restaurado posteriormente por el workflow de publicación. Este técnica, documentada por Adnan Khan en 2024, permite que código ejecutado en un contexto de Pull Request pueda persistir y ejecutarse en contextos de mayor confianza como el pipeline de release.
El atacante específicamente diseñó su payload para escribir en el directorio pnpm-store bajo una clave que el workflow legítimo de release calcularía y buscaría: Linux-pnpm-store-${hashFiles('**/pnpm-lock.yaml')}. Cuando el job de benchmark-pr terminó, actions/cache@v5 guardó el caché envenenado con esa clave exacta. Cuando release.yml se ejecutó posteriormente, restauró el caché comprometido junto con todo el código malicioso que contenía.
3. Extracción del token OIDC de la memoria del runner
La tercera vulnerabilidad fue la más sofisticada: la extracción del token OIDC directamente de la memoria del runner de GitHub Actions. El workflow de publicación de TanStack declaraba id-token: write para usar OIDC trusted publishing con npm. Este permiso permite al workflow obtener un token de acceso mediante el protocolo OIDC.
El problema es que cuando el runner de GitHub Actions levanta el proceso Worker, el token OIDC se almacena en memoria como variable de entorno. El malware del atacante podía localizar el proceso del runner mediante /proc/*/cmdline, leer su memoria a través de /proc/*/mem, y extraer el token OIDC. Con ese token, el atacante podía autenticarse directamente en registry.npmjs.org, suplantando como el repositorio TanStack sin necesidad de robar tokens npm explícitos.
Este técnica exacta fue usada previamente en la compromisión de tj-actions/changed-files en marzo de 2025, demostrando que los atacantes reutilizan técnicas probadas en lugar de desarrollar zero-days.
Qué hacía el malware publicado
Una vez publicadas las 84 versiones maliciosas, cualquier desarrollador que ejecutara npm install, pnpm install o yarn install en un proyecto que dependiera de los paquetes afectados estaba expuesto. El malware usaba optionalDependencies para ejecutar código durante la fase de instalación, específicamente un script prepare que ejecutaba un archivo JavaScript ofuscado de 2.3 MB llamado router_init.js.
Las capacidades del malware eran alarmantemente completas:
-
Recolección de credenciales: Buscaba en AWS IMDS y Secrets Manager, GCP metadata, tokens de cuentas de servicio de Kubernetes, tokens de Vault, ~/.npmrc, tokens de GitHub (variables de entorno, gh CLI, .git-credentials), y claves SSH privadas.
-
Exfiltración de datos: Enviaba toda la información recopilada a través de la red Session/Oxen messenger file-upload (filev2.getsession.org, seed3.getsession.org). Esta red proporciona cifrado de extremo a extremo sin servidor de comando y control controlable, lo que significa que bloquear por IP o dominio era la única mitigación de red disponible.
-
Auto-propagación: El malware enumeraba otros paquetes mantenidos por la víctima mediante registry.npmjs.org/-/v1/search?text=maintainer:<user> y los republicaba con la misma inyección, creando un efecto de propagación automática que podía comprometer maintainers adicionales.
La recomendación oficial de seguridad fue rotar inmediatamente todas las credenciales: tokens npm, tokens de GitHub, credenciales AWS, tokens de Vault, tokens de Kubernetes, y claves SSH.
Por qué npm requiere configuración manual de seguridad
Este incidente pone de manifiesto una diferencia fundamental entre npm y pnpm en cuanto a su postura de seguridad por defecto.
En npm, la seguridad de la cadena de suministro no viene habilitada de serie. Los desarrolladores que quieren protegerse deben configurar manualmente opciones como:
npm auditpara detectar vulnerabilidades conocidas, aunque no detecta malware nuevo--ignore-scriptspara evitar la ejecución de scripts durante la instalación--ignore-scriptsen package.json para bloquear scripts a nivel de proyecto- Revisar manualmente optionalDependencies de cada paquete instalado
El problema es que ninguna de estas configuraciones es el comportamiento por defecto. Un desarrollador que instala un paquete nuevo espera que sea seguro, y la mayoría no revisa el package.json de cada dependencia transitiva. Las configuraciones de seguridad en npm son reactivas: dependen de que el desarrollador sepa qué buscar y tome medidas activas.
La realidad es que la gran mayoría de proyectos npm en producción no implementan ninguna de estas protecciones. El ecosistema ha construido una cultura de confianza implícita donde ejecutamos npm install sin pensar en las consecuencias.
pnpm: seguridad activa por defecto
pnpm toma un enfoque radicalmente diferente. En lugar de requerir configuración manual, pnpm incluye protecciones de seguridad activas que funcionan de serie, sin que el desarrollador tenga que saber que existen.
Scripts postinstall deshabilitados por defecto
Desde pnpm v10, la ejecución automática de scripts postinstall en dependencias está deshabilitada por defecto. Aunque existe una configuración dangerouslyAllowAllBuilds para re-habilitarla globalmente, la recomendación oficial es usar allowBuilds para listar explícitamente solo las dependencias de confianza. Esto significa que si una dependencia no requería build anteriormente, no va a ejecutar silenciosamente un script malicioso si una versión comprometida se publica.
Esta decisión de diseño es significativa: el vector de ataque más común en comprometimientos de npm ha sido históricamente el uso de scripts postinstall, y pnpm lo neutraliza simplemente cambiándolo del comportamiento por defecto.
Prevenir dependencias exóticas
La configuración blockExoticSubdeps permite bloquear dependencias transitivas que usen fuentes no estándar como repositorios git o URLs directas a tarballs. Esto asegura que todas las dependencias se resuelvan desde fuentes confiables, reduciendo el riesgo de que un atacante introduzca código a través de una dependencia transitiva que apunte a un repositorio controlado por él.
Retrasar actualizaciones de dependencias
Una de las protecciones más elegantes de pnpm es minimumReleaseAge, que por defecto en pnpm v11 retrasa la instalación de nuevas versiones durante 1440 minutos (un día completo). La lógica es simple: el malware suele ser detectado rápidamente, generalmente en cuestión de horas. Si retrasas las actualizaciones por 24 horas, la mayoría de versiones comprometidas serán detectadas y eliminadas del registry antes de que tu proyecto pueda instalarlas.
Esta configuración puede ajustarse: establecer en 0 para desactivar el retraso, o aumentarlo a 10080 minutos (una semana) para mayor protección en entornos de alta seguridad.
Política de confianza
La configuración trustPolicy permite establecer reglas sobre qué nivel de confianza se requiere para instalar versiones de paquetes. Cuando se establece en no-downgrade, pnpm impedirá la instalación de un paquete si su nivel de confianza ha disminuido comparado con versiones anteriores. Por ejemplo, si un paquete fue previamente publicado por un editor confiable con provenance verificado pero ahora solo tiene provenance o ningún indicador de confianza, la instalación será bloqueada.
Esto proporciona una capa adicional de protección contra versiones que podrían haber sido publicadas por actores no autorizados o en circunstancias cuestionables.
Un cambio de paradigma necesario
El ataque a TanStack no fue un evento aislado. Es parte de una tendencia más amplia de campaña activa contra el ecosistema npm, documentada por investigadores de seguridad bajo el nombre “Mini Shai-Hulud” y relacionada con el grupo conocido como TeamPCP. Los ataques a la cadena de suministro de software están siendo cada vez más sofisticados, y los atacantes están explotando la confianza implícita que el ecosistema ha construido durante años.
La diferencia fundamental entre npm y pnpm no es solo técnica: es filosófica. npm asume que los paquetes son seguros hasta que se demuestre lo contrario, requiriendo acción del desarrollador para protegerse. pnpm asume que cualquier paquete podría estar comprometido, y proporciona protecciones automáticas que funcionan sin requerir conocimiento específico del usuario.
Para equipos de desarrollo que mantienen proyectos en producción, la elección del gestor de paquetes tiene implicaciones de seguridad reales. Las configuraciones de seguridad en npm no son difíciles de implementar, pero requieren saber que existen y recordar configurarlas en cada proyecto. Las protecciones de pnpm simplemente funcionan, y el desarrollador puede enfocarse en escribir código en lugar de configurar barreras de seguridad.
Compártelo si te ha resultado útil.
Si lo necesitas a nivel profesional en tu empresa, puedo ayudarte.
Y… rota tus credenciales antes de que alguien lo haga por ti.
Artículos relacionados
La Liga bloqueó mi blog: jamás he visto un partido de fútbol
El puto Tebas me ha bloqueado el blog. Mi sitio no tiene nada que ver con el fútbol, pero La Liga obtiene mandatos judiciales para bloquear miles de IPs cada fin de semana y derriba webs inocentes de pasada. Te cuento el escándalo, los números que demuestran lo absurdo que es, y qué puedes hacer si también eres víctima.
⚠️ CVE-2026-3854: RCE crítico en el pipeline git de GitHub
CVE-2026-3854 es una vulnerabilidad crítica de ejecución remota de código en el pipeline de git push de GitHub, con una puntuación CVSS de 8.7. Descubierta por investigadores de Wiz mediante ingeniería inversa asistida por Inteligencia Artificial, permite a cualquier usuario con acceso de push inyectar campos internos a través de un carácter punto y coma mal sanitizado. GitHub.com fue parcheado en menos de 75 minutos tras la validación del reporte. Si usas GitHub Enterprise Server, actualiza ahora.
⚠️ CVE-2026-31431: escalada de privilegios en el kernel Linux
CVE-2026-31431, conocido como 'Copy Fail', es una vulnerabilidad de alta severidad en el módulo algif_aead del kernel Linux que permite escalar privilegios a root desde cualquier cuenta de usuario sin privilegios. Afecta a prácticamente todas las distribuciones Linux activas desde 2017. De momento no hay parche disponible, pero existe una mitigación inmediata que puedes aplicar en menos de un minuto.