この記事は playpark Blog からの転載です。
この記事で分かること
-
permissions.denyを思いついた順に書くとなぜ破綻するのか - 4つのリスクカテゴリで整理する理由と、段階的にルールを積み上げるフェーズ分けの考え方
- どういう場面でカテゴリ整理・フェーズ分けを採用すべきか
背景: こういう課題があった
Claude Codeのsettings.jsonを新規に触るとき、permissions.denyはたいてい空だ。危なそうなコマンドに気づいた順に1行ずつ足していくのが最初の自然なやり方だが、これを続けると「このルールは何のために書いたんだっけ」という行がどんどん増えていく。レビューで指摘されても理由を説明できず、結局消すに消せないまま放置される——というのが、思いつき順で書き足したdenyルールの典型的な末路だった。
選択肢の検討
denyルールをどう組み立てるか、いくつかのやり方を比較した。
| アプローチ | メリット | デメリット |
|---|---|---|
| 思いついた順に足す | 着手が速い | 理由が説明できない行が増える、抜け漏れに気づきにくい |
| 全カテゴリを一気に網羅する | 完成すれば漏れがない | 「これも危ない気がする」で手が止まり、Phase 1にすら着手できない |
| リスクカテゴリ別×段階的に積む(採用) | 迷ったときに「どの棚に入るか」で判断できる、着手障壁が低い | 最初は一部のリスクしかカバーできない期間が生まれる |
なぜこのアプローチを選んだか
リスクを「破壊的操作」「秘匿情報アクセス」「ネットワークアクセス」「システム設定変更」の4カテゴリに先に分けておくと、新しいdenyパターンを思いついたときに「これはどの棚に入るか」で迷わなくなる。さらに、この4カテゴリを一度に全部埋めようとすると着手障壁が上がるため、リスクの大きい順(破壊的操作→秘匿情報→ネットワーク→システム設定)にフェーズを分けて進める設計にした。「空のdenyが怖い」状態は最初から埋めきる必要はなく、可逆性が最低・被害が最大のカテゴリから順に塞げば、途中の状態でも十分に意味がある。
実装例
{
"permissions": {
"deny": [
// 破壊的操作: 取り返しがつかない(Phase 1)
"Bash(rm -rf:*)",
"Bash(git push --force:*)",
"Bash(git push *:main)",
// 秘匿情報アクセス: 漏洩は不可逆(Phase 2)
"Read(./.env)",
"Read(./.ssh/**)",
"Bash(security find-generic-password:*)",
// ネットワークアクセス: 経路をallowlistに寄せる(Phase 3)
"Bash(curl:*)",
"Bash(wget:*)",
"Bash(ssh:*)",
// システム設定変更: 開発作業では基本不要(Phase 4)
"Bash(defaults write:*)",
"Bash(networksetup:*)",
"Bash(csrutil:*)"
]
}
}
ネットワークアクセスは「denyで塞ぐ」だけでなく、sandbox.network.allowedDomainsのような許可ドメインのallowlistを併用すると、コマンドの種類に関わらず経路そのものを構造的に絞れる。denyとallowlistは、同じリスクに対する2枚のフィルターとして考えている。
まとめ: どういう場面で使うべきか
permissions.denyをこれから書き始める、あるいは数行しかまだ書けていない段階なら、思いついた順に足すのではなく、先にリスクカテゴリを4つ切っておくことをすすめる。全部を一気に埋めようとすると手が止まりやすいので、破壊的操作から順にフェーズを分けて進めるほうが、結果的に早く実用段階に到達できる。
さらに深掘りしたい方へ
この記事ではpermissions.denyをカテゴリ整理・フェーズ分けする理由(Why)を解説しました。
Claude Code の permissions、何から書き始めるか迷ったら読むリスクカテゴリ別ガイド ではさらに:
- allow・deny・askを可逆性・影響範囲・頻度の3軸で振り分ける決定木と、実際に踏んだ誤検知事例
- ワイルドカードパターンの3つの落とし穴(前方一致バイパス・広すぎる部分一致・可変長引数の列挙漏れ)と、それぞれの具体的な対処法
- 新しいdenyルールが実際に効いているかを確認する検証手順
を扱っています。
playpark について
playpark LLC - 業務自動化・AI活用・Web開発