← Все статьи

Семь дыр, которые ИИ чаще вставляет в код — и как их ловить

Почему ассистенты генерируют «правдоподобный пример», а не прод: секреты в коде, SQL-склейка, дыры в доступе. Таксономия и сканер ai-vuln-scan.

Семь дыр, которые ИИ чаще вставляет в код — и как их ловить
Содержание

Коротко

Код от GitHub Copilot и Claude Code часто выглядит готовым к запуску — и именно поэтому в прод уезжают одни и те же классы дыр. На Dev.to инженер Джитендра Роут описывает семь повторяющихся шаблонов: не настоящие «глупые ошибки модели», а следствие того, что ассистент оптимизирует правдоподобный рабочий пример, а не безопасную продакшен-сборку. Он выложил открытый сканер ai-vuln-scan и каталог шаблонов, чтобы ловить этот разрыв системно, а не надеяться на «лучший промпт».

Что произошло

Автор заметил, что дыры в коде с ИИ не случайны. Универсальные линтеры ищут баги вообще; здесь вопрос уже: какие промахи чаще, чем в коде, написанном человеком с нуля. Ответ простой: пример «чтобы завелось» не нуждается в менеджере секретов, параметризованном запросе и жёстком конфиге. Модель выдаёт версию, которая работает. Безопасная версия появляется, только если об этом явно попросить.

Семь шаблонов из открытого каталога:

Шаблон Как выглядит «удобный пример» Что должно быть в проде
Секреты в коде Ключ API «для демо» копируют как есть Переменные окружения, хранилище секретов
Склейка запроса SELECT … WHERE id = ${userId} Параметры / плейсхолдеры драйвера
Команда оболочки exec("cmd " + arg) execFile() со списком аргументов
Слишком открытый конфиг CORS *, выключенная проверка сертификата Явный список источников, проверка включена
Слабая криптография MD5, Math.random() «для токена» Нормальные примитивы для безопасности
Разный доступ на похожих маршрутах Новый маршрут «как соседний», без слоя проверки Тот же промежуточный слой, что у остальных
Подробные ошибки клиенту err.stack в ответе HTTP Журнал на сервере, общая фраза клиенту

Шестой пункт автор считает самым «иишным». Человек, копируя маршрут, тащит блок целиком. Модель заново генерирует описание — и шаг с проверкой доступа легко выпадает, особенно если правки шли в разных запросах. В ревью каждая функция по отдельности выглядит нормально. В материале есть показательный обработчик Express: маршрут заказов пользователя, который на первый взгляд только читает id из адреса и отдаёт JSON. Если в том же файле остальные маршруты обёрнуты в слой проверки доступа, а этот — нет, дыра не кричит о себе синтаксисом. Она выглядит как «ещё один простой эндпоинт».

На учебном файле с намеренно вставленными дырами ai-vuln-scan нашёл 12 срабатываний (секреты, склейка запросов, маршрут без доступа, слабый генератор токена) и не дал ложных на тех же маршрутах после правки. Сейчас покрыты JavaScript, TypeScript и Python на регулярках и простой структуре кода; дальше автор хочет дерево разбора с отслеживанием потока данных и размеченный набор примеров. Каталог шаблонов он публикует отдельно от сканера: новый шаблон можно описать и обсудить, ещё не имея правила детекции. Это важно, потому что зоопарк ассистентов меняется быстрее, чем набор регулярных выражений.

Почему это важно

Команды уже встраивают ассистентов в повседневную работу. Ревью по-прежнему читает «выглядит ли функция разумно», а не «не выпал ли слой доступа при регенерации». Обычные плагины безопасности для линтера, Bandit и Semgrep часть этого ловят — но без рамки «это типичный артефакт ИИ». Именованный каталог даёт общий язык для ревью и для правил в конвейере: можно спорить с конкретным шаблоном, а не с ощущением, что «модель иногда враждебна».

Есть и организационный эффект. Если в команде уже принято «не коммитить ключи» и «не клеить SQL строками», каталог всё равно полезен как список мест, где ассистент чаще всего обходит эти правила «ради рабочего примера». Секреты в виде правдоподобного ключа, CORS * «чтобы завелось локально», MD5 «просто похешировать» — это не новая теория безопасности, а статистика того, что модель считает достаточно хорошим ответом на короткий запрос.

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

На практике

  1. В ревью нового маршрута сверяйте промежуточный слой доступа с соседними: если ассистент «добавлял ещё один как остальные», именно здесь чаще всего дыра.
  2. Запретите в политике репозитория ключи и строки подключения в исходниках, даже «временные» и «демо».
  3. Ищите склейку SQL и команд оболочки через шаблонные строки; требуйте параметры и массив аргументов.
  4. Не оставляйте в конфиге разработки CORS *, отключённую проверку сертификата и режим отладки — ассистент не знает ваши реальные источники и сертификаты.
  5. Для хешей паролей и токенов сессии не принимайте MD5 и Math.random() даже в «черновом» патче.
  6. Ошибки: стек — только в журнал сервера; клиенту — нейтральное сообщение и код.
  7. Прогоните ai-vuln-scan (клонировать репозиторий, npm run scan:examples) и решите, встраивать ли его рядом с Semgrep, а не вместо него.

Итог

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