一行要約
ルールは deny → ask → allow の順に評価され、最初に一致したものが結果を決める(具体性は順序を変えない)。したがって広い deny ルールに狭い allow の例外を持たせることはできない。
要点
3階層の権限システム
| ツール種別 | 例 | 承認が要るか | 「今後聞かない」の効果 |
|---|---|---|---|
| 読み取り専用 | ファイル読み取り、Grep | 不要(作業ディレクトリと追加ディレクトリ内) | — |
| Bash コマンド | シェル実行 | 必要(組み込みの読み取り専用コマンドを除く) | リポジトリとコマンドごとに永続 |
| ファイル変更 | Edit / Write | 必要 | セッション終了まで |
評価順序(最重要)
Rules are evaluated in order: deny, then ask, then allow. The first match in that order determines the outcome, and rule specificity doesn’t change the order. ルールは deny → ask → allow の順で評価される。この順序で最初に一致したものが結果を決め、ルールの具体性は順序を変えない。
A broad deny rule like
Bash(aws *)blocks every matching call, including calls that also match a narrower allow rule likeBash(aws s3 ls), so a deny rule can’t carry allowlist exceptions.Bash(aws *)のような広い deny ルールは、一致するすべての呼び出しをブロックする。Bash(aws s3 ls)のようなより狭い allow ルールにも一致する呼び出しを含めてである。つまりdeny ルールに許可の例外を持たせることはできない。
deny ルールは2種類で挙動が違う:
- 裸のツール名(
Bash)— ツールを Claude の context から完全に取り除く。Claude はその存在を知らない - スコープ付き(
Bash(rm *))— ツールは使えるまま、一致する呼び出しをブロックする
Permission rules are enforced by Claude Code, not by the model. Instructions in your prompt or
CLAUDE.mdshape what Claude tries to do, but they don’t change what Claude Code allows. permission ルールを強制するのは Claude Code であって、モデルではない。プロンプトやCLAUDE.mdの指示は Claude が何をしようとするかを形づくるが、Claude Code が何を許すかは変えない。
ルール構文
形式は Tool または Tool(specifier)。
入力パラメータでのマッチ(deny / ask 専用):
Agent(model:opus)/Agent(isolation:worktree)/Bash(run_in_background:true)- allow ルールでは使えない(1つのパラメータ値だけでは呼び出し全体の安全性を保証しないため)
- パラメータ名はツール入力の直下フィールドでなければならない。オブジェクトや配列の中は不可
- **1ルールにつき1パラメータ。**2つを条件にしたいなら2ルール書く
- モデルが省略したパラメータは決してマッチしない —
Agent(model:*)はmodel未設定の呼び出しにマッチしない - 正規化前のリテラル入力と比較される —
Agent(model:opus)は別名opusにはマッチするが完全なモデル ID にはマッチしない
ツールの主要コンテンツフィールドはこの方法でマッチできない — Bash/PowerShell の
command、Read/Edit/Write のfile_path、Grep/Glob のpath、WebFetch のurl。Bash(command:rm *)は複合コマンドで迂回できてしまうので Claude Code は無視して起動時に警告を出す。
ツール名のワイルドカード: deny / ask はツール名の位置でも glob を受け付ける("*" は全ツール、"mcp__*" は全 MCP ツール)。allow のツール名 glob は mcp__<server>__ の literal な接頭辞の後でのみ許される — サーバ部分に glob は使えない。"*" や "mcp__*" のような anchor のない allow glob は警告付きでスキップされ、何も自動承認しない。
The label shown for a tool in the transcript can differ from its canonical name. For example, the tool labeled
Stop Taskhas the canonical nameTaskStop. Permission rules and hook matchers match the canonical name only. トランスクリプト上でツールに表示されるラベルは、正式名称と異なることがある。たとえばStop Taskと表示されるツールの正式名称はTaskStopである。permission ルールと hook のマッチャーは正式名称にのみ一致する。
Bash ルールの落とし穴
単一の * は空白を含む任意の文字列にマッチするので、1つのワイルドカードが複数の引数にまたがる。
末尾の * の前に空白があると単語境界を強制する:
Bash(ls *)はls -laにマッチするがlsofにはマッチしないBash(ls*)(空白なし)はlsofにもマッチする
複合コマンド:
Claude Code is aware of shell operators, so a rule like
Bash(safe-cmd *)won’t give it permission to runsafe-cmd && other-cmd. The recognized command separators are&&,||,;,|,|&,&, and newlines. A rule must match each subcommand independently. Claude Code はシェルの演算子を認識するため、Bash(safe-cmd *)というルールではsafe-cmd && other-cmdの実行は許可されない。認識される区切りは&&、||、;、|、|&、&、改行である。ルールは各サブコマンドに個別に一致しなければならない。
複合コマンドを「今後聞かない」で承認すると、サブコマンドごとに別々のルールが保存される(最大5つ)。
ラッパーの剥がし方(ここは知らないと事故る):
| 剥がされる | 剥がされない |
|---|---|
timeout, time, nice, nohup, stdbuf, シェル組み込みの command / builtin, zsh の noglob | command -v(照会形式)、zsh の nocorrect |
フラグなしの xargs | xargs -n1 ...(フラグ付き) |
既知の安全な環境変数の先頭代入(NODE_ENV=test npm test)。ただし allow ルールはそれ以外の変数代入を跨がない。deny / ask は任意の先頭代入を跨いでマッチする | — |
This wrapper list is built in and is not configurable. Development environment runners such as
direnv exec,devbox run,mise exec,npx, anddocker execare not in the list. Because these tools execute their arguments as a command, a rule likeBash(devbox run *)matches whatever comes afterrun, includingdevbox run rm -rf .. このラッパーの一覧は組み込みであり、設定で変更できない。direnv exec、devbox run、mise exec、npx、docker execといった開発環境のランナーは一覧に含まれない。これらは引数をコマンドとして実行するため、Bash(devbox run *)のようなルールはrunの後に来るものすべてに一致してしまう。devbox run rm -rf .も含めてである。
watch / setsid / ionice / flock のような exec ラッパーは常に確認を求め、接頭辞ルールで自動承認できない。 find の -exec / -delete も同様。
組み込みの読み取り専用コマンド(設定不可): ls, cat, echo, pwd, head, tail, grep, find, wc, which, diff, stat, du, cd、および git の読み取り専用形式。
それでも確認を求めるケース:
- 書き込み可能フラグを持つコマンドでの unquoted glob(
find,sort,sed,git)— glob が-deleteのようなフラグに展開されうるため - 別デーモンを指す
docker(-H,--context, Podman の--url/--connection) fileの-m/-f(フラグの値に書かれたパスを開くため)- Windows のネットワーク(UNC)パス — Windows の認証情報が相手ホストに送られうるため
- 解析できないコマンド、および 10,000文字を超えるコマンド
cd+git(新しいディレクトリの hook が走りうる)、cd+ 出力リダイレクト(リダイレクト先の解決先が確定できない場合。/dev/nullだけなら確認なし)
Bash permission patterns that try to constrain command arguments are fragile.
Bash(curl http://github.com/ *)won’t matchcurl -X GET http://...,https://, redirects,URL=... && curl $URL, or extra spaces. コマンドの引数を制約しようとする Bash の permission パターンは脆い。Bash(curl http://github.com/ *)は、curl -X GET http://...、https://、リダイレクト、URL=... && curl $URL、余分な空白のいずれにも一致しない。
URL を絞りたいなら: curl / wget を deny し、WebFetch の WebFetch(domain:...) を使う / PreToolUse hook で検証する / CLAUDE.md は補助にとどめる。WebFetch だけではネットワークアクセスを防げない — Bash が許可されていれば curl で任意の URL に届く。
Read / Edit ルール
Editルールはファイルを編集する全組み込みツールに適用されるReadの deny ルールは同じパスの Edit(新規作成を含む)もブロックする。 ただし Write と NotebookEdit はカバーされないので、どのツールも変更してはいけないパスにはEditの deny ルールも足す- ファイル権限は
Edit(path)とRead(path)ルールだけで判定される。Write(...)/NotebookEdit(...)/Glob(...)にパスルールを書いても受理はされるが決して参照されず、起動時に警告が出る
パターンの anchor 4種(gitignore 構文):
| パターン | 意味 |
|---|---|
//path | ファイルシステムルートからの絶対パス |
~/path | ホームディレクトリから |
/path | 設定ファイルの出所からの相対 |
path / ./path | カレントディレクトリからの相対 |
A pattern like
/Users/alice/fileisn’t an absolute path. The single leading slash anchors at the settings source, not the filesystem root. Use//Users/alice/filefor absolute paths./Users/alice/fileというパターンは絶対パスではない。先頭のスラッシュ1つは、ファイルシステムのルートではなく設定ファイルの位置を基準にする。絶対パスには//Users/alice/fileを使え。
/path の解決先は設定の出所で変わる:
| 定義場所 | /path の解決先 |
|---|---|
.claude/settings.json | <project root>/path |
.claude/settings.local.json | <original cwd>/path |
~/.claude/settings.json | ~/.claude/path |
--settings <file> | <file のディレクトリ>/path |
CLI フラグ / /permissions / セッションルール | <original cwd>/path |
A deny rule such as
Read(/secrets/**)in user settings blocks~/.claude/secrets/**, not asecretsdirectory in your project. user 設定にあるRead(/secrets/**)のような deny ルールがブロックするのは~/.claude/secrets/**であって、プロジェクト内のsecretsディレクトリではない。
Read and Edit deny rules apply to Claude’s built-in file tools and to file commands Claude Code recognizes in Bash, such as
cat,head,tail, andsed. They don’t apply to arbitrary subprocesses that read or write files indirectly, like a Python or Node script. For OS-level enforcement, enable the sandbox. Read と Edit の deny ルールは、Claude の組み込みファイルツールと、Claude Code が Bash 内で認識するファイル操作コマンド(cat、head、tail、sedなど)に適用される。**Python や Node のスクリプトのように、間接的にファイルを読み書きする任意のサブプロセスには適用されない。**OS レベルで強制したいなら sandbox を有効にせよ。
WebFetch ルール
WebFetch(domain:example.com)— そのホストWebFetch(domain:*.example.com)— 任意の深さのサブドメイン。ただしexample.com自身にはマッチしない- 先頭の
*.と単独の*以外の位置では、ワイルドカードは2つのドットの間だけにマッチする —example.*はexample.orgにマッチするがexample.evil.comにはマッチしない(攻撃者が登録できるドメインに末尾ワイルドカードがマッチしないようにするため)
Agent / Cd ルール
Agent(Explore)/Agent(Plan)/Agent(my-custom-agent)Cdはモデルが呼べるツールではない —/cdを自分で実行したときにだけ適用される。Cdallow ルールを1つでも足すと/cdが allowlist モードに切り替わるCdのパスマッチはディレクトリパス全体に anchor される(gitignore 形式ではない)。*はちょうど1セグメント、**はセグメントを跨ぐ。末尾の/**はその root 自体にもマッチする
hook との関係
Hook decisions don’t bypass permission rules. Claude Code evaluates deny and ask rules regardless of what a PreToolUse hook returns. **hook の判断は permission ルールを迂回しない。**PreToolUse hook が何を返そうと、Claude Code は deny と ask のルールを評価する。
ただし exit code 2 のブロックは別:
A hook that exits with code 2 stops the tool call before permission rules are evaluated, so the block applies even when an allow rule would otherwise let the call proceed. 終了コード 2 で終わる hook は、permission ルールが評価される前にツール呼び出しを止める。そのため、allow ルールなら通していたはずの呼び出しでもブロックが効く。
→ 「Bash を全許可しつつ一部だけ止める」を実現するには、"Bash" を allow に入れて、PreToolUse hook で特定のコマンドを拒否する。
作業ディレクトリと追加ディレクトリ
--add-dir / /add-dir からロードされる設定(permissions.additionalDirectories 設定からは何もロードされない):
| 設定 | --add-dir からロードされるか |
|---|---|
.claude/skills/ の skill | はい(live reload 付き) |
.claude/agents/ の subagent | はい |
.claude/settings.json | enabledPlugins と extraKnownMarketplaces キーのみ |
CLAUDE.md / .claude/rules/ / CLAUDE.local.md | CLAUDE_CODE_ADDITIONAL_DIRECTORIES_CLAUDE_MD=1 のときのみ |
/cd は /add-dir と違ってセッションを移動させる — 新しいディレクトリの CLAUDE.md がロードされ、--resume もそこから見つかる。
設定の優先順位
Permission rules follow the same settings precedence as all other settings, with managed settings highest: no other level, including command line arguments, can override a managed permission rule. permission ルールは他の設定と同じ優先順位に従い、managed 設定が最上位に来る。コマンドライン引数を含め、他のどの階層も managed の permission ルールを上書きできない。
If a tool is denied at any level, no other level can allow it. The same holds across scopes: a user-level deny blocks a project-level allow. **いずれかの階層でツールが拒否されていれば、他のどの階層もそれを許可できない。**これはスコープをまたいでも成り立つ。user 階層の deny は project 階層の allow をブロックする。
project の allow ルールと workspace trust
permissions.allowrules andpermissions.additionalDirectoriesentries in a project’s.claude/settings.jsongrant capability, so Claude Code applies them only after you accept the workspace trust dialog.denyandaskrules aren’t affected, since they only restrict. プロジェクトの.claude/settings.jsonにあるpermissions.allowルールとpermissions.additionalDirectoriesの項目は権限を与えるものなので、Claude Code はワークスペースの信頼ダイアログを承認した後にのみこれらを適用する。denyとaskのルールは制限するだけなので影響を受けない。
trust はワークスペース単位で保存され、git リポジトリのルート(リポジトリ外なら起動ディレクトリ)をキーにする。親ディレクトリを信頼しても、入れ子のプロジェクトの allow ルールは適用されない。
managed 専用の設定(抜粋)
user / project に書いても効かないもの:
| 設定 | 効果 |
|---|---|
allowManagedPermissionRulesOnly | user / project が allow / ask / deny を定義できなくする |
allowManagedHooksOnly | managed / SDK / managed で強制有効化した plugin の hook 以外をブロック |
allowManagedMcpServersOnly | managed の allowedMcpServers のみ有効(deniedMcpServers は全ソースからマージ) |
strictPluginOnlyCustomization | skill / agent / hook / MCP を plugin か managed からのみに限定。true で全4面、配列で個別指定 |
disableSideloadFlags | --plugin-dir / --plugin-url / --agents / --mcp-config を起動時に拒否 |
strictKnownMarketplaces / blockedMarketplaces | plugin marketplace の制限 |
forceRemoteSettingsRefresh | remote managed settings の取得に失敗したら起動を止める(fail-closed) |
そのまま使える具体例
npm と git commit を許可し、git push を禁じる:
{
"permissions": {
"allow": [
"Bash(npm run *)",
"Bash(git commit *)",
"Bash(git * main)",
"Bash(* --version)",
"Bash(* --help *)"
],
"deny": [
"Bash(git push *)"
]
}
}全 MCP ツールを禁じる:
{
"permissions": {
"deny": ["mcp__*"]
}
}Explore エージェントを無効化する:
{
"permissions": {
"deny": ["Agent(Explore)"]
}
}「Bash は全許可、一部だけ hook で止める」構成(この文書で最も実用的なパターン):
{
"permissions": {
"allow": ["Bash"]
},
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{ "type": "command", "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/block-dangerous.sh" }
]
}
]
}
}user settings から全プロジェクトに効くパスルールを書く(/ ではなく // か ~/):
{
"permissions": {
"deny": [
"Read(//Users/alice/secrets/**)",
"Read(~/.ssh/**)"
]
}
}環境ランナーを許可するときは内側のコマンドまで書く:
❌ Bash(devbox run *) → devbox run rm -rf . まで通る
✅ Bash(devbox run npm test) → 許可したい内側のコマンドごとに1ルールワイルドカードの単語境界:
Bash(ls *) → ls -la にマッチ、lsof にはマッチしない
Bash(ls*) → lsof にもマッチしてしまう
Bash(ls:*) → Bash(ls *) と同じ(:* は末尾でのみ有効)原典で言及されている関連文書
- permission-modes — モードとルールの関係
- hooks-guide — exit code 2 のブロックが allow ルールより優先されること
- claude-code-sandboxing — OS レベルの強制(任意のサブプロセスまでカバーする唯一の手段)
- mcp — コネクタツールの
askとrequiresUserInteraction - sub-agents —
Agent(...)ルール - large-codebases —
Readdeny ルールによる読み取り削減
未取得の派生リンク
- https://code.claude.com/docs/en/settings — 設定の完全なリファレンスと優先順位
- https://code.claude.com/docs/en/auto-mode-config — 信頼インフラの設定
- https://code.claude.com/docs/en/security — workspace trust などの安全機構
- https://github.com/anthropics/claude-code/tree/main/examples/settings — 用途別の設定例