Тебе прилетает SAST-отчёт: 11 High-уязвимостей, красные плашки, ощущение надвигающейся катастрофы. А потом оказывается, что 10 из 11 - false positive, и единственную реальную можно пофиксить за пять минут.
Пришёл отчёт - и стало грустно
Обычный рабочий день. На portal-frontend запустили очередной SAST-скан, прилетел HTML-отчёт. 11 уязвимостей уровня High. XSS, инъекции - полный набор.
Первая реакция - паника. Вторая - уныние. Третья - открыть отчёт, посмотреть на сотни строк описаний и закрыть обратно. Знакомая последовательность, если ты хоть раз работал с результатами статического анализа.
Проблема SAST-сканеров известна индустрии. Semgrep в standalone-режиме показывает precision около 35% - это значит, что почти две трети найденного будут ложными срабатываниями. Ты тратишь часы на разбор, чтобы в итоге отфильтровать мусор. А можно ли иначе?
Скармливаем отчёт AI-агенту
Я взял HTML-отчёт и скормил его Claude Code. Без особых инструкций - просто “вот отчёт, разбери”.
Агент распарсил HTML, вытащил CWE-категории, dataflow paths, конкретные строки кода. А дальше сделал то, чего я не ожидал: сам запустил субагентов. По одному на каждую CWE-категорию.
Это не просто красивая архитектура. GitHub Security Lab пришли к похожему выводу в своём Taskflow Agent - разбивать triage на мелкие независимые задачи. Каждый субагент получает свежий контекст, не перегруженный информацией о других уязвимостях. Одна задача - один фокус.
Вся сессия заняла 41 промпт. Это не история про “одну волшебную команду”. Это диалог. Агент задавал уточняющие вопросы, я направлял - какие файлы смотреть, как устроен деплой, какие зависимости используются. Местами я не соглашался с его выводами и просил перепроверить. Нормальный рабочий процесс, просто быстрее ручного разбора.
False positive: почему сканер врёт
Возьмём типичный кейс из отчёта - XSS, CWE-79. Сканер видит untrusted input, который попадает в потенциально опасный sink. Красная плашка, High severity. Всё выглядит страшно.
Только вот sanitization происходит в другом файле. Сканер не отслеживает dataflow между файлами и не знает, что данные проходят через кастомную функцию очистки перед рендером. Агент читает весь проект, видит всю цепочку и говорит: это false positive.
Ещё один частый паттерн - кастомные функции санитизации. Regex-обработка, обёртки над стандартными библиотеками. SAST-сканер видит незнакомую функцию и на всякий случай помечает путь как опасный. Перестраховка, которая генерирует шум.
Индустрия это подтверждает. Гибридный подход - Semgrep плюс fine-tuned Llama 3 8B - снижает false positive rate на 91% по сравнению с чистым SAST. Не потому что LLM умнее сканера. Потому что LLM умеет читать контекст, а сканер работает по правилам.
Одна реальная уязвимость - и что с ней делать
10 из 11 - ложные срабатывания. Осталась одна. И здесь начинается самое интересное.
Агент не просто пометил её как “реальная”. Он объяснил attack vector: откуда приходят данные, через какие функции проходят, где именно происходит эксплуатация. Потом предложил конкретный патч.
Процесс выглядел так: агент показывает уязвимый фрагмент кода, рядом - объяснение, почему это проблема. Затем генерирует fix и проверяет, что изменения не ломают существующие тесты. Полный цикл: найти, классифицировать, объяснить, исправить, проверить.
Вручную этот процесс занял бы у меня существенно больше времени. Не потому что я не умею читать код - а потому что нужно держать в голове CWE-спецификацию, dataflow path, контекст проекта и одновременно думать про fix. Агент делает это параллельно, не теряя фокус.
Anthropic недавно показали похожую историю в масштабе - Claude Code Security нашёл более 500 уязвимостей в production open-source кодебазах. Баги, которые оставались незамеченными годами, несмотря на код-ревью от опытных разработчиков. Multi-stage verification - когда модель перепроверяет собственные findings - отсекает ложные срабатывания до того, как они попадут к человеку.
Как это работает под капотом
Схема простая. Двухстадийный pipeline.
На первом этапе SAST-сканер делает то, что умеет лучше всего - прочёсывает код по правилам, находит потенциальные проблемы, строит dataflow paths. Это детерминированная работа, и сканеры справляются с ней хорошо.
На втором этапе LLM получает structured context: фрагмент кода, dataflow path, CWE-описание, окружающий код. И отвечает на конкретный вопрос - “приводит ли этот пользовательский ввод к эксплуатируемой SQL-инъекции?” Не абстрактный анализ, а ответ yes/no с reasoning.
ZeroFalse framework от Simon Fraser University формализовал этот подход - structured contracts из выхода статического анализатора плюс CWE-specific knowledge плюс LLM-арбитраж. Результат: F1-score 0.912 на OWASP Java Benchmark. GitHub Security Lab идут дальше - детерминированные проверки делегируют MCP-серверам, а LLM оставляют сложный reasoning. Каждый инструмент делает то, в чём он силён.
Попробуй сам: практические советы
Из моего опыта с этим отчётом - несколько вещей, которые помогли.
Дай контекст. Не просто “вот отчёт, разбери” - расскажи, что за проект, какой фреймворк, как деплоится. Чем больше агент знает про архитектуру, тем точнее его выводы. Я начал без контекста и потом добирал его в диалоге - лучше дать сразу.
Разбивай по CWE. Не сваливай все уязвимости в один промпт. Один тип - один запрос. Или доверь агенту сделать это самому через субагентов, как получилось у меня.
Проси объяснить reasoning. “Это false positive” - недостаточно. Пусть агент покажет, почему: где sanitization, какой dataflow, что именно делает этот код. Без объяснения ты не можешь проверить вывод.
Для реальных уязвимостей - проси не только патч, но и тест. Fix без теста - это обещание, а не гарантия.
Перепроверяй. AI может ошибиться в обе стороны. Пропустить реальную уязвимость или зафиксить то, что трогать не нужно. GPT-4 в standalone-режиме показывает precision 65% - лучше сканера, но далеко от идеала. Гибридный подход работает именно потому, что каждый слой ловит ошибки предыдущего.
Мой отчёт с 11 High-уязвимостями превратился в один конкретный fix. Без агента я бы потратил часы на ручной разбор каждого срабатывания. С агентом - получил результат и понимание, почему каждый пункт отчёта оказался тем, чем оказался.