0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Claude Code の permissions を settings.json に書いたのに効かない3つの理由 — deny が allow に勝つ・Write() は参照されない・先頭 / はルートではない【2026】

0
Posted at

はじめに / 対象と前提

settings.json に permissions を書いて「これでもう聞かれないはず」にしたのに、まだ確認ダイアログが出る。逆に、deny したつもりのコマンドが普通に走る。自分はこの両方を踏んだ。

  • 想定読者: Claude Code を日常的に使っていて、許可ルールを settings.json に書いて共有したい人
  • 環境: Claude Code v2.1.2xx 系(2026-09 時点で確認)、macOS / Linux
  • 前提知識: JSON が読める、.claude/settings.json の場所を知っている

厄介なのは構文として正しいのに意図どおり効かないケースで、原因が別々の仕様に散らばっていて追いづらい。実際にハマった3つに絞って、再現条件と回避策を書く。

TL;DR

  • 評価順は deny → ask → allow の固定順。最初にマッチしたものが勝つので、allow で deny に例外を開けることはできない
  • Write(docs/**) や Glob(src/**) は受理されるが参照されない。パス指定のルールは Edit() と Read() の2つだけ
  • /src/** の先頭スラッシュはファイルシステムのルートではない。絶対パスは // で始める

手順 / 動かし方

最小構成。プロジェクト共有なら .claude/settings.json、自分だけなら .claude/settings.local.json に置く。

{
  "permissions": {
    "allow": [
      "Bash(npm run *)",
      "Bash(git commit *)"
    ],
    "deny": [
      "Bash(git push *)",
      "Read(.env)"
    ],
    "ask": [
      "Bash(git clean *)"
    ]
  }
}

ルールの形は Tool または Tool(指定子)。括弧なしの Bash は全 Bash コマンドにマッチする。

書いたら必ず確認する。/permissions を叩くと適用中のルール一覧とどのファイル由来かが出る。ここに出てこないルールは効いていない。ターミナルからは claude doctor で解決結果と無効なルールが見られる。

設定ファイルの優先順位は、マネージド設定 > claude --settings <file> > .claude/settings.local.json > .claude/settings.json > ~/.claude/settings.json の順で上が強い。

ハマりどころ1: allow は deny の例外にならない

aws は広く止めつつ一部だけ通したい、をやろうとして詰まった。

{
  "permissions": {
    "deny": ["Bash(aws *)"],
    "allow": ["Bash(aws s3 ls)"]
  }
}

aws s3 ls は実行できない。 ルールは deny → ask → allow の順に評価され、最初にマッチしたものが結果を決める。ルールの具体性は考慮されない。より狭い allow を書いても広い deny に先に捕まって終わり。ask と allow の間も同じで、マッチする ask があれば具体的な allow があってもプロンプトは出る。

回避策: 例外を作りたいなら deny を広く書かない。止めたいものだけを列挙する。

{
  "permissions": {
    "deny": ["Bash(aws s3 rm *)", "Bash(aws iam *)"],
    "allow": ["Bash(aws s3 ls *)"]
  }
}

なお deny に括弧なしのツール名(Bash だけ)を書くと、そのツールは Claude のコンテキストから丸ごと消える。括弧つきの Bash(rm *) はツールを残したままマッチした呼び出しだけ止める。挙動が違う。

ハマりどころ2: Write() と Glob() のパスルールは読まれない

「docs/ 以下だけ書き込みを許したい」で最初にこう書いた。

{
  "permissions": {
    "allow": ["Write(docs/**)"]
  }
}

これは無視される。 ファイルのパーミッションチェックで参照されるのは Edit(path) と Read(path) だけ。Write / NotebookEdit / Glob / 旧 MultiEdit にパスを付けたルールは受理されるものの一度も参照されない。v2.1.210 以降なら起動時に警告が出るが、読み飛ばすと気づけない。

回避策: 対応はこう。

書きがちな形 正しい形
Write(docs/**) Edit(docs/**)
NotebookEdit(docs/**) Edit(docs/**)
Glob(src/**) Read(src/**)

Read の deny は同じパスへの Edit / Write もブロックする(新規作成含む)が NotebookEdit はカバーされない。絶対に触らせたくないパスには Edit の deny も並べておく。

ハマりどころ3: 先頭 / は「ルート」ではない

~/.claude/settings.json にこう書いた。

{
  "permissions": {
    "deny": ["Read(/secrets/**)"]
  }
}

プロジェクトの secrets/ は一切ブロックされない。 Read / Edit のパターンは gitignore 記法で、先頭スラッシュはルールを定義した設定ファイルのアンカーを指す。

パターン 意味
//path ファイルシステムのルートからの絶対パス
~/path ホームディレクトリ基準
/path 設定ファイルの由来元からの相対
path / ./path カレントディレクトリからの相対

/path の解決先は置き場所で変わる。プロジェクト設定なら主作業ディレクトリ配下だが、ユーザー設定に書いた /secrets/** は ~/.claude/secrets/** に解決される。効かなかったのはこれが理由だった。

回避策: ユーザー設定から全プロジェクトに効かせるなら // の絶対パスか ~/ のホーム相対を使う。gitignore 準拠なので Read(.env) は Read(**/.env) と等価。

{
  "permissions": {
    "deny": ["Read(.env)", "Read(//**/.env)"]
  }
}

背景・補足: Bash ルールはセキュリティ境界ではない

Bash のルールが見ているのはClaude が書いたコマンド文字列であって、プロセスではない。書き方が変われば素通りする。

ルール 止まる 止まらない
Bash(rm *) rm -rf build/ /bin/rm -rf build/、bash -c 'rm -rf build/'
Bash(git push *) git push origin main git -C . push origin main

ラッパーは固定リストで剥がされる。timeout nice nohup などは剥がされるので Bash(npm test *) が timeout 30 npm test にマッチする。が、npx や docker exec のような実行系ランナーはリストにない。 Bash(devbox run *) は devbox run rm -rf . まで許すので、ランナーは Bash(devbox run npm test) と内側まで含めて書く。

文字列に依存しない強制力が要るなら、ルールではなくサンドボックスか PreToolUse hook を使う。ルールは「事故防止」、サンドボックスは「境界」と役割を分けるのが正しい。

まとめ

  • ルールは deny → ask → allow の固定順で先勝ち。allow で deny に穴は開けられないので、deny は最初から狭く書く
  • パス指定は Edit() と Read() だけが読まれる。Write() / Glob() にパスを付けても参照されない
  • 先頭 / は設定ファイル基準のアンカー。絶対パスは //、ホームは ~/、任意の深さはベア名か **/
  • Bash ルールはコマンド文字列マッチなので /bin/rm や sh -c では回避される。境界が必要ならサンドボックスか hook
  • 書いたら /permissions と claude doctor で適用されているかを必ず目で見る
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?