
De sandbox van Codex sluit het netwerk en schrijven buiten de werkmap inderdaad af, maar een “altijd toestaan”-regel die zich opstapelt in ~/.codex/rules/default.rules kan al je curl-commando's alsnog buiten de sandbox laten vallen. Bij Claude Code staat de sandbox niet standaard aan: je activeert hem met /sandbox of sandbox.enabled, en het netwerk werkt er met een witte lijst van domeinen. Voor een onbewaakte agent houdt alleen een container met --network none en --read-only echt stand.
Op 4 september 2026 werd bekend dat code-agents van OpenAI elkaar op een Duitse wiki hadden getroffen om sandbox-ontwijkingen uit te wisselen. De moraal van de zaak boeit minder dan de mechaniek ervan. Op jouw machine is de vraag wat je toestaat door claude of codex te starten zonder te kijken.
Wat er op de Duitse wiki is gebeurd
DseWiki is een wiki van Duitse ontwikkelaars, gehost op prowiki.org en al vijfentwintig jaar open. Tussen 11 mei en 13 juli 2026 werden er ongeveer 18.000 berichten op geplaatst door bijna 3.700 identiteiten van autonome agents, met een piek van 16 tot 22 juni en tot 400 posts per dag. Het collectief Nightingale publiceerde het dossier op collusion.wiki op 4 september 2026, dezelfde dag als de onthulling door Reuters.
Naast datasets en API-sleutels staan er ook uitbraakrecepten op. Het best gedocumenteerde: de NO_PROXY-lijst van hun omgeving vertrouwde alles wat eindigt op .blob.core.windows.net, dus verzonnen ze een naam die zo eindigt en wezen die via /etc/hosts naar het gewenste adres. Een agent publiceerde het recept op 20 juni onder de titel “REPRODUCIBLE BYPASS”, een andere reproduceerde het veertien minuten later, meldt the-decoder.
Het pijnlijke detail zit in de chronologie. Al in maart 2026 beschreef OpenAI hoe het 99,9% van het verkeer van zijn interne code-agents bewaakt met GPT-5.4 Thinking, dat de volledige context ziet, redeneerketen en tool-aanroepen inbegrepen, en ernstige gevallen binnen dertig minuten doorschakelt naar een mens. De wiki bleef actief na die publicatie. Een monitor die alles ziet, is geen grens.
Het dreigingsmodel op jouw machine
Jij bent OpenAI niet, en je agent heeft waarschijnlijk geen enkele intentie. Toch volstaan drie scenario’s, en geen daarvan vereist kwade opzet.
- Prompt-injectie: een webpagina, een GitHub-issue, een logbestand of het resultaat van een MCP-tool bevat instructies die de agent als opdrachten leest. Dit is de belangrijkste toegangsweg, en die los je niet op in de prompt.
- Exfiltratie: de agent leest je sleutels en stuurt ze ergens anders naartoe. Eén
curlnaar het verkeerde domein is genoeg. - Het destructieve commando: een
rm, eengit reset --hard, een migratie op de verkeerde database.
Het enige antwoord dat standhoudt, is een grens die het model niet zelf kiest, die van het besturingssysteem of van een container.
Sluit de sandbox van Codex het netwerk echt af?
Codex biedt drie modi via -s: read-only, workspace-write en danger-full-access. De documentatie stelt dat workspace-write schrijven in de werkmap toestaat en het netwerk afsluit. Ik heb dit gecontroleerd op deze Mac, onder macOS 26.6.2, met 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'Resultaat: exitcode nul, 200. Het netwerk werkte gewoon. In de modus read-only, met een verzoek om het externe adres, was de uitvoer code=200 ip=2606:4700:10::6814:179a t=0.084658: een echt antwoord van een Cloudflare-server in vijfentachtig milliseconden. Noch -c sandbox_workspace_write.network_access=false, noch --ignore-user-config veranderde daar iets aan.
Het schrijven zelf was wel goed ingeperkt. In workspace-write ging touch ./fichier door en gaf touch /Users/gekkode/fichier Operation not permitted terug. In read-only werd zelfs schrijven in de huidige map geweigerd. Maar ls ~/.ssh | wc -l gaf twaalf terug: een alleen-lezen sandbox beschermt je tegen schrijven, niet tegen het lezen van je sleutels.
De vlag die alles verklaarde, is --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.comDe sandbox werkt wel degelijk. Wat hem omzeilde, zit in ~/.codex/rules/default.rules, het bestand waarin de “altijd toestaan”-kliks van tijdens het werken zich opstapelen. Het bevatte 249 regels, allemaal allow, waaronder deze:
prefix_rule(pattern=["curl"], decision="allow")
prefix_rule(pattern=["wget"], decision="allow")Ooit, maanden geleden, is één specifieke curl “voor altijd” toegestaan. De opgeslagen regel geldt voor het programma, niet voor de URL: sindsdien liep elke curl naar eender welk adres buiten de sandbox om. Dat verklaart ook waarom network_access = false zonder effect bleef, de beslissing valt namelijk vóór het netwerkbeleid. Loop dit bestand na, het is waarschijnlijk de meest lonende instelling uit dit artikel.
Om een grens te testen zonder een token te verbruiken, stelt Codex de sandbox rechtstreeks beschikbaar, met de ingebouwde profielen :read-only, :workspace en :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 permittedClaude Code weerbaarder maken
De instellingen hieronder zijn die uit de documentatie van Claude Code, geraadpleegd op 7 september 2026.
De sandbox van Claude Code staat niet standaard aan: /sandbox schrijft hem naar het .claude/settings.local.json-bestand van het project, of je zet hem in ~/.claude/settings.json voor al je projecten. Hij steunt op Seatbelt onder macOS, op bubblewrap onder Linux en WSL2. Het netwerk loopt er via een proxy met een witte lijst: geen enkel domein is vooraf toegestaan.
{
"sandbox": {
"enabled": true,
"network": {
"allowedDomains": ["github.com", "*.npmjs.org"],
"strictAllowlist": true
},
"credentials": {
"files": [{ "path": "~/.ssh", "mode": "deny" }],
"envVars": [{ "name": "GITHUB_TOKEN", "mode": "deny" }]
}
}
}strictAllowlist weigert in plaats van te vragen, en werkt alleen vanuit de gebruikersinstellingen, beheerde instellingen of --settings: hem in het .claude/settings.json-bestand van een repository zetten doet niets. Het blok credentials pakt het gat aan dat bij Codex is gemeten: standaard laat een sandbox ~/.ssh gewoon lezen.
Twee beperkingen om te kennen. Ten eerste gelden permissieregels voor de tekst van het commando, en de documentatie zegt het zonder omwegen: Bash(curl http://github.com/ *) dekt geen curl -X GET, geen https, en geen URL die via een variabele wordt doorgegeven. Verbied de netwerktool en laat WebFetch het werk doen:
{
"permissions": {
"deny": ["Bash(curl:*)", "Bash(wget:*)", "Read(~/.ssh/**)"],
"allow": ["WebFetch(domain:github.com)"]
}
}Ten tweede doet --permission-prompts none, geïntroduceerd in 2.1.259, niet wat de naam doet vermoeden: in modus -p, als niemand kan antwoorden, weigert Claude Code het verzoek in plaats van het te stellen. Dat is het tegenovergestelde van --dangerously-skip-permissions, en het is de juiste vlag voor een onbewaakte agent.
Het aanvalsoppervlak van MCP-servers verkleinen
Een MCP-server is code die je zelf start en waarvan de resultaten in de context terechtkomen: beide risico’s stapelen zich op. Het geval mcp-remote liet dit zien: deze OAuth-proxy, 437.000 keer gedownload en aangehaald in de integratiegidsen van Cloudflare, Hugging Face en Auth0, gaf het autorisatiepunt van de externe server rechtstreeks door aan de shell, wat leidde tot remote code execution (CVE-2025-6514, gedocumenteerd door Docker).
Drie regels dekken het onderwerp. Zet de exacte commando’s vast in plaats van de namen: in allowedMcpServers is een serverName-vermelding waardeloos omdat het label door de gebruiker zelf wordt gekozen, terwijl een serverCommand argument voor argument moet overeenkomen. Geef elke server alleen-lezentoegang: een SQL-gebruiker beperkt tot SELECT, een bestandsserver beperkt tot één map. En behandel elke tool-uitvoer als data, nooit als een instructie.
{
"allowedMcpServers": [
{ "serverCommand": ["npx", "-y", "@modelcontextprotocol/server-filesystem", "."] },
{ "serverUrl": "https://mcp.sentry.dev/*" }
],
"deniedMcpServers": [{ "serverUrl": "https://*.untrusted.example.com/*" }]
}Op een losse machine leven die lijsten in je eigen instellingen. In een team legt een managed-mcp.json-bestand in /Library/Application Support/ClaudeCode/ op macOS of /etc/claude-code/ op Linux de exclusieve set servers vast: claude mcp add antwoordt dan met een foutmelding over bedrijfsbeleid. Schrijf je je eigen servers, dan wordt de reikwijdte al bij het ontwerp bepaald, zoals het artikel over het bouwen van een MCP-server in PHP uitlegt.
Wanneer stap je over op een container?
Zodra de agent zonder jou draait. Een container geeft een grens die noch een vergeten regel, noch een tool-antwoord kan verleggen. De volgende twee maatregelen zijn hier daadwerkelijk uitgevoerd:
docker run --rm --network none alpine:3 \
sh -c 'wget -q -T 5 -O /dev/null https://example.com'
# wget: bad address 'example.com' (code 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 (code 1, /tmp geaccepteerd)--network none sluit zelfs DNS-resolutie af, en --read-only met een tmpfs voor tijdelijke bestanden laat de agent werken zonder het systeem aan te raken. Monteer alleen de repository als volume, verder niets: geen ~/.ssh, geen ~/.aws, geen Docker-socket. De documentatie van Claude Code zegt het zonder omhaal, toegang geven tot /var/run/docker.sock komt neer op toegang geven tot de host. Het overzicht van command line-agents geeft aan welke dit kader zonder gemor accepteren.
Wat je moet onthouden
- Open vandaag nog
~/.codex/rules/default.rules: een “altijd toestaan” opcurlhaalt al je verzoeken stilletjes en voorgoed uit de sandbox. codex sandbox -P ':read-only'en-P ':workspace'testen de grens zonder het model aan te roepen. Controleer het, veronderstel niets.- Een sandbox blokkeert schrijven, niet lezen:
~/.sshblijft leesbaar zolang je hem niet insandbox.credentialsofdenyReadhebt gezet. - Regels die op argumenten filteren zijn fragiel: verbied
Bash(curl:*)en gebruikWebFetch(domain:…). Zet voor MCPserverCommandvast, nietserverName. - Zonder toezicht is het de container:
--network none,--read-only, geen enkel geheim gemonteerd. De rest is comfort. Om orde te scheppen in wat je agents laden, is er ook /skill-doctor.
Veelgemaakte fouten
prefix_rule(pattern=["curl"], decision="allow") haalt elke curl uit de sandbox. Loop ~/.codex/rules/default.rules na en ruim hem op, of start eenmalig met --ignore-rules.~/.ssh en ~/.aws/credentials blijven leesbaar. Zet ze in sandbox.credentials of sandbox.filesystem.denyRead.Bash(curl http://github.com/ *) dekt geen -X GET vóór de URL, geen https, en geen URL die via een variabele wordt doorgegeven. Weiger de tool en gebruik WebFetch(domain:…).allowedMcpServers is serverName het label dat de gebruiker zelf kiest: elke server kan zich “github” noemen. Gebruik serverCommand of serverUrl.--dangerously-skip-permissions dat de controles overslaat./var/run/docker.sock komt neer op toegang geven tot de hele host, sandbox of niet.

