Creare un sandbox sicuro ed efficace per abilitare Codex su Windows
Di David Wiesen, membro dello staff tecnico
Quando sono entrato nel team di ingegneria di Codex nel settembre 2025, Codex per Windows non disponeva di un’implementazione sandbox, il che costringeva gli utenti Windows a scegliere tra due opzioni poco soddisfacenti quando usavano gli agenti di coding di OpenAI:
- Dover approvare quasi ogni comando (perfino le letture) che un agente di coding voleva eseguire era inefficiente e fastidioso. Uno dei principali vantaggi dell’uso di Codex è che non devi fare tutto il lavoro noioso da solo.
- Abilitare la modalità Full Access: consentire a Codex di eseguire tutti i comandi senza approvazione né restrizioni, eliminando l’attrito a scapito del controllo.
Codex, il nostro agente di coding, viene eseguito sui laptop degli sviluppatori, tramite CLI, estensione IDE o app desktop. Gestisce una conversazione tra una persona alla tastiera e un modello in esecuzione nel cloud incaricato di gestire l'inferenza.
Per impostazione predefinita, Codex viene eseguito con i permessi di un utente reale, il che significa che può fare tutto ciò che può fare l’utente. Questo è potente e potenzialmente pericoloso. Il modello di coding può chiedere all’harness di eseguire comandi in locale, dall’esecuzione di test alla lettura o modifica di file fino alla creazione di un branch Git, quindi la modalità predefinita di Codex cerca di trovare il giusto equilibrio tra efficacia e sicurezza. Questa modalità predefinita consente a Codex di leggere file quasi ovunque e di scrivere file all’interno dell’area di lavoro dell’utente (ovvero la directory da cui viene eseguito Codex), senza accesso a Internet a meno che l’utente non lo richieda esplicitamente. Per applicare davvero questi vincoli automatici sulla scrittura dei file e sull’accesso alla rete entro limiti sicuri, Codex ha bisogno di un ambiente sandbox che li faccia rispettare concretamente.
Un sandbox è un ambiente di esecuzione soggetto a restrizioni. Quando uno sviluppatore usa Codex, il sistema operativo del computer avvia un comando con permessi ridotti e tali vincoli si propagano lungo l’albero dei processi. Ogni comando Codex viene isolato in un sandbox fin dall’avvio e ogni processo discendente rimane all’interno dello stesso perimetro.
Codex ha bisogno di funzionalità di isolamento applicate dal sistema operativo per implementare un sandbox efficace. Alcuni sistemi operativi forniscono utilità che svolgono bene questo compito (ad esempio Seatbelt su macOS, seccomp o bubblewrap su Linux); tuttavia, Windows attualmente non offre questo tipo di funzionalità pronte all’uso.
Per rendere Codex su Windows sicuro e piacevole da usare quanto lo è già sulle altre piattaforme, dovevamo implementare il nostro sandbox.
Windows offre alcuni strumenti e primitive per l’isolamento. Sebbene nessuno soddisfacesse davvero i nostri requisiti, abbiamo esaminato diverse soluzioni potenziali, ossia AppContainer, Windows Sandbox e l’etichettatura Mandatory Integrity Control.
AppContainer
- Cosa: AppContainer è il sandbox nativo di Windows, un modello di isolamento basato su capacità progettato per app che sanno in anticipo esattamente a cosa devono accedere.
- Perché: interessante perché offre un vero confine a livello di sistema operativo invece di restrizioni di tipo best effort.
- Perché no: Codex non è un’unica app con un ambito ben delimitato. Gestisce workflow di sviluppo aperti e non predeterminati: shell, Git, Python, package manager, strumenti di build e qualsiasi altro binario di cui l'agente decida di avere bisogno. In pratica, questo rendeva AppContainer inadatto al problema. Era un isolamento robusto, ma per una classe di carichi di lavoro molto più ristretta rispetto a “consentire a un agente di operare come uno sviluppatore”.
Windows Sandbox
- Che cos'è: Windows Sandbox è la VM leggera e usa e getta di Microsoft. Ottieni un desktop Windows pulito con un forte confine di isolamento e tutto ciò che fai al suo interno scompare al termine della sessione.
- Perché: interessante per motivi ovvi, molto più compatibile con software arbitrario rispetto ad AppContainer e, dal punto di vista della sicurezza, un contenitore molto più forte.
- Perché no: Codex deve agire direttamente sul vero checkout dell’utente, sui suoi strumenti reali e sul suo ambiente effettivo, non all’interno di un desktop separato e temporaneo che richiederebbe configurazione e integrazione tra host e guest. Presentava inoltre un problema fondamentale a livello di prodotto: Windows Sandbox non è nemmeno disponibile nelle SKU di Windows Home.
Etichettatura di integrità Mandatory Integrity Control (MIC)
- Che cosa: Windows ha un concetto chiamato “livelli di integrità”, come basso, medio e alto, che determinano quanto il sistema considera affidabili oggetti e processi. La regola di base è che un processo con integrità inferiore non può scrivere in un oggetto con un livello di integrità superiore, anche se la normale ACL lo consentirebbe altrimenti. Ad esempio, un processo a bassa integrità viene considerato meno attendibile, quindi Windows gli impedisce di scrivere in normali oggetti a integrità media, a meno che tali oggetti non vengano esplicitamente rietichettati per consentirglielo.
- Perché: MIC sembrava elegante sulla carta: eseguire Codex a bassa integrità, rietichettare come a bassa integrità le radici scrivibili e lasciare che Windows applichi il divieto di scrittura ovunque altrove. Questo ci avrebbe dato un percorso non da amministratore supportato da un vero meccanismo del sistema operativo.
- Perché no: come le ACL, le etichette di integrità modificano il filesystem reale dell’host e, in questo caso, il cambiamento semantico è particolarmente ampio. Contrassegnare un'area di lavoro come a bassa integrità non significa semplicemente "Codex può scrivere qui". Significa che i processi a bassa integrità in generale possono scrivervi. Su una macchina di sviluppo reale, questo trasforma il checkout effettivo dell’utente in un sink a bassa integrità per l’host, il che è molto più rischioso rispetto a concedere ACL attentamente mirate a un’unica architettura di sandbox. Anche se gli strumenti per sviluppatori a integrità media continuano a funzionare, il modello di attendibilità sottostante dell'area di lavoro è cambiato in un modo difficile da contenere e ancora più difficile da giustificare.
Dopo aver valutato tutte le opzioni come vicoli ciechi, abbiamo iniziato a progettare la nostra soluzione per offrire una buona esperienza Codex agli utenti Windows.
Il nostro primo prototipo funzionante utilizzava una combinazione di concetti e strumenti di Windows per implementare l’isolamento di cui avevamo bisogno. Fin dall’inizio, uno degli obiettivi era fare in modo che funzionasse senza richiedere elevazione, ovvero che Codex non dovesse mostrare all’utente un prompt per i privilegi di amministratore solo per configurare o eseguire la sandbox. Questo significava capire come imporre limiti ragionevoli a due cose: le operazioni di scrittura sui file e l'accesso alla rete.
Se non avessimo limitato affatto la scrittura dei file, avremmo avuto un problema di sicurezza. Se invece l’avessimo limitata troppo, il sandbox avrebbe penalizzato la produttività dell’utente richiedendo approvazioni continue. Per risolvere questo problema, ci siamo basati su due importanti componenti di Windows: SID e token con restrizione di scrittura.
Un SID, o identificatore di sicurezza, è l'identità che Windows associa alle autorizzazioni. Ogni utente ha un SID, i gruppi hanno SID e persino una singola sessione di accesso riceve un proprio SID. Ad esempio, una sessione di accesso attualmente attiva potrebbe avere un SID come S-1-5-5-X-Y. Il SID assegnato al gruppo degli amministratori locali potrebbe essere S-1-5-32-544.
Windows consente anche di creare SID sintetici che non corrispondono a utenti reali ma possono comunque comparire negli ACL (Access Control List), che definiscono chi può leggere, scrivere o eseguire file o directory specifici. Questo rende i SID una primitiva utile per il nostro sandbox: possiamo creare SID esclusivamente per il sandbox di Codex senza interferire con altri elementi del sistema.
I token di processo sono oggetti di sicurezza in Windows che definiscono l’identità e i privilegi per un processo in esecuzione. Determinano quali azioni può eseguire un processo. Un token con restrizione di scrittura è un particolare tipo di token di processo che induce Windows a eseguire un controllo di accesso aggiuntivo sulle operazioni di scrittura.
Affinché una scrittura vada a buon fine, devono essere superati due controlli:
- L’identità utente normale (il “proprietario” del token) deve avere il permesso di farlo
- Deve inoltre essere concesso l’accesso ad almeno un SID nell’elenco dei SID con restrizioni del token
In pratica, questi controlli ci hanno consentito di usare gli ACL per definire esattamente dove il sandbox poteva modificare il filesystem, offrendo la granularità di cui avevamo bisogno per le operazioni di scrittura.
Con SID e token con restrizione di scrittura, il nostro sandbox non elevato funzionava così:
- La configurazione del sandbox ha creato un SID sintetico chiamato
sandbox-write. - Al SID
sandbox-writeè stato concesso l'accesso in scrittura, esecuzione ed eliminazione a- La directory di lavoro corrente
- Eventuali
writable_rootsaggiuntive configurate inconfig.toml.
- La configurazione del sandbox negava esplicitamente a quello stesso SID l’accesso in scrittura alle posizioni “sola lettura all’interno di aree scrivibili”, come:
<cwd>/.git<cwd>/.codex<cwd>/.agents
- Codex avviava i comandi con un token con restrizione di scrittura il cui elenco di SID con restrizioni include
Everyone, il SID della sessione attualmente connessa e il SID sinteticosandbox-write.
Questo approccio ha risolto efficacemente il problema della limitazione della scrittura dei file e sembrava promettente. A quel punto, ci serviva una soluzione per limitare l’accesso alla rete del sandbox.
Limitare l’accesso alla rete è una parte importante del sandbox; senza questo limite, codice malevolo potrebbe esfiltrare dati dalla macchina verso internet. Poiché volevamo evitare di richiedere elevazione, avevamo opzioni limitate per bloccare con forza il traffico di rete. Gli strumenti che volevamo usare, come Windows Firewall, in genere non potevano essere installati senza permessi amministrativi.
Non avendo Windows Firewall come opzione, abbiamo limitato ciò che potevamo controllare. Abbiamo cercato di fare in modo che l’ambiente figlio adottasse un comportamento fail-closed per i tipi di strumenti con accesso alla rete che gli sviluppatori usano realmente, così che i comandi Git, gli installer di pacchetti e simili fallissero nella sandbox e l’utente dovesse approvare qualsiasi operazione con accesso a Internet. L’idea era avvelenare le vie di fuga più ovvie: inviare il traffico consapevole del proxy a un endpoint inattivo, fare in modo che il trasporto HTTP(S) di Git facesse lo stesso e fare fallire immediatamente Git su SSH. Inoltre, abbiamo anteposto una piccola directory denybin a PATH e riordinato PATHEXT in modo che gli script stub SSH e SCP venissero risolti prima dei binari reali.
Ad esempio, ecco alcune delle specifiche configurazioni dell’ambiente che abbiamo usato per limitare l’accesso alla rete:
HTTPS_PROXY=http://127.0.0.1:9ALL_PROXY=http://127.0.0.1:9GIT_HTTPS_PROXY=http://127.0.0.1:9NO_PROXY=localhost,127.0.0.1,::1GIT_SSH_COMMAND=cmd /c exit 1
Questo intercettava gran parte del normale traffico generato dagli strumenti, ma restava comunque un meccanismo puramente informativo. Un processo poteva ignorare le variabili d’ambiente, bypassare PATH o semplicemente aprire socket direttamente: troppo rischioso.
Come accade per qualsiasi implementazione software interessante, il primo prototipo presentava alcuni vantaggi e svantaggi. Sebbene svolgesse il proprio compito usando solo alcune funzionalità standard di Windows, consentisse scritture nel filesystem molto esplicite e granulari e funzionasse senza elevazione, riducendo la necessità per gli utenti di accettare continui prompt di elevazione o di essere amministratori della propria macchina, resentava anche diversi svantaggi concreti, alcuni dei quali lo hanno escluso dal diventare il design finale:
- Velocità di configurazione: applicare ACL all’area di lavoro può essere costoso a seconda della topologia della directory dell’area di lavoro.
- Impatto sul sistema: abbiamo applicato ACL reali al sistema dello sviluppatore, anche se l’impatto non è particolarmente invasivo perché tutti gli ACL applicati riguardano un SID sintetico creato ad hoc e usato solo dal sandbox.
- Semantica difficile da modificare: la dipendenza dalle ACL per le restrizioni basate sui file rende complesso e costoso modificare la semantica del sandbox. Mentre su macOS possiamo modificare dinamicamente il modo in cui generiamo il
.sbplfile utilizzato per configurare Seatbelt, la sandbox di Windows potrebbe richiedere un’operazione lenta e dispendiosa per modificare gli ACL. - La protezione della rete è debole. Come accennato in precedenza, si trattava di un sistema “informativo”, facilmente aggirabile da programmi che implementavano il proprio stack di rete e non progettato per resistere a codice ostile.
I primi tre problemi sono intrinseci a un’implementazione di sandbox personalizzata abbastanza flessibile per flussi agentici. La questione della limitazione dell’accesso alla rete, invece, era diversa.
Oltre al fatto che un agente malevolo avrebbe potuto aggirare facilmente la limitazione della rete basata sulle variabili d’ambiente, anche molto codice o molti binari benintenzionati avrebbero potuto bypassarla semplicemente ignorando le variabili proxy dell’ambiente o implementando un proprio stack di rete basato su socket. Abbiamo ritenuto che questo aspetto fosse sufficiente per giustificare l’investimento in una modalità sandbox migliore.
Per ottenere una efficace limitazione dell’accesso alla rete, volevamo usare Windows Firewall, che ci consente di bloccare il traffico di rete in uscita per utenti o programmi. Purtroppo, non potevamo creare efficacemente una regola firewall funzionale che si applicasse solo ai comandi generati dall’harness di Codex per alcuni motivi:
- Windows non consente di associare una regola del firewall all'identità non principale di un token con restrizioni. Questo significa che non potevamo applicare una regola firewall a “qualsiasi token che includa il nostro SID sintetico nel suo elenco di SID con restrizioni”.
- Sebbene potessimo creare una regola firewall che corrisponda a un binario specifico, questo ci consentirebbe solo di limitare l’accesso alla rete per
codex.exestesso. Non si applicherebbe ai processi che l’agente avvia per conto dell’utente, come i processi Git o Python. - Anche altre dimensioni di corrispondenza del firewall avevano una forma errata. Le regole con ambito utente corrispondevano ancora all’utente Windows reale nella progettazione non elevata, non solo al figlio con restrizioni. Le regole basate sul percorso del programma erano troppo grossolane: potevano bloccare
codex.exeopython.exein generale, ma non questa specifica invocazione in sandbox dipython.exe. Anche le regole basate su porte o indirizzi erano un criterio del tutto errato. Ad esempio, non volevamo bloccare la porta 443; volevamo bloccare l'accesso in uscita arbitrario per questo specifico albero di processi soggetto a restrizioni.
Per applicare una regola firewall specificamente ai nostri comandi eseguiti all’interno del sandbox, dovevamo eseguirli come un principal separato, non come l’utente “reale”. Questo approccio ci ha portato su una nuova strada, una in cui abbiamo allentato il vincolo del “nessuna elevazione”.
La successiva iterazione della sandbox, che corrisponde alla nostra implementazione attuale, richiede privilegi amministrativi elevati in fase di configurazione. Per questo la definisco “sandbox elevato”. Nel punto in cui Codex avvia un comando sul sistema, il sandbox elevato appare simile a quello non elevato. Continua comunque a eseguire i processi figli con un token con restrizioni, nello specifico un token write_restricted con lo stesso elenco di SID con restrizioni di [Everyone, Logon, Synthetic], tuttavia il principal di questo token non è più l’utente Windows effettivo, ma uno dei due utenti locali creati da Codex stesso:
CodexSandboxOffline(quello a cui si applicano le regole firewall)CodexSandboxOnline(quello a cui non si applicano le regole firewall)
Questo dettaglio apparentemente piccolo ha in realtà grandi implicazioni per il sandbox, per chi può usarlo e per la complessità della sua configurazione e della sua esecuzione a runtime.
Visivamente è simile al prototipo non elevato, con l’introduzione di regole firewall e di un utente Windows dedicato che esegue effettivamente i comandi. Tuttavia, l’introduzione di questi nuovi concetti comporta anche più lavoro di configurazione prima che il sandbox possa iniziare a eseguire e proteggere i comandi.
Il design del sandbox non elevato aveva un passaggio di configurazione semplice, ma relativamente ridotto:
- Creare un SID sintetico se necessario
- Applicare ACL al SID sintetico sandbox-write
Il sandbox elevato, invece, ha più cose da fare.
- Creare un SID sintetico, se non è già stato creato
- Crea gli utenti sandbox online e offline, se non sono già stati creati
- Memorizzare localmente le credenziali dei nuovi utenti e cifrarle usando Windows Data Protection API (DPAPI) in una posizione non accessibile agli utenti sandbox
- Creare regole firewall che blocchino tutto il traffico di rete in uscita per l’utente
CodexSandboxOfflineoppure, se esistono già, verificarne la correttezza
C'è un'ulteriore complicazione nella fase di configurazione. La sandbox di Codex dovrebbe disporre di un accesso in lettura equivalente a quello dell’utente Windows effettivo. Nella sandbox senza privilegi elevati, in cui il SID dell’entità di sicurezza del token con restrizioni corrispondeva all’utente Windows, questo risultato è stato ottenuto. Tuttavia, questo non è a costo zero quando il principal diventa un nuovo utente CodexSandbox. Molte directory pertinenti in Windows concederanno autorizzazioni di lettura/esecuzione a “Utenti autenticati”. Un esempio significativo è la directory del profilo dell’utente. Per impostazione predefinita, gli utenti Windows non possono leggere le directory dei profili di altri utenti Windows; pertanto, in molti scenari, anche semplici operazioni di lettura dei file non riuscirebbero.
Per affrontare questo problema, abbiamo aggiunto un altro livello al processo di configurazione del sandbox: uno per concedere ACL di lettura agli utenti sandbox dove tali ACL potrebbero non esistere già. Ad esempio, ad alcune directory di Windows di uso comune:
C:\Users\<real-user>C:\Windows\C:\Program Files\C:\Program Files (x86)\C:\ProgramData\
Poiché questo elenco di directory è di tipo best effort e l’installazione degli ACL su ciascuna di esse può essere piuttosto costosa, eseguiamo questa logica in modo asincrono così che il passaggio di configurazione del sandbox, che blocca l’utente, non debba aspettarne il completamento.
Abbiamo incapsulato la logica di configurazione in un binario dedicato, in parte per attraversare il confine UAC solo quando necessario. Ma la ragione più profonda era architetturale: la configurazione della sandbox svolge un compito fondamentalmente diverso rispetto a codex.exe. Tenere la logica di configurazione del sandbox in un binario dedicato ha consentito a codex.exe di restare un harness normale e non elevato; ha evitato che la meccanica di configurazione specifica di Windows appesantisse codex.exe sulle altre piattaforme; ha separato il lavoro di configurazione più lungo dal ciclo di vita del processo principale; e ci ha fornito un unico punto in cui gestire i diversi percorsi di configurazione richiesti dalla sandbox.
A causa del modo in cui Windows gestisce i confini di accesso tra utenti e token, non potevamo continuare a creare un token con restrizioni e avviare un processo sotto di esso come facevamo con il sandbox non elevato. Per eseguire realmente i comandi come un diverso utente Windows, la nostra prima idea era il seguente flusso:
codex.exeviene eseguito come l'utente Windows effettivo. Quindi, in sequenza, Codex:- Chiama
LogonUserW(...)per l'utente della sandbox. - Chiama
CreateRestrictedToken(...)su quel token dell’utente sandbox. - Usando quel token con restrizioni dell’utente sandbox, chiama
CreateProcessAsUserW(...)per avviare il processo figlio finale.
- Chiama
In pratica, quel flusso non ha funzionato a causa di una barriera legata ai privilegi in corrispondenza di CreateProcessAsUserW(...). Ciò significa che codex.exe poteva creare un token con restrizioni per l’utente sandbox, ma non poteva avviare in modo affidabile un processo figlio con quel token dal lato dell’utente reale. Avevamo bisogno di un processo già in esecuzione come utente sandbox: questo avrebbe consentito che il passaggio di restrizione e lo spawn finale avvenissero dal lato dell’utente sandbox anziché da quello dell’utente reale.
Quel requisito ha portato a codex-command-runner.exe, un nuovo binario il cui unico compito è creare un token con restrizioni e avviare il comando richiesto. Invece di chiedere a codex.exe di eseguire da solo l’intero flusso (utente reale → utente sandbox → token con restrizioni → processo figlio), abbiamo suddiviso il flusso in due parti:
Parte 1
codex.exechiamaCreateProcessWithLogonW(...)per avviarecodex-command-runner.execome utente sandbox, senza ancora usare un token con restrizioni.
Parte 2
- All’interno del runner,
OpenProcessToken(GetCurrentProcess(), ...)apre il token del runner stesso, che appartiene già all’utente sandbox. - Il runner chiama
GetTokenInformation(...)per estrarre il SID di accesso del sandbox, quindi utilizzaCreateRestrictedToken(...)per creare il token finale con restrizioni. - Sempre all’interno del runner, chiama
CreateProcessAsUserW(...)con quel token con restrizioni per avviare il vero processo figlio.
Albert Einstein disse: “Tutto dovrebbe essere reso il più semplice possibile, ma non più semplice.” Seguendo questo principio, il nostro design ha risolto adeguatamente ciascun problema. L’architettura finale si articola nei quattro livelli descritti in precedenza:
codex.exestessocodex-windows-sandbox-setup.exeper gestire tutto il lavoro di configurazione elevata correlatocodex-command-runner.exeper eseguire comandi con token con restrizioni- Il processo figlio
Quando ho iniziato a lavorare a questo progetto, non avevo ancora una chiara idea di dove sarebbe arrivato. Il mio approccio iniziale è stato integrare le funzionalità di sandboxing nel punto di confine tra Codex e il sistema operativo. Questo approccio corrisponde molto da vicino al modo in cui il sandbox di Codex è implementato su macOS e Linux.
Man mano che imparavo di più sugli strumenti specifici offerti da Windows, e attraverso decine di decisioni volte a bilanciare sicurezza e facilità d’uso, il sistema si è evoluto fino alla forma attuale: più binari, utenti personalizzati, regole firewall, un passaggio di configurazione elevato, processi asincroni e altro ancora.
Non è un sistema particolarmente semplice, ma ogni elemento di complessità è stato aggiunto per necessità, per costruire un sandbox che fosse sicuro e, per quanto possibile, non intralciasse l’utente.
Nel lavorare per offrire una buona esperienza agli utenti Windows di Codex, il nostro obiettivo era creare qualcosa di sicuro senza compromettere l’utilità: il vero valore di Codex sta nel permettere agli agenti di svolgere il lavoro senza richiedere costantemente l’attenzione dell’utente.
Una delle lezioni più importanti di questo progetto è stata che Windows non ci ha fornito una singola primitiva che corrispondesse in modo naturale a un “agente di coding autonomo sicuro”. Abbiamo combinato diversi strumenti e concetti per costruire qualcosa di coerente. Alcune idee iniziali si sono rivelate vicoli ciechi. Il design finale è stato un ibrido di prototipi precedenti, ciascuno dei quali risolveva una parte del problema.
L’altra lezione è stata che la sicurezza di un agente di coding è molto diversa dalla tradizionale sicurezza applicativa. Codex deve funzionare nei reali flussi di lavoro degli sviluppatori. Il lavoro di ingegneria consisteva nel bilanciare la compatibilità con i carichi di lavoro agentici e un’applicazione concreta dei vincoli. Questa tensione ha determinato i compromessi del design finale.
Vuoi vedere il sandbox di Codex in azione? Provalo.


