Компания JFrog обнаружила кампанию из 148 пакетов npm, которые выдавали себя за студенческие прокси для обхода школьных фильтров, а на деле около двух недель в мае 2025 года превращали браузеры посетителей в узлы DDoS-ботнета. Штука в том, что npm тут использовался не по назначению атаки на разработчиков, как это обычно бывает, а просто как бесплатный хостинг для вредоносного веб-сайта. Жертвами стали не программисты, а школьники, пытавшиеся зайти на заблокированные игры через прокси.
Обычные атаки на цепочку поставок npm срабатывают сразу при установке пакета через хуки жизненного цикла или скрипты сборки, и целятся именно в разработчиков. Здесь всё иначе: пакеты вообще не рассчитаны на импорт в проект, никаких lifecycle-хуков и build-скриптов в них нет. Полезная нагрузка активируется только когда браузер загружает страницу прокси, а не в момент npm install. Для сравнения, в сентябре 2025 года был замечен червь Shai-Hulud, который сам себя реплицировал, заразил больше 500 пакетов и воровал секреты разработчиков, republishing себя через украденные токены. А буквально за несколько дней до него произошла фишинговая атака на аккаунт мейнтейнера пакета «qix» – в chalk, debug и ещё 16 пакетов с суммарными миллиардами еженедельных скачиваний внедрили код, опустошающий криптокошельки. Кампания с прокси-пакетами устроена принципиально иначе.
Из 148 пакетов изначально в мае каталог SafeDep насчитывал 141, к 8 июля их стало 148. Названия у них весьма характерные: charlie-kirk, ilovefemboys, miguelphonk. Всё это части приложения-прокси под брендом Lucide, замаскированного под сайты репетиторства – «Riverbend Tutoring» и «Northstar Tutoring». Внешне выглядело как безобидный инструмент для обхода школьных фильтров контента.
Первым эту историю разобрал SafeDep ещё в мае 2025 года, каталогизировав 141 пакет. Тогда картина показалась относительно скромной – обычная рекламная накрутка и злоупотребление реестром: попандеры, скрипты монетизации от третьих лиц, трекинг через Google Analytics, всё это построено на базе Scramjet-прокси, ориентированного на студентов. В коде service worker исследователи наткнулись на комментарий «TY WAVES + CHATGPT ILY», который стал косвенным намёком на возраст автора.
JFrog копнула глубже. Компания деобфусцировала входной бандл приложения – файл на 5,4 мегабайта в одну строку JavaScript, который после распаковки превратился в более чем 20 600 строк читаемого кода. С помощью Wayback Machine удалось восстановить архивные версии полезной нагрузки и собрать хронологию кампании. Под слоем рекламного мусора обнаружились два скрытых вредоносных модуля, оба срабатывали ещё до отрисовки интерфейса на React.
Первый модуль, названный «G2», работал как загрузчик удалённых скриптов – подтягивал JavaScript из репозитория на GitHub через CDN jsDelivr. Дизайн крайне небезопасный: ссылка вела на изменяемую main-ветку, а не на закреплённый коммит, проверка целостности через Subresource Integrity отсутствовала полностью, а загруженный код исполнялся с привилегиями происхождения самого прокси-сайта – с доступом к его же cookies, локальному хранилищу и эндпоинтам того же origin. Плюс политика no-referrer скрывала источник запроса. Получается, что тот, кто контролирует аккаунт на GitHub, может в любой момент подменить код, исполняющийся в браузере каждого посетителя. К моменту проверки JFrog живой репозиторий уже отдавал 404, но архивная копия от 30 мая сохранила грубый скрипт HTTP-флуда: каждые 500 миллисекунд он генерировал строку длиной в миллион символов и отправлял её как no-cors POST-запрос на – публичный домен школы медсестёр в городе Маттесон, штат Иллинойс. Запросы не дожидались ответа, из-за чего трафик просто накапливался. По оценкам JFrog, один активный посетитель создавал около 2 мегабайт в секунду исходящего трафика, а тысяча открытых вкладок давала уже около 2 гигабайт в секунду по цели. Случайные параметры запроса позволяли обходить кэширующие прокси, а режим no-cors пропускал preflight-проверку CORS, избегая ограничения скорости.
Второй модуль, «I2», оказался куда изощрённее и работал как генератор WebSocket-флуда. Он подгружал текстовый файл websocket. Шеф в котором содержался целевой WebSocket-адрес и количество сокетов, ограниченное диапазоном от 1 до 1024. Затем открывал указанное число соединений в ступенчатом цикле. В архивной конфигурации каждый браузер получал команду открыть 30 соединений к Wisp-эндпоинту на домене – который сам по себе является действующим прокси, замешанным в инъекции малвертайзинга. Протокол Wisp разработан студией Mercury Workshop как лёгкий способ туннелировать множество TCP/UDP-сокетов через одно WebSocket-соединение, и он широко используется в той самой экосистеме браузерных прокси, под которую маскировались вредоносные пакеты. Сгенерированные фреймы оказались валидными little-endian пакетами Wisp – то есть атака была нацелена именно на удалённый Wisp-сервер, а не на устройство самого студента.
По сути это атака на управляющий слой, а не объёмная бомбардировка трафиком. Один браузер, задействовавший все 1024 сокета, способен заставить Wisp-сервер выделять и разрывать около 10 240 соединений в секунду, генерируя при этом более 20 000 строк лога за то же время. Уязвимость нашлась в конкретной реализации – wisp-server-node от Mercury Workshop: сервер открывает новый сокет на каждый CONNECT-фрейм, не проверяет, не указывает ли адрес назначения на loopback или приватную сеть, и логирует каждую попытку. В итоге заканчиваются файловые дескрипторы, переполняется хранилище логов, и прокси падает. Примечательно, что wisp-server-node уже помечен как устаревший, и сами мейнтейнеры советуют переходить на другие реализации именно из-за этого класса проблем с безопасностью и стабильностью. Получается, что кампания превратила студенческий прокси в оружие против тех же самых Wisp-серверов, на которых держатся другие подобные инструменты, параллельно устраивая отдельный HTTP-флуд против школы в Иллинойсе.
Инфраструктура атаки выглядит как работа не слишком опытного, но упорного оператора. GitHub-организация lucideproxy регистрировала аккаунты с разницей в секунды, коммиты привязаны к почте на домене , найдена связь с ником в Discord. Всего обнаружено 93 хостнейма для развёртывания, 90 из них указывали на один и тот же IP-адрес 92.38.177.17 у хостинг-провайдера G-Core Labs. На молодость и любительский уровень оператора указывает многое: детские названия пакетов, оставленный внутри тарболов shell-скрипт для автопубликации, тот самый комментарий про ChatGPT и волны. Один из аккаунтов умудрился опубликовать 116 пакетов меньше чем за 35 минут, и npm никак не отреагировал на такую активность и не заблокировал её.
По коммитам JFrog восстановила хронологию: в марте 2025 года проект стартовал как обычная рекламная поделка, в середине мая за пару дней в него добавили модули G2 и I2, к концу мая была проведена реальная атака на домен школы медсестёр, а 31 мая вредоносные модули убрали – как раз в тот момент, когда началась публикация отчёта SafeDep. 8 июля прошла вторая волна уже с нового аккаунта, доведя число пакетов до 148 и поставляя «почищенную» сборку, оставленную только с рекламной функциональностью. При этом приложение до сих пор обфусцировано, продолжает подгружать сторонние скрипты с контролируемых атакующими доменов, а загрузчик по-прежнему ссылается на изменяемую ветку. Способность к DDoS не удалена, а лишь отключена – оператор может в любой момент вернуть атаку одним коммитом в ветку, без всякого обновления пакетов.
На момент проверки Hacker News 14 июля 2026 года большинство отмеченных пакетов уже убраны с npm и заменены стандартной security-заглушкой версии 0.0.1. Исключение – пакет charlie-kirk, который всё ещё доступен и содержит две версии, помеченные JFrog как вредоносные: 2.0.0 и 3.0.1.
Сетевым администраторам школ и организаций рекомендуется блокировать домены кампании на уровне DNS, в первую очередь:
Открытым остаётся вопрос о реальном масштабе ботнета и о том, была ли WebSocket-атака подтверждена против живой цели – Hacker News запросил у JFrog дополнительные детали и ждёт ответа. Пока же вся эта история хорошо показывает слабое место современных сканеров зависимостей и песочниц, которые ловят вредоносный код именно в момент npm install. Код из этой кампании установки вообще не требовал – он срабатывал через обычную загрузку страницы в браузере. Пока публичные реестры пакетов можно использовать как бесплатный CDN, самыми опасными пакетами вполне может оказаться не то, что попадает в чью-то сборку, а то, что вообще никогда туда не попадает.
Обычные атаки на цепочку поставок npm срабатывают сразу при установке пакета через хуки жизненного цикла или скрипты сборки, и целятся именно в разработчиков. Здесь всё иначе: пакеты вообще не рассчитаны на импорт в проект, никаких lifecycle-хуков и build-скриптов в них нет. Полезная нагрузка активируется только когда браузер загружает страницу прокси, а не в момент npm install. Для сравнения, в сентябре 2025 года был замечен червь Shai-Hulud, который сам себя реплицировал, заразил больше 500 пакетов и воровал секреты разработчиков, republishing себя через украденные токены. А буквально за несколько дней до него произошла фишинговая атака на аккаунт мейнтейнера пакета «qix» – в chalk, debug и ещё 16 пакетов с суммарными миллиардами еженедельных скачиваний внедрили код, опустошающий криптокошельки. Кампания с прокси-пакетами устроена принципиально иначе.
Из 148 пакетов изначально в мае каталог SafeDep насчитывал 141, к 8 июля их стало 148. Названия у них весьма характерные: charlie-kirk, ilovefemboys, miguelphonk. Всё это части приложения-прокси под брендом Lucide, замаскированного под сайты репетиторства – «Riverbend Tutoring» и «Northstar Tutoring». Внешне выглядело как безобидный инструмент для обхода школьных фильтров контента.
Первым эту историю разобрал SafeDep ещё в мае 2025 года, каталогизировав 141 пакет. Тогда картина показалась относительно скромной – обычная рекламная накрутка и злоупотребление реестром: попандеры, скрипты монетизации от третьих лиц, трекинг через Google Analytics, всё это построено на базе Scramjet-прокси, ориентированного на студентов. В коде service worker исследователи наткнулись на комментарий «TY WAVES + CHATGPT ILY», который стал косвенным намёком на возраст автора.
JFrog копнула глубже. Компания деобфусцировала входной бандл приложения – файл на 5,4 мегабайта в одну строку JavaScript, который после распаковки превратился в более чем 20 600 строк читаемого кода. С помощью Wayback Machine удалось восстановить архивные версии полезной нагрузки и собрать хронологию кампании. Под слоем рекламного мусора обнаружились два скрытых вредоносных модуля, оба срабатывали ещё до отрисовки интерфейса на React.
Первый модуль, названный «G2», работал как загрузчик удалённых скриптов – подтягивал JavaScript из репозитория на GitHub через CDN jsDelivr. Дизайн крайне небезопасный: ссылка вела на изменяемую main-ветку, а не на закреплённый коммит, проверка целостности через Subresource Integrity отсутствовала полностью, а загруженный код исполнялся с привилегиями происхождения самого прокси-сайта – с доступом к его же cookies, локальному хранилищу и эндпоинтам того же origin. Плюс политика no-referrer скрывала источник запроса. Получается, что тот, кто контролирует аккаунт на GitHub, может в любой момент подменить код, исполняющийся в браузере каждого посетителя. К моменту проверки JFrog живой репозиторий уже отдавал 404, но архивная копия от 30 мая сохранила грубый скрипт HTTP-флуда: каждые 500 миллисекунд он генерировал строку длиной в миллион символов и отправлял её как no-cors POST-запрос на – публичный домен школы медсестёр в городе Маттесон, штат Иллинойс. Запросы не дожидались ответа, из-за чего трафик просто накапливался. По оценкам JFrog, один активный посетитель создавал около 2 мегабайт в секунду исходящего трафика, а тысяча открытых вкладок давала уже около 2 гигабайт в секунду по цели. Случайные параметры запроса позволяли обходить кэширующие прокси, а режим no-cors пропускал preflight-проверку CORS, избегая ограничения скорости.
Второй модуль, «I2», оказался куда изощрённее и работал как генератор WebSocket-флуда. Он подгружал текстовый файл websocket. Шеф в котором содержался целевой WebSocket-адрес и количество сокетов, ограниченное диапазоном от 1 до 1024. Затем открывал указанное число соединений в ступенчатом цикле. В архивной конфигурации каждый браузер получал команду открыть 30 соединений к Wisp-эндпоинту на домене – который сам по себе является действующим прокси, замешанным в инъекции малвертайзинга. Протокол Wisp разработан студией Mercury Workshop как лёгкий способ туннелировать множество TCP/UDP-сокетов через одно WebSocket-соединение, и он широко используется в той самой экосистеме браузерных прокси, под которую маскировались вредоносные пакеты. Сгенерированные фреймы оказались валидными little-endian пакетами Wisp – то есть атака была нацелена именно на удалённый Wisp-сервер, а не на устройство самого студента.
По сути это атака на управляющий слой, а не объёмная бомбардировка трафиком. Один браузер, задействовавший все 1024 сокета, способен заставить Wisp-сервер выделять и разрывать около 10 240 соединений в секунду, генерируя при этом более 20 000 строк лога за то же время. Уязвимость нашлась в конкретной реализации – wisp-server-node от Mercury Workshop: сервер открывает новый сокет на каждый CONNECT-фрейм, не проверяет, не указывает ли адрес назначения на loopback или приватную сеть, и логирует каждую попытку. В итоге заканчиваются файловые дескрипторы, переполняется хранилище логов, и прокси падает. Примечательно, что wisp-server-node уже помечен как устаревший, и сами мейнтейнеры советуют переходить на другие реализации именно из-за этого класса проблем с безопасностью и стабильностью. Получается, что кампания превратила студенческий прокси в оружие против тех же самых Wisp-серверов, на которых держатся другие подобные инструменты, параллельно устраивая отдельный HTTP-флуд против школы в Иллинойсе.
Инфраструктура атаки выглядит как работа не слишком опытного, но упорного оператора. GitHub-организация lucideproxy регистрировала аккаунты с разницей в секунды, коммиты привязаны к почте на домене , найдена связь с ником в Discord. Всего обнаружено 93 хостнейма для развёртывания, 90 из них указывали на один и тот же IP-адрес 92.38.177.17 у хостинг-провайдера G-Core Labs. На молодость и любительский уровень оператора указывает многое: детские названия пакетов, оставленный внутри тарболов shell-скрипт для автопубликации, тот самый комментарий про ChatGPT и волны. Один из аккаунтов умудрился опубликовать 116 пакетов меньше чем за 35 минут, и npm никак не отреагировал на такую активность и не заблокировал её.
По коммитам JFrog восстановила хронологию: в марте 2025 года проект стартовал как обычная рекламная поделка, в середине мая за пару дней в него добавили модули G2 и I2, к концу мая была проведена реальная атака на домен школы медсестёр, а 31 мая вредоносные модули убрали – как раз в тот момент, когда началась публикация отчёта SafeDep. 8 июля прошла вторая волна уже с нового аккаунта, доведя число пакетов до 148 и поставляя «почищенную» сборку, оставленную только с рекламной функциональностью. При этом приложение до сих пор обфусцировано, продолжает подгружать сторонние скрипты с контролируемых атакующими доменов, а загрузчик по-прежнему ссылается на изменяемую ветку. Способность к DDoS не удалена, а лишь отключена – оператор может в любой момент вернуть атаку одним коммитом в ветку, без всякого обновления пакетов.
На момент проверки Hacker News 14 июля 2026 года большинство отмеченных пакетов уже убраны с npm и заменены стандартной security-заглушкой версии 0.0.1. Исключение – пакет charlie-kirk, который всё ещё доступен и содержит две версии, помеченные JFrog как вредоносные: 2.0.0 и 3.0.1.
Сетевым администраторам школ и организаций рекомендуется блокировать домены кампании на уровне DNS, в первую очередь:
- []woofbeginner.com
[]c.vipersfutbol.com
Открытым остаётся вопрос о реальном масштабе ботнета и о том, была ли WebSocket-атака подтверждена против живой цели – Hacker News запросил у JFrog дополнительные детали и ждёт ответа. Пока же вся эта история хорошо показывает слабое место современных сканеров зависимостей и песочниц, которые ловят вредоносный код именно в момент npm install. Код из этой кампании установки вообще не требовал – он срабатывал через обычную загрузку страницы в браузере. Пока публичные реестры пакетов можно использовать как бесплатный CDN, самыми опасными пакетами вполне может оказаться не то, что попадает в чью-то сборку, а то, что вообще никогда туда не попадает.