TanStack y MUCHOS paquetes más afectados: análisis profundo

MMaximilian Schwarzmüller
Computing/SoftwareBusiness NewsInternet Technology

Transcript

00:00:00Tenemos otro gran, realmente gran ataque a la cadena de suministro ahora mismo y sigue en curso
00:00:06y se extendió de NPM también al ecosistema de Python, así que tal vez ahora mismo no instales ningún
00:00:12paquete de NPM o Python. Y asegúrate de que tu sistema esté configurado de forma segura en general. Tengo otro video
00:00:19sobre eso, compartiré un enlace abajo y volveré a ello aquí en este video también, pero primero quiero
00:00:23darte algunos detalles sobre qué está afectado y cómo saber si tú lo estás. Todo empezó con los
00:00:30paquetes de TanStack: TanStack query, TanStack router, TanStack start y demás. Ayer, 11 de mayo,
00:00:36en un lapso de tiempo bastante corto, un par de paquetes maliciosos o, de hecho, todos los paquetes de TanStack fueron
00:00:43publicados con versiones maliciosas y se contuvo rápidamente en 20 minutos. Al final
00:00:50se detectó y contuvo rápido, pero todos estos paquetes maliciosos se publicaron en ese
00:00:57lapso de tiempo o en ese corto periodo de tiempo aquí. Y luego continuó propagándose y todavía se está
00:01:03propagando. Llegó a los paquetes de Mistral que, jaja, solo tienen cuatro usuarios, pero aun así se vieron
00:01:09afectados porque este malware actúa como un gusano y roba datos, roba credenciales, también potencialmente
00:01:16las tuyas si está instalado en tu sistema. Volveré a cómo saber si estás afectado en solo
00:01:20un segundo, pero continuó extendiéndose a más paquetes de NPM porque esa es la idea detrás de esto y
00:01:26luego incluso al ecosistema de Python y eso está pasando justo ahora. Esto tiene apenas unas horas,
00:01:32dos horas en el momento en que estoy grabando esto. Ahora, ¿cómo saber si estás
00:01:39afectado? Si instalaste algún paquete de TanStack ayer por la tarde, en mi caso aquí en la zona horaria
00:01:45de Alemania, debes considerarte afectado. Si lo instalaste alrededor de esa hora, ten en cuenta
00:01:54que es UTC, así que tienes que traducirlo a tu zona horaria; en ese caso, debes considerarte
00:02:00afectado. Pero como se está extendiendo a los paquetes de Mistral, a muchos más paquetes de JavaScript,
00:02:06más de los que podría enumerar aquí, también debes considerar que tú o tu máquina están afectados y comprometidos.
00:02:13Y compartiré enlaces a estas publicaciones abajo para que puedas profundizar y ver la lista completa
00:02:18de todos estos paquetes afectados según se han publicado. Pero como mencioné, todavía está en curso,
00:02:22así que quizás no instales nada por ahora. También hay indicadores de compromiso. Debes
00:02:31buscar ciertos hashes de archivos, hashes SHA, para el router en un archivo JS. También enlazaré este post abajo.
00:02:38Y si tienes una forma de monitorear qué solicitudes de red ocurrieron en tu máquina,
00:02:42debes buscar tráfico saliente hacia esta URL, lo cual sería otro indicador claro
00:02:48de que se han exfiltrado datos de tu sistema. ¿Qué significa estar comprometido en detalle? Significa que
00:02:55este malware hace principalmente dos cosas. La primera cosa importante que hace es cosechar datos. Busca
00:03:03tokens de NPM, tokens de GitHub, credenciales de AWS, otros secretos. Escanea tu sistema buscando
00:03:12ubicaciones típicas donde guardas credenciales y secretos, los recopila y los envía a
00:03:18esta URL que te mostré. Así que roba estos secretos. Pero no solo hace eso. Como mencioné,
00:03:26actúa como un gusano, así que también usa estos tokens de GitHub robados. Por ejemplo,
00:03:33los usa junto con los tokens de NPM para publicar más paquetes comprometidos. Si eres el mantenedor
00:03:40de otro paquete, o si tal vez tienes un flujo de trabajo CI/CD que se ejecutó en ese tiempo y que
00:03:46dependía de algunos paquetes de TanStack, entonces en ese flujo CI/CD se han
00:03:53extraído los paquetes de TanStack comprometidos. El código malicioso pudo haberse ejecutado allí. Y luego en ese
00:04:00flujo de trabajo, no en tu máquina, sino en ese flujo, también podría robar ciertas credenciales
00:04:06para publicar una versión maliciosa, una versión comprometida del paquete que tu flujo CI/CD
00:04:14estaba tratando de construir. Así es como se propaga. Como mencioné, actúa como un gusano. Está usando estas
00:04:20credenciales y tokens robados para publicar más paquetes comprometidos. Y así es como llega
00:04:26a Mistral y luego también a otros paquetes de JavaScript, e incluso al ecosistema de Python. Y aquí
00:04:32es donde estamos ahora. Y por lo que sé, sigue extendiéndose. Ahora, ¿cómo puedes protegerte
00:04:39de eso? Creé un video sobre eso en mi otro canal, AkataMind. También lo enlazaré abajo.
00:04:44En resumen, quieres asegurarte de ejecutar tu código o hacer tu desarrollo,
00:04:51no directamente en tu máquina raíz si es posible, sino en alguna máquina virtual, en un dev container,
00:04:57algo así. No quieres almacenar secretos en crudo en tu máquina. Me refiero a que para AWS,
00:05:03por ejemplo, deberías usar su enfoque de inicio de sesión único en lugar de guardar credenciales IAM en
00:05:10tu máquina, por ejemplo, y usar técnicas similares para otros servicios que utilices. Además,
00:05:16también deberías considerar usar servicios como Infisical o Doppler para guardar tus secretos
00:05:25en la nube y no en tu disco duro, ni en archivos .env. Eso es algo que podrías querer hacer.
00:05:30Y de nuevo, hablo de esas cosas en ese video. Y también deberías usar gestores de paquetes
00:05:38y configuraciones que permitan configurar cosas como la edad mínima de lanzamiento, como permite Bun.
00:05:44En el archivo bunfig.toml, puedes establecer una edad mínima de lanzamiento, lo que asegura que incluso si
00:05:49ejecutas bun install, solo instales paquetes que tengan al menos X segundos o X días de antigüedad en este
00:05:56ejemplo. Ahora, pnpm tiene una función similar. Las versiones más recientes de npm tienen algo parecido.
00:06:02De nuevo, cubrí eso en ese otro video. Y si usas algo como Bun o si tienes
00:06:09la configuración correcta para npm, pero Bun lo hace por defecto, por ejemplo, también bloquea la
00:06:15ejecución de, por ejemplo, scripts post-instalación, o sea, scripts del ciclo de vida de los paquetes que
00:06:21estás instalando, lo cual te da otro mecanismo de seguridad porque ese malware típicamente depende
00:06:28de que tales scripts se ejecuten en tu sistema. Así que usar un gestor de paquetes seguro y/o una
00:06:36configuración segura para el mismo, ejecutar tu código en una máquina virtual o en un dev container
00:06:41y no guardar secretos en texto plano en tu sistema. Eso es lo que quieres hacer en general, pero ahora
00:06:46más aún porque estos ataques, ataques como estos aquí, se volverán más serios y profundizaremos
00:06:52en cómo funcionó este ataque porque es muy interesante. Pero por supuesto, estamos teniendo más de
00:06:58estos. Creo un video así casi cada mes ahora o incluso más seguido porque, para empezar,
00:07:04creo que son más fáciles de realizar. Ahora, en la era de la IA, es más fácil analizar los paquetes o
00:07:12las dependencias que quieres afectar y analizar su código fuente o su configuración CICD para posibles
00:07:22vectores de ataque. Eso es lo que pasó aquí con TanStack. No es que la máquina de un mantenedor
00:07:28se viera afectada, sino que fue el flujo de trabajo CICD de TanStack el que fue atacado. Y
00:07:34volveré a eso. Así que es más fácil buscar vulnerabilidades con IA. Es más fácil escribir código,
00:07:40incluyendo código malicioso, por supuesto. Y al mismo tiempo, tenemos esa explosión de software. Tenemos más
00:07:45software escribiéndose que nunca antes. Así que hay más objetivos ahí fuera, incluyendo muchos objetivos
00:07:51que tal vez no se preocupan demasiado por la seguridad. Eso hace que estos ataques sean más interesantes también.
00:07:57Ahora, ¿cómo empezó todo esto? Es muy interesante. Como mencioné, no es un enfoque novedoso,
00:08:03no es uno que nunca hayamos visto antes, pero aun así es bastante elaborado. El equipo de TanStack publicó un
00:08:09post-mortem, un artículo donde explican cómo ocurrió el ataque. Y también lo enlazaré abajo.
00:08:15Pero claro, les daré el resumen aquí porque al final, este ataque de aquí se basó en
00:08:22tres pasos principales, que explicaré en detalle. Un patrón de solicitud pull request pwn. Lo
00:08:30explicaré. Luego, envenenamiento del caché de GitHub Actions a través del límite de confianza de forks
00:08:38y extracción en memoria durante la ejecución de un token OIDC. Vale, ¿qué significa todo eso? De nuevo,
00:08:45pueden leer el artículo para todos los detalles, pero permítanme darles el resumen. Y empecemos con
00:08:50el patrón pull request pwn. ¿Qué es eso? Para entenderlo tenemos que entender
00:08:58que GitHub Actions es, por supuesto, la solución CICD, el producto CICD de GitHub. Y
00:09:05tengo un curso sobre GitHub Actions también, por cierto, si quieres aprender a configurar GitHub Actions,
00:09:10cómo usar el producto para tareas de CICD, cómo publicar tus paquetes o tu sitio web, etc.
00:09:16Ahora, como todas las herramientas de flujo de trabajo CICD, GitHub Actions depende de eventos que activan flujos porque,
00:09:24por supuesto, CICD se trata de hacer algo de forma automatizada. Por ejemplo, lanzar tu sitio web,
00:09:29publicarlo, desplegarlo de forma automatizada cuando haces push a la rama principal, por ejemplo.
00:09:34Así que tienes varios eventos que pueden activar un flujo y push es un evento, por ejemplo,
00:09:40de modo que puedes decir, vale, si hago push a la rama principal, por ejemplo, puedes filtrar por
00:09:44diferentes ramas. Entonces quiero ejecutar ciertas tareas. Quiero instalar mis dependencias. Quiero
00:09:49construir el proyecto. Quiero subirlo a mi servidor. Eso es lo que podrías hacer. Ahora, otro activador
00:09:56es pull_request_target. Este activador se activa si se ha abierto una pull request para tu
00:10:05repositorio. Y eso, por supuesto, significa que cualquiera puede hacer un fork de tu repositorio, hacer algo allí, hacer push
00:10:14en su fork, y luego abrir una pull request con tu repositorio. Y eso activaría
00:10:19este flujo de trabajo. ¿Suena peligroso? Bueno, lo es un poco. Y es lo que inició este ataque.
00:10:25También existe el activador pull_request. Hablé de pull_request_target antes,
00:10:31pero también tenemos pull_request, que funciona igual, pero pull_request ejecuta el flujo
00:10:38CICD en el contexto del repositorio fork. Así que cualquier cosa maliciosa que esté pasando allí,
00:10:45pasa en el repositorio fork, no en el repositorio base. Así que esto no es un problema.
00:10:52pull_request_target, por otro lado, se ejecuta en el contexto del repositorio base. Y eso, por supuesto,
00:10:58es potencialmente peligroso. Es potencialmente peligroso porque cualquiera puede abrir una pull request. Y,
00:11:04por supuesto, lo que pasó en este caso con el ataque a TanStack, en esa pull request, en ese
00:11:10fork, el atacante incluyó el código malicioso, el código del gusano, el malware en el repositorio de TanStack,
00:11:20en el fork del mismo, pero lo incluyó allí. Luego el atacante abrió la pull request,
00:11:26y eso llevó a que se ejecutara pull_request_target. Y luego, como mencioné, eso inicia un
00:11:33runner de GitHub Actions, y se ejecuta en el contexto del repositorio base. ¿Qué significa esto?
00:11:40Esto no significa que el atacante obtenga acceso al código base o pueda fusionar el código malicioso
00:11:46en el repositorio, sino que significa que, por ejemplo, el caché que se usa allí
00:11:53se compartirá con ejecuciones posteriores de GitHub Actions que provengan del repositorio base,
00:12:00potencialmente de ganchos o activadores de eventos totalmente diferentes como el activador push.
00:12:05Lo siguiente que ocurrió fue el envenenamiento del caché. Pero ¿qué significa esto? Bueno,
00:12:11el atacante añadió código a su fork para asegurarse de que cuando la GitHub Action
00:12:17se ejecutara para el activador pull_request_target, ejecutaría un comando, el comando hashfiles,
00:12:23que es soportado por GitHub Actions, para guardar algo en el caché de GitHub Actions. Ahora,
00:12:28¿de qué trata ese caché? La idea detrás del caché de GitHub Actions simplemente es acelerar
00:12:33esos flujos de trabajo de GitHub Actions. Así que puedes, por ejemplo, hashear dependencias. La idea es que
00:12:39si una dependencia de la que depende tu paquete no ha cambiado, ¿por qué pasar por todo el
00:12:46proceso de instalación de nuevo? Eso lleva tiempo, y el tiempo es dinero porque se te factura por el
00:12:52tiempo de ejecución de tu flujo de GitHub Actions. Y por supuesto, no quieres tener flujos que
00:12:56tarden una eternidad. Así que en la mayoría de los flujos, claro, por ejemplo, al construir los paquetes de TanStack,
00:13:00instalas las dependencias de los mismos, y luego haces el paso de compilación y construyes
00:13:06tu paquete de TanStack. De nuevo, si esas dependencias de TanStack no han cambiado,
00:13:12¿por qué reinstalarlas? Esa es la idea del caché. Y tiene sentido. Claro, el problema es que
00:13:18como esa ejecución de pull_request_target y otras ejecuciones de GitHub Actions,
00:13:24como las del activador push, comparten el mismo contexto, comparten el mismo caché. Y ahí es
00:13:31donde entra el envenenamiento del caché, porque el atacante pudo cachear una versión maliciosa o poner
00:13:39ese código malicioso en una dependencia de TanStack, por así decirlo, y cachearla. Entonces el atacante
00:13:46solo tuvo que esperar a que se ejecutara un flujo normal de GitHub Actions para los paquetes de TanStack.
00:13:53O sea, que algún mantenedor hiciera push de algún código, y entonces esa otra ejecución de GitHub Actions reutilizaría
00:14:01el mismo caché que fue configurado por la ejecución maliciosa anterior, y ahora extraería el
00:14:08caché envenenado preparado, que incluía el código malicioso. Así es como el código malicioso
00:14:13pasó del fork a la ejecución normal de GitHub Actions para un push normal de un mantenedor común
00:14:21que no ha sido afectado por ningún código malicioso. Así es como se usó el caché como un vehículo
00:14:28de transporte entre estas dos ejecuciones de GitHub Action al final. Y luego, como tercer paso, una vez que el
00:14:35código malicioso llegó a una ejecución regular de un flujo CICD de TanStack, debido a ese evento
00:14:44de push, robó un token de NPM de corta duración, un token OIDC al final, para publicar una versión maliciosa
00:14:54del paquete TanStack. Ahora, ¿a qué me refiero aquí? NPM tiene esa característica, que se llama
00:15:00trusted publishing (publicación de confianza), que en teoría hace que publicar paquetes en NPM sea más seguro, porque
00:15:04hay básicamente dos formas de publicar un paquete en NPM, se podría decir. Una es que creas un
00:15:11token con tu cuenta de NPM y lo usas para publicar nuevas versiones de tu paquete. El problema
00:15:19es que si ese token es robado, cualquiera puede publicar una nueva versión de ese paquete. Para aumentar la
00:15:26seguridad, existe este proceso de trusted publishing donde NPM dice no, no puedes publicar paquetes desde
00:15:33tu máquina, tienes que pasar por uno de estos proveedores de confianza, siendo GitHub Actions uno de
00:15:37ellos, y hay una integración de trusted publishing para GitHub Actions que puedes configurar. Y entonces,
00:15:44como parte de ese proceso de publicación confiable, se recuperará un token de publicación de corta duración
00:15:50o se solicitará. Y luego ese token de corta duración se usará para firmar esa nueva versión
00:15:57del paquete que se está publicando. Así que, en teoría, la idea es que el token es difícil de robar porque
00:16:03no está en la máquina de ningún mantenedor. Y además, es de corta duración. Incluso si fuera robado,
00:16:08no está activo por mucho tiempo. El problema, por supuesto, es que si el código que se ejecuta en el
00:16:15flujo CICD que solicita ese token confiable, si ese código ha sido afectado, entonces ese código
00:16:21malicioso tiene acceso a este nuevo token de publicación confiable de corta duración. Y eso es lo que pasó
00:16:27aquí. Así que ese código malicioso abusó de este token o usó este token para luego publicar una nueva versión
00:16:36del paquete TanStack. Ahora, curiosamente, este ataque en realidad falló un poco porque sí
00:16:44obtuvo ese token confiable y lo usó para contactar con la API de NPM para publicar una nueva versión
00:16:52del paquete TanStack que incluía este gusano, que incluía el código malicioso. Pero en realidad
00:16:58terminó en un flujo de GitHub Actions que no pudo completarse porque había algo mal en
00:17:06el código que se subió a CICD. Así que si los atacantes hubieran prestado atención para ejecutar su
00:17:12ataque en un momento en que se subiera código válido, entonces por supuesto este flujo se habría
00:17:19completado y no habrían tenido que depender de publicar un paquete malicioso manualmente contactando
00:17:26con la API de NPM, sino que podrían haber inyectado el código malicioso en este flujo como
00:17:32hicieron, dejar que este flujo terminara con éxito y entonces una versión comprometida de TanStack se habría
00:17:38publicado pareciendo muy válida porque fue un push normal de un mantenedor y el flujo
00:17:45terminó con éxito. La forma en que funcionó este ataque, debido a que ese flujo de trabajo no terminó con éxito,
00:17:51hizo que fuera un poco más fácil pillar lo que estaba pasando por parte de un colaborador externo aquí al final,
00:18:00porque se podía ver que se publicó una nueva versión de los paquetes de TanStack a pesar de que el
00:18:05flujo de GitHub Actions falló, por lo que no debería haberse publicado ninguna versión nueva. Así que se podía ver un
00:18:12desajuste allí, lo que facilitó un poco la detección de este ataque, que es una parte donde los
00:18:19mantenedores de TanStack y todos nosotros tuvimos suerte. No obstante, un ataque bastante elaborado, como
00:18:26probablemente puedan notar, que funcionó totalmente sin comprometer la máquina de nadie y, aunque se detectó
00:18:32rápido, hizo un daño serio porque, como mencioné, todavía se está propagando y eso fue un episodio
00:18:41largo sobre todo eso, lo sé, pero realmente quiero enfatizar que tienen que trabajar en hacer su sistema
00:18:49seguro, como compartí antes, como comparto en este video, quieren asegurarse de reducir el
00:18:56peligro de verse afectados; este ataque de nuevo se pilló rápido y aun así se sigue propagando,
00:19:05así que aún no ha terminado y es posible que no todos los ataques se pillen tan rápido
00:19:11en el futuro; como mencioné, tuvieron un poco de suerte aquí, podría haber sido más difícil detectar este
00:19:18ataque, entonces tal vez el daño sería aún mayor; pero ya es bastante grande aquí y
00:19:24no ha terminado, y veremos más ataques así, estoy seguro, porque como mencioné, la superficie de ataque
00:19:31se está volviendo más grande e interesante, hay más gente escribiendo código, mucha gente que
00:19:36no sabe lo que está haciendo y la IA ayuda a ejecutar tales ataques; así que sí, esto es lo que está pasando
00:19:42ahora mismo, si no tienen que hacerlo, quizás no instalen nada, comprueben dos veces su configuración y
00:19:48encontrarán todos los enlaces abajo si quieren profundizar, si quieren ver la lista completa de paquetes
00:19:51afectados y demás.

Key Takeaway

Un ataque de gusano automatizado explotó vulnerabilidades en el flujo de CI/CD de TanStack mediante pull_request_target y envenenamiento de caché para robar credenciales y propagar versiones maliciosas en NPM y Python.

Highlights

  • Un ataque masivo a la cadena de suministro afectó a todos los paquetes de TanStack el 11 de mayo de 2026 y se extendió a los ecosistemas de NPM y Python.

  • El malware funciona como un gusano que roba tokens de GitHub, credenciales de AWS y secretos del sistema para publicar nuevas versiones comprometidas de otros paquetes.

  • La detección del ataque fue posible porque se publicaron versiones de TanStack manualmente a pesar de que el flujo de trabajo de GitHub Actions falló.

  • El vector de ataque utilizó una combinación de pull_request_target y el envenenamiento del caché de GitHub Actions para inyectar código malicioso.

  • Gestores de paquetes como Bun permiten configurar una edad mínima de lanzamiento (min-age) para evitar la instalación automática de versiones recién publicadas potencialmente maliciosas.

Timeline

Alcance y naturaleza del ataque a TanStack

  • El ataque comprometió todos los paquetes de TanStack incluyendo Query, Router y Start en un periodo de 20 minutos.
  • La infección se propaga de forma automatizada hacia otros paquetes como los de Mistral y el ecosistema de Python.
  • El malware actúa como un gusano diseñado para la exfiltración masiva de credenciales y datos sensibles.

La brecha de seguridad comenzó el 11 de mayo y se detectó con rapidez, aunque el código malicioso ya se había infiltrado en múltiples dependencias. El sistema de propagación utiliza la identidad de los usuarios afectados para infectar nuevos proyectos. El alcance actual incluye tanto el registro de NPM como el índice de paquetes de Python (PyPI).

Identificación de sistemas comprometidos

  • Cualquier instalación de paquetes TanStack realizada durante la tarde del 11 de mayo (UTC) debe considerarse comprometida.
  • El tráfico de red saliente hacia URLs específicas es un indicador definitivo de exfiltración de datos.
  • La verificación de hashes SHA específicos en archivos JS como el del Router confirma la presencia de código malicioso.

Existen indicadores de compromiso (IoC) claros que los desarrolladores deben revisar en sus registros de sistema. El malware busca activamente tokens de acceso y los envía a servidores externos controlados por los atacantes. Se recomienda suspender toda instalación de paquetes nuevos hasta que la situación se estabilice por completo.

Mecanismos de robo y propagación del malware

  • El malware escanea ubicaciones típicas del sistema en busca de tokens de NPM, GitHub y secretos de AWS.
  • Los flujos de CI/CD que dependen de paquetes de TanStack ejecutan el código malicioso y permiten el robo de credenciales de publicación.
  • El uso de tokens robados permite al gusano publicar versiones infectadas de paquetes legítimos sin intervención del mantenedor.

El objetivo principal es la recolección de secretos almacenados en el disco duro o en variables de entorno. Una vez que obtiene acceso a un flujo de CI/CD, el atacante puede suplantar la identidad del desarrollador para escalar el ataque. Este método garantiza que la infección se mueva de un repositorio a otro de forma lateral.

Estrategias de defensa y endurecimiento del sistema

  • El desarrollo de software debe realizarse en entornos aislados como máquinas virtuales o contenedores de desarrollo (dev containers).
  • Configurar una edad mínima de publicación en archivos como bunfig.toml previene la instalación de malware de día cero.
  • El uso de servicios de gestión de secretos como Infisical o Doppler elimina la necesidad de almacenar archivos .env en texto plano.

La seguridad se mejora significativamente al desactivar los scripts de post-instalación en los gestores de paquetes. Las herramientas modernas como Bun o las versiones recientes de pnpm ofrecen bloqueos nativos para estos scripts del ciclo de vida. Adoptar el inicio de sesión único (SSO) para servicios de nube evita el almacenamiento de claves permanentes en la máquina local.

Análisis técnico del vector de ataque en GitHub Actions

  • El disparador pull_request_target ejecuta flujos de trabajo en el contexto del repositorio base, permitiendo el acceso al caché compartido.
  • El atacante envenenó el caché de GitHub Actions insertando código malicioso en una dependencia simulada mediante el comando hashfiles.
  • La función Trusted Publishing de NPM fue abusada mediante el robo en memoria de tokens OIDC de corta duración.

El ataque aprovechó el diseño de GitHub Actions donde las pull requests de forks pueden interactuar con el caché del repositorio original si se usa el activador incorrecto. Al realizar un push legítimo, el mantenedor extrajo sin saberlo el caché envenenado que contenía el malware. Aunque los tokens OIDC son temporales, el código malicioso los utilizó instantáneamente para publicar las versiones comprometidas antes de que expiraran.

Community Posts

No posts yet. Be the first to write about this video!

Write about this video