11 уязвимостей, 1 реальная: как AI-агент разобрал SAST-отчёт за меня

Тебе прилетает 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. Без агента я бы потратил часы на ручной разбор каждого срабатывания. С агентом - получил результат и понимание, почему каждый пункт отчёта оказался тем, чем оказался.