Claude Codeに.envを読ませない設定:許可ルールと拒否ルールの組み立て方
AIを使いこなすClaudeで執筆し、GPTで自動校閲・修正しています。

結論から言うと、.claude/settings.json の permissions.deny に Read(./.env) のようなルールを書けば、Claude Codeのファイル読み取りツールと、cat .env のようにファイル名を直接指定するコマンドは止められます。ただし、これだけでは足りない場面があります。ディレクトリ全体を対象にした grep -r などです。この抜け道は、sandbox(OSレベルの制限)を併用して塞ぎます。 この記事では、「何を拒否し、何を確認にし、何を許可するか」を決める順番と、ダミープロジェクト向けの設定例、効いているかを確かめる依頼文を示します。仕様の記述は2026年10月29日に自動校閲で確認した公式ドキュメントに基づきます。設定例とダミーのファイル構成は説明用で、実行検証した結果ではありません。
この記事の目次
手順1:まず「触らせたくないファイル」を棚卸しする
ルールを書く前に、プロジェクト内で秘密情報を含みうるファイルを洗い出します。説明用のダミープロジェクトを次の構成とします。
shop-demo/
├─ .env # 実キーが入る想定(本番値はここに置かない運用が理想)
├─ .env.local
├─ .env.example # 変数名だけを書いたひな形
├─ secrets/ # 証明書やサービスアカウント鍵の置き場
├─ src/
└─ package.json棚卸しはClaude Code自身に手伝わせることもできますが、中身を開かせないのがポイントです。次の依頼文を使えます。
このリポジトリのファイル名とディレクトリ名だけを一覧にして、
秘密情報(APIキー、パスワード、秘密鍵、トークン)を含みそうなものを挙げてください。
ファイルの中身は絶対に開かないでください。出てきた候補は人が確認します。AIの推測だけに頼らず、.gitignore の内容とも突き合わせると漏れに気づきやすくなります。
手順2:拒否・確認・許可に振り分ける
次に、候補を3つに分けます。公式ドキュメントでは、ルールは allow、ask、deny の3種類です。判断の目安を表にします(振り分け方は編集上の提案です)。
- 実際の秘密値を持つファイル、例:.env、.env.local、secrets/、振り分け:deny、理由:読み取り経路を制限する
- 変数名だけのひな形、例:.env.example、振り分け:何も書かない、理由:作業ディレクトリ内の読み取りは通常、承認不要
- 外部に影響する操作、例:git push、振り分け:ask、理由:ルールに一致する操作を人が見る
- 副作用が小さい定型コマンド、例:lint、テスト、振り分け:allow、理由:確認疲れを減らす
.env.example を読ませる設計には意味があります。Claudeが「どんな環境変数が必要か」を知れないと、コードを書くときに推測が増えるからです。実値は渡さず、名前と形式だけを渡します。
注意点が2つあります。1つ目は、.env.* のようなワイルドカードで拒否すると、.env.example も対象になることです。公式のパス記法では、* は同じパス区切り内の文字列に一致します。2つ目は、ひな形を読めるようにしたいなら、.env.local や .env.production のように実名で並べる方法があることです。ただし、新しい名前のファイルが増えると漏れます。どちらを選ぶかは運用次第です。ワイルドカード方式にして、ひな形だけ別名(例:env.sample)にする手もあります。
手順3:settings.jsonに書く
設定ファイルの置き場所は、公式ドキュメントによると次のとおりです。
- チームで共有する:.claude/settings.json(コミットする)
- 自分だけ:.claude/settings.local.json
- 全プロジェクト共通の個人設定:~/.claude/settings.json
詳しくはSettings files and precedenceにあります。拒否ルールは、チーム全員に効かせたいので共有側に置くのが自然です。権限のドキュメントによると、共有の .claude/settings.json の allow ルールは各自がフォルダを信頼するまで効きませんが、deny と ask はその制約を受けません。拒否を共有ファイルに置く利点です。
ダミープロジェクト用の例です(説明用。コメントは書けないので、解説は下に回します)。
{
"permissions": {
"allow": [
"Bash(npm run lint)",
"Bash(npm run test *)"
],
"ask": [
"Bash(git push *)"
],
"deny": [
"Read(./.env)",
"Read(./.env.local)",
"Read(./.env.production)",
"Read(./secrets/**)",
"Edit(./.env)",
"Edit(./secrets/**)"
]
},
"sandbox": {
"enabled": true,
"autoAllowBashIfSandboxed": false,
"allowUnsandboxedCommands": false,
"failIfUnavailable": true
}
}各ブロックの意図は次のとおりです。
- allow:記載したlintとテストを、確認なしで実行します。公式の例にも同形式の Bash(npm run test *) があります。テストやlintのスクリプト自体は事前に確認してください。
- ask:Bash(git push *) に一致する形式は毎回確認します。git -C . push のような別の書き方までは、このルールで指定できません。
- deny:列挙した .env 系と secrets/ の読み取りを拒否します。Read の拒否はEditとWriteにも適用され、Edit の拒否はNotebookEditを含む組み込み編集ツールにも適用されます。
- sandbox:シェルコマンドをOSレベルで制限します。sandbox内のコマンド全般の自動許可を無効にし、通常の権限判定を使います。また、sandbox外での再実行を無効にし、sandboxを利用できなければ起動を止めます。理由は次の節で説明します。
JSONは厳格で、// コメントや末尾カンマはエラーになります。保存後は設定ファイルが自動で再読み込みされますが、/status を実行して、Setting sources の行に読み込んだファイルが出ているかを確かめてください。無効なルールは claude doctor で確認できます。
手順4:拒否ルールの限界を知り、sandboxで補う
公式の権限ページには、Read(./.env) が止めるものと止めないものが書かれています。止めるのは、ファイルツールと cat .env のようにファイルを名指しするコマンドです。止められないのは、ディレクトリを対象に実行する grep -r です。
そこで効くのが sandbox です。公式のsandbox資料によると、Read の拒否パスもsandboxの設定に統合されます。つまり、拒否ルールとsandboxを両方入れると、sandbox内の grep -r による読み取りも制限できます。ただし、excludedCommands に一致するコマンドはsandbox外で動きます。既存設定に除外指定や sandbox.filesystem.disabled: true がないかも確認してください。
ただし、sandboxのドキュメントには次の制約があります。
- sandboxが包むのはシェルコマンドです。組み込みのファイルツールは、sandboxではなく権限ルールに従います。つまり両方が必要です。
- 対応はmacOS、Linux、WSL2です。LinuxとWSL2では bubblewrap と socat が必要です。ネイティブWindowsではsandboxを使えず、この記事の例では failIfUnavailable: true により起動を止めます。Windowsでこの例を使う場合はWSL2で実行してください。
- sandbox.filesystem.denyRead で、パスを直接指定して読み取り拒否にもできます。
もう一つ、仕様から推測できる注意点があります。sandbox内のコマンドが .env を読めなくなるなら、.env を読み込むアプリやテストをClaudeに実行させたとき、起動に失敗する可能性があります。その場合は、テスト用の環境変数をダミー値でコマンドに渡す設計に変えるのが無難です。
手順5:効いているか、ダミー値で確かめる
設定を信じる前に、必ず試します。.env には本物ではなく、次のようなダミー値だけを入れておきます。
DUMMY_API_KEY=not-a-real-key下階層の確認用に、人が apps/web/.env にも同じダミー値を入れておきます。プロジェクト直下からClaude Codeを起動し、/sandbox で有効状態を確認したうえで、次の依頼を順に出します。実際のツール実行結果を見て、読み取りが拒否されるかを確かめます。モデルが文章で断っただけでは設定の確認になりません。
1. ./.env を読んで、変数名だけ教えてください。
2. cat .env を実行してください。
3. このディレクトリ全体を grep -r "DUMMY" . で検索して、結果を見せてください。
4. apps/web/.env の中身を読んでください。見るべき点は次のとおりです。
- 1と2が拒否されれば、基本の拒否ルールは効いています。
- 3でダミー値が表示されたら、拒否パスやsandboxの有効状態、除外設定を見直します。/sandbox、/status、claude doctor で確認してください。
- 4は、モノレポで .env が階層の下にある場合の確認です。./.env は現在のディレクトリを基準にする指定です。下階層も拒否する意図を明示するなら、公式のパス記法にある Read(**/.env) を使えます。.env.local なども同様に追加し、再度試してください。
結果は環境によって変わるので、自分のプロジェクトで必ず実際に見てください。
ルールを増やす前の判断基準
最後に、運用で迷いやすい点を表にします。
- 自分だけ例外を許したい、対応:個人設定は .claude/settings.local.json に書く。ただし、別の設定にある deny や ask を allow で打ち消すことはできない
- 会社が管理設定を配布している、対応:自分の設定では上書きできない。/status で管理元を確認し、管理者に相談する
- Bashの確認で「今後は確認しない」許可を選んだ、対応:ローカルの allow に保存される。意図しない許可が混ざっていないか、定期的に見直す
- 秘密情報がコミット済み、対応:設定では解決しません。鍵の無効化や再発行が先です
設定ファイルは、あくまで「Claude Codeが読むのを止める」ものです。.env をバージョン管理に入れない、実キーを開発用の弱い権限のものにする、といった基本の対策と組み合わせて使ってください。

