Una campaña de paquetes de 148 npm disfrazados de servidores proxy web para estudiantes convirtió los navegadores de los visitantes en una botnet distribuida de denegación de servicio durante aproximadamente dos semanas en mayo, según una nueva investigación de JFrog.
Los paquetes no perseguían a los desarrolladores que podrían instalarlos. Los operadores utilizaron el registro como alojamiento gratuito para un sitio proxy con trampa explosiva y dejaron que los estudiantes que vinieron a esquivar los filtros web de la escuela suministraran el tráfico de ataque.
Los paquetes se enviaron con nombres como charlie-kirk, ilovefemboys y miguelphonk, cada uno con una aplicación proxy con la marca «Lucide» y vestida como una página de inicio de tutoría llamada Riverbend Tutoring o Northstar Tutoring.
En la superficie, el proxy funcionó, permitiendo a los estudiantes pasar los filtros de contenido para acceder a juegos y sitios bloqueados. Debajo, cargó un cargador de código remoto cuya carga útil los operadores podían intercambiar a voluntad, además de un generador de inundación WebSocket creado para hablar el protocolo proxy Wisp. Cualquiera que abriera una página se unía al enjambre sin saberlo.
Nada de esto se ejecuta en el momento de la instalación. Los paquetes no incluyen enlaces de ciclo de vida ni scripts de compilación nativos, y nunca fueron escritos para ser importados a un proyecto.
El gusano Shai-Hulud autorreplicante que afectó a más de 500 paquetes en septiembre de 2025 recopiló secretos de los desarrolladores y se volvió a publicar con tokens robados. Días antes, un ataque de phishing al mantenedor conocido como qix deslizó código de drenaje de billetera en chalk, debug y otros 16 paquetes con miles de millones de descargas semanales entre ellos.
Esos ataques se activan en el momento en que se instala un paquete y se dirigen a las personas que crean el software. Éste omite el proceso de compilación y espera en una pestaña del navegador.
Un anterior aviso de SafeDep catalogó 141 de los paquetes en mayo y leyó la operación como adware y abuso de registro: anuncios popunder, scripts de monetización de terceros y seguimiento de Google Analytics incorporados en un proxy Scramjet dirigido a estudiantes. Eso se mantuvo en lo que era visible en la superficie.
JFrog tiró del hilo más. El equipo desofuscó el paquete de entrada de la aplicación, una sola línea de JavaScript de 5,4 MB que se descomprimió en más de 20.600 líneas de código legible, y recuperó cargas útiles archivadas de Wayback Machine para reconstruir la línea de tiempo de la campaña.
Dos módulos se encontraban debajo del adware y ambos se activaban antes de que se renderizara la interfaz de React.
El primero, que JFrog llama G2es un cargador de scripts remoto y recupera el código de la forma más insegura posible. Extrae JavaScript de un repositorio de GitHub a través de la CDN jsDelivr, apunta a la rama principal mutable en lugar de una confirmación fijada, no incluye verificación de integridad de subrecursos y ejecuta todo lo que regresa con los propios privilegios de origen del sitio proxy: acceso completo a cookies, almacenamiento local y puntos finales del mismo origen.
Una política de no referencia evita que la solicitud anuncie su procedencia. Quien tenga la cuenta de GitHub detrás de ella puede cambiar el código que se ejecuta en el navegador de cada visitante cuando lo desee.
El repositorio devolvía un 404 cuando JFrog lo miró, pero una copia archivada del 30 de mayo conservaba lo que había servido: una burda inundación HTTP. Cada 500 milisegundos, el script crea una nueva cadena de un millón de caracteres y la activa como un POST sin cors en cdn.caan.edu, que JFrog identifica como el dominio público de una escuela de enfermería en Matteson, Illinois.
Las solicitudes nunca esperan una respuesta, por lo que se acumulan. JFrog registra cada visitante activo a aproximadamente 2 MB por segundo de carga, lo que significa que mil pestañas proxy abiertas empujarían alrededor de 2 GB por segundo al objetivo. Un parámetro de consulta aleatorio anula el almacenamiento en caché de los servidores proxy y no-cors omite la verificación previa de CORS, por lo que nada limita los paquetes.
El segundo módulo, I2es el más agudo. Obtiene un archivo de texto sin formato, websocket.txt, que contiene una URL de WebSocket de destino y un recuento de sockets limitado entre 1 y 1024, luego abre esa cantidad de conexiones en un bucle escalonado. La configuración archivada apuntó a cada navegador a 30 conexiones a un punto final Wisp en lunaron[.]arriba, un proxy en vivo ocupado inyectando publicidad maliciosa.
Jirón es un protocolo de Mercury Workshop de bajo costo para hacer túneles de muchos sockets TCP y UDP a través de un único WebSocket, y es una plomería común en la misma escena de proxy de navegador que estos paquetes imitan.
Una vez conectado, cada navegador configura su socket en modo binario y, cada 100 milisegundos, envía una trama Wisp CONNECT válida seguida de una trama CLOSE, ambas apuntando a localhost:1. Los fotogramas son paquetes Wisp little-endian correctos, por lo que el objetivo no es la propia máquina del estudiante. Es el servidor Wisp remoto en el otro extremo de la conexión.
Eso lo convierte en un ataque de plano de control en lugar de volumétrico. Un solo navegador que ejecute los 1.024 sockets completos puede presionar a un servidor Wisp para que asigne y elimine alrededor de 10.240 conexiones por segundo mientras escribe más de 20.000 líneas de registro en el mismo tramo.
JFrog señala que Mercury Workshop nodo-servidor-wisp abre un socket nuevo para cada trama CONNECT sin verificar si el destino es un loopback o una dirección privada, y registra cada intento. Esto agota los descriptores de archivos, inunda el almacenamiento de registros y descarta el proxy. wisp-server-node ya está en desuso; sus encargados están indicando a los usuarios exactamente esta clase de problema de seguridad y estabilidad.
Entonces, la campaña convirtió una herramienta de proxy estudiantil en un arma contra los servidores de los que dependen otros proxy estudiantiles, y apuntó una inundación separada a una escuela lateral.
La infraestructura está muy agrupada y no está diseñada para esconderse. JFrog rastreó las compilaciones hasta una organización de GitHub llamada lucideproxy cuyas cuentas se registraron con segundos de diferencia, vinculadas a un correo electrónico de confirmación en geeked.[.]Wtf y un identificador de Discord. Noventa de los 93 nombres de host de implementación que encontró se resolvieron en una dirección IP, 92.38.177[.]17, organizado por G-Core Labs.
Entre los nombres de los paquetes juveniles, un script de shell de publicación automática dejado dentro de los archivos comprimidos y un comentario «TY WAVES + CHATGPT ILY» que SafeDep encontró en el trabajador del servicio, ambas empresas leen al operador como joven. Una cuenta envió 116 paquetes en menos de 35 minutos y npm no hizo nada para ralentizarlo.
El historial de confirmaciones de JFrog describe el arco. El proyecto comenzó como simple adware en marzo, agregó el cargador remoto y el generador Wisp en una ráfaga de dos días a mediados de mayo, ejecutó la inundación en vivo contra la escuela de enfermería a fin de mes y luego eliminó los módulos maliciosos nuevamente el 31 de mayo cuando comenzaron los informes.
Una segunda ola el 8 de julio, bajo una nueva cuenta, elevó el total a 148 paquetes y envió la versión limpia y solo con publicidad. La aplicación todavía está ofuscada, todavía carga scripts de terceros desde dominios de atacantes y el cargador todavía apunta a una rama mutable. La capacidad DDoS no ha desaparecido, sólo está desactivada. JFrog señala que los operadores conservan la capacidad de rearmarlo: un compromiso con esa rama mutable, no se requiere actualización del paquete.
Desde entonces, muchos de los paquetes de la campaña han sido retirados de npm y reemplazados con el marcador de posición de seguridad estándar 0.0.1 del registro. Una verificación aleatoria realizada por The Hacker News en todas las familias de paquetes el 14 de julio de 2026 encontró que la mayoría había desaparecido, pero charlie-kirk aún ofrecía las dos versiones que JFrog marcó como maliciosas, 2.0.0 y 3.0.1.
Debido a que la amenaza se envía como una aplicación web del lado del cliente en lugar de un implante en el momento de la instalación, la solución de JFrog sigue el método de entrega.
Los administradores de redes escolares y corporativas, donde estos servidores proxy atraen la mayor cantidad de tráfico, deberían bloquear los dominios de la campaña a nivel de DNS. La monetización y los hosts de secuencias de comandos que aún alcanza la versión actual, entre ellos woofbeginner[.]com y c.vipersfutbol[.]com, son los que deben bloquear primero.
Cualquiera que haya cargado uno de los sitios proxy debe borrar el caché del navegador y el almacenamiento local y cancelar el registro de cualquier trabajador de servicio dejado por un dominio de tutoría o proxy. Los equipos cuyos entornos de compilación obtuvieron los paquetes nombrados deben extraerlos de los manifiestos y archivos de bloqueo y reconstruirlos de forma limpia. El artículo de JFrog incluye la lista completa de 148 paquetes, dominios, direcciones IP y hashes.
The Hacker News se comunicó con JFrog para obtener más detalles sobre la escala de la botnet y si el ataque WebSocket se ejecutó contra un objetivo vivo, y actualizará esta historia con cualquier respuesta.
Los escáneres de dependencias y los entornos sandbox en el momento de la instalación están diseñados para detectar el código que se ejecuta en npm install. Este código nunca solicitó ser instalado. Mientras los registros públicos funcionen como CDN gratuitos, es posible que los paquetes por los que vale la pena preocuparse sean cada vez más aquellos que ningún proceso de construcción jamás obtenga.