sandbox.filesystem.denyReadで認証情報ファイルを読ませない
sandbox.filesystem.denyReadは指定パスの読み取りをOSレベルで遮断する設定です。認証情報ファイルを隠す設定例とallowReadでの例外の開け方、関連設定との使い分けを解説します。
Claude Codeのサンドボックスは、既定だと読み取りをほぼ全開放しています。書き込みは作業ディレクトリなどに絞られますが、読み取りはコンピューター全体に及び、~/.aws/credentialsや~/.ssh/のような認証情報ファイルも例外なく読める状態です。sandbox.filesystem.denyReadは、このうち指定したパスだけをOSレベルで読ませなくする設定です。
sandbox.filesystem.denyReadでできること
sandbox.filesystem.denyReadは、サンドボックス化されたBashツールとその子プロセス(kubectl・terraform・npmなど)からの読み取りを、指定パスに対してブロックする設定です。効果はOSのサンドボックス境界で強制されるため、Claudeのツール呼び出しだけでなく、Bash経由で起動したあらゆるサブプロセスに及びます。
前提として、denyReadが意味を持つのはsandbox.enabledがtrueのときだけです。/sandboxパネルでモードを選ぶとプロジェクトの.claude/settings.local.jsonに設定が保存され、その場では現在のプロジェクトだけで有効になります。すべてのプロジェクトで既定にしたいなら~/.claude/settings.json(ユーザー設定)に、組織全体で強制したいなら管理設定にsandbox.enabled: trueを書きます。
対象になるのはあくまでサンドボックス化されたBashツールです。ClaudeのReadツールやGrepツールは別の権限系統で動いており、denyReadが直接それらを止めるわけではありません。ただしpermissions.denyに書いたRead(...)の拒否ルールは、セッション開始時に自動でdenyReadのリストへ合流します。つまり「Read権限のdenyルール」と「サンドボックスのdenyRead」は別の仕組みでありながら、設定した瞬間に同じ禁止パスのリストへ統合される関係です。
型はallowWrite・denyWrite・denyRead・allowReadの配列と、allowManagedReadPathsOnly・disabledの真偽値を持つオブジェクトで、既定は未設定(既定の読み取り境界がそのまま適用される)です。スコープはAny fileなので、プロジェクト設定・ユーザー設定・管理設定のどこに書いても有効になります。
「OSレベルで遮断する」の中身は、プラットフォームごとに実体が違います。macOSはSeatbeltで、LinuxとWSL2はbubblewrapでサンドボックスを実装しており、denyReadはこれらのOSのセキュリティ機構を使ってプロセスの読み取り権限そのものを絞ります。アプリケーション側の判断で「読まない」のではなく、OS側が「読めない」状態を作る点が、Claudeのツール権限による制御との違いです。
~/.aws/credentialsを隠す設定例
書き込み先を追加しつつ、AWSの認証情報ファイルを読ませない設定は次のとおりです。
{
"sandbox": {
"filesystem": {
"allowWrite": ["/tmp/build", "~/.kube"],
"denyRead": ["~/.aws/credentials"]
}
}
}パスの解釈は3つのプレフィックスで決まります。
| プレフィックス | 意味 | 例 |
|---|---|---|
/ | 意味ファイルシステムルートからの絶対パス | 例/tmp/buildはそのまま |
~/ | 意味ホームディレクトリからの相対パス | 例~/.kubeは$HOME/.kubeになる |
./またはプレフィックスなし | 意味プロジェクト設定ならプロジェクトルート、ユーザー設定なら~/.claudeからの相対パス | 例./outputはプロジェクトルート配下 |
この記法はRead・Editの権限ルール(絶対パスに//、プロジェクト相対に/を使う)とは別物なので、sandbox.filesystemの設定で/pathと書くと絶対パス扱いになる点に注意します。
末尾のスラッシュとワイルドカードの扱いにも仕様があります。~/.awsと~/.aws/は同じディレクトリとして扱われ、末尾の/**も除去されるため~/build/**と~/buildは同じ範囲を指します。ワイルドカード(*)はdenyReadとallowReadならどのプラットフォームでも使え、LinuxとWSL2ではマッチする具体パスへ展開されます。一方allowWrite・denyWrite側はmacOSでだけワイルドカードが機能し、LinuxとWSL2では*・?・[を含むエントリがそのまま無効になります。
allowReadで例外を開ける
denyReadで広く塞いだ領域の中に、特定パスだけ読み取りを再許可したいときはallowReadを使います。読み取りルールが重なったときはより具体的なパスが優先されます。
| ルールの組み合わせ | 結果 |
|---|---|
denyRead: ["~/"] + allowRead: ["~/projects"] | 結果~/projectsだけ読める。ホームディレクトリの残りは塞がれたまま |
allowRead: ["~/"] + denyRead: ["~/.env"] | 結果~/.envだけ塞がれ、ホームディレクトリの残りは読める。広いallowの内側でも個別のdenyは通る |
allowRead: ["~/"] + denyRead: ["~/**/.env"] | 結果ホームディレクトリ配下のすべての.envが塞がれる。ワイルドカードのdenyも同じ優先順位で効く |
ホームディレクトリ全体を塞ぎつつプロジェクトだけ読めるようにする設定は次のとおりです。
{
"sandbox": {
"filesystem": {
"denyRead": ["~/"],
"allowRead": ["."]
}
}
}.はプロジェクト設定に書けばプロジェクトルート、~/.claude/settings.jsonに同じ設定を書けば~/.claudeに解決されます。同じファイルをユーザー設定側に置くと、プロジェクトのファイルはdenyReadの対象のまま残ってしまうため、置き場所を間違えないことが重要です。
組織で読み取り可能パスを固定したい場合はallowManagedReadPathsOnlyを管理設定に立てます。trueにすると、管理設定由来のallowReadエントリだけが有効になり、開発者がローカル設定で読み取り範囲を広げ直すことができなくなります。denyRead自体はこのフラグに関係なく、セッションが読み込むすべての設定スコープからマージされ続けます。ホームディレクトリを塞ぎつつ~/workだけ再許可し、それ以外の再許可を開発者に禁じる管理設定は次のとおりです。
{
"sandbox": {
"filesystem": {
"denyRead": ["~/"],
"allowRead": ["~/work"],
"allowManagedReadPathsOnly": true
}
}
}管理設定でsandbox.filesystemを何か1つでも設定すると、sandbox.filesystem.disabled自体もそのセッションでは管理設定からしか設定できなくなります。つまり組織がdenyReadを管理設定に書いた時点で、開発者がローカルのsettings.jsonでfilesystem.disabled: trueを書いても無視され、ファイルシステム分離ごと外してdenyReadを回避することはできません。ユーザー設定やプロジェクト設定に書いたdenyReadにはこの縛りはなく、disabledは引き続きユーザー設定・管理設定・--settingsフラグのいずれからでも変更できます(プロジェクト設定からは元々変更できません)。
/sandboxコマンドのConfigタブでは、現在有効なdenyRead・allowReadの実パスを確認できます。
/sandboxsandbox.credentials・permissions.blockReadsOutsideWorkingDirectoriesとの使い分け
認証情報を守る設定はdenyReadだけではありません。目的が「完全に読ませない」のか「ツールには使わせつつ値だけ隠す」のか、守りたいのがファイルなのか環境変数なのかで選ぶ設定が変わります。
denyReadが扱えるのはファイルパスだけです。AWS_SECRET_ACCESS_KEYやGITHUB_TOKENのように環境変数へ直接入っている秘密情報は、denyReadにいくらパスを書いても消えません。環境変数を守るにはsandbox.credentials.envVarsにmode: "deny"(サンドボックス化コマンドの実行前にその変数を環境から外す)かmode: "mask"を指定します。sandbox.credentials.filesのmode: "deny"は、実装上filesystem.denyReadと同じ制限をファイルに適用するもので、認証情報専用のブロックとしてファイルと環境変数のルールをひとまとめに書けるようにした表記です。つまり「ファイルをdenyする」という一点ではdenyReadとcredentials.filesのdenyは同じ効果で、環境変数まで含めて一箇所で宣言したいときにcredentialsブロックを使うことになります。
| 目的 | 使う設定 | 効果 | 対象 |
|---|---|---|---|
| 特定パスの読み取りを丸ごと遮断 | 使う設定sandbox.filesystem.denyRead | 効果読み取り自体をOSレベルでブロック | 対象サンドボックス化Bashとその子プロセス |
| 環境変数の秘密情報を外す | 使う設定sandbox.credentials.envVars(mode: "deny") | 効果サンドボックス化コマンドの実行前にその環境変数自体を取り除く | 対象サンドボックス化Bashとその子プロセス |
| ツールには使わせつつ値だけ隠す | 使う設定sandbox.credentials.files(mode: "mask") | 効果LinuxとWSL2はセンチネル値を読ませ、送信時にプロキシが実値へ差し替え。macOSは読み取り自体を拒否(denyと同じ挙動) | 対象サンドボックス化Bashとその子プロセス |
| Claude自身のツール呼び出しだけ制限 | 使う設定permissions.blockReadsOutsideWorkingDirectories | 効果Read・Grep・Glob・LSPツールでの作業ディレクトリ外読み取りを禁止。Bash経由のcat等は自動modeでも確認を要求 | 対象Claudeの組み込みツール中心 |
| ファイルシステム層ごと外す | 使う設定sandbox.filesystem.disabled | 効果denyReadとcredentials.filesのdeny判定を含め、ファイルシステム分離全体を無効化(ネットワーク分離は残る) | 対象サンドボックス全体 |
kubectlやterraformのように認証情報ファイルを読んで実際に通信するツールを使い続けたいなら、denyReadではなくmode: "mask"を選びます。読み取りを完全に断ってよい、あるいは元々そのツールをサンドボックス内で使う予定がないならdenyReadの方が単純で確実です。なおsandbox.credentials自体もサンドボックス化されたBashコマンドにしか効かないため、サンドボックスの有無にかかわらず全サブプロセスから環境変数を取り除きたい場合はCLAUDE_CODE_SUBPROCESS_ENV_SCRUBという別の環境変数を使います。mask方式の限界や使い方の詳細は認証情報マスキングは情報漏洩対策になるかで扱っています。
よくあるつまずき
denyReadは仕様変更を重ねてきた設定なので、古い記憶のまま設定すると意図通りに動かないことがあります。
サンドボックス自体が起動しないとdenyReadは素通りします。Claude Codeは既定で、サンドボックスの依存パッケージが足りない環境や未対応プラットフォームでは、警告を出してサンドボックスなしでコマンドを実行します。この既定のままdenyReadだけを認証情報保護の頼みにしていると、サンドボックスが立ち上がらなかった回にはブロックそのものが働きません。保護をセキュリティゲートとして必須にしたい場合はsandbox.failIfUnavailableをtrueにして、サンドボックスが使えないときはコマンド実行自体を止める設定にします。
末尾スラッシュはv2.1.224より前は素通りの原因でした。denyRead: ["~/.aws/"]のように末尾スラッシュを付けて書くと、LinuxとmacOSでは意図せず読み取りが通ってしまうバグがありました。v2.1.224以降は末尾スラッシュを自動で取り除いて解決するため、~/.awsと~/.aws/のどちらで書いても同じ扱いになります。
macOSのワイルドカードallowReadはv2.1.236で挙動が変わりました。それより前は、~/**/.envのようなワイルドカードのdenyReadが広いallowReadの内側にあると、マッチしたディレクトリの中身まで再び読めてしまう不具合がありました。現在は表で示したとおり、ワイルドカードのdenyも具体パスのdenyと同じ優先順位で効きます。
filesystem.disabledはdenyReadごと無効化します。ファイルシステム分離を丸ごとオフにするsandbox.filesystem.disabledをtrueにすると、denyReadの禁止もcredentials.filesのdeny判定も一緒に効かなくなります。ネットワーク分離だけを残してファイルシステムを開けたい場面では、認証情報の保護が消えていないか確認が必要です。この設定自体の詳しい影響範囲はsandbox.filesystem.disabledはファイルシステム分離だけ外す設定にまとめています。
--setting-sourcesで除外した設定ファイルのdenyReadは反映されません(v2.1.246以降)。CLIやAgent SDKで設定の読み込み元を絞ると、除外したファイルのsandbox.filesystemエントリやReadのdenyルールもサンドボックス構成の計算から外れます。複数の設定ファイルにまたがってdenyReadを書いている場合は、除外の有無で保護が抜け落ちていないか確認します。
まとめ
sandbox.filesystem.denyReadは、認証情報ファイルのようにサンドボックス化コマンドへ絶対に見せたくないパスをOSレベルで塞ぐための設定です。既定の読み取りはほぼ全開放という前提を踏まえたうえで、allowReadで必要な例外だけを狭く開け、allowManagedReadPathsOnlyで組織のポリシーを固定できます。まずsandbox.enabledが効いているかを確認し、failIfUnavailableでサンドボックス不在時の扱いも決めておくと、保護が抜け落ちる回を減らせます。ツール自体にその認証情報を使わせたいならmode: "mask"、Claude自身の読み取りツールを制限したいならpermissions.blockReadsOutsideWorkingDirectoriesと、目的に応じて設定を使い分けます。サンドボックス全体の設計はClaude Codeのサンドボックス設計、他のAIコーディングエージェントとの読み取り既定の違いはAIコーディングエージェントのサンドボックス実装比較で扱っています。設定を変えたら/sandboxのConfigタブで反映を確認する習慣をつけておくと安心です。