Skip to content

Fix Cloudflare 403s for openai-codex provider on server IPs#6391

Closed
admin28980 wants to merge 1 commit into
NousResearch:mainfrom
admin28980:fix/codex-cloudflare-headers
Closed

Fix Cloudflare 403s for openai-codex provider on server IPs#6391
admin28980 wants to merge 1 commit into
NousResearch:mainfrom
admin28980:fix/codex-cloudflare-headers

Conversation

@admin28980

Copy link
Copy Markdown
Contributor

Running Hermes with the openai-codex provider against chatgpt.com/backend-api/codex from any non-residential IP (VPS, Mac Mini, etc.) hits Cloudflare 403 JavaScript challenges. Laptops on home networks work fine, which makes this annoying to diagnose.

The issue is missing headers. The official codex-rs CLI sends ChatGPT-Account-Id (extracted from the JWT) and originator: codex_cli_rs, which Cloudflare uses to verify the request is from an authorized client. Without them, the OpenAI SDK's default User-Agent: OpenAI/Python ... looks like bot traffic and gets blocked.

The fix adds three headers when base_url contains chatgpt.com: ChatGPT-Account-Id (decoded from the access token), originator: hermes-agent, and a clean User-Agent. Applied in both AIAgent.__init__ and _update_base_url_headers to cover credential rotation. JWT decode is wrapped in try/except — if the token format changes, it skips the header rather than crashing.

~30 lines across two locations in run_agent.py. No new dependencies. Tested on a Hetzner VPS and a Mac Mini, both previously getting consistent 403s.

Add ChatGPT-Account-Id and originator headers when using chatgpt.com
backend-api endpoint. Matches official codex-rs CLI behavior to prevent
Cloudflare JavaScript challenges on non-residential IPs (VPS, Mac Mini,
always-on servers).

Applied in AIAgent.__init__ and _update_base_url_headers to cover both
initial setup and credential rotation paths.
saamuelng601-pixel added a commit to saamuelng601-pixel/hermes-agent that referenced this pull request Apr 16, 2026
ChatGPT's Codex backend sits behind Cloudflare's managed challenge. When
Hermes hits /responses or /chat/completions via the Python openai SDK,
Cloudflare sees the default "OpenAI/Python X.X.X" User-Agent and the
absence of ChatGPT-Account-Id, classifies the request as bot traffic, and
returns an HTML JS-challenge page that the openai SDK cannot handle.
Hermes reports this as "Non-retryable client error: <html>..." and
falls back to the secondary provider even when the Codex credentials
themselves are fresh and the account is under-quota.

The official Rust codex_cli_rs CLI sends three headers that Cloudflare
uses to verify the client:
  - User-Agent: codex_cli_rs/<version>
  - originator: codex_cli_rs
  - ChatGPT-Account-Id: <decoded from JWT>

This change installs an httpx.Client.send / AsyncClient.send wrapper that
inspects the outbound request, detects chatgpt.com hosts, and injects the
three headers (decoding ChatGPT-Account-Id from the bearer JWT). This
covers every OpenAI client Hermes creates — including auxiliary flows
(_try_codex, resolve_provider_client, _to_async_client) that PR NousResearch#6391
doesn't reach.

Tested locally: requests to /responses now return 200 (previously HTML 403).
/chat/completions returns 404 (backend doesn't expose that route for
Codex), which is the expected behavior — callers should use the
Responses API adapter.

Refs: NousResearch#6391 (upstream CF fix, scoped to main agent only), NousResearch#5169 (closed
earlier attempt), NousResearch#10016 (browser-compat Codex login roadmap).
@teknium1

Copy link
Copy Markdown
Contributor

Merged via PR #12664 — your commit 0760a4cd was cherry-picked with your authorship preserved in git log (now 4d0846b6 on main). Thanks @admin28980 for identifying and reporting the root cause.

Layered a follow-up fix on top to correct a few details vs upstream:

  • originator changed from hermes-agent to codex_cli_rs — Cloudflare's whitelist is codex_cli_rs, codex_vscode, codex_sdk_ts, and Codex* prefixes (per codex-rs default_client.rs).
  • Account-id header changed to canonical ChatGPT-Account-ID casing (from codex-rs auth.rs).
  • Extended to the auxiliary client path in agent/auxiliary_client.py so compression / title generation / vision / session search / web_extract also stop 403'ing from VPS IPs.
  • Consolidated the JWT-decode + header construction into a single _codex_cloudflare_headers() helper to avoid duplication.

13 regression tests added.

@teknium1 teknium1 closed this Apr 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants