Градење безбеден, ефикасен sandbox за овозможување на Codex на Windows
Од David Wiesen, член на техничкиот тим
Кога му се приклучив на инженерскиот тим на Codex во септември 2025 година, Codex за Windows немаше имплементација на тест-средина, што значеше дека корисниците на Windows беа принудени да избираат меѓу две незадоволителни опции кога ги користеа агентите за кодирање на OpenAI:
- Да одобруваат речиси секоја команда (дури и читања) што агентот за кодирање сакаше да ја изврши, што е неефикасно и здодевно. Голема придобивка од користењето на Codex е тоа што не мора самите да ја вршите целата здодевна работа.
- Да го овозможат режимот Full Access: да му дозволат на Codex да ги извршува сите команди без одобрување или ограничувања, што ги намалува проблемите, но по цена на надзорот.
Codex, нашиот агент за кодирање, работи на лаптопите на програмерите - без разлика дали тоа е преку CLI, IDE-екстензијата или десктоп-апликацијата. Управува со разговор помеѓу човек пред тастатура и модел што работи во облакот за извршување инференција.
Codex стандардно работи со дозволите на вистински корисник, што значи дека може да прави сè што може и корисникот. Ова е моќно и потенцијално опасно. Моделот за кодирање може да наложи рамката да извршува команди локално, од извршување тестови до читање или уредување датотека до создавање Git гранка, па затоа стандардниот режим на Codex се обидува да го најде вистинскиот баланс меѓу ефикасност и безбедност. Овој стандарден режим му дозволува на Codex да чита датотеки речиси секаде и да запишува датотеки во вашиот работен простор (односно директориумот каде што го извршувате Codex), без пристап до интернет освен ако не наведете дека го сакате. За да се постигне ова автоматско ограничување на запишувањето датотеки и пристапот до мрежата во безбедни рамки, на Codex му е потребна тест-средина што навистина ги спроведува овие ограничувања.
Тест-средината е ограничена околина за извршување. Кога програмер користи Codex, оперативниот систем на неговиот компјутер стартува команда со намалени дозволи, а тие ограничувања се пренесуваат низ дрвото на процеси. Секоја команда на Codex е изолирана во тест-средина од самиот почеток, а секој потомски процес останува во рамките на истата граница.
На Codex му се потребни функции за изолација што ги спроведува оперативниот систем на компјутерот за да имплементира ефикасен тест-средина. Некои оперативни системи обезбедуваат алатки што тоа го прават добро (на пр., Seatbelt на MacOs, seccomp или bubblewrap на Linux); сепак, Windows во моментов не обезбедува ваков тип можност веднаш по инсталацијата.
За да го направиме Codex исто толку безбеден и пријатен за користење на Windows како што веќе е насекаде на друго место, требаше да имплементираме сопствена тест-средина.
Windows нуди некои алатки и примитиви за изолација. Иако ниту една од нив не ги исполни целосно нашите барања, разгледавме повеќе потенцијални решенија - имено, AppContainer, Windows Sandbox и Mandatory Integrity Control labeling.
AppContainer
- Што: AppContainer е изворната тест-средина на Windows, модел на изолација базиран на можности, создаден за апликации што однапред точно знаат до што треба да пристапат.
- Зошто: Привлечен бидејќи нуди вистинска граница на ОС наместо ограничувања со најдобри напори.
- Зошто не: Codex не е една апликација со тесно дефиниран опсег. Ги придвижува отворените работни текови за програмери: командни обвивки, Git, Python, менаџери на пакети, алатки за градење и какви било други бинарни извршни датотеки за кои агентот ќе одлучи дека му се потребни. Во практика, тоа го направи AppContainer несоодветен за проблемот. Тоа беше силна изолација, но за многу потесна класа работни оптоварувања отколку „да му се дозволи на агент да работи како програмер“.
Windows тест-средина
- Што: Windows тест-средина е лесна виртуелна машина на Microsoft за еднократна употреба. Добивате свеж Windows-десктоп со силна граница на изолација, а сè што ќе правите во него исчезнува кога сесијата ќе заврши.
- Зошто: Интересен од очигледни причини - многу покомпатибилен со произволен софтвер од AppContainer, а од безбедносна перспектива тоа е многу посилна рамка.
- Зошто не: Codex треба да дејствува директно врз вистинското „чекирање“, алатки и околина на корисникот, а не во посебен привремен десктоп што би барал поставување и поврзување меѓу „хост“ и „гостин“. Исто така, имаше и суштински проблем со производот: Windows тест-средина дури не е ни достапен во SKU на Windows Home.
Mandatory Integrity Control (MIC) означување интегритет
- Што: Windows има концепт наречен „нивоа на интегритет“, како што се ниско, средно и високо, кои одредуваат колку системот им верува на објектите и процесите. Основното правило е дека процес со пониско ниво на интегритет не може да запишува во објект со повисоко ниво на интегритет, дури и ако вообичаената ACL инаку би го дозволила тоа. На пример, процес со низок интегритет се третира како помалку доверлив, па Windows го блокира да запишува во нормални објекти со среден интегритет, освен ако тие објекти не се изречно преозначени за да му се дозволи тоа.
- Зошто: MIC изгледаше елегантно на хартија - стартувајте го Codex со низок интегритет, преназначете ги корените за запишување како со низок интегритет и оставете Windows да спроведува забрана за запишување насекаде на друго место. Тоа ќе ни овозможеше пат без администраторски права, поддржан од вистински механизам на ОС.
- Зошто не: Како и ACL, ознаките за интегритет го менуваат вистинскиот систем на датотеки на хостот, а во овој случај семантичката промена е особено опсежна. Означувањето на работен простор како простор со низок интегритет не значи само „Codex може да запишува тука.“ Тоа значи дека процесите со ниско ниво на интегритет општо земено можат да запишуваат таму. На вистинска машина на програмер, тоа ја претвора вистинската работна копија на корисникот во понор со низок интегритет за хостот, што е многу поризично отколку да се доделат внимателно насочени ACL-права за еден дизајн на изолирана околина (тест-средина). Дури и ако алатките за програмери со среден интегритет продолжат да работат, основниот модел на доверба на работниот простор се променил на начин што е тешко да се ограничи и уште потешко да се оправда.
Откако ги оценивме сите опции како неефикасни, почнавме да го дизајнираме сопственото решение за да донесеме добро искуство со Codex за корисниците на Windows.
Нашиот прв функционален прототип користеше комбинација од концепти и алатки на Windows за да ја имплементира изолацијата што ни беше потребна. Од самиот почеток, една од целите беше ова да функционира без да бара елевација, што значи дека Codex не би морал да му прикажува промпт на корисникот за администраторски привилегии само за да ја постави или да ја изврши тест-средината. Тоа значеше да се утврди како да се постават разумни ограничувања за две работи: запишување во датотеки и пристап до мрежата.
Ако воопшто не го ограничевме запишувањето во датотеки, ќе имавме безбедносен проблем. Ако го ограничевме премногу, тест-средината ќе ја намалеше продуктивноста на корисникот, барајќи постојани одобрувања. За да го решиме овој проблем, се потпревме на два важни градбени блока во Windows: SID и токени со ограничено запишување.
SID, или безбедносен идентификатор, е идентитетот што Windows го поврзува со дозволите. Секој корисник има SID, групите имаат SID, па дури и една единствена сесија за најава добива свој SID. На пример, тековна најавена сесија може да има SID како што е S-1-5-5-X-Y. SID доделен на локалната група администратори може да биде S-1-5-32-544.
Windows исто така дозволува создавање синтетички SID што не одговараат на вистински корисник, но сепак можат да се појават во ACL (листи за контрола на пристап), кои дефинираат кој може да чита/запишува/извршува одредени датотеки или директориуми. Тоа ги прави SID корисен примитив за нашиот тест-средина: можеме да создадеме SID исклучиво за тест-средината на Codex, без да влијаеме на што било друго на машината.
Процесните токени се безбедносни објекти во Windows што ги дефинираат идентитетот и привилегиите за процес што се извршува. Тие одредуваат кои дејства може да ги изврши еден процес. Токен со ограничено запишување е посебен тип процесен токен кој прави Windows да изврши дополнителна проверка на пристапот при операции за запишување.
За запишувањето да успее, мора да поминат две проверки:
- Нормалниот кориснички идентитет (сопственикот на токенот) мора да има дозвола за тоа
- Исто така, пристап мора да биде доделен и на барем еден SID во листата на ограничени SID на токенот
Во пракса, овие проверки ни овозможија да користиме ACL за точно да дефинираме каде тест-средината може да го менува датотечниот систем, што ни ја даде потребната грануларност околу операциите на запишување.
Со SID и токени со ограничено запишување, нашиот тест-средина без елевација функционираше вака:
- Поставувањето на тест-средината создаде синтетички SID наречен
sandbox-write. - На SID со
sandbox-writeму беше доделен пристап за запишување, извршување и бришење до- Тековниот работен директориум
- Сите дополнителни
writable_rootsшто се конфигурирани воconfig.toml.
- Поставувањето на тест-средината експлицитно му забрани на истиот SID пристап за запишување до локации „само за читање во рамки на она што може да се запише“, како што се:
<cwd>/.git<cwd>/.codex<cwd>/.agents
- Codex стартуваше команди под токен со ограничено запишување чија листа на ограничени SID ги вклучува
Everyone, SID на тековно најавената сесија и синтетичкиот SIDsandbox-write.
Овој тек ефикасно го реши ограничувањето на запишување датотеки и изгледаше ветувачки. Сега ни требаше решение за ограничување на пристапот до мрежа на тест-средината.
Ограничувањето на пристапот до мрежа е важен дел од тест-средината; без него, злонамерен код би можел да извлече податоци од машината кон интернет. Бидејќи сакавме да избегнеме барање за елевација, имавме ограничени опции за силно блокирање на мрежниот сообраќај. Алатките што сакавме да ги користиме, како Windows Firewall, генерално не можеа да се инсталираат без администраторски дозволи.
Без Заштитниот ѕид на Windows како опција, го ограничивме она што можевме да го контролираме. Се обидовме подредената околина да ја направиме fail-closed (затворена при неуспех) за видовите мрежни алатки што програмерите навистина ги користат, така што Git командите, инсталаторите на пакети итн. би не успевале во изолираното опкружување, а корисникот би морал да одобри какви било операции што се насочени кон интернет. Идејата беше да се „затрујат“ очигледните излези: да се испрати сообраќајот што препознава прокси-сервер до мртва крајна точка, да се натера HTTP(S) транспортот на Git да го прави истото и да направи Git преку SSH веднаш да потфрли. Покрај тоа, додадовме мал директориум denybin на почетокот на PATH и го прередивме PATHEXT за stub скриптите за SSH и SCP да се разрешуваат пред вистинските извршни датотеки.
На пример, еве некои од конкретните преназначувања на околината што ги користевме за ограничување на мрежниот пристап:
HTTPS_PROXY=http://127.0.0.1:9ALL_PROXY=http://127.0.0.1:9GIT_HTTPS_PROXY=http://127.0.0.1:9NO_PROXY=локален домаќин,127.0.0.1,::1GIT_SSH_COMMAND=cmd /c exit 1
Тоа фати многу нормален сообраќај управуван од алатки, но сè уште беше само советодавно. Процесот можеше да ја игнорира околината, да го заобиколи PATH или едноставно директно да отвори „приклучници“ - премногу ризично.
Како и кај секоја интересна софтверска имплементација, првиот прототип имаше некои предности и недостатоци. Иако ја завршуваше работата со само неколку стандардни можности на Windows, овозможуваше многу експлицитни и грануларни запишувања во датотечниот систем и работеше без елевација - со што се намалуваше потребата корисниците да прифаќаат прекумерни промпт за елевација или да бидат администратори на својата локална машина - имаше некои сериозни недостатоци, од кои дел го дисквалификуваа како наш финален дизајн:
- Брзина на поставување: примената на ACL на работниот простор може да биде скапа во зависност од топологијата на директориумот на работниот простор.
- Отпечаток: применувавме вистински ACL на системот на програмерот, иако отпечатокот не е особено инвазивен бидејќи сите применети ACL се однесуваат на специјално создаден синтетички SID што го користи само тест-средината.
- Семантика што тешко се менува: Потпирањето на ACL за ограничувања засновани на датотеки значи дека менувањето на семантиката на тест-средина е скапо и сложено. Додека на macOS можеме динамички да го промениме начинот на кој го генерираме
.sbplдатотека што се користи за конфигурирање на Seatbelt, Windows тест-средина може да бара бавна и ресурсно интензивна операција за приспособување на ACL. - Заштитата на мрежата е слаба. Како што беше спомнато претходно, таа беше „советодавна“, сигурно ќе беше заобиколена од некои програми што имплементираа сопствена мрежна стак-архитектура и не беше дизајнирана да издржи на спротивставен код.
Првите три проблеми се својствени за сопствена имплементација на тест-средина што е доволно флексибилна за агентски текови. Но, приказната со потиснувањето на мрежата беше поинаква.
Покрај тоа што злонамерен агент лесно можеше да го заобиколи потиснувањето на мрежата базирано на околина, и многу добронамерен код/бинарни датотеки исто така ќе го заобиколеа едноставно ако не ги почитуваа прокси-променливите од околината или ако имплементираа сопствен мрежен код базиран на „приклучници“. Сметавме дека овој аспект е доволен за да размислиме за вложување во подобар режим на тест-средина.
За да добиеме подобро потиснување на мрежата, сакавме да користиме Windows Firewall, кој ни овозможува да блокираме излезен мрежен сообраќај за корисници или програми. За жал, не можевме ефикасно да создадеме функционално правило на „заштитен ѕид“ што би се применувало само на командите што ги стартува Codex рамката, од неколку причини:
- Windows не дозволува усогласување на правило на заштитниот ѕид со идентитет што не е главен на ограничен токен. Ова значи дека не можевме да примениме правило на заштитен ѕид на „секој токен што го вклучува нашиот синтетички SID во својата листа на ограничени SID.“
- Иако можевме да создадеме правило на заштитен ѕид што одговара на конкретен бинарен фајл, тоа ни дозволува да го ограничиме мрежното поврзување само за самиот
codex.exe. Тоа не би се применувало на процесите што агентот ги стартува во име на корисникот, како што се процесите на Git или Python. - И другите димензии за совпаѓање на заштитниот ѕид имаа погрешна форма. Правилата со кориснички опсег сè уште се совпаѓаа со вистинскиот корисник на Windows во дизајнот без покачени привилегии, а не само со ограничениот подреден процес. Правилата за патеки на програми беа премногу груби: тие можеа генерално да ги блокираат
codex.exeилиpython.exe, но не и ова конкретно повикување наpython.exeво изолирана околина. Правилата засновани на порта или адреса исто така беа целосно погрешна политика. На пример, не сакавме да го блокираме портот 443; сакавме да го блокираме произволниот излезен пристап за ова конкретно ограничено стебло на процеси.
За да примениме правило на заштитен ѕид специфично на нашите тест-средина-ирани команди, требаше да ги извршуваме како посебен посредник, а не како „вистинскиот“ корисник. Овој пристап нè одведе по нов пат, во кој го олабавивме нашето ограничување „без елевација“.
Следната итерација на тест-средината, која е нашата тековна имплементација, бара зголемени администраторски дозволи при поставувањето. Затоа го нарекувам „тест-средина со зголемени привилегии“. На границата каде што Codex стартува команда на системот, тест-средината со зголемени привилегии изгледа исто како онаа без зголемени привилегии. И понатаму извршува подредени процеси под ограничен токен - слично, токен write_restricted со истата листа на ограничени SID [Everyone, Logon, Synthetic]- меѓутоа, субјектот на овој токен повеќе не е вистинскиот корисник на Windows, туку еден од двата локални корисници создадени од самиот Codex:
Codexтест-срединаOffline(оној што е цел на правилата на заштитен ѕид)Codexтест-срединаOnline(оној што не е цел на правилата на заштитен ѕид)
Овој навидум мал детал всушност има големи импликации за тест-средината, кој може да го користи и за сложеноста на неговото поставување и извршување во време на работа.
Визуелно е сличен на прототипот без елевација, со воведување правила на заштитен ѕид и посветен корисник на Windows, кој всушност ги извршува командите. (Сепак, воведувањето на овие нови концепти значи дека има повеќе работа за поставување пред тест-средината да почне да извршува и да штити команди.)
Дизајнот на тест-средина без елевација имаше едноставен чекор за поставување, но тој беше релативно мал:
- Создајте синтетички SID ако е потребно
- Применете ACL за синтетичкиот SID sandbox-write
Меѓутоа, тест-средината со елевација, меѓутоа, има повеќе работа.
- Создајте синтетички SID, ако веќе не е создаден
- Создајте ги онлајн и офлајн корисниците на тест-средина, ако веќе не се создадени
- Складирајте ги локално акредитивите на новосоздадените корисници и шифрирајте ги со Windows Data Protection API (DPAPI) на место што корисниците на тест-средината всушност не можат да ги читаат
- Создајте правила на заштитен ѕид што го блокираат целиот излезен мрежен пристап за корисникот
Codexтест-срединаOfflineили, ако веќе постојат, потврдете дека се точни
Постои дополнителна компликација во фазата на поставување. Се очекува тест-средината на Codex да има пристап за читање еквивалентен на реалниот корисник на Windows. Во тест-средина без зголемени привилегии, каде што principal SID на ограничениот токен беше корисникот на Windows, ова беше постигнато. Сепак, тоа не доаѓа бесплатно кога субјектот станува нов корисник на Codexтест-средина. Многу релевантни директориуми во Windows им доделуваат дозволи за читање/извршување на „Автентицирани корисници“. Еден значаен пример е директориумот на профилот на корисникот. Стандардно, корисниците на Windows не можат да ги читаат директориумите на профилите на други корисници на Windows, па затоа дури и едноставните читања на датотеки во многу сценарија би завршиле неуспешно.
За да го решиме ова, додадовме уште еден слој во процесот на поставување на тест-средината - слој за доделување ACL за читање на корисниците на тест-средина таму каде што такви ACL можеби веќе не постојат. На пример, до некои најчесто користени директориуми на Windows:
C:\Users\<real-user>C:\Windows\C:\Program Files\C:\Program Files (x86)\C:\ProgramData\
Бидејќи оваа листа на директориуми е најдобар напор и инсталирањето ACL на секој од нив може да биде прилично скапо, ја извршуваме оваа логика асинхроно, така што чекорот за поставување на тест-средината, кој е блокирачки за корисниците, не мора да чека тие да завршат.
Ја вклопивме логиката за поставување во сопствена бинарна датотека, делумно за да ја преминуваме границата на UAC само кога е потребно. Но подлабоката причина беше архитектонска: поставувањето на тест-средина има суштински различна улога од codex.exe. Задржувањето на логиката за поставување на тест-средина во посветен бинарен фајл му дозволи на codex.exe да остане нормален рамка без елевација; спречи машинерија за поставување специфична за Windows да го „надуе“ codex.exe на други платформи; одвои подолготрајна работа за поставување од животниот век на главниот процес; и ни даде едно место за ракување со различните патеки за поставување што му беа потребни на тест-средината.
Поради начинот на кој функционираат границите на најава на корисници на Windows и токени, не можевме да продолжиме да создаваме ограничен токен и да стартуваме процес под него како што можевме со тест-средината без елевација. За навистина да стартуваме команди како различен корисник на Windows, нашата прва идеја беше следниов тек:
codex.exeсе извршува како вистинскиот корисник на Windows. Потоа, по редослед, Codex:- Го повикува
LogonUserW(...)за корисникот на изолираната околина. - Го повикува
CreateRestrictedToken(...)на тој токен на корисникот на тест-средина. - Користејќи го тој ограничен токен на корисникот на тест-средина, се повикува
CreateProcessAsUserW(...)за да се стартува конечниот подреден процес.
- Го повикува
Во практика, тој посакуван тек не функционираше поради пречка поврзана со привилегии кај CreateProcessAsUserW(...). Ова значи дека codex.exe можеше да создаде ограничен токен за корисникот во тест-средина, но не можеше сигурно да стартува подреден процес со тој токен од страната на вистинскиот корисник на границата. Ни требаше процес што веќе се извршуваше како корисник на тест-средина - тоа би овозможило чекорот за ограничување и конечното создавање процес да се случат од страната на границата на корисникот на тест-средината, наместо од страната на вистинскиот корисник.
Тоа барање доведе до codex-command-runner.exe, нова бинарна извршна датотека чија единствена задача е да создаде ограничен токен и да ја стартува побараната команда. Наместо да бараме од codex.exe сам да го прави целиот тек (вистински корисник → корисник на тест-средина → ограничен токен → подреден процес), го поделивме текот на два дела:
Дел 1
codex.exeповикуваCreateProcessWithLogonW(...)за да го стартуваcodex-command-runner.exeкако корисник на тест-средина, без сè уште да користи ограничен токен.
Дел 2
- Во извршителот,
OpenProcessToken(GetCurrentProcess(), ...)го отвора сопствениот токен на извршителот, кој веќе му припаѓа на корисникот на тест-средина. - Извршителот повикува
GetTokenInformation(...)за да го извлече SID на најавата во тест-средина, а потоаCreateRestrictedToken(...)за да го изгради конечниот ограничен токен. - Сè уште во извршителот, повикува
CreateProcessAsUserW(...)со тој ограничен токен за да го стартува вистинскиот подреден процес.
Алберт Ајнштајн рекол: „Сè треба да се направи наједноставно што може, но не поедноставно од тоа.“ Во тој дух, нашиот дизајн соодветно го реши секој проблем. Финалната архитектура ги има четирите слоја што претходно ги опфативме:
- самиот
codex.exe codex-windows-sandbox-setup.exeза ракување со целата работа поврзана со елевација на поставувањетоcodex-command-runner.exeза извршување команди со ограничен токен- Подреден процес
Кога првпат му пристапив на овој проект, немав силно чувство каде ќе заврши. Мојот пристап беше да почнам со инструментализирање на можноста за создавање тест-средина во границата меѓу Codex и оперативниот систем. Овој пристап тесно се совпаѓа со начинот на кој тест-средината на Codex е имплементирана на MacOs и Linux.
Како што учев повеќе за конкретните алатки што Windows ги обезбедува и преку десетици одлуки што балансираат меѓу безбедност и леснотија на користење, системот прерасна во својата сегашна форма - повеќе бинарни фајлови, сопствени корисници, правила на заштитен ѕид, чекор за поставување со елевација, асинхрони процеси и повеќе.
Тоа не е особено едноставен систем, но секој сложен дел беше додаден од неопходност, за да се изгради тест-средина што е и безбеден и, колку што е можно, не му пречи на корисникот.
Работејќи да испорачаме добро корисничко искуство за корисниците на Codex на Windows, нашата цел беше да создадеме нешто безбедно што не прави компромис со корисноста - целата поента на користењето Codex е агентите да можат да завршуваат работа без вашето постојано внимание.
Една од најголемите лекции од овој проект беше дека Windows не ни даде еден примитив што чисто се мапира на „безбеден автономен агент за кодирање“. Комбиниравме неколку алатки и концепти за да изградиме нешто кохерентно. Некои рани идеи дојдоа до ќор-сокак. Финалниот дизајн беше хибрид од претходни прототипи, од кои секој решаваше дел од проблемот.
Другата лекција беше дека безбедноста за агент за кодирање е поинаква од покласичната безбедност на апликации. Codex мора да работи за вистински програмерски работни текови. Инженерската работа беше за балансирање на компатибилноста со агентски оптоварувања наспроти вистинското спроведување. Таа тензија ги обликуваше компромисите во финалниот дизајн.
Љубопитни сте да ја видите тест-средината на Codex во акција? Пробајте ја.


