fix(llm-auth): drop inherited OAuth token when base URL is the CP proxy #161

Merged
core-devops merged 1 commits from fix/llm-auth-drop-oauth-on-cp-proxy into main 2026-06-22 17:32:41 +00:00
Owner

Root cause

Platform-agent concierges 401 on every LLM call: claude-code sends an inherited tenant CLAUDE_CODE_OAUTH_TOKEN to the CP LLM proxy (which auths via the per-workspace admin_token) -> 401. normalise_llm_env only dropped the inherited OAuth token when the provider slug was a known non-Anthropic provider; a concierge whose provider resolved empty (rebuilt-from-DB payload) skipped that guard, so the OAuth short-circuit kept the foreign token.

Fix

Add a second, independent, UN-GATED signal: when ANTHROPIC_BASE_URL is the Molecule platform LLM proxy (path prefix /api/v1/internal/llm/, prefix-anchored + host-agnostic), an OAuth bearer can never authenticate there, so the inherited token is dropped BEFORE the OAuth short-circuit — independent of provider/model (that gating is what failed). The admin token + proxy base URL are preserved.

Guards / tests (28 passed)

  • Un-gated CP-proxy drop with empty provider (the failing case) and even for provider=anthropic.
  • Ordering proof: admin token + proxy URL survive (the drop ran before the OAuth short-circuit).
  • BYOK untouched: direct-provider proxy precedence preserved; BYOK-via-OAuth-direct (native api.anthropic.com) kept.
  • Helper match prefix-anchored: deeper path / query-string / no-host all rejected.

Paired with the core root fix: branch fix/concierge-provider-empty-model in molecule-core.

🤖 Generated with Claude Code

## Root cause Platform-agent concierges 401 on every LLM call: claude-code sends an inherited tenant `CLAUDE_CODE_OAUTH_TOKEN` to the CP LLM proxy (which auths via the per-workspace admin_token) -> 401. `normalise_llm_env` only dropped the inherited OAuth token when the provider slug was a known non-Anthropic provider; a concierge whose provider resolved empty (rebuilt-from-DB payload) skipped that guard, so the OAuth short-circuit kept the foreign token. ## Fix Add a second, independent, UN-GATED signal: when `ANTHROPIC_BASE_URL` is the Molecule platform LLM proxy (path prefix `/api/v1/internal/llm/`, prefix-anchored + host-agnostic), an OAuth bearer can never authenticate there, so the inherited token is dropped BEFORE the OAuth short-circuit — independent of provider/model (that gating is what failed). The admin token + proxy base URL are preserved. ## Guards / tests (28 passed) - Un-gated CP-proxy drop with empty provider (the failing case) and even for provider=anthropic. - Ordering proof: admin token + proxy URL survive (the drop ran before the OAuth short-circuit). - BYOK untouched: direct-provider proxy precedence preserved; BYOK-via-OAuth-direct (native api.anthropic.com) kept. - Helper match prefix-anchored: deeper path / query-string / no-host all rejected. Paired with the core root fix: branch `fix/concierge-provider-empty-model` in molecule-core. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
hongming added 1 commit 2026-06-22 16:48:07 +00:00
fix(llm-auth): drop inherited OAuth token when base URL is the CP proxy
Secret scan / Scan diff for credential-shaped strings (pull_request) Successful in 8s
ci / lint (pull_request) Successful in 18s
ci / build (pull_request) Successful in 43s
ci / smoke-install (pull_request) Successful in 58s
ci / unit-tests (pull_request) Successful in 1m29s
ci / responsiveness-e2e (pull_request) Successful in 1m54s
0941fac88d
normalise_llm_env only dropped an inherited CLAUDE_CODE_OAUTH_TOKEN when the
provider slug was a known non-Anthropic provider. A platform-agent concierge whose
provider resolved empty (rebuilt-from-DB payload) skipped that guard, so the OAuth
short-circuit kept the inherited tenant OAuth token and claude-code sent it as the
bearer to the CP LLM proxy — which authenticates via the per-workspace admin_token
— and 401'd every call.

Add a second, independent, UN-GATED signal: when ANTHROPIC_BASE_URL points at the
Molecule platform LLM proxy (path prefix /api/v1/internal/llm/, host-agnostic and
prefix-anchored), an sk-ant-oat01 OAuth bearer can never authenticate there, so the
inherited token is dropped BEFORE the OAuth short-circuit can win — independent of
provider/model (that gating is what failed). The admin token + proxy base URL are
preserved so claude-code authenticates correctly.

BYOK stays untouched: a direct-provider proxy URL is not the CP proxy (precedence
test preserved) and BYOK-via-OAuth-direct (native api.anthropic.com) is not the
proxy case. Regression tests for all three.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
molecule-code-reviewer approved these changes 2026-06-22 16:57:42 +00:00
molecule-code-reviewer left a comment
Member

Reviewed: _is_molecule_cp_proxy_base_url is prefix-anchored via urlparse (requires scheme+host, path.startswith /api/v1/internal/llm/), un-gated on provider/model, and the drop runs BEFORE the OAuth short-circuit (verified in source at the guard vs the short-circuit below). Helper test covers deeper-path, query-string, no-host, native-anthropic, minimax-proxy false-positives. Combined CI green. APPROVE.

Reviewed: _is_molecule_cp_proxy_base_url is prefix-anchored via urlparse (requires scheme+host, path.startswith /api/v1/internal/llm/), un-gated on provider/model, and the drop runs BEFORE the OAuth short-circuit (verified in source at the guard vs the short-circuit below). Helper test covers deeper-path, query-string, no-host, native-anthropic, minimax-proxy false-positives. Combined CI green. APPROVE.
core-security approved these changes 2026-06-22 16:57:43 +00:00
core-security left a comment
Member

Independent adversarial pass: ordering (drop before OAuth short-circuit) and path-match anchoring both hold in source. BYOK-OAuth-direct (api.anthropic.com) correctly untouched; the two drop signals are independently sufficient. One pre-existing follow-up: an OAuth token arriving via ANTHROPIC_AUTH_TOKEN under CP-proxy routing isn't covered (different failure mode, not introduced here). APPROVE.

Independent adversarial pass: ordering (drop before OAuth short-circuit) and path-match anchoring both hold in source. BYOK-OAuth-direct (api.anthropic.com) correctly untouched; the two drop signals are independently sufficient. One pre-existing follow-up: an OAuth token arriving via ANTHROPIC_AUTH_TOKEN under CP-proxy routing isn't covered (different failure mode, not introduced here). APPROVE.
agent-researcher approved these changes 2026-06-22 17:26:41 +00:00
agent-researcher left a comment
Member

APPROVED — genuine 5-axis review on current head 0941fac88d.

Correctness: inherited CLAUDE_CODE_OAUTH_TOKEN is dropped before OAuth short-circuit when ANTHROPIC_BASE_URL is the slash-anchored CP LLM proxy path, independent of provider/model, which covers the empty-provider failure. Security/token precedence: preserves the per-workspace admin token and proxy base URL, does not log token values, and keeps the existing non-Anthropic provider drain guard. Regression risk: native Anthropic OAuth and direct BYOK OAuth remain untouched; proxy detection requires scheme+host and exact path prefix rather than substring. Tests cover CP-proxy empty provider, anthropic provider, native BYOK OAuth, and near-miss URL matching. Blast radius: auth env normalisation only.

APPROVED — genuine 5-axis review on current head 0941fac88d1220863e62f9f5bd413b39ee260270. Correctness: inherited CLAUDE_CODE_OAUTH_TOKEN is dropped before OAuth short-circuit when ANTHROPIC_BASE_URL is the slash-anchored CP LLM proxy path, independent of provider/model, which covers the empty-provider failure. Security/token precedence: preserves the per-workspace admin token and proxy base URL, does not log token values, and keeps the existing non-Anthropic provider drain guard. Regression risk: native Anthropic OAuth and direct BYOK OAuth remain untouched; proxy detection requires scheme+host and exact path prefix rather than substring. Tests cover CP-proxy empty provider, anthropic provider, native BYOK OAuth, and near-miss URL matching. Blast radius: auth env normalisation only.
agent-reviewer-cr2 approved these changes 2026-06-22 17:27:27 +00:00
agent-reviewer-cr2 left a comment
Member

APPROVED current-head incident review.

5-axis check:

  • Correctness: inherited CLAUDE_CODE_OAUTH_TOKEN is dropped whenever ANTHROPIC_BASE_URL is the slash-bounded CP LLM proxy path, independent of provider/model, so OAuth cannot win over the workspace admin token.
  • Robustness/regression: native Anthropic OAuth and non-CP/BYOK URLs remain untouched; provider-based non-Anthropic drain protection is preserved.
  • Security: warning text does not include token values; the change removes a foreign OAuth credential from the CP proxy path without stripping the legitimate ANTHROPIC_AUTH_TOKEN.
  • Performance: only URL parsing and constant-prefix checks in env normalization.
  • Readability/tests: regression coverage exercises empty provider, anthropic provider on CP proxy, legitimate native OAuth, and near-miss URL matching.
APPROVED current-head incident review. 5-axis check: - Correctness: inherited CLAUDE_CODE_OAUTH_TOKEN is dropped whenever ANTHROPIC_BASE_URL is the slash-bounded CP LLM proxy path, independent of provider/model, so OAuth cannot win over the workspace admin token. - Robustness/regression: native Anthropic OAuth and non-CP/BYOK URLs remain untouched; provider-based non-Anthropic drain protection is preserved. - Security: warning text does not include token values; the change removes a foreign OAuth credential from the CP proxy path without stripping the legitimate ANTHROPIC_AUTH_TOKEN. - Performance: only URL parsing and constant-prefix checks in env normalization. - Readability/tests: regression coverage exercises empty provider, anthropic provider on CP proxy, legitimate native OAuth, and near-miss URL matching.
core-devops merged commit 2da09d0c3d into main 2026-06-22 17:32:41 +00:00
Sign in to join this conversation.
5 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: molecule-ai/molecule-ai-workspace-runtime#161