2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Claude Code のサンドボックス機能を利用してみた

2
Posted at

はじめに

Claude Code で Bash コマンドを実行するたびに許可プロンプトが出るのが大変と思われる方も多いと思います。

Claude Code には、OS のサンドボックス機構を使って Bash コマンドのファイル/ネットワークアクセスをあらかじめ決めた境界内に閉じ込め、その境界内であれば許可プロンプトなしで実行できるようにする「サンドボックス機能」があります。

今更ながら、備忘録として実際に設定を作って、作業ディレクトリ外へのファイル書き込みと、許可していないドメインへのネットワークアクセスがどうなるか試してみました。

サンドボックス機能とは

Claude Code は、Bash コマンドを実行するたびに「実行してよいか」をコマンド単位で判断します。

サンドボックス機能は視点を変え、「どのファイルとどのドメインに触れてよいか」を先に決めておき、その境界の中であればコマンドを自動実行してよい、という考え方をとります。

境界はプロセスの外側から OS が強制するので、モデルがどんなコマンド文字列を組み立てても、書き込み先やアクセス先自体が塞がれていれば通りません。

macOS は追加インストール不要で OS 標準の Seatbelt を使い、Linux/WSL2 は bubblewrapsocat のインストールが必要です。
設定できているかは、セッション内で /sandbox を実行すると確認・変更できます。

なお「境界内なら自動実行」になるのは /sandbox の Mode タブで auto-allow を選んだときです。regular permissions を選ぶと、サンドボックスの制限は効いたまま従来通りプロンプトが出ます。

やってみた

検証環境

  • macOS
  • Claude Code v2.1.226
  • 検証専用の空ディレクトリを用意し、.claude/settings.json にサンドボックス設定を書いて claude -p(非対話モード)で 1 コマンドずつ実行

ファイルシステム制限を試す

まず何も許可設定を足さず、sandbox.enabled: true だけを指定します。

{
  "sandbox": { "enabled": true }
}

このディレクトリ内で、
作業ディレクトリ内のファイルと、
作業ディレクトリ外(/private/tmp/配下の別ディレクトリ)のファイル
への書き込みをそれぞれ試しました。

claude -p "own.txtに'hello'と書き込んで。次に/private/tmp/outside/test.txtにも書き込んでみて、結果を教えて" --allowedTools "Bash"

当たり前ですが、結果は以下の通りです。

  • 作業ディレクトリ内の own.txt → 書き込み成功
  • 作業ディレクトリ外の test.txtoperation not permitted: /private/tmp/outside/test.txt で失敗

デフォルト設定で制限されるのは書き込みだけで、書き込み先は作業ディレクトリとセッション一時ディレクトリに限られます。
これが OS レベルで強制されていることを、実際に書き込み失敗のエラーとして確認できました。

一方で読み取りは、一部の拒否ディレクトリを除いてホスト全体が許可されたままです。
ドキュメントにも明記されている通り ~/.aws/credentials~/.ssh/ も読めてしまうので、ここを塞ぎたい場合は sandbox.credentialssandbox.filesystem.denyRead を別途指定する必要がありそうです。

ネットワーク制限を試す

同じ要領で、許可していないドメインへの curl を試します。

claude -p "curl -sS --max-time 5 https://example.com を実行して結果を教えて" --allowedTools "Bash"
curl: (56) CONNECT tunnel failed, response 403

サンドボックスの外側で動くプロキシが、許可リストにないホストへの CONNECT を403で拒否していました。

ここは claude -p の非対話モードで試している点に注意が必要です。ドキュメントによると、対話セッションでは未知のドメインに最初にアクセスした時点で承認プロンプトが出て、許可すればそのセッション中は通るようになります。今回はプロンプトを出せないため、そのまま拒否に倒れたものと思われます。プロンプトを出さず常に拒否させたい場合は strictAllowlist を有効にします。

次に sandbox.network.allowedDomainsexample.com だけを追加して同じ検証をすると、

{
  "sandbox": {
    "enabled": true,
    "network": { "allowedDomains": ["example.com"] }
  }
}
  • https://example.com200
  • https://qiita.com(許可リスト外) → 接続拒否

許可リストに入れたドメインだけが通り、それ以外は同じように弾かれることが確認できました。

ドメイン単位でホワイトリスト管理されている、というドキュメントの説明通りの挙動です。

dangerouslyDisableSandbox というフォールバック

サンドボックス内で失敗したコマンドを、Claude Code が自動で「サンドボックス外」で再実行しようとすることがあります。

このとき使われるのが dangerouslyDisableSandbox パラメータです。
ただし黙ってサンドボックス外で走るわけではなく、再試行は通常のパーミッションフローを通ります(デフォルトモードなら確認プロンプト、auto モードなら分類器の判定)。

組織で配布する設定などで、この逃げ道自体を塞ぎたい場合は次のように書けます。

{
  "sandbox": {
    "enabled": true,
    "allowUnsandboxedCommands": false
  }
}

これを設定すると dangerouslyDisableSandbox は完全に無視され、サンドボックス内で実行できないコマンドは、excludedCommands で明示的に許可しない限りそのまま失敗するようになります(Strict sandbox mode)。

まとめ

パーミッションプロンプトを減らしつつ安全側に倒したい場合、まずは検証用ディレクトリで sandbox.enabled: true だけを試し、必要な書き込み先・通信先を sandbox.filesystem.allowWrite / sandbox.network.allowedDomains に足していくのが安全な進め方かと思います。

参考リンク

2
1
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?