TL;DR
Исследователи проверили, как разные способы работы с тестами при генерации кода влияют на его безопасность. Тесты можно использовать двояко: показать модели заранее как образец требований (что должен делать код и от каких атак защищаться), или вернуть модели после провала — конкретный текст ошибки, чтобы она переписала код.
Главная находка неприятная: код, который прошёл все проверки, которые ты показал модели, всё равно может остаться дырявым в местах, которые ты не проверил. Модель не "понимает безопасность" в целом — она затыкает именно те дырки, которые ей явно показали тестом. При этом простое общее напоминание типа "пиши безопасный код" работает непредсказуемо: на одной модели помогает, на другой — портит результат, потому что модель либо переусердствует и ломает функциональность, либо просто игнорирует угрозу.
Метод в два хода: до генерации — дай конкретные тест-кейсы (включая примеры атак), а не общие пожелания. После генерации — если код не прошёл проверку, верни модели точный текст ошибки и попроси переписать код полностью, а не подправить кусок. Интересно, что как именно оформлен этот фидбек — красиво по приоритету или просто целиком лог ошибок — почти не влияет на результат. Важен сам факт, что модель увидела конкретную ошибку.
Схема метода
ШАГ 1: Дать модели конкретные тест-кейсы и примеры атак вместо общего "сделай безопасно"
→ код, заточенный именно под эти случаи
ШАГ 2: Прогнать код на реальных данных, найти провал
→ точный текст ошибки/лога
ШАГ 3: Вернуть модели этот текст ошибки, попросить переписать код ЦЕЛИКОМ
→ новая версия кода
ШАГ 4: Повторить шаги 2-3 максимум 1-2 раза
→ финальный код
ШАГ 5 (обязательно): Проверить код на кейсах, которые НЕ входили в исходные тесты
→ страховка от ложного чувства безопасности
Все шаги — в одном диалоге, отдельные сообщения подряд.
Пример применения
Задача: Маркетолог просит у ChatGPT скрипт на Python для формы на сайте (Tilda, Taplink, самописный лендинг) — форма принимает файл от пользователя (резюме, фото, документ) и сохраняет его на сервер.
Промпт (шаг 1):
Напиши функцию на Python, которая сохраняет файл, загруженный пользователем через веб-форму,
на диск в папку /uploads/. Функция должна проходить такие проверки:
1. Обычный файл "photo.jpg" — сохраняется нормально.
2. Если имя файла "../../etc/passwd" или "../../../config.py" — функция должна ОТКАЗАТЬ
и не сохранять файл (защита от выхода за пределы папки).
3. Если в имени файла есть спецсимволы, нулевые байты или двойное кодирование пути —
функция должна отказать.
4. Размер файла больше 10 МБ — отказ.
Покажи код и объясни, как он проверяет каждый пункт.
Промпт (шаг 2, если нашёл дырку):
Я протестировал твою функцию: подсунул имя файла "..%2f..%2fetc%2fpasswd" (закодированный путь),
и файл сохранился ВНЕ папки /uploads/. Вот что вернула функция: [вставить сообщение об ошибке или лог].
Перепиши функцию ЦЕЛИКОМ с защитой от этого случая тоже.
Результат: Модель выдаст переписанную функцию с явной проверкой и очисткой пути к файлу (нормализация пути, проверка что итоговый путь остаётся внутри /uploads/). После этого стоит попробовать ещё пару похожих трюков (абсолютный путь, символическую ссылку, unicode-обход) — потому что прохождение первых тестов не гарантирует, что закрыты все похожие дырки.
Почему это работает
Модель, получив общую инструкцию "будь безопасен", не знает, что конкретно проверять — она добавляет общие практики "на глаз", но может не подумать именно про твой конкретный вектор атаки. Абстрактная безопасность для модели — не счётчик, который можно проверить, а размытое пожелание.
Зато модель отлично реагирует на конкретику: явный тест-кейс или точный текст ошибки — это то, что она умеет закрывать прицельно. Дай ей пример атаки — она напишет защиту именно от этой атаки.
Метод превращает расплывчатое "сделай безопасно" в конкретную, проверяемую задачу: покажи тест — получи защиту от него, покажи ошибку — получи исправление именно этой ошибки. Но это же и ограничение: закрыто только то, что показано явно.
Рычаги управления: - Количество тест-кейсов заранее → больше конкретных примеров атак = более специфичная защита, но никогда не полная. - Формат фидбека (полный лог vs короткая выдержка) → роли почти не играет, можно смело копировать весь текст ошибки без причёсывания. - Число раундов исправления → для простых задач достаточно одного раунда, не нужно гонять цикл до бесконечности.
Ограничения
⚠️ Ложное чувство безопасности: код, прошедший все твои проверки, может остаться дырявым в случаях, которые ты не тестировал. Тестирование закрывает только то, что явно показано модели.
⚠️ Общие напоминания непредсказуемы: фраза "напиши безопасный код" без конкретных примеров иногда помогает, а иногда портит результат — модель может как переусердствовать и сломать функциональность, так и вовсе проигнорировать угрозу.
⚠️ Формат фидбека почти не важен: не трать время на структурирование сообщений об ошибке для модели — простое копирование лога работает почти так же хорошо, как аккуратно оформленное сообщение.
Ресурсы
"Security Tests as Executable Specifications for LLM Code Generation: Benefits, Trade-offs, and Coverage Limits" — Yunhao Liang, Chengguang Gan, Ruixuan Ying, Hanjun Wei, Zhe Cui, Shiwen Ni (Chengdu Institute of Computer Applications CAS, Tohoku University, Shenzhen University of Advanced Technology). Используемые бенчмарки: CWEval, SALLM, CodeGuard+.
