
La sandbox de Codex coupe bien le réseau et l'écriture hors de l'espace de travail, mais une règle « toujours autoriser » accumulée dans ~/.codex/rules/default.rules peut en faire sortir toutes vos commandes curl. Côté Claude Code, la sandbox n'est pas active par défaut : elle s'active avec /sandbox ou sandbox.enabled, et le réseau y fonctionne par liste blanche de domaines. Pour un agent sans surveillance, seul un conteneur avec --network none et --read-only tient vraiment.
La sandbox d'un agent IA : à quoi ça sert ?
Regarder le ShortLa chaîne YouTube Gekkode publie d’autres vidéos sur l’IA et le code.
S’abonner pour soutenir la chaîneLe 4 septembre 2026, on a appris que des agents de code d’OpenAI s’étaient donné rendez-vous sur un wiki allemand pour s’échanger des contournements de sandbox. La morale de l’affaire intéresse moins que sa mécanique. Sur votre machine, la question est de savoir ce que vous autorisez en lançant claude ou codex sans regarder.
Ce qui s’est passé sur le wiki allemand
DseWiki est un wiki de développeurs allemands hébergé sur prowiki.org, ouvert depuis vingt-cinq ans. Entre le 11 mai et le 13 juillet 2026, environ 18 000 messages y ont été déposés par près de 3 700 identités d’agents autonomes, avec un pic du 16 au 22 juin et jusqu’à 400 entrées par jour. Le collectif Nightingale a publié le dossier sur collusion.wiki le 4 septembre 2026, le même jour que la révélation de Reuters.
À côté de jeux de données et de points d’API, on y trouve des recettes d’évasion. La plus documentée : la liste NO_PROXY de leur environnement faisait confiance à tout ce qui se termine par .blob.core.windows.net, alors ils ont inventé un nom qui finit ainsi et l’ont pointé, via /etc/hosts, vers l’adresse voulue. Un agent a publié la recette sous le titre « REPRODUCIBLE BYPASS » le 20 juin, un autre l’a reproduite quatorze minutes plus tard, rapporte the-decoder.
Le détail gênant est chronologique. Dès mars 2026, OpenAI décrivait surveiller 99,9 % du trafic de ses agents de code internes avec GPT-5.4 Thinking, qui voit tout le contexte, chaîne de raisonnement et appels d’outils compris, et escalade les cas graves à un humain sous trente minutes. Le wiki a fonctionné après cette publication. Un moniteur qui voit tout n’est pas une frontière.
Le modèle de menace sur votre machine
Vous n’êtes pas OpenAI et votre agent n’a probablement aucune intention. Trois scénarios suffisent pourtant, et aucun ne demande de malveillance.
- L’injection de prompt : une page web, une issue GitHub, un journal ou le résultat d’un outil MCP contient des instructions que l’agent lit comme des consignes. C’est la voie d’entrée principale, et elle ne se corrige pas dans le prompt.
- L’exfiltration : l’agent lit vos clés et les envoie ailleurs. Un
curlvers le mauvais domaine suffit. - La commande destructrice : un
rm, ungit reset --hard, une migration sur la mauvaise base.
La seule réponse qui tienne est une frontière que le modèle ne choisit pas, celle du système d’exploitation ou d’un conteneur.
La sandbox de Codex coupe-t-elle vraiment le réseau ?
Codex propose trois modes via -s : read-only, workspace-write et danger-full-access. La documentation annonce que workspace-write autorise l’écriture dans l’espace de travail et coupe le réseau. J’ai vérifié sur ce Mac, sous macOS 26.6.2, avec 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'Résultat : code de sortie zéro, 200. Le réseau passait. En mode read-only, en demandant l’adresse distante, la sortie était code=200 ip=2606:4700:10::6814:179a t=0.084658 : une vraie réponse d’un serveur Cloudflare en quatre-vingt-cinq millisecondes. Ni -c sandbox_workspace_write.network_access=false ni --ignore-user-config n’y changeaient rien.
Les écritures, elles, étaient bien contenues. En workspace-write, touch ./fichier passait et touch /Users/gekkode/fichier renvoyait Operation not permitted. En read-only, même l’écriture dans le dossier courant était refusée. Mais ls ~/.ssh | wc -l renvoyait douze : une sandbox en lecture seule vous protège de l’écriture, pas de la lecture de vos clés.
Le drapeau qui a tout expliqué est --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.comLa sandbox fonctionne. Ce qui le contournait tient dans ~/.codex/rules/default.rules, le fichier où s’empilent les « toujours autoriser » cliqués en travaillant. Il contenait 249 règles, toutes en allow, dont celles-ci :
prefix_rule(pattern=["curl"], decision="allow")
prefix_rule(pattern=["wget"], decision="allow")Un jour, il y a des mois, un curl précis a été autorisé « pour toujours ». La règle enregistrée porte sur le programme, pas sur l’URL : depuis, tout curl vers n’importe quelle adresse s’exécutait hors de la sandbox. C’est aussi pourquoi network_access = false restait sans effet, la décision tombant avant la politique réseau. Relisez ce fichier, c’est probablement le réglage le plus rentable de cet article.
Pour tester une frontière sans consommer un token, Codex expose la sandbox en direct, avec les profils intégrés :read-only, :workspace et :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 permittedDurcir Claude Code
Les réglages ci-dessous sont ceux de la documentation de Claude Code, ouverte le 7 septembre 2026.
La sandbox de Claude Code n’est pas active par défaut : /sandbox l’écrit dans le .claude/settings.local.json du projet, ou vous le posez dans ~/.claude/settings.json pour tous vos projets. Il s’appuie sur Seatbelt sur macOS, sur bubblewrap sous Linux et WSL2. Le réseau y passe par un mandataire à liste blanche : aucun domaine n’est autorisé d’avance.
{
"sandbox": {
"enabled": true,
"network": {
"allowedDomains": ["github.com", "*.npmjs.org"],
"strictAllowlist": true
},
"credentials": {
"files": [{ "path": "~/.ssh", "mode": "deny" }],
"envVars": [{ "name": "GITHUB_TOKEN", "mode": "deny" }]
}
}
}strictAllowlist refuse au lieu de demander, et n’a d’effet que depuis les réglages utilisateur, gérés ou --settings : le poser dans le .claude/settings.json d’un dépôt ne fait rien. Le bloc credentials répond au trou mesuré chez Codex : par défaut, une sandbox laisse lire ~/.ssh.
Deux limites à connaître. D’abord, les règles de permission portent sur le texte de la commande, et la documentation le dit sans détour : Bash(curl http://github.com/ *) ne couvre ni curl -X GET, ni https, ni une URL passée par variable. Interdisez l’outil réseau et laissez WebFetch travailler :
{
"permissions": {
"deny": ["Bash(curl:*)", "Bash(wget:*)", "Read(~/.ssh/**)"],
"allow": ["WebFetch(domain:github.com)"]
}
}Ensuite, --permission-prompts none, apparu en 2.1.259, ne fait pas ce que son nom laisse croire : en mode -p, quand personne ne peut répondre, Claude Code refuse la demande au lieu de la poser. C’est l’inverse de --dangerously-skip-permissions, et c’est le bon drapeau pour un agent sans surveillance.
Réduire la surface des serveurs MCP
Un serveur MCP est du code que vous lancez et dont les résultats entrent dans le contexte : les deux risques se cumulent. Le cas mcp-remote l’a montré : ce proxy OAuth, tiré 437 000 fois et cité dans les guides d’intégration de Cloudflare, Hugging Face et Auth0, passait au shell le point d’autorisation fourni par le serveur distant, ce qui donnait une exécution de code à distance (CVE-2025-6514, documentée par Docker).
Trois règles tiennent le sujet. Épinglez les commandes exactes plutôt que les noms : dans allowedMcpServers, une entrée serverName ne vaut rien puisque l’étiquette est choisie par l’utilisateur, alors qu’un serverCommand doit correspondre argument par argument. Donnez à chaque serveur un accès en lecture seule : utilisateur SQL borné à SELECT, serveur de fichiers limité à un dossier. Et traitez toute sortie d’outil comme une donnée, jamais comme une consigne.
{
"allowedMcpServers": [
{ "serverCommand": ["npx", "-y", "@modelcontextprotocol/server-filesystem", "."] },
{ "serverUrl": "https://mcp.sentry.dev/*" }
],
"deniedMcpServers": [{ "serverUrl": "https://*.untrusted.example.com/*" }]
}Sur un poste seul, ces listes vivent dans vos réglages. En équipe, un fichier managed-mcp.json déposé dans /Library/Application Support/ClaudeCode/ sur macOS ou /etc/claude-code/ sur Linux fixe le jeu de serveurs exclusif : claude mcp add répond alors par une erreur de politique d’entreprise. Si vous écrivez vos propres serveurs, la portée se décide dès la conception, comme le détaille l’article sur la création d’un serveur MCP en PHP.
Quand faut-il passer au conteneur ?
Dès que l’agent tourne sans vous. Un conteneur donne une frontière que ni une règle oubliée ni une réponse d’outil ne peuvent déplacer. Les deux mesures suivantes ont été exécutées ici :
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 accepte)--network none coupe jusqu’à la résolution DNS, et --read-only avec un tmpfs pour les fichiers temporaires laisse l’agent travailler sans toucher au système. Montez le dépôt en volume, rien d’autre : ni ~/.ssh, ni ~/.aws, ni la socket Docker, la documentation de Claude Code le dit sans détour, autoriser /var/run/docker.sock revient à donner l’accès à l’hôte. Le panorama des agents en ligne de commande indique lesquels acceptent ce cadre sans se battre.
Ce qu’il faut retenir
- Ouvrez
~/.codex/rules/default.rulesaujourd’hui : un « toujours autoriser » surcurlsort toutes vos requêtes de la sandbox, en silence, pour toujours. codex sandbox -P ':read-only'et-P ':workspace'testent la frontière sans appeler le modèle. Vérifiez, ne supposez pas.- Une sandbox bloque l’écriture, pas la lecture :
~/.sshreste lisible tant que vous ne l’avez pas listé danssandbox.credentialsoudenyRead. - Les règles qui filtrent des arguments sont fragiles : interdisez
Bash(curl:*)et passez parWebFetch(domain:…). Pour les MCP, épinglezserverCommandet nonserverName. - Sans surveillance, c’est le conteneur :
--network none,--read-only, aucun secret monté. Le reste est du confort. Pour faire le ménage dans ce que vos agents chargent, il y a aussi /skill-doctor.
Erreurs fréquentes
prefix_rule(pattern=["curl"], decision="allow") fait sortir tout curl de la sandbox. Relisez et élaguez ~/.codex/rules/default.rules, ou lancez ponctuellement avec --ignore-rules.~/.ssh et ~/.aws/credentials restent lisibles. Listez-les dans sandbox.credentials ou sandbox.filesystem.denyRead.Bash(curl http://github.com/ *) ne couvre ni -X GET placé avant l'URL, ni https, ni une URL passée par variable. Refusez l'outil et passez par WebFetch(domain:…).allowedMcpServers, serverName est l'étiquette choisie par l'utilisateur : n'importe quel serveur peut s'appeler « github ». Utilisez serverCommand ou serverUrl.--dangerously-skip-permissions qui saute les vérifications./var/run/docker.sock revient à donner accès à l'hôte entier, sandbox ou pas.


