Когда я присоединился к инженерной команде 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.
AppContainer
- Что это: AppContainer — это встроенная песочница Windows, основанная на модели изоляции с разграничением возможностей и предназначенная для приложений, которые заранее точно знают, к чему им нужен доступ.
- Почему: Это выглядит привлекательно, потому что обеспечивает реальную границу ОС, а не ограничения без жестких гарантий.
- Почему не стоит: Codex — это не одно приложение с узко заданной областью применения. Это обеспечивает рабочие процессы разработки с открытым набором действий: командные оболочки, Git, Python, менеджеры пакетов, инструменты сборки и любые другие исполняемые файлы, которые агент сочтёт необходимыми. На практике это означало, что AppContainer не подходил для решения этой задачи. Это была надежная изоляция, но для гораздо более узкого класса рабочих нагрузок, чем «позволить агенту действовать как разработчик».
Windows Sandbox
- Что: Песочница Windows — это одноразовая легковесная виртуальная машина Microsoft. Вы получаете чистый рабочий стол Windows с сильной границей изоляции, и все, что вы делаете внутри, исчезает после завершения сеанса.
- Почему: Это было интересно по очевидным причинам — гораздо лучше совместимо с произвольным ПО, чем AppContainer, и с точки зрения безопасности это намного более сильная изоляция.
- Почему нет: Codex должен напрямую работать с реальной рабочей копией пользователя, его инструментами и окружением, а не внутри отдельного временного рабочего стола, для которого потребовались бы настройка и взаимодействие между хостом и гостевой средой. Кроме того, у него была фундаментальная продуктовая проблема: «Песочница Windows» даже недоступна в редакциях Windows Home.
Маркировка целостности Mandatory Integrity Control (MIC)
- Что: В Windows существует понятие «уровни целостности», такие как низкий, средний и высокий, которые определяют степень доверия системы к объектам и процессам. Основное правило состоит в том, что процесс с более низким уровнем целостности не может выполнять запись в объект с более высоким уровнем целостности, даже если обычный список управления доступом (ACL) в иных обстоятельствах это разрешал бы. Например, процесс с низким уровнем целостности считается менее доверенным, поэтому Windows блокирует для него запись в обычные объекты со средним уровнем целостности, если только у этих объектов явно не изменена метка, разрешающая такой доступ.
- Почему: На бумаге MIC выглядел элегантно — запускать Codex с низким уровнем целостности, перемаркировать корневые каталоги с разрешенной записью как низкоцелостные и позволить Windows запрещать запись везде в остальных местах. Это дало бы нам способ без прав администратора, основанный на реальном механизме ОС.
- Почему не подходит: Как и ACL, метки целостности изменяют реальную файловую систему хоста, и в этом случае семантическое изменение имеет особенно широкий охват. Пометка рабочей области как имеющей низкий уровень целостности означает не просто «Codex может выполнять запись здесь». Это означает, что процессы с низким уровнем целостности в целом могут записывать туда данные. На реальной машине разработчика это превращает фактическую рабочую копию пользователя в приёмник с низким уровнем целостности для хоста, что гораздо рискованнее, чем предоставление тщательно нацеленных списков управления доступом (ACL) для одной архитектуры песочницы. Даже если инструменты разработчика со средним уровнем целостности продолжат работать, базовая модель доверия рабочей области изменилась таким образом, что это сложно локализовать и еще сложнее обосновать.
Оценив все варианты как непригодные, мы начали проектировать собственное решение, чтобы обеспечить пользователям Windows полноценную работу с Codex.
Наш первый рабочий прототип использовал сочетание концепций и инструментов 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 Firewall как опции мы ограничили свои возможности управления. Мы пытались сделать дочернюю среду работающей по принципу fail-closed, то есть с безопасным отказом, для тех сетевых инструментов, которыми разработчики действительно пользуются, чтобы команды Git, установщики пакетов и т. д. завершались с ошибкой в песочнице, а пользователю приходилось подтверждать любые операции с выходом в интернет. Идея заключалась в том, чтобы «отравить» очевидные пути обхода: направлять трафик с поддержкой прокси на нерабочую конечную точку, заставить HTTP(S)-транспорт Git делать то же самое, а также сделать так, чтобы Git через SSH сразу завершался с ошибкой. Кроме того, мы добавили небольшой каталог denybin в начало PATH и изменили порядок в PATHEXT, чтобы сценарии-заглушки 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=localhost,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:
CodexSandboxOffline(тот, на которого нацелены правила брандмауэра)CodexSandboxOnline(тот, на который правила брандмауэра не нацелены)
Эта на первый взгляд небольшая деталь на самом деле имеет большие последствия для песочницы, для того, кто может ею пользоваться, и для сложности ее настройки и выполнения во время работы.
Визуально она похожа на прототип без повышения привилегий, но с добавлением правил брандмауэра и выделенного пользователя Windows, который и выполняет команды. (Однако введение этих новых концепций означает, что до того, как песочница сможет начать запускать и защищать команды, нужно выполнить больше работы по настройке.)
В конструкции песочницы без повышения привилегий этап настройки был простым, но сам объём настройки был сравнительно небольшим:
- Создать синтетический SID при необходимости
- Применить ACL для синтетического SID sandbox-write
Однако песочнице с повышением привилегий нужно делать больше.
- Создать синтетический SID, если он ещё не создан
- Создать пользователей песочницы для онлайн- и офлайн-режимов, если они еще не созданы
- Сохранить учетные данные вновь созданных пользователей локально и зашифровать их с помощью Windows Data Protection API (DPAPI) в месте, которое пользователи песочницы фактически не могут прочитать
- Создать правила брандмауэра, блокирующие весь исходящий сетевой доступ для пользователя
CodexSandboxOffline, или, если они уже существуют, проверить их корректность
На этапе настройки возникает дополнительная сложность. Ожидается, что песочница Codex имеет доступ на чтение, эквивалентный доступу фактического пользователя Windows. В песочнице без повышенных привилегий, где основным SID ограниченного токена был пользователь Windows, этого удалось добиться. Однако это не обходится без затрат, когда принципал становится новым пользователем CodexSandbox. Многие соответствующие каталоги в 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 оставаться обычным, неповышенным управляющим компонентом; не раздувать codex.exe на других платформах Windows-специфичной логикой настройки; отделить более длительные задачи настройки от времени жизни основного процесса; и сосредоточить обработку разных сценариев настройки песочницы в одном месте.
Из-за особенностей работы границ входа пользователей и токенов в 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 в действии? Попробовать.


