source dump of claude code
at main 99 lines 4.0 kB view raw
1import { isEnvTruthy } from './envUtils.js' 2 3/** 4 * Env vars to strip from subprocess environments when running inside GitHub 5 * Actions. This prevents prompt-injection attacks from exfiltrating secrets 6 * via shell expansion (e.g., ${ANTHROPIC_API_KEY}) in Bash tool commands. 7 * 8 * The parent claude process keeps these vars (needed for API calls, lazy 9 * credential reads). Only child processes (bash, shell snapshot, MCP stdio, LSP, hooks) are scrubbed. 10 * 11 * GITHUB_TOKEN / GH_TOKEN are intentionally NOT scrubbed — wrapper scripts 12 * (gh.sh) need them to call the GitHub API. That token is job-scoped and 13 * expires when the workflow ends. 14 */ 15const GHA_SUBPROCESS_SCRUB = [ 16 // Anthropic auth — claude re-reads these per-request, subprocesses don't need them 17 'ANTHROPIC_API_KEY', 18 'CLAUDE_CODE_OAUTH_TOKEN', 19 'ANTHROPIC_AUTH_TOKEN', 20 'ANTHROPIC_FOUNDRY_API_KEY', 21 'ANTHROPIC_CUSTOM_HEADERS', 22 23 // OTLP exporter headers — documented to carry Authorization=Bearer tokens 24 // for monitoring backends; read in-process by OTEL SDK, subprocesses never need them 25 'OTEL_EXPORTER_OTLP_HEADERS', 26 'OTEL_EXPORTER_OTLP_LOGS_HEADERS', 27 'OTEL_EXPORTER_OTLP_METRICS_HEADERS', 28 'OTEL_EXPORTER_OTLP_TRACES_HEADERS', 29 30 // Cloud provider creds — same pattern (lazy SDK reads) 31 'AWS_SECRET_ACCESS_KEY', 32 'AWS_SESSION_TOKEN', 33 'AWS_BEARER_TOKEN_BEDROCK', 34 'GOOGLE_APPLICATION_CREDENTIALS', 35 'AZURE_CLIENT_SECRET', 36 'AZURE_CLIENT_CERTIFICATE_PATH', 37 38 // GitHub Actions OIDC — consumed by the action's JS before claude spawns; 39 // leaking these allows minting an App installation token → repo takeover 40 'ACTIONS_ID_TOKEN_REQUEST_TOKEN', 41 'ACTIONS_ID_TOKEN_REQUEST_URL', 42 43 // GitHub Actions artifact/cache API — cache poisoning → supply-chain pivot 44 'ACTIONS_RUNTIME_TOKEN', 45 'ACTIONS_RUNTIME_URL', 46 47 // claude-code-action-specific duplicates — action JS consumes these during 48 // prepare, before spawning claude. ALL_INPUTS contains anthropic_api_key as JSON. 49 'ALL_INPUTS', 50 'OVERRIDE_GITHUB_TOKEN', 51 'DEFAULT_WORKFLOW_TOKEN', 52 'SSH_SIGNING_KEY', 53] as const 54 55/** 56 * Returns a copy of process.env with sensitive secrets stripped, for use when 57 * spawning subprocesses (Bash tool, shell snapshot, MCP stdio servers, LSP 58 * servers, shell hooks). 59 * 60 * Gated on CLAUDE_CODE_SUBPROCESS_ENV_SCRUB. claude-code-action sets this 61 * automatically when `allowed_non_write_users` is configured — the flag that 62 * exposes a workflow to untrusted content (prompt injection surface). 63 */ 64// Registered by init.ts after the upstreamproxy module is dynamically imported 65// in CCR sessions. Stays undefined in non-CCR startups so we never pull in the 66// upstreamproxy module graph (upstreamproxy.ts + relay.ts) via a static import. 67let _getUpstreamProxyEnv: (() => Record<string, string>) | undefined 68 69/** 70 * Called from init.ts to wire up the proxy env function after the upstreamproxy 71 * module has been lazily loaded. Must be called before any subprocess is spawned. 72 */ 73export function registerUpstreamProxyEnvFn( 74 fn: () => Record<string, string>, 75): void { 76 _getUpstreamProxyEnv = fn 77} 78 79export function subprocessEnv(): NodeJS.ProcessEnv { 80 // CCR upstreamproxy: inject HTTPS_PROXY + CA bundle vars so curl/gh/python 81 // in agent subprocesses route through the local relay. Returns {} when the 82 // proxy is disabled or not registered (non-CCR), so this is a no-op outside 83 // CCR containers. 84 const proxyEnv = _getUpstreamProxyEnv?.() ?? {} 85 86 if (!isEnvTruthy(process.env.CLAUDE_CODE_SUBPROCESS_ENV_SCRUB)) { 87 return Object.keys(proxyEnv).length > 0 88 ? { ...process.env, ...proxyEnv } 89 : process.env 90 } 91 const env = { ...process.env, ...proxyEnv } 92 for (const k of GHA_SUBPROCESS_SCRUB) { 93 delete env[k] 94 // GitHub Actions auto-creates INPUT_<NAME> for `with:` inputs, duplicating 95 // secrets like INPUT_ANTHROPIC_API_KEY. No-op for vars that aren't action inputs. 96 delete env[`INPUT_${k}`] 97 } 98 return env 99}