Массовая атака на npm: десятки поддельных пакетов распространяют похититель паролей из Chromium

Атака на цепочку поставок NPM

4 июня 2026 года в реестр пакетов npm была загружена серия вредоносных публикаций, объединённых единой инфраструктурой и целевым механизмом поражения. За 40 минут (с 07:27 до 08:05 UTC) один злоумышленник создал не менее двенадцати учётных записей и опубликовал под ними пакеты, маскирующиеся под вспомогательные утилиты для разработчиков. Каждый пакет содержит обфусцированный пэйлоад размером от 260 до 282 КБ, который выполняется в момент установки через скрипт postinstall. Пэйлоад относится к семейству ранее осуждённого похитителя учётных данных браузера Chromium, известного под именем @apexcraft/nano-key. Атака нацелена на разработчиков, использующих npm в рабочих процессах и CI-средах, а также на любые системы, устанавливающие пакеты из списка скомпрометированных.

Описание

Все пакеты были опубликованы от имени учётных записей, зарегистрированных на одноразовом почтовом домене wshu.net. Адрес каждой записи следовал шаблону: <имя_области>-<шесть_случайных_символов>@wshu.net. Например, для пакета @zymkit/jwtbytes использовался адрес zynkit-sk393b@wshu.net, для @petitcode/eb-retry - petitcode-eq1efk@wshu.net. В файле package.json каждого пакета в поле author указывался адрес в домене @pm.me и ссылка на репозиторий GitHub, соответствующую названию области. Такая маскировка делает каждый пакет внешне не связанным с другими - поиск по одному автору не приводит к обнаружению остальных.

Согласно анализу, все области были созданы в узком временном окне 4 июня 2026 года, а публикации вредоносных версий произведены практически одновременно. Это указывает на автоматизированный процесс развёртывания. Злоумышленник использовал единый инструмент обфускации и единый обёрточный код для пэйлоада, меняя только имя файла-загрузчика. Среди обнаруженных имён: seed.cjs, bootstrap.cjs, prelude.cjs, warmup.js, primer.cjs, preflight.js, tzinit.cjs, tickinit.cjs, encoder.js. Размер файла-пэйлоада всегда значительно превышает размер легитимного кода пакета: в @zymkit/jwtbytes настоящий код занимает около 13 КБ, тогда как dist/prelude.cjs - 282 КБ.

Механизм выполнения основан на скрипте postinstall в package.json. Установка пакета запускает команду, которая передаёт файл пэйлоада интерпретатору Node.js. Пэйлоад проверяет, является ли он главным модулем, и при совпадении вызывает функцию выполнения. Кроме того, два пакета - @petitcode/eb-retry и @briskforge/envcheck - содержат второй триггер: при вызове экспортируемой функции (retry или require модуля) пэйлоад также выполняется. Это позволяет атаке срабатывать даже в случае, если postinstall был отключён флагом --ignore-scripts.

Пэйлоад представляет собой артефакт, созданный с помощью библиотеки javascript-obfuscator. Внутренняя логика включает цикл с перестановкой массива строк, а также декодер на основе Base64 и RC4. Каждый пакет использует уникальную "посевную" строку, поэтому хеши файлов различаются. Однако в двух случаях - @lazyutil/dater@0.9.4 и @glitchpad/throttler@2.2.3 - обнаружен абсолютно одинаковый скомпилированный пэйлоад (SHA256 68b4fe54...), что доказывает принадлежность к одному автору. Для чтения паролей из Chrome-профилей применяется AES-256-GCM, соответствующий схемам app-bound key версий 10 и 11 Chromium. Данные exfiltr по протоколу HTTPS с подменой User-Agent Mozilla/5.0.

Важной особенностью кампании стала так называемая "чистка" версий. После публикации вредоносных версий (например, 0.5.3, 0.10.4 и т.д.) злоумышленник выпускал следующую версию с пустым блоком scripts и без пэйлоада. Например, у @frostnode/waitfor версии 0.10.3-0.10.5 содержали postinstall, а 0.10.6 - уже пустой. Команда npm view показывает последнюю чистую версию, не указывая на наличие вредоносных. Пакет @nullzero/urlcat был полностью удалён автором, что делает анализ его содержимого невозможным. Таким образом, проверка только последней версии не даёт гарантии безопасности.

Общее число скомпрометированных пакетов не окончательно. Поскольку регистрация областей и публикации были плотно упакованы во времени, исследователи продолжают выявлять новые области, использующие ту же инфраструктуру. На данный момент в список подтверждённых индикаторов включены 31 версия, распределённые по 12 областям. Две из них - @zynkit/probe и @frostnode/probe - содержат только зарезервированные области без пэйлоада, что свидетельствует о планомерном захвате пространства имён.

Последствия атаки значительны. Любая установка вредоносной версии на машину разработчика или в CI-окружение приводит к немедленному сбору и отправке паролей, куки и токенов сессий из всех установленных браузеров на базе Chromium (Chrome, Edge, Brave и др.). Это ставит под угрозу корпоративные системы, в которых разработчики используют одни и те же браузерные профили для доступа к внутренним ресурсам, облачным консолям и Git-репозиториям.

Злоумышленник не использовал сложные техники обхода антивирусов: пакеты легко детектируются по размеру аномально большого загрузочного файла. Однако из-за того, что большинство разработчиков и систем автоматической сборки доверяют реестру npm и не проверяют содержимое postinstall, кампания может оставаться незамеченной до момента, когда пароль уже скомпрометирован. Единственный надёжный метод защиты - полный запрет установки любых версий перечисленных пакетов и их областей, а также немедленная смена всех паролей и инвалидация сессий, если подозрительный пакет был установлен на какой-либо хост.

Индикаторы компрометации

Комментарии: 0