サンドボックスとセキュリティ
ここで分離が重要になる理由
「ここで分離が重要になる理由」というセクションエージェントはあなたに代わってファイルを読み、シェルコマンドを実行し、外部 API を呼び出します。気にすべき障害が悪意であることはまれです — あるのは、パスを読み違えて作業中のチェックアウトを書き換えてしまうエージェントであり、レビューを終えていないブランチをプッシュしてしまうエージェントです。したがって、製品が答えなければならない問いは「エージェントは信頼できるか」ではなく、「エージェントが誤ったときの影響範囲はどこまでか」です。
Control Center はこれに層で答えており、その層は意図的に独立しています。ひとつが欠けても、ほかは保たれます。これは重要なことです。というのも、最も外側の層である OS サンドボックスだけが唯一の条件付きの層であり、バックエンドを提供するホストに依存し、Windows ではどのホストも提供しないからです。
エージェントを実際に制約しているもの
「エージェントを実際に制約しているもの」というセクションサンドボックスの有無にかかわらず、あらゆるホストでエージェントの実行を制約するものが 5 つあります。いずれもカーネルの境界ではありませんが、どれも現実のものです。ホストがバックエンドを提供する場合、OS サンドボックスはそれらの上に位置し、以下に挙げる「サンドボックスが追加するものと、それが止まる場所」で、それによって何が変わるかを説明します。
エージェント自身のコピーオンライトのワークツリー。 すべての会話は、リンクされた各リポジトリのチェックアウトを独自に用意し、バイト単位のコピーではなく同梱の rift ネイティブによるコピーオンライトでクローンします。そのため、分離はデフォルトにできるほど低コストです。ワークスペースに追加した登録済みリポジトリは、エージェントが作業するディレクトリではありません — 同じリポジトリに触れる 2 つの会話は互いの編集を見ることができず、どちらもあなたのチェックアウトを編集していません。
粒度については正確に述べておく価値があります: ワークツリーは会話単位であり、エージェント単位ではありません。 同じ会話の 2 つのエージェントは、その会話の repos/ を 共有 する別々のオーバーレイ作業ディレクトリを受け取ります — ひとつの変更に対して協力しているのですから、これが狙いです — 一方で、それぞれのプライベートなエージェントディレクトリは分離されたままです。rift が出荷される環境ではコピーオンライトが唯一のバックエンドです。reflink できないファイルシステムや、リポジトリとは別のボリュームにあるデータディレクトリでは、フォールバックせずにプロビジョニングが失敗します。例外は Windows です。そこにはコピーオンライトのバックエンドが存在しないため、git worktree がバックエンドになります。これは暗黙の劣化ではありません。
内蔵ハーネスのファイルツールにおけるパス制限。 ハーネスの read、write、edit、apply_patch、search、find、search_files ツールは、すべてのパスを実行の作業ディレクトリと共有ルート — 会話の repos/ ディレクトリ(ワークツリーが置かれる場所)と、存在する場合のスペースの添付ファイルディレクトリ — を基準に解決し、その外側に着地するものは拒否します。絶対パスは、すでに内側にあった場合にのみ受け入れられます。ワークツリー内から外を指すシンボリックリンクも解決され、拒否されます。これが、サンドボックスが関与していなくてもエージェントが ~/.ssh に write できない理由です。
モードのツールサーフェス。 会話のモードは、その実行でどのツールがそもそも実体化されるかを決めます。読み取り専用のモード(plan、review、orchestrate)では、変更を伴うツールはそもそもレジストリに存在せず、それらのモードのシェルコマンドポリシーは、あらゆる変更コマンドをプロンプトするのではなく、そもそも拒否します — git commit、git push、npm install、docker などすべてです。存在しないツールは呼び出せません。これは、存在してゲートされているツールよりも強い保証です。
統一されたアクションガードレール。 変更を伴うすべてのツールは、生み出しうるエフェクトクラスを宣言し、ポリシーエンジンは呼び出しが実行される前に、それぞれを許可・確認・拒否のいずれかに解決します。承認者が接続されていない prompt は 拒否 に解決されます — 誰も答えられない問いが「はい」になることはありません。解決モデルについてはガードレールを参照してください。
ブローカー経由の資格情報とサニタイズされた環境。 資格情報は起動ごとに発行され、実行の終了時に取り消されます。実行が持つ GitHub トークンは読み取りはできてもプッシュはできません — 後述の「プッシュは Control Center を通る」を参照してください。ACP、ハーネスの bash、ネイティブラップ下の Claude Code は、プロセスが始まる前に、動的リンカーとインタープリターのインジェクションベクター(LD_PRELOAD、DYLD_INSERT_LIBRARIES、NODE_OPTIONS、GIT_SSH_COMMAND とその類)を除去した環境を受け取ります。NoSandboxAdapter 経由の Claude Code はホストの環境を継承します。
それらの境界が薄くなる場所
「それらの境界が薄くなる場所」というセクションハーネスのファイルツールは子プロセスではなく_サーバープロセス内_で動作するため、サンドボックスプロファイルが接続されたとしてもそれを制約できません — サンドボックス化されたコマンドランナーを通るのは bash だけです。それらの閉じ込めは前述のパスチェックであり、したがってこのチェックは第二の防衛線ではなく、まさに構造を支える要素です。
bash ツールは、正確さが求められるもうひとつの箇所です。そのコマンドはモードのコマンドポリシーに対して評価され、その後、サニタイズされた環境とワークツリーを作業ディレクトリとしてスポーンされます。バックエンドが存在する場合、そのスポーンはラップされるため、シェルコマンドがワークツリーの外に書き込むのを止めるのはサンドボックスです。存在しない場合 — Windows、または bwrap と socat のない Linux — コマンドポリシーが、コマンドとディスクの残りの間にある唯一のものです。chat モードでは、ポリシーは固定リスト(特権昇格、システムとディスクの破壊、コンテナと名前空間の脱出)をハード拒否し、リモート状態の変更(git push、gh pr create、パッケージの公開とインストール)では確認を求めます。どちらのリストにもないものは実行されます。パイプライン、チェーン、サブシェルは解析され、各サブコマンドが個別に評価され、最も制限の厳しい決定が優先されます。
Claude Code をアダプターとして使う場合が、サンドボックスが最も大きな重みを担うケースです。Control Center はそれを --dangerously-skip-permissions 付きで起動します。非対話の claude -p が自身の承認プロンプトで永久にブロックしてしまうからです。その読み取り、書き込み、編集の呼び出しは自プロセス内で行われ、Control Center はそれらを決して見ません。Bash 呼び出しは実行前にサーバー上のフックへ送られ、フックがコマンドラインを分類して対応するルールに問い合わせます。Control Center が提供する mcp__* ツールは、これまでどおりゲートを通ります。バックエンドが存在する場合、それらの見えない呼び出しも依然としてサンドボックスのラップ内で行われるため、それらを取り囲む境界は OS です。存在しない場合、何もありません。各アダプターはこれを自身のエンフォースメントマトリクスで明示しています — アダプターの正直さマトリクスを参照してください。
プッシュは Control Center を通る
「プッシュは Control Center を通る」というセクションエージェント単位の権限フラグはありません。エージェントがコミットの作成、プッシュ、プルリクエストの作成、トラッカーへの書き込み、ネットワークへのアクセスをできるかどうかはガードレールが決めます — 許可、先に確認、拒否のいずれかです — そして、どのアダプターがエージェントを実行しても同じルールが適用されます。
プッシュは、ルールを回避しようとするエージェントに対しても守られなければならないアクションです。そのため、エージェントが何を実行するかではなく、何を持っているかによって強制されます。GitHub App が設定されている場合、GitHub のワークツリーでの実行は、リポジトリ単位のインストールトークンを受け取ります。このトークンはコンテンツの読み取りとプルリクエストの操作はできますが、プッシュはできません。実行の git 設定は、GitHub へのすべてのプッシュ URL(https://github.com/、git@github.com:、ssh://git@github.com/)を、cc_server 上のループバックエンドポイントであるエージェント実行ゲートウェイに書き換えます。ゲートウェイはプッシュがどの ref を更新するかを読み取り、リモートへプッシュのルールに問い合わせます — そのため「main へのプッシュを拒否」のようなブランチ限定のルールも適用されます — そしてその後で初めて、この目的のために発行し、エージェントには決して渡さない書き込みトークンでプッシュを GitHub へ転送します。拒否されたプッシュは git 自身の出力に表示されます:
! [remote rejected] main -> main (Control Center policy: …)ゲートウェイがプッシュを転送するのは、ワークツリー自身のリポジトリか、ワークスペースにリンクされた GitHub リポジトリだけです。フェッチは読み取りトークンで直接 GitHub に送られます。
その他のシェルコマンドは、より緩やかなゲートを通ります。ハーネスの bash ツールと、フック経由の Claude Code の Bash ツールは、各コマンドラインを分類し、該当するルールに問い合わせます: git commit、merge、rebase、cherry-pick、revert、am はコミットを作成、gh pr create はプルリクエストを作成、gh pr merge、review、comment、close はレビューの公開またはマージ、gh issue create、edit、comment、close は外部トラッカーへの書き込み、パッケージのインストールはパッケージをインストール、curl と wget はネットワークにアクセスです。これはアクションの一般的な書き方を認識するものであり、隠そうと決めたエージェント(eval、スクリプトファイル、直接の API 呼び出し)はすり抜けられます。プッシュはこれに依存しません。
チケットの API キーはサンドボックスに置かれません。エージェントは Control Center の MCP ツールを使ってチケットを書き込み、それらのツールが外部トラッカーへの書き込みのルールに問い合わせます。
ネットワークにアクセスのルールは、実行の開始時に一度だけ読み取られます。サンドボックスのネットワークはオンかオフのどちらかしかないため、拒否はそれをオフにし、許可と先に確認はオンのままにします。ハーネスの web_fetch と web_search ツールは引き続き呼び出しごとに確認します。資格情報は実行の終了時に、ゲートウェイが発行した書き込みトークンとともに取り消されるため、ハンドルが実行より長生きすることはありません。
サンドボックスが追加するものと、それが止まる場所
「サンドボックスが追加するものと、それが止まる場所」というセクションSandboxBackend enum には 3 つの値があります — native(macOS では Seatbelt、Linux と WSL2 では bubblewrap)、none、microvm です。エージェントのコマンドラッピングが使うのは最初の 2 つだけです。microvm は対話ターミナルとリグ向けの閉じ込め VM バックエンドであり、bash ラップの暗黙のアップグレードではありません。native の形を理解すると、接続されている場合に何を得られるのか、そしてそれが決して与えようとしなかったものは何かが分かります。
cc_server は起動時に一度だけホストをプローブし、バックエンドが応答する場合、ディスパッチ経路が持つ 2 つのシームの両方にそれを与えます。トランスポートが 1 つを共有しているわけではないからです。1 つ目(SandboxPort)は Claude Code CLI をラップします。2 つ目(SandboxManager)は ACP アダプターと内蔵ハーネスの bash ツールをラップします。片方だけに与えると、ほかはラップされずにスポーンされますが、以前はそうなっていました。バックエンドのないホスト、または --sandbox off の下では、それらはすべてラップされずにスポーンし、サーバーは起動行でどちらのケースなのかを通知します。ACP とハーネスの bash は依然として環境をサニタイズします。NoSandboxAdapter 経由の Claude Code はホストの環境を継承します。
ひとつのサーフェスだけが意図的に除外されます。サーバーがホストするターミナルはセッションごとのバックエンド引数を受け入れ、cc_server はそれをホストシェルをデフォルトとして構築します。そのため、アプリから開くターミナルは、クライアントが明示的に native を指定しない限り、サンドボックスなしで動作します。それはサーバーホスト上の本物のシェルであり、エージェントの実行ではありません。
Linux では、bubblewrap がマウント名前空間を構築するため、エージェントはそこにバインドされたものだけを本当に見ます。macOS では、sandbox-exec が デフォルトで許可 の Seatbelt プロファイルを適用します — 完全なデフォルト拒否のプロファイルでは、対話シェルが使えなくなります。列挙すべき dyld、XPC、Mach 呼び出しの数が非現実的だからです。そのため macOS のプロファイルは (allow default) から始まり、拒否を切り出します: シークレットパスの読み取り、明示的な許可を上に重ねてデフォルト拒否にリセットされた書き込みポリシー、拒否されたすべてのパスとその祖先に対する unlink の禁止(リネームで書き込み拒否を迂回できないようにするため)、常に危険なバイナリと書き込み可能ディレクトリにコピーされたものに対する exec の拒否、そしてループバックプロキシポートと DNS に制限されたネットワークです。
実際の結果はこうです: Linux ではエージェントから見えるファイルシステムが狭められ、macOS ではエージェントは依然としてホストのほとんどを 読み取る ことができ、あなたの登録済みチェックアウトは不可視性によってではなく、明示的な書き込みとリネームの拒否によって保護されます。どちらも名前空間レベルの分離であり、カーネルのセキュリティ境界ではありません — バックエンド自身がその能力ノートでそう述べています。
バインドマウントの集合が、エージェント間境界の引かれる場所です。オーバーレイディスパッチ(Claude Code と ACP)は、実行ごとに解決される最大 4 つのパスをマウントします: エージェントのオーバーレイ作業ディレクトリは読み書き可、エージェントの設定ディレクトリは読み取り専用、会話の共有 repos/ ディレクトリは存在する場合に読み書き可、スペースの添付ファイルディレクトリは存在する場合に読み取り専用です。兄弟エージェントのディレクトリがマウントされることはありません。ハーネスの bash ラップはより狭く、実行の作業ディレクトリだけをバインドマウントします。これはハーネスのインプロセスのパスチェックがソフトウェアで強制するのと同じ形であり、両者は一致しています — ただしハーネス自身のファイルツールをカバーするのはパスチェックだけであり、それらはマウント名前空間にまったく到達しません。
あなたの登録済みチェックアウトは、その上に書き込み拒否の集合として加わります。すべてのモードで、3 つのラップされたパス(Claude Code、ACP、ハーネスの bash)すべてにおいてです。そして各ルールは、そのリテラルの綴りとシンボリックリンク解決後の綴りの両方で出力されます。2 つ目の綴りはおまけではありません: カーネルは拒否ルールを解決後のパスに対して照合し、macOS では解決は例外的なものではなく日常的なものです — /tmp は実際には /private/tmp であり、/var/folders/… は実際には /private/var/folders/… です — そのため、どちらかを通して到達したチェックアウトは、プロファイルが禁じているように見えながら書き込み可能でした。
サンドボックス下のネットワークは、インプロセスのループバックプロキシによって強制されるセッションごとのドメイン許可リストです。外向き通信はデフォルト拒否です: ネットワークがオフの場合、プロキシは依然として起動しますが許可リストは空なので、外向き接続はすべて拒否されます。オンの場合、リゾルバーは、厳選されたベースライン — LLM API プロバイダー、git ホスティング、パッケージレジストリ、モデルカタログ — に GitHub のドメインを加えて許可リストを構築し、すべての接続のターゲットホストをそれに照合します。ワイルドカードは機能します(*.example.com はサブドメインに一致し、apex には一致しません)。別の常時拒否リストが許可リストに優先し、クラウドのメタデータエンドポイントとテレメトリのシンクをカバーします。設定_できない_のはリスト自体です: 仕様は追加ドメイン用の egressAllowlist フィールドを持ちますが、ディスパッチ経路のどこもそれを埋めないため、実際にはすべての実行がベースラインと GitHub だけを取得し、それ以上はありません。
macOS では、拒否は観測可能です: モニターが Sandbox の拒否についてシステムログを監視し、既知のノイズをフィルタリングし、リトライの嵐を重複排除し、それぞれを SandboxViolation として表面化します。何が試みられ、何がブロックされたかを名指ししてです。Linux では、ラップ経路が stderr を解析して EPERM、Operation not permitted、Permission denied を探し、同じイベントタイプを発行します — システムログのタップはありません。それらは実行自身のイベントストリームに届くため、拒否されたシステムコールはログだけでなくトランスクリプトにも現れます。テレメトリは、ネイティブサンドボックスが実際にプロセスをラップしている間だけ存在します — バックエンドのないホストでは観測するものがありません。またこれはガードレールとは無関係です。違反は拒否されたシステムコールから生じ、ルールの参照から生じることは決してありません。
確認はガードレールから来るのであり、サンドボックスからではない
「確認はガードレールから来るのであり、サンドボックスからではない」というセクションサンドボックスには承認の経路がありません。起動し、実行し、イベントを発行し、終了します。そこに人間が問いに答える場所はありません。スペースで確認を見るとき — このプッシュを承認、この削除を承認 — それは、アクションがそもそもランタイムに到達する_前に_、ガードレールエンジン(またはハーネスのコマンドポリシー)が提起したものです。
この順序は意図的です。システムコールの後に起きた承認は、ゲートではなく監査記録になってしまいます。フェイルクローズのルールがガードレールにある理由もここにあります。承認者が接続されていない場合、決定は何かが実行される前に下され、それは拒否です。
エージェント診断の実行は、手作業で確認できることを記している唯一の場所です。
関連するコンセプト
「関連するコンセプト」というセクション- リグとエンクロージャー: サンドボックスの一段上 — 作業に、ラップされたプロセスではなく、カーネル境界を持つ使い捨てのマシン全体が必要なとき
- ガードレール: OS の土台の上にあるポリシー層であり、承認が実際にどこから来るか
- エージェントのディスパッチライフサイクル: ディスパッチフローの中で分離がどこに位置するか
- モード: モードがツールサーフェスとコマンドポリシーをどう狭めるか
- サンドボックスバックエンドのリファレンス: バックエンドとその設定
関連するガイド
「関連するガイド」というセクション- サンドボックスポリシーを設定: アクションのルール、プッシュの強制、ファイルシステムの姿勢
- エージェント診断の実行: 診断チェックがカバーする内容