Skip to content

[WRONG BRANCH] fix(codex): bound entitlement version cache misses - #392

Draft
luvs01 wants to merge 1 commit into
mainfrom
codex/propose-fix-for-client_version-vulnerability
Draft

[WRONG BRANCH] fix(codex): bound entitlement version cache misses#392
luvs01 wants to merge 1 commit into
mainfrom
codex/propose-fix-for-client_version-vulnerability

Conversation

@luvs01

@luvs01 luvs01 commented Aug 31, 2026

Copy link
Copy Markdown
Owner

Motivation

  • A caller-controlled client_version query on GET /v1/models could be cycled to create renewable cache misses that spawned authenticated upstream /backend-api/codex/models requests under every stored account token, allowing sustained request amplification and causing legitimate gated-model checks to fail-closed.

Description

  • Add a per-account, per-credential completed-miss budget (MODEL_ROSTER_VERSION_MISSES_PER_ACCOUNT_MAX) and an accountModelsMisses map to limit how many caller-selected versions may trigger upstream requests in one roster TTL.
  • Refuse further caller-selected-version requests once the per-account miss budget is exhausted by returning an unconfirmed (fail-closed) cached answer without making another authenticated upstream call, while preserving concurrency caps for in-flight flights (MODEL_ROSTER_FLIGHTS_PER_ACCOUNT_MAX).
  • Exempt the trusted local runtime/bundled gated-floor refresh path so the legitimate refresh for the runtime-selected version remains available even after an attacker consumes the caller-selected allowance.
  • Clear the new miss accounting when credentials are invalidated and include it in the test reset seam, and add a focused regression test proving sequential version cycling is bounded while the trusted refresh path stays operational.

Testing

  • Ran the focused entitlement tests with bun test tests/codex-model-entitlements.test.ts, which passed (21 tests, 0 failures).
  • Ran static checks with bun run typecheck and the privacy check with bun run privacy:scan, both of which succeeded.
  • The full repository test run (bun run test) was executed; the entitlement-focused changes pass, while unrelated environment/timing tests in the full suite reported known external failures that are not caused by this change (these were observed but are outside the modified subsystem).

Codex Task

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Aug 31, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-08-31T01:04:15.838620Z 01d1186 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@coderabbitai

coderabbitai Bot commented Aug 31, 2026

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 04af89d6-309d-4063-82e1-b6309d6a1221


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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 01d1186544

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +486 to +499
const recent = (accountModelsMisses.get(missKey) ?? [])
.filter(startedAt => startedAt > now - MODEL_ROSTER_TTL_MS);
if (recent.length >= MODEL_ROSTER_VERSION_MISSES_PER_ACCOUNT_MAX) {
accountModelsMisses.set(missKey, recent);
return {
credentialIdentity: credential.credentialIdentity,
clientVersion,
expiresAt: now,
models: new Set(),
confirmed: false,
};
}
recent.push(now);
accountModelsMisses.set(missKey, recent);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve retries for a repeated client version

When one legitimate non-runtime client_version is retried during an upstream outage, every retry after the 15-second failure-cache expiry appends another timestamp because the budget does not record which version caused the miss. After four failed attempts, even that same version is refused until the five-minute roster window expires, so an upstream recovery after roughly one minute can leave gated models unavailable for several additional minutes. Track distinct versions as documented, or allow a previously counted version to continue retrying on the existing failure TTL.

Useful? React with 👍 / 👎.

Comment on lines +485 to +487
const missKey = `${credential.accountId}\u0000${credential.credentialIdentity}`;
const recent = (accountModelsMisses.get(missKey) ?? [])
.filter(startedAt => startedAt > now - MODEL_ROSTER_TTL_MS);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Remove stale credential generations from miss accounting

For Pool accounts, a normal access-token refresh increments the credential generation, so this identity-qualified key changes even when the account ID stays the same. Expired entries are pruned only when that exact old key is queried again, while the invalidation function is called only on model-400 retry paths, not routine credential refreshes; consequently, an active caller can leave one permanent map entry per account generation for the lifetime of the process. Replace the prior identity's entry when a generation changes or opportunistically remove expired keys so this new protection does not introduce an unbounded memory cache.

Useful? React with 👍 / 👎.

@github-actions github-actions Bot added the bug Something isn't working label Aug 31, 2026
@github-actions

Copy link
Copy Markdown

Deterministic PR hygiene checks passed.

@github-actions github-actions Bot changed the title fix(codex): bound entitlement version cache misses [WRONG BRANCH] fix(codex): bound entitlement version cache misses Aug 31, 2026
@github-actions

Copy link
Copy Markdown

⏳ DRAFT

  • wrong target branch (main); retarget to dev.

What to do

  • Retarget this PR to dev — all contributions go to dev.

Its title has been prefixed with [WRONG BRANCH].
This pull request is being kept as a draft automatically. Once every issue above is resolved, it will be marked ready for review again.

@github-actions
github-actions Bot marked this pull request as draft August 31, 2026 01:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

aardvark bug Something isn't working codex

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant