fix(auth): key admission-bearer substitution on transport, not provider name - #2169
Conversation
…er name An admission bearer is one of OUR secrets. The contract in src/codex/auth-context.ts is that it is either replaced with the stored main credential or the request fails before any I/O -- it must never reach an upstream. #2132 correctly stopped requiring a ChatGPT credential for routed providers, but it asked the question by provider NAME: codexAccountMode comes from providerCodexAccountMode, which special-cases the id "openai". The passthrough adapter asks the same question by TRANSPORT: isCanonicalOpenAiForwardProvider reads adapter, auth mode, and base URL, and when it says yes it copies the caller's Authorization header upstream. A provider row named anything else, pointed at the canonical ChatGPT backend with authMode "forward", satisfies the adapter and fails the name check. Substitution was skipped and the admission secret was forwarded to ChatGPT. Reproduced through the real adapter: URL: https://chatgpt.com/backend-api/codex/responses AUTH: Bearer ocx_data_this_is_our_proxy_key Substitution now consults the same authority the adapter does, so the transport that actually carries the header is what decides. A key-authenticated routed provider is still not canonical-forward, so the install #2132 was filed for keeps working without a ChatGPT login. The two new tests assert the invariant rather than the implementation: an admission bearer never reaches the wire for a canonical transport, whatever the row is called.
|
✅ Deterministic PR hygiene checks passed. |
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
📝 WalkthroughWalkthroughThe response authentication path now substitutes the stored main credential for custom-named providers that use canonical OpenAI forward routing. Tests verify fail-closed behavior without stored credentials and correct credential forwarding when one exists. ChangesCanonical forward credential handling
Estimated code review effort: 2 (Simple) | ~10 minutes Possibly related issues
Possibly related PRs
Suggested labels: Suggested reviewers: ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Summary
An admission bearer is one of our secrets. The contract in
src/codex/auth-context.tsis explicit: it is either replaced with the stored main credential, or the request fails before any I/O. It must never reach an upstream.Found while auditing
origin/main..origin/devfor release safety.The gap. #2132 correctly stopped requiring a ChatGPT credential for routed providers, but it asked the question by provider name —
codexAccountModecomes fromproviderCodexAccountMode, which special-cases the idopenai. The passthrough adapter asks the same question by transport:isCanonicalOpenAiForwardProviderreads adapter, auth mode, and base URL (openai-responses.ts:1451), and when it says yes it copies the caller'sAuthorizationheader upstream.Those two predicates disagree for one configuration: a provider row the operator named anything other than
openai, pointed at the canonical ChatGPT backend withauthMode: "forward". It satisfies the adapter and fails the name check, so substitution was skipped and the adapter forwarded our admission secret.Reproduced through the real adapter, no mocking of the code under test:
The fix. Substitution now consults the same authority the adapter does, so the transport that actually carries the header is what decides. A key-authenticated routed provider is still not canonical-forward, so the install #2132 was filed for keeps working without a ChatGPT login — that behavior is pinned by the three pre-existing tests, which stay green.
Two predicates answering one security question is the underlying bug; this leaves one authority.
Verification
bun run typecheck— clean.bun test --isolate tests/bearer-admission-routed-provider.test.ts tests/server-auth.test.ts tests/codex-auth-context.test.ts— 143 pass / 0 fail.src/server/responses/core.tsfails exactly the two new tests (3 pass / 2 fail). The three that stay green are [Bug] non-OpenAI providers unusable without a ChatGPT login after v2.23.0 #2132's behaviors, which is the evidence this fix did not undo the thing it builds on.The new tests assert the invariant — an admission bearer never reaches the wire for a canonical transport, whatever the row is named — rather than the implementation detail, so a future refactor cannot satisfy them by accident.
Checklist
This is the security-boundary surface
MAINTAINERS.mdreserves for explicit review. The change is strictly narrowing: it adds a condition under which substitution happens, and removes none.Summary by CodeRabbit