Skip to content

Claude Code の権限設定を強化する:リポジトリ外への書き込みをブロック、プロンプト待ちを拒否に、settings.local.json を監査

更新日

Claude Code 2.1.319 で実測した settings.json:blockWritesOutsideWorkingDirectories、denyInsteadOfPrompting、Read の deny ルール、無人実行向けの dontAsk。さらに settings.local.json のシークレット漏洩監査と、バックドア入り拡張のチェック。

結論から: リポジトリのルートにある .claude/settings.json に以下を書いてコミットし、Claude Code を再起動してください。Claude Code 2.1.319 以降が必要です(claude --version で確認し、claude update で更新します)。

{
  "permissions": {
    "blockWritesOutsideWorkingDirectories": true,
    "denyInsteadOfPrompting": true,
    "deny": [
      "Read(./.env)",
      "Read(./.env.*)",
      "Read(./secrets/**)",
      "Bash(curl *)",
      "Bash(wget *)"
    ]
  }
}

各行が何をしてくれるか:

行動作追加されたバージョン
blockWritesOutsideWorkingDirectoriesWrite、Edit、NotebookEdit ツールが作業ディレクトリ外のパスをすべて拒否します。bypassPermissions を含むすべての権限モードで有効です2.1.314(2026 年 10 月 30 日)
denyInsteadOfPrompting権限プロンプトを待つことになるツール呼び出しを拒否し、ターンを続行します。ターミナルセッション、サブエージェント、チームメイトで有効です2.1.319(2026 年 11 月 6 日)
Read(...) の deny ルール.env と secrets/ は、ファイルツールからも、そのファイル名を指定する cat、head、sed などのシェルコマンドからも読めなくなります以前から存在
Bash(curl *) / Bash(wget *)シェルからのネットワーク取得は、確認を求められるのではなく拒否されます以前から存在

書き込みブロック、deny ルール、無人実行時の挙動は、2026 年 11 月 8 日に macOS 上の Claude Code 2.1.319 で、テストごとに権限モードを指定した claude -p --output-format json の実行として実測しました。実際の拒否メッセージは後述の通り引用しています。変更履歴では denyInsteadOfPrompting はターミナルセッション、サブエージェント、チームメイト向けと説明されており、-p の実行はすでに拒否する仕様のため、その説明はテストではなく変更履歴 (opens in a new tab)に基づきます。このガイドの残りでは、これらの設定がなぜ今重要なのか、それぞれが何をカバーし何をカバーしないのか、そして一度は実行しておくべき 3 つのチェックを説明します。

なぜ今なのか:9 日間で 3 件のインシデント

Claude Code は 2026 年 10 月 26 日から 11 月 6 日の間に 7 つのリリースを出し、同じ期間に 3 つのセキュリティ関連の出来事が起きました。それぞれが具体的なチェック項目に対応します。

日付何が起きたか一度だけ行うチェック
10 月 30 日Phorion が、Cursor Marketplace で配布されていた公式 Claude Code for VS Code 拡張のバックドア入りビルド(バージョン 2.1.312 と 2.1.313)を発見。攻撃者の SSH 鍵を ~/.ssh/authorized_keys に追記し、永続化を仕込みます(アドバイザリ (opens in a new tab)、HN 1,011 ポイント (opens in a new tab))拡張のバージョンを一覧し、authorized_keys を grep する。後述のステップ 5 を参照
11 月 5 日GitHub issue #107757 (opens in a new tab):Claude Code が Web リクエストの User-Agent ヘッダーにアカウントのメールアドレスを入れていました。約 1,000 件のリアクション、11 月 8 日時点でまだオープン(HN 1,597 ポイント (opens in a new tab))2.1.317 以降に更新する。ツールがメールアドレスを送信する前に確認が入るようになります。後述のステップ 6 を参照
11 月 7 日Apiiro が、「Yes, and don't ask again」の承認によってパスワードやトークンを含むシェルコマンドが .claude/settings.local.json に保存されていた公開 GitHub ファイルを 1,122 件発見(レポート (opens in a new tab)、HN 500+ ポイント (opens in a new tab))後述のステップ 4 の監査スクリプトを実行する

これらはどれも権限モードでは解決しません。設定ファイル、監査、バージョン確認が必要です。

トレンド記事

ステップ 1:リポジトリ外へのファイル書き込みをブロックする

permissions.blockWritesOutsideWorkingDirectories を有効にすると、3 つのファイル編集ツールが作業ディレクトリ内にないパスをすべて拒否します。作業ディレクトリとは、Claude Code を起動したフォルダに加えて、/add-dir、--add-dir、またはユーザー設定や管理対象設定の permissions.additionalDirectories で追加したものです。リポジトリ自身の .claude/settings.json にある additionalDirectories のエントリでは、このブロックは解除されません。このブロックは bypassPermissions を含むすべての権限モードで維持され、いずれかの設定ファイルに true があれば他の false より優先されるため、リポジトリ側で有効にしておけば clone した全員に適用されます。

実験用プロジェクトでこのキーを設定し、acceptEdits モードの Claude Code に、Write ツールでホームディレクトリにファイルを作るよう頼みました。呼び出しは次のメッセージで拒否されました:

/Users/me/kanaries-block-test.txt is outside /path/to/proj; the
permissions.blockWritesOutsideWorkingDirectories setting blocks writes
outside the working directories. Ask the user to add the directory with
/add-dir, or to remove that setting.

ファイルは作成されず、JSON の結果には tool_name: "Write" としてこの呼び出しが permission_denials に記録されていました。

頼る前に知っておくべき 4 つの制限:

  • シェルコマンド、MCP ツール、hook プログラムは制限しません。Bash ツールからの echo x > ~/file は Write 呼び出しではありません。シェルの書き込みを囲い込むには、後述の「オプション:シェルもサンドボックス化する」でサンドボックスを有効にしてください。
  • Claude Code 自身の一部のファイルは書き込み可能なままです:plan ファイル、セッションのスクラッチパッド、バックグラウンドセッションの tmp ディレクトリ、プロジェクトの auto-memory .md ファイル。これは仕様です。
  • Claude は Claude Code の設定ファイルを一切編集できなくなります。 リポジトリ内の設定ファイルであっても同様です。設定ファイルがこのブロックを解除できてしまうためです。.claude/settings.json は自分で編集してください。
  • worktree ツールが使えなくなります。 このキーを有効にすると、Claude Code は EnterWorktree と ExitWorktree を取り除くか、それらの呼び出しを拒否します。サブエージェントが worktree を必要とする場合は、リポジトリルートの .claude/worktrees を作業ディレクトリとして追加してください。

対になる設定の permissions.blockReadsOutsideWorkingDirectories(2.1.257 以降)は、Read、Grep、Glob、LSP 呼び出しに対して同じことをします。リポジトリからディスクの他の部分を見せたくないときに有効にしてください。

ステップ 2:deny ルールでシークレットを読めないようにする

Read(path) の deny ルールは、組み込みのファイルツールに加えて、ドキュメントによれば Claude Code が Bash 内で認識するファイルコマンド(cat、head、tail、sed、tee)と、そのファイル名を指定するシェルリダイレクトもブロックします。同じパスに対する Edit と Write もブロックされるので、Claude が .env を上書きすることもできません。

実測:"deny": ["Read(./.env)"] を設定し、Read ツールで .env を読むよう Claude に頼むと、次が返りました:

File is in a directory that is denied by your permission settings.

このルールはシェルにも届きます。acceptEdits での実行で cat README.md の次に cat .env を頼んだところ、前者はファイルを表示し、後者は Permission to use Bash with command cat .env has been denied. で拒否されました。別のデフォルトモードの claude -p 実行では、Bash(curl *) ルールにより curl -sI https://example.com が拒否されました。すべての拒否は permission_denials に記録され、どの実行もハングせずに終了しました。

権限リファレンス (opens in a new tab)にあるルール構文の落とし穴 3 つ:

  • Read(...) と Edit(...) を使ってください。パスを指定した Write(docs/**)、Grep(docs/**)、Glob(...) のルールは受け付けられますが、一度もマッチしません。
  • * の前にスペースがある Bash(git diff *) は、git diff で始まる任意のコマンドにマッチします。Bash(git diff*) だと git diff-index にもマッチしてしまいます。
  • deny ルールは、ファイル名を指定せずに読むコマンド(シークレットのあるフォルダから実行した grep -r pattern . など)を捕まえられません。そこはサンドボックスの役目です。

.claudeignore ファイルは効果がありません。その内容は Read の deny ルールに移してください。

ステップ 3:権限プロンプトで止まらないようにする

無人実行の Claude Code を、待たせるのではなく拒否させる方法は現在 4 つあります。実行する場所で選んでください。

状況使うもの挙動
離席する対話ターミナルセッション(そのサブエージェントとチームメイトを含む)設定に "denyInsteadOfPrompting": true(2.1.319)プロンプトを待つことになる呼び出しは拒否され、ターンが続行します(変更履歴の記述。-p モードはすでに拒否する仕様のため、-p でこれをテストすることはできませんでした)
権限モードを指定しない claude -p または Agent SDK の実行追加設定なし2.1.302 以降、-p は Manual モードで開始し、承認が必要な呼び出しをすべて拒否します。上で実測済み
厳重にロックダウンした CI ジョブ--permission-mode dontAskプロンプトを出すことになる呼び出しはすべて拒否されます(インストール済みの mod が一部の呼び出しを承認することはあります)。読み取り専用コマンド、作業ディレクトリ内のファイル読み取り、allow ルールは引き続き実行されます
権限ホストのある実行(canUseTool を持つ SDK アプリや --permission-prompt-tool など)--permission-prompts none(2.1.259 以降)ホストを待ちません。Claude には、誰も承認できないこととリトライしないことが伝えられます

--permission-mode dontAsk --permission-prompts none での実測:python3 -c 'print(2+2)' は Permission to use Bash has been denied because Claude Code is running in don't ask mode で始まるメッセージで拒否され、git log --oneline -1 は組み込みの読み取り専用コマンド一覧にあるため実行されました。結果の JSON には permission_denials に 1 件のエントリがありました。

bypassPermissions であっても、どのモードもどの allow ルールも承認できないもの:明示的な ask ルール、AskUserQuestion ツール、requiresUserInteraction が付いた MCP ツール、rm -rf ~ のような認識済みのクリティカルパスに対する rm コマンド。dontAsk はこれらをすべて即座に拒否し、さらに allow ルールにマッチする場合でもネットワークパスからの読み取りを拒否します。

リポジトリを bypass モードで絶対に実行させたくない場合は、permissions の下に "disableBypassPermissionsMode": "disable" を追加してください。Claude Code は --dangerously-skip-permissions を拒否し、bypass を要求するサブエージェント定義を無視するようになります。

ステップ 4:settings.local.json に漏れた allow ルールを監査する

Apiiro のレポートの背後にある仕組みはこうです。Claude がシェルコマンドの実行許可を求めてきたときに「Yes, and don't ask again」を選ぶと、Claude Code はそのコマンドプレフィックスの allow ルールをリポジトリルートの .claude/settings.local.json に保存します。コマンドが psql postgres://app:Sup3rSecret@db/prod -c ... だった場合、パスワードはそのままルールの中に残ります。

Claude Code は、まだこのファイルを無視していないリポジトリで初めて書き込むとき、グローバルの git excludes ファイルに **/.claude/settings.local.json を追加します。私の Mac ではそのファイルは ~/.config/git/ignore で、パターンは 1 行目にあります。だからこの環境では git add .claude/settings.local.json が「ignored by one of your .gitignore files」で失敗します。しかしこの保護はマシン単位であって、リポジトリ単位ではありません。Claude Code が書き込む前に手で作ったファイル、clone ではなくディレクトリとして別マシンにコピーしたリポジトリ、グローバル excludes のないサンドボックスでは、このファイルは他のファイルと同じようにコミットされます。Apiiro の著者は HN で、追跡した 1,105 リポジトリのうち 539 件で、Claude が共著者のコミットがこのファイルを変更していたと述べています。

次をリポジトリルートから実行してください。すべての .claude/settings*.json を見つけ、git が追跡しているかを報告し、認証情報を含む allow ルールやツールファミリー全体を許可する allow ルールにフラグを立てます。

cat > /tmp/claude-settings-audit.sh <<'EOF'
#!/usr/bin/env bash
set -u
root="${1:-.}"
found=0
while IFS= read -r -d '' f; do
  found=1
  echo "== $f"
  if git -C "$(dirname "$f")" ls-files --error-unmatch "$(basename "$f")" >/dev/null 2>&1; then
    echo "   TRACKED BY GIT  <- settings.local.json should never be"
  fi
  grep -nE '"(Bash|PowerShell)\([^"]*(password|passwd|token|secret|api[_-]?key|Authorization|Bearer |PGPASSWORD|AWS_SECRET|--password|://[^"/]*:[^"@]*@|[A-Z_]{3,}=[^[:space:]"]{8,})' "$f" \
    | sed 's/^/   SECRET-LIKE: /'
  grep -nE '"(Bash|PowerShell)(\(\*\))?"|"Bash\((sudo|rm|curl|wget|ssh|scp|git push|npm publish|docker)[^"]*\*\)"' "$f" \
    | sed 's/^/   BROAD: /'
done < <(find "$root" -path '*/node_modules' -prune -o -type f \
  \( -name 'settings.local.json' -o -name 'settings.json' \) -path '*/.claude/*' -print0 2>/dev/null)
[ "$found" = 0 ] && echo "No .claude/settings*.json under $root"
EOF
bash /tmp/claude-settings-audit.sh .

6 つのルールを持つ合成ファイルで試すと、データベースのパスワード、bearer トークン、DATABASE_URL=... の代入を埋め込んだ 3 つと、Bash(*)、Bash(rm -rf *)、そして BROAD の下で 2 回目にフラグが付いた curl のルールが検出されました。テストリポジトリでこのファイルをコミットした状態では、TRACKED BY GIT の行も出力されました。中身は grep なので、ヒットした行は自分で読んで判断してください。

ヒットしたときの対処:

  1. まず認証情報をローテーションする。 ファイルが一度でも push されていたら、そのシークレットは公開済みとして扱ってください。フォークやスクレイパーに取られた後では、履歴の書き換えだけでは不十分です。
  2. ルールを削除するか、シークレットを含まないものに置き換える。 psql * を許可し、パスワードはコマンド内ではなくシェル環境の PGPASSWORD で渡します。
  3. git がファイルを追跡している場合。 git rm --cached .claude/settings.local.json を実行し、.claude/settings.local.json をリポジトリの .gitignore に追加します。これで保護が各マシンのグローバル excludes に依存せず、リポジトリとともに移動します。
  4. .claude/settings.json も確認する。 こちらはコミットされる前提のファイルなので、シークレットを含む allow ルールがあれば、それは事故ではなく設計上の漏洩です。

同じ理由から、コミットするファイルには deny と ask のルールを優先し、個人的な allow ルールはローカルに置いてください。deny と ask のルールは即座に適用されますが、リポジトリ由来の allow ルールは各チームメイトがそのフォルダを信頼してから初めて適用されます。

ステップ 5:IDE 拡張と SSH 鍵を確認する

バックドア入りのビルドは、Cursor Marketplace 経由で配布された Claude Code for VS Code 拡張のバージョン 2.1.312 と 2.1.313 で、10 月 30 日に Phorion が報告しました。Cursor は両方を削除しています。Phorion によれば、ペイロードは拡張モジュールの読み込み時点で実行され、コメント svc-telemetry の付いた Ed25519 鍵を ~/.ssh/authorized_keys に追記し、リモートログインを有効化しようとし、ホスト情報を外部に送信します。macOS では、インプラントのバグにより管理者権限のないユーザーでは SSH 有効化のステップが失敗しますが、鍵と永続化は残ります。

インストール済みバージョンを一覧します:

cursor --list-extensions --show-versions | grep -i claude
code --list-extensions --show-versions | grep -i claude
ls ~/.cursor/extensions ~/.vscode/extensions 2>/dev/null | grep -i claude

私のマシンでは anthropic.claude-code@2.1.302 が返り、影響範囲外でした。次に Phorion が公開した痕跡を確認します:

grep -n "svc-telemetry" ~/.ssh/authorized_keys 2>/dev/null || echo "no match"

Phorion はコメント文字列が攻撃者の制御下にあると注記しているので、grep にヒットしなくても安全の証明にはなりません。Cursor Marketplace から 2.1.312 または 2.1.313 を実行したことがあるなら、authorized_keys から見覚えのない鍵をすべて削除し、ログイン項目と launch agent を見直し、インシデントレスポンスで確認が済むまでそのマシンは侵害済みとして扱ってください。拡張は VS Code Marketplace からインストールするか、claude CLI の /ide に任せてください。2.1.318 以降、Claude Code は IDE ターミナル内から自動で拡張をインストール・更新しなくなりました。

ステップ 6:User-Agent にメールアドレスが入る問題の修正

Issue #107757 は、Claude Code が検索や取得で発行する Web リクエストの User-Agent ヘッダーにアカウントのメールアドレスを入れて送信していたため、サイトやトラッカーがそれを収集できた、という報告です。11 月 3 日付の 2.1.317 の変更履歴には「Added a check that asks before a web or shell tool call sends your account email address to the network.」とあります。報告者は 2.1.318 で issue を提出しており、11 月 8 日時点で約 1,000 件のリアクションのままオープンなので、最終的な解決は issue を追ってください。

今日できること:更新する(claude update)こと。そして無人実行をしているなら、denyInsteadOfPrompting または dontAsk の下では、この新しい「送信前に確認する」チェックが拒否になることを知っておいてください。それが望ましい挙動です。

各ガードが止めるもの:実測 vs ドキュメント

試行blockWrites…Read の deny ルールBash(curl *) の denydontAsk / -p デフォルトサンドボックス
Write ツールで ~/x.txt を作成拒否(実測)——プロンプト → 拒否サンドボックスは許可。ファイルツールは対象外
Read ツールで .env を読む—拒否(実測)—許可。読み取りに承認は不要—
Bash で cat .env—拒否(実測)—拒否—
Bash で echo x > ~/x.txt対象外——プロンプト → 拒否ブロック(ドキュメント:macOS では Operation not permitted)
Bash で curl https://…——拒否(実測)拒否ホストが許可されていなければブロック
Bash で python3 -c …———拒否(実測)サンドボックス内で実行
git log、ls などの読み取り専用コマンド———実行される(実測)実行される
rm -rf ~———拒否。どのルールでも承認不可ブロック。ホームは書き込み可能セット外(ドキュメント)

「実測」とは、2026 年 11 月 8 日に 2.1.319 で私が実行したことを意味します。それ以外はすべて、このガイドでリンクしている公式ドキュメントに基づきます。

オプション:シェルもサンドボックス化する

上の設定は Claude 自身のファイルツールを囲い込むものです。シェルコマンドを囲い込むのは Bash サンドボックス (opens in a new tab)で、デフォルトではオフです。macOS の Seatbelt を使い、Linux や WSL2 では bubblewrap と socat が必要です。1 つのプロジェクトで有効にするにはセッション内で /sandbox を実行し、すべてのプロジェクトで有効にするには ~/.claude/settings.json に次を追加します:

{
  "sandbox": {
    "enabled": true
  }
}

動作確認には、Claude に touch ~/sandbox-probe を実行させてください。サンドボックス内では macOS で Operation not permitted、Linux で Read-only file system となって失敗します。Claude がサンドボックス外でのリトライを提案してきたら断ってください。

上の対応表の空白を埋めるのが、この組み合わせです:ファイルツールは blockWritesOutsideWorkingDirectories、シェルはサンドボックス、シークレットは Read の deny ルール、無人実行は denyInsteadOfPrompting で囲い込みます。こうすれば bypass モードは、残ったプロンプトを省くだけの存在になります。限定されたタスクでどうしても bypass が必要なら、bypass permissions ガイドでトグルとエラーメッセージを解説しています。

FAQ

関連ガイド