Claude Media
CLAUDE_CODE_SUBPROCESS_ENV_SCRUBとは — 子プロセスから認証情報を消す環境変数

CLAUDE_CODE_SUBPROCESS_ENV_SCRUBとは — 子プロセスから認証情報を消す環境変数

CLAUDE_CODE_SUBPROCESS_ENV_SCRUBはBash・hooks・MCPの子プロセスから認証情報を消す環境変数です。遮断範囲、Linux限定のPID分離、見落としやすい副作用をまとめます。

CLAUDE_CODE_SUBPROCESS_ENV_SCRUB は、Claude Codeが起動する子プロセスから認証情報を消す環境変数です。対象はBashツール・hooks・MCPのstdioサーバーの3つです。1 を設定すると、AnthropicとクラウドプロバイダーのAPIキー、Claude Codeが認証情報と認識するその他の変数、パッケージレジストリのURLに埋め込まれた認証情報が取り除かれます。消えるのは子プロセス側だけです。親のClaudeプロセス自身はAPI呼び出しのために認証情報を保持し続けます。狙いは、プロンプトインジェクションがシェル展開経由で秘密情報を持ち出そうとする経路を塞ぐことです。

CLAUDE_CODE_SUBPROCESS_ENV_SCRUBが遮断する範囲

対象は3種類の子プロセスに限定されています。Claude Codeが実行するBashコマンド、hooksが起動するスクリプト、MCPのstdio方式で起動するサーバーです。SSEやHTTP経由のMCPサーバーはClaude Codeの子プロセスとして起動されないため、この変数の対象には含まれません。

消える情報は3種類です。AnthropicとAWS・GCPなどクラウドプロバイダーの認証情報、Claude Codeが認証情報として認識するその他の変数、そしてnpmやpipのレジストリURLに埋め込まれたトークンです。値そのものが子プロセスの環境変数一覧から消え、printenvenvで確認しても出てきません。

ここがsandbox.credentialsmode: "mask"と決定的に違う点です。maskは実値の代わりにセンチネル(偽の値)を見せ、許可済みの通信先へ出るときだけプロキシが実値に差し替えます。CLAUDE_CODE_SUBPROCESS_ENV_SCRUBにはこの差し替え経路がありません。子プロセスは認証情報を最初から一切受け取らないので、ghnpm publishのように環境変数の認証情報を使って自分自身が通信するツールは、そのままでは認証に失敗します。詳しい使い分けは後述します。

設定方法

既定では無効です。何も設定しなければ、子プロセスは従来どおり親の環境変数をそのまま引き継ぎます。有効にするには、シェルでの一時的な設定とsettings.jsonでの恒久的な設定のどちらかを使います。この変数はオン/オフ型で、1trueを設定すると有効になります(大文字・小文字は区別されません)。空文字にすると無効化したのと同じ扱いです。

export CLAUDE_CODE_SUBPROCESS_ENV_SCRUB=1
claude

チームやプロジェクト全体に配布する場合は、.claude/settings.jsonenvキーに書きます。

{
  "env": {
    "CLAUDE_CODE_SUBPROCESS_ENV_SCRUB": "1"
  }
}

シェルと設定ファイルの両方で値を設定した場合は、設定ファイル側の値が優先されます。設定ファイルのenvブロックは実行中のセッションにも反映されますが、値を消す(unsetする)ことはできない点は他の環境変数と同じです。

!シェルモードには及ばない可能性がある

Claude Codeには、入力の先頭に!を付けてシェルコマンドを直接実行する「シェルモード」があります。公式ドキュメントは、サンドボックスを有効にしていてもシェルモードのコマンドはサンドボックスの対象外になると明記しています。理由は「サンドボックスはClaudeが実行するコマンドに適用されるから」で、シェルモードはClaudeを介さずユーザーが直接実行する経路だからです。

CLAUDE_CODE_SUBPROCESS_ENV_SCRUBが遮断対象として挙げているのも「Bashツール」であり、シェルモードとは明確に区別されています。サンドボックスと同じ理屈が当てはまるなら、!で実行したコマンドには認証情報スクラブが及ばない可能性があります。信頼できないプロンプトを扱うセッションでは、!を使った手動確認自体が保護対象外の経路になりうる点を覚えておいてください。

Linuxだけ子プロセスがPID namespaceで分離される

Linux環境では、この変数を有効にするともう1つの効果が加わります。Bashの子プロセスが独立したPID namespaceで実行され、/proc経由でホスト側のプロセス環境を読み取れなくなります。認証情報を環境変数から消すだけでなく、他のプロセスの/proc/<pid>/environを覗く迂回路もふさぐ形です。

副作用として、サンドボックス化されたBashコマンドの中からpspgrepkillを実行しても、ホスト側のプロセスは見えず、シグナルも送れません。ビルドスクリプトやテストランナーが「実行中の別プロセスを見つけて再起動する」ような処理を挟んでいる場合、この変数を有効にした環境ではその処理が想定通りに動かなくなります。macOSやWindowsではこのPID namespace分離は行われず、認証情報の除去だけが効きます。

sandbox.autoAllowBashIfSandboxedへの影響

見落としやすい副作用がもう1つあります。sandbox.autoAllowBashIfSandboxedは既定でtrueになっており、サンドボックス化されたBashコマンドを権限プロンプトなしで実行できるようにする設定です。CLAUDE_CODE_SUBPROCESS_ENV_SCRUBを有効にすると、この自動許可が止まります。

つまり、サンドボックスと認証情報スクラブを両方オンにしている環境では、サンドボックス化されたBashコマンドが再び通常の権限フロー(許可を求めるプロンプト)を通るようになります。denyルールやBash(git push *)のような内容限定のaskルールは、どちらの状態でも変わらず適用されます。権限設定自体を見直す必要はありません。「サンドボックスにしたのにプロンプトが増えた」と感じたら、まずこの相互作用を疑ってください。

CLAUDE_CODE_SCRIPT_CAPSで呼び出し回数まで絞る

CLAUDE_CODE_SCRIPT_CAPSCLAUDE_CODE_SUBPROCESS_ENV_SCRUBが設定されているときだけ効く、セッションごとの追加防御です。JSONオブジェクトで、キーにコマンド文字列の部分一致、値に呼び出し回数の上限を指定します。

{
  "env": {
    "CLAUDE_CODE_SUBPROCESS_ENV_SCRUB": "1",
    "CLAUDE_CODE_SCRIPT_CAPS": "{\"deploy.sh\": 2}"
  }
}

この例ではdeploy.shを含むコマンドがセッション中に2回までしか実行できなくなります。マッチングは部分一致なので、./scripts/deploy.sh $(evil)のようにシェル展開を仕込んでも、deploy.shという文字列を含む限り上限にカウントされます。ただしxargsfind -execによるランタイムの多重起動は検出対象外です。あくまで多層防御の1つであり、これ単体で実行回数を完全に保証する機能ではありません。

hooksが引き継ぐ環境変数

hookプロセスは基本的に親の環境変数をそのまま引き継ぎますが、例外が2つあります。1つは常時除外されるOTEL_*系のエクスポーター変数、もう1つはCLAUDE_CODE_SUBPROCESS_ENV_SCRUB1のときに追加で取り除かれる認証情報系の変数です。前者は設定に関係なく常に除外され、後者はこの変数を有効にしたときだけ追加で除外される、という違いがあります。hooksスクリプトの中で外部サービスへ通知を送る処理を書いている場合、この変数を有効にした環境では想定していた認証情報がhooks側に渡らなくなる点に注意してください。

MCP stdioサーバーが起動時に認証エラーを返すことがある

MCPのstdioサーバーの多くは、起動時に環境変数からAPIキーやトークンを読み込む設計になっています。mcp.jsonenvにAPIキーを渡す構成は典型例です。該当するMCPサーバーを接続している状態でCLAUDE_CODE_SUBPROCESS_ENV_SCRUBを有効にすると、そのAPIキーが認証情報として認識される変数と重なることがあります。重なった場合は、サーバー起動の時点で認証エラーになる可能性があります。有効化した直後にMCPサーバーの接続が切れたときは、まずこの重なりを疑ってください。

claude-code-actionでの自動設定

GitHub Actionsのclaude-code-actionは、allowed_non_write_usersを設定しているときにこの変数を自動的に有効化します。想定しているのは、書き込み権限を持たない外部コントリビューターのPRからワークフローを動かす構成です。hooksやMCPサーバーの子プロセスにGITHUB_TOKENなどの認証情報が渡らないよう、CI側があらかじめ設定してくれる形です。自前のワークフローで同様の構成を組む場合も、明示的に設定しておくと同じ防御が働きます。

sandbox.credentialsのmaskモードとどちらを使うべきか

どちらも「子プロセスに認証情報の実値を見せない」という目的は共通ですが、対象の絞り方と、通信が必要なツールへの向き不向きが異なります。

観点CLAUDE_CODE_SUBPROCESS_ENV_SCRUBsandbox.credentials(mode: "mask")
対象範囲の指定CLAUDE_CODE_SUBPROCESS_ENV_SCRUBClaude Codeが認識する認証情報全体を一括で遮断sandbox.credentials(mode: "mask")files/envVarsに列挙した変数・パスだけを個別指定
実値の扱いCLAUDE_CODE_SUBPROCESS_ENV_SCRUB子プロセスは一切受け取れないsandbox.credentials(mode: "mask")センチネルを見せ、許可済み通信先にだけ実値を差し替え
認証が必要な通信CLAUDE_CODE_SUBPROCESS_ENV_SCRUBghnpm publish等は認証に失敗しうるsandbox.credentials(mode: "mask")プロキシ経由の通信ならツールを動かしたまま保護できる
適用対象CLAUDE_CODE_SUBPROCESS_ENV_SCRUBBashツール・hooks・MCP stdioサーバーsandbox.credentials(mode: "mask")サンドボックス化されたコマンド全般

信頼していないhooksやMCPサーバーを動かすときのように、「そもそも認証情報を見せたくない」ならCLAUDE_CODE_SUBPROCESS_ENV_SCRUBが向いています。一方でghnpmのように認証情報を使って実際に通信する必要があるツールもあります。そうしたツールを動かしながら保護したいならsandbox.credentialsのmaskモードのほうが適しています。設定の書き方は認証情報マスキングの設定ガイドにまとめています。両方を同時に設定してもエラーにはなりません。ただしBashツールではCLAUDE_CODE_SUBPROCESS_ENV_SCRUBの「一切見せない」が先に効きます。mask側の差し替えが意味を持つのは、MCPサーバーなどスクラブの対象外プロセス経由の場面に限られます。サンドボックス全体の設計はClaude Codeのサンドボックス設計にまとめています。envブロックの書き方全般はClaude Code設定ガイドを参照してください。

まとめ

CLAUDE_CODE_SUBPROCESS_ENV_SCRUBは、Bash・hooks・MCP stdioサーバーという3種類の子プロセスから認証情報を丸ごと消す環境変数です。Linuxではあわせてプロセスの/proc分離も効きます。ただし副作用が2つあります。ps/pgrep/killがホスト側を見られなくなること、そしてsandbox.autoAllowBashIfSandboxedの自動許可が止まることです。どちらも有効化する前に把握しておく価値があります。ghnpm publishのように認証情報で通信するツールを保護したいだけなら、実値を差し替えて渡すsandbox.credentialsのmaskモードのほうが実務では扱いやすい場面もあります。外部コントリビューターのPRをCIで動かす構成や、信頼できないMCPサーバー・hooksを扱う環境では、CLAUDE_CODE_SCRIPT_CAPSと組み合わせた運用を検討する価値があります。有効化する前に、接続中のMCPサーバーとhooksが認証情報を必要としていないか、一度棚卸ししておくと移行がスムーズです。

この記事を共有:XはてブLinkedIn