Claude Code に社内の自動化を任せると、コマンドの中で GitHub のトークンやデータベースの接続文字列、外部 API のキーを使う場面が必ず出てきます。ここで多いのが、「.env を読ませない」ルールは作ったのに、スクリプトが環境変数から受け取った鍵がそのまま実行ログや会話に残る、という状態です。
Claude Code のサンドボックスには、秘密の値を Claude にもコマンドにも見せずに、通信のときだけ本物に差し替える「mask(マスク)」モードがあります。この記事では、Claude Code の公式ドキュメント(2026年10月時点)だけを出典に、隠す(deny)と差し替える(mask)の違い、mask が動く3つの条件、環境変数と認証情報ファイルの設定例、Linux と macOS の挙動差、管理者が会社で配る設定の雛形、導入の手順とチェックリストを整理します。
フォルダ・コマンド・秘密情報の線引き全体は、Claude Code の社内ルールの作り方で deny を中心に書きました。この記事は、その続きとして「見せずに使わせる」設定に絞ります。
結論 — 先に要点だけ
- サンドボックスを有効にしただけでは、認証情報は守られない。 既定の読み取り範囲は
~/.sshや~/.aws/credentialsを含み、環境変数は Claude Code の秘密ごと引き継がれる。組み込みの拒否リストは無く、列挙したものだけが保護される - deny は「隠す」、mask は「差し替える」。 deny はファイルを読めなくし環境変数を消す。mask はコマンドに1セッション限りのプレースホルダー(sentinel)を見せ、許可した送り先への通信でだけプロキシが本物に戻す
- mask には3つの条件がある。 プロキシの TLS 終端(
network.tlsTerminate)、allowedDomainsに含まれる送り先、そして「ユーザー設定・管理設定・--settings」のどれかに書くこと。リポジトリの.claude/settings.jsonに書いた mask は無視される - ファイルの mask は Linux と WSL2 だけ。 macOS ではファイルは読めなくなる(deny と同じ効果)。環境変数の mask は OS を問わない
- 会社で配るなら管理設定に。
allowUnsandboxedCommands: falseとfailIfUnavailable: trueで逃げ道を閉じ、credentials の deny・mask は管理設定から配る
前提 — サンドボックスの既定では、認証情報は読める
最初に押さえるべき事実は、サンドボックスの既定値です。公式ドキュメントの表では、サンドボックス内のコマンドの既定は次のとおりです。
| 項目 | 既定の範囲 |
|---|---|
| 書き込み | 作業ディレクトリ、ユーザーごとの一時ディレクトリ、追加したディレクトリ。保護パスは書き込み拒否のまま |
| 読み取り | マシンのほぼ全部。~/.ssh や ~/.aws/credentials のような認証情報ファイルを含む |
| ネットワーク | 直接の経路は無し。マシン上のプロキシを通り、許可ドメイン(最初は空)と照合される |
| 環境変数 | Claude Code から引き継ぐ。Claude Code の環境にある秘密も含む |
※ 出典: Claude Code Docs — Sandboxing(取得 2026-10)
つまり、サンドボックスを有効にしても、cat ~/.aws/credentials は通り、echo $GITHUB_TOKEN は本物を表示します。公式ドキュメントは「組み込みの認証情報の拒否リストは無く、列挙したファイルと変数だけが制限される」と明記しています。守りたいものは、自分で sandbox.credentials に書く必要があります。
もう1つの前提は、サンドボックスの外で動くものです。Read・Edit・Write・WebFetch・WebSearch などの組み込みツール、フック、ローカルの MCP サーバー、ステータスラインのコマンドはサンドボックスの外で動きます。sandbox.credentials が効くのはサンドボックス内の Bash コマンドだけで、全てのサブプロセスから剥がしたいときは後述の環境変数 CLAUDE_CODE_SUBPROCESS_ENV_SCRUB を使います。
deny と mask の違い — 隠すか、差し替えるか
sandbox.credentials の各エントリは、ファイルの path か環境変数の name と、mode を持ちます。mode は deny と mask の2つです。
deny(隠す) | mask(差し替える) | |
|---|---|---|
| 環境変数 | サンドボックス内のコマンドを動かす前に unset される | コマンドには sentinel(1セッション限りのプレースホルダー)が見える。許可した送り先への通信でプロキシが本物に戻す |
| ファイル | サンドボックス内から読めない(filesystem.denyRead と同じ制限) | Linux と WSL2 では sentinel 入りの写しを読む。macOS では読めない(deny と同じ) |
| 向く場面 | コマンドがその鍵を使う必要が無い | gh・npm・社内 API など、コマンドが認証して通信する必要がある |
| 書ける場所 | どの設定ファイルでも。各スコープの deny は結合され、どこからも外せない | ユーザー設定・管理設定・--settings だけ。プロジェクトとローカルの .claude/settings.json の mask は捨てられる |
| 同じ変数に両方あるとき | deny が優先 | — |
※ 出典: Claude Code Docs — Settings reference(sandbox.credentials)(取得 2026-10)
判断の軸は1つで、「そのコマンドは、その鍵で通信する必要があるか」です。必要が無ければ deny で消します。必要があれば mask にして、本物が届く先を injectHosts で絞ります。公式ドキュメントは mask の効果を「コマンドとそのログは本物の認証情報を一切持たないが、リクエストは認証される」と説明しています。
mask が動く3つの条件 — TLS 終端・送り先・設定の置き場
mask は「本物の鍵をプロキシが外へ送る」仕組みなので、3つの条件が揃わないと動きません。公式ドキュメントの要件をそのまま表にします。
| 条件 | 設定 | 揃わないとどうなるか |
|---|---|---|
| TLS 終端 | sandbox.network.tlsTerminate を {}(セッション限りの CA を自動生成)か、自社の CA の caCertPath・caKeyPath で指定 | コマンドには sentinel しか見えないまま、sentinel がそのままサーバーに届いて認証が失敗する(漏れはしない)。claude doctor に TLS termination is unavailable の警告が出る |
| 許可された送り先 | injectHosts に書くホストは network.allowedDomains でも許可されていること。injectHosts を省くと、allowedDomains の全ホストへの通信で差し替わる | 許可リスト外には差し替えも通信も起きない |
| 信頼された設定スコープ | mask・tlsTerminate・allowPlaintextInject・awsPairs・sigv4 はユーザー設定・管理設定・--settings からだけ読まれる | リポジトリの .claude/settings.json・.claude/settings.local.json に書いても無視される |
※ 出典: Claude Code Docs — Sandboxing(Mask credentials)(取得 2026-10)
3つめの条件には設計上の理由があります。mask は「本物をどこかへ送ってよい」という許可そのものなので、リポジトリに混入した設定で勝手に送り先を増やせないようにしてあります。管理者がサーバー管理設定で mask や tlsTerminate を配るときは、承認が必要な設定として扱われます。
tlsTerminate は公式に「experimental(実験的)」と書かれています。既定のプロキシは TLS を終端も検査もしないため、mask を使うときだけ有効にする、という位置づけです。TLS 終端は内容のフィルタリングを足すものではない点も明記されています。
環境変数のマスク — 設定例と extract・decode
環境変数の mask は credentials.envVars のエントリに "mode": "mask" を書きます。公式の例は、GH_TOKEN を api.github.com への通信でだけ差し替え、NPM_TOKEN は allowedDomains の全ホストで差し替える設定です。
{
"sandbox": {
"enabled": true,
"network": {
"tlsTerminate": {},
"allowedDomains": ["*.github.com", "registry.npmjs.org"]
},
"credentials": {
"envVars": [
{ "name": "GH_TOKEN", "mode": "mask", "injectHosts": ["api.github.com"] },
{ "name": "NPM_TOKEN", "mode": "mask" }
]
}
}
}
※ 出典: Claude Code Docs — Sandboxing(Mask environment variables)(取得 2026-10)
既定では値全体が1つの sentinel に置き換わります。接続文字列や JWT のように構造を持つ値は、全体を置き換えるとそれを解析するツールが壊れます。そのために、環境変数の mask には次の任意フィールドがあります。
| フィールド | 型・値 | 働き | 必要なバージョン |
|---|---|---|---|
extract | キャプチャグループを1つ以上含む正規表現 | グループ1に一致した部分だけを隠す。DATABASE_URL のパスワード部分など | v2.1.224 以降 |
onExtractNoMatch | "warn"・"deny"・"error"、既定は "warn" | extract が何にも一致しなかったとき。warn は隠さず通す、deny はサンドボックス内で unset、error は設定を直すまでサンドボックスの起動を止める | v2.1.224 以降 |
decode | 文字列 "jwt" | 値全体が JWT であることを確かめ、構造が正しい偽トークンに置き換える。検証できない値は警告付きで隠さず通る | v2.1.224 以降 |
maskClaims | 文字列の配列(decode が必要) | JWT の指定したトップレベルのクレームだけを隠し、他のクレームは読める | v2.1.224 以降 |
injectHosts | ホストの配列(allowedDomains でも許可されていること) | 本物に差し替える送り先を絞る | — |
※ 出典: Claude Code Docs — Settings reference(sandbox.credentials.envVars)(取得 2026-10)
extract と decode は同じエントリに同時には書けません。decode のエントリで onExtractNoMatch に書けるのは "warn" だけです。公式の例では、DATABASE_URL のパスワードだけを隠して不一致なら unset し、SERVICE_JWT の api_key クレームだけを隠します。
{
"sandbox": {
"credentials": {
"envVars": [
{
"name": "DATABASE_URL",
"mode": "mask",
"extract": "://[^:]+:([^@]+)@",
"onExtractNoMatch": "deny"
},
{
"name": "SERVICE_JWT",
"mode": "mask",
"decode": "jwt",
"maskClaims": ["api_key"]
}
]
}
}
}
ここで会社として決めるべきは onExtractNoMatch です。既定の warn は「鍵が無いこともある変数」には向きますが、鍵があるのにパターンが外れた場合は本物がそのまま通ります。社内の接続文字列のように「いつも入っている」値には deny を書きます。
認証情報ファイルのマスク — Linux と macOS で挙動が違う
ファイルの mask は credentials.files のエントリに "mode": "mask" を書きます。Claude Code v2.1.221 以降が必要で、何が見えるかは OS で違います。
| OS | サンドボックス内のコマンドに見えるもの |
|---|---|
| Linux・WSL2 | sentinel 入りの写し。通信時にプロキシが本物に差し替える |
| macOS | ファイルを読めない。sentinel の写しは作られないので、そのファイルで認証するツールはサンドボックス内では動かない(deny と同じ効果)。ファイルシステム隔離を切っても読めないまま |
※ 出典: Claude Code Docs — Sandboxing(Mask credential files)(取得 2026-10)
公式の例は、gh の設定ファイル ~/.config/gh/hosts.yml の oauth_token だけを隠す設定です。extract で秘密の位置を示すので、Linux と WSL2 では gh が残りの設定を読めます。
{
"sandbox": {
"enabled": true,
"network": {
"tlsTerminate": {},
"allowedDomains": ["*.github.com"]
},
"credentials": {
"files": [
{
"path": "~/.config/gh/hosts.yml",
"mode": "mask",
"extract": "oauth_token:\\s*(\\S+)",
"injectHosts": ["api.github.com"]
}
]
}
}
}
ファイルの mask には、環境変数には無い2つの注意があります。
maskDuplicates(既定はfalse)。 コメントに貼られた秘密のような、同じ値の別の写しもファイル内で置き換える。生の部分文字列で照合するため、長く推測しにくい秘密に限って使う(設定リファレンスの記載)- deny への自動フォールバック。 ディレクトリのパス、glob パターン、8 MiB より大きいファイル、UTF-8 テキストでないファイルは安全に mask できないので deny として扱われる
mask は1ファイルずつ指定します。~/.ssh のようなディレクトリをまとめて隠したいなら、最初から deny に書きます。確認の方法も公式に書かれていて、Claude に cat ~/.config/gh/hosts.yml をサンドボックス内で実行させると、Linux と WSL2 では sentinel が表示され、macOS では読み取りが失敗します。自分で ! プロンプトに打った行はサンドボックスの外で動くことが多いので、確認にはなりません。
AWS の鍵 — アクセスキー ID とシークレットをペアで隠す
AWS のリクエストは SigV4 署名を含むため、AWS_ACCESS_KEY_ID と AWS_SECRET_ACCESS_KEY は一緒に mask します。プロキシはアクセスキーの sentinel を手がかりにリクエストを見つけ、本物で署名し直します(v2.1.221 以降)。シークレットだけを mask すると、プロキシが検出できないプレースホルダーで署名されるため、AWS 側で失敗します。
慣例の AWS_ACCESS_KEY_ID・AWS_SECRET_ACCESS_KEY・AWS_SESSION_TOKEN は、値全体を mask すれば自動で1つの認証情報として結び付きます。別の変数名を使っているなら credentials.awsPairs(v2.1.224 以降)で組にします。ストリーミングアップロード・presigned URL・SigV4A は署名を再計算できないため、mask したペアで署名されたものはプロキシが失敗させます。credentials.sigv4 でそれらを通すこともできますが、AWS 側で拒否されるので、ツールは AWS の拒否応答を受け取ります。
※ 出典: Claude Code Docs — Sandboxing(Re-sign AWS requests)(取得 2026-10)
全てのサブプロセスから剥がす — CLAUDE_CODE_SUBPROCESS_ENV_SCRUB
sandbox.credentials が効くのはサンドボックス内の Bash だけです。フックやローカルの MCP サーバーも含めて、Claude Code が起動する全てのサブプロセスから認証情報を剥がしたいときは、環境変数 CLAUDE_CODE_SUBPROCESS_ENV_SCRUB を 1 にします。Claude Code 本体は自分の API 呼び出しのために認証情報を保持します。
この scrub は変数名か値の形で認証情報を判定します。公式の表から、何が消え、何が残るかを整理します。
| 例 | scrub の動き |
|---|---|
ANTHROPIC_API_KEY・AWS_SECRET_ACCESS_KEY | 消す |
NPM_TOKEN・DB_PASSWORD | 名前が認証情報らしいので消す |
パスワードを含む DATABASE_URL | 値が認証情報らしいので消す |
パスワードを含む PIP_INDEX_URL・NPM_CONFIG_REGISTRY | URL は残し、ユーザー名とパスワードを切り落とす |
GITHUB_TOKEN・GH_TOKEN などの GitHub のトークン | 残す(gh と GitHub API を呼ぶスクリプトを動かすため) |
HTTP_PROXY・HTTPS_PROXY | 残す(URL 内のユーザー名・パスワードも含めて) |
| 名前も値も認証情報らしくない秘密 | 残す |
※ 出典: Claude Code Docs — Environment variables(What the subprocess environment scrub removes)(取得 2026-10)
ここで見落としやすいのが GitHub のトークンです。scrub は GITHUB_TOKEN を残すので、サンドボックス内の Bash からも消したいなら sandbox.credentials の deny を別に書きます。公式ドキュメントも「scrub は1つの層として、絞った権限ルールと併用する」と書いており、これだけで守ったことにはなりません。Linux では scrub が Bash を隔離された PID 名前空間で動かすため、ps や kill がホストのプロセスを見られなくなる副作用もあります。
管理者が会社で配る設定 — 雛形
会社として揃えるなら、各自の ~/.claude/settings.json に頼らず、管理設定で配ります。公式ドキュメントの「組織向けの設定」を踏まえた雛形です。
{
"sandbox": {
"enabled": true,
"failIfUnavailable": true,
"allowUnsandboxedCommands": false,
"network": {
"tlsTerminate": {},
"allowedDomains": ["api.github.com", "registry.npmjs.org"],
"allowManagedDomainsOnly": true
},
"credentials": {
"files": [
{ "path": "~/.aws/credentials", "mode": "deny" },
{ "path": "~/.ssh", "mode": "deny" }
],
"envVars": [
{ "name": "GH_TOKEN", "mode": "mask", "injectHosts": ["api.github.com"] },
{ "name": "ANTHROPIC_API_KEY", "mode": "deny" }
]
},
"enableWeakerNestedSandbox": false,
"enableWeakerNetworkIsolation": false
}
}
各キーの意味は公式の説明どおりです。
failIfUnavailable: true— Linux で bubblewrap が無いなど依存が欠けるとき、サンドボックス無しで動くのではなく起動を止める。サンドボックスは Windows ネイティブでは動かないので、その端末では Claude Code が起動時に終了するallowUnsandboxedCommands: false— サンドボックス内で失敗したコマンドをサンドボックス外で再実行する逃げ道を閉じる。これかallowManagedDomainsOnly: trueが管理設定にあると「admin-required」になり、リポジトリの.claude/settings.jsonではサンドボックスを緩められないallowManagedDomainsOnly: true— 許可ドメインを管理設定の値に固定し、許可外のホストはプロンプト無しで拒否するenableWeakerNestedSandboxなど — 管理設定で設定しない限り開発者側が有効にできる「弱める」キー。使わせないならfalseを明示する
※ 出典: Claude Code Docs — Sandboxing(Configure the sandbox for your organization)(取得 2026-10)
管理設定の配り方そのもの(MDM・サーバー管理設定・ファイルの置き場)は、Claude Code の法人導入ガイドに書きました。なお、公式ドキュメントは2つの限界も明記しています。開発者が ! のシェルモードで自分で打ったコマンドはサンドボックスの外で動くこと、そして既定のプロキシはクライアントが申告したホスト名で許可を判断し TLS を検査しないため、github.com のような広いドメインを許すとデータ持ち出しの経路になりうること、です。
導入の手順 — 5ステップ
- 鍵の棚卸しをする。 Claude Code を動かす端末と CI で、環境変数と認証情報ファイルを列挙し、「コマンドがその鍵で通信する必要があるか」で deny と mask に仕分ける。迷ったら deny
- mask の3条件を揃える。
tlsTerminate、allowedDomainsとinjectHosts、設定の置き場(ユーザー設定か管理設定)。リポジトリの設定ファイルに mask を書いても無視されることをチームに周知する - ひとりの端末で確かめる。 Claude に
catとenvをサンドボックス内で実行させ、sentinel が表示されることを見る。claude doctorで TLS 終端の警告とinjectHostsの不一致警告が無いことを見る - 管理設定に移す。 雛形を元に
failIfUnavailable・allowUnsandboxedCommands・allowManagedDomainsOnlyを加え、全員に配る。macOS の端末ではファイルの mask が deny になるので、ghなどの設定ファイルで認証するツールの扱いを決めておく - 定期実行と CI にも広げる。 無人で動かす自動化や GitHub Actionsでは、
CLAUDE_CODE_SUBPROCESS_ENV_SCRUBとsandbox.credentialsを組み合わせ、ジョブのpermissionsも最小にする
社内で自動化の仕組みを自分たちで組むときの、鍵の扱いを含めた安全な作り方と止め方は、企業向けの有料の実務書にもまとめています。
セルフチェックリスト(12項目)
- サンドボックスを有効にしても
~/.sshと~/.aws/credentialsは既定で読めると理解している -
sandbox.credentialsに、守りたいファイルと環境変数を全て列挙した(組み込みの拒否リストは無い) - 通信に使わない鍵は deny、使う鍵は mask に仕分けた
- mask のエントリは
~/.claude/settings.jsonか管理設定に置いた(リポジトリの.claude/ではない) -
network.tlsTerminateを設定し、claude doctorに TLS 終端の警告が出ない -
injectHostsのホストがallowedDomainsにも入っている -
DATABASE_URLのような「いつも入っている」値はonExtractNoMatchをdenyにした - AWS の鍵はアクセスキー ID とシークレットをペアで mask した
- macOS の端末では、ファイルの mask が読み取り拒否になることを前提にツールを選んだ
-
CLAUDE_CODE_SUBPROCESS_ENV_SCRUBが GitHub のトークンを残すことを踏まえ、必要なら deny を別に書いた - 管理設定で
allowUnsandboxedCommands: falseとfailIfUnavailable: trueを配った -
!のシェルモードで打ったコマンドはサンドボックスの外で動くことを、利用者に伝えた
よくある失敗パターン 5つ
- サンドボックスを有効にして守ったつもりになる。 既定の読み取り範囲は認証情報ファイルを含み、環境変数は秘密ごと引き継がれる。
credentialsを書くまで何も隠れない - リポジトリの
.claude/settings.jsonに mask を書く。 捨てられて効かない。mask はユーザー設定・管理設定・--settingsだけ tlsTerminateを書き忘れて「認証が失敗する」と悩む。 漏れてはいないが、sentinel がそのままサーバーに届いている。claude doctorの警告を見るextractのパターンが外れたまま既定のwarnで運用する。 鍵があるのに隠されず、本物がサンドボックス内で読める。「いつも入っている」値はdenyに- AWS のシークレットだけ mask する。 署名がプロキシに検出されず AWS で失敗する。アクセスキー ID と一緒に mask する
公式ドキュメント・リソース集
- Sandboxing — 既定の範囲、deny と mask、組織向けの設定、限界
- Settings reference — sandbox.credentials —
files・envVarsの全フィールドとバージョン - Environment variables — CLAUDE_CODE_SUBPROCESS_ENV_SCRUB — scrub が消すもの・残すもの
- Security — 認証情報の保管場所、クラウドセッションでの GitHub 認証情報の扱い
よくある質問
Q. deny と mask はどちらを既定にすべきですか?
deny です。mask は「そのコマンドがその鍵で通信する必要がある」ものに限り、injectHosts で本物が届く先を絞って使います。公式ドキュメントも、鍵があるのにパターンが外れる可能性がある秘密には deny を勧めています。同じ変数が両方に書かれたときは deny が優先されます。
Q. macOS の開発端末では mask は使えないのですか?
環境変数の mask は macOS でも動きます。使えないのは認証情報ファイルの mask で、macOS ではそのファイルがサンドボックス内から読めなくなり、deny と同じ効果になります。公式の例も GH_TOKEN を環境変数として mask しているので、ファイルでなく環境変数で鍵を渡す形に寄せると、OS をまたいで同じ設定にできます。
Q. CLAUDE_CODE_SUBPROCESS_ENV_SCRUB だけで足りますか?
足りません。scrub は変数名と値の形で認証情報を判定するため、名前も値も認証情報らしくない秘密は残り、GitHub のトークンは意図的に残されます。公式ドキュメントは、絞った権限ルールと併用する1つの層と位置づけています。サンドボックス内の Bash から GitHub のトークンも消したいなら、sandbox.credentials の deny を加えます。
Q. リポジトリの .claude/settings.json に mask を書けば、チーム全員に効きますか?
効きません。mask は本物の鍵を外へ送る許可そのものなので、Claude Code はユーザー設定・管理設定・--settings フラグからだけ読み、プロジェクトとローカルの .claude/settings.json に書かれた mask は捨てます。チームで揃えるなら管理設定で配り、deny はどの設定ファイルからでも結合されるので、deny だけはリポジトリにも書けます。
Q. Claude Code 自身の API キーはどこに保存されますか?
公式ドキュメントによると、macOS では Keychain が使える場合はそこに、Linux ではモード 0600 のファイルに、Windows ではユーザープロファイルのアクセス制御を引き継ぐファイルに保存されます。クラウドセッションでは、GitHub の認証情報は Anthropic のサーバー上で暗号化して保管され、セッションの VM には入らず、VM はそのセッションに限った短命の認証情報を持ちます。
※ 出典: Claude Code Docs — Security(取得 2026-10)
次の一歩
まず、Claude Code を動かしている端末で env を見て、認証情報らしい変数を5つ書き出してください。それぞれについて「Claude のコマンドがその鍵で通信する必要があるか」を決め、無いものは deny、あるものは mask と injectHosts にして ~/.claude/settings.json に書き、Claude に env をサンドボックス内で実行させて sentinel になっていることを確かめます。ひとりの端末で動いたら、雛形を元に管理設定へ移します。
鍵の仕分け、macOS と Linux が混在する環境での設定の揃え方、定期実行や CI への広げ方を相談したい場合は、お問い合わせから現在の構成(OS・使っている鍵の種類・配布の方法)をお知らせください。Claude 導入全体の進め方はClaude 導入支援ハブにまとめています。
更新履歴
- 2026-10-31: 初版公開
関連ページ
- Claude Code の社内ルールの作り方【2026年10月】— フォルダ・コマンド・秘密情報を settings と CLAUDE.md で線引きする
- Claude Code の法人導入ガイド【2026年9月】— 管理者が先に決める設定配布・権限・利用上限・監査
- Claude Code を決まった時刻に動かす【2026年9月】— ヘッドレスモードの定期実行と、無人で許す操作の決め方
- Claude Code を GitHub Actions で動かす【2026年10月】— 法人が先に決める認証・権限・費用の上限
- Claude Code で作った自動化が止まっていないか確かめる【2026年10月】— 実行ログ・失敗の通知・やり直しの最小セット
- Claude 導入支援ハブ