14 июля 2026 года злоумышленники скомпрометировали пять официальных npm-пакетов проекта AsyncAPI, получив доступ к веткам GitHub, триггерящим автоматическую публикацию. Вредоносные версии @asyncapi/generator, @asyncapi/generator-components, @asyncapi/generator-helpers и @asyncapi/specs были опубликованы с действительными SLSA-аттестациями, что делает атаку особенно опасной: провенанс доказывает происхождение сборки, но не безопасность кода.
Описание
Под угрозой оказались разработчики и CI-системы, установившие заражённые версии напрямую или транзитивно. По данным npm registry, пакет @asyncapi/specs за неделю до инцидента генерировал около 2,74 миллиона загрузок, а совокупное число загрузок четырёх пострадавших пакетов за 30 дней превысило 11,9 миллиона. Речь идёт об атаке на цепочку поставок с наивысшим радиусом поражения среди недавних инцидентов.
Как произошло заражение
В отличие от предыдущих волн, связанных с кражей токенов мейнтейнеров или подменой npm-логинов, в этом случае атакующий получил доступ на запись к репозиториям asyncapi/generator и asyncapi/spec-json-schemas. Ветки next, alpha и master, настроенные на автоматическую публикацию при пуше, не были защищены. Злоумышленник отправил неподписанные коммиты с сообщениями, начинавшимися с "fix:" - этого было достаточно для запуска GitHub Actions, который через OIDC-доверенную публикацию загрузил вредоносные сборки в npm.
В репозитории spec-json-schemas атака затронула даже мастер-ветку: пять коммитов просочились в основной код, и после этого была опубликована версия 6.11.2, ставшая latest. В репозитории generator атакующий использовал ветку next, которая позднее была удалена. Ни мейнтейнерские npm-аккаунты, ни человеческие токены не были скомпрометированы - злоумышленник действовал исключительно через ветки и CI.
Архитектура загрузчика: трёхступенчатая цепочка
Загрузчик срабатывал не через скрипты установки, а при вызове require(). Пользователь, установивший заражённый пакет, уже при импорте модуля запускал вредоносный код. Это делает традиционную защиту - флаг "--ignore-scripts - бесполезной. Вредоносная полезная нагрузка распространялась по трём этапам.
На первом этапе обфусцированный код, встроенный в легитимные файлы утилит (ErrorHandling.js, utils.js, validator.js) или в главный файл index.js пакета specs, запускал дочерний процесс Node, который загружал второй этап с IPFS. Первый этап представлял собой одну строку, спрятанную между десятками строк обычного кода.
Второй этап - скрипт длительностью в несколько десятков строк, который с помощью "https.get()" скачивал 8-мегабайтный файл sync.js из IPFS по определённому CID. Для пакетов generator использовался CID QmQobZSp1…, для specs - Qmet4fhs…. Этот скрипт сохранялся в каталог, зависящий от операционной системы (Windows: %LOCALAPPDATA%/NodeJS/sync.js; macOS: ~/Library/Application Support/NodeJS/sync.js; Linux: ~/.local/share/NodeJS/sync.js), и затем выполнялся новый экземпляр Node с этим файлом.
Третий этап - полноценный фреймворк Miasma, обнаруженный при [анализе] загрузчика пакетов generator. Это 48-строчная обёртка, дешифрующая и выполняющая более 3 МБ сжатого кода. Внутри находится набор модулей: C2-каналы, закрепление в системе, платформа для выполнения команд, а также отключённые в этой сборке модули для кражи учётных данных, распространения через другие реестры и отравления AI-инструментов (Claude, Cursor, Gemini, VSCode).
Возможности фреймворка Miasma
Расшифрованная конфигурация называет кампанию miasma-train-p1 - тренировочная фаза. В этой версии включены только закрепление и связь с C2, тогда как распространение через npm, PyPI, Ruby и Crates.io, сбор учётных данных и AI-отравление выключены. Разработчики отметили флаги "propagate.npm: false", "recon: false", "poisonAI: false". Однако код этих функций уже заложен в ядре и может быть активирован в следующей волне без замены первых двух этапов.
C2-сервер использует HTTP на IP 85.137.53[.]71 (порты 8080, 8081, 8091) с резервными каналами через Nostr, IPFS, libp2p/DHT и Ethereum-контракт для аварийного переключения адресов. Взаимодействие шифруется с помощью HKDF и AES-256-GCM. Для распространения между узлами применяется ECDH-сертификат с максимальной глубиной в 4 поколения.
Закрепление реализовано для всех трёх основных ОС: на macOS добавляет блок nohup в .zshrc или .bashrc, на Linux - systemd-юнит пользователя, на Windows - запись в реестр HKCU Run.
Последствия и рекомендации
Учитывая огромную популярность пакета @asyncapi/specs, который транзитивно подтягивается парсером, CLI и другими инструментами, число потенциально пострадавших систем может исчисляться миллионами. Разработчикам, использовавшим AsyncAPI, необходимо немедленно проверить lockfile на версии 3.3.1, 0.7.1, 1.1.1, 6.11.2 и 6.11.2-alpha.1. Заражённые пакеты следует заменить на чисто предыдущие версии (specs@6.11.1 и т.д.), удалить node_modules и переустановить зависимости. Также требуется проверить наличие файла sync.js в каталогах, перечисленных выше, и удалить следы закрепления (shell-rc блоки, systemd-юниты, ключи реестра). Все учётные данные на машинах, где могли быть установлены заражённые пакеты (npm-токены, AWS, GitHub, CI-токены), следует сбросить.
Текущий анализ предоставленного анализа не включает расшифровку третьего этапа для пакета specs - его IPFS-объект не был исследован. Это означает, что для пакета specs третий этап может быть иным, и его возможности неизвестны. Тем не менее, общая схема загрузчика идентична, и риски для систем, установивших specs@6.11.2, не меньше, чем для generator.
Атака демонстрирует принципиально новый вектор: неподписанные коммиты на ветки с автоматической публикацией, защищённые лишь тривиальной проверкой префикса сообщения коммита. Miasma - не разовая акция, а платформа, способная разворачиваться поэтапно. Следующая волна, скорее всего, активирует модули распространения и кражи, что превратит единичную компрометацию в червеобразное заражение целых экосистем. Разработчикам инструментов с автоматической публикацией следует немедленно пересмотреть защиту веток, требовать подписанные коммиты и внедрить ручную верификацию перед публикацией, даже для CI-пайплайнов.
Индикаторы компрометации
URL
- http://85.137.53.71:8080
- http://85.137.53.71:8081
SHA256
- 24b9ee242f21a73b55f7bb3297eafb33c60840907386b542ed79fc6b72365168
- 082d733db0687dcd768104972b065d4b58cb1e6043688c6c20fa3702337f36ab
- 34014776d3d3ff11bc4439b02fd7ac0f02a887eb3a052eeafff236e2f6db8ad1
- 9b2e65db653ca8575c9b10eefb9a80c6006404812c2ec212bf5675e3c690233b
- bfaeb987faa6de2b5a5eb63b1233d055215b09b0349a9394f2175fd7cdf385e4
- d425e4583cc6185d41e95c45eda00550045a5d1919b9a012236a4520d009dbd7
- b270bdf8e2274ea1af0a6eed74d8f10e5fe61012d6cc226a43cc7cc7fd9f6292
- 8351d251cf0b5a0bd82242deaa0a14e3e1394418d55c0f4259dac4303b79fc0c
Package
- @asyncapi/generator@3.3.1
- @asyncapi/generator-components@0.7.1
- @asyncapi/generator-helpers@1.1.1
- @asyncapi/specs@6.11.2
- @asyncapi/specs@6.11.2-alpha.1