148 npm Packages Disguised as Student Proxies Turned Browsers Into a DDoS Botnet
148 npm packages disguised as student proxies became a DDoS botnet.
Summary
A campaign involving 148 npm packages, masquerading as student web proxies, was discovered to have turned visitors' browsers into a distributed denial-of-service (DDoS) botnet for approximately two weeks in May. These packages, named after pop culture figures, provided a functional proxy service while secretly loading a remote code loader and a WebSocket flood generator. The operators used the npm registry for hosting and targeted students attempting to bypass school web filters, with the attack traffic originating from the students themselves.
Full text
148 npm Packages Disguised as Student Proxies Turned Browsers Into a DDoS Botnet Swati KhandelwalJul 14, 2026Browser Security / Malvertising A campaign of 148 npm packages disguised as student web proxies turned visitors' browsers into a distributed denial-of-service botnet for roughly two weeks in May, according to new research from JFrog. The packages did not go after the developers who might install them. The operators used the registry as free hosting for a booby-trapped proxy site and let the students who came to dodge school web filters supply the attack traffic. The packages shipped under names like charlie-kirk, ilovefemboys, and miguelphonk, each carrying a proxy app branded "Lucide" and dressed as a tutoring landing page called Riverbend Tutoring or Northstar Tutoring. On the surface, the proxy worked, letting students slip past content filters to reach games and blocked sites. Underneath, it loaded a remote code loader whose payload the operators could swap at will, plus a WebSocket flood generator built to speak the Wisp proxy protocol. Anyone who opened a page joined the swarm without knowing it. None of this runs at install time. The packages carry no lifecycle hooks and no native build scripts, and they were never written to be imported into a project. The self-replicating Shai-Hulud worm that hit more than 500 packages in September 2025 harvested developer secrets and republished itself with stolen tokens. Days before it, a phishing attack on the maintainer known as qix slipped wallet-draining code into chalk, debug, and 16 other packages with billions of weekly downloads between them. Those attacks fire the moment a package installs and target the people building software. This one skips the build pipeline and waits in a browser tab. An earlier advisory from SafeDep cataloged 141 of the packages in May and read the operation as adware and registry abuse: popunder ads, third-party monetization scripts, and Google Analytics tracking bolted onto a Scramjet proxy aimed at students. That held up for what was visible on the surface. JFrog pulled the thread further. The team deobfuscated the app's entry bundle, a 5.4 MB single line of JavaScript that unpacked into more than 20,600 lines of readable code, and recovered archived payloads from the Wayback Machine to reconstruct the campaign's timeline. Two modules sat underneath the adware, both firing before the React interface renders. The first, which JFrog calls G2, is a remote script loader, and it fetches code about as unsafely as possible. It pulls JavaScript from a GitHub repository through the jsDelivr CDN, points at the mutable main branch instead of a pinned commit, ships no Subresource Integrity check, and runs whatever comes back with the proxy site's own origin privileges: full access to cookies, local storage, and same-origin endpoints. A no-referrer policy keeps the request from advertising where it came from. Whoever holds the GitHub account behind it can change the code running in every visitor's browser whenever they want. The repository was returning a 404 by the time JFrog looked, but an archived copy from May 30 preserved what it had served: a crude HTTP flood. Every 500 milliseconds, the script builds a fresh one-million-character string and fires it as a no-cors POST at cdn.caan.edu, which JFrog identifies as the public domain of a nursing school in Matteson, Illinois. The requests never wait for a response, so they stack up. JFrog clocks each active visitor at roughly 2 MB per second of upload, meaning a thousand open proxy tabs would push around 2 GB per second at the target. A randomized query parameter defeats caching proxies, and no-cors skips the CORS preflight, so nothing throttles the packets. The second module, I2, is the sharper one. It fetches a plain text file, websocket.txt, holding a target WebSocket URL and a socket count capped between 1 and 1,024, then opens that many connections in a staggered loop. The archived config aimed each browser at 30 connections to a Wisp endpoint on lunaron[.]top, itself a live proxy busy injecting malvertising. Wisp is a low-overhead Mercury Workshop protocol for tunneling many TCP and UDP sockets over a single WebSocket, and it is common plumbing in the same browser-proxy scene these packages imitate. Once connected, each browser sets its socket to binary mode and, every 100 milliseconds, sends a valid Wisp CONNECT frame followed by a CLOSE frame, both pointed at localhost:1. The frames are correct little-endian Wisp packets, so the target is not the student's own machine. It is the remote Wisp server on the far end of the connection. That makes it a control-plane attack rather than a volumetric one. A single browser running the full 1,024 sockets can push a Wisp server to allocate and tear down about 10,240 connections a second while writing more than 20,000 log lines in the same stretch. JFrog notes that Mercury Workshop's wisp-server-node opens a fresh socket for every CONNECT frame without checking whether the destination is a loopback or private address, and logs each attempt. That exhausts file descriptors, floods log storage, and drops the proxy. wisp-server-node is already deprecated; its maintainers are pointing users elsewhere over exactly this class of security and stability problem. So the campaign turned a student proxy tool into a weapon against the servers that other student proxies depend on, and aimed a separate flood at a school on the side. The infrastructure is clustered tightly and not built to hide. JFrog traced the builds to a GitHub organization named lucideproxy whose accounts were registered seconds apart, tied to a commit email at geeked[.]wtf and a Discord handle. Ninety of the 93 deployment hostnames it found resolved to one IP address, 92.38.177[.]17, hosted by G-Core Labs. Between the juvenile package names, an auto-publish shell script left inside the tarballs, and a "TY WAVES + CHATGPT ILY" comment SafeDep found in the service worker, both firms read the operator as young. One account pushed 116 packages in under 35 minutes, and npm did nothing to slow it down. JFrog's commit history lays out the arc. The project started as plain adware in March, added the remote loader and the Wisp generator in a two-day burst in mid-May, ran the live flood against the nursing school at the end of the month, then stripped the malicious modules back out on May 31 as reporting started. A second wave on July 8, under a new account, brought the total to 148 packages and shipped the cleaned-up, adware-only build. The app is still obfuscated, still loads third-party scripts from attacker domains, and the loader still points at a mutable branch. The DDoS capability is not gone, only switched off. JFrog notes the operators keep the ability to re-arm it: one commit to that mutable branch, no package update required. Many of the campaign's packages have since been pulled from npm and replaced with the registry's standard 0.0.1-security placeholder. A spot check by The Hacker News across the package families on July 14, 2026, found most gone but charlie-kirk still serving the two versions JFrog flagged as malicious, 2.0.0 and 3.0.1. Because the threat ships as a client-side web app rather than an install-time implant, JFrog's remediation follows the delivery method. Administrators on school and corporate networks, where these proxies pull the most traffic, should block the campaign's domains at the DNS level. The monetization and script hosts the current build still reaches, among them woofbeginner[.]com and c.vipersfutbol[.]com, are the ones to block first. Anyone who has loaded one of the proxy sites should clear the browser cache and local storage and unregister any service worker left behind by a tutoring or proxy domain. Teams whose build environments fetched the named packages should pull them from manifests and lockfiles and rebuild clean. JFrog's write-up carries the full list of 148 packages, domains, IP
Indicators of Compromise
- domain — cdn.caan.edu