El 4 de agosto de 2026, quien controlaba la cuenta de mantenedor detrás de keyv —una biblioteca de caché con unos 127 millones de descargas semanales— publicó una versión con un script que se ejecuta solo al instalar el paquete. En torno a media hora después, el código malicioso se había copiado a sí mismo en cientos de paquetes de npm y había saltado a proyectos de varias organizaciones sin relación entre sí. No hizo falta que nadie ejecutara nada a mano: bastó con instalar una dependencia.
Lo que separa este caso de otro robo de credenciales en npm es dónde deja su persistencia. Además de saquear los secretos del entorno de desarrollo, el gusano escribe en el propio repositorio dos ficheros de configuración —uno de Claude Code y otro de VS Code— preparados para lanzar su carga en cuanto un desarrollador abre el proyecto o arranca una sesión con su agente de IA. Convierte la confianza que depositas en la configuración de tu propio proyecto en un mecanismo de ejecución.
Lo esencial
- El gusano, una variante de Mini Shai-Hulud, arrancó en keyv@6.0.0 el 4 de agosto y se propaga solo usando los tokens de publicación que roba, en un ataque a la cadena de suministro.
- Un script
preinstallroba credenciales de npm, GitHub, AWS, Vault, Kubernetes y claves privadas en entornos de desarrollo y de integración continua. - Planta
.claude/settings.jsony.vscode/tasks.jsonen el repositorio, cableados para ejecutarse al abrir el proyecto en VS Code o en Claude Code. - keyv suma unos 127 millones de descargas semanales; flat-cache y file-entry-cache cuelgan de ESLint, así que alcanza a quien nunca los eligió.
- Los recuentos aún divergen: The Hacker News habla de más de 400 paquetes en la primera media hora; Aikido eleva la cifra a más de 800 paquetes y más de mil versiones. Sin CVE asignado.
- Defensa: fijar versiones y ficheros de bloqueo (lockfiles),
--ignore-scripts, tokens de publicación de vida corta con OIDC, aislar secretos en CI y revisar los ficheros de configuración que aparezcan en tu copia del repositorio.
Cómo funciona: tres piezas encadenadas
El ataque encadena tres capacidades que por separado ya se habían visto, pero que juntas explican por qué se propagó tan rápido y por qué cuesta erradicarlo.
Robo de credenciales en el momento de instalar
El paquete comprometido incluye un script preinstall, una instrucción que npm ejecuta de forma automática antes incluso de que el código llegue a usarse. Ese script descarga el entorno de ejecución Bun (runtime) y lanza un recolector ofuscado que busca lo que da acceso a todo lo demás: tokens de .npmrc, credenciales de la CLI de GitHub, claves de AWS, tokens de Vault, configuraciones de Kubernetes, claves privadas y cadenas de conexión a bases de datos. Según el análisis de Datadog Security Labs, la carga ronda los 727 KB. El robo ocurre en la máquina del desarrollador o en el agente de integración continua, y termina en la exfiltración de esos secretos antes de que el proyecto llegue a compilarse.
Autopropagación con los tokens robados
Aquí está el mecanismo de gusano. Entre lo que roba hay tokens de publicación de npm, y el propio código los usa para republicar versiones envenenadas de otros paquetes que el mantenedor comprometido tuviera a su alcance. Cada nueva víctima con permisos de publicación amplía el radio, y por eso el código saltó a paquetes de organizaciones que no tenían ninguna relación con keyv. La velocidad —cientos de paquetes en la primera media hora— no es humana: es la de un proceso que se replica solo.
Persistencia en el IDE y en el agente de IA
La tercera pieza es la más novedosa. El gusano deja en el repositorio un .vscode/tasks.json y un .claude/settings.json configurados para ejecutar un comando en cuanto el proyecto se abre en VS Code o se inicia una sesión de Claude Code. Es una forma de persistencia que no vive en el sistema operativo, sino en el propio código fuente: sobrevive a un formateo de la máquina y viaja con el repositorio a quien lo clone. Depende de un matiz —que el desarrollador confíe en el espacio de trabajo—, pero ese clic de confianza es lo que la rutina diaria concede sin pensar.
El alcance: keyv, ESLint y la dependencia que nadie eligió
keyv no es un paquete cualquiera. Está en la base de innumerables proyectos, casi siempre de forma indirecta. Dos de los paquetes hermanos comprometidos, flat-cache y file-entry-cache, cuelgan de ESLint, la herramienta de análisis de estilo que usa medio ecosistema JavaScript. El resultado es que el gusano llegó a desarrolladores que jamás escribieron keyv ni ESLint en su lista de dependencias: lo arrastraron como dependencia de una dependencia.
Sobre el tamaño exacto los rastreadores aún no coinciden, y esa divergencia es normal en las primeras horas de un incidente vivo. The Hacker News contabilizó más de 400 paquetes afectados en la primera media hora; Aikido elevó el recuento a más de 800 paquetes y más de mil versiones envenenadas. Varios equipos de seguridad —entre ellos SafeDep, Socket y Datadog Security Labs— confirmaron el compromiso de keyv@6.0.0 y de paquetes hermanos como file-entry-cache. No hay CVE asignado, lo que en la práctica significa que no puedes apoyarte en un identificador único para rastrear tu exposición: toca mirar tu árbol de dependencias y tu lockfile.
Por qué los controles habituales no lo ven
Un antivirus de endpoint y un análisis de vulnerabilidades por CVE se quedan cortos aquí, por varias razones. La ejecución ocurre en la fase de instalación, antes de las pruebas y del análisis estático que muchos equipos consideran su red de seguridad. El entorno de ejecución que descarga, Bun, es una herramienta legítima y firmada, no un binario sospechoso. Y los ficheros de persistencia son configuración de proyecto con formato válido: para un revisor apresurado, un .vscode/tasks.json es ruido de fondo. Sin CVE, tampoco aparece en los paneles que solo vigilan vulnerabilidades con identificador.
El denominador común es que el ataque se apoya en confianza legítima en cada paso: confías en el paquete, en el token de publicación, en el entorno de ejecución y en la configuración de tu propio repositorio. Ninguno de esos elementos es, por sí solo, una anomalía.
Detección: qué mirar en el repositorio y en la cadena de CI
La detección fiable es por comportamiento y por revisión, no por firma. Cuatro señales concretas que sí puedes cazar:
- Ficheros de configuración de IDE o de agente de IA que aparecen en tu copia del repositorio sin que los pusieras. Un
.claude/settings.jsono un.vscode/tasks.jsoninesperado merece una lectura línea a línea antes de abrir el proyecto. - Scripts
preinstallopostinstallnuevos en los cambios del lockfile. Una modificación depackage-lock.jsonque introduce un gancho de instalación (hook) es una señal de primer orden. - Conexiones salientes anómalas desde una máquina de desarrollo o un agente de CI durante un
npm install: descargas de entornos de ejecución o llamadas a dominios que ese proyecto nunca contacta. - Uso de tokens de publicación de npm o de credenciales de nube desde ubicaciones o a horas que no encajan con la actividad legítima.
Si aparece cualquiera de esas señales, el punto de partida no es «un paquete malicioso», sino «qué credenciales han pasado por esta máquina o esta cadena de CI y hay que rotar ya». Es trabajo de caza de amenazas y de una respuesta a incidentes que asuma el robo de secretos como hipótesis por defecto.
Defensa: blindar el desarrollo y la integración continua
Ningún control aislado detiene esto; lo que reduce el daño es una cadena de decisiones sobre cómo tu organización consume software de terceros, la materia de un enfoque DevSecOps y de la gestión del riesgo de terceros. Estas son las medidas que más rinden.
Fijar versiones y respetar el lockfile
Los rangos abiertos (^, ~) permiten que una versión recién publicada entre en tu construcción sin que nadie la apruebe. Fijar versiones exactas, versionar el lockfile en el control de versiones y usar npm ci en lugar de npm install en CI evita que una publicación maliciosa se cuele automáticamente en la siguiente construcción.
Desactivar los scripts de instalación por defecto
--ignore-scripts impide que npm ejecute los hooks preinstall y postinstall, que es por donde entra esta familia de ataques. Tiene un coste —algunos paquetes legítimos dependen de esos scripts para compilar binarios—, así que la práctica sensata es desactivarlos de forma global y permitir de manera explícita solo los pocos paquetes que de verdad los necesitan.
Tokens de publicación de vida corta y publicación de confianza
El combustible del gusano son los tokens de publicación robados. Sustituir los tokens de larga duración por credenciales efímeras y por publicación basada en OIDC (trusted publishing), donde el registro confía en la identidad del flujo de CI en lugar de en un secreto almacenado, corta esa cadena: no queda un token persistente que robar. Los tokens que sigan siendo necesarios deben ser granulares y de mínimo privilegio, igual que cualquier otra identidad no humana.
Aislar los secretos en la integración continua
Un agente de CI que ejecuta un npm install no debería tener a mano todas las llaves del reino. Secretos con alcance limitado a lo que cada trabajo necesita, sin variables de entorno globales con credenciales de producción, y separación entre el entorno que construye y el que despliega: así, un robo en la fase de instalación no entrega la nube entera.
Revisar la configuración del repositorio como rutina
El vector de los hooks de IDE convierte la revisión de .claude/settings.json, .vscode/tasks.json y ficheros equivalentes en parte de la revisión de código, no en una curiosidad. La función de confianza del espacio de trabajo —tanto en VS Code como en el agente de IA— deja de ser un clic automático: abrir un repositorio ajeno sin revisar su configuración es aceptar su ejecución. Es también el terreno de la seguridad de agentes de IA y MCP.
El fondo: la confianza que este gusano explota
El patrón de fondo no es un paquete concreto, sino la confianza implícita que sostiene el desarrollo moderno. Damos por hecho que instalar una dependencia es una operación inerte, que un token de publicación solo publica, que la configuración de un repositorio describe el proyecto y no lo ataca. Cada una de esas suposiciones es razonable por separado, y este gusano las encadena todas. Ya lo vimos, con otra mecánica, en el caso de easy-day-js y en el infostealer de jscrambler.
La novedad que merece retenerse es que los agentes de IA para programar añaden una superficie de ejecución nueva y de confianza alta: un fichero que le dice al agente qué hacer al abrir el proyecto es, a efectos prácticos, código que se ejecuta con tus permisos. No invita a desconfiar de la herramienta; obliga a tratar su configuración con el mismo rigor que cualquier script. Lo que queda por ver en las próximas semanas es si la técnica se copia —los repositorios de gusanos de código abierto bajan la barrera de entrada— y si los registros aceleran hacia la publicación sin secretos almacenados. Mientras tanto, la conclusión operativa es concreta: cada vez que alguien de tu equipo instala una dependencia o abre un repositorio que no ha escrito, algo se ejecuta con sus permisos. Merece la pena saber qué.
Este artículo describe el incidente y las medidas de mitigación con la información pública disponible a 5 de agosto de 2026. Los recuentos de paquetes afectados varían entre fuentes y siguen actualizándose; verifica tu exposición contra tu propio árbol de dependencias y el aviso de tu registro antes de tomar decisiones operativas.
Los paquetes citados como comprometidos se basan en divulgaciones públicas de varios equipos de seguridad con la información disponible en la fecha. Nombrar un paquete no implica un fallo en npm ni en el resto del trabajo de sus mantenedores: el vector fue el robo de cuentas y de tokens de publicación. Las cifras y las atribuciones pueden evolucionar.