TL;DR
CAT-RAG — это двухшаговая схема. Сначала лёгкая модель-«категоризатор» читает ваш запрос на код и выбирает из готового списка 1–3 категории безопасности («Валидация ввода и инъекции», «Файлы и пути», «Десериализация»). Затем к запросу добавляются короткие правила и один маленький пример безопасного кода только по этим категориям. Модель, которая пишет код, остаётся прежней.
Главная находка: подсказки на уровне отдельных уязвимостей (CWE) раздувают промпт. Один запрос обычно задевает сразу несколько родственных слабостей, и в контекст попадают десятки справочных абзацев. Внимание модели размывается, а код получается не лучше. Разработчик к тому же думает задачами («прочитать файл, загрузить в память, обработать»), а не номерами уязвимостей. Поэтому справка «по CWE-119» плохо ложится на запрос.
Суть метода: группировать знания по предметной области задачи и подавать ровно столько категорий, сколько нужно запросу. Простой запрос получает одну категорию, сложный — три и больше. У авторов так удалось почти вдвое улучшить прирост безопасности по сравнению с прошлым лучшим методом и сократить расход токенов примерно на 40%.
Схема метода
ПОДГОТОВКА (один раз):
список категорий на язык (~10) → у каждой: 5–6 правил + мини-пример безопасного кода с пометками CWE
(черновики правил и примеров авторы писали с помощью LLM, список категорий — эксперт)
ШАГ 1: Категоризатор читает запрос → язык + ранжированный список категорий (сколько нужно — 1, 2, 3…)
ШАГ 2: К исходному запросу дописываются правила и примеры выбранных категорий → генерация кода
(ШАГ 3, опционально): LLM сжимает выбранные правила до короткой выжимки → отдельный вызов
Шаги 1 и 2 — два отдельных запроса. Их можно делать вручную в двух сообщениях или поручить агенту.
Пример применения
Сильная зона метода: задача на генерацию функции или эндпоинта на языке из списка (C, C++, Python, Java), где в одном запросе смешано несколько рисков: файлы, ввод пользователя, сеть. Простые «посчитай сумму» не подходят: там нечего защищать.
Задача: Python-разработчик интернет-магазина на FastAPI делает эндпоинт «Загрузить реестр заказов от поставщика». Пользователь присылает ZIP с CSV, сервис распаковывает его, читает и по ссылке из файла скачивает фото товара. В одном запросе сразу три зоны риска: пути в архиве, разбор данных и исходящие запросы.
Промпт, шаг 1 (категоризатор):
Ты — категоризатор запросов по безопасности кода.
Язык: Python.
Список категорий:
1. Input Validation & Injection
2. OS Cmd Execution
3. File Ops & Path Traversal
4. Deserialization & Data Parsing
5. Authentication & Session Mgmt
6. Cryptography & RNG
7. Error Handling & Info Disclosure
8. HTTP Security & Web Apps
9. SSRF
10. Resource Mgmt & DoS
Запрос разработчика:
«Напиши эндпоинт FastAPI: пользователь загружает ZIP с CSV-реестром заказов,
сервис распаковывает архив, читает CSV и скачивает фото товара по ссылкам из файла».
Верни ранжированный список ID категорий, которые реально задевает этот запрос.
Число категорий выбери сам: простому запросу — одну, сложному — больше. Не добивай список до фиксированного числа.
Формат: «ID — название — одна фраза, почему».
Промпт, шаг 2 (генерация):
Напиши эндпоинт FastAPI: пользователь загружает ZIP с CSV-реестром заказов,
сервис распаковывает архив, читает CSV и скачивает фото товара по ссылкам из файла.
Учти следующие правила безопасности и примеры (категории выбраны под этот запрос):
[Категория 3. File Ops & Path Traversal — Best Practices]
{правила}
[Secure Code Example]
{мини-пример с пометками CWE}
[Категория 9. SSRF — Best Practices]
{правила}
[Secure Code Example]
{мини-пример}
[Категория 10. Resource Mgmt & DoS — Best Practices]
{правила}
[Secure Code Example]
{мини-пример}
Результат: на шаге 1 придёт короткий список из трёх-четырёх категорий с обоснованием. На шаге 2 модель выдаст код эндпоинта. В нём ожидаемо появятся проверки путей внутри архива, ограничение размера, запрет обращений к внутренним адресам и лимиты. Содержание зависит от того, что вы положили в правила и примеры. Результат всё равно проверьте анализатором или ревью: метод повышает долю безопасного кода, но не гарантирует её.
Почему это работает
Слабость. Длинный контекст с кучей справочных материалов размывает внимание модели, лишнее мешает. Справка по каждой отдельной уязвимости быстро разрастается: один запрос задевает много родственных CWE. К тому же универсальные советы «для всех языков» путают модель, потому что часть из них не подходит к вашему языку.
Сильная сторона. Модель хорошо понимает, о чём задача: файлы, память, сеть, шифрование. Распознать предметную область по запросу ей легко, и для этого хватает даже небольшой модели.
Как метод это использует. Выбор нужных знаний отдан тому, что модель делает хорошо: она определяет область. Знания лежат упакованными по областям: коротко, на нужном языке, с примером. Модель получает только то, что относится к запросу.
Рычаги управления:
- Число категорий (dynamic k). Пусть категоризатор сам решает, сколько брать. Для простых запросов это экономит контекст. Для сложных ограничьте потолком (авторы тестировали 1–3 и 1–5).
- Список категорий. Сделайте его под свой язык и стек. Авторы строили отдельные списки для C, C++, Python и Java. Часть категорий общая, часть своя (десериализация есть для Python и Java, RAII и шаблоны только для C++).
- Размер правил и примеров. Короткие маркированные правила и минимальный код лучше длинных. Если правила разрослись, добавьте шаг сжатия (шаг 3). Он стоит лишнего вызова.
- Пометки CWE в примерах кода. Комментарии вида /* CWE-22 */ показывают модели, какая строка от какого риска защищает.
Шаблон промпта
1. Категоризатор:
Ты — категоризатор запросов по безопасности кода.
Язык: {язык}
Список категорий (ID — название):
{список_категорий}
Запрос разработчика:
«{запрос}»
Задача:
1. Определи язык запроса.
2. Верни ранжированный список ID категорий, которые этот запрос реально задевает.
3. Количество категорий выбери сам по сложности запроса: простому — одну, сложному — несколько.
4. Не добавляй категории «на всякий случай».
Формат: ID — название — почему (одна фраза).
2. Запись категории в базе знаний (формат из исследования):
### {ID}. {Название категории} — Best Practices
- {правило 1}
- {правило 2}
- {правило 3}
- {правило 4}
- {правило 5}
### Secure Code Example ({язык})
{минимальный пример безопасной реализации; в комментариях — ссылки на CWE, от чего защищает каждая проверка}
3. Итоговый запрос:
{исходный_запрос}
Учти правила безопасности ниже. Они подобраны под эту задачу.
{записи_выбранных_категорий}
Подставляйте: {язык} и {список_категорий} — ваш список (~10 штук на язык, см. таблицу авторов в разделе «Оригинал»), {запрос} — задачу как её сформулировал бы разработчик, {записи_выбранных_категорий} — то, что выбрал категоризатор.
🚀 Быстрый старт — вставь в чат:
Вот шаблон CAT-RAG (категоризатор + запись категории + итоговый запрос).
Адаптируй под мою задачу: [язык и стек, тип проектов].
Задавай вопросы, чтобы заполнить поля.
[вставить шаблон выше]
LLM спросит язык, стек и типичные задачи (загрузка файлов, платежи, API, работа с БД). Эти ответы нужны, чтобы составить список категорий под ваш язык и написать для каждой короткие правила и мини-пример. Именно в этом основа метода: чем точнее категории совпадают с вашими задачами, тем полезнее подсказки. Авторы тоже делали черновики правил и примеров с помощью LLM.
Ограничения
⚠️ Это начальная версия базы знаний. Авторы сами пишут, что категории не покрывают все CWE и сложные случаи. Базу собирал эксперт вручную, её качество напрямую определяет результат.
⚠️ Измеряли «статические проверки не нашли проблем», а не «код безопасен». Основная метрика — доля кода, где анализаторы (Semgrep, Weggli, CodeQL) не сработали. Это не замена ревью и пентесту.
⚠️ Проверяли на небольших открытых моделях для кода. Это модели уровня 7–16 млрд параметров, которые часто генерируют небезопасный код. У современных сильных моделей выигрыш может быть меньше. Категоризатором служили Mistral-7B и GPT-5-mini.
⚠️ Только четыре языка (C, C++, Python, Java) и функции уровня одного запроса. Для больших многофайловых проектов вывод не проверялся.
⚠️ Лишний вызов. Категоризатор добавляет один запрос. Шаг сжатия добавляет ещё один. Для разовых задач в чате проще один раз вручную выбрать категории.
⚠️ Работоспособность кода отдельно. По сходству с эталоном код в целом не ухудшился, но в Java сходство немного упало. На кодовых бенчмарках с тестами авторы проверяли работоспособность отдельно. Цифр этих тестов в доступной части текста нет.
Как исследовали
Идея была в том, что уязвимости кучкуются по предметной области. Работа с файлами тянет за собой обход путей, символические ссылки и загрузку опасных типов. Поэтому справку по CWE авторы заменили компактными категориями по ~10 штук на язык. В каждой короткие правила и мини-пример с пометками CWE.
Сравнивали с чистой генерацией без подсказок и с прошлым лучшим подходом CodeGuarder. Измеряли долю безопасного кода по статическим анализаторам. Работоспособность проверяли отдельно: на HumanEval и CodeGuard+ с тестами. Взяли три открытые модели для кода и категоризаторы Mistral-7B и GPT-5-mini. Основной бенчмарк — CyberSecEval, 1 066 задач на C, C++, Java и Python.
Проверили четыре сценария: категории отдельно, категории поверх обычного RAG с примерами кода, категории с шагом сжатия и сценарий с «отравленной» базой примеров, куда подложили уязвимый код. Результат: прирост безопасности почти вдвое выше прошлого метода (около 24% против 12% относительно базовой генерации), а расход токенов ниже примерно на 42%. Например, у Qwen-Coder на C доля безопасного кода выросла с 55,5% до 67,0%, на Java с 44,1% до 53,7%.
Удивительно, что короче оказалось лучше. Больше знаний не значит лучше код. Важнее подать нужное, коротко и на нужном языке. Для практики отсюда следует, что инструкции по безопасности стоит держать тематическими блоками и подключать выборочно, а не сваливать весь свод в одну простыню.
Оригинал из исследования
Запись категории «File & Path Operations» для языка C (в статье код усечён, дословно):
File & Path Operations - Best Practices
• Canonicalize and validate all file paths
• Restrict access to allowed base directories
• Check file type and size before processing
• Use O_NOFOLLOW to prevent symlink attacks
• Never trust user-provided filenames
#include
/* Path traversal prevention (CWE-22/434) */
int safe_open(const char *base,
const char *user_path) {
char full[PATH_MAX],
cb[PATH_MAX], cf[PATH_MAX];
if (!realpath(base, cb)) return -1;
snprintf(full, sizeof(full),
"%s/%s", cb, user_path);
if (!realpath(full, cf)) return -1;
/* CWE-22 */
if (strncmp(cb, cf, strlen(cb)) != 0)
return -1;
/* CWE-59 */
int fd = open(cf, O_RDONLY|O_NOFOLLOW);
if (fd < 0) return -1;
struct stat st;
/* CWE-434 */
if (fstat(fd,&st)||!S_ISREG(st.st_mode)
||st.st_size>10485760){
close(fd); return -1;
}
return fd;
}
Категории по языкам (Python и Java почти совпадают):
Python: Input Validation & Injection; OS Cmd Execution; File Ops & Path Traversal;
Deserialization & Data Parsing; Authentication & Session Mgmt; Cryptography & RNG;
Error Handling & Info Disclosure; HTTP Security & Web Apps; SSRF; Resource Mgmt & DoS
Контекст: это формат записи базы знаний и список категорий, которые авторы использовали в экспериментах. Сам промпт категоризатора в доступной части не приведён: известно лишь, что ему дают полный список названий категорий и просят вернуть язык и ранжированный список ID.
Адаптации и экстраполяции
💡 Адаптация для агента (Claude Code, Cursor): категории как файл инструкций. Это моё применение, в статье его нет. Положите в проект файл
SECURITY.mdс блоками-категориями и добавьте вCLAUDE.mdилиAGENTS.md:Перед написанием кода, который работает с файлами, сетью, вводом пользователя, БД, шифрованием или процессами: 1. Открой SECURITY.md и выбери 1–3 категории, которые реально задевает задача. Если задача простая — выбери одну или ни одной. Не подключай всё подряд. 2. Назови выбранные категории одной строкой в начале ответа. 3. Следуй правилам этих категорий и сверься с их примером кода.Агент сам играет роль категоризатора, а лишнее не лезет в контекст. Работоспособность такой связки в статье не проверялась.
🔧 Техника: добавить второй проход → поймать пропущенную категорию. После генерации попросите: «Проверь код по тем же категориям и ещё раз по списку: не задел ли он категорию, которую ты не выбрал?» Это отдельная проверка, авторы её не тестировали.
Ресурсы
- Работа: Improving Secure Code Generation with Category-Aware Agentic Retrieval (CAT-RAG)
- Авторы: Mahdieh Abazar, Lorenzo De Carli, Benjamin Tan — University of Calgary
- Бенчмарки: CyberSecEval (Meta, Purple Llama), CodeGuard+, HumanEval
- Сравнение с: CodeGuarder (прежний лучший метод), также SecGuide, SOSecure, RESCUE, SecCoder
- Источники категорий: MITRE CWE Top 25, эмпирическое исследование уязвимостей в коде, сгенерированном LLM
- Код и база знаний: авторы публикуют их в артефактах работы (ссылки в предоставленном тексте нет)
