El 4 de agosto de 2026 se registró un ataque a gran escala contra la cadena de suministro en el ecosistema npm: el código malicioso, detectado por primera vez en [email protected], se propagó más allá de los espacios de nombres Keyv y Cacheable, afectando a cientos de paquetes de múltiples organizaciones. El malware utiliza el mecanismo de scripts preinstall para robar credenciales de entornos de desarrollo y de CI/CD y, a continuación, volver a publicar automáticamente versiones infectadas de otros paquetes accesibles mediante los tokens npm robados. Cualquier sistema que haya ejecutado una versión infectada debe considerarse comprometido, y antes de rotar los tokens es necesario eliminar primero el observador de revocación de credenciales instalado por el malware; de lo contrario, la propia rotación activará el manejador del atacante.
Alcance de la campaña y discrepancias en las estimaciones
Las estimaciones del alcance de la infección difieren de forma significativa entre los grupos de investigación. Según SafeDep, se han verificado 353 versiones maliciosas en 79 paquetes del registro npm, mientras que su monitorización detectó un abanico más amplio —442 versiones en 353 paquetes—. Aikido informa de al menos 868 paquetes y 1 381 versiones infectadas. Ninguna de las estimaciones ampliadas ha sido reproducida de forma independiente a partir de un listado público completo en el momento de preparar este material.
Es fundamental subrayar que todas estas cifras describen el número de artefactos maliciosos en el registro, y no el número de sistemas comprometidos. La infección real de una estación de trabajo o de un runner de CI depende de si una versión concreta infectada fue resuelta en las dependencias del proyecto y de si se ejecutó su script de lifecycle.
Anatomía técnica del ataque
Vector primario: paquete npm
La primera versión maliciosa confirmada fue [email protected]. En el archivo package.json se añadió el comando node setup.mjs como hook preinstall, y en el paquete se incluyeron los archivos setup.mjs y Math_Symbol.js. El código compilado de la biblioteca permaneció sin cambios, por lo que la funcionalidad del paquete no se vio afectada, lo que dificultaba su detección.
Según SafeDep, la primera fase comprueba la presencia del entorno de ejecución Bun y, si es necesario, descarga la versión 1.3.13 desde los lanzamientos oficiales en GitHub, tras lo cual cede el control a un bundle compilado de 727 680 bytes. Este bundle recopila una amplia gama de secretos:
- Tokens de GitHub y npm
- Credenciales de servicios en la nube
- Secretos de HashiCorp Vault y Kubernetes
- Datos de conexión a bases de datos
- Claves privadas
- Contenido de la memoria de runners de GitHub Actions
Socket confirmó de forma independiente la presencia en el código de funciones para modificar, versionar y volver a publicar paquetes en nombre de la identidad npm robada; es este mecanismo el que permite la propagación tipo gusano.
Segundo vector: hooks en el repositorio
Además del paquete npm, se ha identificado una vía alternativa de ejecución del código malicioso en el repositorio de Keyv. El archivo .claude/settings.json contiene un hook SessionStart que invoca a .vscode/setup.mjs. El archivo .vscode/tasks.json contiene la tarea “Environment Setup” con el parámetro runOn: folderOpen, que invoca a .claude/setup.mjs. El commit que introdujo estos hooks mostraba el icono verde de verificación de GitHub y estaba firmado en nombre de github-actions[bot]. La firma verificada solo confirma la validez de la operación criptográfica, pero no identifica a la persona que controlaba las credenciales.
Estos hooks no se ejecutan de manera incondicional. VS Code bloquea las tareas automáticas en espacios de trabajo no confiables y solicita confirmación de forma predeterminada. Claude Code aplica un mecanismo de confianza a la configuración que se suministra desde el repositorio. No obstante, un desarrollador que aprueba de forma habitual la confianza en el proyecto activa la ejecución del código malicioso.
A las 17:40 IST del 4 de agosto, ambos archivos con hooks seguían presentes en la rama main, y core/keyv/package.json seguía declarando la versión 6.0.0 con el script preinstall malicioso.
Elusión de los mecanismos de confianza
La versión comprometida de Keyv pasó por un workflow legítimo de GitHub Actions y obtuvo una attestation válida de OpenID Connect (OIDC) y SLSA (Supply-chain Levels for Software Artifacts). La attestation identificó correctamente el proceso de build, pero no podía determinar que el código fuente que entró en ese proceso fuera seguro. Esto demuestra una limitación fundamental: la proveniencia y las firmas verifican la ruta de construcción, pero no el contenido de lo que se construyó.
Relación con ataques anteriores
Semgrep documentó los mismos hooks de Claude Code y VS Code, el nombre de archivo setup.mjs y la descarga de Bun 1.3.13 en la compromisión de abril del paquete lightning en PyPI. Aikido atribuye la actividad de agosto a la familia de malware Shai-Hulud. La coincidencia de artefactos confirma la relación a nivel de familia de malware, pero no permite establecer quién está detrás de la campaña de agosto: ni el vector inicial de acceso ni el actor concreto han sido identificados.
Con los datos disponibles no es posible determinar si el gusano se propagó exclusivamente a partir de una única identidad de publicador robada o si intervinieron cuentas de varios desarrolladores comprometidas de forma independiente.
Evaluación del impacto
Están en riesgo todos los equipos y organizaciones que utilicen Keyv, Cacheable y paquetes relacionados en sus proyectos. Keyv es una biblioteca popular para el acceso unificado a almacenes de datos, ampliamente utilizada en el ecosistema Node.js. La compromisión afecta no solo a las aplicaciones finales, sino también a los pipelines de CI/CD, donde los scripts de lifecycle se ejecutan de forma automática.
No todos los paquetes asociados al maintainer original se infectaron. Según SafeDep, los adaptadores publicados @keyv/* y la línea Keyv 5.x se mantuvieron limpios. Sin embargo, el repositorio representa un riesgo adicional: un commit posterior ubicó los archivos maliciosos en los 19 paquetes del workspace, por lo que cualquier release generado a partir del árbol infectado contendrá código malicioso.
Recomendaciones de respuesta
- Revise los archivos lockfile (
package-lock.json,yarn.lock,pnpm-lock.yaml) para detectar versiones exactas incluidas en el conjunto infectado. No confíe en las etiquetas actualeslatest, ya que cambiaron durante el incidente. En el momento de la observación, para varios paquetes, incluidos [email protected], [email protected] y [email protected], se habían restaurado versiones seguras. - Si se instaló y ejecutó una versión infectada, considere comprometidas todas las credenciales en esa máquina.
- Antes de rotar los tokens, asegúrese de localizar y eliminar el observador de revocación de credenciales instalado por el malware. La rotación sin eliminar el observador puede activar el manejador del atacante.
- Actualice el cliente npm a la versión 12, que bloquea por defecto los scripts de lifecycle de dependencias no aprobados. Las versiones anteriores de npm y las vías de instalación alternativas que permiten scripts de lifecycle siguen siendo vulnerables.
- No utilice el bloqueo por espacio de nombres como medida única, ya que esto genera el riesgo tanto de pasar por alto versiones infectadas como de bloquear falsamente releases limpios.
- Revise los clones del repositorio de Keyv para detectar los archivos
.claude/settings.jsony.vscode/tasks.jsoncon hooks maliciosos. No apruebe la confianza en el espacio de trabajo hasta haber limpiado el repositorio.
Al momento de preparar este material, ni el maintainer del proyecto, ni npm, ni GitHub habían publicado declaraciones oficiales sobre el incidente. Las organizaciones que utilicen los paquetes afectados deben auditar de inmediato sus dependencias por versiones exactas a partir de los archivos lockfile, eliminar el observador del malware antes de cualquier rotación de secretos y migrar a npm 12 para protegerse frente a la ejecución de scripts de dependencias no aprobados, mecanismo que fue el vector clave de propagación del gusano.