fix(runtime#162): drop inherited OAuth token from ANTHROPIC_AUTH_TOKEN under CP-proxy routing #165
Reference in New Issue
Block a user
Delete Branch "fix/162-oauth-via-anthropic-auth-token-under-cp-proxy"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
What
Closes runtime#162: OAuth-leak via
ANTHROPIC_AUTH_TOKENunder CP-proxy routing — the second variant of the foreign-OAuth drop guard introduced in #161 (which coveredCLAUDE_CODE_OAUTH_TOKEN; this one coversANTHROPIC_AUTH_TOKEN).The bug
When an inherited Anthropic OAuth token (prefix
sk-ant-oat01-*) arrived viaANTHROPIC_AUTH_TOKEN(notCLAUDE_CODE_OAUTH_TOKEN) whileANTHROPIC_BASE_URLpointed at the Molecule platform LLM proxy,normalise_llm_env'skind=="oauth"branch RENAMED the token toCLAUDE_CODE_OAUTH_TOKENAND STRIPPED the proxy base URL. The agent then talked directly toapi.anthropic.comusing the inherited OAuth token — silent native-Anthropic billing leak, the 2026-05-28 drain shape.This is the second variant of the bug #161 fixed for
CLAUDE_CODE_OAUTH_TOKEN. Discovered during the #3160/#161 review (CEO adversarial pass); it was NOT introduced by those PRs.The fix
Mirror #161's structure for the
ANTHROPIC_AUTH_TOKENpath. The detection signal (cp_proxy_routed = _is_molecule_cp_proxy_base_url(ANTHROPIC_BASE_URL)) is the same host-agnostic, path-prefix-anchored check on the Molecule proxy URL — so the two guards stay in lockstep.When
cp_proxy_routedis true:ANTHROPIC_AUTH_TOKEN(it cannot authenticate against the per-workspace admin-token proxy anyway — would 401)ANTHROPIC_BASE_URL(the SDK still needs it to reach the proxy with the workspace admin token, NOT the dropped OAuth bearer — removing the URL would force the SDK back toapi.anthropic.com, which is exactly the leak this branch is closing)detected_kind = "oauth_dropped_cp_proxy", emit an operator-friendly warningTests (7 new)
test_oauth_via_anthropic_auth_token_under_cp_proxy_is_dropped— main case: token dropped, proxy URL preservedtest_oauth_via_anthropic_auth_token_to_native_anthropic_still_renamed— control: BYOK-via-OAuth-direct still renamestest_oauth_via_anthropic_auth_token_to_byok_proxy_still_renamed— control: non-CP proxy still renamestest_oauth_via_anthropic_auth_token_under_cp_proxy_does_not_leak_token— security: warning contains no token bytes (even prefixes)test_oauth_via_anthropic_auth_token_under_cp_proxy_works_with_provider_arg— UN-GATED on provider (same as #161)test_oauth_via_anthropic_auth_token_under_cp_proxy_is_idempotent— second call is a no-op (boot loop doesn't re-leak)test_summary_renders_oauth_dropped_cp_proxy_without_error— boot-log pathpytest tests/test_llm_auth.py→ 35/35 pass (was 28).Why this is independent of the #3164 deployment-pipeline gap
The PM check was: "does this depend on the same concierge MCP-surfacing machinery that's red (#3164 deployment gap)?" — No. This is a pure
normalise_llm_envenv-var rename/drop branch in a runtime file. It does not touch the platform-agent concierge identity gate, MCP-present delivery, the heartbeat, the operator deployment pipeline, or any of the red #3164 surface. The fix lands and the LLM proxy gets a cleanANTHROPIC_AUTH_TOKEN(the workspace's admin token) without inheriting the tenant's stray OAuth — the bug class is fully closed regardless of the operator's #3164 redeploy.Scope
Single-purpose, scoped to issue #162. ~30 lines of fix code + ~130 lines of test code; no other paths touched. Behaviour-preserving for the non-CP-proxy paths (covered by the control tests above).
Gate
APPROVE on
8dd05923e3(target=main).Security/RCA review: the fix closes the runtime#162 leak shape. When ANTHROPIC_AUTH_TOKEN contains an OAuth token and ANTHROPIC_BASE_URL is the Molecule CP proxy, normalise_llm_env now drops ANTHROPIC_AUTH_TOKEN, does not rename it to CLAUDE_CODE_OAUTH_TOKEN, and preserves the CP proxy base URL. That removes the residual native-Anthropic fallback path that previously happened through rename + proxy URL stripping.
Edge cases look correctly bounded: the CP-proxy predicate is host-agnostic but path-prefix anchored on /api/v1/internal/llm/ with scheme+host required, so query/deep-path false positives do not match. Native Anthropic and non-CP BYOK proxy OAuth paths retain their prior behavior. This is consistent with the #161 CLAUDE_CODE_OAUTH_TOKEN guard: both OAuth var shapes are dropped under CP-proxy routing, and neither warning leaks token bytes.
CI on this head is green: secret scan, lint, build, smoke-install, unit-tests, responsiveness-e2e. Local targeted check: tests/test_llm_auth.py passed 35/35.
APPROVE on
8dd05923e3(target=main).Security review:
CI: own-head CI green.