Volver a todas las publicaciones
Publicado el · por Renaud Deraison

El comando se llamaba aipoison

Socket encontró un clúster de 18 paquetes npm que suplantaban el scope privado @ali de Alibaba. Ninguno de los tarballs contenía malware. El RAT se armaba en el momento de la instalación a partir de un archivo JSON en un repositorio de GitHub que el atacante aún controla, y su plan de persistencia incluía parchear Python dentro de los directorios .skills de las herramientas de código con IA, con comandos llamados aipoison, aipoison_inject y aipoison_deploy. Leer el código no podía encontrar esto. Bromure Agentic Coding juzga lo que estuvo visible todo el tiempo: un paquete sin reputación se detiene a esperar tu consentimiento en el proxy del host, las tres descargas que arman el payload cruzan un cable que solo habla con destinos que tú aprobaste, y cada archivo que el RAT escribe cae en una VM que vive una tarea.

En algún lugar del payload final hay un comando llamado aipoison. Su trabajo es meterse en el directorio de skills de tu herramienta de código con IA y parchear un archivo Python, para que la próxima vez que te pongas a trabajar, el atacante también empiece.

El 3 de agosto de 2026, The Hacker News cubrió la investigación que Socket publicó a finales de julio: un clúster de unos dieciocho paquetes npm, preparados a finales de abril, que pasaron tres meses en el registro antes de que alguien los detectara. Suplantan los paquetes privados de Alibaba bajo el scope @ali publicando los mismos nombres sin scope (aone-cloud-cli, def-open-client, open-worker-cli, uniapi-bridge), de modo que un desarrollador o un build dentro de la organización objetivo resuelve el doble público y recibe un troyano de acceso remoto injertado en el árbol de dependencias. Karlo Zanki, investigador de Socket, lee el móvil como espionaje industrial.

Nada en los paquetes era malicioso

Abre cualquiera de esos tarballs y no encuentras nada que reportar. No hay hook de postinstall, lo primero que todo el mundo busca con grep. Los paquetes señuelo dependen de smart-config-manager, que depende de cloud-config-fetcher y local-config-parser. Un gestor de config, un fetcher, un parser: utilidades aburridas, cada una legible en un minuto.

La malicia vive en la composición, y en un archivo que el atacante nunca envió. Al importar, el fetcher descarga defaults/preferences.json desde un repositorio de GitHub que el atacante controla, y sigue controlando, y lo escribe en disco como .cloud-preferences.json. El parser evalúa las “reglas de transformación” de ese archivo dentro de un vm de Node, que es donde vive el ataque. Una de las reglas es un escape de sandbox con estatus de folclore:

var F = items.constructor.constructor;   // recover Function
var p = F('return process')();           // recover process

Desde process baja por una escalera de alternativas (getBuiltinModule, mainModule.require, mainModule.constructor._load) hasta que una de ellas entrega require en la versión de Node donde haya aterrizado. Luego descarga setting.js desde un bucket de almacenamiento de Alibaba Cloud, que toma la huella del host e instala el payload: en Windows, matar Alilang, la app de seguridad de la propia Alibaba, y reemplazar su app.asar por una copia troyanizada; en Linux, soltar un binario en /tmp, ejecutarlo desacoplado, borrar el archivo; en macOS, inyectarse en ~/.zshrc y registrar un LaunchAgent que se dispara cada diez minutos.

GBHackers puso el diseño en su titular: los atacantes repartieron el RAT entre paquetes para evadir revisiones de código aisladas. El atacante construyó esta campaña para sobrevivir a que alguien la leyera. Revisa cualquier paquete por separado y pasa. Revisa el árbol completo y sigue pasando, porque la parte hostil es un archivo JSON en un servidor, descargado después de que terminaste de revisar, editable por el atacante entre tu auditoría y tu instalación.

El plan de persistencia incluye a tu agente

Socket recuperó el payload final como aone-cli. Hace lo que hacen estas cosas: comandos de shell, subida y descarga de archivos, reconocimiento del host, capturas de pantalla, un proxy TCP inverso cifrado y un comando dws_lateral que se mueve por DingTalk. Su tráfico de C2 lleva cabeceras Origin y Referer falsificadas que dicen venir de un dominio interno de documentación de Alibaba.

Un grupo de comandos convierte esto en una historia de agentes de código. Junto a los verbos habituales, el RAT trae aipoison, aipoison_inject y aipoison_deploy. Parchean scripts de Python instalados en los directorios .skills de herramientas de desarrollo concretas, marcando el fragmento inyectado con # __INJECT_MARKER__, para que un script traído del C2 se ejecute más tarde, desde dentro de la herramienta, como tú. Entre los objetivos nombrados está Qoder, el IDE agéntico de la propia Alibaba, que superó los cinco millones de usuarios a los pocos meses de lanzarse el agosto pasado.

Alguien se sentó, miró la máquina del desarrollador moderno y eligió la carpeta de skills del agente como el punto de apoyo duradero: un directorio de scripts que se ejecuta con tus permisos al inicio de cada sesión, y que casi nadie revisa nunca con un diff. Ya vimos este movimiento antes, cuando un gusano se copió dentro de .claude para que el siguiente arranque del agente reinfectara la máquina. Se ha graduado: del truco improvisado de un gusano a un comando con nombre en un kit de espionaje.

Las partes que el atacante no podía esconder

Leer el código nunca iba a encontrar esto. El ataque aún tenía requisitos, y todos eran visibles: un paquete sin historial y sin reputación, tres conexiones salientes antes de poder actuar (el archivo de reglas en GitHub, la etapa en el almacenamiento en la nube, el C2), y una máquina que seguiría ahí mañana.

Bromure Agentic Coding pone una decisión sobre cada uno de ellos, y la toma en tu Mac, fuera de la caja donde corre el agente, donde nada de dentro puede discutir.

La instalación se detiene en el registro. Cada descarga de paquete cruza el proxy del lado del host, que aplica la política de supply chain de tu espacio de trabajo a la respuesta antes de que un byte llegue a la VM. Activa el filtrado de paquetes y el proxy consulta un proveedor de reputación por cada artefacto. Uno de los dos proveedores seleccionables es Socket, cuya investigación es el tema de este artículo. Cuando ninguna fuente habilitada puede avalar un paquete, el proxy retiene la descarga y te pregunta. Los dobles de un scope privado, publicados el trimestre pasado con un puñado de descargas y sin reputación en ninguna parte, se detienen ahí. La aplicación vive en el host por diseño: el .npmrc dentro de la VM puede endurecer la política y no puede aflojarla, así que la regla se mantiene incluso cuando la cosa comprometida es la cosa que vigila.

El cable rechaza el ensamblaje. Este diseño se rompe contra el consentimiento de salida, porque sin nada hostil en el tarball, la red es el ataque. El proxy del host comprueba cada una de las tres descargas (el archivo raw del GitHub del atacante, el bucket que sirve setting.js, el host de C2) contra los destinos que aprobaste para este perfil. El registro desde el que instalas está en esa lista. La ruta raw de un desconocido y un bucket bautizado con el nombre de un CLI del que nunca has oído hablar no lo están. El proxy no tiene opinión sobre items.constructor.constructor y no la necesita. Lee el destino, no encuentra nada aprobado y corta la conexión. Tu instalación termina, tu build corre, y el RAT nunca se arma, porque sus piezas nunca llegan a la misma habitación.

La persistencia recibe una máquina con una vida útil de una tarea. Supón que toda la cadena corre de todos modos, porque aprobaste un destino más amplio de lo que querías y las etapas aterrizan. La línea en ~/.zshrc, el LaunchAgent de los diez minutos, el app.asar troyanizado, el Python de .skills parcheado: todo eso se escribe en una VM Linux desechable, a un hipervisor de macOS, que guarda el espacio de trabajo de esta tarea, y que tiras cuando el trabajo se fusiona. aipoison es una apuesta a que la herramienta que parchea y el host que comprometió son la misma máquina longeva. En un perfil, esa apuesta pierde. El reconocimiento que corre primero vuelve con señuelos del broker: tus credenciales reales viven en el host y se inyectan en el cable solo para destinos aprobados, así que nunca estuvieron en la VM para ser recolectadas.

Cómo se arma el RAT: nada hostil está en el paquete1 · npm installtarballs limpiossin postinstall3 utilitarios2 · preferences.jsondel GitHub del atacanteescape de vm en reglaeditable tras tu auditoría3 · setting.jsdel almacenamientopayload según el OS.zshrc · LaunchAgent4 · C2shell · archivos · proxyaipoison → .skillsparchea tu tooling IALos pasos 2, 3 y 4 son eventos de red. El código que podías leer solo hacía el paso 1.Los mismos cuatro pasos, dentro de un perfil BromureVM Linux desechableagente · npm · lo que escriba el payload.zshrc, LaunchAgent, .skills → solo esta máquinacredenciales a mano: señuelos del brokerdesechada al terminar la tareacada saltoProxy del host, en tu Mac1 · registro → reputación, o te pregunta2 · raw del GitHub del atacante → rechazado3 · bucket desconocido → rechazado4 · C2 → rechazado
El ataque se arma a partir de tres descargas. Nada en los tarballs de npm es malicioso: la lógica hostil llega desde un archivo de GitHub que el atacante aún controla, las etapas llegan desde el almacenamiento en la nube, y el RAT entonces llama a casa. En un perfil Bromure, el proxy del host comprueba cada uno de esos saltos contra los destinos que aprobaste para este espacio de trabajo, y cada archivo que el payload escribe cae en una VM que existe una tarea.

Revisar un artefacto te informa sobre el artefacto

Los investigadores vuelven a enseñar esta lección cada semana en una biblioteca distinta. Ayer, una flag de confianza cayó porque la comprobación y la carga ocurrían en momentos distintos. En junio, un repositorio se mantuvo limpio porque el reverse shell vivía en un registro DNS. Ahora dieciocho paquetes se leen limpios porque la parte maliciosa es un archivo JSON que el atacante todavía sostiene.

Los agentes afilan esto, porque son rápidos. Un agente al que le pides conectar una API interna añade la dependencia, ejecuta la instalación y pasa al siguiente paso de la tarea en lo que tardas en cambiar de ventana. Esa velocidad es la razón entera por la que lo compraste. Pon el juicio donde la velocidad no pueda adelantarlo: en la descarga del registro y en el cable, donde tu Mac decide contra una política que definiste una vez, para cada paquete y cada conexión que hace el agente.

Sigue dejando que el agente instale cosas, porque ahí está la palanca. Instala Bromure Agentic Coding, activa las capas de supply chain y dale al perfil una lista de destinos que tengan sentido para el trabajo. La próxima campaña esconderá su payload en otro sitio, la única predicción segura en este negocio, y aun así tendrá que descargarlo por un cable que te pregunta primero.