Cloudflare показала архитектуру ИИ-конвейера для поиска уязвимостей во всём парке репозиториев

Cloudflare показала архитектуру ИИ-конвейера для поиска уязвимостей во всём парке репозиториев

Cloudflare продолжает серию постов о Project Glasswing, внутреннем проекте о том, что происходит, если направить передовые модели ИИ на корпоративную кодовую базу. Тезис компании: будущее агентных рабочих процессов не в отдельной модели, промпте или одной агентной сессии, а в архитектуре, где модели, взаимозаменяемые детали. Одна модель смотрит на код через один и тот же «объектив» и пропускает одни и те же классы багов, поэтому в конвейере модели специально чередуют и перекрёстно проверяют друг друга, например, одна модель ищет уязвимости, а совсем другая их проверяет. Полноценный корпоративный инструмент (harness) должен также прослеживать зависимости между репозиториями и отфильтровывать тысячи сырых кандидатов до доверенной очереди реальных исправлений.

Всё начиналось с навыка (skill) на ~450 строк, который гоняли на одном репозитории, пока не начали всплывать реальные баги. Навык запускал 7-этапный аудит за один сеанс: три параллельных агента-разведчика пишут файл architecture.md; на каждый класс атаки запускается отдельный агент-«охотник» (Hunter), который пытается сломать код, а не просто прочитать его; агенты-валидаторы пытаются опровергнуть находки; выжившие находки оформляются в отчёт для человека и одновременно выгружаются как findings.json по схеме с механической проверкой; наконец, свежий агент независимо перепроверяет каждую находку против исходного кода, и только выжившие уходят в API приёма. Навык работал, но один прогон находил только около половины багов по сравнению с несколькими прогонами подряд, причём находил в основном простые и не самые тонкие. Команда упёрлась в три стены, главная, исчерпание контекста: примерно через час модель начинает «пожирать» собственную память и мгновенно забывает баги, найденные с утра. Решение, полностью вынести состояние наружу и обращаться с LLM как со stateless (не хранящим состояние) вычислительным движком.

Перевод навыка в полноценный конвейер занял около шести недель: каждый этап навыка стал отдельным агентом, за ним встала база данных, а перед ней, оркестратор. Итоговая система охватывает 128 репозиториев на смеси языков (Rust, Go, C, Lua, TypeScript, Python) без ручной настройки под конкретный язык, харнесс работает на уровне логики безопасности, а не синтаксиса. Рабочий процесс разбит на два этапа: Vulnerability Discovery Harness (VDH, харнесс обнаружения уязвимостей) ищет проблемы, а Vulnerability Validation System (VVS, система проверки уязвимостей) принимает находки сразу от нескольких харнессов и прогоняет их через дедупликацию, оценку (Judgment) и исправление (Fixing). Для VDH и VVS специально берут разные модели, чтобы они перепроверяли друг друга: одна модель ищет баг, совершенно другая, независимо судит находку с иным набором «логических весов» и данных обучения. Есть и практическая выгода: провайдеры моделей со временем меняют температуру, кэширование и бюджет на инференс даже в рамках одной версии модели, а харнесс, не завязанный на конкретную модель, спокойно переживает эту изменчивость.

Внутри VDH этапы 4-8 работают как непрерывный цикл «производитель-потребитель»: агенты Gapfill, Feedback и Trace генерируют новые задачи, агент Dedup сворачивает пересекающиеся находки, и вся очередь продолжает обрабатываться, так что даже баг, найденный под конец прогона, проходит валидацию и проверку на совпадение с уже известными находками. Контекст каждого агента жёстко ограничен (используется меньше 25% окна), потому что наивное «прочитать все файлы» гарантированно выбивает лимит. Каждый этап пишет в единую SQLite-базу с ключом (run_id, репозиторий, этап), поэтому любой этап можно приостановить, повторить или подхватить в следующем прогоне без потери уже сделанной работы, падение стоит только незавершённую в моменте задачу.

На этапе Recon (разведка) агент сам пишет модель угроз для конкретного репозитория, а не получает готовую: помимо примерно десяти встроенных классов атак (разные виды инъекций, повреждение памяти, разбор протоколов, тайминг-атаки по побочным каналам) агент может придумывать классы, специфичные для конкретной кодовой базы. Агенты-охотники не просто читают код, а активно его исполняют: компилируют фрагменты, собирают небольшие версии программ и атакуют их в песочнице на основе unshare, чтобы ронять бинарники, именно это дало наибольший прирост качества находок. Отдельный механизм, Sibling Forking (порождение агента-«побратима»): если охотник натыкается на интересный, но не относящийся к текущей задаче код, он не сворачивает с курса, а вызовом инструмента порождает агента-побратима с точным структурным заданием на эту находку; по всему парку репозиториев на такие ответвления приходится около 9% задач, а доля сильно зависит от модели, от почти нуля до примерно пятой части.

Cloudflare прямо предупреждает: не стоит сразу строить полный харнесс. Минимальная рабочая версия, это всего три этапа (Recon, Hunt, Validate) поверх базы данных плюс отдельный валидатор, который не может сам заводить находки; кросс-репозиторную трассировку и отдельного агента-дедупликатора стоит добавлять только тогда, когда без них уже реально плохо. Ещё два практических предупреждения из статьи: временная ошибка API иногда приходит текстом внутри ответа 200 OK вместо исключения, такой ответ надо явно разбирать, иначе оркестратор запишет пустой прогон как успешный; а если харнесс запускается внутри Docker, песочнице нужны флаги seccomp=unconfined и apparmor=unconfined, иначе она молча не запускается.

Ключевые факты

  • Cloudflare масштабировала проект Glasswing от навыка (skill) на ~450 строк для одного репозитория до конвейера, покрывающего 128 репозиториев на Rust, Go, C, Lua, TypeScript и Python, переход занял около 6 недель
  • Система разбита на два этапа: VDH (Vulnerability Discovery Harness, поиск уязвимостей) и VVS (Vulnerability Validation System, дедупликация, оценка и исправление находок), причём для поиска и для проверки берут намеренно разные модели, чтобы они перепроверяли друг друга
  • Один прогон одной моделью находит лишь около половины багов, которые находятся за несколько прогонов; главным ограничением было исчерпание контекстного окна примерно через час работы, решение состоит в вынесении состояния в SQLite-базу и удержании контекста каждого агента ниже 25% окна
  • Агенты-«охотники» не просто читают код, а компилируют фрагменты и активно атакуют их в песочнице на основе unshare, чтобы ронять бинарники; механизм Sibling Forking (порождение агента-побратима для побочных находок) даёт около 9% всех задач в парке репозиториев
  • Практические предупреждения: временная ошибка API может прийти текстом в ответе 200 OK вместо исключения (нужна явная классификация ответа), а песочнице внутри Docker требуются флаги seccomp=unconfined и apparmor=unconfined, иначе она молча не стартует

Почему это важно

Пост описывает не демо и не бенчмарк, а работающую инженерную систему, которая уже год с лишним сканирует реальный парк из 128 репозиториев компании. Это редкий подробный отчёт о том, как довести ИИ-агентов до продакшена в задаче с высокой ценой ошибки (поиск уязвимостей): вместо ставки на одну лучшую модель Cloudflare строит инфраструктуру, где модели, взаимозаменяемые и специально дублирующие друг друга компоненты, а состояние живёт в базе данных, а не в контексте модели. Это прямой ответ на главную практическую проблему одноагентных систем, потерю памяти при исчерпании контекстного окна.

Кому это важно

Инженерам AppSec и DevSecOps, которые оценивают ИИ-инструменты для поиска уязвимостей в крупных мультиязычных кодовых базах; командам, строящим собственные агентные пайплайны (не только для security) и упирающимся в те же стены, контекст, устойчивость к сбоям, зависимость от одной модели; техническим руководителям, выбирающим между покупкой готового решения и разработкой своего харнесса.

Как это применить

Рецепт Cloudflare пошаговый: начать с одного навыка (skill) на один репозиторий и довести промпты до реальных находок; не спешить строить полный харнесс, минимум это три этапа (Recon, Hunt, Validate) над базой данных плюс отдельный валидатор без права заводить находки; кросс-репозиторную трассировку и агента-дедупликатора добавлять только тогда, когда без них реально тяжело; хранить состояние каждого этапа в SQLite с ключом (run_id, репозиторий, этап), чтобы любой шаг можно было повторить без потери работы; держать контекст каждого агента ниже 25% окна; использовать разные модели для поиска и для проверки находок; при запуске песочницы в Docker сразу выставлять seccomp=unconfined и apparmor=unconfined.

Можно ли доверять

Это первоисточник, собственный технический блог Cloudflare, без независимой верификации цифр (128 репозиториев, ~9% форков, доля ~половины багов за прогон и т.д.) сторонними наблюдателями. При этом текст не выглядит рекламным глянцем: авторы прямо признают ограничения (один прогон находит меньше половины багов, находки скошены к простым случаям, шесть недель ушло на кодификацию, отдельные баги вроде «200 OK с текстом ошибки внутри»), что типично для честного инженерного пост-мортема, а не маркетинга. Как и в любом корпоративном блоге, стоит учитывать, что часть деталей архитектуры могла быть упрощена или опущена в интересах компании.

Риски и подводные камни

Подход требует серьёзных инженерных вложений: полноценный харнесс, это база данных, оркестратор, песочница для исполнения кода и месяцы разработки, а не промпт. Поведение сторонних моделей (температура, кэширование, бюджет инференса) может незаметно меняться со временем даже в рамках одной версии, отсюда и решение специально не привязываться к одной модели. Песочница для исполнения кода в контейнере, источник тонких отказов (нужные флаги seccomp/apparmor легко упустить). Даже зрелая система по признанию авторов пропускает часть багов и генерирует ложные срабатывания, которые приходится отсеивать отдельными этапами дедупликации и валидации, а окончательное исправление находок, из отдельного этапа Fixing, детали которого в этом посте не раскрыты.

«Когда речь идёт о поиске уязвимостей, мы используем ту передовую модель, которая на данный момент лучше всего справляется с задачей. Если направить на одну и ту же цель разные модели, каждая находит свою долю багов. Именно инструмент (харнесс) переживает модели, а не наоборот.»

— блог Cloudflare, Project Glasswing