Пять вредоносных версий пакетов AsyncAPI успели попасть в npm, а суммарная недельная аудитория затронутых зависимостей превышала 2,25 млн загрузок. Для тех, кто живет в Node.js-стеке, это не очередная страшилка про supply chain, а очень прикладной сигнал: даже доверенная публикация через CI/CD и легитимные аттестации происхождения уже не гарантируют, что в проект не приедут вредоносные npm-пакеты.
Инцидент произошел 14 июля, сообщает BleepingComputer. По данным исследователей Step Security, злоумышленник скомпрометировал два GitHub-репозитория AsyncAPI и внедрил вредоносный код в файлы проекта. Ключевой момент в том, что атака шла не через украденный npm-токен и не через злонамеренного мейнтейнера. Нападавший использовал неверно настроенный workflow в GitHub Actions: добавил коммиты с подставной git-личностью, а затем штатный релизный процесс сам опубликовал зараженные пакеты через доверенную интеграцию npm с GitHub OIDC.
В итоге в реестр ушли версии, которые внешне выглядели вполне официально и даже получили корректные SLSA provenance attestations, то есть признаки того, что сборка и публикация прошли через авторизованный pipeline. Под раздачу попали @asyncapi/generator 3.3.1, @asyncapi/generator-helpers 1.1.1, @asyncapi/generator-components 0.7.1, а также @asyncapi/specs 6.11.2-alpha.1 и 6.11.2. Самый неприятный пункт в списке — именно @asyncapi/specs с аудиторией около 2,1 млн недельных загрузок. Даже если значительная часть этих инсталляций автоматическая, масштаб потенциального каскадного заражения для экосистемы выглядит совсем не академическим.
Технически схема была многоступенчатой. По оценке Socket, первый этап выглядел как обфусцированная JavaScript-вставка, которая запускала downloader при импорте зараженного файла. Затем подтягивался второй скрипт с конфигурацией и основным рантаймом: его грузили из IPFS и запускали в скрытом процессе. Дальше, как пишет Wiz, срабатывал уже третий этап — модульный вредоносный фреймворк примерно на 92 тыс. строк кода. Он закреплялся в системе и связывался с управляющей инфраструктурой не одним, а сразу несколькими каналами: через HTTP, ретрансляторы Nostr, смарт-контракты Ethereum и сеть на базе libp2p. Иными словами, авторы явно проектировали не одноразовый скрипт, а довольно живучую платформу с запасом на обход блокировок и отказ отдельных каналов связи.
Полезная нагрузка тоже была рассчитана не на шоу, а на сбор всего, что плохо лежит. Исследователи указывают на попытки вытащить учетные данные, ключи аутентификации, токены, данные браузеров, секреты из CI/CD-сред, сведения из AI-инструментов для разработчиков, криптокошельков и баз данных. В коде также нашли возможность догружать Gitleaks и HackBrowserData для помощи в эксфильтрации чувствительной информации. Отдельно SafeDep обратил внимание, что артефакты и конфиги похожи на бэкдор Miasma, уже замеченный в прошлых атаках на цепочку поставок. При этом исследователи считают, что это может быть либо частная сборка тех же операторов, либо другая группа, которая просто подхватила уже известный бренд после публикации исходников.
Есть и одна ироничная деталь. Aikido сообщает, что автоматизированные функции кражи данных в текущем варианте, похоже, не отрабатывали как задумано: harvesting-инструмент завершался до того, как успевал что-то собрать. Но расслабляться на этом месте было бы странно. Во-первых, присутствие удаленного шелла уже само по себе делает заражение серьезным инцидентом. Во-вторых, если у атакующего есть интерактивный доступ к машине разработчика, runner'у CI или внутреннему серверу, многие действия можно сделать вручную и без идеально работающего стилера. Наконец, Ox Security заметила еще одну характерную особенность: вредонос проверял локаль на принадлежность к России и в случае совпадения прекращал работу. Для русскоязычной аудитории это не повод считать себя вне зоны риска. Такие проверки часто служат лишь для ухода от внимания определенных юрисдикций и почти ничего не говорят о реальной географии жертв.
На момент публикации все пять зараженных релизов были удалены из npm, но главное окно риска уже состоялось: примерно с 07:10 до 11:18 UTC 14 июля, то есть чуть больше четырех часов. Для npm-экосистемы этого более чем достаточно, особенно если пакет стоит в транзитивных зависимостях популярных инструментов, шаблонов и внутренних генераторов. Отсюда практический вывод для команд, которые работают с Node.js: простой апдейт реестра проблему не закрывает. Если lock-файлы были созданы в это окно или сборки тянули затронутые версии из кеша, зараженный код мог остаться в проектах и после удаления релиза из публичного каталога.
Что делать разработчикам и компаниям, если AsyncAPI есть в зависимостях, набор мер вполне приземленный. Нужно зафиксировать безопасные версии, пересобрать lock-файлы, проверить наличие скрытой полезной нагрузки NodeJS/sync.js, завершить подозрительные процессы и ротировать учетные данные на затронутых хостах. Причем речь не только о токенах npm или GitHub. Под замену могут пойти секреты CI/CD, облачные ключи, доступы к контейнерным реестрам, переменные окружения, сервисные аккаунты и все, что лежало в рабочем окружении разработчика или build-агента. Для бизнеса это опять поднимает неприятный, но уже неизбежный вопрос: достаточно ли вы доверяете одной только подписи поставщика, если сам доверенный pipeline можно использовать против вас.
В более широком контексте история с AsyncAPI укладывается в уже знакомый тренд 2025–2026 годов: атаки на open source все чаще бьют не по репозиторию как таковому, а по автоматизации вокруг него. Вчера слабым звеном был компрометированный токен, сегодня — доверенный publisher и неудачно настроенный GitHub Actions workflow. Завтра, вероятно, цель снова сместится, но логика останется той же: злоумышленники ищут самый короткий путь к официальной поставке. Для индустрии это неприятный, зато очень ясный вывод: безопасность цепочки поставок теперь надо проверять не по красивым бейджам, а по тому, кто и при каких условиях реально может заставить ваш CI выпустить очередной «легитимный» пакет.