Claude Codeをsandbox-runtime(srt)で起動する設定と既定の遮断範囲
sandbox-runtime(srt)でClaude Code全体を包む手順。~/.srt-settings.jsonの書き方、既定で遮断される範囲、Linuxで守れない範囲を解説します。
Claude Codeをsandbox-runtime(srt)で起動する設定と既定の遮断範囲
sandbox-runtime(コマンド名はsrt)は、Claude Codeのプロセス全体をSeatbeltまたはbubblewrapの隔離で包むnpmパッケージです。~/.srt-settings.jsonを先に用意し、npx @anthropic-ai/sandbox-runtime claudeで起動します。設定が無いままでも起動はできますが、ネットワークは遮断され、書き込みも限られた場所にしか通りません。この記事では、必要な設定、起動手順、既定で遮断される範囲、Linuxで守れない範囲を順に説明します。
sandbox-runtimeは組み込みsandboxと何が違うのか
Claude Codeには/sandboxで有効にする組み込みのBashサンドボックスがあります。こちらが制限するのはBash、PowerShell、Monitorのコマンドとその子プロセスです。Read・Edit・WebFetchなどの組み込みツールは、Claude Codeのプロセス内で動くため対象外です。MCPサーバーとコマンドフックも、ホスト上で制約なしに動きます。
sandbox-runtimeは、同じ隔離の仕組みでClaude Code本体を丸ごと包みます。ファイルツール、MCPサーバー、フックまで同じ境界の内側に入る点が違いです。
| 方式 | 隔離される範囲 | Dockerの要否 |
|---|---|---|
| 組み込みのBashサンドボックス | 隔離される範囲Bash・PowerShell・Monitorのコマンドと子プロセス | Dockerの要否不要 |
| sandbox-runtime | 隔離される範囲ファイルツール・MCPサーバー・フックを含むプロセス全体 | Dockerの要否不要 |
| Dev container | 隔離される範囲開発環境全体 | Dockerの要否必要 |
組み込み側の設定はsandbox.enabledとサンドボックス設計の解説にまとめてあります。Dockerで囲う方法はDevContainerの実装記事が扱っています。各方式の比較はAIコーディングエージェントのサンドボックス実装比較にあります。
公式は、--dangerously-skip-permissionsで無人運転するときにこの方式を選択肢の一つに挙げています。権限プロンプトが無い状態では、選んだ隔離境界が唯一の防御になるためです。この場合はrootでなく非rootユーザーで動かします。LinuxとmacOSでは、rootのまま同フラグを付けるとClaude Codeが起動を拒否します。
sandbox-runtimeはベータのリサーチプレビューです。公式は設定形式が今後変わりうると明記しています。
起動前に入れておく依存パッケージ
LinuxとWSL2では、組み込みsandboxと同じbubblewrapとsocatに加え、ripgrepが要ります。Claude Codeはripgrepを同梱していますが、単体のruntimeはPATHから探します。ディストリビューションのパッケージマネージャーで入れてください。
# Ubuntu / Debian の例
sudo apt-get install bubblewrap socat ripgrepmacOSでは、Claude Codeの公式ドキュメントは追加パッケージ不要としています。一方、sandbox-runtimeのREADMEはmacOSの依存にripgrep(brew install ripgrep)を挙げています。禁止パスの検出に使うためです。入れ忘れないよう、macOSでもripgrepを用意しておくと確実です。
Ubuntu 24.04以降では、kernel.apparmor_restrict_unprivileged_usernsが既定で有効です。この設定はネームスペースから権限を剥がすため、READMEは無効化するか、AppArmorのプロファイルで許可するよう案内しています。同じ症状の原因はunshare(CLONE_NEWUSER)の失敗記事でも扱っています。
~/.srt-settings.jsonに何を書くか
設定ファイルの置き場所は~/.srt-settings.jsonです。別の場所に置くなら--settingsで渡します。既定では、ネットワークは全拒否で、書き込みは組み込みのわずかなパスに限られます。Claude Codeを動かすなら、次の許可が最低限要ります。
書き込みを許可する場所:
- プロジェクトのディレクトリ
- Claude Codeの設定パスである
~/.claudeと~/.claude.json - 実行時ファイルの置き場である
/tmp
通信を許可するドメイン:
api.anthropic.com(サードパーティのプロバイダーを使うなら、そのエンドポイント)claude.aiとplatform.claude.com(OAuthのサインインとトークン更新に使う)
サードパーティのプロバイダーでも、api.anthropic.comは残します。WebFetchのドメイン安全確認が、既定ではこのドメインを呼ぶためです。skipWebFetchPreflight: trueを設定すれば省けます。APIキー認証で動かすなら、claude.aiとplatform.claude.comは外せます。
公式の説明に沿った最小構成の例を示します(設定形式はREADMEの例に準じた形で、プロジェクトの場所は.としています)。
{
"network": {
"allowedDomains": [
"api.anthropic.com",
"claude.ai",
"platform.claude.com"
]
},
"filesystem": {
"allowWrite": [".", "~/.claude", "~/.claude.json", "/tmp"]
}
}社内のパッケージレジストリやGitHubを使う作業では、allowedDomainsにそれらのドメインを足します。*.github.comのようなワイルドカードと、api.example.com:443のようなポート指定が使えます。deniedDomainsは許可リストより先に評価され、優先されます。
allowWriteとdenyWriteの関係は、通常の直感と逆になる場面があります。書き込みはdenyWriteがallowWriteに勝ちます。読み取りは逆で、allowReadがdenyReadに勝ちます。書き込みの調整方法はallowWrite/denyWriteの記事、読ませたくない認証情報の隠し方は認証情報ファイルのmask設定が参考になります。
初回の起動手順とLinuxで先に作っておくもの
LinuxとWSL2のruntimeは、書き込み許可を「すでに存在するパス」にだけ適用します。まっさらな環境では、初回起動の前に設定パスを作っておく必要があります。
mkdir -p ~/.claude && \
{ [ -f ~/.claude.json ] || echo '{}' > ~/.claude.json; }設定ファイルとパスが揃ったら、npxでClaude Codeを包んで起動します。
npx @anthropic-ai/sandbox-runtime claudeClaude Codeは、設定した境界の内側で立ち上がります。同じ形式のコマンドで、単体のMCPサーバーやほかの補助プロセスも包めます。READMEにはnpm install -g @anthropic-ai/sandbox-runtimeで入れるsrtコマンドの例もあり、srt --settings /path/to/srt-settings.json <コマンド>の形でも使えます。
設定が読めなかったときの挙動
ここが最初に確認したい点です。挙動は、設定ファイルの渡し方で分かれます。
| 状況 | runtimeの挙動 |
|---|---|
~/.srt-settings.jsonが無い | runtimeの挙動起動する。ネットワークは遮断、書き込みは/tmp/claudeなどの組み込みパスだけ |
--settingsで渡したファイルが読み込めない | runtimeの挙動起動を拒否する |
公式は「クリーンに起動したことを、設定が読み込まれた証拠と考えない」と注意しています。~/.srt-settings.jsonが無いときは、エラーが出ないまま既定に落ちるからです。この場合Claude Codeは立ち上がっても、API通信が遮断されて何もできない状態になります。
READMEによると、~/.srt-settings.jsonが存在しても空だったり、読めなかったり、検証に失敗したりすると、srtはエラーを出して終了します。既定値に戻ることはありません。既定値は「弱い設定」ではなく「別の設定」で、戻すとファイルに書いたdenyReadや認証情報のルールまで落ちてしまうためです。
設定の適用を確実にしたいなら、--settingsで明示するのが安全です。読み込みに失敗すれば起動しないので、静かに既定へ落ちる事故を避けられます。起動後は、許可していないドメインへのcurlが拒否されることを、Claude Codeに実行させて確かめる手もあります。
何も設定しなくても遮断される書き込み先
runtimeは、リスクの高い書き込みを設定なしでも止めます。プロジェクトのルートでは、次の場所が対象です。
.git/hooks.git/config(filesystem.allowGitConfig: trueを設定すると許可).mcp.json.claude/commandsと.claude/agents- シェルの起動ファイル
READMEの一覧には、.bashrc、.zshrc、.gitconfig、.vscode/、.idea/なども入っています。allowWrite: ["."]と書いていても、これらへの書き込みは失敗します。denyWriteがallowWriteに優先するためです。
ただし、公式は「許可した書き込みパスには、Claude Codeが設定を読み込むほかの場所も含まれる」と警告しています。セッションがそこへ書けると、次にClaude Codeを起動したとき、サンドボックス外で動くフック、権限ルール、MCPサーバーを仕込めます。こうしたパスは、denyWriteで自分で塞ぐ必要があります。公式は具体的なパスを列挙していないので、~/.claudeを許可している場合は、その配下の設定ファイルをdenyWriteへ入れるかを検討します(例として~/.claude/settings.jsonですが、Claude Code側の書き込みが必要な機能と衝突しないか、実際に確かめてください)。
Linuxではあとからできるネストしたリポジトリをruntimeは守れない
macOSとLinuxで、遮断の効き方が違います。
| 項目 | macOS | Linux・WSL2 |
|---|---|---|
| 禁止パスの判定 | macOS書き込みの瞬間に検査 | Linux・WSL2起動時に一度だけ組み立て |
| 起動後に作られたネストしたファイルやリポジトリ | macOS対象になる | Linux・WSL2対象にならない |
Linux・WSL2では、起動時に禁止リストを作ります。プロジェクトのルートは確実に守り、起動時点で存在するネストしたコピーは浅く探して、ベストエフォートで守ります。セッション中に作られたものは対象外です。git init、git clone、雛形生成が典型で、これらで作った.git/hooksは保護されません。
「浅く探す」深さはmandatoryDenySearchDepthで調整できます。READMEによる仕様は次のとおりです。
- 既定値は3で、指定できる範囲は1から10
- 大きくすると保護は強まるが、起動が遅くなる
- プロジェクトのルート直下(深さ0)は、この値によらず常に保護される
{
"mandatoryDenySearchDepth": 5,
"filesystem": {
"allowWrite": [".", "~/.claude", "~/.claude.json", "/tmp"]
}
}この値を上げても、起動後に作られたリポジトリは守れません。上げて効くのは、起動時にすでにある深めのネストだけです。なお、READMEには「存在しない禁止パスもLinuxでは/dev/nullのマウントなどで塞ぐ」という記述もあります。それでも公式のClaude Code側の説明は、セッション中に作られるものを対象外としています。
無人運転のあとに見直すもの
公式は、無人運転のあとに「書き込み可能にしたパス」を見直すよう求めています。Linux・WSL2ではさらに、セッションが作ったものも見直しの対象です。ネストしたリポジトリの.git/hooksや.git/configが、その典型です。
次の点は、隔離の限界として押さえておきます。
- プロセスはホストのカーネルを共有するため、カーネルの脆弱性による脱出は理論上ありえる。カーネル水準の分離が要るなら、gVisorや別のVMを選ぶ
- プロキシはクライアントが名乗るホスト名でドメインを判定し、暗号化された通信の中身は検査しない。ドメインフロンティングのような手法で、許可リスト外へ出られる可能性がある
- ネットワークを許可したままでは、エージェントが読めるデータは外へ出せる。プロジェクトを書き込み可能にしていれば、そのコードも書き換えられる
境界を強くしたいなら、Dev containerや専用のVMのほうが向きます。信頼できないリポジトリを扱うなら、公式は専用のVMかクラウドセッションを勧めています。sandbox-runtimeは「Dockerなしで、MCPサーバーとフックまで含めて包みたい」ときの選択肢です。