El gusano npm de la campaña testmetest dejó armados 42 repositorios de GitHub de 11 dueños reales, con una carga oculta en archivos de hasta 13,7 MB que el buscador de código de la plataforma ni siquiera indexa. JFrog Security Research publicó el despiece el 26 de octubre y la conclusión incómoda llega rápido: abrir uno de esos proyectos en Claude Code, Gemini, Cursor o Visual Studio Code puede ejecutar el código sin instalar nada.
SafeDep, firma de seguridad de la cadena de suministro de código abierto, había documentado la parte de los paquetes el 22 de octubre y en ese momento no había confirmado víctimas de terceros: todo parecía actividad de prueba en cuentas del propio operador. JFrog revisó la infraestructura de GitHub y encontró otra historia, con cuentas secuestradas, historiales de cambios falsificados, ramas de publicación de vida corta y credenciales de npm expuestas.
Un archivo demasiado grande para el buscador
El truco central cabe en una cifra. Los envoltorios plantados en los repositorios miden entre 12,9 y 13,7 MB: la búsqueda de código de GitHub no indexa archivos de ese tamaño y la interfaz de contenidos tampoco puede devolverlos. La primera pasada de JFrog localizó los ganchos de ejecución en 26 repositorios, y los archivos de carga parecían vacíos por las rutas habituales de consulta.
La foto completa salió por otra vía. El equipo enumeró cada repositorio recorriendo los árboles de archivos y los objetos internos de Git, cuenta por cuenta, y el total subió a 42 repositorios de GitHub armados, sin un solo marcador vacío. Diez envoltorios con aspecto distinto escondían el mismo cargador de 4.067.677 caracteres, que se descifra en una carga idéntica de 2 MB en todos los casos: el tamaño variable era un efecto de la codificación, no una capacidad nueva.
Abrir una carpeta basta para ponerlo en marcha
El gancho vive en archivos de configuración que las herramientas de programación con inteligencia artificial leen al arrancar. La campaña plantó un gancho de inicio de sesión para Claude Code, ajustes para Gemini, configuración del protocolo de contexto de modelo para Cursor y tareas que se activan al abrir la carpeta en Visual Studio Code. Aman Mahapatra, directivo de Tribeca Softech citado por CSO Online, lo resumió con una comparación vieja: ese archivo de ajustes de Claude es el nuevo autorun.inf, el mecanismo que ejecutaba programas al conectar una memoria USB.
En npm, el registro de paquetes de JavaScript, la entrada era más silenciosa. Las versiones maliciosas ejecutaban el cargador durante la instalación mediante una expansión de comandos en el archivo de compilación, sin declarar un guion de instalación convencional. El código robaba credenciales de GitHub y de npm, alteraba repositorios y configuraciones de integración continua (CI) y se propagaba por los registros de paquetes. El inventario reunido al 26 de octubre sumaba 25 nombres de paquetes y 82 versiones conocidas, entre maliciosas y de señuelo.
El complemento nativo que duerme en los escáneres
Tres paquetes cambiaron de disfraz a mitad de campaña. En lugar de un cargador en JavaScript llevan un complemento nativo compilado que parece un marcador temporal inofensivo; al ejecutarse descifra un archivo vecino llamado .napi_cache y lanza el código real en un proceso separado. Antes de actuar comprueba el entorno y se queda dormido si detecta sistemas de integración continua, contenedores, máquinas virtuales pequeñas (1,5 GB de memoria o un solo procesador) o un depurador conectado. En Windows suma otra lista: si Wireshark o Process Monitor están abiertos, tampoco se mueve.
La infraestructura de publicación funcionaba en paralelo. Una cuenta del operador reunía 17 repositorios y ramas de vida corta con un publicador oculto de unos 2,2 MB en su segunda etapa, capaz de intercambiar un token de identidad de GitHub Actions por un token de publicación de npm y sacar versiones armadas de paquetes. Otro repositorio del mismo operador recibía sobres cifrados con datos capturados: 27 archivos entre el 22 y el 24 de octubre, 384.825 bytes en total.
JFrog pide tratar cada instalación de una versión completa del gusano como un equipo comprometido. Toca revocar y rotar credenciales de GitHub, GitLab, npm, PyPI, RubyGems, servicios en la nube, SSH, Vault, Kubernetes y proveedores de inteligencia artificial, revisar los repositorios en busca de los archivos gancho, borrar ramas no autorizadas y enumerar los árboles completos en lugar de fiarse de la búsqueda de código. Un detalle ordena la limpieza: la persistencia plantada se retira antes de revocar el token robado de GitHub, porque el gusano npm trae un componente de borrado que reacciona a esa revocación y puede eliminar datos del equipo.
Las oleadas reales arrancaron en julio: ocho repositorios recibieron archivos auxiliares el 23 de julio y el 28 de septiembre el operador armó cuentas enteras en lotes de minutos, con fechas de autor copiadas del historial legítimo. Una de las cuentas secuestradas, creada en 2013, pertenecía a un desarrollador argentino de PHP y Laravel con actividad genuina hasta 2022; 13 de sus repositorios quedaron armados en una ventana de dos minutos. JFrog vincula el mismo grupo de cuentas con flujos que escaneaban sistemas cPanel expuestos por la vulnerabilidad CVE-2026-41940, sin pruebas de equipos cPanel comprometidos al final de esa cadena: ese tramo queda como intento documentado, no como víctimas confirmadas.
Fuente: JFrog Security Research
Foto: JFrog Security Research
Descubre más desde Tecnología Geek
Suscríbete y recibe las últimas entradas en tu correo electrónico.
