Skip to content

[Bug]: stale loopback proxy credentials survive the ocx claude base-URL rewrite #3004

Closed

Description

@lidge-jun

Client or integration

Claude Code

Area

CLI

Summary

buildClaudeEnv rewrites a stale loopback ANTHROPIC_BASE_URL to the current launch port but does not re-evaluate the Anthropic credential slots that were paired with the destination it just replaced.

The launcher already knows that a loopback ANTHROPIC_BASE_URL on a different port belongs to a previous opencodex launch: that is exactly the condition it logs and overwrites in src/cli/claude.ts (the Replacing stale opencodex ANTHROPIC_BASE_URL branch). An ANTHROPIC_AUTH_TOKEN inherited alongside it was minted by that other proxy, and after the rewrite it is carried into the new launch unchanged.

Two consequences, both on the subscription path:

  1. The token is not valid admission for this proxy. When the previous proxy required an admission key and this one does not, the launch is not merely mis-authenticated, it is silently pushed out of subscription mode.
  2. setDefault preserves any non-empty value, so this proxy's own configured key is never injected. hostOwnsAuthentication then evaluates against a foreign token, so CLAUDE_CODE_PROVIDER_MANAGED_BY_HOST is decided on stale evidence.

The subscription-preserving default immediately below the rewrite is explicit that setting ANTHROPIC_AUTH_TOKEN "disables claude.ai connectors and overrides the user's Claude login". A stale token reaching the child does precisely that: Claude Code authenticates as a host-managed provider instead of using the caller's own claude.ai OAuth, so native claude models no longer pass through with the caller's credential (wantsNativePassthrough in src/server/claude-messages.ts requires an sk-ant- credential on the request).

The existing PROXY_MARKER cleanup at the top of buildClaudeEnv and the inheritedTokenIsOurs check below both handle other shapes of this problem, which is why this specific pairing has stayed open: neither is keyed on the destination rewrite.

A genuine user sk-ant- credential must keep surviving the rewrite, because that is the credential native passthrough authenticates with.

Reproduction

  1. Start a proxy on port 19999 that requires an admission key, and launch ocx claude from it so the environment carries ANTHROPIC_BASE_URL=http://127.0.0.1:19999 plus that proxy's ANTHROPIC_AUTH_TOKEN.
  2. From the same shell, start a second proxy on 10100 with no apiKeys configured and run ocx claude.
  3. The launcher prints Replacing stale opencodex ANTHROPIC_BASE_URL http://127.0.0.1:19999 with http://127.0.0.1:10100.
  4. Inspect the spawned environment: ANTHROPIC_AUTH_TOKEN still holds the 19999 proxy's key, even though this launch requires no admission key and should have stayed token-free in subscription mode.

Expected: credentials recognized as opencodex admission material are dropped when their paired destination is replaced, so the launch either injects this proxy's own key or stays token-free.

Version

2.36.0

Operating system

macOS 15.5 (platform-independent, env assembly only)

Provider and model

anthropic / claude-opus-5 (subscription OAuth path)

Logs or error output

Replacing stale opencodex ANTHROPIC_BASE_URL http://127.0.0.1:19999 with http://127.0.0.1:10100.

Screenshots and supporting files

No response

Redacted configuration

{
  "port": 10100,
  "apiKeys": []
}

Activity

  1. added
    account-poolOAuth, credentials, Codex pool, quota, failover, plans
    cliCLI, config inject, packaging flags
    on Aug 30, 2026
  2. lidge-jun commented on Aug 30, 2026

    @lidge-jun
    OwnerAuthor

    리뷰 · 우선순위 74 / 80

    이 이슈는 ocx claude가 예전 루프백 프록시 주소를 새 포트로 바꿀 때, 그 주소에 짝지어져 있던 Anthropic 입장 토큰을 그대로 물려주는 버그를 보고한다. 지금 dev(bb6a6fbdf)의 src/cli/claude.ts buildClaudeEnv는 “다른 포트의 루프백 ANTHROPIC_BASE_URL은 예전 opencodex 실행이다”라고 이미 알고 주소를 덮어쓴다. 그런데 ANTHROPIC_AUTH_TOKEN/ANTHROPIC_API_KEY는 그 분기에서 다시 보지 않는다.

    그 결과 두 가지가 겹친다. 첫째, 예전 프록시가 발급한 토큰은 이번 프록시 입장에는 쓸모가 없다. 둘째, setDefault는 비어 있지 않은 값을 보존하므로 이번 프록시의 키가 있어도 주입되지 않고, hostOwnsAuthentication은 남의 토큰을 근거로 CLAUDE_CODE_PROVIDER_MANAGED_BY_HOST를 켠다. 입장 키가 필요 없는 프록시에서는 구독 OAuth로 남아야 하는데, Claude Code가 호스트 관리 공급자로 떠서 사용자 로그인·커넥터를 덮어쓴다. 주소 교체 바로 아래 “토큰을 넣으면 claude.ai를 끈다”는 주석이 경고하는 바로 그 상황이다.

    기존 PROXY_MARKER 제거와 inheritedTokenIsOurs 검사는 다른 모양의 문제를 다루고, “주소를 바꿨다”는 조건에는 묶여 있지 않다. 그래서 이 짝이 비어 있었다. 사용자 sk-ant- 키는 wantsNativePassthrough(src/server/claude-messages.ts) 때문에 주소 교체 후에도 살아남아야 한다. 재현 단계(19999에서 입장 키 있는 프록시 → 10100에서 키 없는 프록시)도 명확하다.

    착륙 PR은 이미 열려 있다. #3005가 같은 설명을 코드로 옮겼고, stale rewrite 분기 안에서 PROXY_MARKER/isProxyAdmissionSecret만 지운 뒤 회귀 테스트 세 개를 붙였다. types/config 대형 분할과 무관한 CLI 버그라 닫고 다시 열 대상이 아니다.

    이슈 본문 / buildClaudeEnv stale rewrite - 주소만 고치고 자격 증명 슬롯을 안 본다는 진단이 현재 HEAD와 맞다. 추가 재현 로그는 없어도 된다.

    이슈 본문 / setDefault·hostOwnsAuthentication - 구독 경로에서 OAuth가 덮이는 인과도 코드 순서와 일치한다.

    #3005 - 수정·테스트·Closes #3004가 이미 붙어 있다. CI만 남았다.

    메인테이너의 판단이 필요한 지점

    너의 추천
    #3005 CI가 초록이면 머지하고 이 이슈는 자동 닫힘에 맡긴다. 별도 설계 이슈로 키울 필요는 없다. 중복 수정 PR이 오면 닫는다.

    이 댓글은 grok-bot이 작성했습니다

  3. added a commit that references this issue on Aug 30, 2026
    c2778ca
  4. lidge-jun commented on Aug 30, 2026

    @lidge-jun
    OwnerAuthor

    Fixed on dev in c2778ca (#3005).

    The stale-destination rewrite in buildClaudeEnv now drops the credential slots paired with the replaced destination, but only for values matched by PROXY_MARKER or isProxyAdmissionSecret. A genuine user sk-ant- credential still survives the rewrite, because that is the credential native passthrough authenticates with.

    Three regression cases in tests/claude-cli.test.ts cover it: the stale admission token is dropped on a proxy with no configured keys, this proxy's own key is injected when it does configure one, and a user sk-ant- credential is preserved. Both new assertions were driven red against the unpatched launcher.

    Merged with --admin on maintainer authority. Exact-head CI was green on 22 checks; the three failures were the repository-wide package.json 2.36.0 versus released tag v2.36.0 version-line gate plus one unrelated macOS SIGHUP launcher case, both reproduced on pristine origin/dev without this change.

  5. added a commit that references this issue on Sep 14, 2026
    d51c7bb
  6. added a commit that references this issue on Sep 17, 2026
    c5e4b94
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    account-poolOAuth, credentials, Codex pool, quota, failover, plansbugSomething isn't workingcliCLI, config inject, packaging flags

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions