本文へスキップ
AI活用

Claude Codeのdenyが効かない3つの穴|権限ルールは書き方で無効になる

Hirokuma
8分で読める
Claude Codeのdenyが効かない3つの穴|権限ルールは書き方で無効になる

denyルールを「書いたこと」と、それが「効いていること」は別の話です。2026-09-03公開のClaude Code 2.1.260は、権限ルールの書き方そのものが境界の穴になっていた3件を修正しました。しかも同じリリースで、直前の2.1.259が塞いだ穴の修正を1本、差し戻しています。

書いたルールが適用側に届いていたか。設定ファイルを読み直しても、これは出てきません。今回のchangelogはその怖さがよく出ているので、3つの穴の中身と、差し戻しから持ち帰った運用の型を整理します。一次情報は公式のchangelogです。

Claude Code公式changelog(2.1.259 / 2.1.260)Release notes for Claude Code, including new features, improvements, and bug fixes by version.code.claude.com

書き方が穴になっていた3つのパターン

2.1.260で修正された3件は、どれも「ルールの意図」ではなく「ルールの記法」が原因です。

1. パスに括弧が入ると、ルールごと捨てられていた

Edit / Write / Read の権限ルールで、パスに括弧が含まれるものが「無効」として捨てられるか、Bashサンドボックスに無視されていました。結果として、読み取り専用にしたはずのフォルダが書き込み可能なまま残ります。

Next.jsのルートグループ(app/(marketing)/ のような形)を思い浮かべると、括弧入りパスは特別な形ではありません。守っているつもりのdenyが、パスの見た目だけで不発になっていたことになります。

2. 壊れたパターンが1本あると、全ファイル編集が死んでいた

ファイル権限ルールのどれか1本に、コンパイルできないパターン(閉じていない角括弧など)があると、すべてのファイル編集が Invalid regular expression で失敗していました。1本のtypoが、そのルールだけでなく編集機能全体を巻き込む形です。

2.1.260からは、そうしたdenyルールは書かれたリテラルパスを守るようになりました。壊れ方が「全停止」から「文字どおりのパスを守る」に変わったわけです。

3. zshの変数代入に隠したコマンド置換が素通りしていた

Bashの権限チェックが、zshの REPORTTIME / REPORTMEMORY / DIRSTACKSIZE への代入に隠したコマンド置換を自動承認していました。変数代入の見た目をしていれば、中でコマンドが動いても素通りする形です。2.1.260からは承認を求めるようになりました。

これは他人事ではないと思っています。うちの自動運用では、破らせたくない操作をhooksのBashガード(正規表現ベースの検査スクリプト)で止めていますが、変数代入に埋めたコマンド置換は、この種の正規表現検査が取りこぼしやすい形のはずです(自前ガードで実際に試した結果ではなく、パターンからの見立てです)。禁止ラインを正規表現で書く設計の限界がそのまま出る例だと受け止めました。

Claude Codeのhooksで自動運用に禁止ラインを引く|Bashガード実装記録Claude Codeのhooksで、エージェントに破らせたくない操作をコードとして強制する実装記録。PreToolUseフックの設定、Bashコマンドを検査するガードスクリプト、exit code 2でブロックする仕組み、正規表現ルールの設計と限界まで、実運用中の構成をそのまま解説します。www.tentspace.net

塞いだ穴が、1リリースで戻った

今回いちばん考えさせられたのは、修正そのものより差し戻しです。

直前の2.1.259には、Bashコマンドの引数にも Read() のdenyルールを適用する修正が入っていました。オプションの値、gitの操作対象、cd DIR && cat FILE のような複合コマンドで、denyしたはずのパスが読めてしまう取りこぼしを塞ぐ変更です。

これが2.1.260で差し戻されました。理由もchangelogに明記されています。build 配下を対象にした Read() denyルールの下で npm run build が全モードで拒否され、cdgrep の複合コマンドがauto modeでも承認プロンプトを出すようになっていたためです。

つまりこういうことです。「build 配下を読むな」というルールを素直に引数へ適用すると、npm run build という日常操作まで止まる。権限の穴を塞ぐ修正が、正常な操作を巻き込んで、1リリースで戻る。塞がったはずの取りこぼし(引数経由の読み取り)は、いままた開いている状態です。

境界の実装は行ったり来たりします。「あのバージョンで直ったはず」は、次のバージョンでも真とは限りません。

黙って捨てられなくなった、という改善

2.1.260には、地味ですが運用上ありがたい変更も入っています。

  • 閉じ括弧の後ろに文字が続くルール(Bash(ls) x のような、これまで何にもマッチしなかったもの)が、黙って無視されず「無効な設定」として報告されるようになった
  • Glob / Grep の検査順序が変わり、パスの存在確認より権限チェックが先になった(存在しないパスは権限判定の後に報告される。Read と同じ順序)
  • permissions.blockReadsOutsideWorkingDirectories がmacOSでsandbox内のgitからユーザーのgit configを隠していた不具合の修正

特に1つ目は性質が違います。これまでは「書いたのに何にもマッチしないルール」が沈黙のまま存在できました。報告されるようになったことで、記法ミスが観測できる事象に変わっています。穴の修正と観測手段の追加が同じリリースに入っているのは、権限まわりの改善の筋としてよいと思います。

実務でどうするか

ここからはうちの運用判断です。無人でエージェントを回す前提なので、境界が静かに壊れていることが一番怖い。その観点で3つに絞りました。

1. 先に更新する。棚卸しはその後。 記法起因の穴は、設定を読み直しても見つけられません(無効なルールが報告されるのは2.1.260以降です)。手元の設定を精査するより先にバージョンを上げる方が、同じ時間で塞がる穴が多い。順番の問題です。

2. 記法だけの棚卸しを1回やる。 更新後に、settings.json の権限ルールを「意図」ではなく「記法」の観点だけで見ます。数えるのは3つ。括弧入りパスに当たる行、文字クラスや複雑なパターンを使う行、閉じ括弧の後ろに余分な文字がある行。意図の見直しを始めると終わらないので、まず計数だけ。うちもhooksのガードと settings.json の2箇所に同じ観点を当てる予定です。

3. denyの意図を書き分ける。 Read() のdenyがBash引数に及ぶ範囲は、2.1.259と2.1.260で実際に往復しました。「このパスを読まれたくない」のか「このパスに触れる操作を全部止めたい」のか。意図が後者なら、ファイル権限ルールだけに任せず、hooks側にも同じ禁止を重ねて置く。どちらか一方が仕様変更で動いても、もう一方が残る配置です。層を分けて守る考え方は、以前に4層で整理しています。

Claude Codeの権限設定4層ガイド|denyを厚くするだけでは守れないClaude Codeの権限設定を「渡さない・許す・止める・外側で強制」の4層で設計する方法を解説します。allowルールのワイルドカード警告や--restrictedフラグなど直近の公式アップデートを根拠に、hooksによる禁止だけでは塞げない穴と、各層の使い分けを実運用の構成で整理します。www.tentspace.net

denyは届いてはじめて境界になる

  • 2.1.260は、括弧入りパスの無視・壊れたパターンによる全編集停止・zsh変数代入に隠したコマンド置換の自動承認という、記法起因の穴3件を修正した
  • 同じリリースで、2.1.259の「Bash引数へのRead deny適用」は正常操作を巻き込んで差し戻された。引数経由の取りこぼしは現在も開いている
  • 無効なルールが報告されるようになり、記法ミスは観測できる事象になった

denyは書いた瞬間ではなく、適用側に届いてはじめて境界になります。そして届くかどうかは、バージョンで変わります。設定を増やすより先に、いま書いてあるものが届いているか。まずそこからです。