Mini Shai-Hulud ha vuelto. Como dije antes, aún no habíamos visto la magnitud total del ataque.
La campaña de npm que cubrimos en abril, cuando se dirigió a los paquetes de SAP, se ha convertido ahora en un compromiso mucho mayor. Nuestro Equipo de Malware detectó 373 entradas maliciosas de versiones de paquetes en 169 nombres de paquetes npm.
El objetivo básico sigue siendo el mismo: robar credenciales de máquinas de desarrolladores y runners de CI/CD, y luego usar esas credenciales para alcanzar más paquetes.
Lo que ha cambiado es la escala y la ruta de lanzamiento. Esta oleada no parece solo que alguien esté publicando versiones maliciosas manualmente. El malware está diseñado para ejecutarse dentro de los sistemas de compilación, robar el acceso a npm y GitHub, y abusar de las rutas de publicación de confianza para impulsar nuevos paquetes comprometidos.
Si leyó nuestra publicación anterior, Mini Shai-Hulud Targets SAP npm Packages With a Bun-Based Secret Stealer, esta es la continuación: la misma idea, pero con un radio de impacto mucho mayor.
Qué ocurrió
TanStack sigue siendo uno de los clusters más visibles, pero ya no es toda la historia. El conjunto afectado ahora incluye paquetes en @squawk, @tanstack, @uipath, @tallyui, @beproduct, @mistralai, @draftlab, @draftauth, @taskflow-corp, @tolka, y varios paquetes sin ámbito.
Los clústeres más grandes en esta campaña son:
@squawk: 87 entradas de paquete-versión@tanstack: 83 entradas de paquete-versión@uipath: 66 entradas de paquete-versión- paquetes sin ámbito: 39 entradas de paquete-versión
@tallyui: 30 entradas de paquete-versión@beproduct: 18 entradas de paquete-versión
Esta lista sigue en evolución. Puede consultar la lista completa de paquetes afectados al final del blog. Lo importante no es solo el número de paquetes, sino dónde se ejecutan. Es probable que estos paquetes estén instalados en entornos de desarrollo locales, trabajos de CI, flujos de trabajo de lanzamiento y sistemas de compilación internos.
Cómo funciona la nueva ola
En la ola de SAP, los paquetes comprometidos añadieron un preinstall hook que ejecutaba setup.mjs, que luego utilizó Bun para ejecutar una gran carga útil ofuscada llamada execution.js.
Esta ola utiliza una ruta ligeramente diferente.
En los paquetes TanStack comprometidos, el tarball del paquete incluye un nuevo archivo ofuscado en la raíz del paquete:
router_init.js
El paquete comprometido también añade una dependencia opcional que apunta a un paquete alojado en GitHub
"optionalDependencies": {
"@tanstack/setup": "github:tanstack/router#79ac49eedf774dd4b0cfa308722bc463cfe5885c"
}Esa dependencia de Git contiene un prepare script:
"scripts": {
"prepare": "bun run tanstack_runner.js && exit 1"
}Aquí está el truco. npm ejecuta scripts de ciclo de vida para las dependencias de Git durante la instalación. Así, un paquete que parece una dependencia normal puede acceder discretamente a una dependencia alojada en GitHub, ejecutar su prepare hook, y ejecutar la carga útil.
El && exit 1 al final también es interesante. Dado que la dependencia es opcional, fallar después de que se ejecute la carga útil puede hacer que la instalación parezca menos sospechosa. El código malicioso ya se ha ejecutado cuando npm considera que la dependencia opcional ha fallado.
Por qué la publicación de confianza es relevante aquí
Una de las partes más incómodas de esta ola es el uso de la publicación de confianza.
La publicación de confianza está diseñada para eliminar los tokens npm de larga duración de los flujos de trabajo de lanzamiento. Un flujo de trabajo de GitHub Actions puede usar OIDC para solicitar un token de publicación npm de corta duración, publicar el paquete y adjuntar la procedencia al lanzamiento.
Eso es bueno cuando el flujo de trabajo está limpio.
Es mucho peor cuando el código controlado por un atacante se ejecuta dentro del flujo de trabajo. En ese momento, el atacante podría no necesitar robar un token npm de larga duración en absoluto. Puede usar los propios permisos OIDC del flujo de trabajo para generar un token de publicación durante la compilación y publicar desde allí.
Esto también significa que la procedencia no es una señal de seguridad completa. Un paquete malicioso aún puede provenir del flujo de trabajo esperado de GitHub Actions si dicho flujo fue comprometido durante la publicación.
En pocas palabras: la procedencia puede indicar dónde se construyó el paquete. No prueba que la construcción fuera segura.
Lo que el payload intenta robar
La carga útil está diseñada para entornos de CI/CD y desarrollo.
Busca:
- Tokens de GitHub
- Tokens de npm
- Tokens OIDC de GitHub Actions
- Credenciales de AWS y metadatos de instancia
- Archivos de cuenta de servicio de Kubernetes
- Tokens de HashiCorp Vault y endpoints locales de Vault
- variables de entorno
- Secretos del sistema de archivos local
La carga útil también contiene lógica de propagación. Tras robar los tokens, intenta usarlos para encontrar paquetes que la víctima puede publicar, modificar archivos de paquetes, inyectar la dependencia maliciosa, actualizar versiones y publicar nuevas versiones comprometidas.
Esto es lo que lo convierte en algo más que un infostealer normal. El malware no solo intenta robar a la víctima actual, sino que también busca convertir el acceso de publicación de la víctima en la siguiente vía de infección.
Qué cambió del ataque a SAP
La ola de SAP fue menor en número de paquetes, pero aun así tuvo un alto impacto porque afectó a las herramientas de construcción empresariales.
Esta ola es más amplia. Los paquetes de TanStack son ampliamente utilizados en aplicaciones JavaScript modernas, especialmente en herramientas de enrutamiento y React full-stack. Un paquete comprometido en esa parte del árbol de dependencias puede propagarse rápidamente a muchos lugares.
También hay algunos cambios técnicos:
- los paquetes de SAP utilizaban
setup.mjsyexecution.js - la nueva ola de TanStack utiliza
router_init.jsy una dependencia alojada en GitHub@tanstack/setupdependencia - la nueva ola se apoya más en GitHub Actions, OIDC, la publicación de npm y el reempaquetado de paquetes
- la carga útil sigue estando basada en Bun y centrada en el robo de secretos
El patrón es el mismo, sin embargo: obtener la ejecución de código durante la instalación, robar credenciales, usar esas credenciales para publicar más malware.
Detección y mitigación
Empiece con los archivos lockfile y las cachés de paquetes.
Busque espacios de nombres y paquetes afectados:
@squawk/@tanstack/@uipath/@tallyui/@beproduct/nestjs-auth@mistralai/@draftauth/@draftlab/@taskflow-corp/cli@tolka/cli@ml-toolkit-ts/@mesadev/@dirigible-ai/sdk@supersurkhet/- paquetes sin ámbito enumerados anteriormente, incluyendo
safe-action,ts-dna,cross-stitch,cmux-agent-mcp,agentwork-cli,git-branch-selector,wot-api,git-git-git,nextmove-mcp, yml-toolkit-ts
Busque los nuevos archivos de payload y marcadores de dependencia:
router_init.jsrouter_runtime.jstanstack_runner.js@tanstack/setupgithub:tanstack/router#79ac49eedf774dd4b0cfa308722bc463cfe5885cbun run tanstack_runner.js
Busque en los logs de CI:
- ejecución inesperada de Bun durante
npm install - fallos de dependencias opcionales que involucren
@tanstack/setup - conexiones salientes durante la instalación de dependencias
- actividad de publicación de npm desde flujos de trabajo que no deberían haber publicado
- solicitudes de tokens OIDC de GitHub Actions durante pasos inesperados
Si una versión de paquete comprometida se ejecutó en una máquina de desarrollador o un runner de CI, rote los secretos de ese entorno. No se limite a los tokens de npm.
Rote o revise:
- tokens de npm y acceso de publicación de paquetes
- PATs de GitHub y secretos de GitHub Actions
- credenciales de cloud
- Tokens de cuentas de servicio de Kubernetes
- tokens de Vault
- secretos de despliegue
Audite también las publicaciones recientes de npm, las ejecuciones de GitHub Actions y los registros de procedencia. Un registro de procedencia válido no debe considerarse como prueba de que el paquete está limpio.
Indicadores de compromiso
Archivos y payloads:
router_init.jsrouter_runtime.jstanstack_runner.jsrouter_init.jsSHA-256:ab4fcadaec49c03278063dd269ea5eef82d24f2124a8e15d7b90f2fa8601266ctanstack_runner.jsSHA-256:2ec78d556d696e208927cc503d48e4b5eb56b31abc2870c2ed2e98d6be27fc96
Marcadores de paquete:
@tanstack/setupgithub:tanstack/router#79ac49eedf774dd4b0cfa308722bc463cfe5885cprepareejecución de scriptbun run tanstack_runner.js- archivo de payload a nivel raíz incluido fuera del contenido normal del paquete
Indicadores de red y servicio:
hxxp://filev2[.]getsession[.]org/file/hxxp://169[.]254[.]169[.]254/latest/meta-data/iam/security-credentials/hxxp://169[.]254[.]170[.]2hxxps://registry[.]npmjs[.]org/-/npm/v1/tokensvault[.]svc[.]cluster[.]local:8200
Marcadores de campaña:
Ha aparecido un Mini Shai-Hulud- Nombres de repositorio con temática de Dune utilizados para la salida y el staging del gusano
Conclusión
Mini Shai-Hulud ha pasado de un incidente menor centrado en SAP a un ataque más amplio a la cadena de suministro de npm.
La lección importante no es solo que se comprometieron más paquetes. Es que el malware está diseñado en torno al funcionamiento de los sistemas de lanzamiento modernos. Se ejecuta durante la instalación, busca credenciales de CI/CD, abusa de las rutas de publicación de GitHub y npm, e intenta propagarse al siguiente paquete.
Si alguno de los paquetes afectados se ejecutó en su entorno, considere la máquina o el runner como expuestos hasta que se roten los secretos y se revise la actividad de publicación reciente.
Cómo Aikido detecta esto
Si es usuario de Aikido, revise su feed central y filtre por problemas de malware. Esto aparecerá como un problema crítico de 100/100. Aikido realiza reescaneos cada noche, pero recomendamos activar un reescaneo manual ahora.
Si aún no es usuario de Aikido, puede crear una cuenta y conectar sus repositorios. Nuestra cobertura de malware está incluida en el plan gratuito, sin necesidad de tarjeta de crédito.
Para una cobertura más amplia en todo su equipo, el Endpoint Protection de Aikido le proporciona visibilidad y control sobre los paquetes de software instalados en los dispositivos de su equipo. Cubre extensiones de navegador, librerías de código, plugins de IDE y dependencias de compilación, todo en un solo lugar. Detenga el malware antes de que se instale.
Para una protección futura, considere Aikido Safe Chain (código abierto). Safe Chain se integra en su flujo de trabajo existente, interceptando comandos npm, npx, yarn, pnpm y pnpx y verificando los paquetes con Aikido Intel antes de la instalación.
Apéndice: Paquetes y versiones afectados
Lista actual de paquetes y versiones que nuestro equipo ha identificado:
@tanstack/history:1.161.9,1.161.12@tanstack/react-router:1.169.5,1.169.8@tanstack/router-core:1.169.5,1.169.8@tanstack/router-utils:1.161.11,1.161.14@tanstack/router-plugin:1.167.38,1.167.41@tanstack/virtual-file-routes:1.161.10,1.161.13@tanstack/router-generator:1.166.45,1.166.48@tanstack/start-server-core:1.167.33,1.167.36@tanstack/start-client-core:1.168.5,1.168.8@tanstack/start-storage-context:1.166.38,1.166.41@tanstack/start-plugin-core:1.169.23,1.169.26@tanstack/react-start-server:1.166.55,1.166.58@tanstack/react-start-client:1.166.51,1.166.54@tanstack/start-fn-stubs:1.161.9,1.161.12@tanstack/react-start:1.167.68,1.167.71@tanstack/react-start-rsc:0.0.47,0.0.50@mistralai/mistralai:2.2.2,2.2.3,2.2.4@tanstack/react-router-devtools:1.166.16,1.166.19@tanstack/router-devtools-core:1.167.6,1.167.9@tanstack/router-devtools:1.166.16,1.166.19@tanstack/router-ssr-query-core:1.168.3,1.168.6@tanstack/react-router-ssr-query:1.166.15,1.166.18@tanstack/router-cli:1.166.46,1.166.49@tanstack/zod-adapter:1.166.12,1.166.15@tanstack/eslint-plugin-router:1.161.9@tanstack/router-vite-plugin:1.166.53,1.166.56@tanstack/nitro-v2-vite-plugin:1.154.12,1.154.15@mistralai/mistralai-gcp:1.7.1,1.7.2,1.7.3@tanstack/solid-router:1.169.5,1.169.8@tanstack/solid-start:1.167.65,1.167.68@tanstack/solid-start-client:1.166.50,1.166.53@tanstack/solid-start-server:1.166.54,1.166.57@tanstack/solid-router-devtools:1.166.16,1.166.19@tanstack/start-static-server-functions:1.166.44,1.166.47@tanstack/vue-router:1.169.5,1.169.8@uipath/apollo-react:4.24.5@tanstack/solid-router-ssr-query:1.166.15,1.166.18safe-action:0.8.3,0.8.4@tanstack/valibot-adapter:1.166.12,1.166.15@tanstack/vue-start:1.167.61,1.167.64@uipath/apollo-wind:2.16.2@uipath/cli:1.0.1@tanstack/vue-start-server:1.166.50,1.166.53@squawk/types:0.8.2,0.8.3,0.8.4@uipath/rpa-tool:0.9.5@squawk/mcp:0.9.1,0.9.2,0.9.3,0.9.4@tanstack/vue-start-client:1.166.46,1.166.49@squawk/weather:0.5.6,0.5.7,0.5.8,0.5.9@squawk/airspace:0.8.1,0.8.2,0.8.3,0.8.4@squawk/icao-registry-data:0.8.4,0.8.5,0.8.6,0.8.7@tanstack/arktype-adapter:1.166.12,1.166.15@squawk/flightplan:0.5.2,0.5.3,0.5.4,0.5.5@squawk/airports:0.6.2,0.6.3,0.6.4,0.6.5@mesadev/sdk:0.28.3@squawk/geo:0.4.4,0.4.5,0.4.6,0.4.7@mesadev/rest:0.28.3@squawk/procedure-data:0.7.3,0.7.4,0.7.5,0.7.6@squawk/navaid-data:0.6.4,0.6.5,0.6.6,0.6.7@squawk/fix-data:0.6.4,0.6.5,0.6.6,0.6.7@squawk/navaids:0.4.2,0.4.3,0.4.4,0.4.5@squawk/fixes:0.3.2,0.3.3,0.3.4,0.3.5@squawk/airport-data:0.7.4,0.7.5,0.7.6,0.7.7@squawk/airway-data:0.5.4,0.5.5,0.5.6,0.5.7@squawk/units:0.4.3,0.4.4,0.4.5,0.4.6@squawk/procedures:0.5.2,0.5.3,0.5.4,0.5.5@squawk/airways:0.4.2,0.4.3,0.4.4,0.4.5@squawk/icao-registry:0.5.2,0.5.3,0.5.4,0.5.5@uipath/apollo-core:5.9.2@squawk/notams:0.3.6,0.3.7,0.3.8,0.3.9@uipath/filesystem:1.0.1@uipath/solutionpackager-tool-core:0.0.34@squawk/flight-math:0.5.4,0.5.5,0.5.6,0.5.7@squawk/airspace-data:0.5.3,0.5.4,0.5.5,0.5.6@mistralai/mistralai-azure:1.7.1,1.7.2,1.7.3@uipath/solution-tool:1.0.1@tanstack/eslint-plugin-start:0.0.4,0.0.7@uipath/maestro-tool:1.0.1@uipath/codedapp-tool:1.0.1@uipath/agent-tool:1.0.1@draftlab/auth:0.24.1,0.24.2@uipath/orchestrator-tool:1.0.1@uipath/integrationservice-tool:1.0.2@taskflow-corp/cli:0.1.24,0.1.25,0.1.26,0.1.27,0.1.28,0.1.29@tanstack/vue-router-ssr-query:1.166.15,1.166.18@uipath/rpa-legacy-tool:1.0.1@uipath/vertical-solutions-tool:1.0.1@uipath/flow-tool:1.0.2@uipath/codedagent-tool:1.0.1@uipath/common:1.0.1@uipath/resource-tool:1.0.1@uipath/auth:1.0.1@uipath/docsai-tool:1.0.1@uipath/case-tool:1.0.1@uipath/api-workflow-tool:1.0.1@tanstack/vue-router-devtools:1.166.16,1.166.19@uipath/test-manager-tool:1.0.2@uipath/robot:1.3.4@uipath/traces-tool:1.0.1@uipath/agent-sdk:1.0.2@uipath/integrationservice-sdk:1.0.2@uipath/maestro-sdk:1.0.1@uipath/data-fabric-tool:1.0.2@mesadev/saguaro:0.4.22@uipath/tasks-tool:1.0.1@uipath/insights-tool:1.0.1@uipath/insights-sdk:1.0.1@uipath/uipath-python-bridge:1.0.1@draftlab/db:0.16.1@uipath/ap-chat:1.5.7@uipath/project-packager:1.1.16@uipath/packager-tool-case:0.0.9@uipath/packager-tool-workflowcompiler-browser:0.0.34@uipath/packager-tool-connector:0.0.19@uipath/packager-tool-workflowcompiler:0.0.16@uipath/packager-tool-webapp:1.0.6@uipath/packager-tool-apiworkflow:0.0.19@uipath/packager-tool-functions:0.1.1ts-dna:3.0.1,3.0.2,3.0.3,3.0.4@uipath/widget.sdk:1.2.3@uipath/resources-tool:0.1.11@uipath/agent.sdk:0.0.18cross-stitch:1.1.3,1.1.4,1.1.5,1.1.6@uipath/codedagents-tool:0.1.12@uipath/aops-policy-tool:0.3.1@uipath/solution-packager:0.0.35@draftlab/auth-router:0.5.1,0.5.2cmux-agent-mcp:0.1.3,0.1.4,0.1.5,0.1.6,0.1.7,0.1.8agentwork-cli:0.1.4,0.1.5@uipath/packager-tool-bpmn:0.0.9@draftauth/core:0.13.1,0.13.2@dirigible-ai/sdk:0.6.2,0.6.3@uipath/packager-tool-flow:0.0.19git-branch-selector:1.3.3,1.3.4,1.3.5,1.3.6,1.3.7wot-api:0.8.1,0.8.2,0.8.3,0.8.4git-git-git:1.0.8,1.0.9,1.0.10,1.0.11,1.0.12@beproduct/nestjs-auth:0.1.2,0.1.3,0.1.4,0.1.5,0.1.6,0.1.7,0.1.8,0.1.9,0.1.10,0.1.11,0.1.12,0.1.13,0.1.14,0.1.15,0.1.16,0.1.17,0.1.18,0.1.19@ml-toolkit-ts/xgboost:1.0.3,1.0.4nextmove-mcp:0.1.3,0.1.4,0.1.5,0.1.6,0.1.7ml-toolkit-ts:1.0.4,1.0.5@uipath/telemetry:0.0.7@draftauth/client:0.2.1,0.2.2@ml-toolkit-ts/preprocessing:1.0.2,1.0.3@tallyui/connector-medusa:1.0.1,1.0.2,1.0.3@uipath/tool-workflowcompiler:0.0.12@uipath/vss:0.1.6@tallyui/theme:0.2.1,0.2.2,0.2.3@tallyui/storage-sqlite:0.2.1,0.2.2,0.2.3@uipath/solutionpackager-sdk:1.0.11@tallyui/connector-vendure:1.0.1,1.0.2,1.0.3@tallyui/core:0.2.1,0.2.2,0.2.3@tallyui/connector-woocommerce:1.0.1,1.0.2,1.0.3@tallyui/components:1.0.1,1.0.2,1.0.3@uipath/ui-widgets-multi-file-upload:1.0.1@tallyui/pos:0.1.1,0.1.2,0.1.3@tallyui/database:1.0.1,1.0.2,1.0.3@supersurkhet/cli:0.0.2,0.0.3,0.0.4,0.0.5,0.0.6,0.0.7@tallyui/connector-shopify:1.0.1,1.0.2,1.0.3@tolka/cli:1.0.2,1.0.3,1.0.4,1.0.5,1.0.6@supersurkhet/sdk:0.0.2,0.0.3,0.0.4,0.0.5,0.0.6,0.0.7@uipath/access-policy-tool:0.3.1@uipath/context-grounding-tool:0.1.1@uipath/gov-tool:0.3.1@uipath/admin-tool:0.1.1@uipath/identity-tool:0.1.1@uipath/llmgw-tool:1.0.1@uipath/resourcecatalog-tool:0.1.1@uipath/functions-tool:1.0.1@uipath/access-policy-sdk:0.3.1@uipath/platform-tool:1.0.1

