Bash(git push *)をdenyすればpushされませんか?
保証はない。公式によればこのルールはgit push origin mainを止めるが、git -C . push origin mainのような書き方は止めない。確実に止めるにはサンドボックスのネットワーク制限かPreToolUse hookを使う。
allowルールを広くなりすぎないよう書くには?
*をサブコマンドの後ろに置き、内側のコマンドまで書く。Bash(devbox run *)ではなくBash(devbox run npm test)を使う。前者はdevbox run rm -rf .にも一致する。
WebFetch(domain:...)でドメインを制限すれば十分ですか?
不十分だ。公式はWebFetchだけではネットワークアクセスを防げず、Bashが許可されていればClaudeはcurlで任意のURLに到達できると述べている。curl・wgetのdenyとサンドボックスのネットワーク許可リストを併用する。
エンジニアではありません。一言でいうと?
権限ルールは「刃物持ち込み禁止」の貼り紙のようなもので、普通の持ち方しか認識しない。隠し方を変えれば気づかない。確実に止めるには検査機、つまりサンドボックスが必要だ。
Bashの権限ルールは「このコマンドを許可・禁止する」ものに見えるが、公式の権限ドキュメントは繰り返し、ルールが照合するのはプログラムそのものではなくClaudeが書くコマンドテキストだと強調している。本稿は、ドキュメントの中で「ブロックされているはず」と誤解しやすい箇所を集めた。すべて公式の権限ページ(Configure permissions)に基づく。各ケースを自分で検証してはいないので検証結果は書かず、「私の判断」と記した部分が私の整理だ。
ドキュメントの警告は、*をサブコマンドの後ろに置くことだ。Bash(git log *)はgit logのみを許可し、Bash(git *)はすべてのgitコマンドを許可する。さらに微妙なのがBash(git * main)で、ドキュメントの表はgit -c core.fsmonitor=<script> diff mainに一致すると述べる。*がサブコマンドとその前のすべてのオプションを表すためで、gitに指定プログラムを実行させる-cも含まれる。また、末尾の「スペース+*」であるBash(ls *)はlsofに一致しないが、Bash(ls*)は一致する。
ドキュメントの表は、denyまたはaskルールが止められるものと止められないものを挙げている:
Bash(rm *)はrm -rf build/を止めるが、/bin/rm -rf build/やbash -c 'rm -rf build/'は止めない。Bash(curl *)はcurl https://example.comを止めるが、/usr/bin/curlやsh -c 'curl ...'は止めない。Bash(git push *)はgit push origin mainを止めるが、git -C . push origin main、git -c push.default=current push origin main、git 'push' origin mainは止めない。ドキュメントの結論は明快だ。denyやaskルールはClaudeが通常生成する書き方をカバーするだけで、そのプログラムを囲むセキュリティ境界ではない。コマンドテキストに依存しないファイル・ネットワークの強制にはサンドボックスを、コマンド全文を独自ロジックで検査するにはPreToolUse hookを使う。「止めない」列のコマンドは、他のルールと権限モードで決まる。
&&、||、;、|、|&、&、改行。Bash(safe-cmd *)はsafe-cmd && other-cmdを通さず、各サブコマンドがそれぞれ一致する必要がある。denyとaskは、サブシェル、コマンド置換、forループ内を含め、どのサブコマンドが一致しても有効になる。timeout、time、nice、nohup、stdbuf、command、builtin、zshのnoglob。そのためBash(npm test *)はtimeout 30 npm testにも一致する。リストは組み込みで設定できない。Bash(rm *)のdenyはFOO=bar rm -rf tmp/も止める。direnv exec、devbox run、mise exec、npx、docker execは除去されず、Bash(devbox run *)はrun以降のすべて、devbox run rm -rf .も含めて一致する。ドキュメントは、Bash(devbox run npm test)のように内側のコマンドまで含めた具体的なルールを勧める。watch、setsid、ionice、flockなどのexecラッパーや、-exec、-delete、-fprint付きのfindは、プレフィックスルールでは自動承認できず、Manualモードでは確認が出る。ドキュメントの例はBash(curl http://github.com/ *)で、GitHubだけに制限するつもりが、URLの前に置いたオプション、httpsへの変更、-Lでのリダイレクト追従、変数に入れたURLのいずれも一致しない。代替案は、curlとwgetをdenyし、WebFetch(domain:github.com)でドメインを許可すること。denyはパス指定やsh -cを捕まえないので、制限を確実にしたいならサンドボックスのネットワーク許可リストと組み合わせること。またはPreToolUse hookを使う。さらにドキュメントは、WebFetchだけではネットワークアクセスを防げず、Bashが許可されていればClaudeはcurlで任意のURLに到達できると強調している。
ドキュメントによれば、どのスコープのdenyもallowより優先される。managedのdenyは--allowedToolsで上書きできず、ユーザーレベルのdenyはプロジェクトレベルのallowを止める。PreToolUse hookはルールを迂回しない。一致するdenyルールは依然としてブロックし、一致するaskルールはhookが"allow"を返しても確認を出す。逆に、exit code 2で終了するhookは、権限ルールの評価より前に呼び出しを止め、allowルールがあっても同じだ。
この節は私の整理であり、公式の助言ではない。Bashルールは確認を減らす便利層と考え、何かが起きないことの保証とは考えない。本当に起きてはいけないこと(削除、push、外部通信)はサンドボックスかhookで止める。allowルールは内側のコマンドまで含めて具体的に書き、Bash(git *)やBash(npx *)のような広すぎる形は避ける。