Claude Code 権限チェックリスト: settings.jsonの点検22項目
Claude Codeのallow/deny、危険な許可、Hooks、シークレット露出、sandboxまで、settings.jsonで点検すべき項目をチェックリスト化。コピペ監査スクリプト付き。
先週、後輩のリポジトリのsettings.jsonを覗いて、思わず「うわ」と声が出ました。allowの中にBashがぽつんと一行。これ、全Bashコマンドを確認なしで通す設定です。本人は「npm testを毎回聞かれるのが面倒で、ダイアログで雑にYes押してたら入ってた」と。
そういうものなんですよね。権限の穴は、悪意じゃなくて面倒くささから空く。そして一度空いた穴は、誰も見直さないと半年残る。
だから僕は、設定を「ちゃんと作る」よりも「定期的に点検する」ほうに振りました。この記事は、その点検で僕が実際にチェックしている項目を、上から順に潰せるチェックリストにしたものです。allow/denyの中身、危険な許可、Hooks、シークレットの露出、sandbox。1枚ずつ見ていきます。
この記事の要点
- Claude Codeの権限は4つの設定ファイルに分散する。点検は「どのファイルに何が書いてあるか」を
/permissionsで出すところから始める。 - 最優先で探すのは
allowの中の素のBash/Edit/Write/WebFetch。これらは境界をほぼ消すので、見つけたら即降格。 denyに.env系・curl/wget・rm -rfが入っているか、askにgit push・npm install・課金/デプロイ系があるかを確認する。- ファイルやネットワークを本当に止めたいなら権限ルールだけでは足りない。OSレベルで効くのはsandbox、ランタイムで止めるのはHooks。
- 下に置いた監査スクリプトを
nodeで走らせれば、3つの設定ファイルの危険パターンを一覧化できる。目視の抜けを埋める用です。
なぜ「作る」より「点検する」のか
settings.jsonを一度きれいに書いても、運用すると必ず汚れます。デバッグ中に「今だけ」と足したBash(npx *)、ダイアログで勢いYesしたBash(git push *)、調査用に開けたRead(./logs/**)。こういう一時許可は、.claude/settings.local.jsonに静かに溜まっていきます。
公式ドキュメントもはっきり書いています。権限を強制するのはモデルではなくClaude Code本体で、プロンプトやCLAUDE.mdに「やらないで」と書いても境界にはならない、と。境界になるのは権限ルール、権限モード、Hook、sandboxの4つだけ。つまり点検対象は、この4つが今どうなっているかです。
用語を最初に整理しておきます。専門用語は最初だけ平易に言い換えます。
- allow = 確認なしで実行してよい操作。
- ask = 毎回ダイアログで確認する操作。
- deny = そもそも実行させない操作。
- harness(ハーネス) = エージェントの足場。本体・設定・Hook・sandbox・ログ方針をまとめた「AIが安全に動く土台」のこと。
評価の順番はdeny -> ask -> allowで、最初に一致したルールが勝ちます。だからdenyがいちばん強い。点検でもdenyから見るのが効率的です。
権限を「いつ」点検するか(朝イチ/デプロイ前/引き継ぎ時)は Claude Code デプロイ前の権限監査チェックリスト に、allow/deny/askのパターン構文や評価順の網羅リファレンスは Claude Code 権限設定リファレンス にまとめてあります。この記事は「何を点検するか」に絞ります。
点検その1: どのファイルを見るか確定する
権限は1か所にありません。優先度の高い順に4つ(+管理者用)です。下の表をそのまま「開くべきファイル」の地図に使ってください。
| 設定ファイル | 役割 | 点検でまず疑うこと |
|---|---|---|
| 管理設定(managed) | 組織が配布、上書き不可 | 個人では触れない。あれば前提として把握 |
.claude/settings.local.json | 自分だけの一時許可(gitに入れない) | 昨日の調査用ルールの残骸 |
.claude/settings.json | チーム共有 | 本番操作や課金リンクがallowに紛れていないか |
~/.claude/settings.json | 自分の全プロジェクト共通 | どのリポジトリでも効く広すぎるallow |
優先度は managed > コマンドライン引数 > local > project共有 > user の順。重要なのは「denyはどの階層からでも最強」という性質です。ユーザー設定でdenyしたものを、プロジェクト設定のallowでは覆せません。逆も同じ。だから安全側に倒したいルールは、いちばん広い~/.claude/settings.jsonのdenyに置くのが効きます。
まずやることは1つ。Claude Codeで/permissionsを開きます。これは全ルールと、それがどのファイル由来かを一覧表示するUIです。「このルール、誰が入れたんだっけ」が一目でわかります。点検はここがスタート地点です。
点検その2: allowの中の「危険な許可」を狩る
ここがいちばん事故率が高い。allowを上から見て、次のパターンがあったら赤信号です。重い順に並べます。
| 危険な許可 | なぜまずいか | どう直すか |
|---|---|---|
Bash(素・括弧なし) | 全Bashが無確認。denyだとツール自体が消える特殊挙動 | 具体コマンドへ分解(Bash(npm run test *)等) |
Edit / Write(素) | 全ファイル編集が無確認 | 範囲を切る(Edit(/src/**)) |
WebFetch(素) | 任意ドメインへ取得 | WebFetch(domain:example.com)に限定 |
Bash(curl *) / Bash(wget *) | 任意URLへ通信。データ持ち出し経路 | denyへ。取得はWebFetchで |
Bash(rm -rf *) 系 | 破壊的削除 | denyへ |
Bash(git push *) / npm install * | リモート更新・依存変更 | askへ降格 |
素のBashの挙動は知っておくと点検が速くなります。allowに素のBashがあると全コマンドが無確認。一方でdenyに素のBashを書くと、BashツールそのものがClaudeの文脈から消えます(ツールが見えなくなる)。範囲を絞ったBash(rm -rf *)はツールを残したまま該当コマンドだけ止める。この差を踏まえると、「Bashは残したいが特定コマンドだけ止めたい」なら必ず括弧付きで書く、が結論です。
もう1つ、2026年6月時点で点検に効く新しめの仕様。allowに素のBashを入れたうえで、危険なコマンドだけPreToolUseフックで弾く設計が公式に認められています。「ほぼ全部通すが数個だけ止める」運用はこの形が正攻法です。逆に言うと、素のBashを見つけても「Hookとセットなら意図的かもしれない」ので、Hookの有無まで確認してから判断します。
ワイルドカードの落とし穴も同時に見る
Bash(git push *)の*はワイルドカードです。点検時に見落としやすいのが、*の前のスペース。Bash(ls *)はls -laに一致しますがlsofには一致しません(スペースが単語境界を作る)。Bash(ls*)はスペースなしなので両方に一致してしまう。意図せず広いほうになっていないか確認します。
末尾の:*はトレイリングワイルドカードとしてBash(ls *)と同じ意味になりますが、これは末尾でだけ有効。Bash(git:* push)のように途中に置くとコロンはただの文字扱いになり、git系に一致しません。チームで読む設定はスペース付き(Bash(git push *))にそろえると誤読が減ります。
点検その3: denyに最低限の堤防があるか
denyは「最初に勝つ」最強ルールなので、ここに堤防が無いと他がどれだけ整っていても抜けます。次が入っているか確認します。コピペでそのままdenyに足せます。
{
"permissions": {
"deny": [
"Read(./.env)",
"Read(./.env.*)",
"Read(./secrets/**)",
"Bash(curl *)",
"Bash(wget *)",
"Bash(rm -rf *)"
]
}
}
ただしRead/Editのdenyを過信しないこと。これはClaude Code組み込みのファイルツールと、Claudeが認識できるBashの読み取り(cat/head/tail/sedなど)には効きますが、任意のNodeやPythonスクリプトが内部でファイルを開くケースまでは止めません。.envを本当に隔離したいなら、後述のsandboxを併用します。
Windowsの人は書き方に注意。パスはマッチ前にPOSIX形式へ正規化されるので、C:\Users\aliceは/c/Users/aliceになります。ドライブ全体の.envを止めたいならRead(//c/**/.env)、全ドライブならRead(//**/.env)です。普通のRead(.env)はgitignore準拠で「カレント以下のどの深さの.env」に一致するので、リポジトリ内ならこれで十分機能します。
URLをBashパターンで縛るのは諦めるのが点検の鉄則です。Bash(curl https://github.com *)のようなルールは、オプション前置き(curl -X GET ...)、プロトコル違い(https)、リダイレクト(-Lで短縮URL経由)、変数展開(URL=... && curl $URL)、余分なスペースで全部抜けます。だから「curl/wgetはdeny、必要な取得はWebFetch(domain:...)かHook」が公式の推奨です。
点検その4: Hooks・モード・環境変数を見る
allow/ask/denyの3配列だけ見て終わる人が多いですが、点検の差はここから出ます。
権限モード(defaultMode)。 セッション開始時の既定の振る舞いです。bypassPermissionsになっていたら全プロンプトをスキップする設定なので即赤信号(rm -rf /等の破壊操作だけはサーキットブレーカーで止まりますが)。組織で固めるならdisableBypassPermissionsModeとdisableAutoModeを"disable"に。acceptEditsは編集とmkdir/mv等を自動受諾、planは読み取り専用探索、dontAskは未承認ツールを自動拒否。リポジトリの性質に合っているか確認します。
Hooks。 PreToolUseフックは、権限ダイアログの前に走る自前のシェルコマンドです。点検では「Hookが何を許可・拒否しているか」を必ず読む。ここで重要な事実が2つ。
- Hookの判定は権限ルールを上書きしない。
denyとaskはHookが"allow"を返しても評価される。deny-first は崩れません。 - ただし終了コード2で止まるHookはallowルールより先に効く。だから「素の
Bashをallowにして、危険コマンドだけHookで弾く」が成立します。
Hookの具体的な書き方や、禁止コマンド防止・ログ保存・format/test自動実行の型は Claude Code Hooks入門 にまとめています。点検で「Hookで止めるべきでは」と思ったらここを参照してください。
環境変数(env)。 ログとサブプロセスの扱いに直結します。
| 環境変数 | 値 | 点検ポイント |
|---|---|---|
CLAUDE_CODE_SKIP_PROMPT_HISTORY | 1 | プロンプト履歴・トランスクリプトを書かない。機密一時セッションには有用だが、チーム監査で判断理由を追いたいなら逆効果 |
CLAUDE_CODE_SUBPROCESS_ENV_SCRUB | 1 | サブプロセスへ渡す環境変数から資格情報を除去。シークレットを子プロセスに漏らさないために有効化したい |
点検その5: sandboxで「OSレベルの線」を引いているか
権限ルールはClaude Codeの判断レイヤーの話で、プロンプトインジェクションで判断ごと乗っ取られると抜けます。これを最後に止めるのがsandbox(OSレベルでBashのファイル・ネットワークアクセスを制限する仕組み)です。点検では「機密リポジトリなのにsandboxが無い」を探します。
押さえる挙動は2つ。
- sandboxのファイル制限は
sandbox.filesystemの設定とRead/Editのdenyをマージして最終境界を作る。ネットワークもWebFetchルールとsandboxのallowedDomains/deniedDomainsをマージする。つまり権限ルールとsandboxは足し算で効く。 autoAllowBashIfSandboxedがtrue(既定)だと、sandbox内のBashはask: Bash(*)があってもプロンプトなしで走る。sandbox境界がプロンプトの代わりになる、という考え方です。これを知らないと「askにしたのに聞かれない」で混乱します。
承認とsandboxの線引き、plan/acceptEdits/auto/bypassPermissionsの使い分けは Claude Code 承認とsandboxの運用術 に実務目線でまとめてあります。
コピペで使える: 22項目セルフ監査スクリプト
目視だけだと、素のBashの自動許可や昨日入れたBash(npx *)を見落とします。次のスクリプトをscripts/audit-claude-permissions.mjsとして保存し、リポジトリ直下でnode実行してください。ユーザー設定・共有設定・ローカル設定の3つを読み、危険パターンを表にします。コメントは全部日本語です。
#!/usr/bin/env node
// Claude Code 権限セルフ監査: 3つの settings.json を点検し危険パターンを表示する
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
const repo = process.cwd();
// 点検対象(存在するものだけ読む)
const settingsFiles = [
path.join(os.homedir(), ".claude", "settings.json"), // ユーザー全体
path.join(repo, ".claude", "settings.json"), // チーム共有
path.join(repo, ".claude", "settings.local.json"), // 個人の一時許可
].filter((file) => fs.existsSync(file));
// allow に入っていたら危険な許可パターン
const riskyAllow = [
{ re: /^Bash$/i, sev: "high", why: "全Bashコマンドが無確認" },
{ re: /^PowerShell$/i, sev: "high", why: "全PowerShellコマンドが無確認" },
{ re: /^(Edit|Write)$/i, sev: "high", why: "全ファイル編集が無確認" },
{ re: /^WebFetch$/i, sev: "medium", why: "任意ドメインへの取得が無確認" },
{ re: /^Bash\((curl|wget|nc|ncat|ssh|scp|rsync)\b.*\)$/i, sev: "high", why: "通信・転送コマンドが無確認" },
{ re: /^Bash\(.*\b(rm\s+-[^\)]*r|git\s+push|npm\s+install|pnpm\s+add|yarn\s+add|npx|docker\s+exec|terraform\s+apply|kubectl\s+apply)\b.*\)$/i, sev: "high", why: "破壊的・環境変更コマンドが無確認" },
{ re: /^PowerShell\(.*\b(Remove-Item|Invoke-WebRequest|Invoke-RestMethod|Start-Process)\b.*\)$/i, sev: "high", why: "危険なPowerShellが無確認" },
];
// deny に入っていてほしい最低限の堤防
const expectedDeny = [
"Read(./.env)", "Read(./.env.*)", "Read(./secrets/**)",
"Bash(curl *)", "Bash(wget *)",
];
const findings = [];
const add = (file, sev, rule, why) =>
findings.push({ file: path.relative(repo, file) || file, severity: sev, rule, reason: why });
const readJson = (file) => {
try { return JSON.parse(fs.readFileSync(file, "utf8")); }
catch (e) { add(file, "high", "JSON", `設定を解析できません: ${e.message}`); return null; }
};
for (const file of settingsFiles) {
const s = readJson(file);
if (!s) continue;
const p = s.permissions ?? {};
const allow = Array.isArray(p.allow) ? p.allow : [];
const ask = Array.isArray(p.ask) ? p.ask : [];
const deny = Array.isArray(p.deny) ? p.deny : [];
// モードの点検
if (p.defaultMode === "bypassPermissions") add(file, "high", "defaultMode", "起動時から全許可スキップ");
if (p.disableBypassPermissionsMode !== "disable") add(file, "medium", "disableBypassPermissionsMode", "bypassモードが無効化されていない");
// 環境変数の点検
if (s.env?.CLAUDE_CODE_SKIP_PROMPT_HISTORY === "1") add(file, "low", "SKIP_PROMPT_HISTORY", "履歴・記録が残らない(監査で追えない)");
if (s.env?.CLAUDE_CODE_SUBPROCESS_ENV_SCRUB !== "1") add(file, "low", "SUBPROCESS_ENV_SCRUB", "子プロセスへの資格情報除去が無効");
// allow の危険許可
for (const rule of allow)
for (const r of riskyAllow)
if (r.re.test(rule)) add(file, r.sev, rule, r.why);
// deny の堤防チェック
for (const need of expectedDeny)
if (!deny.includes(need)) add(file, "low", need, "このdenyルールの追加を検討");
// ask が空=判断ゲートが無い
if (ask.length === 0) add(file, "low", "ask", "askルールが1つも無い");
// :* を途中に置くと壊れる
for (const rule of [...allow, ...ask, ...deny])
if (/:\*[^)]/.test(rule)) add(file, "medium", rule, ":* は末尾でのみワイルドカードとして機能する");
}
if (settingsFiles.length === 0) {
console.log("ユーザー・リポジトリ範囲に settings.json が見つかりません。");
} else if (findings.length === 0) {
console.log("危険な権限パターンは見つかりませんでした。");
} else {
console.table(findings);
}
// high が1つでもあれば終了コード1(CIで落とせる)
if (findings.some((f) => f.severity === "high")) process.exitCode = 1;
PowerShellからはこう実行します。
New-Item -ItemType Directory -Force -Path .\scripts | Out-Null
node .\scripts\audit-claude-permissions.mjs
このスクリプトは完璧な判定器ではありません。目的はレビューの入口を作ること。Bash(curl *)をdenyにしていても、許可した別のBashやNodeスクリプトから通信される余地は残ります。OSレベルで止めたいものはsandbox、ランタイムで止めたいものはHook、と役割分担で考えてください。
点検結果を1枚に残すテンプレート
点検は長いセキュリティ文書にすると続きません。PR本文や引き継ぎメモに、次のブロックを貼るだけで十分です。allowed_todayがキモで、永久リストではなく「今日の作業に必要な範囲だけ」を書きます。
claude_code_permission_audit:
date: "2026-06-07"
repository:
name: "your-repo"
branch: "feature/your-task"
dirty_before_start: "yes/no"
allowed_today:
- "プロジェクトファイルの読み取り"
- "MDX とテストファイルの編集"
- "npm run lint の実行"
ask_before:
- "依存パッケージの追加・更新"
- "認証・課金・分析・デプロイ設定の変更"
- "push / リリース作成"
never_allow:
- ".env / トークン / Cookie / 秘密鍵の表示"
- "任意URLへの curl/wget"
- "git履歴の削除・force push"
proof_required:
- "git diff を確認した"
- "test または build の実行結果を記録した"
- "rollback 手順を書いた"
よくある質問
Q. CLAUDE.mdに「rm -rfは使わないで」と書けば防げますか?
いいえ。公式が明記している通り、プロンプトやCLAUDE.mdは「Claudeが何を試みるか」を形づくるだけで、Claude Codeが何を許すかは変えません。境界にしたいならdenyルール、権限モード、PreToolUseフック、sandboxのどれかを使ってください。
Q. allowに素のBashがあったら必ずダメ?
原則ダメですが、例外があります。素のBashをallowにしたうえで、危険コマンドだけ終了コード2のPreToolUseフックで弾く設計は公式に認められた正攻法です。だから素のBashを見つけたら「Hookとセットか」をまず確認します。Hookが無ければ降格、あれば意図を確認、です。
Q. Bash(devbox run *)を許可すると何が起きますか?
その先で実行されるコマンドまで広く許す形になります。devbox run・mise exec・npx・docker execなどの開発環境ランナーはラッパー解析の対象外なので、Bash(devbox run rm -rf .)まで通り得ます。許可するならBash(devbox run npm test)のように内側のコマンドまで指定し、1コマンド1ルールで書きます(timeout・time・nice・nohup・stdbuf、フラグ無しxargsは解析されます)。
Q. Read(./.env)をdenyにすれば.envは安全ですか?
組み込みのファイルツールと、Claudeが認識できるcat/head/sed等のBash読み取りには効きます。ただし任意のNode/Pythonスクリプトが内部で.envを開くケースは止まりません。完全に隔離したいならsandboxでOSレベルの制限を併用してください。
Q. 点検はどのくらいの頻度でやればいい?
最低でも本番リポジトリを開いた朝イチと、デプロイ直前の2回。タイミングごとの具体手順は デプロイ前の権限監査チェックリスト にまとめています。/permissionsを開く30秒だけでも、settings.local.jsonの残骸はだいたい見つかります。
実際に試した結果
このチェックリストを自分のリポジトリ3つに当てて、いちばん刺さったのは点検その2の「素のBash狩り」でした。冒頭の後輩のケースに限らず、自分のlocal設定にも調査用のBash(npx *)が残っていて、監査スクリプトが赤(high)で拾ってくれた。これをCIにnode scripts/audit-claude-permissions.mjsとして組み込んでから、highがあるとPRが落ちるので「面倒だから雑にYes」が物理的にできなくなりました。
意外と効いたのが環境変数の点検です。CLAUDE_CODE_SUBPROCESS_ENV_SCRUBを1にするだけで、子プロセスにAPIキーが渡らなくなる。設定を知らなければ一生空いていた穴でした。点検の価値は「すごい設定を書くこと」じゃなくて、「空いている穴に気づくこと」なんだと改めて思います。設定の網羅的な書き方は 権限設定リファレンス を、いつ点検するかは デプロイ前チェックリスト を見てください。チーム導入や運用設計まで一緒に詰めたいときは 導入相談 へどうぞ。
無料PDF: Claude Code はじめてのチートシート
まずは無料PDFで基本コマンドと最初の使い方をまとめて確認してください。登録後はそのままテンプレート集や導入相談にも進めます。
スパムは送りません。登録情報は厳重に管理します。
Claude Codeを仕事で使える形にしませんか?
まず無料PDFで基本を固め、繰り返し使う作業はGumroad教材へ、チーム導入や権限設計は導入相談へ進めます。
この記事を書いた人
Masa
Claude Codeの実務活用、導入設計、収益導線改善を検証しているエンジニア。10言語の技術メディアを運営中。
関連書籍・参考図書
この記事のテーマに関連する書籍を楽天ブックスで探せます。
※ 当サイトは楽天市場のアフィリエイトプログラムに参加しています。上記リンクから商品をご購入いただくと、運営者に紹介料が支払われる場合があります。
関連記事
Claude Codeのコマンドを覚えたのに手が止まる人へ、最初の一手を安全に出す型
コマンド表を覚えたのに何を頼めばいいか分からない。読むだけで終わらず、初めての一手を安全に通すまでの手順とプロンプト雛形を紹介します。
Claude Codeで既存リポジトリの最初の1編集を安全にする導入手順
他人が書いた既存コードにClaude Codeを入れる初日に、触らせる範囲・禁止領域・検証コマンドを先に決めて事故を防ぐ実践手順。
Claude Codeに最初の1タスクを任せる依頼文の書き方
Claude Codeへの最初の依頼で事故らないために、目的・触ってよい範囲・検証・戻し方を1枚にまとめる依頼文の型を、コピペ例つきで紹介します。