ИИ-агенту запретили запись в CRM. Но CRM всё равно изменилась
Ограничение прав самой модели ещё не означает, что вся система работает в режиме read-only. Это особенно важно учитывать перед запуском AI-агента в production, расширением его полномочий и передачей автоматизированного процесса клиентам.
Фраза "модель не может изменять данные" часто появляется в архитектурных документах, результатах security review и ответах на вопросы заказчика. Однако она описывает только один элемент системы. На практике внешнее изменение может выполнить не модель, а оркестратор, workflow-движок, интеграционный сервис или отдельный исполнительный узел.
Ключевой вопрос следует формулировать иначе: какой компонент способен вызвать реальное внешнее последствие и какая проверка останавливает его непосредственно перед выполнением действия?
Где находилась настоящая возможность записи
Рассмотрим типовую связку: n8n, языковая модель DeepSeek и CRM HubSpot.
У модели не было учётных данных HubSpot, поэтому напрямую отправить запрос на изменение записи она не могла. Но credential с правом записи находился у следующего узла n8n. Этот узел принимал структурированный результат работы модели и на его основе формировал PATCH-запрос к CRM.
Таким образом, у модели действительно были ограниченные полномочия. Но у системы в целом возможность записи сохранялась. Если downstream-компонент без дополнительной проверки доверяет параметрам, сгенерированным моделью, он способен изменить внешний объект.
Это классическая проблема confused deputy: компонент с легитимными полномочиями выполняет действие по указанию источника, который сам таких полномочий не имеет. В агентных системах риск усиливается тем, что между намерением пользователя, выводом модели и внешним действием появляется несколько преобразований.
Контрольный сценарий с неправильным объектом
Проверка проводилась в изолированной лабораторной среде с синтетическими данными. В HubSpot были созданы две тестовые сделки:
- LAB-042;
- LAB-043.
В штатном варианте запрос пользователя, предложение модели и изменяемая запись должны относиться к LAB-042. Затем в сценарий намеренно внесли несовпадение: исходный запрос указывал на одну сделку, а структурированное предложение содержало идентификатор другой.
Это не была проверка на "злонамеренную" модель. Задача состояла в другом: выяснить, остановит ли архитектура ошибочное предложение до момента обращения к CRM.
В первой конфигурации независимой проверки не существовало. n8n получил результат от модели, использовал собственный HubSpot credential и выполнил PATCH для LAB-043.
Последующее чтение CRM подтвердило:
- LAB-043 действительно изменилась;
- LAB-042 осталась без изменений.
Иными словами, была изменена не та сделка, которая фигурировала в исходном запросе. При этом модель по-прежнему не обладала прямым доступом к HubSpot.
Что изменила проверка на границе исполнения
Во втором варианте между результатом модели и запросом к HubSpot добавили отдельный детерминированный gateway. Его функция была намеренно ограниченной: перед записью проверить параметры, от которых зависит итоговое последствие.
Проверка учитывала:
- целевую систему;
- идентификатор объекта;
- ожидаемое исходное состояние;
- разрешённый тип перехода;
- соответствие цели исходному запросу;
- допустимые поля и значения;
- отсутствие признаков повторного или устаревшего выполнения.
Ожидаемый target фиксировался независимо от ответа модели. Поэтому результат генерации не становился единственным источником истины для определения объекта записи.
В штатном сценарии с LAB-042 gateway возвращал allow, после чего операция успешно выполнялась. Предложение с LAB-043 получало deny и не доходило до HubSpot.
Важно, что credential с правом записи никуда не исчез. n8n всё ещё имел техническую возможность отправлять изменения. Но теперь использование этого полномочия зависело от отдельного контроля непосредственно перед внешним вызовом.
Именно этот слой меняет свойства всей системы. Ограничение модели отвечает на вопрос "что может сделать модель?". Gateway отвечает на гораздо более важный вопрос: "что может произойти после работы модели?".
Почему модельный read-only недостаточен
Режим read-only на уровне LLM может означать лишь отсутствие у неё прямого инструмента записи. Но данные, которые она сформировала, могут:
- попасть в webhook;
- быть преобразованы workflow-движком;
- использоваться в REST-запросе;
- передаваться функции с более широкими правами;
- стать параметрами SQL-операции;
- инициировать отправку письма, платежа или команды в другой системе.
Поэтому безопасность нельзя оценивать только по списку инструментов, доступных агенту. Необходимо анализировать всю execution chain - от пользовательского запроса до изменения внешнего состояния.
Особое внимание следует уделять местам, где меняется формат данных. Например, модель может вернуть JSON с идентификатором сделки, а интеграционный узел автоматически использовать этот идентификатор в PATCH-запросе. На этапе преобразования проверка контекста часто теряется.
Какие проверки должны быть обязательными
Перед разрешением записи стоит проверять не только права, но и смысл операции.
Во-первых, система должна убедиться, что объект действительно совпадает с тем, который был выбран на предыдущем этапе. Нельзя считать идентификатор из ответа модели достоверным только потому, что он имеет корректный формат.
Во-вторых, полезно применять optimistic locking: операция разрешается лишь при сохранении ожидаемой версии или исходного состояния записи. Если объект уже изменился, запрос блокируется и отправляется на повторное согласование.
В-третьих, необходимо ограничивать допустимый переход. Например, агент может перевести сделку из "Новая" в "В работе", но не вправе менять её на "Закрыта" без участия человека.
В-четвёртых, следует вводить allowlist полей. Даже если workflow получил доступ к записи, он должен иметь право изменять только заранее определённый набор атрибутов.
В-пятых, все решения gateway должны журналироваться: исходный запрос, ответ модели, проверенный target, причина разрешения или отказа, идентификатор операции и фактический результат.
Что это меняет в решении о production-запуске
Наличие read-only-доступа у модели само по себе не является достаточным основанием для вывода о безопасности решения. Перед запуском нужно установить, какой узел обладает конечным write capability и существует ли независимая проверка перед использованием этого права.
Если такого контроля нет, систему нельзя описывать как полностью read-only. Более точной формулировкой будет: "модель не имеет прямого доступа к записи, однако downstream-workflow способен изменять внешние данные".
Это принципиально разные утверждения. Первое может создать ложное ощущение безопасности, второе корректно отражает архитектурный риск.
Для высокорисковых операций желательно разделять этапы намерения и исполнения. Модель может подготовить предложение, но окончательное решение должен принимать детерминированный контроллер либо человек. Особенно это важно для финансовых данных, персональной информации, договоров, прав доступа и массовых изменений.
Шесть вопросов перед расширением полномочий
Перед production-запуском или увеличением числа доступных инструментов стоит получить чёткие ответы на следующие вопросы:
1. Какой конкретный компонент может изменить внешнее состояние?
2. Где хранятся его credentials и насколько широки эти права?
3. Может ли target-объект быть подменён или изменён по пути?
4. Есть ли независимая проверка непосредственно перед записью?
5. Что произойдёт при повторном запуске, задержке или устаревшем ответе?
6. Можно ли доказать по журналам, почему операция была разрешена?
Если хотя бы на один вопрос нет ясного ответа, полномочия агента расширять преждевременно.
Главный вывод прост: полномочия модели и полномочия всей AI-системы - не одно и то же. Модель может оставаться без доступа к CRM, тогда как оркестратор рядом с ней будет способен изменить любую запись, переданную ему в параметрах.
Надёжная архитектура начинается не с запрета записи в LLM, а с контроля на границе исполнения. Именно перед внешним действием система должна повторно проверить объект, контекст, допустимый переход и актуальность состояния. Только тогда заявление о read-only описывает не отдельный компонент, а реальное поведение всей цепочки.
