feat(agent): add curl_cffi TLS impersonation transport for Cloudflare-protected endpoints - #41899
feat(agent): add curl_cffi TLS impersonation transport for Cloudflare-protected endpoints#41899Midnight-Kyo wants to merge 2 commits into
Conversation
tonydwb
left a comment
There was a problem hiding this comment.
Code Review Summary
Verdict: Approved
Analysis
Correctness ✅
- Subclassing httpx.Client and overriding only send() is the correct pattern to satisfy the OpenAI SDK's isinstance check while using curl_cffi for TLS.
- The CurlCffiClient properly strips httpx auto-headers (python-httpx User-Agent, Accept-Encoding, etc.) so curl_cffi sends browser-impersonating headers instead.
- Stream mode correctly returns b'' for streamed content — the caller handles streaming separately.
- Proxy support is wired through to curl_cffi session correctly.
Security ✅
- curl_cffi is a well-known library for browser TLS impersonation — this is not a security vulnerability, it's the intended use case.
- Import errors and setup failures gracefully fall back to stock httpx.
Code Quality ✅
- Clean separation: transport class is separate from the integration logic in run_agent.py.
- The _is_cloudflare_protected() check limits this to known endpoints only.
- Config-driven via model.tls_impersonate with sensible defaults.
Recommendation
Approve — well-engineered feature with proper fallback handling.
…-protected endpoints Add CurlCffiClient — an httpx.Client subclass that routes send() through curl_cffi with browser TLS fingerprint impersonation. Config-gated via model.tls_impersonate in config.yaml. When set to 'chrome124' (the profile confirmed to bypass chatgpt.com Cloudflare on this droplet), the Codex/OpenAI transport impersonates Chrome 124's JA3/JA4 TLS fingerprint, preventing the 403 + cf-mitigated: challenge that blocks httpx from datacenter IPs. Also strips httpx auto-headers (User-Agent: python-httpx/..., etc.) that otherwise flag requests as bot traffic regardless of TLS. Refs: NousResearch#30480 Co-Authored-By: Wahab (@Midnight-Kyo)
|
Update on this PR: I refreshed the branch onto the latest While refreshing it, I also tightened the implementation to make review/CI easier:
Verification run locally after the rebase:
Motivating endpoint behavior still reproduces:
Default behavior remains unchanged unless Happy to adjust the scope further if maintainers would prefer this split differently. |
|
Thanks for the focused transport implementation and streaming coverage. Problems
Suggested changes
This is an automated hermes-sweeper review. |
Problem
Cloudflare's WAF in front of
chatgpt.com/backend-api/codex(and other endpoints) blocks Pythonhttpxclients via TLS fingerprinting (JA3/JA4), not just HTTP headers. From datacenter/VPS IPs, even with correctoriginatorandUser-Agentheaders, requests get HTTP 403 +cf-mitigated: challenge.This is the deeper root cause beyond the User-Agent header fixes in #24295/#24559 — identified in #30480.
Fix
This PR adds
CurlCffiClient— anhttpx.Clientsubclass that routessend()throughcurl_cffiwith browser TLS fingerprint impersonation. It is config-gated viamodel.tls_impersonateinconfig.yaml:What happens when enabled:
_build_keepalive_http_client()returns aCurlCffiClientinstead of stockhttpx.Clientisinstance(client, httpx.Client)→ True (OpenAI SDK gate passes)python-httpx/X.Y.Z,accept-encoding,connection) are stripped so curl_cffi sends its own browser-impersonating headersWhat is NOT affected:
tls_impersonateis absent or"none"chatgpt.comandapi.openai.com(detected by_is_cloudflare_protected())Files changed
agent/curl_cffi_transport.py(new) —CurlCffiClientclass +build_curl_cffi_http_client()factoryrun_agent.py—_build_keepalive_http_client()extended with curl_cffi path, +_tls_impersonation_profile(), +_is_cloudflare_protected()Tested on
curl_cffi0.15.0,httpx0.28.1chatgpt.com/backend-api/codex/responsesreturns HTTP 400 with zerocf-mitigated: challenge(Cloudflare bypass confirmed)cf-mitigated: challengeNotes
auxiliary_client.py) are not touched — those would be a follow-up.Closes #30480