Для начала — одна неприятная мысль о вашем ИИ-помощнике по программированию.
Во второй части этой серии Foundry потратила около двух миллионов токенов на сканирование API Langflow и подтвердила наличие уязвимости: эндпоинт защищает себя проверкой «только локальные соединения», а затем определяет, что считать «локальным», доверяя заголовку HTTP, который может подделать любой злоумышленник. Неплошая находка. Проверено по исходному коду, залогировано, снабжено цифровым следом, отсортировано.
Теперь представьте, что завтра утром разработчик из другой команды откроет свой редактор и попросит ИИ-помощника: «добавь административный эндпоинт, который принимает запросы только с localhost».
Как вы думаете, что напишет ИИ-помощник?
Держу пари: какую-то версию той же ошибки. Он учился на том же публичном коде, что и все остальные. Ассистент не читал наш отчёт Foundry. Ему никто об этом не говорил.
В этом и заключается проблема обнаружения как такового. Каждая находка — это урок, за который организация заплатила, а самый быстро растущий автор нового кода в вашей компании ничего о них не слышал. ИИ-помощники теперь пишут код быстрее, чем любая команда безопасности успевает его проверять. Поэтому, если предотвращение не доходит до каждого нажатия клавиши, обнаружение превращается в бег на месте: вы вечно находите те же классы уязвимостей в свежем коде, написанном вчера.
Эта статья посвящена тому, как остановить этот бег по кругу. Кузница из Части 2 теперь обзавелась стражем.
Встречайте стража: Проект CodeGuard
Проект CodeGuard — это проект с открытым исходным кодом, не зависящий от конкретных моделей фреймворк правил безопасности и навыков для ИИ-агентов по написанию кода. Компания Cisco изначально разработала его и передала в Коалицию за безопасный ИИ (CoSAI).
Идея проста и эффективна. Рекомендации по безопасности пишутся один раз в виде простого Markdown и переводятся в тот формат, который читает каждый конкретный ассистент: .cursor/rules/ для Cursor; .github/instructions/ для GitHub Copilot; .windsurf/rules/ для Windsurf; навыки для Codex, Devin, OpenCode и других; а также плагин для Claude Code. Существует даже MCP-сервер, с помощью которого организация может передавать централизованно управляемый набор правил каждому помощнику по программированию.
Правила работают в три момента времени:
- Перед генерацией, направляя планирование и работу на основе спецификаций в сторону безопасных архитектурных решений.
- Во время генерации, чтобы ассистент с самого начала писал код по безопасному шаблону.
- После генерации, в качестве рекомендаций для проверки кода теми же агентами.
Базовый набор правил охватывает классические темы: криптография, валидация ввода и инъекции, аутентификация, авторизация, управление сеансами, цепочка поставок, облачные технологии и инфраструктура, защита данных.
Вопрос, на который отвечает эта статья: что происходит, когда правила представляют собой не просто хорошо подобранный общий набор, а заимствованы из реальных уязвимостей в вашем собственном коде?
Маховик в три оборота
В центре спецификации Foundry лежит один механизм: когда система находит что-то, что не покрывается ее правилами, она должна подсказать вам, какое правило написать следующим. В спецификации это называется «маховиком обнаружения и предотвращения» (detection-to-prevention flywheel), при этом сам механизм намеренно не конкретизируется. Создание его реальной реализации оказалось той частью проекта, которая понравилась мне больше всего.
В моих реальных запусках маховик срабатывал тремя разными способами.
Оборот первый: шумное правило стало точнее
Первый масштабный запуск Langflow активировал правило «утечка информации об ошибках» для идиомы, которая встречается по всей кодовой базе: возвращение чистого текста исключения в ошибке HTTP. 72 практически идентичных результата. Технически верно, но абсолютно бесполезно. Это не 72 ошибки. Это одна системная проблема в 72 обличьях.
Инстинкт подсказывает, что нужно спорить с результатами. Однако правильный шаг — отнестись к шумному правилу как к сигналу о самом правиле. Я ужесточил его так, чтобы подтверждались только действительно чувствительные утечки (трассировки, ошибки базы данных, файловой системы и подпроцессов, пути и запросы), а общая идиома фиксировалась один раз. При повторном запуске этот класс сократился с 72 результатов до 6, а на переднем плане остались реальные проблемы с авторизацией и обходом пути (path traversal).
Это и есть работа маховика, улучшающая обнаружение. Меньше находок, больше полезного сигнала.
Оборот второй: система обнаружила класс, для которого у нее не было правил
Пробный проход детектора выявил ту самую проверку «только локально», доверяющую заголовкам — паттерн, выходящий за рамки всего корпуса из 13 правил. Затем модуль сортировки (Triager) подтвердил это, и Foundry записала проблему в rule-gaps.jsonl:
В MLflow тот же механизм обнаружил совершенно другую проблему: метод, который извлекает идентификатор запуска (run ID) из переданного вызывающей стороной пути к артефакту. Отсутствует проверка границ, отсутствует проверка формата, и последующие привилегированные вызовы API используют полученный результат (CWE-129).
Ничего из этого не было в корпусе. Теперь оба случая стали уроками.
Оборот третий: база стала учителем
В Части 2 я сравнил Foundry с честной базовой линией на базе простого агента. Действуя свободно, эта базовая линия также выявила класс уязвимостей вне моего корпуса: CWE-348, «использование менее доверенного источника». Предпочитаю признавать это честно, а не оправдываться. Неограниченный агент может охватывать больше, чем объявленный набор правил. Это не поражение для тестового окружения. Напротив, это бесплатный входной ресурс для маховика, а модуль оценки детерминированно вычисляет пробел в покрытии.
И предыдущие обороты уже принесли плоды еще до этих запусков: четыре правила в рабочем корпусе (авторизация на уровне объектов, инъекция через заголовки, утечки через ошибки, раскрытие конфиденциальных данных) появились в результате предыдущих итераций именно этого цикла.
Экспорт: от урока к правилу одной командой
Здесь цикл замыкается. В моем репозитории Foundry есть команда synthesize, которая читает журнал пробелов в правилах и для каждого пробела просит модель создать два артефакта:
- Правило предотвращения CodeGuard, файл .mdc в стиле Markdown, записываемое в каталог правил IDE целевого проекта. Это останавливает ассистента от повторного написания уязвимости.
- Правило обнаружения Foundry в формате YAML, добавляемое в собственный корпус тестового окружения. Это позволяет находить существующие экземпляры при каждом последующем запуске.
Для этой статьи я заполнил его на практике для обоих пробелов:
Каждый вызов занял около 90 секунд и примерно 28 000 токенов. Для контекста, сканирование Langflow, обнаружившее первый пробел, обошлось примерно в два миллиона. Самым дорогим было найти урок. Записать его так, чтобы вам больше никогда за него не платить, стоит около 1,4% от этой суммы.
Конкретно для правила CodeGuard вот фрагмент того, что получилось для пробела в Langflow. Сначала правило называет точный антипаттерн, по сути, очищенную версию кода, найденного Foundry:
Затем оно предлагает ассистенту безопасные шаблоны на замену: явный белый список доверенных прокси и, что самое главное для этой ошибки, проверки локальности на основе сокетов на уровнеピア (peer), а не заголовков:
В завершение приводится контрольный список, включающий регрессионный тест, который отправляет поддельный заголовок «X-Forwarded-For: 127.0.0.1» и проверяет получение ответа 403. Это именно тот тест, который позволил бы обнаружить оригинальную ошибку.
Парное правило обнаружения для детектора Foundry:
Пробел в MLflow породил ту же пару для CWE-129: корпус Foundry вырос с 13 правил до 15, причем мне не пришлось писать вручную ни одно из них.
Все четыре сгенерированных файла находятся в репозитории, так что вы можете оценить качество самостоятельно: два правила CodeGuard в examples/synthesized/ и два правила обнаружения в rules/. Это ровно то, что написала модель.
Импорт: предотвращение — это и есть файл
Это самая крутая часть… потому что делать практически ничего не нужно.
По умолчанию команда synthesize записывает правило CodeGuard в собственный каталог .cursor/rules/ целевого проекта. Закоммитьте этот файл, и у следующего разработчика, открывающего проект в Cursor, правило загрузится автоматически. В следующий раз, когда кто-либо (человек или агент) попросит ассистента написать эндпоинт «только для localhost» в этом репозитории, ассистенту уже будет объяснено, почему заголовок обманчив и что делать вместо этого. Никаких пайплайнов, никаких деплоев, никаких тикетов. Предотвращение — это и есть файл.
Это предложение и есть суть всего данного поста.
Масштабирование за пределы одного репозитория и одной IDE следует собственной модели распространения CodeGuard:
- Выберите место назначения. Флаг --output-dir позволяет записывать правила куда угодно, например в общий внутренний репозиторий «правил безопасности» вместо целевого проекта.
- Охватите каждого ассистента, а не только Cursor. CodeGuard поддерживает свои правила в едином исходном формате с валидатором и конвертерами, которые создают форматы для Cursor, Copilot, Windsurf, Codex, Devin и других. Добавьте синтезированное правило в исходные коды внутреннего форка, запустите валидатор и конвертер, и этот же урок попадет к каждому ассистенту, используемому вашими разработчиками.
- Обслуживайте централизованно. MCP-сервер CodeGuard предоставляет правила в виде инструментов по протоколу HTTP, поэтому команда платформы может один раз передать только что изученное правило, и все подключенные ассистенты подхватят его.
Это утверждение с накоплением эффекта, и именно по этой причине примерно 10-кратная стоимость токенов из Части 2 является оправданной: за обнаружение плата вносится один раз, а предотвращение работает везде и бесконечно. Каждый урок, который усваивает Foundry, сокращает количество багов, которые следующее оценивание должно обнаружить.
Чего я не утверждаю
Синтезированные правила нуждаются в проверке человеком. И это далеко не формальность. Сгенерированное мной правило для CWE-346 представляет собой действительно хорошие рекомендации, но в первоначальном виде его абзац «это не теоретическая проблема» ссылался на CVE-2023-45857 в качестве примера этого паттерна. На самом деле этот CVE связан с утечкой токена в axios, а не с подделкой прокси-заголовков. Рекомендация была верной, но модель выдумала одно подтверждающее цитирование. Я поймал это при проверке и заменил его единственным примером, за который могу поручиться — находкой в самом Langflow, — прежде чем закоммитить правило. Заметьте иронию: Часть 2 была полностью посвящена тому, что нельзя слепо доверять цитатам модели без их проверки. Поэтому синтез правил заслуживает такой же дисциплины. Относитесь к каждому сгенерированному правилу как к пулл-реквесту, а не как к деплою.
Ничто в этом посте не доказывает, что правила работают. Я показал, что изученное правило попадает в IDE. Но я не показал, как часто оно меняет написание уязвимого паттерна ассистентом. Для этого требуется контролируемый эксперимент, которому будет посвящен отдельный пост: на следующей неделе.
Не каждый пробел устраняется автоматически. Синтезатор считывает собственный журнал пробелов в правилах Foundry. Пробел CWE-348 из сравнения по базовой линии хранится в отчете оценщика, и его перенос в правило на данный момент является ручным шагом.
Далее: докажем это
Вот вопрос, который хороший архитектор безопасности должен задать в этот момент и который я постоянно задавал себе: действительно ли правило меняет то, что пишет ассистент?
Не «находится ли файл в правильной папке». Не «хорошо ли читаются рекомендации». Пишет ли ИИ-помощник по кодингу при обычном запросе на добавление функционала уязвимый паттерн реже, когда правило есть, и чаще, когда его нет?
Все в Части 2 было посвящено отказу принимать утверждения модели на веру без доказательств. Было бы странно принимать на веру мое собственное утверждение о предотвращении, верно? Поэтому на следующей неделе мы проведем эксперимент: те же запросы на функции, реальный ИИ-ассистент по кодингу, рабочие пространства, которые идентичны во всем, кроме правил, и слепой судья, с которым вы уже знакомы. Кузня из Части 2 оценивает защитника из этого поста.
Все здесь воспроизводимо из : журналы пробелов в правилах из реальных запусков, команда synthesize, сгенерированные правила CodeGuard в examples/synthesized/, правила обнаружения в rules/, а также файл docs/CODEGUARD.md с полным описанием интеграции. Сам проект CodeGuard находится по адресу .











