Cadena de suministro de paquetes de JavaScript comprometida por el gusano ChainDrop

ChainDrop: el gusano que envenenó la cadena de suministro de JavaScript

El 4 de agosto de 2026, entre las 6:40 y las 10:20 de la mañana (hora argentina), miles de proyectos de JavaScript quedaron expuestos sin que nadie tocara una sola línea de su propio código. Los atacantes no vulneraron el lenguaje ni los servidores: envenenaron los paquetes que los desarrolladores descargan automáticamente todos los días.

La campaña fue bautizada ChainDrop y se vincula con la familia de malware Shai-Hulud. Empezó con paquetes muy usados para manejo de caché, como keyv y cacheable, y se extendió a otros como flat-cache, file-entry-cache y cache-manager.


Cómo operó el ataque

Los atacantes se apoderaron de la cuenta de un mantenedor, modificaron los repositorios y publicaron versiones nuevas con apariencia legítima. Cuando un desarrollador corría un simple npm install o pnpm install, el paquete podía disparar un script automático (preinstall) que salía a la caza de:

  • Tokens de GitHub y credenciales de npm.
  • Claves de AWS, Azure y Google Cloud.
  • Secretos de Kubernetes, Vault y archivos .env.
  • Claves SSH, contraseñas de bases de datos y variables de entornos CI/CD.
  • Lo más grave: con las credenciales robadas, el malware intentaba publicar versiones infectadas de otros paquetes. Cada víctima se convertía en un nuevo foco de contagio. Por eso se lo describe como un gusano, no como un virus aislado.


    Por qué fue tan peligroso

    El ataque explotó tres costumbres muy extendidas en el desarrollo moderno:

  • Dependencias invisibles: los proyectos arrastran decenas de dependencias indirectas que nadie revisa.
  • Scripts automáticos: los gestores de paquetes ejecutan código automáticamente al instalar.
  • Credenciales a mano: los entornos de desarrollo y CI/CD guardan las llaves más valiosas de la empresa.
  • Una empresa podía no haber instalado keyv jamás y recibirlo igual, escondido cuatro niveles abajo en el árbol de dependencias: la aplicación usa ESLint, ESLint usa file-entry-cache, este usa flat-cache, y flat-cache usa keyv. Revisar solo el package.json no alcanza: hay que mirar los lockfiles y el árbol completo.


    La trampa de la firma válida

    Un detalle inquietante: algunas versiones comprometidas se publicaron mediante flujos legítimos de GitHub Actions. Tenían firma válida, procedencia válida y salían del repositorio correcto. La firma probaba que el paquete lo construyó el pipeline autorizado, pero no que el código fuente estuviera limpio.

    La moraleja es incómoda pero útil: la procedencia importa, y aun así no reemplaza la revisión del código y de los permisos del pipeline.


    ¿Cómo saber si tu proyecto está afectado?

  • Revisá el árbol de dependencias. Con npm ls --all keyv cacheable flat-cache file-entry-cache cache-manager, o bien pnpm why keyv y yarn why keyv.
  • Buscá los nombres en los lockfiles (package-lock.json, pnpm-lock.yaml, yarn.lock), comparando las versiones exactas con las listas de indicadores publicadas por los investigadores. No confíes en la etiqueta latest: durante un ataque puede cambiar varias veces.
  • Revisá GitHub: commits desconocidos, workflows nuevos en .github/workflows/, repositorios públicos creados solos, cambios de mantenedor y publicaciones desde cuentas extrañas.
  • Revisá logs y tráfico: descargas raras de Bun, conexiones a dominios como npm-cache[.]com y accesos cloud desde runners que normalmente no los usan.
  • Conviene decirlo claro: npm audit por sí solo no alcanza. Está pensado para vulnerabilidades ya registradas, y un paquete malicioso recién publicado puede no tener todavía ningún CVE.


    Si encontraste una versión comprometida

  • Aislá la máquina: no vuelvas a instalar nada desde ella y desconectala de la red.
  • Preservá información: lockfiles, logs de instalación, historial de commits y registros de publicación. Borrar todo de entrada destruye la evidencia.
  • Investigá persistencia: el malware pudo dejar workflows, tareas automáticas o archivos ocultos. Algunos análisis de Shai-Hulud detectaron mecanismos que reaccionaban al revocarse ciertos tokens, así que conviene aislar antes de revocar a lo loco.
  • Rotá todos los secretos: desde una máquina limpia, regenerá tokens de GitHub y npm, claves cloud, SSH, secretos de CI/CD y contraseñas de bases de datos. Cambiar solo la clave de GitHub no sirve.
  • Reconstruí: runner limpio, caches eliminadas, lockfile regenerado desde un entorno confiable e instalación sin scripts hasta aprobar solo los necesarios.

  • Cómo blindarte para la próxima

  • Aprobación explícita de scripts en pnpm, con pnpm approve-builds: los paquetes no autorizados no ejecutan nada al instalarse.
  • Instalación sin scripts mientras dure una investigación, con pnpm install --ignore-scripts o npm install --ignore-scripts.
  • Período de espera para versiones nuevas. Muchos paquetes maliciosos se detectan y retiran a las pocas horas de publicados, así que exigir un día de antigüedad reduce mucho el riesgo: minimumReleaseAge: 1440 en pnpm-workspace.yaml, en minutos.
  • Lockfiles congelados en CI/CD, para que el pipeline no cambie versiones en silencio, con pnpm install --frozen-lockfile o npm ci.
  • Y como regla general: tokens con permisos mínimos, alcance limitado, duración corta y rotación automática. Cada actualización de dependencia debería revisarse antes de aceptarse: versión exacta, quién la publicó, si agregó scripts nuevos y si cambió la procedencia.


    Conclusión

    ChainDrop no fue un virus dentro de JavaScript: fue un golpe directo a la confianza que sostiene todo el ecosistema de paquetes. Una dependencia diminuta, que nadie eligió instalar, puede terminar con acceso a la computadora del desarrollador, los secretos del CI/CD, los repositorios y las cuentas cloud de una empresa entera.

    Ninguna medida aislada frena todos los ataques. Pero la combinación de lockfiles revisados, scripts bloqueados por defecto, período de espera, permisos mínimos y rotación rápida de credenciales convierte una infección casi automática en algo mucho más difícil de lograr.


    Fuentes

  • TechRadar: ChainDrop y los paquetes Keyv/Cacheable.
  • ITPro: campaña ChainDrop y Shai-Hulud.
  • GitHub Security Blog: ataques a npm y GitHub Actions.
  • Documentación de pnpm: aprobación de scripts y antigüedad mínima de versiones.
  • Guía de respuesta de GitHub ante malware.