11 мая 2026 года злоумышленники за 6 минут опубликовали 84 вредоносные версии 42 npm-пакетов семейства @tanstack/* (популярный набор библиотек для фронтенд-разработки) с легитимной подписью происхождения (SLSA provenance). При этом учетные данные мейнтейнеров не были украдены, а 2FA была включена.
Схема атаки:
⚪️ Pwn Request. Злоумышленник создал PR из форка. Воркфлоу
bundle-size.yml использовал триггер pull_request_target. Сам по себе он безопасен (запускает код из ветки main), но внутри был шаг сборки бенчмарков, который явно подтягивал файлы из коммита форка. Это и позволило вредоносному коду выполниться в контексте базового репозитория без одобрения админов.⚪️ Отравление кэша. Вредоносный скрипт записал отравленный кэш
pnpm-store (1.1 ГБ) в общий репозиторий под ключом ветки main. Разграничение прав через permissions не сработало, так как экшен использовал внутренний токен раннера для записи, а не GITHUB_TOKEN. Затем злоумышленник сделал force-push пустышки, скрыв изменения в PR.⚪️ Кража OIDC-токена из памяти. Когда мейнтейнер сделал штатный пуш в main, запустился легитимный релизный воркфлоу, который восстановил отравленный кэш. Вредоносный код активировался и извлек валидный OIDC-токен прямо из оперативной памяти процесса GitHub Actions Runner, после чего легитимно залил пакеты в npm.
Вредоносный код внедрялся через хук
prepare (optionalDependencies) и выполнял:⚪️ Сбор секретов. Сканировал
.npmrc, сессии GitHub/gh CLI, ключи AWS (IMDS/Secrets Manager), GCP, Azure, конфиги Kubernetes, HashiCorp Vault, приватные SSH-ключи, файлы .env и сессии 1Password.⚪️ Эксфильтрацию. Отправлял данные по HTTPS и скрытым DNS-каналам в сеть Session/Oxen.
⚪️ Червь-эффект. Запрашивал у npm другие пакеты, где скомпрометированный юзер был админом, и пытался заразить и их (пострадали некоторые пакеты Mistral AI, UiPath, Guardrails AI).
Если ваша команда пользуется TanStack:
⚪️Проверить lock-файлы на наличие зараженных версий (полный список в CVE-2026-45321 / GHSA-g7cv-rxg3-hmpx). Если пакеты ставились — считать раннеры/хосты скомпрометированными и провести полную ротацию всех секретов и ключей, к которым они имели доступ.
⚪️Блокировать хуки сборки. В CI/CD использовать флаг
--ignore-scripts при установке зависимостей (например, pnpm install --ignore-scripts или npm ci --ignore-scripts).⚪️Изолировать кэш. Недостаточно просто ограничить OIDC-токен веткой main (ведь атакующие дождались легитимного пуша). Необходимо строго разделять области видимости кэша. Кэш для релизных пайплайнов должен быть полностью изолирован от кэша, доступного для воркфлоу проверки PR (
pull_request_target).В GitHub Actions фиксировать сторонние экшены по SHA-хэшам коммитов, ограничить область действия OIDC конкретными защищенными ветками (refs/heads/main) и жестко изолировать триггер
pull_request_target.@DevOpsKaz 😛
