Context
Recientemente, el sistema de monitoreo de seguridad MistEye detectó información sobre versiones anómalas en múltiples paquetes npm bajo la organización Red Hat Cloud Services. Este incidente involucra un total de 32 paquetes npm y 96 versiones pertenecientes a dicha organización. En este artículo, se seleccionan tres muestras locales para un análisis offline detallado: estas muestras no son paquetes de imitación de espacio de nombres ni de typo-squatting, sino versiones reales que utilizan el ámbito @redhat-cloud-services; el código fuente de las muestras confirma que sus tarballs contienen un cargador malicioso multicapa, oculto y diseñado para activarse automáticamente durante la instalación.
Tras la restauración completa, se puede confirmar: estos 3 muestras poseen capacidades de código fuente para lectura de memoria del GitHub Actions Runner, recolección de credenciales en múltiples nubes y locales, exfiltración y dead-drop a través de la API de GitHub, inyección en workflows de GitHub, autopropagación mediante npm, persistencia mediante Claude Code / VS Code / systemd / LaunchAgent, countermedidas contra Harden-Runner / StepSecurity, y detección de EDR y productos de seguridad. En términos de cobertura de capacidades, los posibles objetivos incluyen estaciones de desarrollo, runners de CI/CD, contenedores de construcción, repositorios de GitHub, workflows de GitHub Actions, cadenas de publicación de npm y credenciales de entornos en la nube; el alcance real del impacto debe confirmarse mediante registros de instalación, auditoría de repositorios y telemetría de la plataforma.
Desde la estructura del código, la ruta de propagación y la combinación de capacidades, este malware es una variante del malware Shai-Hulud.
MistEye response
MistEye es un sistema de inteligencia de amenazas Web3 y monitoreo de seguridad dinámico desarrollado internamente por SlowMist, que integra capacidades de monitoreo de seguridad y agregación de inteligencia para proporcionar a los usuarios alertas de riesgo en tiempo real y protección de activos.
Tras capturar el incidente de envenenamiento de la cadena de suministro del paquete npm de Red Hat Cloud Services y sus muestras maliciosas asociadas, el sistema MistEye ha activado una alerta de alto riesgo y ha realizado un análisis sistemático de la estructura de confusión, la descifrado de carga útil, la recuperación de capacidades y los IOC de esta cadena de ataque.
(https://enterprise.misteye.io/threat-intelligence/SM-2026-378450)
Visión general de la cadena de ataque
La parte de análisis técnico de este artículo se basa únicamente en un análisis estático local y fuera de línea, desempaquetando, decodificando y verificando la desobfuscación de 3 muestras de npm tgz.
Las muestras cubiertas en esta verificación son las siguientes:
@redhat-cloud-services/frontend-components-config
Versión: 6.11.3
tgz SHA-256: 0c9c67ec40d5f23efa1ec3470d0ac88b4993ccc0e92be913fc29a337dfc4f060
@redhat-cloud-services/types
Versión: 3.6.1
tgz SHA-256: d543bb3cdf1569c2b3d38c8a4081ed746cfe78bf3236c2302704d79ab7fa9558
@redhat-cloud-services/rule-components
Versión: 4.7.2
tgz SHA-256: aaf00d06baa3c679b82452c50014e9824b8874e9ca2d150f19095f8de19ba90f
Las tres muestras tienen la misma entrada de ataque: en todos los archivos package.json se encuentra scripts.preinstall = "node index.js". Esto significa que siempre que el entorno del desarrollador o CI/CD instale estas versiones, el archivo index.js en el directorio raíz se ejecutará automáticamente durante la fase de instalación, sin necesidad de que el usuario importe o ejecute explícitamente el código de negocio.
Tres muestras comparten la misma carga maliciosa central, pero difieren en los parámetros de envoltura externa. Es decir, las tres muestras utilizan diferentes valores de desplazamiento ROT/César y claves/AES-GCM IV/tag; esto dificulta la reutilización directa de características estáticas basadas en hash de la envoltura externa, claves fijas o desplazamientos fijos entre muestras. Sin embargo, el arrancador del entorno de ejecución Bun y el hash de la carga maliciosa central son idénticos: uno es un módulo auxiliar de inicio diseñado para preparar el entorno de ejecución Bun, y el otro es la carga principal que contiene las funciones maliciosas. En este artículo, se denominan respectivamente "Arrancador del entorno de ejecución Bun (nombre de variable en el código fuente _b)" y "Carga maliciosa central (nombre de variable en el código fuente _p)".
La cadena de ataque restaurada es la siguiente:

Análisis técnico
1. Entrada: secuestro de scripts de ciclo de vida de npm
Los tres muestras activan la cadena de ataque a través del hook de ciclo de vida preinstall en package.json:
"scripts": {
"preinstall": "node index.js"
}
preinstall se ejecutará automáticamente durante la fase de instalación de npm. Para componentes frontales comunes, definiciones de tipos o paquetes de componentes de reglas, generalmente no es necesario ejecutar un archivo JavaScript de gran tamaño en el directorio raíz durante la fase de instalación; este es el indicador más directo de una anomalía.
La evidencia a nivel de muestra es la siguiente:
@redhat-cloud-services/frontend-components-config@6.11.3
- principal: lib/index.js
- campo files: ["/lib", "/bin"]
- Archivo raíz index.js SHA-256: 545a1838c66e1771f58d84a17b3e1841e5eeab91a73f4ccc59c9492450a6d9c0
@redhat-cloud-services/types@3.6.1
- principal: index.d.ts
- Campo files: no configurado
- Índice raíz index.js SHA-256: b86c5ae9e95bd841a595440faa3eb6317441e746f241ae8fd641ab59ed1d1966
@redhat-cloud-services/rule-components@4.7.2
- principal: index.js
- Campo files: no configurado
- Índice raíz index.js SHA-256: 1a30a9abe20bab121aaa75ed040565af14e6cdfb745609ee0e7b94a2d814fb9c
En este caso, el campo files de frontend-components-config@6.11.3 solo declara "/lib" y "/bin", pero en la raíz del tarball existe un archivo index.js adicional que es llamado por preinstall. Esta anomalía solo se aplica a esta muestra; types@3.6.1 y rule-components@4.7.2 no tienen definido el campo files, por lo que esta anomalía no se generaliza a todas las muestras.
2. Primera capa: matriz de números + sustitución de letras ROT/César
Los archivos index.js de la raíz de los tres ejemplos son archivos JavaScript de una sola línea muy grandes, con una estructura consistente y un contenedor principal de try { eval(...) } catch (...)
Este wrapper primero convierte el gran arreglo de números en una cadena mediante String.fromCharCode, luego aplica un desplazamiento ROT/Caesar a las letras inglesas en la cadena y finalmente pasa el resultado descodificado a eval para su ejecución. El manejo de excepciones solo muestra el prefijo "wrapper:", reduciendo la exposición de errores evidentes en caso de fallo en la instalación.
Los valores de desplazamiento externo y el hash de Stage 2 de los tres muestras son los siguientes:
frontend-components-config@6.11.3
index.js tamaño: 4.294.798 bytes
ROT/Caesar shift: 10
Etapa 2 SHA-256: b19c2fd48535c8c40aeb3e627ce92775f33ef9292611767bb1236c238e6f90cc
types@3.6.1
index.js tamaño: 4,135,588 bytes
ROT/Caesar shift: 4
Etapa 2 SHA-256: 9c0425aa6e6d7792ac38d24f3e7245f42fcaa553ddfeb6bd97677017f10c3b75
rule-components@4.7.2
index.js tamaño: 4,294,336 bytes
ROT/Caesar shift: 11
Etapa 2 SHA-256: d590bd375d95e4ac072b7ebc1fc4489bcaf5f20a939e92486267aa398bcf1e5d
3. Capa dos: Desencriptación AES-128-GCM del arrancador Bun y la carga útil principal
El código de la Etapa 2, tras descodificar ROT/Caesar, realiza la desencriptación AES-128-GCM (Advanced Encryption Standard - Galois/Counter Mode) mediante Node.js crypto.createDecipheriv y establece la etiqueta de autenticación mediante setAuthTag. El objetivo de la desencriptación son dos componentes posteriores: el iniciador del entorno de ejecución Bun y la carga útil maliciosa principal.
Entre ellos, el iniciador del entorno Bun se encarga de detectar, localizar o preparar el entorno Bun para que el código posterior pueda ejecutarse a través de Bun; la carga maliciosa principal es el núcleo de la cadena de ataque e incluye las principales capacidades maliciosas, como la recopilación de credenciales, la propagación a través de GitHub/npm, la persistencia, la evasión de protecciones y la desencriptación de recursos incrustados.
Cada una de las tres muestras utilizó una clave AES-128-GCM diferente, un vector de inicialización y una etiqueta de autenticación para cifrar ambos componentes, pero después de descifrar, el SHA-256 de los tres entornos de ejecución Bun es ac2a2208e1726e008be6c73dc0872d9bba163319259dff1b62055ac933ca46b6, y el SHA-256 de las tres cargas útiles maliciosas principales es 0dc06ecdaa63fe24859cfd955053c23245c536e4733480239d14bebf12688e35. Esto indica que el atacante cambió los parámetros de envoltura externa en diferentes paquetes npm, pero reutilizó el mismo conjunto de componentes maliciosos principales.
Después de desencriptar, Stage 2 escribe la carga útil maliciosa principal en /tmp, la ejecuta a través de Bun y luego elimina el archivo temporal. La lógica real recuperada de las tres muestras es la siguiente:
Por lo tanto, el patrón de archivo temporal verificable en las tres muestras es:
/tmp/p.js
El iniciador del entorno Bun tiene un tamaño de 898 bytes, y los tres hashes de muestra son idénticos:
ac2a2208e1726e008be6c73dc0872d9bba163319259dff1b62055ac933ca46b6
El iniciador del entorno de ejecución de Bun contiene lógica como child_process.execSync, fs.existsSync, fs.mkdtempSync, fs.chmodSync, os.platform(), os.arch(), getBunPath(), etc., para localizar o preparar el entorno de ejecución de Bun. Es decir, la Etapa 2 no asume simplemente que Bun está instalado globalmente en el sistema; en rutas de ejecución distintas a las de Bun, primero carga el iniciador del entorno de ejecución de Bun y luego llama a Bun mediante getBunPath() para ejecutar la carga útil maliciosa principal.
4. Tercer nivel: tabla de cadenas de obfuscator.io
La carga útil maliciosa desencriptada no es JavaScript en texto plano legible directamente, sino que sigue siendo confundida mediante una técnica de tabla de cadenas al estilo obfuscator.io. Esta capa agrupa numerosas cadenas en un array y las restaura mediante índices en tiempo de ejecución y lógica de rotación, impidiendo que los analistas puedan recuperar directamente las API clave, rutas y nombres de configuración posteriores hasta que no completen la restauración de la tabla de cadenas.
5. Cuarta capa: B5 Cifrado de cadena personalizada
Después de desenmascarar la tabla de cadenas de obfuscator.io, aún existe una capa adicional de cifrado de cadenas personalizado B5 dentro de la carga útil maliciosa principal. Se han confirmado los siguientes parámetros:
- KDF: PBKDF2 (Password-Based Key Derivation Function 2)
- Función hash: SHA-256
- Número de iteraciones: 200000
- longitud de la clave: 32 bytes
- Rondas de descifrado: 3
- contraseña: ba2c6ddb3672bdd6a611e6850b4f700b52aed3dab2f1b3d5f8c839d4a157a709
- salt: 5b26508dc0f1075a7c0b4d8aa464487e
El resultado desencriptado es el siguiente:
Entre ellos, tras descifrar B5, son visibles múltiples cadenas de texto plano clave. Es importante tener en cuenta que algunas cadenas originalmente se encontraban en la tabla de cadenas de obfuscator.io y solo serán directamente grepables después de completar ambos pasos: "reemplazo de tabla de cadenas + descifrado B5":
6. Capa de incrustación adicional: AES-256-GCM + gzip
La carga útil maliciosa principal también contiene recursos incrustados cifrados con AES-256-GCM y comprimidos con gzip. La lógica de restauración utiliza:
Los recursos incrustados clave resueltos se clasifican en tres categorías según su función:
Lectura de memoria entre plataformas:
Este tipo de recurso se utiliza para leer la memoria de procesos en ejecución. Las claves y tokens en archivos normales aún pueden descubrirse mediante búsqueda de archivos, pero los CI/CD Runner o herramientas de desarrollo almacenan temporalmente ciertos valores sensibles en memoria durante su ejecución. Los atacantes incorporan scripts de lectura de memoria para las plataformas Linux, Windows y macOS con el objetivo de capturar estos secrets temporales desde la memoria de los procesos en distintos sistemas.

Configuración persistente:
Estos recursos se utilizan para "dejar puntos de activación de puertas traseras". Es decir, incluso después de que el proceso inicial de instalación de npm haya finalizado, los atacantes desean que el código malicioso se ejecute nuevamente cuando el desarrollador abra el proyecto, inicie el editor, ingrese a una sesión de Claude Code o tras un reinicio del sistema. Por lo tanto, estos recursos apuntan a configuraciones a nivel de proyecto y mecanismos de inicio automático a nivel de usuario: las configuraciones a nivel de proyecto son más discretas, mientras que los servicios a nivel del sistema son más adecuados para ejecución prolongada.

C2 y propagación:
Estos recursos incrustados se utilizan para la posterior transferencia de cadenas de control y secrets del repositorio. Tras desencriptarse, YZ es un monitor de búsqueda de commits de GitHub que busca periódicamente mensajes de commit en el formato firedalazer ., verifica la firma y descarga y ejecuta contenido Python remoto; zZ, tras desencriptarse, es una plantilla de workflow de GitHub Actions llamada Run Copilot, que escribe ${{ toJSON(secrets) }} en format-results.txt y lo sube como artifact. El primero proporciona la cadena para obtener/ejecutar tareas posteriores, mientras que el segundo ofrece una plantilla para transferir secrets del repositorio mediante artifacts de GitHub Actions; la inyección real del workflow, la espera de ejecución y la descarga del artifact se completan mediante la lógica de API de GitHub incluida en la carga principal.

Análisis de las capacidades de la carga útil maliciosa principal
Tras completar la desconfusión en múltiples capas, la muestra finalmente libera y ejecuta la carga maliciosa principal. Todos los siguientes análisis se centran en el módulo de carga maliciosa principal, desglosado paso a paso en cinco etapas: obtención de datos, exfiltración, propagación, persistencia y evasión.
Lectura de memoria del ejecutor de GitHub Actions:
La muestra incluye scripts de lectura de memoria para las plataformas Linux, Windows y macOS, con capacidad de dump cruzada. La implementación en Linux realiza la extracción de memoria leyendo /proc//maps y /proc//mem del proceso objetivo:
La lógica de activación del payload malicioso principal está dirigida al runner de Linux de GitHub Actions: cuando GITHUB_ACTIONS === "true" y RUNNER_OS === "Linux", el código busca el proceso Runner.Worker, realiza un volcado de memoria y extrae secretos enmascarados con el formato "":{"value":"","isSecret":true}. Las rutas de recolección activa confirmadas en las tres muestras se centran en el runner de Linux, aunque los scripts para las tres plataformas ya están incrustados.
2. Nubes múltiples y recopilación de credenciales locales del desarrollador:
La carga útil maliciosa principal incluye un módulo sistemático de recopilación de credenciales que cubre proveedores de nube, entornos CI, configuraciones locales de desarrolladores, GitHub CLI, gestores de contraseñas y archivos de billeteras.
Los objetivos de recopilación de credenciales del proveedor de nube son:

El módulo AWS también incluye lógica relacionada con ECS/IMDS (Instance Metadata Service)/STS WebIdentity.
La recopilación de credenciales locales del desarrollador cubre los siguientes objetivos:

La lógica del gestor de contraseñas se implementa en el código fuente como un array runCommand(command, args), en lugar de concatenación de cadenas shell.
El módulo de recopilación de credenciales cubre una amplia gama de objetivos, desde plataformas en la nube hasta entornos locales de desarrolladores; los datos sensibles recopilados se exfiltraron mediante los siguientes mecanismos.
3. GitHub API externo y dead-drop:
La carga útil maliciosa principal utiliza la API de GitHub como canal principal para la exfiltración de datos. La solicitud falsifica el User-Agent como python-requests/2.31.0 y, tras validar el token mediante x-oauth-scopes (que debe incluir repo, public_repo o workflow), ejecuta la exfiltración: crea un repositorio (con la descripción fija como Miasma: The Spreading Blight) y escribe los datos robados, codificados en base64, mediante PUT /repos///contents/results/.
Además, la carga útil implementa un mecanismo dead-drop basado en la búsqueda de commits de GitHub, obteniendo instrucciones C2 mediante la búsqueda del marcador "thebeautifulmarchoftime" (o "thebeautifulsnadsoftime"):
let result = await X9("thebeautifulmarchoftime ", xZ);
El recurso incrustado YZ.bin es un monitor independiente de commits de GitHub que realiza sondeos cada 3600 segundos en busca de mensajes de commit en formato firedalazer. Tras la verificación de la firma, descarga y ejecuta contenido Python remoto. Esto constituye una cadena de control posterior independiente del canal principal de exfiltración.
El código fuente también contiene un cuerpo de configuración de remitente HTTP POST dirigido a los puntos finales api.anthropic.com y v1/api. El campo noop de esta configuración está establecido en true, lo que significa que, sin modificaciones externas, este remitente no realizará solicitudes de red reales. Por lo tanto, el análisis estático solo puede confirmar la existencia de esta estructura de código, pero no prueba la presencia de una transmisión activa hacia la API de Anthropic.
4. Repositorio de GitHub e infección del flujo de trabajo:
La carga útil maliciosa principal puede manipular objetos git del repositorio mediante la API REST / GraphQL de GitHub:

Un workflow malicioso construido con carga útil, disfrazado como release, solicita permisos de id-token: write y utiliza la ruta OIDC (OpenID Connect) para intercambiar un token de publicación de npm. Las variables de entorno y la interfaz de la ruta OIDC son ACTIONS_ID_TOKEN_REQUEST_TOKEN y ACTIONS_ID_TOKEN_REQUEST_URL, con el audience configurado como npm:registry.npmjs.org. A nivel de código fuente, se puede confirmar que la carga útil tiene la capacidad de inyectar workflow en repositorios de GitHub y obtener permisos de publicación mediante OIDC / publicación confiable de npm.
Además del método anterior de inyección de workflow a través de git refs, la carga útil incluye un mecanismo más sutil para transferir secretos: un workflow de GitHub Actions disfrazado como Run Copilot escribe ${{ toJSON(secrets) }} en format-results.txt y sube el artifact. En comparación con escribir directamente los secretos en el contenido del repositorio, este enfoque se centra más en transferir datos a través de los artefactos generados por el workflow, y las revisiones convencionales de diff de código podrían no mostrar directamente el contenido final de los secretos exportados.
5. Ejecutar el flujo de Copilot mediante artifact para transferir secrets:
El recurso incrustado zZ.bin es un flujo de trabajo de GitHub Actions disfrazado como Copilot que escribe ${{ toJSON(secrets) }} en format-results.txt y lo sube como artifact.
El comportamiento asociado de la API de GitHub incluye: crear/actualizar una rama temporal → escribir el blob del workflow → esperar la ejecución del workflow → descargar el archivo zip del artifact → leer format-results.txt → eliminar la ejecución del workflow y la rama temporal. Los términos de búsqueda relacionados incluyen Run Copilot, VARIABLE_STORE, format-results, chore/add-codeql-static-analysis, .github/workflows/codeql.yml.
6. Auto-propagación de npm:
La carga útil maliciosa principal tiene dos rutas de publicación/difusión de npm independientes.
Ruta del token npm: La carga útil enumera los tokens npm del usuario actual mediante GET /-/npm/v1/tokens, filtra los tokens con bypass_2fa === true y permisos de escritura en paquetes, y utiliza estos tokens para publicación automatizada. bypass_2fa es un campo de metadatos del token, no un parámetro del cuerpo de publicación.
Ruta de GitHub Actions OIDC: Lee las variables de entorno ACTIONS_ID_TOKEN_REQUEST_TOKEN y ACTIONS_ID_TOKEN_REQUEST_URL, solicita un token OIDC con el audience npm:registry.npmjs.org, e intercambia el token OIDC de npm mediante la interfaz de intercambio de tokens OIDC de npm para obtener permisos de publicación.
El proceso para contaminar el tarball de destino es desempaquetar → escribir index.js malicioso → modificar package.json:
Aquí se distinguen dos tipos de entradas: los tres muestras cargadas localmente utilizan preinstall: "node index.js" — en este caso, el entorno de instalación no requiere la instalación previa de Bun, ya que usar Node.js como entrada inicial es más discreto; cuando se propaga automáticamente y contamina otros paquetes, se escribe preinstall: "bun run index.js" y se añade la dependencia de bun — porque la lógica posterior de la carga maliciosa depende de las API proporcionadas por el entorno de ejecución de Bun (como Bun.gunzipSync y Bun.file), y en escenarios de propagación automática es necesario asegurar que el entorno objetivo tenga Bun.
7. Mecanismo de persistencia:
La carga útil maliciosa principal incluye cuatro métodos de persistencia, que cubren el directorio del proyecto y el inicio automático a nivel del sistema.
Claude Code SessionStart hook: El recurso incrustado S8.bin escribe el hook SessionStart en .claude/settings.json, ejecutando automáticamente node .claude/setup.mjs al iniciar cada sesión de Claude Code. La carga maliciosa también se escribe en .claude/setup.mjs y .claude/index.js (la ruta se concatena con ".claude/" + M0, donde M0 = "index.js").
Tarea folderOpen de VS Code: incrustar el recurso EZ.bin para escribir la tarea folderOpen en .vscode/tasks.json y ejecutar automáticamente el mismo script al abrir la carpeta del proyecto infectado. También escribir en .vscode/setup.mjs.
kitty-monitor (systemd / LaunchAgent): Embeds the RZ.bin resource to install a persistent service, with files distributed across /.local/share/kitty/cat.py, /.config/systemd/user/kitty-monitor.service (Linux), and ~/Library/LaunchAgents/com.user.kitty-monitor.plist (macOS). The malicious payload creates the /tmp/kitty- directory, writes YZ.bin (GitHub commit monitor) to cat.py, and installs it via RZ.bin.
gh-token-monitor (systemd / LaunchAgent): Instala el servicio de monitoreo de token de GitHub incrustando el recurso jZ.bin, con archivos distribuidos en las rutas /.local/bin/gh-token-monitor.sh y /.config/gh-token-monitor/, junto con las rutas correspondientes de systemd / LaunchAgent. Este monitor detecta si el token de GitHub devuelve un código de estado 40x o si los metadatos del paquete npm @cap-js/openapi@1.4.1 son anormales, y al activarse ejecuta el controlador:
Esto significa que cuando el monitor detecta que la API de GitHub devuelve un código de estado 40x, por ejemplo, cuando el token ha sido revocado, expirado o presenta un estado de permisos anormal, el script malicioso ejecuta el handler proporcionado. El handler recuperado de las tres muestras de este artículo es rm -rf ~/; rm -rf ~/Documents. Al realizar la respuesta, no se debe revocar el token directamente en el host que aún podría estar ejecutando el payload; en su lugar, primero se debe aislar el host, eliminar los elementos de persistencia y los procesos en ejecución, y luego rotar las credenciales desde un entorno limpio.
8. Harden-Runner / StepSecurity:
La carga útil maliciosa principal incluye lógica de detección y destrucción específica para StepSecurity Harden-Runner, eludiendo las protecciones de CI/CD mediante los siguientes pasos:
- Verificar si el socket de Docker /var/run/docker.sock está disponible;
- Listar contenedores Docker que coincidan con los términos clave harden-runner o stepsecurity en el nombre o la imagen;
- Terminar el contenedor coincidente mediante POST /containers//kill;
- Crear un contenedor Alpine con privilegios y reescribir sudoers como runner ALL=(ALL) NOPASSWD:ALL;
- Escribir resoluciones inválidas para los dominios relacionados con StepSecurity en /etc/hosts;
- Sobrescribir /etc/resolv.conf con 8.8.8.8 y 1.1.1.1.
Esta lógica de ataque indica que la muestra se adaptó específicamente a entornos CI/CD protegidos por StepSecurity.
9. EDR / Detección de productos de seguridad, evaluación del entorno y evasión:
La carga útil maliciosa principal detecta nombres de procesos y rutas de instalación de múltiples productos EDR (Endpoint Detection and Response) / de seguridad:

La carga también incluye lógica de evitación de región: detecta las variables de entorno LC_ALL, LC_MESSAGES, LANGUAGE y LANG; si, tras convertirlas a minúsculas, comienzan con "ru", se omite la ejecución. Se admite la identificación de entornos CI como GitHub Actions, GitLab CI, Travis CI, CircleCI, Jenkins, AWS CodeBuild, Buildkite, AppVeyor, Bitbucket, Drone, TeamCity y Cirrus CI. Las marcas de estado utilizadas durante la ejecución incluyen tmp.0987654321.lock, __IS_DAEMON (marca para subprocesos daemon desacoplados), SKIP_DOMAIN (omite la ruta del remitente de dominio), /tmp/kitty-*, cat.py y /var/tmp/.gh_update_state.
Análisis de impacto
Desde la perspectiva de la capacidad del código fuente, el impacto de estos tres ejemplos no se limita a una ejecución única durante la fase de instalación de npm. Su riesgo real se puede dividir en cuatro niveles:
Nivel del host del desarrollador. La muestra recopilará variables de entorno, .npmrc, .pypirc, claves SSH, configuración de Docker, .env, token de GitHub CLI, datos del gestor de contraseñas y archivos de billetera, y mantendrá la capacidad de activación posterior mediante Claude Code, VS Code, servicio de usuario de systemd o LaunchAgent de macOS.
Nivel del ejecutor CI/CD. El ejemplo identifica el ejecutor Linux de GitHub Actions, lee la memoria del proceso Runner.Worker y extrae secretos enmascarados; además, posee lógica de contramedida contra StepSecurity Harden-Runner, intentando dañar o eludir los componentes de protección CI/CD.
A nivel de organización y repositorio de GitHub. Las muestras pueden crear repositorios mediante la API de GitHub, escribir en contents/results/, manipular git refs/blobs/trees/commits, inyectar flujos de trabajo maliciosos y transferir secretos mediante Run Copilot workflow + artifact.
Nivel de propagación del ecosistema npm. Se pueden seleccionar muestras de tokens npm con permisos de escritura de paquete y bypass_2fa === true, o aprovechar la ruta de GitHub Actions OIDC / publicación confiable de npm para obtener capacidad de publicación; luego, descargar el tarball objetivo, insertar un cargador malicioso, modificar preinstall, agregar dependencias de Bun, aumentar la versión patch y publicar, creando así una cadena de propagación automática en npm.
Resumen
La evidencia del código fuente de tres muestras muestra que este paquete malicioso no es simplemente un script de robo de información durante la instalación, sino una combinación de un loader multietapa y un implant completo: la capa externa se aleatoriza según el paquete, mientras que el iniciador del entorno de ejecución Bun y la carga útil maliciosa central permanecen coherentes; el implant principal abarca múltiples etapas, incluyendo la recopilación de credenciales, la extracción de secretos de CI, la propagación a través de GitHub/npm, la persistencia y la evasión de protecciones.
Diseño de entrada de alta ocultación. Los atacantes no insertan lógica maliciosa en el código de negocio, sino que montan un loader enmascarado en los scripts de ciclo de vida de npm. Este loader se encarga principalmente de desencriptar y ejecutar la carga útil incrustada, lo que hace que sea difícil detectar las verdaderas capacidades mediante solo la revisión del código fuente del negocio.
Cadena de desconfusión anidada en múltiples capas. La carga maliciosa pasa por cinco capas de empaquetado: matriz de números + sustitución de letras ROT, cifrado AES-128-GCM, confusión mediante obfuscator.io, cifrado de cadena personalizado B5, y capa incrustada AES-256-GCM + gzip. Las claves o parámetros de cada capa pueden variar independientemente entre paquetes, dificultando la detección masiva basada en características estáticas.
Capacidad de ataque organizativo completa. Este implant posee capacidades para leer memoria de GitHub Actions Runner, recolectar credenciales en múltiples nubes y locales, exfiltrar datos mediante GitHub API y dead-drop, infectar repositorios y workflows de GitHub, auto-propagarse mediante npm, y mantener persistencia y contrarrestar medidas de protección. Desde la estructura del código fuente, ya cuenta con rutas de código para desencadenar una propagación desde una instalación puntual hacia repositorios, CI/CD y cadenas de publicación de npm; el alcance real de la propagación debe confirmarse mediante logs de instalación, auditorías de repositorios y telemetría de la plataforma.
Lo que se puede confirmar a partir de la evidencia del código fuente es que los tres muestras se activan automáticamente mediante preinstall y desencriptan y ejecutan el mismo implant principal. Sin embargo, no se puede probar únicamente con estas tres muestras tgz cómo se obtuvo el permiso inicial en el evento real.
Recomendación de disposición
- Identificar y eliminar versiones maliciosas en las dependencias del proyecto, el archivo lock, la caché del registro privado y la caché de compilación.
- Verifique si en los registros de instalación aparecen preinstall, node index.js, bun run, /tmp/p*.js, tmp.0987654321.lock.
- No revoque directamente el token en el host afectado que aún podría estar ejecutando el payload. Se recomienda aislar primero el host afectado, limpiar los procesos en ejecución y los elementos de persistencia, y luego rotar los tokens relacionados con GitHub, npm, credenciales en la nube, Kubernetes, Vault, SSH, Docker registry y gestores de contraseñas desde un entorno limpio.
- Verifique el repositorio de GitHub reciente en cuanto a branch, commit, workflow, artifact y repositorios recién creados, con énfasis en las palabras clave Run Copilot, format-results, chore/add-codeql-static-analysis, .github/workflows/codeql.yml, OIDC_PACKAGES.
- Verifique si se han agregado o modificado los siguientes archivos del directorio del proyecto: .claude/settings.json, .claude/setup.mjs, .vscode/tasks.json, .vscode/setup.mjs.
- Verificar la persistencia a nivel de usuario: /.local/share/kitty/cat.py, /.config/systemd/user/kitty-monitor.service, ~/Library/LaunchAgents/com.user.kitty-monitor.plist, archivos relacionados con gh-token-monitor.
- Verifique el historial de publicación de npm para confirmar si existen lanzamientos de parches no autorizados; además, audite los metadatos del token de npm, centrándose en los tokens que puedan omitir la autenticación de dos factores y que tengan permisos de escritura para paquetes.
- Realizar una auditoría de integridad de los productos derivados construidos en entornos contaminados.
IOC
Archivos maliciosos
nombre de archivo: redhat-cloud-services-frontend-components-config-6.11.3.tgz MD5: 633ad8849a59e2bfb7a0fe589e816a07 SHA1: 675294612f455fe6a9acb195f0cbe3687d8e2e34 SHA256: 0c9c67ec40d5f23efa1ec3470d0ac88b4993ccc0e92be913fc29a337dfc4f060
nombre de archivo: redhat-cloud-services-types-3.6.1.tgz MD5: 9e6c5af01438b52c9a411686c1f1b8ff SHA1: 88d098c8d96e9ae17550e9798c3b62c420464b8c SHA256: d543bb3cdf1569c2b3d38c8a4081ed746cfe78bf3236c2302704d79ab7fa9558
nombre de archivo: redhat-cloud-services-rule-components-4.7.2.tgz MD5: f1ffdbf5e639899f26a6ebab2eec408d SHA1: f3c5c21274045ae02fef11e931de6dcf8462a067 SHA256: aaf00d06baa3c679b82452c50014e9824b8874e9ca2d150f19095f8de19ba90f
SHA256
ac2a2208e1726e008be6c73dc0872d9bba163319259dff1b62055ac933ca46b6
0dc06ecdaa63fe24859cfd955053c23245c536e4733480239d14bebf12688e35
Dependencia maliciosa
npm:@redhat-cloud-services/topological-inventory-client@3.0.10
npm:@redhat-cloud-services/topological-inventory-client@3.0.11
npm:@redhat-cloud-services/topological-inventory-client@3.0.13
npm:@redhat-cloud-services/compliance-client@4.0.3
npm:@redhat-cloud-services/compliance-client@4.0.4
npm:@redhat-cloud-services/compliance-client@4.0.6
npm:@redhat-cloud-services/rbac-client@9.0.3
npm:@redhat-cloud-services/rbac-client@9.0.4
npm:@redhat-cloud-services/rbac-client@9.0.6
npm:@redhat-cloud-services/insights-client@4.0.4
npm:@redhat-cloud-services/insights-client@4.0.5
npm:@redhat-cloud-services/insights-client@4.0.7
npm:@redhat-cloud-services/frontend-components@7.7.2
npm:@redhat-cloud-services/frontend-components@7.7.3
npm:@redhat-cloud-services/frontend-components@7.7.5
npm:@redhat-cloud-services/frontend-components-utilities@7.4.1
npm:@redhat-cloud-services/frontend-components-utilities@7.4.2
npm:@redhat-cloud-services/frontend-components-utilities@7.4.4
npm:@redhat-cloud-services/remediations-client@4.0.4
npm:@redhat-cloud-services/remediations-client@4.0.5
npm:@redhat-cloud-services/remediations-client@4.0.7
npm:@redhat-cloud-services/frontend-components-notifications@6.9.2
npm:@redhat-cloud-services/frontend-components-notifications@6.9.3
npm:@redhat-cloud-services/frontend-components-notifications@6.9.5
npm:@redhat-cloud-services/patch-client@4.0.4
npm:@redhat-cloud-services/patch-client@4.0.5
npm:@redhat-cloud-services/patch-client@4.0.7
npm:@redhat-cloud-services/host-inventory-client@5.0.3
npm:@redhat-cloud-services/host-inventory-client@5.0.4
npm:@redhat-cloud-services/host-inventory-client@5.0.6
npm:@redhat-cloud-services/rule-components@4.7.2
npm:@redhat-cloud-services/rule-components@4.7.3
npm:@redhat-cloud-services/rule-components@4.7.5
npm:@redhat-cloud-services/frontend-components-advisor-components@3.8.2
npm:@redhat-cloud-services/frontend-components-advisor-components@3.8.4
npm:@redhat-cloud-services/frontend-components-advisor-components@3.8.6
npm:@redhat-cloud-services/notifications-client@6.1.4
npm:@redhat-cloud-services/notifications-client@6.1.5
npm:@redhat-cloud-services/notifications-client@6.1.7
npm:@redhat-cloud-services/sources-client@3.0.10
npm:@redhat-cloud-services/sources-client@3.0.11
npm:@redhat-cloud-services/sources-client@3.0.13
npm:@redhat-cloud-services/integrations-client@6.0.4
npm:@redhat-cloud-services/integrations-client@6.0.5
npm:@redhat-cloud-services/integrations-client@6.0.7
npm:@redhat-cloud-services/frontend-components-config@6.11.3
npm:@redhat-cloud-services/frontend-components-config@6.11.4
npm:@redhat-cloud-services/frontend-components-config@6.11.6
npm:@redhat-cloud-services/frontend-components-config-utilities@4.11.2
npm:@redhat-cloud-services/frontend-components-config-utilities@4.11.3
npm:@redhat-cloud-services/frontend-components-config-utilities@4.11.5
npm:@redhat-cloud-services/hcc-pf-mcp@0.6.1
npm:@redhat-cloud-services/hcc-pf-mcp@0.6.2
npm:@redhat-cloud-services/hcc-pf-mcp@0.6.4
npm:@redhat-cloud-services/frontend-components-remediations@4.9.2
npm:@redhat-cloud-services/frontend-components-remediations@4.9.3
npm:@redhat-cloud-services/frontend-components-remediations@4.9.5
npm:@redhat-cloud-services/eslint-config-redhat-cloud-services@3.2.1
npm:@redhat-cloud-services/eslint-config-redhat-cloud-services@3.2.2
npm:@redhat-cloud-services/eslint-config-redhat-cloud-services@3.2.4
npm:@redhat-cloud-services/javascript-clients-shared@2.0.8
npm:@redhat-cloud-services/javascript-clients-shared@2.0.9
npm:@redhat-cloud-services/javascript-clients-shared@2.0.11
npm:@redhat-cloud-services/quickstarts-client@4.0.11
npm:@redhat-cloud-services/quickstarts-client@4.0.12
npm:@redhat-cloud-services/quickstarts-client@4.0.14
npm:@redhat-cloud-services/config-manager-client@5.0.4
npm:@redhat-cloud-services/config-manager-client@5.0.5
npm:@redhat-cloud-services/config-manager-client@5.0.7
npm:@redhat-cloud-services/hcc-feo-mcp@0.3.1
npm:@redhat-cloud-services/hcc-feo-mcp@0.3.2
npm:@redhat-cloud-services/hcc-feo-mcp@0.3.4
npm:@redhat-cloud-services/entitlements-client@4.0.11
npm:@redhat-cloud-services/entitlements-client@4.0.12
npm:@redhat-cloud-services/entitlements-client@4.0.14
npm:@redhat-cloud-services/tsc-transform-imports@1.2.2
npm:@redhat-cloud-services/tsc-transform-imports@1.2.4
npm:@redhat-cloud-services/tsc-transform-imports@1.2.6
npm:@redhat-cloud-services/hcc-kessel-mcp@0.3.1
npm:@redhat-cloud-services/hcc-kessel-mcp@0.3.2
npm:@redhat-cloud-services/hcc-kessel-mcp@0.3.4
npm:@redhat-cloud-services/frontend-components-testing@1.2.1
npm:@redhat-cloud-services/frontend-components-testing@1.2.2
npm:@redhat-cloud-services/frontend-components-testing@1.2.4
npm:@redhat-cloud-services/types@3.6.1
npm:@redhat-cloud-services/types@3.6.2
npm:@redhat-cloud-services/types@3.6.4
npm:@redhat-cloud-services/chrome@2.3.1
npm:@redhat-cloud-services/chrome@2.3.2
npm:@redhat-cloud-services/chrome@2.3.4
npm:@redhat-cloud-services/frontend-components-translations@4.4.1
npm:@redhat-cloud-services/frontend-components-translations@4.4.2
npm:@redhat-cloud-services/frontend-components-translations@4.4.4
npm:@redhat-cloud-services/vulnerabilities-client@2.1.8
npm:@redhat-cloud-services/vulnerabilities-client@2.1.9
npm:@redhat-cloud-services/vulnerabilities-client@2.1.11
