Backends de sandbox
Visão geral dos backends
Seção intitulada “Visão geral dos backends”| Backend | Valor | Plataforma | Disponibilidade |
|---|---|---|---|
| VM fechada | microvm |
macOS, Linux, Windows (hipervisor de microVM) | Condicionado à sondagem do runtime de microVM; aplica-se a terminais interativos — o shell roda dentro de um rig, não no host |
| Nativo | native |
macOS (Seatbelt), Linux e WSL2 (bubblewrap) | Sondado na inicialização; o Linux recusa uma execução que exija negações de escrita por glob de nome de arquivo, que o bubblewrap não consegue aplicar |
| Nenhum | none |
Todos | O padrão da análise, o padrão do terminal e o fallback quando nenhum backend está disponível ou --sandbox off está definido |
SandboxBackend.fromName retorna none para um valor armazenado nulo ou não reconhecido. Um "docker" armazenado é mapeado para native.
microvm é o único backend com fronteira de kernel — a carga de trabalho
genuinamente não roda no host. Ele nunca é um fallback silencioso em nenhuma das
direções: pedi-lo explicitamente em um host que não consegue inicializar uma VM
falha de forma ruidosa (“pedi uma VM e recebi meu notebook” é a única degradação
que o recinto não pode se permitir), e apenas um padrão não especificado
recorre a native, com uma linha de log dizendo isso. O backend real da sessão é
reportado de volta ao cliente e recebe um selo, então um terminal nunca pode
alegar estar fechado enquanto roda no host. Ciclo de vida, imagens e saída de rede
da própria VM estão cobertos pela referência de rigs.
O Windows não tem sandbox nativo. NativeSandboxAdapter.probe retorna available: false em todo host que não seja macOS ou Linux/WSL2. O despacho de agentes no Windows, portanto, usa none. O backend microvm é separado: ele é condicionado à sondagem do runtime de microVM e se aplica a terminais interativos e rigs, não a envolver o bash no host.
Resultados da sondagem
Seção intitulada “Resultados da sondagem”A sondagem é o que condiciona a aplicação. Ela roda uma vez, na inicialização do servidor.
| Host | available |
Nota / dica |
|---|---|---|
| macOS | true |
sandbox-exec (Seatbelt) — isolamento de namespace, sem fronteira de kernel |
Linux ou WSL2 com bwrap e socat |
true |
bubblewrap — isolamento de namespace, sem fronteira de kernel |
| Linux ou WSL2 sem qualquer uma das ferramentas | false |
requiresInstall: true, com uma dica de instalação que nomeia os pacotes ausentes |
| Qualquer outra plataforma | false |
O sandbox nativo não é oferecido nesta plataforma |
O servidor registra o resultado em uma única linha de inicialização: agent sandbox ON mais a nota, no OS-native agent sandbox on this host mais a dica, ou agent sandbox DISABLED by --sandbox off. GET /healthz não carrega nenhum campo de sandbox.
--sandbox / CC_SERVER_SANDBOX aceita on (padrão) ou off. É uma desativação explícita, não uma habilitação: on significa “envolver quando o host oferecer um backend”, nunca “exigir um”.
Backend nativo
Seção intitulada “Backend nativo”macOS: Seatbelt
Seção intitulada “macOS: Seatbelt”Usa o mecanismo de sandbox Seatbelt da Apple (o mesmo sistema usado pelo App Sandbox do macOS).
O perfil gerado é permissivo por padrão ((allow default)) e recorta negações, porque um perfil totalmente de negação por padrão torna um shell interativo inutilizável — há chamadas demais de dyld, XPC e Mach para enumerar. A consequência prática é que um agente ainda consegue ler a maior parte do host; seus checkouts registrados são protegidos por negações explícitas de escrita e de renomeação, não por invisibilidade.
- Leituras do sistema de arquivos: negadas para os caminhos secretos (
~/.ssh,~/.aws,~/.gnupg,~/.config/gh,~/Library/Keychainse o resto do conjunto de leitura negada) - Escritas no sistema de arquivos: redefinidas para negar e depois permitidas em subcaminhos explícitos, com os caminhos de negação obrigatória (arquivos rc do shell,
.git/hooks, a configuração do Claude, checkouts protegidos) bloqueados mesmo dentro de uma raiz gravável.file-write-unlinké negado em todo caminho negado e em seus ancestrais, de modo que uma renomeação não pode contornar uma negação de escrita - Processos: negações de
process-execpara os binários sempre perigosos, além de um bloqueio à execução de qualquer coisa a partir de um diretório gravável - Rede: restrita às portas do proxy em processo mais o DNS — o loopback não é permitido de forma irrestrita e sockets Unix não são permitidos. Os proxies aplicam a lista de permissões de domínios por sessão (veja Saída de rede)
- Configuração: os perfis são gerados a cada inicialização a partir do
SandboxSpec
Requisitos:
sandbox-exec(/usr/bin/sandbox-exec), presente em toda instalação do macOS — nenhuma ferramenta adicional é necessária
Linux: bubblewrap
Seção intitulada “Linux: bubblewrap”Usa o bubblewrap (bwrap) para criar namespaces de montagem e de PID.
- Sistema de arquivos: cria um namespace de montagem com apenas os caminhos vinculados visíveis
- Rede: roda em um namespace de rede não compartilhado; o tráfego chega aos proxies do host por pontes de socket Unix do
socat - Processos: isolamento de namespace de PID
Requisitos:
bubblewrapesocatinstalados (sudo apt-get install bubblewrap socatno Debian/Ubuntu)- Suporte a namespaces do kernel (padrão no Linux moderno)
O bubblewrap consegue ocultar um caminho existente, mas não consegue proibir um arquivo .env, *.key ou *.pem novo dentro de um bind gravável. A política de despacho padrão exige essas negações por glob de nome de arquivo, então o despacho nativo de agentes hoje falha de forma fechada no Linux/WSL2 mesmo quando a sondagem encontra o bubblewrap. Ele não roda com uma política silenciosamente mais fraca. É preciso um backend com regras de nome de arquivo no momento da criação para restaurar o despacho nativo no Linux. Desativar o sandbox é uma desativação explícita e sem confinamento, não uma alternativa equivalente.
Backend none
Seção intitulada “Backend none”Nenhum sandbox. O processo roda diretamente no host, com o acesso a sistema de arquivos, rede e processos do host. O ACP e a ferramenta bash do harness ainda recebem a sanitização do ambiente e a política de comandos; o Claude Code pelo NoSandboxAdapter herda o ambiente do host. É para isso que o despacho de agentes recorre em um host sem backend disponível ou com --sandbox off, e é o padrão do terminal quando um cliente não nomeia nenhum.
Terminal hospedado no servidor
Seção intitulada “Terminal hospedado no servidor”O terminal roda em sandbox nos próprios termos, não pela sondagem do despacho. O defaultBackend de TerminalSessionService é none e o cc_server não o sobrescreve, então uma sessão de terminal executa o shell do host a menos que o cliente peça native explicitamente — o painel de terminal do desktop não pede.
Quando native é solicitado, o shell é envolvido pelo SandboxManager sob um perfil de terminal fixo: $HOME e o diretório de trabalho da sessão são graváveis, a rede fica aberta e a leitura de ~/.ssh, ~/.aws, ~/.gnupg, ~/.config/gh e ~/Library/Keychains é negada. O token de forge somente leitura e o gateway de push não se aplicam — são questões do despacho. Se o envolvimento não for suportado, a sessão falha em vez de mostrar um selo nativo sobre um PTY do shell do host.
Saída de rede
Seção intitulada “Saída de rede”Quando um sandbox é iniciado, o acesso de rede de saída é aplicado por proxies em processo, não por regras de firewall do kernel. Em um host sem backend disponível nada disso se aplica, e um processo gerado chega à rede exatamente como o próprio usuário do servidor chegaria.
- O runtime do sandbox executa um proxy HTTP/HTTPS e um proxy SOCKS5 em
127.0.0.1dentro do processo docc_server, um par por sessão restrita (http_proxy.dart,socks_proxy.dart). Execuções simultâneas não compartilham um par. - Processos em sandbox recebem variáveis de ambiente de proxy (
HTTP_PROXY/HTTPS_PROXY→ o proxy HTTP,ALL_PROXY→ o proxy SOCKS;GIT_SSH_COMMANDencaminha git-over-SSH pelo proxy SOCKS). No Linux o namespace de rede não é compartilhado, então os proxies são a única saída; no macOS o sandbox compartilha o loopback do host e fala com eles diretamente. - O host de destino de cada conexão é comparado com a lista de permissões de domínios da sessão; qualquer outra coisa é negada. Há duas formas de curinga, cada uma com exatamente um
*: um*.example.comno início casa com qualquer subdomínio (incluindoa.b.example.com), mas não com o próprio domínio raiz; umbedrock.*.amazonaws.comcom rótulo no meio casa exatamente com um rótulo (bedrock.us-east-1.amazonaws.com, nãobedrock.evil.attacker.amazonaws.com). - A lista de permissões é resolvida por sessão a partir da base curada (
kBaselineAllowedDomains: provedores de LLM, hospedagem de Git, registros de pacotes), mais os domínios do GitHub (kGithubDomains), maisSandboxSpec.egressAllowlist. O caminho de despacho nunca passa entradas extras deegressAllowlist, então na prática toda execução recebe a base mais o GitHub. - Uma lista fixa de negação (
kBaselineDeniedDomains: endpoints de metadados de nuvem, destinos de telemetria) tem precedência sobre todas as permissões. networkEnabled: falseainda inicia os proxies por sessão, mas a lista de permissões fica vazia, então toda conexão de saída é recusada. O despacho o define quando a execução começa a partir da regra Acessar a rede: negar desliga a rede; permitir e perguntar primeiro a mantêm ligada.
SandboxSpec
Seção intitulada “SandboxSpec”A especificação passada para SandboxPort.launch:
| Campo | Tipo | Descrição |
|---|---|---|
sessionId |
String |
Identificador estável da sessão (normalmente o id do espaço) |
workspaceId |
String |
Id do espaço de trabalho proprietário |
agentId |
String? |
Agente atualmente vinculado ao sandbox, se houver |
bindMounts |
List<SandboxBindMount> |
Montagens host→guest; o sandbox vê apenas os caminhos do host listados aqui |
networkEnabled |
bool (padrão true) |
Definido no despacho a partir da regra de saída de rede (desligado só quando ela resolve para negar). Quando desativado, os proxies por sessão ainda iniciam, mas a lista de permissões fica vazia, então toda conexão de saída é recusada |
egressAllowlist |
List<String> (padrão []) |
Domínios de saída adicionais permitidos; curingas são suportados (*.example.com, além de uma forma intermediária de um único rótulo). O despacho nunca preenche isto, então uma execução envolvida recebe a base curada mais os domínios do GitHub |
guestWorkdir |
String? |
Diretório de trabalho padrão dentro do sandbox; chamadas exec individuais podem sobrescrevê-lo |
mode |
Mode (padrão chat) |
Recorta as regras de escrita do sistema de arquivos: chat mantém as montagens bind graváveis; review, plan e orchestrate são somente leitura |
protectedPaths |
List<String> (padrão []) |
Caminhos do host que nunca podem ser graváveis dentro do sandbox, em nenhum modo |
runnerStateDirs |
List<String> (padrão []) |
Diretórios do host onde o runner mantém o próprio estado, graváveis em todos os modos (um CLAUDE_CONFIG_DIR gerenciado pelo Control Center é o atual) |
execGrantRoots |
List<String> (padrão []) |
Árvores de diretórios aprovadas pelo operador que reabrem o bloqueio de exec em diretórios graváveis no macOS. O Linux as ignora — o bwrap não tem nenhum bloqueio de exec em $HOME a reabrir |
protectedPaths contém os checkouts originais dos repos registrados, resolvidos a cada despacho a partir dos repos do espaço de trabalho. Os agentes trabalham exclusivamente em worktrees de copy-on-write por conversa, então os originais nunca podem ser graváveis de dentro do sandbox — no macOS, a permissão geral de escrita do Seatbelt sobre $HOME os deixaria graváveis via bash caso contrário. Eles se juntam ao conjunto de negação de escrita de segredos em todos os modos, chat incluído.
Todo caminho de leitura negada e de escrita negada é emitido tanto na sua forma literal quanto na sua forma resolvida por symlink. O kernel casa uma regra de negação com o caminho resolvido, então uma regra escrita contra um caminho com symlink nunca dispara — e no macOS esse é o caso comum, e não o exótico, já que /tmp resolve para /private/tmp e /var/folders/… para /private/var/folders/…. Entradas que contêm * ou ? são tratadas como globs e deixadas como estão; um caminho que não resolve é mantido como escrito.
SandboxBindMount
Seção intitulada “SandboxBindMount”| Campo | Tipo | Descrição |
|---|---|---|
hostPath |
String |
Caminho absoluto no host |
guestPath |
String |
Caminho dentro do sandbox (com o sandbox nativo isto é igual a hostPath; mantido por simetria entre adaptadores) |
readOnly |
bool (padrão false) |
Monta como somente leitura quando verdadeiro |
SandboxHandle
Seção intitulada “SandboxHandle”Retornado por SandboxPort.launch:
| Campo | Tipo | Descrição |
|---|---|---|
sessionId |
String |
Identificador da sessão |
backend |
SandboxBackend |
Qual backend está rodando |
state |
SandboxState |
Estado de ciclo de vida |
error |
Object? |
Definido quando state é error |
details |
Map<String, Object?> |
Contabilidade interna do adaptador (diretório de trabalho, PID, caminho do perfil etc.) |
SandboxState
Seção intitulada “SandboxState”| Estado | Descrição |
|---|---|
created |
Especificação criada, mas a VM ainda não iniciou |
warm |
Em execução e pronta para executar comandos |
active |
Executando um comando no momento |
suspended |
Pausado / com checkpoint em disco para economizar RAM |
destroyed |
Desmontado; o handle não é mais válido |
error |
A inicialização falhou — veja SandboxHandle.error |
Eventos do sandbox
Seção intitulada “Eventos do sandbox”| Tipo de evento | Descrição |
|---|---|
stdout |
Saída padrão do sandbox |
stderr |
Erro padrão do sandbox |
exit |
O processo do sandbox saiu (carrega exitCode) |
starting |
O sandbox está iniciando |
ready |
O sandbox está pronto para aceitar chamadas exec |
killed |
Processo morto pelo host (OOM, timeout, parada manual) |
violation |
Uma política do sandbox foi violada (carrega um SandboxViolation) |
SandboxViolation
Seção intitulada “SandboxViolation”| Campo | Tipo | Descrição |
|---|---|---|
action |
String |
O verbo negado (por exemplo, file-read*, network-outbound) |
target |
String |
Caminho ou host que foi alvo da operação negada |
raw |
String? |
Linha de log bruta, útil para depuração |
Veja também
Seção intitulada “Veja também”- Sandbox e segurança
- Políticas de sandbox
- Barreiras
- CLI do cc_server: a flag
--sandbox