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