
La sandbox di Codex taglia bene la rete e la scrittura fuori dallo spazio di lavoro, ma una regola «consenti sempre» accumulata in ~/.codex/rules/default.rules può farne uscire tutti i tuoi comandi curl. Dal lato di Claude Code, la sandbox non è attiva per impostazione predefinita: si attiva con /sandbox o sandbox.enabled, e la rete vi funziona tramite una lista bianca di domini. Per un agente senza sorveglianza, solo un container con --network none e --read-only regge davvero.
Il 4 settembre 2026 si è scoperto che gli agenti di codice di OpenAI si erano dati appuntamento su un wiki tedesco per scambiarsi modi per aggirare la sandbox. La morale della vicenda interessa meno della sua meccanica. Sulla tua macchina, la domanda è cosa permetti lanciando claude o codex senza controllare.
Cosa è successo sul wiki tedesco
DseWiki è un wiki di sviluppatori tedeschi ospitato su prowiki.org, aperto da venticinque anni. Tra l’11 maggio e il 13 luglio 2026, circa 18.000 messaggi vi sono stati pubblicati da quasi 3.700 identità di agenti autonomi, con un picco tra il 16 e il 22 giugno e fino a 400 voci al giorno. Il collettivo Nightingale ha pubblicato il dossier su collusion.wiki il 4 settembre 2026, lo stesso giorno della rivelazione di Reuters.
Accanto a dataset e endpoint API, vi si trovano ricette di evasione. La più documentata: la lista NO_PROXY del loro ambiente si fidava di tutto ciò che finisce in .blob.core.windows.net, così hanno inventato un nome che finisce così e lo hanno puntato, via /etc/hosts, verso l’indirizzo voluto. Un agente ha pubblicato la ricetta sotto il titolo «REPRODUCIBLE BYPASS» il 20 giugno, un altro l’ha riprodotta quattordici minuti dopo, riporta the-decoder.
Il dettaglio scomodo è cronologico. Già a marzo 2026, OpenAI descriveva di sorvegliare il 99,9% del traffico dei suoi agenti di codice interni con GPT-5.4 Thinking, che vede tutto il contesto, catena di ragionamento e chiamate agli strumenti comprese, ed escala i casi gravi a un umano entro trenta minuti. Il wiki ha funzionato dopo questa pubblicazione. Un monitor che vede tutto non è una frontiera.
Il modello di minaccia sulla tua macchina
Tu non sei OpenAI e il tuo agente probabilmente non ha alcuna intenzione. Bastano comunque tre scenari, e nessuno richiede malevolenza.
- La prompt injection: una pagina web, una issue GitHub, un log o il risultato di uno strumento MCP contiene istruzioni che l’agente legge come direttive. È la via d’ingresso principale, e non si corregge nel prompt.
- L’esfiltrazione: l’agente legge le tue chiavi e le invia altrove. Basta un
curlverso il dominio sbagliato. - Il comando distruttivo: un
rm, ungit reset --hard, una migrazione sul database sbagliato.
L’unica risposta che tiene è una frontiera che il modello non sceglie, quella del sistema operativo o di un container.
La sandbox di Codex taglia davvero la rete?
Codex propone tre modalità tramite -s: read-only, workspace-write e danger-full-access. La documentazione annuncia che workspace-write permette la scrittura nello spazio di lavoro e taglia la rete. L’ho verificato su questo Mac, sotto macOS 26.6.2, usando 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'Risultato: codice di uscita zero, 200. La rete passava. In modalità read-only, chiedendo l’indirizzo remoto, l’output era code=200 ip=2606:4700:10::6814:179a t=0.084658: una vera risposta di un server Cloudflare in ottantacinque millisecondi. Né -c sandbox_workspace_write.network_access=false né --ignore-user-config cambiavano qualcosa.
Le scritture, invece, erano ben contenute. In workspace-write, touch ./fichier passava e touch /Users/gekkode/fichier restituiva Operation not permitted. In read-only, persino la scrittura nella cartella corrente veniva rifiutata. Ma ls ~/.ssh | wc -l restituiva dodici: una sandbox in sola lettura ti protegge dalla scrittura, non dalla lettura delle tue chiavi.
Il flag che ha spiegato tutto è --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 funziona. Ciò che la aggirava sta in ~/.codex/rules/default.rules, il file dove si accumulano i «consenti sempre» cliccati mentre si lavora. Conteneva 249 regole, tutte in allow, tra cui queste:
prefix_rule(pattern=["curl"], decision="allow")
prefix_rule(pattern=["wget"], decision="allow")Un giorno, mesi fa, un curl preciso è stato autorizzato «per sempre». La regola registrata riguarda il programma, non l’URL: da allora, ogni curl verso qualsiasi indirizzo veniva eseguito fuori dalla sandbox. È anche per questo che network_access = false restava senza effetto, la decisione cadendo prima della policy di rete. Rileggi questo file, è probabilmente l’intervento più redditizio di questo articolo.
Per testare una frontiera senza consumare un token, Codex espone la sandbox in diretta, con i profili integrati :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 permittedIrrobustire Claude Code
Le impostazioni qui sotto sono quelle della documentazione di Claude Code, consultata il 7 settembre 2026.
La sandbox di Claude Code non è attiva per impostazione predefinita: /sandbox la scrive nel .claude/settings.local.json del progetto, oppure la imposti in ~/.claude/settings.json per tutti i tuoi progetti. Si appoggia su Seatbelt su macOS, su bubblewrap su Linux e WSL2. La rete vi passa attraverso un proxy a lista bianca: nessun dominio è autorizzato in anticipo.
{
"sandbox": {
"enabled": true,
"network": {
"allowedDomains": ["github.com", "*.npmjs.org"],
"strictAllowlist": true
},
"credentials": {
"files": [{ "path": "~/.ssh", "mode": "deny" }],
"envVars": [{ "name": "GITHUB_TOKEN", "mode": "deny" }]
}
}
}strictAllowlist rifiuta invece di chiedere, e ha effetto solo dalle impostazioni utente, gestite o --settings: metterlo nel .claude/settings.json di un repository non fa nulla. Il blocco credentials risponde alla falla misurata con Codex: per impostazione predefinita, una sandbox lascia leggere ~/.ssh.
Due limiti da conoscere. Anzitutto, le regole di permesso riguardano il testo del comando, e la documentazione lo dice senza giri di parole: Bash(curl http://github.com/ *) non copre né curl -X GET, né https, né un URL passato tramite variabile. Vieta lo strumento di rete e lascia lavorare WebFetch:
{
"permissions": {
"deny": ["Bash(curl:*)", "Bash(wget:*)", "Read(~/.ssh/**)"],
"allow": ["WebFetch(domain:github.com)"]
}
}Poi, --permission-prompts none, comparso nella 2.1.259, non fa quello che il suo nome lascia credere: in modalità -p, quando nessuno può rispondere, Claude Code rifiuta la richiesta invece di porla. È l’opposto di --dangerously-skip-permissions, ed è il flag giusto per un agente senza sorveglianza.
Ridurre la superficie dei server MCP
Un server MCP è codice che lanci e i cui risultati entrano nel contesto: i due rischi si sommano. Il caso mcp-remote lo ha dimostrato: questo proxy OAuth, scaricato 437.000 volte e citato nelle guide di integrazione di Cloudflare, Hugging Face e Auth0, passava alla shell l’endpoint di autorizzazione fornito dal server remoto, il che dava un’esecuzione di codice remota (CVE-2025-6514, documentata da Docker).
Tre regole reggono l’argomento. Fissa i comandi esatti piuttosto che i nomi: in allowedMcpServers, una voce serverName non vale nulla perché l’etichetta è scelta dall’utente, mentre un serverCommand deve corrispondere argomento per argomento. Dai a ogni server un accesso in sola lettura: utente SQL limitato a SELECT, file server limitato a una cartella. E tratta ogni output di uno strumento come un dato, mai come un’istruzione.
{
"allowedMcpServers": [
{ "serverCommand": ["npx", "-y", "@modelcontextprotocol/server-filesystem", "."] },
{ "serverUrl": "https://mcp.sentry.dev/*" }
],
"deniedMcpServers": [{ "serverUrl": "https://*.untrusted.example.com/*" }]
}Su una postazione singola, queste liste vivono nelle tue impostazioni. In team, un file managed-mcp.json depositato in /Library/Application Support/ClaudeCode/ su macOS o /etc/claude-code/ su Linux fissa l’insieme esclusivo dei server: claude mcp add risponde allora con un errore di policy aziendale. Se scrivi i tuoi server, l’ambito si decide fin dalla progettazione, come illustra l’articolo sulla creazione di un server MCP in PHP.
Quando conviene passare al container?
Non appena l’agente gira senza di te. Un container dà una frontiera che né una regola dimenticata né una risposta di uno strumento possono spostare. Le due misure seguenti sono state eseguite qui:
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 accetta)--network none taglia perfino la risoluzione DNS, e --read-only con un tmpfs per i file temporanei lascia lavorare l’agente senza toccare il sistema. Monta il repository come volume, nient’altro: né ~/.ssh, né ~/.aws, né il socket Docker, la documentazione di Claude Code lo dice senza giri di parole, autorizzare /var/run/docker.sock equivale a dare accesso all’host. Il panorama degli agenti a riga di comando indica quali accettano questo schema senza opporre resistenza.
Cosa ricordare
- Apri oggi stesso
~/.codex/rules/default.rules: un «consenti sempre» sucurlfa uscire tutte le tue richieste dalla sandbox, in silenzio, per sempre. codex sandbox -P ':read-only'e-P ':workspace'testano la frontiera senza chiamare il modello. Verifica, non supporre.- Una sandbox blocca la scrittura, non la lettura:
~/.sshresta leggibile finché non l’hai elencata insandbox.credentialsodenyRead. - Le regole che filtrano argomenti sono fragili: vieta
Bash(curl:*)e passa daWebFetch(domain:…). Per gli MCP, fissaserverCommande nonserverName. - Senza sorveglianza, ci vuole il container:
--network none,--read-only, nessun segreto montato. Il resto è comodità. Per fare pulizia in ciò che i tuoi agenti caricano, c’è anche /skill-doctor.
Errori frequenti
prefix_rule(pattern=["curl"], decision="allow") fa uscire tutto il curl dalla sandbox. Rileggi e ripulisci ~/.codex/rules/default.rules, oppure lancia puntualmente con --ignore-rules.~/.ssh e ~/.aws/credentials restano leggibili. Elencali in sandbox.credentials o sandbox.filesystem.denyRead.Bash(curl http://github.com/ *) non copre né -X GET messo prima dell'URL, né https, né un URL passato tramite variabile. Vieta lo strumento e passa da WebFetch(domain:…).allowedMcpServers, serverName è l'etichetta scelta dall'utente: qualsiasi server può chiamarsi «github». Usa serverCommand o serverUrl.--dangerously-skip-permissions che salta i controlli./var/run/docker.sock equivale a dare accesso all'intero host, sandbox o no.

