
Escáner para el ataque a la cadena de suministro keyv/cacheable: detecta paquetes npm comprometidos, verifica los hashes de los payloads y encuentra implantes de persistencia en los modos repo y host.
English | Português
Escáner independiente para el incidente de la cadena de suministro de keyv/cacheable ("Shai-Hulud: Here We Go Again", 4 ago 2026) — 440+ paquetes npm comprometidos por un gusano autopropagante que roba credenciales de nube/CI e instala persistencia con un interruptor de hombre muerto.
Detecta, en minutos y sin instalar nada:
package-lock.json, npm-shrinkwrap.json, yarn.lock (v1 y Berry), pnpm-lock.yaml y bun.lock — incluidas las dependencias transitivas, con la cadena completa (p. ej. eslint → file-entry-cache → flat-cache → [email protected]);node_modules (nombre + hash SHA-256 de los artefactos conocidos);SUSPECT, nunca confirmadas sin un hash;.claude/settings.json y .vscode/tasks.json, artefactos temporales (bun-dl-*);keyv/cacheable fue comprometida; el atacante publicó nuevas versiones con un hook "preinstall": "node setup.mjs" — código que se ejecuta antes de que el paquete se instale, con los privilegios de quien haya ejecutado npm install.setup.mjs descarga el runtime de Bun desde GitHub y ejecuta el payload dentro de él — evasión contra herramientas que solo monitorizan procesos node.Math_Symbol.js (~728 KB, ofuscado) roba credenciales: metadatos de instancia de AWS, claves de AWS/GCP/Azure, tokens de Vault, cuentas de servicio de Kubernetes, secretos de GitHub Actions, tokens de npm, además de un barrido regex genérico en busca de claves privadas y bearer tokens en el disco.npm install/npm ci con los scripts de ciclo de vida habilitados desde 2026-08-04 09:35 UTC. Con --ignore-scripts, el hook no se ejecutó..claude/settings.json (SessionStart) y .vscode/tasks.json (folderOpen) que ejecutan el cargador cuando se abre la carpeta clonada — sin npm install, sin instalar nada. Esto incluye a quienes clonaron el repositorio para investigar el incidente y a agentes de codificación de IA que abrieron el directorio — uno de los primeros casos públicos de hooks de agentes de IA (.claude/) usados como vector de cadena de suministro.El implante instala un "watcher" (gh-token-monitor) mantenido vivo por un LaunchAgent (macOS) o un servicio de usuario de systemd + loginctl enable-linger (Linux). Cada 60 segundos valida el token de GitHub robado contra la API. Mientras el token funcione, no pasa nada. Cuando la respuesta se vuelve 4xx — es decir, el momento en que revocas el token — ejecuta, vía eval, el contenido de ~/.config/gh-token-monitor/handler: un comando arbitrario definido remotamente por el atacante. El análisis público no sabe qué contiene — podría ser destrucción de datos, reimplantación, ransomware o nada. El riesgo no es evaluable; por eso el orden de respuesta es absoluto.
Tres propiedades que cambian la respuesta:
host.[email protected] se publicó con una atestación SLSA en regla. La procedencia da fe de la integridad de la compilación, no de la fuente: el workflow legítimo compiló código ya troyanizado.package.json (el hook preinstall) y en dos archivos nuevos añadidos al paquete (setup.mjs, Math_Symbol.js).eslint → file-entry-cache → flat-cache → keyv. Por eso el escáner muestra la cadena en cada hallazgo.scan.mjs tiene las siguientes propiedades — importantes para cualquiera que responda a un incidente de cadena de suministro:
npm install. Audita todo scan.mjs en 15 minutos antes de ejecutarlo.--update (descargar un manifiesto de IOCs nuevo), explícita y opcional.docker run --network=none o una máquina aislada: solo copia scan.mjs + iocs.json.Requisito: Node.js ≥ 18 (cualquier máquina con npm ya lo tiene). Descarga los dos archivos — scan.mjs + iocs.json — y listo: sin instalación.
Aviso: si clonaste este repositorio completo, la carpeta
fixtures/contiene IOCs inertes usados en las pruebas (nombres y versiones reales, contenido ficticio — sin malware). El escáner la omite automáticamente y lo advierte en la salida; los hallazgos de allí solo aparecen si la escaneas a propósito.
Hay dos modos de ejecución que responden a preguntas distintas, y eso es lo que decide dónde ejecutarlo:
repo lee lockfiles y node_modules — y los lockfiles viven en git, por lo que se puede centralizar: una persona escanea todos los repositorios de la empresa.host busca el implante (watcher, LaunchAgent/systemd, hooks de IDE), que vive en la máquina donde se ejecutó el código — eso no está en git y no se puede centralizar.node scan.mjs repo /folder/with/all/the/repos --json=result.json --html=report.html
Responde "qué proyectos están expuestos" en minutos, sin involucrar a nadie. Acepta múltiples rutas; recorre subdirectorios (incluidos monorepos y workspaces).
Para cada proyecto con un hallazgo, identifica quién lo tocó desde 2026-08-04 09:35 UTC (git log, registros de CI). Esas personas ejecutan, en su máquina:
node scan.mjs # current directory + host, in ~30 seconds