28 августа 2026 года в реестре npm появились десять вредоносных версий пакета @7nohe/openapi-react-query-codegen, который используется для генерации кода на основе OpenAPI-схем и ежемесячно загружается более 670 тысяч раз. Атака привела к публикации поддельных релизов под учётной записью легитимного сопровождающего, при этом злоумышленник не получал доступа ни к паролю от npm, ни к токенам GitHub. Вместо этого он воспользовался ошибкой в конфигурации автоматического релизного конвейера.
Описание
Пакет предназначен для разработчиков, работающих с API-описаниями, поэтому основные жертвы - команды, использующие JavaScript-инструменты в процессах непрерывной интеграции. Установка заражённых версий происходила стандартным способом через менеджер зависимостей, что делало атаку незаметной для большинства пользователей. Все вредоносные публикации уже удалены из npm, однако часть проектов могла успеть скачать их в течение примерно трёх часов, пока пакеты оставались доступны.
Уязвимость находилась не в коде самого проекта, а в настройках GitHub Actions - встроенной платформе автоматизации, которая собирает и публикует пакеты. Релизный сценарий имел триггер, реагирующий на комментарии к запросам на включение изменений. Любой пользователь GitHub, а не только доверенный участник репозитория, мог создать запрос из собственного форка и оставить комментарий с текстом "npm publish". Этого было достаточно, чтобы запустить процесс релиза, который проверял код из форка, устанавливал зависимости и выполнял команду публикации в npm.
Ключевая ошибка состояла в отсутствии проверки уровня доступа автора комментария. Конвейер получал особый токен идентификации, предназначенный для "доверенной публикации" - механизма, при котором npm доверяет временным учётным данным, выпущенным инфраструктурой GitHub, и позволяет публиковать версии без ввода пароля. Поскольку код из форка выполнялся на этапе установки зависимостей, вредоносный скрипт получал доступ к этому токену и от имени владельца пакета выкладывал произвольные сборки. Опубликованный впоследствии анализ инцидента показал, что атака велась в две волны с интервалом около двадцати минут.
Первая волна, начавшаяся в 20:00 UTC, включала вредоносный код в файле конфигурации сборки нативных модулей. При установке пакета npm запускает инструмент node-gyp для пересборки таких модулей, а тот обрабатывает конфигурационный файл с помощью встроенного в Python механизма вычисления выражений. Злоумышленник записал в этот файл строку, которая при разборе выполняла системную команду и запускала многоуровневый обфусцированный скрипт размером от четырёх до шести мегабайт. Сложность заключалась в том, что такой триггер срабатывает даже тогда, когда разработчик отключил установочные скрипты в npm, поскольку node-gyp воспринимается как отдельный этап сборки, а не как жизненный цикл пакета.
Вторая волна вышла в 20:19 UTC, уже после появления первых публичных сообщений о проблеме. Злоумышленник добавил в манифест пакета ещё и прямой предустановочный скрипт, который запускал тот же вредоносный код перед установкой зависимостей. Таким образом он создал два независимых пути выполнения: один неявный и труднообнаруживаемый, второй - явный и более надёжный. По всей видимости, автор атаки оперативно реагировал на действия сообщества и вносил изменения в реальном времени.
Сам вредоносный файл представлял собой однострочный код, зашифрованный в несколько слоёв. После последовательного снятия защиты скрипт загружал из публичного репозитория GitHub исполняемый файл среды выполнения Bun версии 1.4.0 и помещал его во временный каталог с характерным префиксом. На системах Windows загруженный бинарный файл дополнительно переименовывался в случайное шестисимвольное имя, чтобы усложнить обнаружение по имени процесса. Подобная схема загрузки и стиль обфускации ранее встречались в атаках на цепочку поставок, которые связывали с инструментарием Mini Shai-Hulud, применявшимся при компрометации пакетов SAP и AntV весной 2026 года.
Полное назначение финальной стадии пока не установлено: исследователи разобрали загрузчик, но конечный исполняемый код требует дальнейшего изучения. Среди вероятных целей - кража переменных окружения, установка скрытого доступа к системе или использование заражённой машины в качестве промежуточного узла для последующих атак.
Пострадали проекты, в которых использовались диапазоны версий, начиная с ранних релизов вплоть до актуальной ветки. Вредоносные сборки выходили под номерами 0.5.4, 0.5.5, 1.6.3, 1.6.4, 2.2.1, 2.2.2, 3.0.3, 3.0.4, а также две служебные тестовые версии с префиксом 0.0.0. Если проект был привязан к конкретным диапазонам, менеджер зависимостей мог подтянуть заражённый релиз в промежутке с 20:00 до 23:11 UTC. После удаления всех вредоносных версий последней безопасной публикацией остаётся версия 3.0.2 от 11 августа 2026 года.
Сопровождающий проекта закрыл проблему в тот же день: из сценария автоматизации убрали триггер, реагирующий на комментарии, лишили конвейер прав на запись в репозиторий и запретили сохранение учётных данных при проверке кода. Дополнительно установка зависимостей теперь выполняется строго по зафиксированному файлу блокировок, что исключает выполнение произвольного кода из запросов на включение изменений.
Для пользователей, которые могли столкнуться с заражёнными сборками, основная рекомендация - проверить используемые версии пакета и обновиться до актуальной чистой. О наличии вредоносного кода могут свидетельствовать неожиданно появившиеся крупные файлы в каталоге пакета, подозрительные предустановочные команды, а также временные каталоги с необычными именами, создаваемые во время установки. После заражения не лишним будет сменить секреты и токены, хранившиеся в окружении, поскольку конечный вредоносный сценарий мог собирать данные с машины.
Инцидент с @7nohe/openapi-react-query-codegen показывает, что современные атаки на цепочку поставок всё реже требуют кражи паролей. Намного более эффективным оказывается злоупотребление доверием между системами автоматизации: если конвейер способен публиковать пакеты, но не проверяет источник кода, который он выполняет, злоумышленнику достаточно одного комментария к чужому запросу. Регулярный аудит настроек CI/CD, ограничение круга лиц, способных запускать чувствительные операции, и использование токенов с минимально необходимыми правами становятся обязательными элементами защиты для любого проекта с публикацией в открытые реестры.
Индикаторы компрометации
Package
- @7nohe/openapi-react-query-codegen
SHA256
- 0d58f3434c55842fc41ad99656c20a295d46e7d16f432a122a5a094d7c1de0e2
- 1757c9203143db4958b53cb5c97af64bfe46ad57a07764fed59bbb886a71f1da
- 5654e2b3e19cf5e7f1d39d04ebdd3507d3349f76eeb8319de42b2fdb537b8a2d
- 59370c67b54a0ccaedd265e2356f04540b2fba1e1845300ef6de4d5437d99380
- 709af2fdeb50324229e94c44c679a0fab18bd8e17d3864405989c526cbb63ad8
- 73bac41332ea7438b671e6538750502a4548302ce26f99e114ded478436a0cb4
- 778d6f0058045d6a2ab9a7e1d3e3be8e7e6b4d9cc217d13949bf1dfbab759a7c
- 8e5d1af68ca340ae0c6e8132cb00c686ec2d60502c1994d94ce353d1472ad5a3
- a8c00f59e629e5bc4fc6a116fa1ceb8fcf328893a9c798ca446fdcacb0fbdc18
- acaee3a02873334002a27d6643c20f4e38e52c8d0d1f492788e2b68586e2cbfa
- b24d121667f21f492cb9db34fbfd515d5922a8dd30b9c45215c7220abbb10ca8
- b49afb7dba04cd99b357ce7c652c823a3707f28e130bd5c6645851a7adc030d6
- b6012b2ff87f08f93ee53921c48db907ddbcf5461b03bb988083b01a36886237
- c555a1ab1a2e0425d6d7f965bae55af83b5aceab2177494a00ec43451c863c63
- cb46dbd078753f562931920fe4b109c673925138b0e9399527e84c53f07d8a7a
- d1f9960349f2bc0689518ef754d577e1c13125db59b0252f1c85894bb69b5c8e
- d3246926b20a8d021ed7de0ac8e9eee1dda986088f84ba18f31cb2042a121f5d
- e1f1162ece9a6e6ea21a20399cbf31c563a8149d433a68711f4223870c203d5a
- f2f88ce6e8b0d8a6c75b4c6cf6a23db4bc1430f359b9bb12c9418fcb74cdfe46