Into
Я занимаюсь бэкенд-разработкой и слежу за security-инцидентами, которые касаются нашего стека. В марте 2026 года произошло кое-что, что я не мог пропустить - взломали Trivy. Это open source сканер уязвимостей, которым пользуются десятки тысяч компаний, включая нас. История получилась почти детективная, с несколькими волнами атаки и последствиями, которые расходятся до сих пор.
Что такое Trivy и зачем он нужен

Trivy - это инструмент, который ты запускаешь в своём CI/CD пайплайне и он проверяет твой код на уязвимости. Ищет проблемы в NPM-пакетах, Python-зависимостях, Docker-образах, проверяет мисконфигурации в Kubernetes, находит захардкоженные секреты.
В общем, это именно тот инструмент, которой должен быть про безопасноть - но иронично что вот его-то и взломали.
Первый акт: незакрытая дверь
29 ноября 2025 года компания Boost Security (которая занимается аудитом опенсорс пакетов) нашла в Trivy мисконфигурацию в GitHub Actions.
Называется это "Pwn Request" - когда workflow настроен на триггер pull_request_target, который запускается с секретами самого репозитория даже если PR открыл совершенно посторонний человек. После этого - всё, у чужака есть доступ к твоим ключам.
Уязвимость нашли в ноябре. Она просидела непропатченной три месяца.
Акт второй: AI-от открывает дверь
27 февраля 2026 года hackerbot-claw автономный агент открывает PR#10254 (уже удаленный) и он выглядит как рутинный фикс - но цель одна - заэкспойтить уязвимый триггер.
- Через 19 минут спустя токен окен сервисного аккаунта
aqua-botукраден. - Сразу же удалены 178 GitHub Releases и реозиторий был переимеинован
- А в Open VSX Marketplace (это маркетплейс расширений для VS Code) публикуются две заражённые версии Trivy-расширения с AI иньекциями. Промпт в любом AI-ассистенте разработчика (Copilot, Cursor), превращая его в "агента безопасности" с задачей найти и передать все credentials. Оба расширения срабатывали при открытии workspace - без единого действия пользователя.
- 1 марта Aqua обнаружила атаку и начала ротировать секреты. Но сделала это неатомарно - не всё сразу, а по очереди. Пока ротировали один токен, у злоумышленников оставался доступ через другого. Так они оставили за собой контроль над репозиторием.
Акт третий: подготовка бомбы
4 марта в основной репозиторий Trivy прилетает коммит как будто от реального мейнтейнер DmitriyLewen с датой январь 2026. Сообщение - скучное CI-обслуживание.
На самом деле: автор подделан, дата подделана, а в диффе спрятаны две важные строчки.
- Первая перенаправляет сборочный пайплайн на коммит злоумышленников - при следующем релизе туда будет скачан вредоносный Go-код.
- Вторая добавляет флаг --skip=validate в сборщик, отключая проверку целостности бинарника. Коммит пролежал в репо незамеченным 15 дней.
Акт четвёртый: главная атака
19 марта, 17:43 UTC. Два удара одновременно.
Удар A по GitHub Actions. Злоумышленники force-push'ат 75 новыйх тэгов в trivy-action. Тэги в гите используются чтобы указать на определенный коммит, и злоумышленник перевешивает их на свои коммиты. Но делает это хитро - перевешивает все кроме последнего, чтобы было незаметно.
С этого момента все uses: aquasecurity/trivy-action@0.20.0 в github workflow начинают ссылкаться на зараженные коммиты
Удар B по бинарнику. Параллельно публикуется тег v0.69.4 в основном репо. Запускается автоматический релизный пайплайн Aqua и он (смотри АКТ#3) а, скачивает вредоносный код и собирает из него официальный бинарник Trivy. Через 40 минут он уже лежит на GitHub Releases, Docker Hub, GHCR и AWS ECR и все докер имиджи которые запрашивают в паплайнах докер имидж :latest или без указания начинают подгружать этот зараженный бинарник
Что же крал код?
## Env dump
printenv
## Cred fies
~/.ssh/id_rsa, ~/.ssh/config → SSH private keys
~/.aws/credentials, ~/.aws/config → AWS access keys
~/.kube/config → Kubernetes cluster tokens
~/.docker/config.json → Docker registry tokens
~/.config/gcloud/ → GCP credentials
~/.azure/ → Azure credentials
~/.npmrc, ~/.netrc, ~/.pgpass → npm tokens, postgres passwords
~/.config/solana/, ~/.ethereum/ → crypto wallets
.env .env.local .env.production .env.staging
/proc/*/mem
/proc/*/cmdline
/proc/*/environ
Всё украденное шифровалось и отправлялось POST-запросом на
scan.aquasecurtiy.org домен с намеренной опечаткой в слове "securtiy".
Когда community попыталось координировать response через GitHub Discussions, злоумышленники удалили основной тред #10265, а новый тред #10420
немедленно заспамили 47 ботов за 12 секунд бессмысленными комментариями вроде "this is exactly the answer I needed".
Как обнаружили
Три независимых сигнала за 45 минут.
- Boost Security ( та что сканирует opensource проекты) засекла аномалию в git-активности: 75 force-push'ей за несколько секунд - так не ведёт себя ни один сервисный аккаунт.
- Независимый исследователь Пол Макарти, который следил за репозиторием после первого инцидента, заметил странный релиз v0.69.4. Написал предупреждение прямо из аэропорта - летел на RSAC 2026, ту самую главную конференцию по кибербезопасности, куда в этот момент направлялось большинство профессионалов индустрии, возможно момент для атаки был выбран не просто так
- CrowdStrike Falcon на self-hosted runner'ах у энтерпрайз-клиентов поймал странное поведение на CI: чтение памяти процессов, открытие файлов с credentials, исходящие POST-запросы . Одна и та же картина у разных компаний одновременно.
Последствия
Очистка тегов заняла с 20:38 19 марта до 05:40 утра 20 марта. Всё это время заражённый код продолжал работать в чужих пайплайнах.
Интересная подробность заключалась в том что злоумышленники заранее предусмотрели, что maintainer'ы попытаются переставить теги обратно - это обычно делается одной git-командой.
Поэтому сразу после force-push'а они пометили каждый из 75 отравленных тегов как Immutable Release - платформенная фича GitHub, которая блокирует удаление и изменение тега на уровне API.
Для очистки maintainer'ам пришлось вручную снимать этот флаг с каждого из 75 релизов через admin-интерфейс, потом переставлять тег и верифицировать.
При этом GitHub rate limits не дают делать это мгновенно. Процесс занял с 20:38 вечера до 05:40 следующего утра - почти 12 часов, в течение которых тысячи пайплайнов продолжали тянуть и исполнять заражённый код.
Aftermath
Дальше пошли волны.
- 20 марта украденные npm-токены пустили в дело а именно злоумышленники начали публиковать заражённые патч-версии npm-пакетов всех кто попал под раздачу. Которые в свою очередь при установке крали новые npm-токены и заражали следующие пакеты. 141 зараженный npm пакет найдены зараженными
- 22 марта. Через неротированный Docker Hub-токен запушены ещё две заражённые версии бинарника - 0.69.5 и 0.69.6 - напрямую в Docker Hub, минуя GitHub. А заодно и переименовали все 44 репозитория внутренней организации
- 23 марта. Атакован Checkmarx KICS - ещё один популярный security-сканер по такой же методике
- 24 марта. LiteLLM - Python-библиотека-прокси для всех LLM API с 95 миллионами загрузок в месяц, которая использовала Trivy в своём CI потеряла токен мейнтейнера и с его помощью были опубликованы версии 1.82.7 и 1.82.8 с вредоносным кодом.
Возможные выводы
Из всего вышеописанного я бы предложил следующие вещи которые бы могли бы повысить безопасность малыми усилиями
- Пинить GitHub Actions по SHA, не по тегу не
uses: aquasecurity/trivy-action@0.20.0аuses: aquasecurity/trivy-action@57a97c7e - Пинить и убирать
:latestиз Docker образов по той же причине - Ввести Cooldown для пакетных менеджеров чтобы несколько дней свежие версии пакетов могли бы отлежаться и не устанавливаться например
npm min-release-age v11.10.0+ - Использовать Docker Hardened images так как DHI проходят доп проверки и намеренно отстают от апстрима
Для меня эта история интересна прежде всего тем, насколько она обыденная. Злоумышленники не взламывали шифрование, не эксплуатировали zero-day в ядре Linux, а воспользовались тем, как устроена повседневная работа разработчика: тегами в Git, автоматическими пайплайнами, доверием к инструментам с 34k звёздами на GitHub.
Всё что они сделали - это переставили указатели.
И ирония тоже очевидна: именно security-инструменту давали самый широкий доступ к пайплайнам и именно это сделало его идеальной целью.

