- Se publicaron en npm dos versiones maliciosas del cliente HTTP axios ampliamente usado, que al instalarse distribuían un troyano de acceso remoto (RAT)
- Los atacantes robaron las credenciales de la cuenta del mantenedor para eludir GitHub Actions y subir manualmente los paquetes maliciosos
- Las versiones maliciosas incluían una dependencia falsa
plain-crypto-js@4.2.1que instalaba el RAT mediante un scriptpostinstally luego borraba rastros - El RAT infecta macOS, Windows y Linux, y se comunica con el servidor C2 (
sfrclak.com:8000) para descargar cargas adicionales - npm y GitHub retiraron rápidamente las versiones maliciosas, pero volvió a quedar en evidencia la importancia de reforzar la seguridad de la cadena de suministro y proteger las credenciales
Resumen del ataque a la cadena de suministro de axios en npm
- El 31 de marzo de 2026 se publicaron en npm dos versiones maliciosas de la biblioteca cliente HTTP axios ampliamente utilizada (
axios@1.14.1,axios@0.30.4) - Los atacantes robaron las credenciales npm de un mantenedor principal de axios, eludieron el pipeline CI/CD de GitHub Actions y publicaron manualmente los paquetes maliciosos
- Ambas versiones insertaron una dependencia falsa
plain-crypto-js@4.2.1; este paquete instalaba un troyano de acceso remoto (RAT) mediante un scriptpostinstall - El RAT apunta a macOS, Windows y Linux, y se comunica con el servidor C2 (Command and Control) (
sfrclak.com:8000) para descargar una carga de segunda etapa - Tras la instalación, borra el código malicioso y sus rastros, y reemplaza el archivo por un
package.jsonlimpio para evadir la detección forense
Línea de tiempo del ataque
- 30 de marzo 05:57 UTC: se publica
plain-crypto-js@4.2.0(versión legítima) - 30 de marzo 23:59 UTC: se publica
plain-crypto-js@4.2.1(versión maliciosa), con ganchopostinstall - 31 de marzo 00:21 UTC: se publica
axios@1.14.1, con la dependencia maliciosa insertada - 31 de marzo 01:00 UTC: se publica
axios@0.30.4, con la misma dependencia maliciosa insertada - 31 de marzo 03:15 UTC: npm elimina las dos versiones maliciosas
- 31 de marzo 04:26 UTC: npm reemplaza
plain-crypto-jspor un stub de contención de seguridad (0.0.1-security.0)
Descripción general de axios
- axios es el cliente HTTP más usado en el ecosistema JavaScript, y se utiliza tanto en Node.js como en navegadores
- Con más de 300 millones de descargas semanales, una sola versión maliciosa ya tiene potencial de causar daños a gran escala
- Para un desarrollador común es difícil darse cuenta de que se instala código malicioso durante
npm install
Etapas del ataque
-
Etapa 1 — Compromiso de la cuenta del mantenedor
- Los atacantes comprometieron la cuenta npm
jasonsaaymany cambiaron el correo aifstap@proton.me - Después publicaron builds maliciosos en las ramas de lanzamiento 1.x y 0.x
- Las versiones legítimas se publican mediante OIDC Trusted Publisher de GitHub Actions, pero
axios@1.14.1se publicó manualmente, singitHeadni firma OIDC - Se presume que los atacantes usaron un token de acceso npm de larga duración
- Los atacantes comprometieron la cuenta npm
-
Etapa 2 — Despliegue previo de la dependencia maliciosa
plain-crypto-js@4.2.1fue publicado desde la cuentanrwise@proton.me- Se hacía pasar por
crypto-jsusando la misma descripción y la misma URL de repositorio - Incluía el gancho
"postinstall": "node setup.js", que se ejecuta automáticamente al instalar - Tras el ataque, reemplazó
package.mdporpackage.jsonpara preparar el borrado de evidencia
-
Etapa 3 — Inserción de la dependencia en axios
- Se agregó
plain-crypto-js@^4.2.1como dependencia de runtime - Nunca se importa en el código → dependencia fantasma (phantom dependency)
- Al ejecutar
npm install, se instala automáticamente y corre el scriptpostinstall
- Se agregó
Análisis del dropper RAT (setup.js)
-
Técnicas de ofuscación
- Las cadenas se guardan cifradas en el arreglo
stq[]y se descifran con_trans_1(XOR) y_trans_2(Base64 + orden inverso) - La URL C2 es
http://sfrclak.com:8000/6202033 - Entre las cadenas descifradas hay identificadores de SO (
win32,darwin), rutas de archivos y comandos de shell
- Las cadenas se guardan cifradas en el arreglo
-
Cargas por plataforma
-
macOS
- Escribe un AppleScript en
/tmpy lo ejecuta conosascript - Descarga el binario RAT desde el C2, lo guarda en
/Library/Caches/com.apple.act.mondy lo ejecuta - El nombre del archivo se disfraza como si fuera un daemon del sistema de Apple
- Escribe un AppleScript en
-
Windows
- Busca la ruta de PowerShell y copia el archivo a
%PROGRAMDATA%\\wt.exe - Mediante VBScript descarga y ejecuta un RAT en PowerShell desde el C2
- Los archivos temporales (
.vbs,.ps1) se eliminan tras ejecutarse
- Busca la ruta de PowerShell y copia el archivo a
-
Linux
- Descarga
/tmp/ld.pyconcurly lo ejecuta connohup python3 - El archivo
/tmp/ld.pypermanece en el sistema - En las tres plataformas usa cuerpos POST a
packages.npm.org/product0~2para disfrazarse como tráfico legítimo de npm
- Descarga
-
-
Autoborrado y ocultamiento
- Elimina
setup.jsypackage.json - Reemplaza
package.mdporpackage.jsonpara hacerse pasar por un paquete legítimo - Después de eso,
npm audito una revisión manual ya no lo detectan - Aun así, la sola presencia de
node_modules/plain-crypto-js/es evidencia de infección
- Elimina
Verificación de ejecución con StepSecurity Harden-Runner
- Harden-Runner registra en tiempo real eventos de red, procesos y archivos dentro de GitHub Actions
- Al instalar
axios@1.14.1se detectaron dos conexiones al C2 (curl,nohup)- La primera conexión ocurrió 2 segundos después de iniciar
npm install - La segunda ocurrió 36 segundos después y siguió ejecutándose como proceso en segundo plano
- La primera conexión ocurrió 2 segundos después de iniciar
- El análisis del árbol de procesos mostró que el proceso
nohupquedó huérfano bajo PID 1 (init), confirmando que seguía en ejecución - En los logs de eventos de archivos,
package.jsonfue sobrescrito dos veces- Primera: durante la instalación se escribió la versión maliciosa
- Segunda: 36 segundos después se reemplazó por un stub limpio
Indicadores de compromiso (IOC)
-
Paquetes npm maliciosos
- axios@1.14.1 · shasum: 2553649f232204966871cea80a5d0d6adc700ca
- axios@0.30.4 · shasum: d6f3f62fd3b9f5432f5782b62d8cfd5247d5ee71
- plain-crypto-js@4.2.1 · shasum: 07d889e2dadce6f3910dcbc253317d28ca61c766
-
Red
- Dominio C2: sfrclak.com
- IP: 142.11.206.73
- URL:
http://sfrclak.com:8000/6202033
-
Rutas de archivos
- macOS:
/Library/Caches/com.apple.act.mond - Windows:
%PROGRAMDATA%\\wt.exe - Linux:
/tmp/ld.py
- macOS:
-
Cuentas del atacante
jasonsaayman(mantenedor comprometido)nrwise(cuenta creada por el atacante)
-
Versión segura
- axios@1.14.0 (legítima)
Verificación del impacto y procedimiento de respuesta
- Revisar
npm list axiosopackage-lock.jsonpara confirmar 1.14.1 / 0.30.4 - Verificar si existe
node_modules/plain-crypto-js - Si aparecen archivos del RAT según el sistema operativo, debe considerarse una infección total del sistema
- Revisar en los logs de CI/CD si se instalaron esas versiones y rotar todas las claves y tokens secretos
Pasos de recuperación
- Fijar axios en una versión segura (1.14.0 o 0.30.3)
- Eliminar la carpeta
plain-crypto-jsy reinstalar connpm install --ignore-scripts - Si se detectan rastros del RAT, reconstruir el sistema
- Rotar todas las credenciales (AWS, SSH, CI/CD, etc.)
- Revisar el pipeline CI/CD y reemplazar secretos
- Usar la opción
--ignore-scriptsen builds automáticos - Bloquear el dominio/IP C2 con el firewall o
/etc/hosts
Funciones de StepSecurity Enterprise
-
Harden-Runner
- Aplica una lista permitida de tráfico saliente en GitHub Actions
- Bloquea tráfico anómalo y registra logs
- Puede bloquear de antemano la conexión a
sfrclak.com:8000
-
Dev Machine Guard
- Monitorea en tiempo real los paquetes npm instalados en PCs de desarrolladores
- Detecta de inmediato equipos con
axios@1.14.1o0.30.4instalados
-
npm Package Cooldown Check
- Aplica un período temporal de bloqueo de instalación a paquetes recién publicados
- Puede detectar publicaciones maliciosas rápidas como
plain-crypto-js@4.2.1
-
Compromised Updates Check
- Bloquea merges de PR con base en una base de datos en tiempo real de paquetes maliciosos
- Registra de inmediato
axios@1.14.1yplain-crypto-js@4.2.1
-
Package Search
- Busca en PR y repositorios de toda la organización dónde se introdujo un paquete específico
- Permite identificar de inmediato el alcance del impacto (repositorios, equipos, PR)
-
AI Package Analyst
- Monitorea en tiempo real el registro npm y realiza detección conductual de malware
- Detectó ambas versiones maliciosas a los pocos minutos de su publicación
-
Threat Center Alert
- Proporciona alertas de inteligencia de amenazas con resumen del ataque, IOC y procedimiento de respuesta
- Asegura visibilidad en tiempo real mediante integración con SIEM
Agradecimientos
- Los mantenedores de axios y la comunidad respondieron rápidamente a través del issue #10604 de GitHub
- GitHub suspendió la cuenta comprometida y npm eliminó las versiones maliciosas y aplicó el security holder
- La respuesta coordinada entre mantenedores, GitHub y npm ayudó a minimizar el daño a desarrolladores de todo el mundo
2 comentarios
Nunca pensé que comprometerían un paquete de este tamaño; lo de axios está más allá de lo imaginable.
Comentarios de Hacker News
npm, bun, pnpm y uv ahora admiten configurar un tiempo mínimo antes de aceptar una nueva versión de paquete
Yo agregué
ignore-scripts=trueen~/.npmrc, y solo con esa configuración ya se podía mitigar la vulnerabilidadbun y pnpm no ejecutan scripts de lifecycle por defecto
Ejemplos de configuración para cada package manager:
exclude-newer = "7 days"min-release-age=7minimum-release-age=10080minimumReleaseAge = 604800Curiosamente, cada uno usa una unidad de tiempo distinta
Si usas agentes LLM, esta configuración puede causar fallas, así que conviene agregar instrucciones relacionadas en
AGENTS.mdoCLAUDE.mdtimeoutMinutesen lugar detimeoutmin-release-age=7 # daysen realidad no funcione~/.yarnrc.ymlcomonpmMinimalAgeGate: "3d"A varios les sorprendió enterarse de que Axios estuvo expuesto a un ataque a la cadena de suministro
Axios no contenía código malicioso internamente, pero se le inyectó una dependencia falsa,
plain-crypto-js@4.2.1, que ejecutaba un script de postinstall para instalar un RAT (troyano de acceso remoto)Es una buena noticia para quienes usan pnpm o bun y tienen que aprobar manualmente los scripts de postinstall
Se planteó que los package managers son un experimento fallido
Existen bibliotecas C de alta calidad compuestas por un solo archivo
.c, como SQLite, y con ese enfoque se puede evitar el problema de las dependencias transitivasLa mayor parte de la superficie de ataque surge precisamente de esas dependencias indirectas
Incluso OpenSSL está siendo reescrito por problemas de calidad de código, y en JS es difícil ampliar la librería estándar, así que abundan los polyfills
En cambio, se propuso endurecer los estándares de calidad en repositorios como npm y permitir el registro solo a mantenedores responsables
Salió la broma de que algunos empiezan el día saludando con un resignado: “¿Qué paquete de npm habrán comprometido hoy?”
Para usuarios de Linux, se recomendó usar bwrap para aislar en sandbox toda la lógica de build de npm, pip, cargo, gradle, etc.
bwrap ofrece un entorno aislado como Docker, pero sin necesidad de imágenes. Flatpak también se basa en esta tecnología
En despliegues de servidor, lo importante es el hardening de contenedores, y la clave es tratar el entorno de CI/CD como una zona no confiable
También sería buena idea usar el mismo sandbox para ejecutar IA
requiredentro del programaAl ver una y otra vez problemas con dependencias, algunos se preocupan por si al ecosistema de Rust le pasará algo parecido algún día
Aunque no es fácil inflar la biblioteca estándar, sí hace falta un sistema confiable de garantía de calidad para paquetes
Se comentó que gracias a la IA este trabajo extra ahora es más viable, y que en realidad así se debió haber hecho desde antes
Reglas clave para minimizar la exposición a ataques de cadena de suministro en NPM
--frozen-lockfileya hay suficiente protecciónAnte la pregunta “¿cómo se puede evitar por completo este tipo de ataques?”,
alguien comentó que le gustaría pasarse a Qubes OS para separar por completo el administrador de contraseñas y el entorno de build
Lo compararon con el equipo de protección personal (PPE) de un laboratorio químico: en el entorno de desarrollo también hace falta aislamiento y protección
pip ya empezó a bloquear instalaciones fuera de virtualenv, y esperan que en el futuro los package managers ofrezcan una opción para negarse a ejecutarse fuera de un sandbox
pnpm y bun ahora ignoran por defecto los scripts de postinstall, pero npm todavía los ejecuta
Conviene configurar
ignore-scripts=trueen~/.npmrcnpm sigue registrando 80 millones de descargas semanales
Se especuló que la filtración de credenciales de este incidente probablemente provino del caso anterior de LiteLLM
A algunos les inquieta usar Python o Node.js, pero sienten que en realidad es un problema generalizado