Анатомия сбоя ИИ-агента: почему Claude удалил 700 ГБ данных во время теста защитного скрипта
В августе 2026 года инженерное сообщество обсуждало резонансный инцидент с потерей данных разработчика Себастьяна Гиймо. При попытке автоматизировать очистку временных директорий /tmp, засоряемых автономными ИИ-агентами, кодинг-ассистент Claude сгенерировал защитный bash-скрипт. Его запуск привел к внезапному удалению около 700 ГБ файлов из домашней директории пользователя ($HOME). Процесс прервали до полного разрушения системы, восстановив часть проектов из Git, Nix и логов сессий. Инцидент стал наглядным примером того, как сочетание классических ошибок bash и специфики систем безопасности LLM создает критические риски в среде разработки.
Хронология событий: как проверялся отказной сценарий
Автономные агенты создают множество временных файлов и кэшей, быстро переполняющих /tmp. Разработчик поручил ИИ-агенту написать утилиту безопасной очистки с механизмом самотестирования (self-test).
Скрипт должен был гарантированно отклонять попытки удаления каталогов за пределами префикса /tmp. Однако при генерации тестов агент добавил в список проверяемых «опасных путей» реальный домашний каталог пользователя $HOME.
Последовательность шагов сбоя:
- Генерация скрипта с самопроверкой: Агент передал путь
$HOMEв функцию очистки, рассчитывая, что валидатор прервет выполнение с ошибкой. - Некорректный порядок операций: В коде переменная удаляемого каталога инициализировалась до завершения проверки пути по регулярному выражению.
- Срабатывание системной ловушки: Валидатор распознал, что
$HOMEне лежит в/tmp, и вызвал функцию аварийного выхода_pin_die. - Катастрофический cleanup: Выход из скрипта активировал обработчик
trap ... EXIT, где была зарегистрирована командаrm -rfс уже заполненной переменной пути. - Экстренная остановка: Разработчик вручную прервал процесс, однако скрипт успел удалить 700 ГБ рабочих данных и локальных конфигураций.
Разбор бага в коде: почему EXIT trap сработал на уничтожение
В кодовой базе возникла коллизия между механизмом валидации и системным обработчиком завершения процесса. Реконструированный фрагмент логики демонстрирует ошибку:
# 1. Присвоение непроверенного значения переменной очистки
PIN_CANARY="$TMP_REAPER_SELFTEST_CANARY_DIR"
# 2. Проверка пути по белому списку (allowlist)
[[ "$PIN_CANARY" =~ ^/tmp/[^/]+$ ]] || _pin_die
# 3. Функция очистки и регистрация ловушки выхода
pin_cleanup() {
rm -rf -- "$PIN_CANARY"
}
trap pin_cleanup EXIT
Анализ выполнения вскрывает цепочку проблем:
- Загрязнение переменной: Переменная
PIN_CANARYпринимает входящее значение немедленно. При передаче$HOMEпеременная сразу связывается с домашним каталогом. - Отказ проверки: Проверка
[[ "$PIN_CANARY" =~ ^/tmp/[^/]+$ ]]завершается ошибкой для/home/userи вызывает_pin_die. - Семантика GNU Bash: Функция
_pin_dieзавершает работу шелла. По стандарту Bash ловушкаtrap ... EXITсрабатывает всегда при завершении процесса — как успешном, так и аварийном. - Инверсия защиты: Обработчик
pin_cleanupвыполняетrm -rf -- "$PIN_CANARY", уничтожая путь, проверка которого только что завершилась отказом.
Ветка кода, созданная для предотвращения опасных удалений, сама инициировала исполнение деструктивной команды.
Анализ барьеров защиты: матрица уязвимостей
Кажущаяся надежность опиралась на пять уровней защиты, каждый из которых содержал уязвимость:
| Защитный барьер | Предполагаемая роль | Фактическая уязвимость |
|---|---|---|
| Self-test suite | Проверить отклонение недопустимых путей | Направил реальное удаление на рабочий $HOME |
| Regex-валидатор | Заблокировать пути вне /tmp | Значение переменной сохранилось до валидации |
| EXIT trap | Гарантировать удаление мусора | Сработал при аварийном выходе после отказа |
| Подтверждение агента (UI) | Запросить одобрение на команды | Однократное подтверждение запустило весь сценарий |
| Git | Обеспечить восстановление | Не защищает untracked-файлы, ключи и настройки |
Роль LLM и систем безопасности: версия о даунгрейде моделей
В обсуждениях инцидента упоминалась версия о влиянии фильтров безопасности провайдера модели (Anthropic safety harness). По оценке разработчика, при генерации кода защитная система среагировала на слова об удалении файлов и автоматически переключила сессию на более слабую модель (Opus 4.8).
Менее способная модель не удержала в контексте связи между POSIX-ловушками trap и порядком вычислений в Bash, что привело к генерации некорректного кода.
Однако с инженерной точки зрения ключевой вывод иной: сгенерированный скрипт не может служить границей безопасности (security boundary) внутри пользовательской сессии. Текстовые промпты и внутренние проверки в коде не заменяют системную изоляцию ОС.
Принципы проектирования деструктивных скриптов
Разбор инцидента позволяет сформулировать базовые правила написания сценариев с потенциально опасными операциями:
- Не использовать боевые пути в негативных тестах: Проверка отказа должна тестироваться на изолированных одноразовых каталогах или через
dry-runс логированием намерений без вызоваrm. - Разделение валидации и capability: Входные аргументы канонизируются и проверяются в локальных переменных. Переменная для деструктивной команды инициализируется только после успешной валидации.
- Отложенная регистрация
trap: Регистрировать cleanup следует строго после создания временной фикстуры и подтверждения ее принадлежности безопасному корню. - Двухфазное исполнение (Plan and Apply): Скрипт формирует манифест удаляемых объектов, выводит его пользователю и запрашивает подтверждение на конкретный список путей.
- Проверка резервных копий: Регулярные изолированные бэкапы (снапшоты, BorgBackup, Restic) должны регулярно тестироваться на процедуру восстановления.
Практическая изоляция ИИ-агентов
Автономные ассистенты требуют среды с минимальными привилегиями. Домашняя директория ($HOME), ключи SSH/GPG, токены облаков, сокет Docker и конфигурация Kubernetes должны быть скрыты.
Инструменты изоляции на Linux:
- Unprivileged Sandboxing через
bubblewrap(bwrap): Утилита создает изолированные пространства имен (user, pid, mount namespaces) без правroot. Системные библиотеки монтируются через--ro-bindтолько для чтения, а запись разрешается во временный каталог проекта. Попытка обратиться к$HOMEзавершается ошибкой ядра. - Контейнеры и виртуальные машины: Запуск сессий в Docker или MicroVM с пробросом только целевого репозитория.
Чек-лист безопасности для разработчиков
- Агент запускается от выделенного непривилегированного пользователя или в контейнере без доступа к хостовому
$HOME. - Секреты, ключи SSH/GPG и токены облаков исключены из видимости агента.
- Скрипты с командами
rm,mkfs,ddпроходят ручной аудит перед запуском. - Автоматические тесты разрушительных операций выполняются на tmpfs.
- Настроено создание снапшотов и проверено восстановление из бэкапа.

![Node.JS [ru]](/api/digests/it_development/daily/20260901/assets/sources/we-use-js.jpg)