allowUnsandboxedCommandsは抜け道を管理設定で塞ぐ設定
サンドボックスが弾いたコマンドをClaudeがdangerouslyDisableSandboxで再試行する抜け道を、allowUnsandboxedCommandsで管理設定から塞ぐ方法と、それでも残る2つの穴を解説します。
Claude Codeのサンドボックスがコマンドをブロックしても、ClaudeはdangerouslyDisableSandboxパラメーターを付けて同じコマンドをサンドボックス外で再試行できます。これは標準の挙動です。sandbox.allowUnsandboxedCommandsをfalseにすると、この再試行そのものを無効化でき、/sandboxのOverridesタブは状態をStrict sandbox modeと表示します。ただしこの設定が塞ぐのはClaude自身が実行するコマンドの再試行だけです。開発者が自分で打つコマンドやexcludedCommandsに載せたツールは別扱いで、そこを知らずに「厳格モードにした」と思い込むと抜け道が残ります。
allowUnsandboxedCommandsは何を止める設定か
サンドボックスがコマンドをブロックすると、Claude Codeはブロックされたコマンドの実行結果に違反内容(拒否したパスやホスト)を記録し、Claudeに何が弾かれたかを伝えます。Claudeはその情報をもとに、タスクを失敗させる代わりにdangerouslyDisableSandboxパラメーターを付けて同じコマンドをサンドボックス外で再試行することがあります。公式ドキュメントはこれを「アンサンドボックス再試行の脱出口(escape hatch)」と呼んでいます。
sandbox.allowUnsandboxedCommandsはこの脱出口そのもののスイッチです。
ブロックから再試行までの流れ
- 1
サンドボックスがコマンドを止める
ブロックされたコマンドの実行結果に、拒否したパスやホストが載ります。
- 2
Claudeが違反内容を読む
何が弾かれたかを見て、タスクを諦める代わりに再試行を選ぶことがあります。
- 3
dangerouslyDisableSandbox付きで再実行する
allowUnsandboxedCommandsがtrueのときだけ成立する段階です。falseならパラメーターごと無視されます。 - 4
通常の権限フローで承認される
サンドボックス外で動くため、通常の権限フローに戻ります。
allowUnsandboxedCommandsの2つの値
true(既定値)
サンドボックスがブロックした後、ClaudeはdangerouslyDisableSandboxで再試行できます。
false
Claude Codeはこのパラメーターを完全に無視します。Claudeが実行できるのは、サンドボックス化されたコマンドかexcludedCommandsに列挙済みのコマンドだけです。
trueのままの再試行が権限モードごとにどう扱われるかは、後半の権限モードの節に書いています。
管理設定でStrict sandbox modeを強制する
組織全体に強制したいときのmanaged settingsの構成は次の形です。
{
"sandbox": {
"enabled": true,
"failIfUnavailable": true,
"allowUnsandboxedCommands": false
}
}3つのキーはそれぞれ役割が違います。enabledはサンドボックス自体のスイッチで、これがtrueでなければ再試行という概念自体が発生しません(コマンドが最初からサンドボックス化されないため)。failIfUnavailableは、bubblewrapのような依存が欠けてサンドボックスを起動できない環境で、警告を出して非サンドボックス実行にフォールバックする既定動作を止め、Claude Codeの起動自体を失敗させます。allowUnsandboxedCommands: falseは、この2つが揃ってサンドボックスが実際に動いている前提のもとで、ブロック後の再試行だけを塞ぎます。
手元で挙動を試すだけなら、--settingsにJSON文字列を渡せば設定ファイルを書き換えずに済みます。公式のsandboxingページにも同じ形の例があります。
claude --settings '{"sandbox": {"enabled": true, "allowUnsandboxedCommands": false}}'v2.1.285のclaude --helpでは、このフラグは--settings <file-or-json>と表示され、「設定JSONファイルのパス、またはJSON文字列」を追加で読み込むと説明されています(原文はPath to a settings JSON file or a JSON string to load additional settings from)。
このキーのスコープは「Any file」、つまりユーザー設定・共有プロジェクト設定・プロジェクトのローカル設定のどこからでも書けます。ではプロジェクト側の.claude/settings.jsonでtrueに戻せば無効化できるかというと、そうはなりません。Claude CodeはBoolean型キーの値を、そのキーを設定している中で最も優先度の高いスコープから採用します。設定の優先順位は高い順にmanaged settings・コマンドラインの--settings・プロジェクトのローカル設定・共有プロジェクト設定・ユーザー設定で、managed settingsが最上位です。managed settingsでfalseにしておけば、開発者側の設定ファイルが何を書いていても無視されます。
managed settingsの配信経路(server-managed settings・MDM・managed-settings.json)は、既定では合成されません。ポリシーキーを配信している経路のうち最も優先度の高いものだけが使われるため、server-managed settingsやMDMで他のポリシーを配っている組織では、sandboxのキーも同じ経路に入れます。
公式ドキュメントはこの構成にもう1つ、sandbox.credentialsへの追記を勧めています。デフォルトのファイル読み取り許可は~/.awsや~/.sshのような認証情報ディレクトリも含んだままなので、再試行を塞いだだけでは認証情報の読み取りそのものは守られません。sandbox.credentialsではファイルパス・環境変数それぞれにmodeとしてdeny(遮断)かmask(値を隠したまま見せる)を指定できます。
もう1つ見落としやすいのが対応プラットフォームです。サンドボックスはネイティブのWindowsでは動作しません。Windows機を含む組織にこの構成を配布する場合は、対象をmacOSとLinuxに絞るか、Windows側のユーザーにはWSL2かコンテナの中でClaude Codeを実行してもらう必要があります。
厳格モードでも抜けられる2つの穴
allowUnsandboxedCommands: falseが塞ぐのは、Claudeが実行するコマンドの再試行だけです。公式ドキュメントは残る2つの経路を明記しています。
1つ目は!シェルモードです。開発者が自分で!プレフィックス付きのコマンドを入力した場合、そのコマンドは通常サンドボックスの対象外です。現行バージョンでは、通常のセッションで開発者自身が打つコマンドにサンドボックスは及びません。これが変わるのは次の2種類のセッションだけです。
| セッションの種類 | !シェルモードコマンドの扱い |
|---|---|
| 通常のセッション | !シェルモードコマンドの扱いサンドボックス化されない |
| バックグラウンドセッション | !シェルモードコマンドの扱いStrict sandbox modeがシェルモードコマンドにも及ぶ |
CLAUDE_CODE_SUBPROCESS_ENV_SCRUBを設定したLinuxセッション | !シェルモードコマンドの扱いシェルモードコマンドを含め全実行がサンドボックス化される |
v2.1.260より前は、Strict sandbox modeが有効なあらゆるセッションでシェルモードコマンドもサンドボックス化されていました。現行バージョンでは対象がこの2種類のセッションに絞られています。管理設定で厳格化したつもりでも、通常セッションで開発者が!から打つコマンドは、Claude Code以外のターミナルで実行するのと同じアクセス権のまま残ります。
2つ目はexcludedCommandsです。docker *のようなパターンをここに登録すると、該当コマンドはサンドボックス化を免除されて通常の権限フローに回ります。各エントリの照合はBash(...)権限ルールと同じ構文で、完全一致・docker *のようなprefix・ワイルドカードパターンのいずれかを使えます。複合コマンドは、v2.1.277以降はすべての部分が一致したときだけサンドボックス外で実行されます。単純な文字列条件のゆるさが、そのまま抜け道の広さに直結します。
この一覧には専用のロックキーがありません。allowReadをallowManagedReadPathsOnlyでmanaged設定だけに縛ったり、許可ドメインをallowManagedDomainsOnlyで固定したりする仕組みは用意されていますが、excludedCommandsには同等のキーがなく、配列は各スコープから合流します。ただしv2.1.282以降は、次の2つの場合にプロジェクト・ローカル設定のエントリが無視されます。managed設定か--settingsでallowUnsandboxedCommands: falseを指定した場合と、managed設定でallowManagedDomainsOnly: trueにした場合です。ユーザー設定のエントリは残るため、管理設定のリストを狭く保つ運用は引き続き必要です。
excludedCommandsに書いても外れない呼び出しがある
厳格モードでdockerのようなツールを動かすには、excludedCommandsに載せる必要があります。ただし載せても、次の形の呼び出しはサンドボックスに残ります。
excludedCommandsに載せてもサンドボックスに残る形
複合コマンドの一部だけ一致
docker *だけのエントリでは、npm ci && docker build .はサンドボックス外になりません。すべての部分が一致する必要があります。sudo・eval・xargsで始まる
先頭がこれらのコマンドの呼び出しは、サンドボックスに残ります。
cd・pushd・popdを含む
呼び出しのどこに現れても対象です。
cd build && docker compose upはdocker *エントリでもサンドボックスに残ります。置換・サブシェル・制御構文・リダイレクト
コマンド置換、サブシェル、
ifやforのブロック、docker build . > build.logのようなリダイレクト(2>&1だけは除く)、変数から決まるコマンド名も、公式が挙げる例です。
公式はこの一覧を「セキュリティ境界ではなく利便性のための仕組み」と位置づけ、ツールが特定の場所に書ければ足りるならfilesystem.allowWriteを優先するよう書いています。
症状から逆引きすると、allowUnsandboxedCommands: falseにした環境で起きやすいのは次の3つです。
dockerコマンドが失敗する:docker *をexcludedCommandsに追加します- macOSで
ghやterraformがTLS検証に失敗する: Go製CLIはSeatbelt下で失敗することがあり、excludedCommandsに載せます - gitが
unable to unlink oldで失敗する:git mergeやgit checkoutが、サンドボックスが書き込みを拒否するファイルを置き換えようとしたときの症状です。falseではClaudeが再実行を提案できないため、自分で別のターミナルから実行するか、頻発するならexcludedCommandsに載せます
Manual modeとAuto modeで再試行の扱いが変わる
allowUnsandboxedCommandsを既定のtrueのままにしていても、再試行は無条件で通るわけではありません。サンドボックス外での実行は必ず通常の権限フローに戻るため、権限モードによって挙動が変わります。
Manual modeでは、再試行のたびに確認プロンプトが表示されます。Auto modeでは、プロンプトの代わりに分類器が再試行対象のコマンドそのものを評価します。毎回の再試行を確認したい場合は、Bash(dangerouslyDisableSandbox:true)という入力パラメーター指定のaskルールを追加すると、Auto modeでも再試行のたびにプロンプトが出るようになります。permissions.blockReadsOutsideWorkingDirectoriesを有効にしている間は、承認が必要な再試行はAuto modeでもプロンプトになります。
サンドボックス化されたコマンド自体に毎回の確認が入るかどうかは、別のキーautoAllowBashIfSandboxed(既定はtrue)で決まります。allowUnsandboxedCommandsをfalseにしても、このキーは変わりません。
dangerouslyDisableSandboxとdisableBypassPermissionsModeは別物
「Claude Codeの安全装置を外させない」という目的で似た名前の設定を混同しやすい組み合わせがもう1つあります。permissions.disableBypassPermissionsModeです。
| 設定 | 塞ぐ対象 | 塞いだ後の状態 |
|---|---|---|
sandbox.allowUnsandboxedCommands: false | 塞ぐ対象サンドボックスがブロックしたコマンドの再試行(dangerouslyDisableSandbox) | 塞いだ後の状態Claudeが実行するコマンドはサンドボックス化されるかexcludedCommandsのみ |
permissions.disableBypassPermissionsMode: "disable" | 塞ぐ対象bypassPermissionsモードへの遷移(--dangerously-skip-permissions) | 塞いだ後の状態このフラグ自体をClaude Codeが拒否し、サブエージェント定義のpermissionMode: bypassPermissionsも無視される |
前者はサンドボックスという1つの防御層の中の脱出口を塞ぎ、後者は確認プロンプトと安全チェックを素通りさせるモードへの入口を塞ぎます。サンドボックスはOSが強制する別の層で、権限モードとは独立して働きます。組織のポリシーとして両方を求めるなら、どちらか一方だけでは足りません。
まとめ
allowUnsandboxedCommands: falseは、managed settingsでenabled・failIfUnavailableと組にして初めて、Claude自身の再試行を塞ぐ設定になります。開発者が!で打つコマンドとexcludedCommands、bypassPermissionsへの遷移は別の管理項目なので、「厳格モードにした」で終わらせず、この3点を組織のポリシーとして別に決めておく必要があります。
サンドボックス全体の二層分離はClaude Codeのサンドボックス設計、ファイルシステム分離だけを外す設定はsandbox.filesystem.disabledはファイルシステム分離だけ外す設定にあります。ネットワーク許可リストの書式はIPv6ドメイン許可リストの書き方、settings.json全体の構成はClaude Code設定ガイドを参照してください。