К содержимому
Подарок
Нейросети

Как проверить код, написанный нейросетью: чек-лист

Код, написанный нейросетью, проверяют не на «красоту», а на четыре вещи: кто имеет право вызвать этот код, что он делает с пользовательским вводом, где лежат секреты и какие зависимости он тянет. По моему опыту, почти всё, что находится при аудите такого кода, — это не хитрые логические баги, а отсутствующие проверки прав и незакрытый ввод. […]

Проверка
кода

Коротко

  • Код нейросети проверяю на права, ввод, секреты и зависимости.
  • Почти все дыры — это не хитрый баг, а забытая проверка.
  • Чек-лист из девяти пунктов, на среднем проекте около часа.
  • Логику предметной области чат сам не подтвердит.

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

Я Дмитрий Гугуян, разрабатываю сайты в Майкопе и последний год почти всю рутину пишу через ИИ-агентов. Так что это не взгляд скептика со стороны — это список того, что я проверяю в собственном коде перед выкаткой.

В канале пишу то, что не доезжает до статьи.Короткие заметки и тесты нейросетей

Читать канал

Почему код от нейросети ломается не там, где вы ждёте

Модель пишет код под счастливый сценарий. Вы попросили форму обратной связи — получите форму, которая отправляет письмо. Она не додумает, что кто-то отправит её пятьсот раз за минуту, подставит чужой ID заказа или зальёт файл avatar.php вместо avatar.jpg, если вы про это отдельно не спросили. Она не знает, что ваш обработчик будет доступен по открытому URL.

Вторая причина — обучающие данные. Модель видела много публичного кода, включая туториалы десятилетней давности. Отсюда в ответах всплывают конкатенация SQL-строк, проверка isset($_POST['submit']) вместо nonce и давно удалённые из ядра функции.

Третья причина самая неприятная: такой код выглядит уверенно. Ровные отступы, осмысленные имена переменных, аккуратные комментарии. У кода джуниора обычно видно, где он сомневался, — здесь этого сигнала нет, всё написано одинаково убедительно.

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

Чек-лист: девять проверок кода от ИИ

  1. Права, а не только вход. Проверка «пользователь залогинен» и проверка «пользователю можно это делать» — разные вещи, и вторую модель пропускает чаще всего. Ищите обработчики, которые принимают ID сущности из запроса и не проверяют, принадлежит ли она вызывающему.
  2. Пользовательский ввод в запросах к базе. Любая переменная, попавшая в строку SQL без подготовленного выражения, — это дыра. В WordPress это $wpdb->prepare(), в чистом PHP — PDO::prepare().
  3. Экранирование вывода. Данные, пришедшие от пользователя и попавшие обратно в HTML без esc_html() / htmlspecialchars(), дают XSS. Особенно в админке, где «свои же люди».
  4. Секреты в коде. Ключи API, пароли от почты и токены платёжек регулярно оказываются прямо в файле — потому что вы сами вставили их в промпт, чтобы «просто заработало». Проверьте заодно, не ушли ли они в git.
  5. Зависимости, которых не существует. Модель может выдумать название пакета. Дальше начинается то, что называют slopsquatting: кто-то регистрирует популярное галлюцинированное имя в npm или PyPI и кладёт туда вредонос. Перед установкой смотрите дату первого релиза, мейнтейнера и число загрузок.
  6. Загрузка файлов. Проверка по расширению и по $_FILES['file']['type'] не проверка вообще: и то и другое присылает клиент. Нужен белый список MIME, определённый на сервере, переименование файла и каталог, в котором запрещено исполнение.
  7. Что происходит при ошибке. Включённый display_errors, WP_DEBUG на проде, текст исключения в ответе API — всё это отдаёт наружу пути, версии и структуру базы.
  8. Устаревшие и несуществующие API. Модель уверенно вызывает функцию, которой нет в вашей версии фреймворка, или ту, что удалена. Проверяется быстро: код просто не работает. Хуже, когда функция есть, но делает не то, что описано в ответе модели.
  9. Необратимые действия. Удаление, списание денег, рассылка. Здесь я читаю код глазами целиком, без исключений: одна перепутанная ветка if — и письмо уходит всей базе.

Пример: обработчик, который мне прислали на проверку

Классика. Владелец магазина попросил у нейросети «сделай так, чтобы статус заказа менялся кнопкой без перезагрузки страницы». Получил вот это:

add_action( 'wp_ajax_nopriv_save_order', 'save_order' );
add_action( 'wp_ajax_save_order', 'save_order' ); function save_order() { global $wpdb; $id = $_POST['order_id']; $status = $_POST['status']; $wpdb->query( "UPDATE orders SET status = '$status' WHERE id = $id" ); wp_send_json_success();
}

Код работает. Кнопка нажимается, статус меняется, заказчик доволен. При этом здесь сразу три проблемы: wp_ajax_nopriv_ открывает эту ручку любому неавторизованному посетителю, $status и $id склеиваются в SQL напрямую, и нигде не проверяется, можно ли этому пользователю вообще трогать заказы. Один POST-запрос — и чужой человек переписывает вам статусы всех заказов.

Если статья попала в точку, в канале есть продолжение.Без рассылки на почту, только Telegram

Подписаться

Как должно быть:

// nopriv убран: гостям здесь делать нечего
add_action( 'wp_ajax_save_order', 'save_order' ); function save_order() { check_ajax_referer( 'save_order' ); // запрос пришёл с нашей страницы if ( ! current_user_can( 'edit_shop_orders' ) ) { // и у пользователя есть право wp_send_json_error( 'forbidden', 403 ); } $id = absint( $_POST['order_id'] ?? 0 ); $status = sanitize_key( $_POST['status'] ?? '' ); if ( ! $id || ! in_array( $status, array( 'new', 'paid', 'shipped' ), true ) ) { wp_send_json_error( 'bad request', 400 ); } global $wpdb; $wpdb->update( 'orders', array( 'status' => $status ), array( 'id' => $id ), array( '%s' ), array( '%d' ) ); wp_send_json_success();
}

Разница в семь строк. Модель написала бы так сразу, если бы в запросе было сказано «только для менеджеров, проверь права и nonce». Но так запрос никто не формулирует.

Быстрый скан: что находится grep-ом за пять минут

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

# 1. Секреты прямо в файлах
grep -rnE "(api_key|apikey|secret|password|token)[[:space:]]*=[[:space:]]*['"][A-Za-z0-9_-]{12,}"  --include=*.php --include=*.js --include=*.py . # 2. Переменные, склеенные в SQL-строку
grep -rnE '(query|get_results|get_var|mysqli_query)(.*$' --include=*.php . # 3. Пользовательский ввод, попадающий в вывод без экранирования
grep -rnE 'echo[[:space:]]+$_(GET|POST|REQUEST)' --include=*.php . # 4. AJAX-ручки, открытые для гостей
grep -rn 'wp_ajax_nopriv_' --include=*.php .

Дальше по пакетам. Для каждой зависимости, про которую вы не слышали раньше:

npm view имя-пакета time.created maintainers
pip index versions имя-пакета

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

Можно ли попросить проверить код саму нейросеть

Можно, и это работает лучше, чем принято думать, — но при двух условиях. Первое: открывать новую сессию. В той же переписке, где код был написан, модель будет защищать своё решение. Второе: давать ей роль и критерии, а не вопрос «всё нормально?». Формулировка вида «ты проводишь аудит безопасности чужого кода; найди места, где не проверяются права доступа, где пользовательский ввод попадает в SQL или в HTML, где захардкожены секреты» находит большую часть списка выше.

Чего такая проверка не даёт: модель не знает, кто и с какими правами вызывает этот код в вашем приложении. Она видит функцию, но не видит, что эта функция висит на публичном роуте. Контекст приложения — ровно то место, где заканчивается автоматическая проверка и начинается человек.

Чего чек-лист не заменит

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

Если своего времени на такую проверку нет, я делаю аудит кода, написанного с ИИ, — с отчётом по каждому пункту и правками там, где они нужны.

Автор: Дмитрий Гугуян Обновлено: 28 октября 2026 Основано на личном опыте
Следующий шаг

Пак промптов и ТЗ для Grok

Промпты и шаблоны ТЗ, которыми пользуюсь каждый день.

990 ₽
Подробнее

Дмитрий Гугуян

Разработчик сайтов и SEO-специалист · Майкоп

Делаю сайты с 2016 года, сдал 50+ проектов. Руковожу агентством Рекком. Каждый день работаю с нейросетями и пишу только о том, что проверил сам. Цифры дохода — мой результат, не гарантия.

WordPress 1С-Битрикс Python SEO Яндекс/Google ИИ-агенты

Бесплатно: Чек-лист: бан в Claudeбот попросит подписаться на канал

Забрать