Claude Codeの権限設定、なんもわからん
Claude Codeで「毎回Askされるのをなんとかしたい」と思って設定ファイルをいじり始めたら、沼にハマった話。
結論: 公式が「バイパスされうる」「tricky」と言ってる時点で、完璧な制御は諦めた方がいい。
やりたかったこと
- プロジェクト内のファイル読み込みでAskされるのを止めたい
- Dockerにコマンド打つときに毎回Askが入るのを止めたい
- ただし本番環境へのアクセスは防ぎたい
最初に試したこと
.claude/settings.json に許可ルールを書く方法:
{
"permissions": {
"allow": [
"Read(*)",
"Bash(docker *)",
"Bash(docker-compose *)"
]
}
}
これで行けるはずだった。
地獄の始まり
しばらく作業していると、settings.local.json が勝手に肥大化していた:
{
"permissions": {
"allow": [
"Bash(echo:*)",
"Bash(npx playwright install chromium)",
"Bash(curl:*)",
"Bash(TOKEN=\"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...\")",
"Bash(npx playwright test:*)",
"Bash(node test-login.js:*)",
"Bash(npm install:*)",
"Bash(docker exec:*)",
"Bash(docker-compose down:*)",
"Bash(__NEW_LINE__ echo \"=== POST /reports ===\")",
"Bash(__NEW_LINE__ echo -e \"\\n\\n=== POST /messages ===\")"
]
}
}
何がまずいのか
- JWTトークンがそのまま記録されている(期限切れとはいえパターンとしてよくない)
- フルパスが入っている(
c:\Users\username\...) - エコー文やワンライナーがそのまま(意味のない許可が大量に)
__NEW_LINE__という内部表現がそのまま記録されている
パターンマッチの謎
Bash(npm *) を設定しているのに、なぜか Bash(npm run build:*) が追加される。
試したこと
スペースの有無で挙動が変わる?
// 記事で見た書き方
"Bash(npm install*)"
// 自分の書き方
"Bash(npm install *)"
両方の形式を書いてみる
"Bash(npx *)",
"Bash(npx:*)"
それでもダメ。
__NEW_LINE__ 対策
複数行コマンドの内部表現がそのまま記録されるので:
"Bash(__NEW_LINE__*)"
これを追加してみたが…
結局どうなったか
いろいろ追加した結果:
{
"permissions": {
"allow": [
"Read(*)",
"Write(*)",
"Bash(docker *)",
"Bash(docker-compose *)",
"Bash(docker compose *)",
"Bash(git *)",
"Bash(npm *)",
"Bash(npx *)",
"Bash(node *)",
"Bash(php *)",
"Bash(composer *)",
"Bash(cat *)",
"Bash(ls *)",
"Bash(dir *)",
"Bash(find *)",
"Bash(grep *)",
"Bash(tar *)",
"Bash(powershell *)",
"Bash(powershell.exe *)",
"Bash(npx playwright test:*)",
"Bash(npm run build:*)",
"Bash(tar:*)",
"Bash(docker exec:*)"
],
"deny": [
"Bash(*https://example.com*)",
"Bash(*http://example.com*)",
"Bash(*curl*example.com*)",
"Bash(*scp*)",
"Bash(*ssh*example.com*)",
"Bash(*rsync*)"
]
}
}
「ほぼ止まらない」状態にはなった。
でもその後も増え続ける:
"Bash(__NEW_LINE__ echo \"*\")",
"Bash(__NEW_LINE__ echo \"=== * ===\")",
"Bash(__NEW_LINE__ echo \"\")",
"Bash(docker cp:*)",
"Bash(docker-compose restart:*)",
"Bash(__NEW_LINE__ echo \"=== Some API ===\")"
Redditを見てみた
みんな同じ苦労をしていた。
公式ドキュメントを確認
設定ファイルの優先順位
公式ドキュメントによると、設定ファイルには階層がある:
~/.claude/settings.json- ユーザーレベル(全プロジェクト共通).claude/settings.json- プロジェクト設定(チーム共有、git管理対象).claude/settings.local.json- 個人用オーバーライド(gitignore対象)- Managed settings(Enterprise)- 最優先
settings.local.json が肥大化していたのは、Askで「Allow always」を選ぶたびにここに追記されていたから。
公式の例
{
"permissions": {
"allow": [
"Bash(npm run lint)",
"Bash(npm run test:*)",
"Read(~/.zshrc)"
],
"deny": [
"Bash(curl:*)",
"Read(./.env)",
"Read(./.env.*)",
"Read(./secrets/**)"
]
}
}
そして重要な注記:
Bash rules use prefix matching, not regex
Bash patterns are prefix matches and can be bypassed
FAQにも:
Wildcard syntax can be tricky - test permissions thoroughly.
公式が「バイパスされうる」「tricky」と認めている。
現実的な選択肢
1. 全許可してdenyで守る
{
"permissions": {
"allow": [
"Read(*)",
"Write(*)",
"Bash(*)"
],
"deny": [
"Bash(*本番ドメイン*)",
"Bash(*scp *)",
"Bash(*rsync *)"
]
}
}
ただし deny もバイパスされる可能性がある。
2. --dangerously-skip-permissions で起動
claude --dangerously-skip-permissions
全ての確認をスキップ。名前が怖すぎて使う気になれないが、ローカル開発なら現実的らしい。
3. 自動追加を止める
claude config set --global autoAddPermissions false
勝手に追加されなくなる。Askされたら毎回「Allow once」で対応。
4. ネットワークレベルで制限
Claude Code側ではなく、hostsファイルやファイアウォール、Dockerのネットワーク設定で本番アクセスを防ぐ。これが一番確実。
5. sandbox機能を使う
claude --sandbox で起動すると、OSレベル(Linux bubblewrap / macOS seatbelt)でファイルシステム・ネットワークを制限できる。
{
"sandbox": {
"enabled": true,
"excludedCommands": ["docker"],
"network": {
"allowUnixSockets": ["~/.ssh/agent-socket"]
}
}
}
許可するファイルパスやドメインを事前に定義しておく方式。権限設定のパターンマッチより確実。
まとめ
Claude Codeの権限設定は:
- パターンマッチの仕様が不透明
- 内部表現(
__NEW_LINE__等)がそのまま記録される - ワイルドカードの挙動が不安定
allowに書いても Ask される場合がある- 公式が「バイパスされうる」と認めている
設定ファイルでの完璧な制御は諦めて、--dangerously-skip-permissions か、ネットワークレベルでの制限、または --sandbox を併用するのが現実的。
感想
なんもわからん、とりあえず言うこと聞いてくれない……