permissions.denyで.envやsecretsフォルダを読み取り禁止にする書き方
Claude Codeに.envや認証情報を読ませないようにするには、settings.jsonのpermissions.deny配列にReadルールを追加するだけで済む。「Read(./.env)」と指定すれば、そのファイルへの読み取りはdeny→ask→allowの順で評価され、最初に一致したdenyでブロックされる。あとはどのファイルに書き、パターンをどこまで細かくするかという実装上の判断が残るだけだ。
settings.jsonとsettings.local.jsonどちらに書くべきか
チームで共有すべきセキュリティ方針はバージョン管理にコミットするsettings.jsonに、個人的な一時調整やマシン固有の設定はsettings.local.jsonに書く。注意したいのは、denyルールが「上書き」ではなく「スコープ全体でマージ」される点だ。両方のファイルにdenyを書いている場合、片方から削除しても無効化されるわけではなく、集められたルールがそのまま合算されて効き続ける。組織として絶対に外させたくないルールは、managed設定に置くのが最も強い手段になる。
Read(./.env)・Read(./.env.*)・Read(./secrets/**)—パターンの書き分け方
「Read(./.env)」だけでは.envという1ファイルしか止まらない。.env.productionや.env.localのように本番用ファイルを分けている構成では、これらは素通りしてしまう。実運用では「Read(./.env.*)」を必ず併記し、.envから始まる派生ファイルを一括で塞ぐ必要がある。フォルダ単位で守るなら、公式の設定例にも挙げられている「Read(./secrets/**)」のように書き、secretsディレクトリ配下をまとめて対象にするとよい。サブフォルダに置いた鍵ファイルまで確実にカバーできているかは、パターンを適用したうえで実際の構成で確認しておくと安全だ。
denyルールだけでは防げない—Bashコマンド経由で機密ファイルが読まれてしまう抜け穴
Read(./.env)で塞げるのはReadツール経由のアクセスだ。Claude Codeはls、cat、head、tail、grep、findなどを読み取り専用コマンドとして組み込みで認識しており、これらはすべてのモードで権限プロンプトなしに実行される。denyルールはツールごとに評価されるため、Readツールへのdenyを設定しても、Claudeが「cat .env」をBashで実行するケースまで同じdenyでカバーされるとは限らない点に注意したい。経路が変わればアクセスするツールが異なり、確認画面を経由せず内容が出力される可能性があるため、Read以外の経路も併せて塞ぐ発想が要る。

この抜け穴を塞ぐ第一歩は、Bash側にも同種のdenyを重ねることだ。「Bash(cat ./.env)」のように個別コマンドを拒否できるが、読み取り専用コマンドの種類は多く、パイプやリダイレクトを絡めた複合コマンドでは突破されやすい。コマンド文字列のパターンだけで完全に防ぐのは現実的ではなく、確実に閉じたいならPreToolUseフックでBashの入力コマンドを検査し、機密ファイル名を含む呼び出しを拒否するのが実務上の落としどころになる。
設定が実際に読み込まれているかは、/permissionsを実行し、該当ルールと取得元ファイルが一覧に表示されるかで確認できる。表示されない場合は設定ファイルの階層やスコープを見直すとよい。なお、Readのdeny挙動がGrepやGlob経由では仕様上あいまいになりやすいことは、既知の報告からもうかがえる。