ESPN DeportesMonchi se disculpa por pedir Balón de Oro para LamineESPNHarbaugh offers rare critique of struggling QB Herbert: 'Be better'The Jerusalem PostWATCH: 'Don't mess with us': Netanyahu warns enemies may attack Israel ahead of electionBollywood HungamaJubin Nautiyal welcomes first child with wife after intimate wedding, shares update: “Mom and baby are back home”Daily MaverickTHE CONVERSATION: New world map makes Africa look bigger – What’s the fuss about? Cartographers explainRTP DesportoBrasil vence Austrália com Circati a marcar e Irankunda a cometer penáltiInquirerMost wanted person in Ilocos Sur town fallsBusiness AMRusland wil dit jaar nieuwe ballistische raket in dienst nemen met een bereik van 800 kmThe RegisterApple patches CoreGraphics zero-day already exploited in targeted attacksThe Hollywood ReporterHow a Microdramas Director Landed Her First Feature Film GigDeadlineLauren Cohan & Jake Epstein To Co-Star In Eric Stoltz Directed Rom-Com ‘Both Sides Now’The South AfricanPowerBall Xtra: R21 million up for grabs – plus guaranteed winner twist
The Daily Newsstand · Free, Always
Tuesday, September 29, 2026

Агент не справляется с аудитом кода? Просто добавь графы

Translate

Привет, Хабр! Меня зовут Радда Юрьева, я ведущий специалист отдела исследований безопасности приложений в Positive Technologies. В мае этого года на встрече OWASP Russia мы с моим руководителем Владимиром Кочетковым рассказали о графовых подходах к анализу кода с участием ИИ-агентов.

К осени 2026 года индустрия окончательно осознала: одних ИИ-агентов на языковых моделях недостаточно для проверки безопасности кода. В этой статье мы хотим поделиться расширенным пересказом нашего доклада. Вы узнаете, как графы могут помочь закрыть большинство проблем современных LLM, какую роль в этой связке играет языковая модель, а какую — формальные методы.

Хотите понять, как графы и языковые модели дополняют друг друга в реальном аудите безопасности? Заглядывайте под кат!

Если вам когда-нибудь казалось, что точность анализа кода упирается в размер модели, удачно сформулированный вопрос или объем контекстного окна, готовьтесь расстроиться. Каждое из этих предположений звучит разумно, но ни одно не выдерживает проверки.

Первое: надо лишь удачно сформулировать промпт. Промпт-инжениринг полезен, но он никак не поможет решить основную проблему анализа кода: как ни выкручивай вопрос, полная трасса выполнения — из реального, а не синтетического приложения — в ответе едва ли появится. И даже самый виртуозный промпт не позволит получить доказательство полноты анализа — гарантию, что были исследованы все достижимые пути в приложении.

Второе: нужна модель побольше. Больше параметров — умнее рассуждения, тут спорить не о чем. Но потолок от этого никуда не девается: масштаб не выращивает структурное знание, и то, что значение из одной функции утекает в буфер другой через десяток файлов, только от большего числа параметров модель не узнает. Размер лишь немного отодвигает границу, но не убирает ее.

Третье (самое соблазнительное): зальем в контекст весь проект. Окна разрослись до миллионов токенов — бери и загружай репозиторий целиком. Но даже если бюджет выдержит, объем играет против точности: модель тонет в шуме и теряет нить между началом и концом файла.

Все эти способы дорогие в реализации и ненадежные. Гораздо эффективнее дать модели правильную карту — о ней и расскажем дальше.

Почему ИИ проигрывает на больших репозиториях

Представьте репозиторий на сотни тысяч, а то и миллионы строк кода с кучей микросервисов и функций. У сырой языковой модели есть несколько фундаментальных проблем:

  • Огромный контекст: репозиторий просто не помещается в контекстное окно, поэтому модель видит лишь фрагмент за раз и теряет общую картину.

  • Длинные цепочки: уязвимый путь может проходить через десятки файлов, сотни функций, очереди сообщений, промежуточное ПО и ORM — на каком-то этапе модель теряет связь между источником данных и точкой их использования.

  • Неявные зависимости: рефлексия, внедрение зависимостей, динамические импорты и самописные слои абстракции остаются для языковой модели невидимыми — без формального анализа обнаружить эти связи невозможно.

  • Галлюцинации связей: модель начинает додумывать вызовы, которых нет в коде и даже в ее контекстном окне, или пропускать реальные — с таким подходом невозможно гарантировать, что найдены все пути и что среди них нет выдуманных.

  • Перерасход токенов: модель тратит ресурсы на бесконечные вопросы (например, какую функцию кто вызывает) вместо того, чтобы заниматься реальным анализом. Например, библиотека GGML содержит 832 файла (C, C++, заголовков), 416 474 строки и 18,79 млн символов исходников (весь рабочий каталог — 2262 файла, 24,59 млн символов). Чтобы модель просто прочитала ее целиком, понадобится несколько миллионов токенов. И это для среднего по объему проекта. Агент с доступом к графу (MCP-сервер codebadger) вместо линейного чтения ориентировался по семантике: нашел 54 точки выделения памяти, от них — больше 300 опасных операций и проследил уже только их.

В августе были опубликованы результаты сравнительного теста VulnGym от команды Tencent, Китайского университета Гонконга и еще нескольких вузов. Исследователи впервые проверили работу ИИ-агентов в честной постановке: требовалось самостоятельно отыскать уязвимости в реальном репозитории — просто ответить на вопрос о заранее известных уязвимостях было недостаточно.

Внутри — 184 уведомления об угрозах безопасности в 23 проектах, разметка выверена людьми построчно, а сами уязвимости появились в период с ноября 2025-го по апрель 2026 года, после даты отсечки знаний моделей: утечка в обучающие данные была исключена. В тестировании участвовали девять агентских конфигураций: три передовые открытые модели (DeepSeek-V4-Flash, GLM-5.2, MiniMax-M3) в трех обвязках (Claude Code, OpenHands, MiniSWE). Моделям дали большой объем контекстной памяти (от 256 000 токенов), но ограничили в инструментах: агенты получили только оболочку с правами чтения (cat, grep, rg). Рядом для проверки масштабирования прогнали серию моделей Qwen3.5 (от 2 до 27 млрд параметров) под управлением Claude Code. Получился чистый эксперимент: ориентирование вслепую против навигации по графу.

Итог: в трудных случаях, где цепочка от источника до стока насчитывает девять и более шагов, лучший агент смог обнаружить только 22,58% уязвимостей, а модели на 2–4 млрд параметров сдались на полпути и выдали нулевой результат. Разбор фейлов показал, что в 56,5% случаев агент вообще не находит нужный файл (26,8%) или находит файл, но не строку (29,7%). И дело не сводится к C или C++: в наборе есть, например, хранимая XSS в Open WebUI — с цепочкой через несколько компонентов от обработчика эндпойнта до innerHTML в представлении.

Про метрики точности и полноты
  • Полнота (recall) отвечает на вопрос, сколько реальных уязвимостей обнаружила система. Классический статический анализ (SAST) старается обеспечить высокую полноту, чтобы не пропустить проблему, но за это приходится платить огромным количеством шума в виде ложноположительных срабатываний.

  • Точность (precision) — доля настоящих проблем среди найденных. Низкая точность заставляет аналитиков страдать в ходе триажа срабатываний.

Языковая модель иногда показывает более высокую точность, так как умеет семантически интерпретировать код. Но при этом полнота резко падает — модель пропускает часть уязвимостей. Даже обычную проверку кода приходится проводить 5–7 раз, чтобы собрать все замечания по изменениям. Гибридный подход дает правильный баланс: граф поддерживает полноту поиска, а языковая модель отсеивает шум и повышает точность.

Эффективность такого подхода доказана цифрами. Авторы работы LLMxCPG (представленной на конференции USENIX Security 2025) построили именно такой конвейер: граф выделяет «кандидатов в уязвимости», а дообученная языковая модель классифицирует их. В результате они получили +15–40% к F1 и +9–27% к доле верных ответов по сравнению с передовыми базовыми решениями (VulSim, ReGVD, VulBERTA), а на наборе данных SVEN преимущество по доле верных ответов составило примерно 20%. Баланс точности и полноты там сделан настоящей ручкой — порог классификатора γ калибруется буквально по ~20 размеченным примерам из целевого домена (в экспериментах значения разнились от 0,193 до 0,594). Правда, реальные показатели скромнее рекламных заголовков: 0,634 на проектном ReposVul и 0,6 на свежих уязвимостях, опубликованных уже после того, как модель закончила обучение. Это заметный шаг вперед, но говорить о том, что проблема решена, пока рано.

Постепенно стало ясно, что языковая модель хороша как слой интерпретации, но тянуть весь анализ программы в одиночку ей не по силам.

Три графа, которые все меняют

Объединение синтаксической структуры, потока управления и зависимостей данных в единый граф кода (CPG)

Объединение синтаксической структуры, потока управления и зависимостей данных в единый граф кода (CPG)

Граф — это набор узлов (фрагментов кода) и связей между ними. В таком виде формально описываются и структура программы, и семантика, и все ее зависимости. В анализе кода обычно используют три базовых типа графов:

  1. AST — абстрактное синтаксическое дерево. Представляет код в виде иерархической структуры из объявлений, инструкций и выражений. Отвечает на вопрос, из каких частей состоит программа, но не показывает порядок выполнения.

  2. CFG — граф управления потоком. Ориентированный граф, описывающий все возможные пути выполнения программы. Показывает, куда программа пойдет после этого блока.

  3. DFG — граф потока данных. Отслеживает, откуда переменная берет значение и на что влияет.

PDG — граф зависимостей программы — объединяет управляющие (CFG) и информационные (DFG) зависимости. Он особенно полезен для taint-анализа и построения срезов.

Срез программы — это выделение только релевантной части программы, которая влияет на конкретную переменную, сток (выполнение запроса) или точку выполнения. Например, при анализе SQL-инъекции нам не нужен весь репозиторий. Мы можем взять сток и построить обратный срез — проследить назад, откуда пришли данные, какие функции влияли на значение и какие фильтры стояли на пути.

Построение срезов резко уменьшает объем кода для анализа. Вместо миллионов строк мы получаем небольшой релевантный подграф, зачастую вполне умещающийся в контекстное окно целиком. Модель перестает тонуть в шуме и работает только с тем кодом, который относится к потенциальной уязвимости. По сути, это можно рассматривать как своеобразное сжатие контекста еще до попадания данных в контекстное окно.

Сколько именно сжимается? В уже упомянутой работе LLMxCPG обратный срез по PDG сокращал код на 68–70% на функциональных наборах данных (PrimeVul, SVEN) и на 90,93% на проектном ReposVul. Наглядный пример из статьи: функция на 85 строк сжимается до 18 строк, полностью сохраняя контекст уязвимости. Показательна и обратная проверка: когда тот же классификатор кормили полным кодом, без предварительного построения срезов, доля верных ответов падала с 0,7250 (72%) до 0,4875 (48%) на PrimeVul и с 0,6020 (60%) до 0,5078 (50%) на SVEN. Срезы настолько компактны, что классифицирующая модель в этой работе уверенно работала даже с контекстом в 8000 токенов.

А что именно загружать в нейросеть — код, граф или все вместе? В июньском исследовании RepBench прогнали десять вариантов представления (сырой код, AST, CFG, PDG и комбинации) через одну задачу разметки уязвимостей, с фиксированным протоколом рассуждений. Выиграла комбинация AST и PDG: 83,2% верных ответов против 53,5% у сырого кода. Но самое интересное в другом. Выяснилось, что когда модели давали только граф, она справлялась лучше, чем когда получала только код или комбинацию кода и графа. Подмешивание исходника к компактному графу только вредит — авторы назвали это эффектом разбавления контекста. Практический вывод: загружайте в модель подграф и не подмешивайте исходник. Только учтите масштаб эксперимента: в нем участвовали 107 тестовых примеров, все на языках C и C++. Есть тренд на то, как графами анализировать код, но нет единой работающей методологии. Короче говоря, тренд — есть, а заповеди — нет.

Композиция: CPG (граф свойств кода)

Эти представления полезны и по отдельности, но вместе они дают гораздо больше. Их наложение на общее множество узлов называется CPG (code property graph). Слово property (свойство) здесь означает, что каждый узел хранит свойства (тип узла, строку кода, имя переменной), а graph (граф) — что узлы связаны типизированными ребрами (синтаксис, управление, данные).

CPG позволяет пройти весь путь — от источника до стока — в обе стороны без пробелов и необходимости гадать вслепую.

Что дает связка графа и языковой модели

Схема поиска уязвимостей в исходном коде на основе графового анализа и LLM

Схема поиска уязвимостей в исходном коде на основе графового анализа и LLM

Языковая модель читает данные из графа и вдобавок усиливает его.

Без графа (только языковая модель):

  • Галлюцинации связей.

  • Нет формальной гарантии полноты.

  • Переполнение контекстного окна.

  • Перерасход токенов на восстановление структуры программы.

С графом (языковая модель + PDG/CPG):

  • Точность: каждый путь формально доказан и проверяем.

  • Полнота: гарантированный обход всех путей в графе.

  • Экономия токенов: граф уже знает все связи — модель освобождена от навигации и занимается только семантикой.

  • Экономия контекста: модели передается только релевантный подграф (путь доказательства) вместо всего кода.

  • Масштабируемость: графовые базы данных (Neo4j, TigerGraph) масштабируются до миллионов узлов — CPG реальных проектов как раз такого порядка.

  • Устойчивость к обфускации: срез строится по семантическим зависимостям, поэтому переименования переменных, функций и даже переформатирование кода его не меняют. Детекторы на основе машинного обучения, работающие с сырым кодом, от таких семантически сохраняющих трансформаций заметно проседают (это показали Risse и Böhme на конференции USENIX Security 2024), а CPG-подход LLMxCPG сохранил эффективность. Чувствительнее всего он оказался лишь к выносу кода в отдельные функции, меняющему границы среза.

Летом в этой теме появилась новая глава: против детекторов на языковых моделях стали воевать с помощью обычного текста. В июльской работе ALIBI агент-вредитель вставлял уязвимость в код и добавлял комментарии, представляющие небезопасные изменения как обоснованные. сбивающими детектор с толку, а кроме того адаптировал атаку, основываясь на обратной связи от самого детектора уязвимостей. Скрыться от обнаружения получилось более чем в 90% случаев на 125 реальных уязвимостях класса разыменования нулевого указателя, с одной из систем это удалось сделать на все 100%. Защита на уровне промптов почти не спасает. Реально помогают только очистка комментариев перед проверкой и архитектурная изоляция.

Вторая работа Words Speak Louder Than Code показала, что вердикты моделей могут меняться от формулировки задачи (33,2%), от подброшенного «предварительного анализа» (23,5%) и даже от репутации автора кода (18,4%). В худших сценариях такие манипуляции приводили к тому, что ИИ пропускал до 97% реальных угроз. Связь с нашей темой прямая: срез, построенный по CPG, не содержит комментариев, а значит, они физически не доезжают до классификатора. Конвейер вроде LLMxCPG — это и есть архитектурная изоляция, которую ALIBI рекомендует в качестве защиты. Прямых экспериментов «враждебные комментарии против построения срезов» пока никто не ставил, но они напрашиваются сами собой.

Граф устойчив к галлюцинациям, потому что связи в нем формально доказаны. Языковая модель надстраивается поверх этого каркаса и опирается на него.

Кстати, это же ответ на популярный вопрос «А почему не RAG?». Векторные представления отлично ловят синтаксическое сходство, но не видят семантических отношений уровня «возвращаемое значение функции A утекает в запись в буфер функции B» или «переменная проверена в одной ветке, а используется без проверки в другой». Для поиска уязвимостей нужны как раз такие межпроцедурные потоки — и кодировать их умеет граф, векторному представлению фрагмента это недоступно.

Насколько далеко можно увести разделение функциональности? Работа LeanGuard довела его до логического конца: языковая модель там — только семантический фильтр фактов из AST, а вердикт выносит ядро доказательного ассистента Lean 4. Авторы исследования сформулировали вывод, который хочется цитировать: доверять модели снятие обязательств безопасности преждевременно, интерпретатор не должен быть судьей.

Августовский проект CLEAR показывает, что граф в этой связке не обязан быть графом кода: авторы построили причинно-следственный граф знаний об уязвимостях (точки входа → предусловия → корневые причины → намерения исправлений) и гоняют по нему четверку агентов: Сборщика, Утверждающего, Критика и Судью. Приросты выглядят внушительно: +130,7% к парной корректности для кода на C, C++ и +71.56% для Java. Но это числа относительно базовых решений, названия которых в аннотации не указаны. Так что аплодируем, но сдержанно.

Поток данных от источника до потенциально опасного вызова и преимущества его графового представления для LLM

Поток данных от источника до потенциально опасного вызова и преимущества его графового представления для LLM

Что именно добавляет языковая модель к графу?

  1. Объяснение: граф находит путь, языковая модель читает код в узлах и объясняет, почему это уязвимость.

  2. Разбор находок: модель оценивает уровень опасности и отсеивает ложные срабатывания. Формально путь может существовать, но семантически быть безопасным.

  3. Запросы: здесь чуть интереснее, чем «умеет — не умеет». Наивное «опишу уязвимость словами, а модель напишет запрос на Cypher или Gremlin» не работает. Графовые языки запросов низкоресурсны, их мало в обучающих корпусах, поэтому базовые модели вроде DeepSeek-v3 и Qwen2.5-Coder без подготовки генерируют нерабочий CPGQL — путают .code с .name, неверно трактуют семантику регулярных выражений в фильтрах. Но есть два рабочих подхода. Первый — дообучить генератор запросов: в LLMxCPG тренировочные CPGQL-запросы генерировал DeepSeek-v3, Joern их проверял, сообщения об ошибках возвращались модели для исправления — на этом цикле была дообучена Qwen2.5-Coder, стабильно пишущая корректные запросы. Второй — абстракция: MCP-сервер codebadger вообще прячет CPGQL за высокоуровневыми инструментами (отслеживание заражения, построение срезов, граф вызовов). Показательно и то, что готовые статические наборы запросов вроде Joern-scan в проверке LLMxCPG не нашли ни одной уязвимой функции в выборке из 50 образцов, потому что разработчики часто оборачивают опасные функции собственными обертками, под которые не заточены фиксированные правила. Запросы должна генерировать система, видящая контекст. И ещё есть режим предварительного синтеза. Свежая работа об автоматической генерации запросов предлагает вообще не генерировать запросы на лету: языковая модель читает описания уязвимостей из NVD и компилирует из них постоянный набор запросов CodeQL. Синтезированный набор дает +82% среднего F1 к базовым наборам, а экономика сходится изящно: сканировать репозитории самой моделью непозволительно дорого, синтезировать запросы для статического движка — дешево. Это та же упомянутая ранее схема «языковая модель как слой интерпретации, движок как механизм поиска», только материалом для интерпретации служат чужие отчеты об уязвимостях.

  4. Межъязыковой контекст: модель понимает, как данные перетекают между Python и C++, Java и SQL. Граф показывает границу, модель — семантику перехода.

  5. Демонстрация и исправления: на основе найденного пути модель генерирует демонстрационный эксплойт и предлагает исправление.

Конвейер изнутри: от кода до отчета

Архитектура современных систем с участием ИИ выглядит как четкий конвейер:

  1. Исходный код (Java, C++, Python и т. д.) попадает в парсер (Tree-sitter, Joern). Он строит AST, затем формируются CFG и DFG, которые объединяются в CPG — один граф с типизированными ребрами.

  2. Графовая БД индексирует миллионы узлов и поддерживает сложные запросы на поиск путей.

  3. Поиск и GNN: система ищет подозрительные подграфы (пути от источника к стоку, отсутствие фильтров) с помощью формальных языков запросов или графовых нейросетей.

  4. Языковая модель получает только релевантный подграф (путь доказательства). Вместо перебора всего кода модель анализирует конкретный маршрут: разбирает находки, объясняет, почему путь ведет к уязвимости, и оценивает уровень ее опасности.

  5. Отчет содержит полный путь доказательства (все узлы — от источника до стока), объяснение уязвимости с семантикой кода, демонстрационный эксплойт и предложение исправления. Все это опирается на формальные данные, без догадок модели.

Усиление через GNN и цикл ReAct с аннотациями

Схема аннотирования графа кода с помощью LLM и использования аннотаций в ReAct-цикле

Схема аннотирования графа кода с помощью LLM и использования аннотаций в ReAct-цикле

Для поиска типовых шаблонов уязвимостей в огромных репозиториях активно используются графовые нейросети (GNN), например: Devign или ReVeal. GNN классифицирует подозрительные подграфы на основе обучения представлениям, ища фрагменты, похожие на известные уязвимости.

Однако у GNN есть ограничения:

  • Мало качественно размеченных наборов данных — и это самый настоящий системный кризис. Анализ PrimeVul показал, что в популярных наборах данных лишь 38–64% функций с меткой vulnerable действительно уязвимы, а точность передовых детекторов на строго верифицированных данных проседает до 45% относительно заявленной. Иными словами, модели выучивают шаблоны шумной разметки вместо признаков уязвимостей. Элегантный обход продемонстрирован в FormAI-v2: 331 000 сгенерированных языковой моделью программ на C разметил формальный верификатор ESBMC. Метки он ставит по построению, и точность их выше, чем у ручной разметки.

  • Плохая переносимость между языками (модель, обученная на C, почти бесполезна для Java).

  • Проблема объяснимости — GNN находит узел, но не объясняет, почему он опасен.

Кризис наборов данных для тестов постепенно решается. В сентябре разработчики открыли доступ к новой базе LLMVul, которая содержит 21 430 функций на C и C++, собранных из 226 промышленных репозиториев за четыре года разработки с участием ИИ, 1540 из них содержат уязвимости 17 разных классов CWE, согласованность разметки κ = 0,79, данные лежат на платформе Zenodo. Вывод не слишком радостный: теперь проверять на безопасность нужно не только код, написанный людьми, но и тот, что был сгенерирован нейросетями и уже живет в проде, — его уязвимости сами себя не найдут.

Поэтому GNN и языковая модель работают в тандеме: GNN находит подозрительные подграфы, улучшая полноту, а языковая модель интерпретирует находки, проводит разбор и генерирует отчет.

Цикл ReAct с аннотациями

Теперь про ReAct (рассуждение и действие) и предварительную аннотацию графа. До начала основного анализа языковая модель проходит по всем узлам CPG и создает краткие описания семантики каждого фрагмента. Например, для функции handle_request() модель может записать: «HTTP request handler, parses JSON body, writes to SQL query without parameterization. No input validation detected».

Аннотации превращают огромный CPG в удобную карту с пояснениями. В процессе цикла ReAct (где модель чередует рассуждения и запросы к графу) она сразу знает, какие узлы являются критически важными, куда направлять запросы и какие фрагменты проверять в первую очередь. Это дает быструю навигацию, более точный разбор находок и минимальный расход токенов.

Экономику всего этого недавно улучшила DREA. Авторы развели роли: тяжелая модель планирует и выдвигает гипотезы, а дешевая локальная модель тянет контекст из репозитория. Парная корректность выросла с 19–26% до 30–42%, при этом 93% токенов съедает локальная модель, а счет за API снижается в 16–48 раз. Так что аргумент «граф + языковая модель — это дорого» больше не работает: грамотно разделенная связка оказалась дешевле монолита.

Ироничный контрпример: авторы LLMxCPG попробовали дообучить свой классификатор на цепочках рассуждений DeepSeek-v3 — и точность не выросла. По их оценке, для настоящего переноса навыков рассуждения нужно порядка 800 тысяч примеров дистилляции (как при переносе из DeepSeek-R1 в Qwen). И DREA добавляет свой штрих: 26–55% верных вердиктов их агентов шли с ложным обоснованием — правильный ответ еще не означает правильное рассуждение. Мораль совпадает с главной мыслью этой статьи: важнее, что модель видит на входе (срез, аннотации, карту графа), чем то, насколько изощренно она рассуждает вслепую.

И еще один удар по вере в промпт-инжениринг. Авторы Routing Ceilings показали, что «структурные априорные промпты» (шпаргалки вида «ищи вот такие признаки уязвимого кода») поднимают полноту на синтетике с 20% до 100%, но стоит перейти на реальные CVE из VUDENC (CWE-89) — и F1, еще недавно достигавший 100%, падает до 48,9%. Итеративная перекалибровка шпаргалок делает только хуже. Вывод авторов: нужно обучение с учетом распределения, а дописывание промпта делу не поможет. Знакомая картина, когда модель цепляется к поверхностным шаблонам там, где нужен разбор потока данных.

Бонус: от слов к делу

То, как граф и языковая модель работаю в связке, хорошо видно на примере двух недавних работ одной исследовательской группы: LLMxCPG и codebadger. Обе экспериментировали с безопасностью памяти в коде на C и C++, но с точки зрения механики там нет ничего специфичного: те же пути от источника к стоку, тот же обратный срез по PDG, тот же обход CPG. На веб-стеке меняются только словари источников и стоков — SQL-запрос вместо записи в буфер, а графовая часть остается прежней.

codebadger — это открытый MCP-сервер поверх Joern. Вместо того чтобы заставлять языковую модель писать запросы на CPGQL, он дает ей высокоуровневые инструменты: найти источники и стоки заражения, построить срез программы, получить зависимости переменной, проверить наличие проверок границ, обойти граф вызовов.

Для исправления уязвимостей, тоже есть системная оценка. Команда Team Atlanta из Georgia Tech, построившая систему киберзащиты для DARPA AIxCC, прогнала десять конфигураций агентов (четыре фреймворка, пять передовых моделей) на 63 уязвимостях из финала соревнования и вручную проверила все 630 исправлений. Прогресс за год ощутимый: ~52% корректных исправлений в 2025-м (Claude 3.7 Sonnet) против ~71% у лучших конфигураций в 2026-м. Но даже у лучших примерно каждое пятое исправление семантически ложно: оно компилируется, проходит тесты и воспроизведение сбоя, но при этом чинит лишь симптом, ломает функциональность или доверяет атакуемому API. Вывод: выбор модели важнее выбора агентского фреймворка, а ансамбль из трех кандидатов с отбором почти всегда превосходит одиночного агента (код открыт в OSS-CRS).

Инструменты и прокачка кодинг-агента

Прокачать агент, ничего не знающий о формальных методах, тоже вполне возможно. Зрелых решений несколько:

  • Joern для работы с CPG на Java, C, C++, Python, JS.

  • Semgrep и CodeQL, работающие на уровне AST и потоков данных для шаблонного поиска.

  • Агентные ИИ-инструменты с поддержкой MCP: code-review-graph (для проверки кода), CodeGraphContext (для навигации по коду), codebase-memory-mcp (для долговременной памяти агента), codebadger (аудит безопасности поверх Joern: анализ заражения, построение срезов, граф вызовов). Если решите создать собственное решение, стоит ориентироваться на архитектуру codebadger: изоляция сеансов в Docker с образом Joern, состояние сеансов в Redis, кэширование CPG по хешу исходников и языку, чтобы не запускать пересборку графа после каждого  изменения в коде.

За последнее время зоопарк код-графовых MCP-серверов тоже разросся. Свежий обзор wal.sh разбирает дюжину инструментов: у Semgrep — встроенный MCP и облачная версия mcp.semgrep.ai, у ast-grep — официальный MCP, у Joern — целый набор сторонних оберток.

Как прокачать

  1. Подключаем MCP: используйте Joern или Semgrep для тщательного поиска уязвимостей, code-review-graph — для периодических ревью, CodeGraphContext или codebase-memory-mcp — для регулярной разработки.

  2. Добавляем скиллы: отличные примеры — скиллы от Trail of Bits (для поиска уязвимостей) и Semgrep (для проверки кода). В промптах или рулах обязательно связывайте скиллы с MCP-серверами и добавляйте ссылки на модели угроз.

  3. SECURITY.md: создайте (и регулярно актуализируйте) с помощью security-policy-generator, где будут отражены требования к безопасности, модель угроз, базовые критерии проверки и правила безопасного кодинга, подстроенные под специфику вашего проекта и его стек.

  4. Спецификации: разработка по спецификациям с VibeSpec, OpenSpec или Github Spec-Kit значительно снижает риск архитектурных уязвимостей и уязвимостей бизнес-логики.

Напоследок

Недавно вышел структурный обзор языковых моделей на стыке программной инженерии и безопасности (arXiv:2608.21107), и его ключевая формулировка описывает как раз то, к чему шла эта статья: результаты работы модели следует оценивать как доказательное обоснование с подтверждениями, лишний балл сравнительного теста здесь вообще ни о чем не говорит.

Получается, графы снова в главной роли: они дают формальную структуру, а языковая модель дает смысл. Будущее безопасности приложений определенно за этой связкой (ну... с нынешними трасформерами и их нынешнем вниманием).

Спасибо за внимание!

Радда Юрьева TG: @raddayurieva, Владимир Кочетков @v0lka TG: @vkochetkov, @art_code_ai (авторский канал).

View the original on Хабр →

KioskNews shows a cleaned-up reading view extracted from the publisher’s page — the original always lives on their site, not ours.