Нейросеть написала функцию, разработчик запустил ее, получил нужный результат и закрыл задачу. Ситуация знакомая, особенно когда речь идет о небольшом изменении, на которое раньше пришлось бы потратить час или два. Теперь достаточно нескольких запросов к ИИ, чтобы получить готовое решение.
Проблема обнаруживается позже. Например, когда выясняется, что функция возвращает данные без проверки прав доступа или повторно отправляет запрос во внешнюю систему, создавая дубликаты записей. Код при этом может быть написан аккуратно, без синтаксических ошибок и с вполне разумной структурой.
Работая с корпоративными веб-сервисами и системами, которые переходят к нам от других подрядчиков, мы в «Энсайн» привыкли внимательно относиться к чужим решениям. Иногда на первый взгляд непонятный участок кода оказывается связан с особенностями бизнес-процесса, ограничениями внешнего API или требованиями, которые давно перестали упоминать в документации. Удалив такую проверку или заменив ее более изящной конструкцией, можно получить проблему там, где ее раньше не было.
С нейросетями возникает похожая ситуация. Разница лишь в том, что чужое решение появляется за секунды, а необходимость разобраться в нем никуда не исчезает.
Когда разработчик пишет функцию самостоятельно, он постепенно принимает множество небольших решений. Как обработать пустое значение, что вернуть при ошибке, какие данные разрешено показывать пользователю, нужно ли учитывать повторный вызов. Часть этих вопросов возникает еще до написания первой строки.
При работе с нейросетью порядок часто меняется. Сначала появляется реализация, а уже потом разработчик начинает выяснять, все ли необходимые условия она учитывает.
Это не обязательно плохо. Быстрый прототип помогает увидеть возможное решение, особенно если задача новая. Но здесь есть одна особенность: готовый код создает впечатление завершенной работы, хотя на самом деле может быть только первым вариантом реализации.
Допустим, мы попросили ИИ написать метод получения документа по идентификатору. Он обращается к базе данных, находит запись и возвращает ее. На тестовых данных все работает. Но в корпоративной системе документы могут принадлежать разным подразделениям, а доступ к ним — зависеть от роли сотрудника, статуса документа и внутренних правил.
Если эти ограничения не попали в запрос к нейросети, модель вполне может их проигнорировать. Причем ошибка не обязательно будет заметна при тестировании. Мы получим корректный ответ от базы данных, только выдавать его конкретному пользователю было нельзя.
Именно такие ситуации сложнее всего обнаруживать автоматическими проверками. Инструмент может найти опасную конструкцию, но не всегда способен определить, какое бизнес-правило разработчик забыл реализовать.
Поэтому, разбирая код от нейросети, мы бы начинали не с поиска синтаксических ошибок, а с сопоставления результата с исходной задачей. Что должна делать функция? При каких условиях? Какие действия запрещены? Что произойдет, если входные данные окажутся не такими, как ожидалось?
Нередко после этих вопросов становится понятно, что проблема находится не в написанных строках, а в отсутствующей логике.
В исследовании Veracode GenAI Code Security Report 2026 авторы проверяли код, созданный генеративными моделями на специально подготовленных заданиях. По результатам исследования, примерно в 44% проверок сгенерированные решения содержали известные уязвимости.
Разумеется, это не означает, что почти половина любого AI-кода небезопасна. Речь идет о конкретной методике и наборе заданий. Тем не менее результат хорошо иллюстрирует проблему: внешне правильная реализация может содержать ошибки, которые не проявляются при обычном запуске.
Возьмем простую задачу. Нужно найти пользователя по адресу электронной почты. Нейросеть может предложить такой PHP-код:
$email = $_GET['email'];
sql="SELECT*FROMusersWHEREemail='email'";
$result = pdo->query(sql);
Если передать обычный адрес, запрос выполнится и вернет ожидаемый результат. Но значение переменной напрямую включается в SQL. Подставив вместо адреса специально сформированную строку, злоумышленник может изменить логику запроса.
Проблема известная — SQL-инъекция. Для ее устранения в данном случае достаточно подготовленного запроса:
$email = $_GET['email'] ?? '';
$stmt = $pdo->prepare(
'SELECT * FROM users WHERE email = :email'
);
$stmt->execute(['email' => $email]);
$user = $stmt->fetch(PDO::FETCH_ASSOC);
Значение здесь передается отдельно от SQL-команды. Разработчику остается проверить корректность входных данных и обработку возможных ошибок.
Можно возразить, что современные модели давно научились использовать параметризованные запросы. Действительно, во многих случаях они предлагают безопасную реализацию сразу. Но мы проверяем не способности нейросети в целом, а конкретный фрагмент кода, который собираемся внедрить.
Если в одном ответе модель использовала правильную конструкцию, это еще не повод пропускать проверку следующего.
С SQL-инъекцией все относительно понятно. Есть опасная конструкция, которую можно обнаружить при просмотре исходников или с помощью инструментов анализа.
С авторизацией ситуация сложнее, поскольку проблема нередко заключается в отсутствии проверки.
Предположим, нейросеть написала функцию получения документа:
function getDocument(PDO $pdo, int $id): array|false
{
$stmt = $pdo->prepare(
'SELECT * FROM documents WHERE id = :id'
);
$stmt->execute(['id' => $id]);
return $stmt->fetch(PDO::FETCH_ASSOC);
}
С точки зрения работы с базой данных здесь нет очевидной ошибки. Используется подготовленный запрос, результат обрабатывается корректно.
Но представим, что функция вызывается через API, а проверка прав доступа нигде больше не предусмотрена. Тогда пользователь сможет запрашивать документы, изменяя их идентификаторы, независимо от того, кому они принадлежат.
Для простой модели, в которой каждый документ имеет одного владельца, запрос можно дополнить условием:
function getDocument(
PDO $pdo,
int $id,
int $userId
): array|false {
$stmt = $pdo->prepare(
'SELECT * FROM documents
WHERE id = :id AND owner_id = :user_id'
);
$stmt->execute([
'id' => $id,
'user_id' => $userId
]);
return $stmt->fetch(PDO::FETCH_ASSOC);
}
При этом идентификатор пользователя должен поступать из проверенного серверного контекста авторизации, а не из параметров запроса.
В корпоративных системах модель доступа обычно сложнее. Сотрудник может работать с документами своего подразделения, руководитель — просматривать материалы подчиненных, а отдельные записи могут иметь дополнительные ограничения.
Не зная этих правил, нейросеть не сможет надежно реализовать авторизацию, даже если напишет технически безупречный код.
Проверяя подобную функцию, полезно попробовать выполнить ее от имени пользователя, которому запрашиваемый документ недоступен. Если метод возвращает данные, значит, нужно разбираться, где должна выполняться проверка прав и почему она не сработала.
Еще один источник проблем — взаимодействие с внешними сервисами.
Представим, что приложение отправляет заявку в CRM. Нейросеть написала обработчик, который формирует запрос, передает данные и сохраняет полученный идентификатор. На тестовом окружении все проходит успешно.
Теперь изменим условия. CRM приняла заявку, но соединение оборвалось до того, как наше приложение получило ответ. Не зная, что операция уже выполнена, обработчик повторяет запрос.
В результате в CRM появляются две одинаковые заявки.
Это не обязательно ошибка конкретной нейросети. Аналогичную проблему может допустить и разработчик, особенно если в документации внешнего API не описано поведение при повторных запросах.
Но при генерации кода подобные детали легко упустить, ограничившись просьбой «написать интеграцию с CRM».
Разбирая такой обработчик, необходимо выяснить, как он реагирует на тайм-аут, можно ли безопасно повторить операцию, поддерживает ли внешний сервис ключи идемпотентности и что делать, если результат запроса остался неизвестен.
Иногда достаточно передавать уникальный идентификатор операции. Иногда приходится хранить состояние обмена и отдельно обрабатывать неоднозначные результаты. Решение зависит от возможностей внешнего сервиса и требований проекта.
Просто добавить несколько повторных попыток недостаточно. В отдельных сценариях это только увеличит количество дублирующихся операций.
Использовать ИИ для код-ревью вполне разумно. Он может быстро просмотреть большой фрагмент, обратить внимание на потенциально опасные конструкции, предложить тесты или найти места, где отсутствует обработка исключений.
Однако мы бы не рассматривали такую проверку как независимое подтверждение качества.
Допустим, первая нейросеть написала функцию расчета скидки, а вторая проверила арифметику. Формулы могут оказаться правильными, тесты — успешными, но обе модели пропустят условие, согласно которому определенные категории товаров не участвуют в акции.
Причина проста: если правило отсутствовало в исходном описании, проверяющая модель тоже может о нем не узнать.
Есть и другая проблема. Получив большой объем кода, ИИ иногда уверенно указывает на несуществующую уязвимость или предлагает исправление, которое нарушает действующую логику. Поэтому замечания нейросети приходится проверять так же внимательно, как ее первоначальное решение.
Практическая польза от AI-ревью становится выше, когда задачу формулируют конкретно.
Вместо общей просьбы «проверь код на ошибки» можно попросить найти места, где пользовательский ввод попадает в SQL, проверить обработку повторных запросов или предложить негативные сценарии для тестирования авторизации.
Такой подход не гарантирует обнаружения всех дефектов, зато позволяет сосредоточить проверку на определенном классе рисков.
Когда изменения затрагивают критичные компоненты системы, автоматических проверок может оказаться недостаточно. В таких случаях необходим более глубокий аудит программного кода, учитывающий архитектуру проекта, безопасность и связи между компонентами.
Но если у вас есть своя команда разработки, ниже оставим несколько базовых рекомендаций и способов проверки кода.
Для PHP-проектов мы бы в первую очередь рассматривали статический анализ. PHPStan и Psalm помогают обнаруживать ошибки типов, некорректные вызовы методов и другие проблемы, которые могут не проявляться при поверхностном тестировании.
Если нейросеть добавила новую библиотеку, стоит проверить зависимости. Команда composer audit позволяет выявить известные уязвимости в установленных пакетах. Заодно полезно убедиться, что предложенная библиотека действительно существует, поддерживает используемую версию PHP и не дублирует функциональность проекта.
Отдельную роль играют SAST-инструменты, предназначенные для поиска потенциальных уязвимостей в исходном коде. Они могут обнаруживать опасные конструкции, однако результат зависит от возможностей анализатора и качества настроенных правил.
И, конечно, остаются автоматические тесты.
Здесь есть нюанс, который легко пропустить. Если нейросеть написала функцию, а затем сама подготовила тесты к ней, существует риск, что тесты будут подтверждать ее собственное представление о задаче. При неверно понятых требованиях все проверки могут успешно проходить.
Поэтому тестовые сценарии стоит сверять с документацией и ожидаемым поведением системы. Особенно внимательно — в случаях, когда речь идет о правах доступа, расчетах, изменении данных и интеграциях.
Наличие CI/CD позволяет выполнять эти проверки автоматически при каждом изменении. Но автоматизация не заменяет изучение кода. Анализатор не знает всех правил бизнеса, а тесты проверяют только те ситуации, которые в них предусмотрели.
Ниже — базовые проверки, которые можно использовать перед отправкой изменений на код-ревью. Не все пункты применимы к каждой функции: например, у простого преобразователя строк нет авторизации или внешнего API. Но если соответствующая логика присутствует, пропускать ее проверку не стоит.
1. Сопоставьте результат с требованиями
Запустите функцию с корректными, пустыми и некорректными данными. Проверьте граничные значения: ноль, отрицательные числа, слишком длинные строки, отсутствующие параметры.
Для расчетов сравните полученные значения с результатами, вычисленными независимо по требованиям. Не используйте ответ другой нейросети как единственный эталон.
2. Найдите места, куда попадает пользовательский ввод
Просмотрите использование данных из HTTP-запросов, загруженных файлов и внешних API.
Проверьте, что SQL-запросы параметризованы, HTML-вывод экранируется с учетом контекста, а пользовательские значения не могут произвольно изменять команды операционной системы или пути к файлам.
3. Попробуйте выполнить действие без необходимых прав
Вызовите метод от имени пользователя, которому недоступен запрашиваемый объект.
Попробуйте получить чужой документ, изменить запись другого пользователя или выполнить операцию без нужной роли. Убедитесь, что ограничение действует на сервере, а не только в интерфейсе.
4. Смоделируйте сбои внешних сервисов
Проверьте поведение при тайм-ауте, ответе с ошибкой, пустом результате и временной недоступности API.
Если операция изменяет данные, выполните повторный запрос и выясните, не создает ли он дубликаты или другие нежелательные последствия.
5. Запустите автоматические проверки
Для PHP используйте принятый в проекте статический анализ, например PHPStan или Psalm. Проверьте зависимости через composer audit.
Если в проекте настроен анализ безопасности, убедитесь, что новые изменения проходят и его. Просмотрите предупреждения, не ограничиваясь формальным успешным завершением проверки.
6. Проверьте тесты отдельно от реализации
Убедитесь, что они покрывают не только успешные сценарии, но и ошибки ввода, отсутствие доступа, некорректные ответы и сбои зависимых компонентов.
Если тесты сгенерированы ИИ, сопоставьте ожидаемые результаты с исходными требованиями. При необходимости добавьте сценарии самостоятельно.
7. Просмотрите diff и связанные компоненты
Убедитесь, что нейросеть не изменила посторонние файлы, не удалила существующие проверки и не продублировала уже реализованную логику.
Посмотрите, не изменились ли контракты API, форматы данных и поведение методов, которые используются в других частях приложения. Для запросов к базе данных оцените их выполнение на объеме данных, сопоставимом с рабочим.
Этот перечень помогает отсеять распространенные проблемы, но не заменяет полноценное ревью. Изменения, затрагивающие платежи, персональные данные или механизмы авторизации, требуют дополнительных проверок с учетом рисков конкретной системы.
У нейросетей есть вполне практическое преимущество: они позволяют быстрее переходить от описания задачи к работающему варианту кода. Особенно заметно это при подготовке типовых функций, работе с незнакомыми библиотеками и поиске вариантов реализации.
Но получив готовую функцию, разработчик не освобождается от необходимости разобраться в ее поведении.
Мы бы не стали делить код на надежный и ненадежный только по признаку того, написал его человек или нейросеть. Ошибки встречаются в обоих случаях. Гораздо важнее, насколько полно команда понимает требования, проверяет изменения и учитывает последствия их внедрения.
ИИ может взять на себя часть рутинной работы. Решение о том, готов ли результат к использованию в действующей системе, по-прежнему остается за разработчиками.




Мы находим подход даже к самым нестандартным задачам. Расскажите нам о своем проекте — мы готовы обсудить любые детали и предложить решения.