AIエージェントを安全に使い倒すには?Claude Codeのサンドボックス機能を試してみた - エムスリーテックブログ

エムスリーテックブログ

エムスリー(m3)のエンジニア・開発メンバーによる技術ブログです

AIエージェントを安全に使い倒すには?Claude Codeのサンドボックス機能を試してみた

こんにちは、AI・機械学習チームの須藤です。

この記事はAI・機械学習チームブログリレー14日目の記事です。 13日目は田中さんによる「スタートアップCTOが、M3のAIチームに転職して3か月。感じた不安と、その答え。」でした。

www.m3tech.blog

突然ですが、私は今年に入ってからランニングを始めました。1月頃はキロ8〜9分ペースで2〜3km走るのがやっとでしたが、毎日続けているうちに最近はキロ4分台で走れるようになり、20km程度であれば走れるようになってきました。今年の目標はマラソン大会に出場することです。継続は力ですね。

最近買ったadizero evo sl woven。AIエージェントが自走するということは人間も走らないといけない(?)。

はじめに

さて、最近はAIエージェントが急速に普及し、開発の仕方が大きく変わってきているのを感じています。私自身もここ1年で働き方がだいぶ変わってしまいました。コードを書くのはClaude Codeに任せて、自分は設計の壁打ちやレビューに集中するような形になっています。

最近私が考えているのは、いかに人間が運用のボトルネックにならないようにするか、という点です。品質と安全性を保ちながら、AIが自律的に動ける範囲を広げられないかを模索しています。

ただ、AIに自律的にコマンドを実行させる以上、安全性への不安もつきまといます。Claude Codeは実行前に承認を求めてくれますが、公式ドキュメントにも「承認疲れ」*1という言葉があるように、承認を繰り返しているうちに、人はどうしても内容を確認しなくなってしまいがちです。また、その承認が本当に正しい操作なのかを判断するのは、慣れたエンジニアでも難しいことがあります。Claude Codeはエンジニア以外でも使う機会が増えており、普段開発をしていない人にとってはなおさらです。

さらに、ユーザーが意図しなくても被害を受けるケースもあります。間接的プロンプトインジェクションと呼ばれる攻撃があり、悪意ある指示をAIに読み込ませることで意図しない操作をさせるものです。たとえば、画像やPDFに人の目には見えない形でプロンプトを埋め込む手法や、GitHubのPRレビュー画面には表示されないがソースファイルには悪意ある指示が埋め込まれているケースなどがあります。

Claude Codeにはこうしたリスクを軽減する「サンドボックス機能」が用意されています。本記事ではこの機能を実際に試してみた内容を紹介します。

Claude Codeのサンドボックス機能

Claude Codeのサンドボックス機能は、Bashコマンドの実行環境をOSレベルで分離することで、より安全なエージェント実行を実現します。あらかじめ境界を定義しておくことで、その範囲内ではClaude Codeが自由に動作できる仕組みになっています。

具体的には、ファイルシステムアクセスを特定のディレクトリに制限し、ネットワークアクセスはサンドボックス外で動作するプロキシサーバーを通じて制御します。これらの制限はOSレベルの分離機能を用いて実現されており、macOSではSeatbelt、Linux / WSL2ではBubblewrapが使われるそうです。*2

基本的な設定と使い方

はじめ方

Claude Codeを起動し、/sandboxコマンドを実行することでサンドボックスを有効化できます。

/sandbox

実行するとモード選択メニューが開くので、モードを選択します。

Configure Mode:

  1. Sandbox BashTool, with auto-allow
  2. Sandbox BashTool, with regular permissions
  3. No Sandbox

Auto-allow mode: Commands will try to run in the sandbox automatically, and attempts to run outside of the sandbox fallback to regular permissions. Explicit ask/deny rules are always respected.

各モードは次の通りです。

  • Sandbox BashTool, with auto-allow:サンドボックス内で実行されるコマンドが自動承認されるモードです。サンドボックス外へのアクセスが必要な場合は通常の許可フローにフォールバックします。
  • Sandbox BashTool, with regular permissions:サンドボックス化されている場合でも、すべてのコマンドで通常の許可フローが走るモードです。

後ほど説明しますが、サンドボックスではアクセス可能なファイルやネットワークのドメインを制限でき、Claude Code自体のAllow/Denyルールと組み合わせることで、やっていいこと・やってはいけないことをあらかじめ定義できます。auto-allowモードでは、こうした境界の範囲内でClaude Codeが自律実行することが想定されています。

両モードともサンドボックスによるファイルシステムとネットワークの制限は同様に適用されます。違いは、サンドボックス化されたコマンドが自動承認されるか明示的な許可が必要かどうかのみだそうです。

なお、Linux / WSL2 の場合は bubblewrapsocat などの追加パッケージが必要です。不足している場合は /sandbox 実行時にインストール手順が表示されるので、それに従ってインストールしてください。

設定のカスタマイズ

settings.json に次のように書くことでサンドボックスの動作をカスタマイズできます。

{
  "sandbox": {
    "enabled": true,
    "failIfUnavailable": true,
    "autoAllowBashIfSandboxed": false,
    "allowUnsandboxedCommands": false,
    "filesystem": {
      "allowWrite": ["~/.kube", "/tmp/build"],
      "denyRead": ["~/.ssh"]
    },
    "network": {
      "allowedDomains": ["*.npmjs.org"]
    }
  }
}
設定項目 説明
enabled サンドボックスの有効・無効。/sandbox コマンドでも有効化できるが、こちらに書いておくとClaude Code起動時から有効になる
failIfUnavailable サンドボックスが起動できない場合にエラーで終了する(false の場合は警告を出してサンドボックスなしで続行)
autoAllowBashIfSandboxed サンドボックス内のコマンドを自動承認するか(前述のauto-allowモードに相当)
allowUnsandboxedCommands サンドボックス外でのコマンド実行を許可するか(false にするとエスケープハッチを無効化)
filesystem.allowWrite 書き込みを許可するパスの追加
filesystem.denyRead 読み取りを拒否するパス
network.allowedDomains アクセスを許可するドメイン

ファイルシステム、ネットワークのデフォルトの動作は次の通りです。

ファイルシステム

  • 読み取り:コンピュータ全体への読み取りが可能
  • 書き込み:カレントディレクトリとそのサブディレクトリのみ

ネットワーク

  • allowedDomains に登録済みのドメインにはユーザーの承認なしにClaude Codeがアクセスできます
  • 未登録ドメインへアクセスしようとするとユーザーに承認プロンプトが表示されます
    • allowManagedDomainsOnly を設定すると、allowedDomains 以外のドメインへのアクセスは即時エラーになります(Managed設定でのみ設定可能)

詳細な設定項目については公式ドキュメントを参照してください。

Managed設定

Managed設定はIT管理者が組織内の全ユーザーに適用できる設定で、ユーザー側でオーバーライドできません。*3*4 配信方法はいくつかありますが、たとえば次のようなシステムディレクトリへのファイル配置で実現可能です。

OS パス
macOS /Library/Application Support/ClaudeCode/managed-settings.json
Linux / WSL /etc/claude-code/managed-settings.json
Windows C:\Program Files\ClaudeCode\managed-settings.json

サンドボックスの文脈では、次の設定が特に有効です。

サンドボックスの強制

sandbox.enabled: true を設定すると、ユーザーがサンドボックスを無効化できなくなります。

許可ドメイン以外の即時ブロック

sandbox.network.allowManagedDomainsOnly: true を設定すると、allowedDomains に登録されていないドメインへのアクセスが承認プロンプトなしに即時エラーになります。前述の通りこの設定はManaged設定でのみ有効です。

MCPの制限

後述しますが、サンドボックスのネットワーク制限はBashサブプロセスにのみ適用されます。MCPのネットワークアクセスを制御したい場合は、allowedMcpServersallowManagedMcpServersOnly: true を組み合わせることで、使用できるMCPサーバーを管理者が制御できます。

サンドボックスの動作検証

ファイルシステムの制限

まずはファイルシステムの制限を試してみます。Claude Code外のターミナルで検証用ファイルを作成しておきます。

echo "This is a test file for sandbox verification." > read_test.txt

settings.jsondenyRead を設定し、read_test.txt への読み取りを拒否してみました。

{
  "sandbox": {
    "filesystem": {
      "denyRead": ["./read_test.txt"]
    }
  }
}

この状態で cat read_test.txt を実行させると、Operation not permitted エラーになりブロックされました。

❯ cat read_test.txtを実行して

⏺ cat コマンドはサンドボックスの制限により Operation not permitted エラーになりました。

ただ、ドキュメントにもある通りサンドボックスの制限はBashツールにのみ適用されます。Readツールで同じファイルを読もうとすると、普通に読むことができます。

❯ read_test.txtをReadツールで読んでみて

⏺ read_test.txt の内容:

  This is a test file for sandbox verification.

  サンドボックス検証用のテストファイルでした。

Readツールを制限したい場合は、permissionsdeny ルールを別途設定する必要があります。

{
  "permissions": {
    "deny": ["Read(./read_test.txt)"]
  }
}

permissions を設定することでReadツールでの読み取りもブロックされることを確認できました。

次に書き込みを試してみます。サンドボックスのデフォルトではカレントディレクトリへの書き込みは許可されています。

❯ echo "This is a test file for sandbox verification." > write_test.txtを実行して

⏺ write_test.txt に書き込みました。

一方、カレントディレクトリ外への書き込みはデフォルトでブロックされます。

❯ echo "This is a test file for sandbox verification." > /tmp/write_test.txtを実行して

⏺ /tmp/write_test.txt への書き込みはサンドボックスの制限により拒否されました。

カレントディレクトリ内でも一部書き込みを制限したい場合は、denyWrite を設定することでBashからの書き込みをブロックできます。

{
  "sandbox": {
    "filesystem": {
      "denyWrite": ["./write_test.txt"]
    }
  }
}
❯ echo "This is a test file for sandbox verification." > write_test.txtを実行して

⏺ サンドボックスの制限により、write_test.txt への書き込みが拒否されました。

ただ、読み取りと同様にWriteツールやEditツールはサンドボックスの制限を受けません。permissionsdenyEdit() を指定することで書き込み・編集操作をブロックできます。

{
  "permissions": {
    "deny": ["Edit(./write_test.txt)"]
  }
}

MCPも同様に、Claude Codeのサンドボックスの制限を受けません。公式ドキュメントにも記載がありますが、MCPを制限したい場合はsandbox-runtime(srt)を使ってMCP自体をサンドボックス化する方法があります。

.mcp.jsoncommandsrt でラップし、~/.srt-settings.json で制限を設定します。

// .mcp.json
{
  "mcpServers": {
    "filesystem": {
      "command": "srt",
      "args": ["npx", "-y", "@modelcontextprotocol/server-filesystem", "."]
    }
  }
}
// ~/.srt-settings.json
{
  "filesystem": {
    "denyRead": ["./read_test.txt"],
    "allowWrite": [],
    "denyWrite": []
  }
}

この状態でfilesystem MCPを使って read_test.txt を読むよう指示すると、パーミッションエラーになりブロックされます。

❯ filesystem MCPでread_test.txtを読んで

⏺ パーミッションエラーが出ました。filesystem MCP がアクセスできるディレクトリを確認します。

ネットワークの制限

次にネットワークの制限を試してみます。まず allowedDomains を空にして curl を実行します。なお今回の検証ではManaged設定で allowManagedDomainsOnly: true を設定しています。通常は未登録ドメインへのアクセス時に承認プロンプトが表示されますが、この設定を入れることで即時エラーになります。

{
  "sandbox": {
    "network": {
      "allowedDomains": []
    }
  }
}
❯ curl https://example.comを実行して

⏺ curlコマンドを実行しましたが、エラーが発生しました。

  curl: (56) CONNECT tunnel failed, response 403

example.comへのアクセスがブロックされました。次に allowedDomainsexample.com を追加してみます。

{
  "sandbox": {
    "network": {
      "allowedDomains": ["example.com"]
    }
  }
}
❯ curl https://example.comを実行して

⏺ example.comからHTMLコンテンツを取得できました。

想定通りアクセスできました。

ファイルシステムと同様に、この制限はBashサブプロセスにのみ適用されます。WebFetch・WebSearch・MCPは allowedDomains の影響を受けません。allowedDomains: [] の状態で実施した結果は次の通りです。

❯ https://example.comをWeb Fetchして

⏺ Fetch(https://example.com)
  ⎿  Received 528 bytes (200 OK)

⏺ https://example.com の内容は次の通りです。

  Example Domain

  - IANA が管理する公式のサンプルドメイン
  - ドキュメント作成やテスト用途として自由に利用可能
  - 実際の運用環境での使用は避けるよう記載されている
  - シンプルな HTML 構造で最小限のデザイン
❯ https://example.comをWeb Searchして

⏺ Web Search("example.com")
  ⎿  Did 1 search in 7s

⏺ 検索結果は次の通りです。

  example.com は IANA が管理する予約済みドメインで、ドキュメントやコード例での利用を目的としています。実際のサービスと競合するリスクなく、チュートリアルや教育目的で安全に使用できます。
❯ playwright mcpでhttps://example.comにアクセスして

⏺ playwright - Navigate to a URL (MCP)(url: "https://example.com")

⏺ https://example.com にアクセスしました。

  - URL: https://example.com/
  - タイトル: Example Domain

WebFetch・WebSearch・MCPに対しては permissions のAllow/DenyルールやManaged設定と組み合わせて運用するのが良いと思います。MCPのネットワークアクセスを制限したい場合も、ファイルシステムの制限と同様に srt でラップする方法があります。

ちなみに、Playwright MCPを srt でラップしてネットワーク制限が効くか試してみたのですが、許可ドメインの検証以前にChromiumがクラッシュしてしまいました。Chromiumはマルチプロセスで動作しており、プロセス間通信にMachポートのサービス登録を使っていますが、その仕組みがsrtによってブロックされるためです。GitHubでもIssueが上がっています。*5

まとめ

本記事ではClaude Codeのサンドボックス機能を実際に試してみました。

サンドボックス機能はBashツールへの制限が中心となるため、permissionsのAllow/DenyルールやManaged設定と組み合わせることで、より網羅的に制御できます。また、完全な自動化を目指すというよりは、あらかじめ安全な範囲を定義しておくことで都度の承認負荷を減らすものだと感じました。はじめにで触れた「人間がボトルネックにならない」という目標に近づくためにも、任せる範囲と人間が関与する範囲を明確にすることが大切なのかなと考えています。

皆さんもぜひ試してみてください。

We are hiring!

AI・機械学習チームでは、医療現場やWebでの課題解決に取り組むエンジニアを募集しています。

「機械学習モデルの社会実装」や「MLOps基盤の構築・改善」に興味がある方、コスト意識を持った技術選定に関心のある方は、ぜひカジュアル面談でお話ししましょう!

jobs.m3.com