Dentro del compromiso de la cadena de suministro de Axios: un RAT para gobernarlos todos

Elastic Security Labs analiza un compromiso de la cadena de suministro del paquete npm de Axios, ofreciendo un RAT unificado multiplataforma

Inside the Axios supply chain compromise - one RAT to rule them all

Elastic Security Labs publicó las reglas iniciales de triaje y detección para el compromiso de la cadena de suministro de Axios. Este es un análisis detallado del RAT y las cargas útiles.

Introducción

Elastic Security Labs identificó un compromiso en la cadena de suministro del paquete axios npm, uno de los paquetes más confiables del ecosistema JavaScript, con aproximadamente 100 millones de descargas semanales. El atacante comprometió una cuenta de mantenedor y publicó versiones con puerta trasera que entregaban un troyano de acceso remoto multiplataforma a sistemas macOS, Windows y Linux mediante un gancho malicioso de postinstalación.

Conclusiones clave

  • Se empleó una cuenta de mantenedor npm comprometida (jasonsaayman) para publicar dos versiones maliciosas del cliente HTTP de Axios, ampliamente empleado — 1.14.1 (última etiquetada) y 0.30.4 (legado etiquetado) — lo que significa que una instalación predeterminada de npm se resolvió en un paquete backdoor
  • El JavaScript malicioso despliega implantes de etapa 2 específicos de la plataforma para macOS, Windows y Linux
  • Las tres cargas útiles de etapa 2 son implementaciones del mismo RAT — protocolo C2 idéntico, conjunto de comandos, cadencia de baliza y user-agent suplantado, escritos en PowerShell (Windows), C++ (macOS) y Python (Linux)
  • El gotero realiza una limpieza antiforense eliminar a sí mismo y cambiando su package.json por una copia limpia, borrando la evidencia del disparador postinstalación de node_modules

Preámbulo

El 30de marzo de 2026, Elastic Security Labs detectó una vulnerabilidad en la cadena de suministro dirigida al paquete Axios npm mediante monitorización automatizada de la cadena de suministro. El atacante obtuvo el control de la cuenta npm perteneciente a jasonsaayman, uno de los principales mantenedores del proyecto, y publicó dos versiones backdoor en un plazo de 39 minutos.

El paquete axios es una de las bibliotecas cliente HTTP más empleadas en el ecosistema JavaScript. En el momento del descubrimiento, tanto las últimas como las antigas dist-tags apuntaban a versiones comprometidas, cerciorando que la mayoría de las instalaciones nuevas tuvieran un lanzamiento por backdoor.

Las versiones maliciosas introdujeron una única nueva dependencia: plain-crypto-js, un paquete diseñado específicamente cuyo gancho postinstalación descargaba y ejecutaba silenciosamente implantes RAT de etapa 2 específicos de la plataforma desde sfrclak[.]com:8000.

Lo que hace que esta campaña sea notable más allá de su radio de explosión es la maquinaria de la fase 2. El atacante desplegó tres implementaciones paralelas del mismo RAT — una para Windows, una macOS y una para Linux — todas compartiendo un protocolo C2, estructura de comandos y comportamiento de beacon idénticos. No son tres herramientas diferentes; Es un único marco de implantes multiplataforma con implementaciones nativas de plataforma.

Elastic Security Labs presentó un Aviso de Seguridad de GitHub al repositorio axios el 31 de marzo de 2026 a las 01:50 AM UTC para coordinar la divulgación y cerciorar que los mantenedores y el registro de npm pudieran actuar sobre las versiones comprometidas.

Mientras la comunidad señalaba el compromiso en redes sociales, Elastic Security Labs compartió públicamente los primeros hallazgos para ayudar a los defensores a responder en tiempo real.

Esta publicación cubre toda la cadena de ataque: desde el compromiso de la cadena de suministro a nivel npm pasando por el dropper ofuscado, hasta la arquitectura del RAT multiplataforma y las diferencias significativas entre sus tres variantes.

Resumen de la campaña

El compromiso es evidente en los metadatos del registro npm. El correo del mantenedor cambió de jasonsaayman@gmail[.]com — presente en todas las versiones legítimas anteriores — a ifstap@proton[.]me en las versiones maliciosas. El método de publicación también cambió:

VersiónPublicado porMethodProcedencia
axios@1.14.0 (legítimo)jasonsaayman@gmail[.]comOIDC de acciones en GitHubAtestaciones de procedencia de SLSA
axios@1.14.1 (comprometido)ifstap@proton[.]mePublicación directa de CLINinguno
axios@0.30.4 (comprometido)ifstap@proton[.]mePublicación directa de CLINinguno

El cambio de un flujo de editor OIDC confiable con procedencia SLSA a una publicación directa de CLI con un email modificado es un claro indicador de acceso no autorizado.

Línea de tiempo

  • 2026-02-18 17:19 UTCaxios@0.30.3 publicado legítimamente por jasonsaayman@gmail[.]com
  • 2026-03-27 19:01 UTCaxios@1.14.0 publicado legítimamente a través de GitHub Actions OIDC
  • 2026-03-30 05:57 UTCplain-crypto-js@4.2.0 publicado por nrwise (nrwise@proton.me) — limpiar señuelo para construir el historial del registro
  • 2026-03-30 23:59 UTCplain-crypto-js@4.2.1 publicado por nrwise — versión maliciosa con postinstall puerta trasera
  • 2026-03-31 00:21 UTCaxios@1.14.1 publicado por cuenta comprometida — etiquetado latest
  • 2026-03-31 01:00 UTCaxios@0.30.4 publicado por cuenta comprometida — etiquetado legacy

Paquetes afectados

  • axios@1.14.1 — Malicioso, etiquetado latest en el momento del descubrimiento
  • axios@0.30.4 — Malicioso, etiquetado legacy en el momento del descubrimiento
  • plain-crypto-js@4.2.0 — Señuelo limpio, publicado para construir la historia del registro
  • plain-crypto-js@4.2.1 — Vehículo malicioso, de entrega de carga (postinstall puerta trasera)

Versiones seguras: axios@1.14.0 (última versión legítima 1.x con procedencia de SLSA) y axios@0.30.3 (última versión legítima 0.30.x ).

El atacante etiquetaba tanto los canales más recientes como los heredados, maximizando el radio de explosión entre proyectos usando la API Axios actual o heredada.

Análisis de código

Etapa 1: El dropper de crypto-js simple

Toda la cadena de entrega depende del gancho del ciclo de vida posterior a la instalación de NPM. Instalar cualquiera de las versiones comprometidas de Axios plain-crypto-js@^4.2.1 atrae como dependencia, lo que declara:

"scripts": {
  "postinstall": "node setup.js"
}

Esto hace que setup.js se ejecute automáticamente durante la instalación de npm — sin necesidad de interacción del usuario.

El archivo setup.js emplea un esquema de codificación de dos capas para ocultar su comportamiento:

  • Capa 1: Reversión de cadenas seguida de decodificación Base64
  • Capa 2: Cifrado XOR usando el OrDeR_7077 clave con un índice dependiente de la posición (7 * i²% 10)

Todas las cadenas críticas, nombres de módulos, URLs y comandos de shell se almacenan en un array codificado stq[] y se decodifican en tiempo de ejecución. El contenido decodificado revela la infraestructura operativa:

Entrega específica de la plataforma

Tras decodificar su tabla de cadenas, el dropper comprueba os.platform() y se ramifica en una de tres rutinas de entrega. Cada uno envía un HTTP POST a http://sfrclak[.]com:8000/6202033 con un cuerpo específico para cada plataforma — packages.npm.org/product0 (macOS), packages.npm.org/product1 (Windows), packages.npm.org/product2 (Linux) — permitiendo que el C2 sirviera la carga útil correcta desde un único punto final. El packages.npm.org/ El prefijo es un intento deliberado de hacer que el tráfico saliente aparezca como una comunicación benigna del registro NPM en los registros de red:

PlatformMétodo de AdministraciónUbicación de la Fase 2Disfraz
macOSAppleScript mediante osascript descarga binario con curl/Library/Caches/com.apple.act.mondDemonio del sistema Apple
WindowsVBScript descargas .ps1 vía curl, se ejecuta mediante PowerShell renombrado (%PROGRAMDATA%\wt.exe)%TEMP%\6202033.ps1 (transitorio)Windows Terminal
LinuxDescarga directa de curl y ejecución de python3/tmp/ld.pyNinguno

Antiforense

El cuentagotas realiza dos acciones de limpieza:

  1. Autoeliminación: setup.js se elimina a sí mismo a través de fs.unlink(__filename)
  2. Intercambio de manifiestos de paquete: Un archivo limpio llamado package.md (que contiene una configuración benigna de la versión 4.2.0 sin gancho de postinstalación) se renombra como package.json, sobreescribir la versión maliciosa

La inspección posterior al incidente de node_modules/plain-crypto-js/package.json no revela rastro del disparador posterior a la instalación. La setup.js maliciosa desapareció. Solo los registros de lockfile y auditoría del NPM conservan pruebas.

Fase 2: RAT multiplataforma

Las tres cargas útiles de etapa 2: PowerShell para Windows, C++ compilado para macOS, Python para Linux no son tres herramientas diferentes. Son tres implementaciones de la misma especificación RAT, que comparten un protocolo C2, conjunto de comandos, formato de mensaje y comportamiento operativo idénticos. La consistencia indica claramente un solo desarrollador o un equipo estrechamente coordinado trabajando a partir de un documento de diseño compartido.

Arquitectura compartida

Las siguientes propiedades son idénticas en las tres variantes:

  • Transporte C2: HTTP POST
  • Codificación corporal: JSON codificado en Base64
  • Agente de usuario: mozilla/4.0 (compatible; msie 8.0; windows nt 5.1; trident/4.0)
  • Intervalo de baliza: 60 segundos
  • UID de sesión: cadena alfanumérica aleatoria de 16 caracteres, generada por ejecución
  • Tipos de mensajes salientes: FirstInfo, BaseInfo, CmdResult
  • Tipos de comandos entrantes: kill, peinject, runscript, rundir
  • Tipos de comandos de respuesta: rsp_kill, rsp_peinject, rsp_runscript, rsp_rundir

La cadena de usuario-agente falsificada de IE8/Windows XP es especialmente notable, es anacrónica en las tres plataformas y su presencia en un host de macOS o Linux es un fuerte indicador de detección.

Inicialización y reconocimiento

Al arrancar, cada variante:

  1. Genera un UID de sesión — 16 caracteres alfanuméricos aleatorios, incluidos en cada mensaje C2 posterior
  2. Detecta el sistema operativo y la arquitectura — informa de identificadores específicos de la plataforma (por ejemplo, windows_x64, macOS, linux_x64)
  3. Enumera los directorios iniciales de interés (perfil de usuario, documentos, escritorio, directorios de configuración)
  4. Envía una baliza FirstInfo que contiene el UID, el identificador del sistema operativo y la instantánea del directorio

Tras la inicialización, el implante entra en el bucle principal. El primer BaseInfo Heartbeat incluye un perfil completo del sistema. Las mismas categorías de datos se recopilan en todas las plataformas, aunque las APIs subyacentes difieren:

Datos recopiladosFuente de WindowsFuente de macOSFuente de Linux
Nombre de host%COMPUTERNAME% env vargethostname()/proc/sys/kernel/nombre de host
Nombre de usuario%USERNAME% env vargetuid() + getpwuid()os.getlogin()
Versión del sistema operativoWMI / registrosysctlbyname("kern.osproductversion")plataforma.sistema() + plataforma.release()
Zona horariaHuso horario del sistemalocaltime_r()fechatiempo.zona horaria
Tiempo de arranqueTiempo de funcionamiento del sistemasysctl("kern.boottime")/proc/uptime
Fecha de instalaciónRegistro / WMIstat("/") o sysctlctime de /var/log/installer o /var/log/dpkg.log
Modelo de hardwareWMIsysctlbyname("hw.model")/sys/class/dmi/id/product_name
Tipo de CPUWMIsysctlbyname()plataforma.máquina()
Process listPID completo, sesión, nombre, rutapopen("ps") (hasta 1000)Enumeración completa /proc (PID, PPID, usuario, cmdline)

Los latidos posteriores son ligeros, conteniendo solo una marca temporal para confirmar que el implante está vivo.

Despacho de mando

La respuesta C2 se analiza como JSON, y el campo tipo determina la acción. Las tres variantes implementan los mismos cuatro comandos:

matar — Auto-terminación. Envía un rsp_kill acuse de recibo y se va. El mecanismo de persistencia de la variante de Windows (clave de registro + archivo batch) sobrevive al comando de eliminación a menos que se limpie explícitamente; las variantes de macOS y Linux no tienen persistencia propia.

runscript — Ejecución de script/comando. La orden principal de interacción del operador. Acepta un campo Script (código a ejecutar) y un campo Param (argumentos). Cuando Script está vacío, Param se ejecuta directamente como un comando. El mecanismo de ejecución es nativo de la plataforma:

PlatformMecanismo de ejecución
WindowsPowerShell con -NoProfile -ep Bypass
macOSAppleScript vía /usr/bin/osascript
LinuxShell vía subprocess.run(shell=True) o Python vía python3 -c

peinject — Entrega binaria de carga útil. A pesar de la denominación centrada en Windows ("PE inject"), las tres plataformas implementan esto como una forma de eliminar y ejecutar cargas útiles binarias:

PlatformImplementation
WindowsCarga de ensamblador reflective .NET mediante [System.Reflection.Assembly]::Load()
macOSBase64-decodifica y elimina un binario, ejecutar con parámetros proporcionados por el operador.
LinuxBase64-decodifica un binario a /tmp/.<random La cadena de 6 caracteres> (archivo oculto), se inicia mediante subproceso. Popen().

La implementación de Windows tiene ejecución en memoria sin pérdida de archivo pero sin desactivar AMSI, que sin duda se detectará en la carga de ensamblador. Las variantes de macOS y Linux adoptan el enfoque más sencillo de escribir un binario en disco y ejecutarlo directamente.

rundir — Enumeración de directorios. Acepta rutas y devuelve listados detallados de archivos (nombre, tamaño, tipo, marcas de tiempo de creación/modificación, recuento de hijos para directorios). Permite al operador navegar interactivamente por el sistema de archivos.

Resumen de capacidades

CapacidadWindows (PowerShell)macOS (C++)Linux (Python)
PersistenciaClave de ejecución del registro + .bat ocultaNingunoNinguno
Ejecución de scriptsPowerShellAppleScript vía osascriptShell o Python en línea
Inyección binariaCarga reflectiva de .NET inyectar en cmd.exeDrop binario + ejecutarDrop binario a /tmp/ + ejecutar
AntiforenseVentanas ocultas, limpieza de archivos temporalesTemp oculto .scpt/tmp/ oculto. Archivos XXXXXX

Atribución

El binario Mach-O de macOS entregado por el gancho de postinstalación plain-crypto-js presenta una superposición significativa con WAVESHAPER, una puerta trasera de C++ rastreada por Mandiant y atribuida a UNC1069, un clúster de amenazas vinculado a la RPDC.

Conclusión

Esta campaña demuestra la continua atractividad del ecosistema de npm como vector de ataque a la cadena de suministro. Al comprometer una sola cuenta de mantenedor en uno de los paquetes más confiables del ecosistema JavaScript, el atacante obtuvo un mecanismo de entrega con potencial de alcance en millones de entornos.

El indicador de detección más fiable del kit de herramientas es también su elección de diseño más curiosa: la cadena de agente de usuario de IE8/Windows XP codificada de forma idéntica en las tres variantes de plataforma. Aunque proporciona una huella de protocolo consistente para el enrutamiento C2 en el lado del servidor, es fácilmente detectable en cualquier red moderna — y es una anomalía inmediata en hosts de macOS y Linux.

Elastic Security Labs continuará monitorizando este grupo de actividades y actualizará esta publicación con cualquier hallazgo adicional.

MITRE ATT&CK

Elastic usa el framework MITRE ATT&CK para documentar tácticas, técnicas y procedimientos comunes que las amenazas persistentes avanzadas emplean contra las redes empresariales.

Táctica

La táctica representa el porqué de una técnica o subtécnica. Es el objetivo táctico del adversario: la razón para realizar una acción.

Técnicas

Las técnicas representan cómo un adversario logra un objetivo táctico mediante la realización de una acción.

Observaciones

En esta investigación se discutieron los siguientes observables.

ObservableTipoNombreReferencia
617b67a8e1210e4fc87c92d1d1da45a2f311c08d26e89b12307cf583c900d101SHA-2566202033.ps1Carga útil de Windows
92ff08773995ebc8d55ec4b8e1a225d0d1e51efa4ef88b8849d0071230c9645aSHA-256com.apple.act.mondCarga útil de MacOS
fcb81618bb15edfdedfb638b4c08a2af9cac9ecfa551af135a8402bf980375cfSHA-256ld.pyCarga útil de Linux
sfrclak[.]comDominioC2
142.11.206[.]73IPv4-ADDRC2

Referencias

A lo largo de la investigación anterior se hizo referencia a lo siguiente: