1500 npm-пакетов можно было угнать, просто заняв старое имя на GitHub
Защитный механизм npm оказался способен передать право на выпуск чужого пакета тому, кто просто занял освободившееся имя репозитория. Bloom Security обнаружила проблему SlugFest и насчитала более 1500 потенциально уязвимых пакетов с суммарно более чем 10 млн загрузок и свыше 1 млн загрузок в месяц. Для атаки не требовалось похищать учётные данные.
Trusted Publishing позволяет публиковать релизы из GitHub Actions без постоянного npm-токена. CI/CD получает короткоживущий OIDC-токен, который npm проверяет перед выдачей временных прав на публикацию. Ошибка скрывалась в привязке доверия: до первого успешного релиза npm сохранял текстовый адрес owner/repository, а не постоянные числовые идентификаторы репозитория и владельца.
Если разработчик переименовывал, переносил или удалял связанный репозиторий, старый адрес мог снова стать доступным. Атакующий мог зарегистрировать репозиторий с прежним именем, создать workflow с нужным названием и получить корректный OIDC-токен. npm видел совпавший адрес и выдавал временный токен публикации, хотя новый репозиторий уже принадлежал другому владельцу.
Bloom проверила схему на собственном npm-пакете и подконтрольных репозиториях. Исследователи смогли выпустить новую версию из репозитория другой организации, не похищая npm- или GitHub-учётные данные. Вредоносный релиз мог сохранить имя, репутацию и зависимости легитимного пакета, а postinstall-сценарий запускал бы код при установке. Реальные атаки через SlugFest не подтверждены.
Риск усиливает автоматизация разработки. По измерениям Bloom, обычная рабочая станция получает около 70 пакетов в месяц через ИИ-агентов, а машина разработчика около 350. Агент может выбрать свежую версию зависимости без ручной проверки происхождения. Похожую проблему уже показывали ИИ-зависимости, где автоматический выбор пакетов расширяет поверхность атаки.
GitHub получила отчёт 6 июня и подтвердила проблему 9 июня, а исправление появилось 2 октября. Компания изменила правила: непроверенная конфигурация Trusted Publishing теперь живёт только 48 часов, после чего теряет право публиковать. Первый успешный релиз подтверждает привязку к неизменяемой идентичности репозитория. npm также перестал принимать Trusted Publishing-токены из событий issue_comment.
Сопровождающим советуют проверить привязки через npm trust list, удалить настройки для переименованных, перенесённых или удалённых репозиториев и создать новые. После новой привязки лучше сразу выпустить релиз, чтобы npm зафиксировал постоянный идентификатор. Дополнительный барьер даёт поэтапная публикация, где выпуск требует одобрения сопровождающего с 2FA.