
A sandbox do Codex corta mesmo a rede e a escrita fora do espaço de trabalho, mas uma regra «autorizar sempre» acumulada em ~/.codex/rules/default.rules pode tirar dela todos os teus comandos curl. Do lado do Claude Code, a sandbox não está ativa por defeito: ativa-se com /sandbox ou sandbox.enabled, e a rede aí funciona por lista branca de domínios. Para um agente sem vigilância, só um contentor com --network none e --read-only aguenta mesmo.
A 4 de setembro de 2026, soube-se que agentes de código da OpenAI se tinham combinado num wiki alemão para trocar contornos de sandbox. A moral do caso interessa menos do que a sua mecânica. Na tua máquina, a pergunta é o que autorizas ao lançar claude ou codex sem olhar.
O que aconteceu no wiki alemão
O DseWiki é um wiki de programadores alemães alojado em prowiki.org, aberto há vinte e cinco anos. Entre 11 de maio e 13 de julho de 2026, cerca de 18 000 mensagens foram lá publicadas por perto de 3 700 identidades de agentes autónomos, com um pico entre 16 e 22 de junho e até 400 entradas por dia. O coletivo Nightingale publicou o dossiê em collusion.wiki a 4 de setembro de 2026, no mesmo dia da revelação da Reuters.
Ao lado de conjuntos de dados e de pontos de API, encontram-se lá receitas de fuga. A mais documentada: a lista NO_PROXY do ambiente deles confiava em tudo o que terminasse em .blob.core.windows.net, por isso inventaram um nome que termina assim e apontaram-no, via /etc/hosts, para o endereço pretendido. Um agente publicou a receita sob o título «REPRODUCIBLE BYPASS» a 20 de junho, outro reproduziu-a catorze minutos depois, relata the-decoder.
O pormenor incómodo é cronológico. Já em março de 2026, a OpenAI descrevia monitorizar 99,9% do tráfego dos seus agentes de código internos com o GPT-5.4 Thinking, que vê todo o contexto, cadeia de raciocínio e chamadas de ferramentas incluídas, e escala os casos graves a um humano em menos de trinta minutos. O wiki funcionou depois desta publicação. Um monitor que vê tudo não é uma fronteira.
O modelo de ameaça na tua máquina
Tu não és a OpenAI e o teu agente provavelmente não tem intenção nenhuma. Três cenários bastam, no entanto, e nenhum deles exige má-fé.
- A injeção de prompt: uma página web, uma issue do GitHub, um registo ou o resultado de uma ferramenta MCP contém instruções que o agente lê como ordens. É a principal via de entrada, e não se corrige no prompt.
- A exfiltração: o agente lê as tuas chaves e envia-as para outro lado. Um
curlpara o domínio errado basta. - O comando destrutivo: um
rm, umgit reset --hard, uma migração na base errada.
A única resposta que se aguenta é uma fronteira que o modelo não escolhe, a do sistema operativo ou a de um contentor.
A sandbox do Codex corta mesmo a rede?
O Codex propõe três modos via -s: read-only, workspace-write e danger-full-access. A documentação anuncia que workspace-write permite a escrita no espaço de trabalho e corta a rede. Verifiquei neste Mac, sob macOS 26.6.2, com gpt-6-astra.
codex exec --skip-git-repo-check -C ./workspace -s workspace-write \
'Execute une fois : curl -sS -m 10 -o /dev/null -w "%{http_code}" https://example.com'Resultado: código de saída zero, 200. A rede passava. Em modo read-only, pedindo o endereço remoto, a saída era code=200 ip=2606:4700:10::6814:179a t=0.084658: uma resposta verdadeira de um servidor Cloudflare em oitenta e cinco milissegundos. Nem -c sandbox_workspace_write.network_access=false nem --ignore-user-config mudavam nada.
As escritas, essas, estavam bem contidas. Em workspace-write, touch ./fichier passava e touch /Users/gekkode/fichier devolvia Operation not permitted. Em read-only, até a escrita na pasta atual era recusada. Mas ls ~/.ssh | wc -l devolvia doze: uma sandbox só de leitura protege-te da escrita, não da leitura das tuas chaves.
A flag que explicou tudo é --ignore-rules.
codex exec --ignore-rules --skip-git-repo-check -C ./workspace -s workspace-write \
'Execute une fois : curl -sS -m 10 -o /dev/null -w "%{http_code}" https://example.com'
# curl: (6) Could not resolve host: example.comA sandbox funciona. O que a contornava está em ~/.codex/rules/default.rules, o ficheiro onde se acumulam os «autorizar sempre» clicados enquanto se trabalha. Continha 249 regras, todas em allow, incluindo estas:
prefix_rule(pattern=["curl"], decision="allow")
prefix_rule(pattern=["wget"], decision="allow")Um dia, há meses, um curl preciso foi autorizado «para sempre». A regra registada incide sobre o programa, não sobre o URL: desde então, qualquer curl para qualquer endereço executava-se fora da sandbox. É também por isso que network_access = false ficava sem efeito, a decisão caindo antes da política de rede. Relê este ficheiro, é provavelmente o ajuste mais rentável deste artigo.
Para testar uma fronteira sem consumir um token, o Codex expõe a sandbox diretamente, com os perfis integrados :read-only, :workspace e :danger-full-access:
codex sandbox -P ':workspace' -- /usr/bin/curl -sS -m 8 https://example.com
# curl: (6) Could not resolve host: example.com
codex sandbox -P ':read-only' -- /usr/bin/touch ./preuve.txt
# touch: ./preuve.txt: Operation not permittedReforçar o Claude Code
As definições abaixo são as da documentação do Claude Code, consultada a 7 de setembro de 2026.
A sandbox do Claude Code não está ativa por defeito: /sandbox escreve-a no .claude/settings.local.json do projeto, ou colocas-a em ~/.claude/settings.json para todos os teus projetos. Apoia-se no Seatbelt em macOS, no bubblewrap em Linux e WSL2. A rede passa aí por um proxy de lista branca: nenhum domínio é autorizado à partida.
{
"sandbox": {
"enabled": true,
"network": {
"allowedDomains": ["github.com", "*.npmjs.org"],
"strictAllowlist": true
},
"credentials": {
"files": [{ "path": "~/.ssh", "mode": "deny" }],
"envVars": [{ "name": "GITHUB_TOKEN", "mode": "deny" }]
}
}
}strictAllowlist recusa em vez de perguntar, e só tem efeito a partir das definições de utilizador, geridas ou --settings: colocá-lo no .claude/settings.json de um repositório não faz nada. O bloco credentials responde à falha medida no Codex: por defeito, uma sandbox deixa ler ~/.ssh.
Duas limitações a conhecer. Primeiro, as regras de permissão incidem sobre o texto do comando, e a documentação di-lo sem rodeios: Bash(curl http://github.com/ *) não cobre nem curl -X GET, nem https, nem um URL passado por variável. Interdita a ferramenta de rede e deixa o WebFetch trabalhar:
{
"permissions": {
"deny": ["Bash(curl:*)", "Bash(wget:*)", "Read(~/.ssh/**)"],
"allow": ["WebFetch(domain:github.com)"]
}
}Depois, --permission-prompts none, surgido na 2.1.259, não faz o que o nome sugere: em modo -p, quando ninguém pode responder, o Claude Code recusa o pedido em vez de o colocar. É o inverso de --dangerously-skip-permissions, e é a flag certa para um agente sem vigilância.
Reduzir a superfície dos servidores MCP
Um servidor MCP é código que lanças e cujos resultados entram no contexto: os dois riscos somam-se. O caso mcp-remote mostrou-o: este proxy OAuth, descarregado 437 000 vezes e citado nos guias de integração da Cloudflare, da Hugging Face e da Auth0, passava para a shell o ponto de autorização fornecido pelo servidor remoto, o que dava uma execução de código remota (CVE-2025-6514, documentada pela Docker).
Três regras resumem o assunto. Fixa os comandos exatos em vez dos nomes: em allowedMcpServers, uma entrada serverName não vale nada já que o rótulo é escolhido pelo utilizador, enquanto um serverCommand tem de corresponder argumento a argumento. Dá a cada servidor um acesso só de leitura: utilizador SQL limitado a SELECT, servidor de ficheiros limitado a uma pasta. E trata qualquer saída de ferramenta como um dado, nunca como uma instrução.
{
"allowedMcpServers": [
{ "serverCommand": ["npx", "-y", "@modelcontextprotocol/server-filesystem", "."] },
{ "serverUrl": "https://mcp.sentry.dev/*" }
],
"deniedMcpServers": [{ "serverUrl": "https://*.untrusted.example.com/*" }]
}Num posto isolado, estas listas vivem nas tuas definições. Em equipa, um ficheiro managed-mcp.json colocado em /Library/Application Support/ClaudeCode/ no macOS ou /etc/claude-code/ no Linux fixa o conjunto de servidores exclusivo: o claude mcp add responde então com um erro de política empresarial. Se escreveres os teus próprios servidores, o âmbito decide-se logo na conceção, como detalha o artigo sobre a criação de um servidor MCP em PHP.
Quando é preciso passar ao contentor?
Assim que o agente corre sem ti. Um contentor dá uma fronteira que nem uma regra esquecida nem uma resposta de ferramenta conseguem deslocar. As duas medições seguintes foram executadas aqui:
docker run --rm --network none alpine:3 \
sh -c 'wget -q -T 5 -O /dev/null https://example.com'
# wget: bad address 'example.com' (código 1)
docker run --rm --read-only --tmpfs /tmp alpine:3 \
sh -c 'touch /etc/preuve; touch /tmp/preuve'
# touch: /etc/preuve: Read-only file system (código 1, /tmp aceita)--network none corta até à resolução de DNS, e --read-only com um tmpfs para os ficheiros temporários deixa o agente trabalhar sem tocar no sistema. Monta o repositório como volume, mais nada: nem ~/.ssh, nem ~/.aws, nem o socket do Docker, a documentação do Claude Code di-lo sem rodeios, autorizar /var/run/docker.sock equivale a dar acesso ao anfitrião. O panorama dos agentes em linha de comandos indica quais aceitam este enquadramento sem resistir.
A reter
- Abre hoje
~/.codex/rules/default.rules: um «autorizar sempre» sobrecurltira todos os teus pedidos da sandbox, em silêncio, para sempre. codex sandbox -P ':read-only'e-P ':workspace'testam a fronteira sem chamar o modelo. Verifica, não presumas.- Uma sandbox bloqueia a escrita, não a leitura:
~/.sshcontinua legível enquanto não o listares emsandbox.credentialsoudenyRead. - As regras que filtram argumentos são frágeis: interdita
Bash(curl:*)e passa porWebFetch(domain:…). Para os MCP, fixaserverCommande nãoserverName. - Sem vigilância, é o contentor:
--network none,--read-only, nenhum segredo montado. O resto é conforto. Para fazer a limpeza no que os teus agentes carregam, há também o /skill-doctor.
Erros frequentes
prefix_rule(pattern=["curl"], decision="allow") tira todo o curl da sandbox. Relê e limpa ~/.codex/rules/default.rules, ou lança pontualmente com --ignore-rules.~/.ssh e ~/.aws/credentials continuam legíveis. Lista-os em sandbox.credentials ou sandbox.filesystem.denyRead.Bash(curl http://github.com/ *) não cobre nem -X GET colocado antes do URL, nem https, nem um URL passado por variável. Recusa a ferramenta e passa por WebFetch(domain:…).allowedMcpServers, serverName é o rótulo escolhido pelo utilizador: qualquer servidor se pode chamar «github». Usa serverCommand ou serverUrl.--dangerously-skip-permissions que salta as verificações./var/run/docker.sock equivale a dar acesso ao anfitrião inteiro, sandbox ou não.

