Skip to content

[Bug]: account-gated native models are advertised and routed through unentitled ChatGPT accounts #2097

Closed

Description

@Ingwannu

Client or integration

Codex App

Area

Authentication and account pool

Summary

OpenCodex advertises the account-gated gpt-daybreak-blue-latest model to every ChatGPT/Codex account after #1814, even when the authenticated account's upstream model catalog does not contain that slug. In Pool mode this lets a bare Daybreak request bind to an unentitled account and relay the upstream 400:

{"detail":"The 'gpt-daybreak-blue-latest' model is not supported when using Codex with a ChatGPT account."}

The catalog and runtime should use authenticated per-account /models evidence for account-gated native models. A gated row should be visible only when at least one eligible account reports it, selector-qualified rows should exist only for selectors whose account reports it, and Pool routing should exclude accounts that do not report it.

Reproduction

  1. Configure the canonical openai Codex-forward provider in Pool mode with two valid ChatGPT accounts.
  2. Use one account whose authenticated GET /backend-api/codex/models?client_version=0.0.0 response includes gpt-daybreak-blue-latest, and one whose response does not.
  3. Run catalog sync. Observe that the bare Daybreak row and every account-selector clone are generated from the static native set instead of the per-account model rosters.
  4. Allow an unqualified Daybreak request to select the unentitled account, or select that account's qualified row.
  5. Observe the upstream 400 quoted above.

This is distinct from #1747. That draft proposes a broad user-configurable custom-model account binding across GUI, CLI, API, docs, and routing. This bug is the narrower built-in native entitlement boundary: discovery and automatic Pool routing should never offer an account-gated native model through an account that upstream says cannot use it.

Version

2.25.0 / current dev at a5ec64172

Operating system

Ubuntu 22.04 Linux

Provider and model

OpenAI ChatGPT/Codex forward provider / gpt-daybreak-blue-latest

Logs or error output

{"detail":"The 'gpt-daybreak-blue-latest' model is not supported when using Codex with a ChatGPT account."}

Screenshots and supporting files

Authenticated, redacted model-discovery comparison on the same host:

main account: gpt-5.6-sol, gpt-daybreak-blue-latest
secondary account: gpt-5.6-sol

The local usage ledger also shows successful Daybreak requests resolving to gpt-5.6-sol on the entitled account and exact unsupported-model 400s when the gated route is rejected. No tokens, account ids, emails, or request bodies are included.

Redacted configuration

{
  "providers": {
    "openai": {
      "adapter": "openai-responses",
      "baseUrl": "https://chatgpt.com/backend-api/codex",
      "authMode": "forward",
      "codexAccountMode": "pool"
    }
  },
  "codexAccounts": [
    { "id": "<redacted-secondary>", "plan": "plus" }
  ]
}

Checks

  • I searched existing issues and documentation.
  • I removed secrets, tokens, account details, request credentials, and personal data.

Activity

  1. added
    account-poolOAuth, credentials, Codex pool, quota, failover, plans
    catalogModel catalog, slugs, visibility, routed entries
    on Aug 19, 2026
  2. coderabbitai commented on Aug 19, 2026

    @coderabbitai
    Contributor
    🔗 Related PRs

    #426 - feat(codex): add account-qualified model namespaces [open]
    #671 - feat(codex): add exact account routing [merged]
    #949 - feat(codex): add account-qualified catalog entries [merged]
    #1212 - feat(codex): converge account picker catalogs [merged]
    #1515 - fix(codex): preserve account-scoped native model ids [merged]


    📝 Issue Planner

    Check the box below or use the @coderabbitai plan command to generate an implementation plan and prompts that you can use with your favorite coding assistant.

    • Create Plan

    🧪 Issue enrichment is currently in open beta.

    To disable automatic issue enrichment, add the following to your .coderabbit.yaml:

    issue_enrichment:
      auto_enrich:
        enabled: false

    💬 Have feedback or questions? Drop into our discord!

  3. Ingwannu commented on Aug 19, 2026

    @Ingwannu
    OwnerAuthor

    Implemented in #2101. The fix now uses each authenticated ChatGPT account’s own Codex model roster as the entitlement authority, filters unentitled catalog/selector rows, excludes unentitled Pool accounts before dispatch, and bounds unsupported-model recovery to confirmed eligible accounts. Local focused tests, typecheck, privacy scan, docs build, and a real Daybreak request are green. Because this changes authentication and credential-selection boundaries, I requested explicit security review from @lidge-jun and will not merge before that approval and required exact-head CI.

  4. Ingwannu commented on Aug 19, 2026

    @Ingwannu
    OwnerAuthor

    Confirmed with live evidence: the account roster currently advertises gpt-daybreak-blue-latest with supported_in_api: true, yet upstream request shards can still reject the same entitled account repeatedly. After applying the exact-head local overlay from #2101, a real streamed probe hit six consecutive exact unsupported-model 400s and succeeded on send 7 as gpt-5.6-sol (HTTP 200, DAYBREAK_OK). PR #2101 now bounds this recovery at eight total sends while rechecking the exact rejection and fresh same-account entitlement before each later send. It remains pending owner review and required CI.

  5. Ingwannu commented on Aug 19, 2026

    @Ingwannu
    OwnerAuthor

    Further live evidence changed the fix from retry-only to deterministic wire normalization. One entitled Daybreak request exhausted all 8 retry sends, and Codex also emitted prompt_cache_retention is not supported on this model. PR #2101 now keeps Daybreak as the entitlement/UI identity but sends the successful serving id gpt-5.6-sol after entitlement selection and removes only the unsupported retention hint. Five real local streamed probes, each including prompt_cache_retention: "24h", passed on send 1 with HTTP 200 and no relevant error. This remains pending owner review and exact-head CI.

  6. Ingwannu commented on Aug 19, 2026

    @Ingwannu
    OwnerAuthor

    The repeated local failure had one additional boundary: long-context auto-compaction uses /v1/responses/compact, which bypassed the ordinary Daybreak wire normalization. PR #2101 exact head e01b2fb01 now routes entitled Daybreak compaction through streaming /responses, sends the stable gpt-5.6-sol wire model without the unsupported retention hint, and returns the resulting opaque encrypted compaction item. Local OCX 2.25.0 now completes the real compact request with HTTP 200; focused tests are 7/7 and typecheck is green. The PR remains unmerged pending owner review and exact-head CI.

  7. lidge-jun commented on Aug 19, 2026

    @lidge-jun
    Owner

    리뷰 · 우선순위 56 / 80

    Pool 모드에서 gpt-daybreak-blue-latest가 자격 없는 ChatGPT 계정에도 카탈로그에 뜨고, 그 계정으로 라우팅되면 업스트림 400이 난다. The 'gpt-daybreak-blue-latest' model is not supported when using Codex with a ChatGPT account. 기본 단일 계정 native 설치가 아니라 계정 풀 + 게이트된 모델 호환 문제라 56이다. 매일 재현되고 토큰이 새는 사고는 아니지만, 셀렉터가 잘못된 계정을 고르면 턴이 죽는다.

    #1814 이후 Daybreak는 정적 native 집합에 들어가 있다. src/codex/catalog/native-models.ts의 NATIVE_OPENAI_MODELS가 NATIVE_DAYBREAK_BLUE_MODEL을 포함한다. 주석이 이 이슈를 이미 인정한다. entitlement-gated라 인증된 /models에만 보이는데, 클린 설치에서 자격 있는 계정이 발견 못 하는 걸 막으려고 전역 행을 넣었고, 자격 없는 계정도 그 행을 본다. 선택은 400으로 끝난다고 적혀 있다. 리포터가 본 동작과 같다.

    셀렉터 복제도 같은 집합을 씨앗으로 쓴다. src/codex/catalog/metadata.ts의 accountBoundNativeOpenAiSlugsBySelector()는 모든 공개 셀렉터에 new Set(NATIVE_OPENAI_MODELS)를 넣는다. 관찰 루프는 SUPPORTED_NATIVE_OPENAI_SLUGS.has(slug)면 continue라, 정적 집합에 들어간 뒤에는 계정별 관찰이 Daybreak를 빼지 못한다. src/codex/catalog/sync.ts는 이 맵으로 bare 행과 selector/slug 클론을 만든다. 그래서 자격 없는 secondary에도 Daybreak qualified 행이 생긴다.

    라이브 발견이 이 구멍을 메우지 않는다. src/codex/catalog/provider-fetch.ts는 authMode === "forward"면 observed([], "authoritative")를 주고 주석이 ChatGPT backend has no /models다. 리포터가 쓴 GET /backend-api/codex/models?client_version=0.0.0은 OpenCodex 카탈로그 경로에 연결되어 있지 않다. 함수 이름을 새로 지어 호출부를 추측하지는 않는다. 지금 sync는 정적 집합과 캐시 관찰만 본다.

    Pool 라우팅이 계정 로스터로 거르지 않으면 자격 없는 계정이 bare Daybreak를 받아 400을 중계한다. disabledModels는 행을 숨길 뿐 런타임 거절이 아니라고 native-models 주석이 말한다. #1747의 사용자 지정 바인딩과 겹치지 않게, 이 버그는 내장 native entitlement 경계만 고치면 된다.

    해결방안

    Daybreak처럼 계정 게이트된 슬러그를 NATIVE_OPENAI_MODELS 전역 씨앗에서 분리한다. 자격 있는 계정이 한 번도 관찰되지 않은 클린 설치의 발견 문제는, 메인 계정 관찰이 있을 때만 bare 행을 넣는 쪽으로 옮긴다. accountBoundNativeOpenAiSlugsBySelector()는 게이트된 슬러그를 모든 셀렉터에 복사하지 말고, ACCOUNT_BOUND_OBSERVED_SELECTORS_MARKER 또는 해당 계정 로스터가 있는 셀렉터에만 넣는다. SUPPORTED_NATIVE_OPENAI_SLUGS에 들어 있다고 관찰 루프를 skip하면 안 된다. Pool 고를 때도 그 맵에 없는 계정은 Daybreak 후보에서 뺀다. ChatGPT /models를 새로 치려면 기존 provider-fetch 경로를 확인한 뒤에만 붙이고, 엔드포인트나 함수 이름은 추측하지 않는다. 회귀는 세 갈래다. 자격 있는 계정만 Daybreak가 보인다. 자격 없는 셀렉터 클론이 없다. 자격 없는 계정으로 bare Daybreak가 400을 내지 않는다.

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

  8. added a commit that references this issue on Aug 20, 2026
    0bce951
  9. lidge-jun commented on Aug 20, 2026

    @lidge-jun
    Owner

    Fixed on dev by #2146, merged as aa07bc3.

    Verified present on the branch rather than assumed: git log origin/dev shows the merge commit above. These PRs target dev rather than main, so GitHub does not auto-close the linked issue — this closure is manual.

    It ships in the next release cut from dev. Reopen if you still see it after updating.

  10. added 3 commits that reference this issue on Sep 17, 2026
    419141f
    608f0a5
    f177a2a
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 workingcatalogModel catalog, slugs, visibility, routed entries

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions