Bygge en sikker og effektiv sandkasse for å aktivere Codex på Windows
Av David Wiesen, medlem av teknisk stab
Da jeg begynte i Codex-ingeniørteamet i september 2025, hadde Codex for Windows ingen sandkasse-implementering, som betydde at Windows-brukere ble tvunget til å velge mellom to dårlige alternativer når de brukte OpenAIs kodeagenter:
- Godkjenne nesten alle kommandoer (til og med lesninger) som en kodeagent ønsket å kjøre, noe som er ineffektivt og plagsomt. En stor fordel med å bruke Codex er at du slipper å gjøre alt det kjedelige arbeidet selv.
- Aktivere full tilgangsmodus: la Codex kjøre alle kommandoer uten godkjenning eller begrensninger, noe som fjerner friksjon på bekostning av tilsyn.
Codex, kodeagenten vår, kjører på utvikleres bærbare datamaskiner – enten det er via CLI, IDE-utvidelsen eller skrivebordsappen. Den administrerer en samtale mellom et menneske ved et tastatur og en modell som kjører i skyen for å håndtere inferens.
Codex kjører som standard med tillatelser som en ekte bruker, noe som betyr at den kan gjøre alt brukeren kan gjøre. Dette er kraftig og potensielt farlig. Kodemodellen kan be rammeverket om å kjøre kommandoer lokalt, fra å kjøre tester til å lese eller redigere en fil til å opprette en Git-gren, så Codex’ standardmodus forsøker å finne den rette balansen mellom effektivitet og sikkerhet. Denne standardmodusen gjør at Codex kan lese filer nesten hvor som helst og skrive filer i arbeidsområdet ditt (dvs. katalogen der du kjører Codex), uten Internett-tilgang med mindre du spesifiserer at du vil ha det. For å oppnå denne automatiske begrensningen om å skrive filer og få tilgang til nettverket innenfor trygge grenser, trenger Codex et sandkassemiljø som faktisk håndhever disse begrensningene.
En sandkasse er et begrenset kjøringsmiljø. Når en utvikler bruker Codex, starter datamaskinens operativsystem en kommando med reduserte rettigheter, og disse begrensningene forplanter seg nedover i prosesstreet. Alle Codex-kommandoer kjøres i en sandkasse fra starten av, og alle etterfølgende prosesser holder seg innenfor de samme grensene.
Codex trenger isolasjonsfunksjoner som håndheves av datamaskinens operativsystem for å implementere en effektiv sandkasse. Noen operativsystemer har verktøy som gjør dette bra (f.eks. Seatbelt på MacOs, seccomp eller bubblewrap på Linux). Windows har for øyeblikket ikke denne typen funksjonalitet.
For å gjøre Codex like trygt og fint å bruke på Windows som det allerede er andre steder, måtte vi implementere vår egen sandkasse.
Windows tilbyr noen verktøy og primitiver for isolering. Selv om ingen av dem helt oppfylte kravene våre, så vi på en rekke mulige løsninger – nemlig AppContainer, Windows Sandbox og Mandatory Integrity Control-merking.
AppContainer
- Hva: AppContainer er Windows’ innebygde sandkasse, en kapabilitetsbasert isolasjonsmodell utviklet for apper som på forhånd vet nøyaktig hva de trenger tilgang til.
- Hvorfor: Tiltalende fordi den tilbyr en ekte OS-grense i stedet for begrensninger etter beste evne.
- Hvorfor ikke: Codex er ikke én app med et stramt omfang. Den driver åpne arbeidsflyter for utviklere: skall, Git, Python, pakkebehandlere, byggeverktøy og andre binære filer som agenten bestemmer at den trenger. I praksis gjorde det AppContainer dårlig egnet for problemet. Det var sterk isolasjon, men for en langt snevrere klasse av arbeidsbelastninger enn «la en agent operere som en utvikler».
Windows Sandbox
- Hva: Windows Sandbox er Microsofts lettvekts-VM til engangsbruk. Du får et nytt Windows-skrivebord med en sterk isolasjonsgrense, og det du gjør der forsvinner når økten avsluttes.
- Hvorfor: Interessant av åpenbare grunner – langt mer kompatibel med vilkårlig programvare enn AppContainer, og fra et sikkerhetsperspektiv er det en mye sterkere kasse.
- Hvorfor ikke: Codex må handle direkte på brukerens faktiske input, verktøy og miljø, ikke på et separat, midlertidig skrivebord som ville kreve oppsett og bro mellom vert og gjest. Det hadde også et grunnleggende produktproblem: Windows Sandbox er ikke engang tilgjengelig på Windows Home SKU-er.
Integritetsmerking med Mandatory Integrity Control (MIC)
- Hva: Windows har et konsept som kalles «integritetsnivåer», for eksempel lavt, middels og høyt, som avgjør hvor mye systemet stoler på objekter og prosesser. Den grunnleggende regelen er at en prosess med lavere integritetsnivå ikke kan skrive til et objekt med et høyere integritetsnivå, selv om den vanlige ACL-en ellers ville tillatt det. For eksempel behandles en prosess med lav integritet som mindre pålitelig, så Windows blokkerer den fra å skrive til vanlige objekter med middels integritet, med mindre disse objektene eksplisitt er merket for å tillate det.
- Hvorfor: MIC så elegant ut på papiret – kjør Codex med lav integritet, merk de skrivbare røttene på nytt som lav integritet, og la Windows håndheve skriveforbud alle andre steder. Det ville ha gitt oss en bane uten administratorrettigheter, støttet av en ekte mekanisme i operativsystemet.
- Hvorfor ikke: I likhet med ACL-er endrer integritetsetiketter det virkelige vertsfilsystemet, og i dette tilfellet er den semantiske endringen spesielt omfattende. Å merke et arbeidsområde som lav integritet betyr ikke bare «Codex kan skrive her». Det betyr at prosesser med lav integritet generelt sett kan skrive der. På en ekte utviklermaskin gjør det brukerens faktiske input til en lav-integritets sink for vertssystemet, noe som er mye mer risikabelt enn å gi nøye målrettede ACL-er til ett sandkassedesign. Selv om utviklerverktøy med middels integritet fortsetter å fungere, har den underliggende tillitsmodellen for arbeidsområdet endret seg på en måte som er vanskelig å begrense og enda vanskeligere å rettferdiggjøre.
Etter å ha vurdert alle alternativene som uaktuelle, begynte vi å designe vår egen løsning for å gi Windows-brukere en god Codex-opplevelse.
Vår første fungerende prototype brukte en kombinasjon av Windows-konsepter og -verktøy for å implementere isolasjonen vi trengte. Fra begynnelsen av var et mål å få dette til å fungere uten å kreve forhøyede rettigheter, noe som betyr at Codex ikke ville trenge å be brukeren om administratorrettigheter bare for å konfigurere eller kjøre sandkassen. Det innebar å finne ut hvordan vi kunne sette rimelige grenser på to ting: filskriving og nettverkstilgang.
Hvis vi ikke begrenset filskriving i det hele tatt, ville vi hatt et sikkerhetsproblem. Hvis vi begrenset filskriving for mye, ville sandkassen hemmet brukerens produktivitet ved å hele tiden be om godkjenning. For å løse dette problemet tok vi utgangspunkt i to viktige byggeklosser i Windows: SID-er og skrivebegrensede token.
En SID, eller sikkerhetsidentifikator, er identiteten Windows knytter til tillatelser. Hver bruker har en SID, grupper har SID-er, og selv én enkelt påloggingsøkt får sin egen SID. For eksempel kan en aktiv innlogget økt ha en SID som S-1-5-5-X-Y. SID-en som er tilordnet den lokale administratorgruppen, kan være S-1-5-32-544.
Windows lar deg også opprette syntetiske SID-er som ikke tilsvarer en ekte bruker, men som likevel kan vises i ACL-er (tilgangskontrollister), som definerer hvem som kan lese/skrive/kjøre bestemte filer eller kataloger. Det gjør SID-er til en nyttig primitivitet for sandkassen vår: vi kan opprette SID-er utelukkende for Codex-sandkassen, uten å forstyrre noe annet på maskinen.
Prosesstokener er sikkerhetsobjekter i Windows som definerer identitet og privilegier for en prosess som kjører. De bestemmer hvilke handlinger en prosess kan utføre. En skrivebegrenset token er en bestemt type prosesstoken som gjør at Windows utfører en ekstra tilgangskontroll ved skriveoperasjoner.
For at en skriving skal lykkes, må to kontroller bestås:
- Den vanlige brukeridentiteten (tokenets «eier») må ha tillatelse til å gjøre det
- Minst én SID i tokenets liste over begrensede SID-er må også ha blitt gitt tilgang
I praksis lot disse kontrollene oss bruke ACL-er til å definere nøyaktig hvor sandkassen kunne endre filsystemet, noe som ga den detaljeringsgraden vi trengte rundt skriveoperasjoner.
Med SID-er og skrivebegrensede tokener fungerte sandkassen vår uten forhøyede rettigheter slik:
- Oppsettet for sandkassen opprettet en syntetisk SID kalt
sandbox-write. - SID-en
sandbox-writeble gitt skrive-, kjøre- og slettetilgang til- Gjeldende arbeidskatalog
- Eventuelle ekstra
writable_rootskonfigurert iconfig.toml.
- Oppsettet for sandkassen nektet eksplisitt den samme SID-en skrivetilgang til «skrivebeskyttet innenfor skrivbare» plasseringer som:
<cwd>/.git<cwd>/.codex<cwd>/.agents
- Codex startet kommandoer under et skrivebegrenset token med en liste over begrensede SID-er som inkluderer
Everyone, SID-en for gjeldende påloggede økt og den syntetiske SID-ensandbox-write.
Denne flyten løste effektivt begrensning av filskriving og virket lovende. Nå trengte vi en løsning for å begrense sandkassens nettverkstilgang.
Begrensning av nettverkstilgang er en viktig del av sandkassen, fordi uten dette kan ondsinnet kode eksfiltrere data fra maskinen til internett. Fordi vi ønsket å unngå et krav om forhøyede rettigheter, hadde vi begrensede muligheter for å blokkere nettverkstrafikk på en sterk måte. Verktøyene vi ville bruke, som Windows-brannmuren, kunne vanligvis ikke installeres uten administratorrettigheter.
Uten Windows-brannmuren som et alternativ, begrenset vi hva vi kunne kontrollere. Vi prøvde å gjøre det underordnede miljøet fail-closed for den typen nettverksverktøy som utviklere faktisk bruker, slik at Git-kommandoer, pakkeinstallasjonsprogrammer osv. ville feile i sandkassen, og brukeren måtte godkjenne alle operasjoner som kommuniserer med Internett. Tanken var å blokkere de åpenbare fluktveiene: sende proxy-bevisst trafikk til et dødt endepunkt, få Gits HTTP(S)-transport til å gjøre det samme, og få Git over SSH til å feile umiddelbart. I tillegg la vi en liten denybin-katalog i PATH og omorganiserte PATHEXT slik at stub SSH og SCP-skript skulle løses før de ekte binære filene.
Her er for eksempel noen av de spesifikke miljøoverstyringene vi brukte for å begrense nettverkstilgangen:
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
Det fanget opp mye vanlig verktøydrevet trafikk, men det var fortsatt bare rådgivende. En prosess kunne ignorere miljøet, omgå PATH eller bare åpne sokler direkte – for risikabelt.
Som med all interessant programvareimplementering hadde den første prototypen noen fordeler og ulemper. Selv om den fikk jobben gjort med bare noen få standard Windows-funksjoner, tillot svært eksplisitte og detaljerte filsystemskrivinger og kjørte uten forhøyede rettigheter – som reduserte behovet for at brukere måtte godta et stort antall forespørsler om forhøyede rettigheter eller være administratorer på deres lokale maskin – hadde den noen reelle ulemper, og noen av dem diskvalifiserte den som vårt endelige design:
- Nødvendig tid for oppsett: Det kan være kostbart å bruke ACL-er på arbeidsområdet, avhengig av topologien til arbeidsområdekatalogen.
- Fotavtrykk: Vi brukte ekte ACL-er på utviklerens system, selv om fotavtrykket ikke er særlig invasivt fordi alle de brukte ACL-ene er knyttet til en spesialopprettet syntetisk SID som bare brukes av sandkassen.
- Semantikk som er vanskelig å endre: Avhengigheten av ACL-er for filbaserte begrensninger betyr at det er kostbart og komplekst å endre sandkassens semantikk. Mens vi på macOS kan dynamisk endre måten vi genererer
.sbplfilen som brukes til å konfigurere Seatbelt på, kan Windows-sandkassen kreve en tidkrevende og ressurskrevende operasjon for å justere ACL-er. - Nettverksbeskyttelsen er svak. Som nevnt tidligere var den «rådgivende», ville definitivt bli omgått av noen programmer som implementerte sin egen nettverksstack, og var ikke designet for å stå imot fiendtlig kode.
De tre første problemene er iboende i en tilpasset sandkasseimplementering som er fleksibel nok for agentiske flyter. Historien om nettverksundertrykkelse var imidlertid annerledes.
I tillegg til at en ondsinnet agent lett kunne omgå den miljøbaserte nettverksundertrykkelsen, ville også mange velmenende kode/binære filer kunne omgå den hvis de ikke respekterte miljøproxyvariablene, eller hvis de implementerer sin egen socket-baserte nettverkskode. Vi mente at dette alene var nok til å vurdere å investere i en bedre sandkassemodus.
For å få bedre nettverksundertrykkelse ønsket vi å bruke Windows-brannmuren, som lar oss blokkere utgående nettverkstrafikk for brukere eller programmer. Dessverre kunne vi ikke effektivt lage en funksjonell brannmurregel som bare gjaldt kommandoene som ble startet av Codex-rammeverket. Dette skyldtes flere grunner:
- Windows tillater ikke at en brannmurregel samsvarer med den ikke-prinsipale identiteten til et begrenset token. Dette betyr at vi ikke kunne bruke en brannmurregel på «ethvert token som inkluderer vår syntetiske SID i listen over begrensede SID-er».
- Selv om vi kunne opprette en brannmurregel som samsvarer med en bestemt binær fil, lar det oss bare begrense nettverkstilgangen for selve
codex.exe. Det ville ikke gjelde for prosessene som agenten starter på vegne av brukeren, for eksempel Git- eller Python-prosesser. - Andre match-dimensjoner for brannmur hadde også feil form. Brukerdefinerte regler samsvarer fortsatt med den virkelige Windows-brukeren i designet uten forhøyede rettigheter, ikke bare med den begrensede underordnede prosessen. Reglene for programbane var for grove: de kunne blokkere
codex.exeellerpython.exegenerelt, men ikke denne ene sandkassepåkallingen avpython.exe. Port- eller adressebaserte regler var også helt feil policy. For eksempel ønsket vi ikke å blokkere port 443. Vi ville blokkere vilkårlig utgående tilgang for dette spesifikke, begrensede prosesstreet.
For å bruke en brannmurregel spesifikt på kommandoene i sandkassen vår måtte vi kjøre dem som en separat prinsipal, ikke som den «ekte» brukeren. Denne tilnærmingen førte oss inn på en ny vei, der vi lempet på kravet om «ingen forhøyede rettigheter».
Den neste iterasjonen av sandkassen, som er vår nåværende implementering, krever forhøyede administratorrettigheter under oppsettet. Jeg omtaler den derfor som «den forhøyede sandkassen». Ved grensen der Codex starter en kommando på systemet, ser den forhøyede sandkassen ut som den uten forhøyede rettigheter. Den kjører fortsatt underordnede prosesser under et begrenset token – tilsvarende et write_restricted-token med den samme begrensede SID-listen [Everyone, Logon, Synthetic] – men identiteten til dette tokenet er ikke lenger den faktiske Windows-brukeren, men en av to lokale brukere som Codex selv har opprettet:
CodexSandboxOffline(den som er omfattet av brannmurreglene)CodexSandboxOnline(den som ikke er omfattet av brannmurreglene)
Denne tilsynelatende lille detaljen har faktisk store konsekvenser for sandkassen, hvem som kan bruke den og kompleksiteten i oppsettet og kjøringen av den.
Den ligner visuelt på prototypen uten forhøyede rettigheter, med introduksjonen av brannmurregler og en dedikert Windows-bruker som faktisk kjører kommandoene. (Innføringen av disse nye konseptene betyr imidlertid at det er mer oppsettsarbeid som må gjøres før sandkassen kan begynne å kjøre og beskytte kommandoer.)
Sandkassedesignet uten forhøyede rettigheter hadde et enkelt oppsettstrinn, men det var relativt lite:
- Opprett en syntetisk SID om nødvendig
- Bruk ACL-er for sandbox-write syntetisk SID
Sandkassen med forhøyede rettigheter har derimot mer å gjøre.
- Opprett en syntetisk SID, hvis den ikke allerede er opprettet
- Opprett sandkassebrukerne online og offline, hvis de ikke allerede er opprettet
- Lagre legitimasjonen til de nyopprettede brukerne lokalt og kryptere med Windows Data Protection API (DPAPI) på et sted der sandkassebrukerne faktisk ikke kan lese den
- Opprett brannmurregler som blokkerer all utgående nettverkstilgang for brukeren
CodexSandboxOffline, eller hvis de allerede finnes, kontroller at de er korrekte
Det er en ekstra utfordring i oppsettsfasen. Codex’ sandkasse forventes å ha samme lesetilgang som den faktiske Windows-brukeren. I sandkassen uten forhøyede rettigheter, der det begrensede tokenets prinsipal-SID var Windows-brukeren, ble dette oppnådd. Dette skjer imidlertid ikke uten videre når prinsipalen blir en ny CodexSandbox-bruker. Mange relevante kataloger i Windows gir lese- og kjøretillatelser til «Autentiserte brukere». Et kjent eksempel er brukerens profilkatalog. Som standard kan ikke Windows-brukere lese profilkatalogene til andre Windows-brukere, så selv enkel lesing av filer vil i mange tilfeller mislykkes.
For å løse dette la vi til et nytt lag i oppsettsprosessen for sandkassen – et lag for å gi lese-ACL-er til sandkassebrukerne der slike ACL-er kanskje ikke allerede finnes. For eksempel til noen vanlige Windows-kataloger:
C:\Users\<real-user>C:\Windows\C:\Program Files\C:\Program Files (x86)\C:\ProgramData\
Fordi denne listen over kataloger er basert på beste innsats og det kan være ganske kostbart å installere ACL-er på hver enkelt katalog, kjører vi denne logikken asynkront slik at oppsettet av sandkassen, som blokkerer for brukerne, ikke må vente på at de fullføres.
Vi kapslet inn oppsettlogikken i sin egen binære fil, slik at den bare krysser UAC-grensen når det er nødvendig. Men den dypere årsaken var arkitektonisk: sandkasseoppsettet har en fundamentalt annerledes oppgave enn codex.exe. Ved å holde oppsettslogikken for sandkassen i en egen binær fil kunne codex.exe forbli et normalt rammeverk uten forhøyede rettigheter, og vi unngikk at Windows-spesifikk oppsettsmekanikk blåste opp codex.exe på andre plattformer, frikoblet lengre oppsettsarbeid fra hovedprosessens levetid, og fikk ett sted å håndtere de ulike oppsettsbanene sandkassen trengte.
På grunn av hvordan grenser for innlogging av Windows-brukere og token fungerer, kunne vi ikke fortsette å opprette et begrenset token og starte en prosess under det slik vi kunne med sandkassen uten forhøyede rettigheter. For å faktisk starte kommandoer som en annen Windows-bruker var den første ideen vår følgende flyt:
codex.exekjøres som den faktiske Windows-brukeren. Deretter, i en sekvens, Codex:- Kaller
LogonUserW(...)for sandkassebrukeren. - Kaller
CreateRestrictedToken(...)på det sandkasse-brukertokenet. - Bruker det begrensede tokenet for sandkassebrukeren og kaller
CreateProcessAsUserW(...)for å starte den endelige underordnede prosessen.
- Kaller
I praksis fungerte ikke den ønskede flyten på grunn av en rettighetsbarriere ved CreateProcessAsUserW(...). Dette betyr at codex.exe kunne opprette en begrenset token for sandkassebrukeren, men kunne ikke på en pålitelig måte starte en underordnet prosess med dette tokenet fra den virkelige brukerens side av sikkerhetsgrensen. Vi trengte en prosess som allerede kjørte som sandkassebrukeren – dette ville gjøre at begrensningstrinnet og den endelige prosessopprettelsen kunne skje på sandkassebrukerens side av sikkerhetsgrensen i stedet for på den virkelige brukerens side.
Dette kravet førte til codex-command-runner.exe, en ny binær fil hvis eneste oppgave er å utstede et begrenset token og starte den forespurte kommandoen. I stedet for å be codex.exe om å gjøre hele flyten selv (ekte bruker → sandkassebruker → begrenset token → underordnet prosess), deler vi flyten i to:
Del 1
codex.exekallerCreateProcessWithLogonW(...)for å startecodex-command-runner.exesom sandkassebrukeren, uten å bruke et begrenset token ennå.
Del 2
- Inne i kjøreren åpner
OpenProcessToken(GetCurrentProcess(), ...)kjørerens eget token, som allerede tilhører sandkassebrukeren. - Kjøreren kaller
GetTokenInformation(...)for å hente ut SID-en for pålogging til sandkassen, og deretterCreateRestrictedToken(...)for å lage det endelige begrensede tokenet. - Fortsatt inne i kjøreren kaller den
CreateProcessAsUserW(...)med det begrensede tokenet for å starte den virkelige underordnede prosessen.
Albert Einstein sa: «Alt bør gjøres så enkelt som mulig, men ikke enklere.» I den ånden løste designet vårt hvert problem på en tilfredsstillende måte. Den endelige arkitekturen har de fire lagene vi har beskrevet tidligere:
- selve
codex.exe codex-windows-sandbox-setup.exefor å håndtere alt oppsettsarbeid relatert til forhøyede rettighetercodex-command-runner.exefor å kjøre kommandoer med begrenset token- Den underordnede prosessen
Da jeg først startet med dette prosjektet, hadde jeg ingen klar formening om hvor det ville ende opp. Tilnærmingen min var å begynne med å instrumentere sandkassekapasiteten i grensen mellom Codex og operativsystemet. Denne tilnærmingen samsvarer godt med hvordan Codex’ sandkasse er implementert på MacOs og Linux.
Etter hvert som jeg lærte mer om de spesifikke verktøyene som Windows tilbyr, og gjennom dusinvis av beslutninger som balanserte sikkerhet og brukervennlighet, vokste systemet til sin nåværende form – flere binære filer, egendefinerte brukere, brannmurregler, et oppsettstrinn med forhøyede rettigheter, asynkrone prosesser og mer.
Det er ikke et spesielt enkelt system, men hver del av kompleksiteten ble lagt til av nødvendighet, for å bygge en sandkasse som både er trygg og, så langt som mulig, ikke er i veien for brukeren.
Da vi jobbet for å levere en god brukeropplevelse for Codex-brukere på Windows, var målet vårt å lage noe trygt som ikke gikk på bekostning av nytteverdi – hele poenget med å bruke Codex er å la agenter kunne utføre arbeid uten din konstante oppmerksomhet.
En av de største lærdommene fra dette prosjektet var at Windows ikke ga oss én primitiv løsning som uten videre kan oversettes til «trygg autonom kodeagent». Vi satte sammen flere verktøy og konsepter for å bygge noe sammenhengende. Noen av de tidlige ideene var blindspor. Det endelige designet var en hybrid av tidligere prototyper som hver for seg løste deler av problemet.
Den andre lærdommen var at sikkerhet for en kodeagent er noe helt annet enn mer klassisk applikasjonssikkerhet. Codex må fungere for ekte arbeidsflyter for utviklere. Utviklingsarbeidet handlet om å balansere kompatibilitet med agentiske arbeidsbelastninger mot reell håndheving. Denne spenningen formet avveiningene i det endelige designet.
Er du nysgjerrig på å se Codex-sandkassen i praksis? Prøv den.


