El 17 de junio de 2026, alguien tomó el control del espacio de nombres @mastra en npm y, en cuestión de minutos, publicó más de 140 versiones nuevas de paquetes de este popular marco de desarrollo de aplicaciones de inteligencia artificial. A primera vista, ninguno de esos paquetes contenía código malicioso. La trampa estaba un nivel más abajo, en una dependencia añadida sin hacer ruido.
El detalle que convierte el incidente en una lección, y no en una anécdota, es su alcance: los paquetes afectados sumaban más de 1,1 millones de descargas semanales, según el análisis de JFrog Security Research. Y la carga se ejecutaba antes de que ningún desarrollador llegara a usar el paquete, durante la propia instalación. No hubo CVE ni exploit remoto. Hubo una cuenta de mantenedor olvidada y un gancho de instalación.
Qué ocurrió exactamente
El vector de entrada no fue una vulnerabilidad, sino una credencial viva que nadie había revocado. Los atacantes accedieron a la cuenta «ehindero», perteneciente a un antiguo colaborador de Mastra cuyo acceso al espacio de nombres seguía activo mucho después de que dejara de contribuir, según The Hacker News. Con esa cuenta publicaron de forma masiva más de 140 paquetes del espacio @mastra en una ventana muy corta de tiempo.
Lo más astuto es que los paquetes de Mastra en sí permanecían limpios. Quien revisara su código no habría encontrado nada raro. La acción maliciosa se trasladó a una dependencia nueva llamada easy-day-js, un clon de la conocida librería de fechas dayjs, que se añadió a la lista de dependencias de cada paquete. Es un ataque a la cadena de suministro de manual: esconder el daño donde nadie mira, en la dependencia de una dependencia.
No es casualidad que el objetivo fuera un marco para construir aplicaciones de inteligencia artificial. El ecosistema de desarrollo de IA crece deprisa, mueve mucho dinero y arrastra grafos de dependencias enormes, lo que lo convierte en un terreno atractivo para este tipo de campañas. Quien trabaja con seguridad en inteligencia artificial debería asumir que la cadena de suministro de sus herramientas es parte del modelo de amenazas.
La anatomía técnica: todo pasa en el postinstall
El componente clave es el gancho postinstall de npm, una instrucción que se ejecuta de forma automática justo después de instalar un paquete, sin que el desarrollador tenga que hacer nada más. Estos ganchos existen por motivos legítimos, como compilar módulos nativos, pero son también una puerta de ejecución de código que muchas organizaciones no vigilan.
easy-day-js abusó de ese gancho con un truco de versiones limpio y eficaz. La versión 1.11.21 era una copia inocente de dayjs, sin ganchos de instalación. La versión 1.11.22, publicada como «latest», añadía el postinstall que lanzaba el código malicioso. Como la dependencia se declaraba con un rango flexible (el típico acento circunflejo de npm), una instalación normal resolvía a la 1.11.22 y disparaba la carga, tal como documenta StepSecurity.
| Versión | Gancho postinstall | Comportamiento |
|---|---|---|
| 1.11.21 | No | Copia limpia de dayjs, sin actividad maliciosa |
| 1.11.22 (latest) | Sí | Ejecuta setup.cjs y descarga la segunda fase |
Fuente: análisis técnico de StepSecurity y JFrog (junio de 2026).
El gancho ejecutaba un archivo ofuscado, setup.cjs, que seguía una secuencia reconocible: desactivaba la verificación de certificados TLS para evitar inspección, dejaba marcas de baliza en directorios temporales, descargaba una segunda fase desde la infraestructura de mando y control del atacante, la lanzaba como proceso independiente en segundo plano y, por último, se autoeliminaba para borrar el rastro forense.
La segunda fase era un troyano de acceso remoto multiplataforma, capaz de operar en Windows, macOS y Linux. Entre sus capacidades documentadas estaban robar el historial de navegación y extraer datos de más de 160 extensiones de navegador asociadas a carteras de criptomonedas, según recogen The Hacker News y SC Media. JFrog ha catalogado la campaña con el identificador XRAY-1004962.
El robo de carteras de criptomonedas apunta a un móvil económico. Algunos analistas han señalado solapamientos de técnicas con grupos vinculados a Corea del Norte, como BlueNoroff o Sapphire Sleet, según The Hacker News, pero la atribución definitiva sigue abierta. Conviene quedarse con lo que sí está confirmado: el método de entrega, el alcance y las capacidades del troyano.
Por qué los controles habituales no lo ven
Este incidente es incómodo precisamente porque burla buena parte del instrumental defensivo estándar. Conviene entender por qué.
- No hay CVE que buscar. Un escáner de vulnerabilidades compara las dependencias contra catálogos de fallos conocidos. Aquí no había un fallo: había un paquete legítimo convertido en arma. No hay identificador que casar.
- El paquete padre estaba limpio. Una revisión superficial del paquete de Mastra no revelaba nada; el daño vivía en una dependencia transitiva. Si no inspeccionas el grafo completo, no lo ves.
- Se ejecuta antes de cualquier prueba. El postinstall corre durante la instalación, con los permisos del usuario, tanto en el portátil del desarrollador como en los servidores de integración continua. Cuando el código entra en revisión, la máquina ya está comprometida.
- MFA no basta; hacen falta privilegios mínimos, tokens granulares, trusted publishing y enforcement de provenance. No fue un robo de contraseña, sino una cuenta de colaborador autorizada y olvidada, con acceso al espacio de nombres nunca revocado. El problema no era de autenticación, sino de gestión de privilegios.
Detección operativa
Si construyes software o ejecutas instalaciones de npm en tu organización, hay señales concretas que puedes vigilar sin necesidad de herramientas exóticas.
- Tráfico de salida durante la instalación. Un comando de instalación no debería abrir conexiones a dominios externos más allá del registro de paquetes. Una baliza saliente desde un servidor de integración continua es una anomalía que merece alerta inmediata.
- Telemetría de detección en el endpoint. Busca procesos node o npm que lancen procesos hijos independientes, que escriban en directorios temporales y que generen tráfico con la verificación TLS desactivada.
- Diferencias en el archivo de bloqueo. Revisa cada cambio en package-lock.json dentro de las revisiones de código: la aparición repentina de una dependencia transitiva nueva como easy-day-js es exactamente la señal que conviene cazar. Una rutina de caza de amenazas bien diseñada parte de hipótesis como esta.
- Indicadores de compromiso. Comprueba si easy-day-js figura entre tus dependencias, busca las marcas de baliza en directorios temporales y cruza tus hallazgos con la ficha XRAY-1004962 de JFrog. Los indicadores de compromiso publicados son tu punto de partida.
Si encuentras rastro de la dependencia maliciosa en una máquina o en un servidor de compilación, trátalo como un incidente: aísla el equipo, rota credenciales y carteras que hayan podido quedar expuestas y, si el alcance lo justifica, recurre a análisis forense digital para reconstruir lo ocurrido. El autoborrado del descargador complica la investigación, pero la telemetría previa al borrado suele dejar huella.
Indicadores concretos a buscar
Como punto de partida para una revisión rápida, estos son los rastros documentados de la campaña:
- La dependencia easy-day-js presente en el árbol de dependencias, especialmente la versión 1.11.22.
- Conexiones de salida durante la instalación con la verificación de certificados TLS desactivada.
- Marcas de baliza escritas en directorios temporales durante o justo después de un npm install.
- Procesos node o npm que lanzan procesos hijos independientes en segundo plano.
- El archivo setup.cjs ofuscado, que se autoelimina tras ejecutarse; cruza tus hallazgos con la ficha XRAY-1004962 de JFrog.
Defensa práctica
La buena noticia es que las contramedidas son concretas y, en buena parte, ya están disponibles en el propio gestor de paquetes.
- Desactiva los scripts de instalación por defecto. Usa la opción para ignorar scripts allá donde sea viable. npm v12 los desactivará por defecto, y gestores como Bun los bloquean salvo lista de permitidos, según Rescana y Mondoo.
- Instala de forma reproducible. Usa instalaciones limpias a partir del archivo de bloqueo versionado y fija versiones exactas en las dependencias más sensibles, en lugar de rangos abiertos que resuelven a la última versión publicada.
- Exige procedencia verificable. npm permite firmar la procedencia de un paquete y demostrar que se publicó desde una canalización de integración concreta. Verifica esas firmas y bloquea las descargas que no la tengan.
- Aísla la instalación. Ejecuta las instalaciones en entornos efímeros y sin salida a Internet salvo hacia el registro, con una lista de dominios permitidos. Un troyano que no puede contactar con su servidor de mando y control pierde la mitad de su utilidad.
- Pon un cortafuegos a tus dependencias. Un registro interno que actúe de intermediario, con cuarentena de versiones nuevas y análisis de comportamiento, te da margen para detectar publicaciones anómalas antes de que lleguen a tus equipos.
- Revoca los accesos durmientes. La causa raíz fue una cuenta de colaborador olvidada. Aplica el mínimo privilegio también del lado de quien publica: revisa quién puede publicar en tus espacios de nombres y retira el acceso a quien ya no contribuye. Esto enlaza directamente con la gestión de riesgo de terceros.
- Mantén un inventario de dependencias. Un SBOM actualizado te permite responder en minutos a la pregunta «¿distribuimos easy-day-js?» en lugar de en días de búsqueda manual.
Qué implica para NIS2 y DORA
Para una entidad europea sujeta a NIS2, o para una entidad financiera bajo DORA, este tipo de incidente no es solo un problema técnico: toca de lleno las obligaciones de seguridad de la cadena de suministro de NIS2 y la gestión del riesgo de terceros TIC de DORA.
Si desarrollas software, las dependencias que incorporas viajan hasta tus clientes, y un componente comprometido que llegue a producción puede activar los plazos de notificación de incidentes que ambas normas exigen. Demostrar que controlas tu grafo de dependencias, que mantienes un inventario y que dispones de capacidad de respuesta a incidentes es precisamente la clase de evidencia que estos marcos piden.
La superficie de ataque que nadie eligió
La lección más incómoda de easy-day-js es que puedes tener un programa de parches impecable y aun así acabar comprometido por una librería de fechas que nunca elegiste instalar. El grafo de dependencias es superficie de ataque, con la misma seriedad que un puerto abierto o un servidor sin actualizar.
No se trata de dejar de usar código abierto, algo que hoy no es realista, sino de tratarlo con la misma disciplina que cualquier otro proveedor: saber qué entra, controlar cómo entra y poder reaccionar deprisa cuando algo va mal. Para situar este incidente en una estrategia más amplia, hemos recogido cinco lecciones para el CISO sobre la cadena de suministro digital.