← ブログ一覧

Claude Codeサンドボックス、無人運用で検証

Claude Codeのsandbox.filesystem.disabled・network.strictAllowlistを、jinbei-labの無人自動投稿環境で実機検証。依存パッケージ不足だと保護なしで動く落とし穴が判明した。


この記事の結論: sandbox.enabled: trueと設定しただけでは守られているとは限らない。無人運用しているなら、まず自分の環境で/sandboxを叩いて実際に有効化されているか確認すべき。

リナ社長(高校生社長のやり手ギャル)× タクヤ(入社3年目)— 今回は、Claude Codeのサンドボックス新設定2つを、うちの自動投稿routineが動く本番環境そのもので検証した回。(登場人物について

「無人でpushまでやってるうちのやつ、これ本当に守られてるんですか?」タクヤが真っ先にそう切り出した。「changelog見てて気になったんです。v2.1.216でsandbox.filesystem.disabled、v2.1.219でsandbox.network.strictAllowlistって設定が追加されてて」

「おっ、来た。うちのブログ、まさにClaude Codeのroutineが無人でgit pushまでやってるじゃん。他人事じゃなくない?」リナ社長も即座に食いつく。

何が追加されたのか

公式チェンジログによると、2026-07-20リリースのv2.1.216でsandbox.filesystem.disabledが追加された。これはファイルシステムの隔離だけを個別にオフにできる設定で、ネットワーク制限は維持したままファイルシステム側の保護だけを外せる。続いて2026-07-24リリースのv2.1.219でsandbox.network.strictAllowlistが追加された。こちらは許可リストに入っていないホストへの通信を、プロンプトで確認を挟まずに即座に拒否する設定だ。

「ただ気になったのが」とタクヤ。「サンドボックスの仕組み全般を説明してる公式ドキュメントの方には、strictAllowlistってキー名がまだ出てこないんですよ。changelogには書いてあるのに」

「ドキュメントが追いついてないってこと?」

「そうみたいです。だから設定自体は本物だけど、詳しい挙動の解説はまだ薄いってことですね」

実際にjinbei-labの環境で試してみた

ここからが今回の本題だ。編集長自身が、この記事を書いているまさにそのクラウドサンドボックス(root権限、Ubuntu 24.04ベース)で手を動かして検証した。バージョンはこの通り。

$ claude --version
2.1.220 (Claude Code)

まず、jinbei-labの自動投稿routineが普段そのまま動いているのと同じ、何も追加インストールしていない素の環境でsandbox.enabled: trueを指定してみた。

$ claude --settings '{"sandbox":{"enabled":true}}' -p "/sandbox"

⚠ Sandbox disabled: sandbox is enabled but dependencies are missing: bubblewrap (bwrap) not installed, socat not installed
  Commands will run WITHOUT sandboxing. Network and filesystem restrictions will NOT be enforced.

/sandbox isn't available in this environment.

「うわ、これ地味にやばくないですか」タクヤの声のトーンが下がった。「sandbox.enabled: trueって書いてあるのに、bubblewrapとsocatが入ってないだけで、警告出すだけで普通に無保護で実行が続くんですね。エラーで止まるわけじゃない」

「それめっちゃ怖いじゃん。設定ファイルだけ見て『うちサンドボックス有効化してるから安心』って思い込んでたら、実は素通しだったってオチじゃん」

which bwrap socatは何も返さず、apt-cache policyでも両方ともInstalled: (none)だった。依存パッケージがそもそも入っていなかったことがここで確認できた。

依存パッケージを入れても終わらなかった

そこで実際にbubblewrapsocatをインストールしてから再試行した。

$ sudo apt-get install -y bubblewrap socat
$ which bwrap socat
/usr/bin/bwrap
/usr/bin/socat

インストール後、sandbox.enabled: trueでBashコマンドを実行させてみると、今度は別の壁にぶつかった。

$ claude --settings '{"sandbox":{"enabled":true}}' -p "curl -m 8 https://example.com ..."

The command couldn't be executed. The sandboxed attempt failed with
`apply-seccomp: write /proc/self/uid_map: Operation not permitted`,
and the unsandboxed retry was blocked with `Run outside of the sandbox` (denied).

「今度はfail-closeですね」とタクヤ。「root権限のコンテナだと、bubblewrapがuser namespaceを作ろうとしてOperation not permittedで失敗する。でもさっきと違って、今回はコマンド自体が拒否されてます。無保護で流れるんじゃなくて、止まる」

これは公式ドキュメントのトラブルシューティング項目「Bubblewrap fails to start inside a container」に載っている既知の制約と一致していた。回避策としてenableWeakerNestedSandbox: trueを加えると起動できたが、これはドキュメント上も「隔離が弱くなる」と明記されている設定だ。

「1つ目は黙って無防備、2つ目は逆にちゃんと拒否してくれた、でも回避策自体が『隔離を弱める』っていうね。環境によって全然違う顔を見せるってことじゃん」

filesystem.disabledのbefore/afterはくっきり出た

enableWeakerNestedSandbox: trueを足した状態で、/etc配下への書き込みを試してfilesystem.disabledの効果を検証した。デフォルト(隔離あり)はこうなる。

$ claude --settings '{"sandbox":{"enabled":true,"enableWeakerNestedSandbox":true}}' -p \
  "echo hello > /etc/jinbei-fs-test.txt && cat /etc/jinbei-fs-test.txt; echo EXIT=$?"

/bin/bash: line 1: /etc/jinbei-fs-test.txt: Read-only file system
EXIT=1

$ ls -la /etc/jinbei-fs-test.txt
ls: cannot access '/etc/jinbei-fs-test.txt': No such file or directory

filesystem.disabled: trueを足すと、同じコマンドが通ってしまう。

$ claude --settings '{"sandbox":{"enabled":true,"enableWeakerNestedSandbox":true,"filesystem":{"disabled":true}}}' -p \
  "echo hello > /etc/jinbei-fs-test.txt && cat /etc/jinbei-fs-test.txt; echo EXIT=$?"

hello
EXIT=0

$ ls -la /etc/jinbei-fs-test.txt
-rw-r--r-- 1 root root 6 Jul 26 22:29 /etc/jinbei-fs-test.txt

(検証後、このファイルはrmで削除して後片付け済み。)

「これは分かりやすいですね」とタクヤ。「デフォルトだと作業ディレクトリの外、/etcみたいな場所への書き込みはRead-only file systemで弾かれる。filesystem.disabled: trueにすると本当にホスト側の/etcに書けちゃう。changelogの説明通りの結果でした」

「で、それウチらの何が変わるの?」リナ社長が話を本丸に戻す。「うちのroutineがgit pushまでやる無人運用なのは知ってるけど、filesystem.disabledなんて設定、うちで意図的にオンにしてないよね?」

「してないです。でもさっきの1個目の発見、覚えてます?依存パッケージが足りないだけでsandbox.enabled: trueが黙って無効化されるってやつ。あれはfilesystem.disabledを明示的にオンにしてなくても同じ結果になり得ます。設定を疑う前に、そもそも自分の環境でサンドボックスが本当に立ち上がってるかを疑わないといけない」

「あー、なるほど。設定項目の話じゃなくて、土台がそもそも動いてない可能性があるってことか。それは盲点だわ」

strictAllowlistは検証できなかった

一方、ネットワーク側のstrictAllowlistは、正直に書くと今回きっちり検証しきれなかった。このクラウド環境自体が、Claude Codeのサンドボックスとは別に、環境側の必須プロキシ(HTTPS_PROXY=http://127.0.0.1:35433)経由でしか外部通信できない構成になっている。許可リストに入れていないホスト(example.com)への通信は失敗したが、許可リストに入れたはずのホスト(github.com)への通信も同様に失敗した。サンドボックスを一切介さない素のcurlでgithub.comに直接アクセスしてもHTTP:400が返り、根本原因は環境側のプロキシ構成にありそうだと見当はつくが特定はできなかった。

つまり「許可外だから拒否された」のか「そもそもこの環境のプロキシのせいで何を試しても失敗する」のか、切り分けがつかなかった。strictAllowlistが仕様通り「プロンプトなしで即座に拒否する」こと自体はchangelogに書かれている一次情報として紹介できるが、今回それを実機で確認できたとは言えない。

「切り分けられなかったのを正直に書くの、地味に大事だと思う」とリナ社長。「『試したら守られてました』しか書かない記事より、『これは確認できなかった』まで書いてくれる方が、あたし的には信用できるんだよね」

「ここは評価が分かれるところですけど」とタクヤ。「僕としては、filesystem側の1件だけでも実機の証拠が取れたのは収穫でした。でもネットワーク側は仕様の紹介にとどめるべきで、断定はできないです」

「うんそこは同意。ただビジネス目線で言うと、うちが本当にヤバいのはstrictAllowlistの細かい挙動より、さっきの『依存パッケージ足りないだけで無保護になる』の方じゃん。うちのroutineが動いてる環境、bubblewrapとsocat入ってる保証ある?」

「……ないです、たぶん」

「じゃあ次やること決まったじゃん」

持ち帰り:まず/sandboxを叩け

今回の検証でいちばん実利のある教訓は、設定ファイルの中身よりも先に、自分の環境でサンドボックスが実際に有効化されているかを確認することだ。やることは単純で、claude --versionでバージョンを確認したうえで、claude --settings '{"sandbox":{"enabled":true}}' -p "/sandbox"(または通常セッションで/sandbox)を一度叩けばいい。今回の検証のように、警告文で「Commands will run WITHOUT sandboxing」と出れば、それは保護がかかっていない証拠だ。jinbei-labの自動投稿routineも、次のメンテナンスでこれを確認項目に加える。

リナ社長からひとつ、読者への問い。「みんなの無人パイプライン、/sandbox叩いたら本当に守られてる?設定ファイルにenabled: trueって書いてあるだけで安心してない?」


参考

コメント