← Code Review in the AI Era: Trust, Verify, Merge
03 / 07 · 50 min

Security Review of Generated Code

SQL injection from concatenation, missing permission checks, hardcoded secrets, and invented packages: where generated code is insecure by default and how to raise a SAST gate in CI.

Lesson content is currently available in Russian.

What you will learn

  • →Находить в AI-диффах типовые уязвимости: инъекции, пропущенную авторизацию, слабое крипто, path traversal.
  • →Проверять цепочку поставок: существование, репутацию и целостность каждой новой зависимости.
  • →Встраивать SAST, secret scanning и dependency review в CI как обязательный гейт для AI-PR.

Небезопасно по умолчанию

Модель оптимизирует правдоподобие, а не безопасность. В обучающих данных уязвимого кода огромное количество — Stack Overflow полон примеров «просто чтобы работало», а туториалы десятилетиями учат конкатенировать SQL-строки. Модель честно воспроизводит это распределение: в исследовании «Asleep at the Keyboard» около 40% сгенерированных фрагментов в сценариях, соотнесённых с CWE-списком опасных дефектов, оказались уязвимыми. При этом уязвимый код почти всегда функционально корректен: инъекция не мешает запросу работать на демо-данных, отсутствие проверки прав незаметно, пока все ходят под админом.

Поэтому security-ревью AI-кода строится на презумпции: сгенерированный дифф — недоверенный вклад, как PR от незнакомого внешнего контрибьютора. Никакие заслуги агента в прошлых задачах не переносятся на текущий дифф — у модели нет памяти о том, что «в этом проекте мы так не делаем», если это не написано в её контексте явно.

Вторая причина усиленного внимания — эффект масштаба. Человек пишет один уязвимый эндпоинт в неделю, агент — двадцать за вечер, и все двадцать с одинаковой дырой, потому что паттерн один. Уязвимость в AI-кодовой базе — это почти всегда класс, а не экземпляр: нашёл одну инъекцию — ищи такую же во всех местах, которые агент генерировал по тому же образцу. Отсюда практическое правило: каждая найденная уязвимость превращается в Semgrep-правило или тест, который ищет весь класс по всей базе.

Классика уязвимостей в сгенерированном коде

Пять классов, которые стоит проверять в каждом AI-диффе, трогающем ввод, данные или файлы.

Инъекции из конкатенации. Самый частый класс:

// Сгенерировано: конкатенация — SQL-инъекция
const rows = await db.query(
  "SELECT * FROM orders WHERE user_id = " + req.params.userId
);

// Параметризованный запрос
const rows = await db.query(
  "SELECT * FROM orders WHERE user_id = $1",
  [req.params.userId]
);

Пропущенная авторизация (IDOR). Агент генерирует эндпоинт по образцу соседнего, но проверку «этот ресурс принадлежит этому пользователю» образец не содержал — и она не появилась. Любой новый маршрут в диффе проверяется на два вопроса: кто может вызвать и чьи данные он отдаёт.

Захардкоженные секреты. Модель охотно вставляет ключи-плейсхолдеры прямо в код, а агент с доступом к .env может скопировать реальный ключ в исходник «для простоты».

Слабое крипто и legacy-паттерны. MD5/SHA1 для паролей, Math.random для токенов, собственный «шифр» вместо библиотеки — наследие обучающих данных из прошлого урока.

Path traversal и SSRF. Склейка пути из пользовательского ввода без нормализации, fetch по URL из запроса без allowlist. Оба класса модель воспроизводит из бесчисленных туториалов «file server за 20 строк».

Цепочка поставок: выдуманные и подменённые пакеты

Галлюцинации API из первого урока имеют security-измерение. Модели стабильно выдумывают несуществующие имена пакетов — и злоумышленники это заметили. Атака slopsquatting: собрать частые галлюцинации моделей, зарегистрировать пакеты с этими именами и начинить их вредоносным кодом. Агент импортирует выдуманный пакет, npm install находит его в реестре — и вредоносный postinstall-скрипт уже выполняется на машине разработчика или в CI. Родственная атака typosquatting эксплуатирует пакеты с именами, похожими на популярные.

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

Механика защиты уровнем ниже: фиксируй версии через lockfile и не позволяй агенту его редактировать руками; включи запрет install-скриптов там, где возможно (npm config set ignore-scripts true для CI-шагов, которым скрипты не нужны); используй dependency review в CI, чтобы новая зависимость была видна в PR как отдельное событие, а не строчка в шуме lockfile. Правило для команды: новая зависимость — всегда отдельное решение человека, никогда — побочный эффект генерации. Агент может предложить пакет, но добавление в package.json проходит явную проверку по чек-листу выше.

SAST-заслон: проверки, которые не устают

Глаза ревьюера — худший инструмент для поиска однотипных уязвимостей: внимание падает, паттерны сливаются. Машинные проверки не устают, поэтому security-гейт для AI-PR строится в CI.

  • SAST на каждый PR. Semgrep с набором правил под ваш стек ловит инъекции, слабое крипто и опасные API за секунды; CodeQL глубже анализирует потоки данных от источника к стоку. Найденная вручную уязвимость превращается в собственное правило — так база правил накапливает память команды.
  • Secret scanning. Сканирование диффа на ключи и токены до мержа. Найденный секрет означает не «удалить строку», а «ротировать ключ» — история Git помнит всё.
  • Dependency review. Шаг CI, который показывает новые зависимости и известные уязвимости в них прямо в PR.
  • Чек-лист security-ревью для человека — то, что автоматика не видит:

Security-чек-лист AI-диффа

  • каждый новый маршрут: кто может вызвать? чьи данные отдаёт?
  • каждый пользовательский ввод: валидируется до использования в запросе, пути, URL, команде?
  • каждая новая зависимость: проверена по чек-листу цепочки поставок?
  • секреты: только из окружения, ни одного литерала в коде?
  • крипто: только стандартные библиотеки и современные алгоритмы?

Критические находки SAST блокируют мерж без исключений для AI-PR: у агента нет права на «я знаю, что делаю», которое иногда есть у senior-человека. Исключение оформляется человеком явным подавлением правила с комментарием-обоснованием — и это событие само по себе видно в ревью.

Practice

Security-гейт своими руками

Сгенерируйте агентом небольшой REST-сервис (3–4 эндпоинта с БД и загрузкой файлов) без упоминания безопасности в промпте. Прогоните по security-чек-листу урока и Semgrep с дефолтным набором правил. Классифицируйте находки по классам урока, почините критические и добавьте Semgrep-шаг в CI.

Deliverable

Отчёт: список находок «класс → файл → строка → фикс», вывод Semgrep до и после фиксов и работающий CI-шаг, который падает при повторном внесении любой из найденных уязвимостей.

Checkpoint

Объясните, почему сгенерированный код считается недоверенным по умолчанию, и опишите ваш security-гейт для AI-PR: что проверяет автоматика, что остаётся человеку и что блокирует мерж.

  • ✓ Названы причины: модель воспроизводит уязвимые паттерны обучающих данных, уязвимый код функционально корректен, дефекты тиражируются классами.
  • ✓ Перечислены минимум три класса уязвимостей с способом обнаружения каждого (SAST-правило, secret scanning, ревью авторизации человеком).
  • ✓ Описана политика цепочки поставок: проверка новых пакетов, lockfile, запрет install-скриптов, новая зависимость как явное решение человека.

Check yourself

Почему уязвимый AI-код часто проходит и тесты, и беглое ревью?

01Почему уязвимый AI-код часто проходит и тесты, и беглое ревью?

Что такое slopsquatting?

02Что такое slopsquatting?

Агент сгенерировал 20 эндпоинтов по одному образцу, в одном найден IDOR. Каков правильный следующий шаг?

03Агент сгенерировал 20 эндпоинтов по одному образцу, в одном найден IDOR. Каков правильный следующий шаг?

Почему найденный в диффе секрет требует ротации ключа, а не просто удаления строки?

04Почему найденный в диффе секрет требует ротации ключа, а не просто удаления строки?

Какая политика для новых зависимостей в AI-PR правильная?

05Какая политика для новых зависимостей в AI-PR правильная?

Sources

Security Review of Generated Code · Code Review in the AI Era: Trust, Verify, Merge · VORCL