Массовая атака на 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, кампания может оставаться незамеченной до момента, когда пароль уже скомпрометирован. Единственный надёжный метод защиты - полный запрет установки любых версий перечисленных пакетов и их областей, а также немедленная смена всех паролей и инвалидация сессий, если подозрительный пакет был установлен на какой-либо хост.

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

Package

  • @apexcraft/nano-key 1.3.2
  • @apexcraft/nano-key 1.3.3
  • @apexcraft/nano-key 1.3.4
  • @apexcraft/nano-key 1.3.5
  • @apexcraft/nano-key 1.3.6
  • @apexcraft/nano-key 1.3.7
  • @apexcraft/nano-key 1.3.8
  • @briskforge/envcheck 0.5.2
  • @briskforge/envcheck 0.5.3
  • @briskforge/envcheck 0.5.4
  • @bytemend/mfebus 1.4.2
  • @chunklab/hexparse 1.0.7
  • @chunklab/hexparse 1.1.4
  • @chunklab/hexparse 1.1.5
  • @chunklab/hexparse 1.1.6
  • @frostnode/probe 0.0.1
  • @frostnode/waitfor 0.10.3
  • @frostnode/waitfor 0.10.4
  • @frostnode/waitfor 0.10.5
  • @frostnode/waitfor 0.9.0
  • @glitchpad/throttler 2.2.3
  • @lazyutil/dater 0.8.1
  • @lazyutil/dater 0.9.2
  • @lazyutil/dater 0.9.3
  • @lazyutil/dater 0.9.4
  • @nullzero/urlcat 1.4.2
  • @petitcode/eb-retry 1.3.5
  • @thymelab/logfx 2.15.5
  • @tinyfox/shapecheck 0.8.7
  • @zynkit/jwtbytes 0.5.3
  • @zynkit/probe 0.0.1

Email

  • apexcraft-8uiljr@wshu.net
  • briskforge-5psyxc@wshu.net
  • bytemend-dwzfhq@wshu.net
  • chunklab-bpriqx@wshu.net
  • frostnode-gk8pbf@wshu.net
  • glitchpad-revqgz@wshu.net
  • lazyutil-78muyg@wshu.net
  • nullzero-rlnozk@wshu.net
  • petitcode-eq1efk@wshu.net
  • thymelab-v0et8w@wshu.net
  • tinyfox-yjwiqz@wshu.net
  • zynkit-sk393b@wshu.net

SHA256

  • 0d27ca72b6f02faf4db95effb18347a7e2fa2def2034707bf9e56fa217879a3b
  • 24c8f9b8ac17c2f88cc01d44543963206472112510962b68cf5f74d598b3b065
  • 26ddfae644673e0ad65b63caaaf67c0f7dc6c2b2b4127bb5271f8d03fb62091a
  • 2de602e6422a991346aaf0b74ed6bd525215f5177b9f7f267ccb4d82e919273d
  • 32d02f806d58a6670f7cc9b93f1d85b22e0e0f535e1f90a62d86918033896f54
  • 4e927f22ad04f4ac9b487ae11412fc2a55210188789ac29f3a47ad77931907a5
  • 618dfffb6829356c131fded9f4c6528b73b4f9d7ff1fc1d3b457599a12584e29
  • 68b4fe54a4c05cd0115535ebd4aa8d3cccb03ea5a685f440314814ba1b89e875
  • a9a28f2e9f7e0348092682940b3bf63d47a63afc18eb8bfe628e5ddab0d73b47
  • d06ee17d30ebb333ab2e5b6e8a1324fcf95edaaae17b6793ec0f3647338efda1

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