私が2025年9月に Codex のエンジニアリングチームへ加わった当時、Windows 版 Codex にはサンドボックス実装がありませんでした。そのため、Windows ユーザーは OpenAI のコーディングエージェントを使う際、どちらも十分とは言えない2つの選択肢から選ばざるを得ませんでした。
- コーディングエージェントが実行しようとするほぼすべてのコマンド(読み取り操作も含む)を逐一承認すること。これは非効率で煩雑です。Codex の大きな利点は、こうした面倒な作業を自分で行わなくて済むことです。
- 「Full Access」(フルアクセス)モードを有効にし、Codex が承認や制限なしですべてのコマンドを実行できるようにすること。操作はスムーズになりますが、その分、管理や統制は弱まります。
当社のコーディングエージェントである Codex は、CLI、IDE 拡張機能、デスクトップアプリなどを通じて、開発者のラップトップ上で動作します。Codex は、キーボードを操作するユーザーと、推論処理を担うクラウド上のモデルとのやり取りを管理します。
Codex はデフォルトで実際のユーザー権限を使って動作するため、ユーザーができる操作は基本的にすべて実行できます。これは非常に強力である一方、潜在的なリスクも伴います。コーディングモデルは、テスト実行、ファイルの読み取りや編集、Git ブランチの作成など、ローカルでコマンドを実行するようハーネスへ指示できます。そのため、Codex のデフォルトモードは、有用性と安全性の適切なバランスを取るよう設計されています。このモードでは、ほぼあらゆる場所にあるファイルを読み取れる一方、ファイルの書き込みはワークスペース(つまり Codex を実行しているディレクトリ)内に制限されます。また、ユーザーが明示的に許可しない限り、インターネットにはアクセスできません。こうしたファイル書き込みやネットワークアクセスの制限を安全な範囲で自動的に適用するには、それらを実際に強制できるサンドボックス環境が必要になります。
サンドボックスとは、制限付きの実行環境です。開発者が Codex を使用すると、コンピューターのオペレーティングシステムは権限を制限した状態でコマンドを実行し、その制約はプロセスツリー全体へ引き継がれます。すべての Codex コマンドは開始時点からサンドボックス内で実行され、その配下で生成されるすべてのプロセスも同じ境界内にとどまります。
Codex が効果的なサンドボックスを実現するには、オペレーティングシステムによって強制される分離機能が必要です。こうした機能を提供するユーティリティを備えた OS もあります(例: macOS の Seatbelt、Linux の seccomp や bubblewrap)が、Windows には現時点でこの種の機能が標準装備されていません。
Codex を Windows でも他の環境と同じように安全かつ快適に使えるようにするため、私たちは独自のサンドボックスを実装する必要がありました。
Windows には、分離のためのツールや基本機能がいくつか用意されています。どれも私たちの要件を十分に満たすものではありませんでしたが、AppContainer、Windows Sandbox、Mandatory Integrity Control(MIC)の整合性ラベル付けなど、いくつかの選択肢を検討しました。
AppContainer
- 概要:AppContainer は Windows ネイティブのサンドボックスであり、アプリ側が事前に必要なアクセス先を正確に把握していることを前提とした、機能ベースの分離モデルです。
- 採用を検討した理由:ベストエフォート型の制限ではなく、OS レベルでの実際の境界を提供できる点が魅力的でした。
- 採用しなかった理由:Codex は、機能範囲が厳密に限定された単一アプリではありません。シェル、Git、Python、パッケージマネージャー、ビルドツールに加え、エージェントが必要と判断した任意のバイナリまで含めた、自由度の高い開発ワークフローを扱います。実際には、その性質が AppContainer と噛み合いませんでした。強力な分離機能ではあるものの、「エージェントを開発者のように動作させる」という用途に比べると、対象とするワークロードがあまりにも限定的だったのです。
Windows Sandbox
- 概要:Windows Sandbox は、Microsoft が提供する使い捨て型の軽量 VM です。強固な分離境界を備えた新しい Windows デスクトップ環境が提供され、セッション終了時には内部で行った操作はすべて消去されます。
- 採用を検討した理由:理由は明白です。任意のソフトウェアとの互換性は AppContainer よりはるかに高く、セキュリティ面でも、より強力な隔離環境を提供できました。
- 採用しなかった理由:Codex は、セットアップやホスト/ゲスト間の橋渡しを必要とする別個の使い捨てデスクトップではなく、ユーザーの実際のチェックアウト、ツール、環境に対して直接動作する必要があります。また、根本的な製品上の問題もありました。Windows Sandbox は Windows Home エディションでは利用できません。
Mandatory Integrity Control(MIC)の整合性ラベル付け
- 概要:Windows には「整合性レベル」という概念があり、低、中、高といったレベルによって、システムがオブジェクトやプロセスをどの程度信頼するかが決まります。基本的なルールとして、整合性レベルの低いプロセスは、通常の ACL では許可されている場合でも、より高い整合性レベルを持つオブジェクトには書き込めません。たとえば、低整合性プロセスは信頼度が低いものとして扱われるため、対象オブジェクト側で明示的に許可するラベル変更が行われていない限り、通常の中整合性オブジェクトへの書き込みは Windows によってブロックされます。
- 採用を検討した理由:MIC は、机上では非常に洗練された方法に見えました。Codex を低整合性で実行し、書き込み可能なルートを低整合性へ再ラベル付けすることで、それ以外への書き込みを Windows 側に強制させる、という考え方です。これにより、実際の OS 機構に裏付けられた、管理者権限不要の方法を実現できるはずでした。
- 採用しなかった理由:ACL と同様に、整合性ラベルは実際のホストファイルシステムを変更します。しかも、この場合は意味上の変更範囲が特に広範です。ワークスペースを低整合性としてマークすることは、単に「Codex がここへ書き込める」という意味ではありません。低整合性プロセス全般が、その場所へ書き込めるようになることを意味します。実際の開発者マシンでは、これによってユーザーの実際のチェックアウト先が、ホスト側にとっての低整合性の受け皿になってしまいます。これは、単一のサンドボックス設計に対して慎重に対象を絞った ACL を付与する場合より、はるかにリスクが高いものでした。仮に中整合性の開発者ツールが引き続き動作するとしても、ワークスペースの基盤となる信頼モデルそのものが、封じ込めも正当化も難しい形で変化してしまいます。
こうした選択肢はいずれも現実的ではないと判断し、私たちは Windows ユーザーに優れた Codex 体験を提供するため、独自ソリューションの設計に着手しました。
最初に動作したプロトタイプでは、必要な分離を実現するために、Windows のさまざまな概念やツールを組み合わせて利用しました。当初からの目標の一つは、権限昇格を必要とせずに動作させることでした。つまり、Codex がサンドボックスのセットアップや実行のたびに、ユーザーへ管理者権限を求める必要がない状態を目指していました。そのためには、ファイル書き込みとネットワークアクセスという2つの要素に対して、どのように妥当な制限を設けるかを考える必要がありました。
ファイル書き込みをまったく制限しなければ、安全性の問題が生じます。一方で、制限を厳しくしすぎると、頻繁に承認を求める必要が生じ、ユーザーの生産性を損なってしまいます。この問題を解決するために、私たちは Windows の重要な2つの仕組みである SID と書き込み制限付きトークンを利用しました。
SID(セキュリティ識別子)は、Windows がアクセス許可と結び付ける識別情報です。ユーザーごとに SID があり、グループにも SID があり、さらには個々のログインセッションにも専用の SID が割り当てられます。たとえば、現在ログイン中のセッションには、S-1-5-5-X-Y のような SID が割り当てられている場合があります。ローカル管理者グループに割り当てられている SID は、S-1-5-32-544 のようなものです。
Windows では、実在のユーザーには対応しないものの、ACL(アクセス制御リスト)内で使用できる合成 SID も作成できます。ACL は、特定のファイルやディレクトリに対して、誰が読み取り・書き込み・実行できるかを定義するものです。そのため、SID は私たちのサンドボックスにとって有用な基本要素となります。マシン上の他のものに干渉することなく、Codex サンドボックス専用の SID を作成できるからです。
プロセストークンは、実行中のプロセスに対する ID や権限を定義する Windows のセキュリティオブジェクトです。これにより、プロセスが実行できる操作が決まります。書き込み制限付きトークンは、書き込み操作時に Windows が追加のアクセスチェックを行うようにする特殊なプロセストークンです。
書き込みを成功させるには、次の2つのチェックを通過する必要があります。
- 通常のユーザー ID(トークンの「所有者」)に、その操作を行う権限があること
- トークンの制限付き SID リストに含まれる少なくとも1つの SID にも、アクセス権が付与されていること
実際には、これらのチェックによって、サンドボックスがファイルシステムのどこを変更できるかを ACL で細かく定義できるようになり、書き込み操作に必要な粒度を実現できました。
SID と書き込み制限付きトークンを組み合わせることで、非昇格サンドボックスは次のように動作しました。
- サンドボックスのセットアップ時に、
sandbox-writeという合成 SID を作成します。 sandbox-writeSID には、以下に対する書き込み・実行・削除権限を付与しました。- 現在の作業ディレクトリ
config.tomlで設定された追加のwritable_roots
- 一方で、サンドボックスのセットアップでは、同じ SID に対して、次のような「書き込み可能領域内の読み取り専用」パスへの書き込みを明示的に拒否しました。
<cwd>/.git<cwd>/.codex<cwd>/.agents
- Codex は、
Everyone、現在ログイン中のセッション SID、sandbox-write合成 SID を制限付き SID リストに含む書き込み制限付きトークンで、コマンドを実行しました。
この仕組みにより、ファイル書き込み制限の問題は効果的に解決され、有望なアプローチに見えました。次に必要だったのは、サンドボックスのネットワークアクセスを制限する方法でした。
ネットワークアクセスの制限は、サンドボックスにおける重要な要素です。これがなければ、悪意あるコードがマシン上のデータをインターネットへ持ち出す可能性があります。私たちは権限昇格を避けたかったため、ネットワークトラフィックを強力に遮断する手段は限られていました。Windows Firewall のような利用したいツールも、通常は管理者権限なしでは設定できませんでした。
Windows Firewall を利用できなかったため、制御できる範囲には限界がありました。そこで私たちは、開発者が実際に利用するネットワーク対応ツールに対して、子環境がフェイルクローズになるようにしました。これにより、Git コマンドやパッケージインストーラーなどはサンドボックス内で失敗し、インターネット接続を伴う操作にはユーザーの承認が必要になります。狙いは、明らかな抜け道を封じることでした。プロキシ対応トラフィックを応答しないエンドポイントへ送信し、Git の HTTP(S) 通信にも同じ動作を適用し、SSH 経由の Git は即座に失敗するようにしました。さらに、小さな 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 の調整に時間がかかる負荷の高い処理が必要になる場合があります。 - ネットワーク保護が弱いこと:前述のとおり、これはあくまで「補助的」な対策であり、独自のネットワークスタックを実装したプログラムには確実に回避されます。また、敵対的なコードへの耐性を前提として設計されたものでもありませんでした。
最初の3つの課題は、エージェント型フローに十分対応できる柔軟なカスタムサンドボックス実装には、本質的に伴うものでした。ただし、ネットワーク抑止については事情が異なりました。
悪意あるエージェントが環境変数ベースのネットワーク抑止を簡単に回避できるだけでなく、善意のコードやバイナリであっても、環境変数のプロキシ設定を参照しなかったり、独自のソケットベースのネットワークコードを実装していたりすれば、同様に回避できてしまいます。私たちは、この点だけでも、より優れたサンドボックスモードに投資する十分な理由になると考えました。
より強力なネットワーク抑止を実現するため、私たちは Windows Firewall を利用したいと考えました。これにより、ユーザー単位またはプログラム単位で送信ネットワークトラフィックをブロックできます。しかし、いくつかの理由から、Codex ハーネスが起動したコマンドだけに適用される実用的なファイアウォールルールを効果的に作成することはできませんでした。
- Windows では、制限付きトークンの非プリンシパル ID に対してファイアウォールルールを適用することはできません。つまり、「制限付き SID リストに私たちの合成 SID を含む任意のトークン」に対してファイアウォールルールを適用することはできませんでした。
- 特定のバイナリに一致するファイアウォールルールは作成できますが、それで制限できるのは
codex.exe自体のネットワーク通信だけです。これは、Git や Python のプロセスのように、エージェントがユーザーに代わって起動するプロセスには適用されません。 - 他のファイアウォールの一致条件も、用途に適していませんでした。ユーザー単位のルールでは、非昇格設計において、制限付き子プロセスだけでなく実際の Windows ユーザーにも一致してしまいます。プログラムパスルールは粒度が粗すぎました。
codex.exeやpython.exeを全体としてブロックすることはできますが、この特定のサンドボックス化されたpython.exeの実行だけを対象にすることはできません。ポートベースやアドレスベースのルールも、求めているポリシーとは根本的に異なっていました。たとえば、私たちがブロックしたかったのはポート443ではなく、この特定の制限付きプロセスツリーによる任意の外向き通信です。
サンドボックス化されたコマンドだけにファイアウォールルールを適用するには、それらを「実際の」ユーザーではなく、別のプリンシパルとして実行する必要がありました。このアプローチにより、私たちは「昇格なし」という制約を緩和する新たな方向へ進むことになりました。
次のイテレーションである現在のサンドボックス実装では、セットアップ時に昇格された管理者権限が必要です。そのため、私はこれを「昇格サンドボックス」と呼んでいます。Codex がシステム上でコマンドを起動する境界においては、昇格サンドボックスは非昇格サンドボックスと似た構造になっています。引き続き、子プロセスは制限付きトークンの下で実行されます。具体的には、[Everyone, Logon, Synthetic] という同じ制限付き SID リストを持つ write_restricted トークンです。ただし、このトークンのプリンシパルは、もはや実際の Windows ユーザーではなく、Codex 自身が作成した次の2つのローカルユーザーのいずれかになります。
CodexSandboxOffline(ファイアウォールルールの対象になる方)CodexSandboxOnline(ファイアウォールルールの対象にならない方)
一見すると小さな違いですが、実際にはサンドボックスの仕組みや利用できるユーザー層、さらにセットアップや実行時の複雑さに大きな影響を与えます。
見た目は非昇格プロトタイプに近いものの、実際にコマンドを実行する専用の Windows ユーザーと、ファイアウォールルールが導入されています。(ただし、こうした新しい仕組みの導入により、サンドボックスがコマンドを実行して保護を開始するまでに、より多くのセットアップ作業が必要になりました。)
非昇格サンドボックス設計にもセットアップ手順はありましたが、比較的小規模なものでした。
- 必要に応じて合成 SID を作成する
- sandbox-write 合成 SID に ACL を適用する
一方、昇格サンドボックスでは、さらに多くの処理が必要です。
- まだ作成されていなければ合成 SID を作成する
- まだ作成されていなければ、オンライン用とオフライン用のサンドボックスユーザーを作成する
- 新しく作成したユーザーの認証情報をローカルに保存し、サンドボックスユーザー自身はアクセスできない場所で、Windows Data Protection API(DPAPI)を使って暗号化する
CodexSandboxOfflineユーザーによるすべての送信ネットワークアクセスをブロックするファイアウォールルールを作成する。すでに存在する場合は、その設定が正しいことを検証する
セットアップ段階には、さらに別の課題もありました。Codex のサンドボックスには、実際の Windows ユーザーと同等の読み取りアクセス権が求められます。制限付きトークンのプリンシパル SID が Windows ユーザーだった非昇格サンドボックスでは、これは自然に実現できていました。しかし、プリンシパルが新しい CodexSandbox ユーザーになると、同じことが自動的に成立するわけではありません。Windows 上の多くの関連ディレクトリでは、「Authenticated Users」に読み取り/実行権限が付与されています。代表的な例の1つが、ユーザーのプロファイルディレクトリです。既定では、Windows ユーザーは他の Windows ユーザーのプロファイルディレクトリを読み取れないため、多くのケースで単純なファイル読み取りすら失敗してしまいます。
これに対処するため、私たちはサンドボックスのセットアッププロセスにもう1つのレイヤーを追加しました。既存の ACL が存在しない可能性がある場所に対して、サンドボックスユーザーへ読み取り ACL を付与するための仕組みです。たとえば、次のような一般的な Windows ディレクトリです。
C:\Users\<real-user>C:\Windows\C:\Program Files\C:\Program Files (x86)\C:\ProgramData\
このディレクトリ一覧はベストエフォートであり、それぞれに ACL を適用する処理には大きなコストがかかるため、この処理は非同期で実行しています。これにより、ユーザーを待たせるサンドボックスのセットアップ処理が、それらの完了を待たずに進められるようになっています。
セットアップロジックを専用バイナリに切り出した理由の1つは、必要な場合にのみ UAC 境界を越えられるようにするためでした。しかし、より本質的な理由はアーキテクチャにあります。サンドボックスのセットアップは、codex.exe とは根本的に異なる役割を担っているからです。サンドボックスのセットアップロジックを専用バイナリに分離することで、codex.exe を通常の非昇格ハーネスのまま維持でき、Windows 専用のセットアップ機構によって他プラットフォーム上の codex.exe が肥大化するのを防げました。また、長時間かかるセットアップ処理をメインプロセスのライフサイクルから切り離せるようになり、サンドボックスに必要なさまざまなセットアップパスを1か所で扱えるようにもなりました。
Windows におけるユーザー境界とトークンログイン境界の仕組み上、非昇格サンドボックスのように制限付きトークンを作成し、その下でプロセスを起動する方法は使えませんでした。実際に別の Windows ユーザーとしてコマンドを起動するため、私たちが最初に考えたフローは次のとおりです。
codex.exeは実際の Windows ユーザーとして実行されます。次に、Codex は次の手順を順番に実行します。- サンドボックスユーザーに対して
LogonUserW(...)を呼び出す。 - そのサンドボックスユーザーのトークンに対して
CreateRestrictedToken(...)を呼び出す。 - その制限付きサンドボックスユーザートークンを使って
CreateProcessAsUserW(...)を呼び出し、最終的な子プロセスを起動する。
- サンドボックスユーザーに対して
しかし実際には、このフローは CreateProcessAsUserW(...) の段階で権限上の制約に突き当たり、うまく機能しませんでした。つまり、codex.exe はサンドボックスユーザー用の制限付きトークンを作成できても、境界の実ユーザー側から、そのトークンを使って子プロセスを確実に起動することはできませんでした。そこで必要になったのが、サンドボックスユーザーとしてあらかじめ実行されているプロセスです。これにより、制限を適用するステップと最終的なプロセス生成を、実ユーザー側ではなくサンドボックスユーザー側で行えるようになります。
この要件から生まれたのが codex-command-runner.exe です。これは、制限付きトークンを生成し、要求されたコマンドを起動することだけを役割とする新しいバイナリです。codex.exe にフロー全体(実ユーザー → サンドボックスユーザー → 制限付きトークン → 子プロセス)を実行させるのではなく、私たちはこのフローを2段階に分割しました。
Part 1
codex.exeはCreateProcessWithLogonW(...)を呼び出し、まだ制限付きトークンを使わない状態で、サンドボックスユーザーとしてcodex-command-runner.exeを起動します。
Part 2
- ランナー内部では、
OpenProcessToken(GetCurrentProcess(), ...)がランナー自身のトークンを開きます。このトークンは、すでにサンドボックスユーザーに属しています。 - ランナーは
GetTokenInformation(...)を呼び出してサンドボックスのログオン SID を取得し、その後CreateRestrictedToken(...)を呼び出して最終的な制限付きトークンを構築します。 - さらにランナー内部で、その制限付きトークンを使って
CreateProcessAsUserW(...)を呼び出し、実際の子プロセスを起動します。
アルベルト・アインシュタインは、「物事はできるだけ単純にすべきだが、それ以上に単純にしてはならない」と言いました。その精神に従い、私たちの設計はそれぞれの問題を十分に解決しています。最終的なアーキテクチャは、これまで説明してきた次の4つのレイヤーで構成されています。
codex.exe自身- 昇格が必要なセットアップ関連作業を担当する
codex-windows-sandbox-setup.exe - 制限付きトークンによるコマンド実行を担当する
codex-command-runner.exe - 子プロセス
私がこのプロジェクトに最初に取り組んだとき、最終的にどのような形に着地するのか、明確な見通しはありませんでした。まずは、Codex とオペレーティングシステムの境界部分にサンドボックス機能を組み込むところから始めました。このアプローチは、Codex のサンドボックスが macOS や Linux で実装されている方法ともよく一致しています。
Windows が提供する具体的なツールについて理解を深め、安全性と使いやすさのバランスを取るために何十もの判断を重ねる中で、このシステムは現在の形へと発展していきました。複数のバイナリ、専用ユーザー、ファイアウォールルール、昇格が必要なセットアップ手順、非同期プロセスなどが含まれています。
決して単純なシステムではありませんが、こうした複雑さはすべて必要に応じて加えられたものです。目的は、安全でありながら、可能な限りユーザーの邪魔にならないサンドボックスを実現することでした。
Windows 上で Codex ユーザーに優れた体験を提供するため、私たちは実用性を損なわない安全な仕組みを目指しました。そもそも Codex を使う意義は、エージェントが常に人の注意を必要とせずに作業を進められることにあります。
このプロジェクトで得た大きな教訓の1つは、Windows には「安全な自律型コーディングエージェント」にそのまま対応できる単一のプリミティブが存在しなかったことです。私たちは複数のツールや概念を組み合わせ、一貫性のある仕組みを構築しました。初期のアイデアの中には行き詰まったものもありました。最終的な設計は、それぞれ異なる課題を解決していた複数のプロトタイプを組み合わせたハイブリッド構成になっています。
もう1つの教訓は、コーディングエージェントのセキュリティは、従来のアプリケーションセキュリティとは性質が大きく異なるということです。Codex は、実際の開発者ワークフローの中で機能しなければなりません。今回のエンジニアリングでは、エージェント型ワークロードとの互換性と、実効性のある制御とのバランスを取る必要がありました。こうした相反する要件が、最終設計におけるさまざまなトレードオフにつながりました。
Codex サンドボックスの動作に興味がある方は、ぜひ実際にお試しください。


