Песочница и безопасность
Почему изоляция здесь важна
Заголовок раздела «Почему изоляция здесь важна»Агент читает файлы, выполняет команды оболочки и вызывает внешние API от вашего имени. Сбой, который вас волнует, редко бывает злым умыслом — это агент, который неверно понял путь и переписал вашу рабочую копию, или тот, который отправил ветку, которую вы ещё не успели проверить. Поэтому вопрос, на который должен ответить продукт, — не «можно ли доверять агенту», а «каков радиус поражения, когда он ошибается».
Control Center отвечает на него слоями, и слои независимы намеренно. Если одного не хватает, остальные продолжают держать. Это важно, потому что самый внешний слой — песочница ОС — единственный условный: он зависит от того, предлагает ли хост бэкенд, а в Windows этого не делает ни один хост.
Что на самом деле ограничивает агента
Заголовок раздела «Что на самом деле ограничивает агента»Пять вещей ограничивают запуск агента на любом хосте, с песочницей или без. Ни одна из них не является границей ядра; все они настоящие. Там, где хост предлагает бэкенд, песочница ОС стоит над ними, а раздел «Что добавляет песочница и где она останавливается» ниже описывает, что это меняет.
Собственный worktree с копированием при записи. Каждый разговор создаёт себе
рабочую копию каждого связанного репозитория, клонированную с копированием при
записи через встроенный нативный rift, а не скопированную побайтово, поэтому
изоляция достаточно дешева, чтобы быть поведением по умолчанию. Зарегистрированный
репозиторий, который вы добавили в рабочее пространство, — не тот каталог, в
котором работает агент: два разговора, затрагивающих один репозиторий, не видят
правок друг друга, и ни один из них не редактирует вашу рабочую копию.
Гранулярность стоит уточнить: worktree привязан к разговору, а не к агенту.
Два агента в одном разговоре получают разные рабочие каталоги оверлея, которые
совместно используют каталог repos/ этого разговора — в этом и смысл, ведь они
вместе работают над одним изменением, — а их личные каталоги агентов остаются
раздельными. Копирование при записи — единственный бэкенд везде, где поставляется
rift: файловая система, не умеющая reflink, или каталог данных на другом томе,
чем репозиторий, приводят к сбою выделения, а не к откату. Windows — исключение:
бэкенда с копированием при записи там нет, поэтому бэкендом служит git worktree,
и это не тихое ухудшение.
Привязка к путям в файловых инструментах встроенного харнесса. Инструменты
харнесса read, write, edit, apply_patch, search, find и search_files
разрешают каждый путь относительно рабочего каталога запуска плюс общих корней —
каталога repos/ разговора, где лежат worktree, и каталога вложений пространства,
когда он существует, — и отказывают во всём, что выходит наружу. Абсолютные пути
принимаются, только если они уже были внутри. Символическая ссылка внутри
worktree, указывающая наружу, тоже разрешается и отклоняется. Именно поэтому агент
не может выполнить write в ~/.ssh, даже когда песочницы в картине нет.
Поверхность инструментов режима. Режим
разговора решает, какие инструменты вообще материализуются для запуска. В режимах
только для чтения (plan, review, orchestrate) изменяющие инструменты просто
отсутствуют в реестре, а политика команд оболочки для этих режимов отклоняет любую
изменяющую команду сразу — git commit, git push, npm install, docker и
остальные — вместо запроса подтверждения. Инструмент, которого нет, нельзя
вызвать, и это более сильная гарантия, чем инструмент, который есть, но проходит
через шлюз.
Единые ограничения действий. Каждый изменяющий инструмент объявляет классы
эффектов, которые он может произвести, а движок политик до выполнения вызова
решает по каждому из них: разрешить, запросить подтверждение или отклонить.
Решение prompt без подключённого подтверждающего превращается в отказ —
вопрос, на который никто не может ответить, никогда не становится «да». Модель
разрешения описана в разделе
Ограничения.
Учётные данные от брокера и очищенное окружение. Учётные данные выпускаются при каждом запуске и отзываются, когда запуск завершается, а токен GitHub, который есть у запуска, позволяет читать, но не делать push, — см. «Push проходит через Control Center» ниже. ACP, bash харнесса и Claude Code под
нативной обёрткой получают окружение, очищенное от векторов внедрения через
динамический компоновщик и интерпретатор (LD_PRELOAD, DYLD_INSERT_LIBRARIES,
NODE_OPTIONS, GIT_SSH_COMMAND и им подобных), прежде чем процесс запустится.
Claude Code через NoSandboxAdapter наследует окружение хоста.
Где эти границы слабеют
Заголовок раздела «Где эти границы слабеют»Файловые инструменты харнесса выполняются в процессе сервера, а не в дочернем
процессе, поэтому никакой профиль песочницы не смог бы их ограничить, даже если бы
был к ним привязан, — через обёрнутый исполнитель команд проходит только bash.
Их граница — та самая проверка путей, описанная выше, и поэтому эта проверка
несущая, а не вторая линия обороны.
Инструмент bash — другое место, где нужна точность. Его команды оцениваются по
политике команд режима, а затем запускаются с очищенным окружением и worktree в
качестве рабочего каталога. Там, где бэкенд есть, этот запуск обёрнут, поэтому
именно песочница не даёт команде оболочки писать вне worktree; там, где его нет —
в Windows или в Linux без bwrap и socat — политика команд остаётся единственным,
что стоит между командой и остальным диском. В режиме chat политика жёстко
отклоняет фиксированный список (повышение привилегий, уничтожение системы и диска,
побег из контейнера и пространства имён) и запрашивает подтверждение для изменений
удалённого состояния (git push, gh pr create, публикации и установки пакетов).
Всё, чего нет ни в одном списке, выполняется. Конвейеры, цепочки и подоболочки
разбираются, и каждая подкоманда оценивается отдельно, а побеждает самое строгое
решение.
Claude Code, когда он используется как адаптер, — это случай, где песочница несёт
наибольший вес. Control Center запускает его с --dangerously-skip-permissions,
потому что неинтерактивный claude -p иначе навсегда завис бы на собственном
запросе подтверждения. Его вызовы чтения, записи и редактирования происходят внутри собственного процесса, и Control Center их никогда не видит. Его вызовы Bash перед выполнением отправляются в хук на сервере, который классифицирует командную строку и спрашивает соответствующее правило, а инструменты mcp__*, которые обслуживает Control Center, проходят через шлюз как обычно. Там, где бэкенд есть, эти невидимые вызовы всё
равно происходят внутри обёртки песочницы, поэтому границей вокруг них служит ОС.
Там, где его нет, нет и границы. Каждый адаптер указывает это в своей матрице
соблюдения — см. матрицу честности
адаптеров.
Push проходит через Control Center
Заголовок раздела «Push проходит через Control Center»Флагов разрешений для отдельных агентов нет. Может ли агент создать коммит, сделать push, открыть pull request, писать во внешний трекер или выходить в сеть, решают ограничения — разрешить, спросить сначала или запретить, — и одни и те же правила действуют независимо от того, какой адаптер запускает агента.
Push — это действие, которое должно выдерживать даже агента, пытающегося обойти
правило, поэтому его обеспечивают тем, что у агента есть, а не тем, что он
запускает. При настроенном GitHub App запуск в worktree GitHub получает токен
установки с областью действия на репозиторий, который может читать содержимое и
работать с pull request, но не может делать push. Конфигурация git запуска
переписывает каждый URL для push в GitHub (https://github.com/,
git@github.com:, ssh://git@github.com/) на шлюз запусков агентов —
loopback-эндпоинт в cc_server. Шлюз читает, какие ref обновляет push,
спрашивает правило Отправить в удалённый репозиторий — так что правило,
ограниченное ветками, например «запретить push в main», тоже действует, — и
только потом передаёт push в GitHub с токеном записи, который выпускает для этой
цели и никогда не отдаёт агенту. Отклонённый push виден в собственном выводе
git:
! [remote rejected] main -> main (Control Center policy: …)Шлюз передаёт push только в собственный репозиторий worktree или в репозиторий GitHub, связанный с рабочим пространством. Fetch идёт прямо в GitHub с токеном чтения.
Остальные команды оболочки встречают более мягкий шлюз. Инструмент bash
харнесса и, через хук, инструмент Bash Claude Code классифицируют каждую
командную строку и спрашивают правило, под которое она подпадает: git commit,
merge, rebase, cherry-pick, revert и am — это Создать коммит;
gh pr create — Открыть pull request; gh pr merge, review, comment и
close — Опубликовать ревью или слияние; gh issue create, edit,
comment и close — Писать во внешний трекер; установка пакетов —
Установить пакет; curl и wget — Обращаться к сети. Это распознаёт
привычную запись действия, и агент, решивший его спрятать (eval, файл со
скриптом, прямой вызов API), сможет это сделать. Push от этого не зависит.
API-ключ тикетов в песочницу не попадает. Агенты пишут тикеты через MCP-инструменты Control Center, которые спрашивают правило Писать во внешний трекер.
Правило Обращаться к сети читается один раз, при старте запуска. Сеть
песочницы либо включена, либо выключена, поэтому запрет выключает её, а
разрешить и спросить сначала оставляют включённой; инструменты харнесса
web_fetch и web_search по-прежнему спрашивают при каждом вызове. Учётные
данные отзываются, когда запуск сворачивается, вместе со всеми токенами записи,
выпущенными шлюзом, поэтому дескриптор не переживает запуск.
Что добавляет песочница и где она останавливается
Заголовок раздела «Что добавляет песочница и где она останавливается»Перечисление SandboxBackend содержит три значения — native (Seatbelt в macOS,
bubblewrap в Linux и WSL2), none и microvm. Обёртка команд агента использует
только первые два: microvm — это бэкенд изолированной виртуальной машины для
интерактивных терминалов и Rigs, а не тихое улучшение обёртки bash. Понимание
нативной формы объясняет, что вы получаете там, где она подключена, и чего она
никогда не собиралась давать.
cc_server опрашивает хост один раз при запуске, и там, где бэкенд отзывается, он
питает оба стыка пути диспетчеризации, потому что транспорты не делят один. Первый
(SandboxPort) оборачивает CLI Claude Code. Второй (SandboxManager) оборачивает
адаптеры ACP и инструмент bash встроенного харнесса. Питание только одного
оставило бы остальных запускаться без обёртки — именно это и происходило раньше. На
хосте без бэкенда или при --sandbox off все они запускаются без обёртки, и сервер
в строке запуска сообщает, какой у вас случай. ACP и bash харнесса всё равно
очищают окружение; Claude Code через NoSandboxAdapter наследует окружение хоста.
Одна поверхность намеренно выходит из этой схемы: терминал, размещённый на сервере,
принимает аргумент бэкенда для каждой сессии, а cc_server создаёт его со значением
по умолчанию — оболочка хоста, поэтому терминал, открытый из приложения, работает
без песочницы, если клиент явно не назовёт native. Это настоящая оболочка на хосте
сервера, а не запуск агента.
В Linux bubblewrap строит пространство имён монтирования, поэтому агент
действительно видит только то, что было в него смонтировано. В macOS sandbox-exec
применяет профиль Seatbelt, который по умолчанию разрешающий — полностью
запрещающий по умолчанию профиль делает интерактивную оболочку непригодной, потому
что перечислить все вызовы dyld, XPC и Mach непрактично. Поэтому профиль macOS
начинается с (allow default) и вырезает запреты: чтение секретных путей, политика
записи, сброшенная в запрет с явными разрешениями поверх, блокировка unlink для
каждого запрещённого пути и его предков, чтобы переименование не обошло запрет
записи, запреты exec для всегда опасных бинарников и для всего, что скопировано в
записываемый каталог, и сеть, ограниченная портами loopback-прокси плюс DNS.
Практическое следствие: в Linux представление агента о файловой системе сужается; в macOS агент всё ещё может читать большую часть хоста, а ваши зарегистрированные рабочие копии защищены явными запретами записи и переименования, а не невидимостью. И то и другое — изоляция на уровне пространств имён, а не граница безопасности ядра; сами бэкенды говорят об этом в своих заметках о возможностях.
Набор bind-монтирований — это то место, где проводится граница между агентами.
Оверлейная диспетчеризация (Claude Code и ACP) монтирует до четырёх путей,
определяемых для каждого запуска: рабочий каталог оверлея агента для чтения и
записи, каталог конфигурации агента только для чтения, общий каталог repos/
разговора для чтения и записи, когда он существует, и каталог вложений пространства
только для чтения, когда он существует. Каталог соседнего агента не монтируется
никогда. Обёртка bash харнесса уже: она bind-монтирует только рабочий каталог
запуска. Это та же форма, которую внутрипроцессная проверка путей харнесса
обеспечивает программно, поэтому обе согласуются — но только проверка путей
покрывает собственные файловые инструменты харнесса, которые вообще никогда не
доходят до пространства имён монтирования.
Ваши зарегистрированные рабочие копии добавляются к набору с запретом записи сверх
этого, в каждом режиме и на всех трёх обёрнутых путях (Claude Code, ACP, bash
харнесса), и каждое правило выдаётся в двух написаниях — буквальном и после
разрешения символических ссылок. Второе написание не любезность: ядро сопоставляет
правило запрета с разрешённым путём, а macOS делает разрешение обычным случаем, а не
экзотическим — /tmp на самом деле /private/tmp, /var/folders/… на самом деле
/private/var/folders/… — поэтому рабочая копия, до которой добрались через любой
из них, оставалась бы записываемой, пока профиль якобы её запрещал.
Сеть под песочницей — это доменный список разрешённых для каждой сессии,
обеспечиваемый внутрипроцессными loopback-прокси. Исходящие подключения по
умолчанию запрещены: при выключенной сети прокси всё равно запускаются, но их
список разрешённых пуст, поэтому любое исходящее подключение отклоняется. При
включённой резолвер строит список разрешённых из подобранной базовой линии —
провайдеры LLM API, хостинг git, реестры пакетов, каталог моделей — плюс домены
GitHub, и сверяет целевой хост каждого подключения с ним. Шаблоны работают
(*.example.com совпадает с поддоменами, но не с самим доменом). Отдельный
всегда запрещённый список имеет приоритет над списком разрешённых и покрывает
конечные точки метаданных облака и приёмники телеметрии. Чего нельзя
настроить — это сам список: спецификация несёт поле egressAllowlist для
дополнительных доменов, но ничто на пути диспетчеризации его не заполняет,
поэтому на практике каждый запуск получает базовую линию плюс GitHub и ничего
больше.
Отказы в macOS наблюдаемы: монитор считывает из системного журнала отказы Sandbox,
фильтрует известный шум, дедуплицирует штормы повторных попыток и выводит каждый
как SandboxViolation, называющий, что было предпринято и что было заблокировано. В Linux путь обёртки разбирает stderr на EPERM,
Operation not permitted и Permission denied и выдаёт тот же тип события —
обращения к системному журналу там нет. Они приходят в собственный поток событий
запуска, поэтому отклонённый системный вызов виден в транскрипте, а не только в
журнале. Телеметрия существует только пока нативная песочница действительно
оборачивает процесс — на хосте без бэкенда наблюдать нечего. Она также не связана с ограничениями: нарушение происходит из отклонённого системного вызова, а никогда из обращения к правилу.
Подтверждения исходят от ограничений, а не от песочницы
Заголовок раздела «Подтверждения исходят от ограничений, а не от песочницы»У песочницы нет пути подтверждения. Она запускается, выполняет, выдаёт события и сворачивается; в ней нет места, где человек мог бы ответить на вопрос. Когда вы видите подтверждение в пространстве — подтвердите эту отправку, подтвердите это удаление — его поднял движок ограничений (или политика команд харнесса) до того, как действие вообще дошло до среды выполнения.
Этот порядок намеренный. Подтверждение, случившееся после системного вызова, было бы записью аудита, а не шлюзом. Именно поэтому правило отказа по умолчанию живёт в ограничениях: при отсутствии подключённого подтверждающего решение принимается до того, как что-либо запустится, и это отказ.
Диагностика
Заголовок раздела «Диагностика»Запустить диагностику агента — единственное место, где сказано, что можно проверить вручную.
Связанные понятия
Заголовок раздела «Связанные понятия»- Rigs и изолированные среды: шаг над песочницей — когда работе нужна целая одноразовая машина с границей ядра, а не обёрнутый процесс
- Ограничения: слой политик над системным полом и то, откуда на самом деле берутся подтверждения
- Жизненный цикл запуска агента: где изоляция встраивается в поток диспетчеризации
- Режимы: как режим сужает поверхность инструментов и политику команд
- Справка по бэкендам песочницы: бэкенды и их конфигурация
Связанные руководства
Заголовок раздела «Связанные руководства»- Настроить политики песочницы: правила действий, контроль push и режим работы с файловой системой
- Запустить диагностику агента: что покрывают диагностические проверки