codex - 💡(How to fix) Fix Chat & WebSocket runtime have no TLS-bypass escape hatch — PR #20676 only fixed login (enterprise MITM still blocked)

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…

PR #20676 (commit 9e90552, 2026-05-02) added SSL_CERT_FILE / CODEX_CA_CERTIFICATE detection to the login flow's reqwest client (codex-client/src/custom_ca.rs::build_reqwest_client_with_env). This partially addressed #6849.

The chat runtime and WebSocket transport are still broken behind any TLS-inspecting proxy whose MITM CA is rejected by rustls (modern signature/key policy):

  • WebSocket (tokio-tungstenite with rustls-tls-native-roots feature) is hardcoded to rustls — it has no env-var / config / flag escape hatch.
  • HTTPS fallback (chat path) also appears to use rustls without honoring the login-flow CA logic.

Net effect: codex login succeeds; codex chat dies on every prompt with invalid peer certificate: BadSignature and stream disconnected before completion.

Error Message

codex doctor ... ⚠ websocket Responses WebSocket failed; HTTPS fallback may still work endpoint wss://chatgpt.com/backend-api/<redacted> handshake transport error network error: invalid peer certificate: BadSignature

In chat: ⚠ Falling back from WebSockets to HTTPS transport. stream disconnected before completion: invalid peer certificate: BadSignature ■ stream disconnected before completion: error sending request for url (https://chatgpt.com/backend-api/codex/responses)

Root Cause

Even if a user sets SSL_CERT_FILE to a bundle containing the corporate MITM root, rustls still rejects because the chain itself uses SHA1 / RSA-1024 / unreachable revocation — adding the CA to the bundle doesn't override those algorithm policies. This is a class of corporate MITM (FortiGate, certain Trend Micro / Palo Alto deployments etc.) where the root cert was generated decades ago and can't be cycled by IT in any short timeframe.

Fix Action

Fix / Workaround

Same cert chain, three different rejection paths (proves no single workaround works):

Workarounds users currently rely on

  • #6849 — login-only version of this issue, fixed by PR #20676 for the auth path
  • PR #20676 / commit 9e90552 — partial fix (login only)
  • codex-rs/codex-client/src/custom_ca.rs::build_reqwest_client_with_env — the existing pattern that should be extended

Code Example

codex doctor
...
⚠ websocket    Responses WebSocket failed; HTTPS fallback may still work
    endpoint                 wss://chatgpt.com/backend-api/<redacted>
    handshake transport error network error: invalid peer certificate: BadSignature

In chat:
Falling back from WebSockets to HTTPS transport.
stream disconnected before completion: invalid peer certificate: BadSignature
■ stream disconnected before completion: error sending request for url (https://chatgpt.com/backend-api/codex/responses)
RAW_BUFFERClick to expand / collapse

Summary

PR #20676 (commit 9e90552, 2026-05-02) added SSL_CERT_FILE / CODEX_CA_CERTIFICATE detection to the login flow's reqwest client (codex-client/src/custom_ca.rs::build_reqwest_client_with_env). This partially addressed #6849.

The chat runtime and WebSocket transport are still broken behind any TLS-inspecting proxy whose MITM CA is rejected by rustls (modern signature/key policy):

  • WebSocket (tokio-tungstenite with rustls-tls-native-roots feature) is hardcoded to rustls — it has no env-var / config / flag escape hatch.
  • HTTPS fallback (chat path) also appears to use rustls without honoring the login-flow CA logic.

Net effect: codex login succeeds; codex chat dies on every prompt with invalid peer certificate: BadSignature and stream disconnected before completion.

Environment

  • codex-cli 0.132.0 (also reproduced on 0.130, 0.131, 0.133)
  • Windows 11 (x86_64)
  • Hospital LAN with two-tier SSL inspection:
    • "AI hosts" (chatgpt.com, *.openai.azure.com, api.anthropic.com, Bedrock, Vertex etc.) → MITM with CN=GlobalTrust Root CA (2002 self-signed, SHA1WithRSAEncryption, RSA-1024)
    • "Legacy" hosts (api.openai.com, github.com) → MITM with CN=FG200ETK18915851, O=Fortinet (SHA256, RSA-2048)
  • Result: api.openai.com works in codex (FortiGate SHA256 chain passes rustls). chatgpt.com (ChatGPT auth path) and Azure / Anthropic / etc. all fail.

Reproduction

codex doctor
...
⚠ websocket    Responses WebSocket failed; HTTPS fallback may still work
    endpoint                 wss://chatgpt.com/backend-api/<redacted>
    handshake transport error network error: invalid peer certificate: BadSignature

In chat:
⚠ Falling back from WebSockets to HTTPS transport.
stream disconnected before completion: invalid peer certificate: BadSignature
■ stream disconnected before completion: error sending request for url (https://chatgpt.com/backend-api/codex/responses)

Evidence — every modern TLS library rejects this same chain

Same cert chain, three different rejection paths (proves no single workaround works):

TLS stackVerdictReason
rustls (codex)BadSignatureRFC 9155 — SHA1 signatures hard-deprecated
schannel (curl.exe on Windows)CRYPT_E_NO_REVOCATION_CHECK (0x80092012)Hospital MITM CA has no reachable CRL/OCSP endpoint
OpenSSL 3.xverify error num=66 EE certificate key too weak + num=67 CA certificate key too weakSecurity level 2 rejects RSA-1024
Node 22 OpenSSL with NODE_TLS_REJECT_UNAUTHORIZED=0✅ WorksValidation bypassed — only path that succeeds

The Node escape hatch (NODE_TLS_REJECT_UNAUTHORIZED=0) is the only reason claude-code and other Node-based clients work in this environment. As #6849 comment put it bluntly: "I can easily use claude simply with NODE_TLS_REJECT_UNAUTHORIZED=0, whereas with codex I'm simply blocked".

What PR #20676 doesn't cover

The login flow's build_reqwest_client_with_env only wires the custom-CA path for codex-client (auth/login). But:

  1. The runtime chat client (whatever builds reqwest::Client for chatgpt.com/backend-api/codex/responses calls) does not read SSL_CERT_FILE / CODEX_CA_CERTIFICATE the same way. With those env vars set per #20676, login succeeds but chat still rejects.
  2. The WebSocket transport uses tokio-tungstenite with the rustls-tls-native-roots feature — Cargo.toml declares this with no opt-out and the wss connect path has no config hook for an accept-invalid-certs flag or alternate TLS backend.

Even if a user sets SSL_CERT_FILE to a bundle containing the corporate MITM root, rustls still rejects because the chain itself uses SHA1 / RSA-1024 / unreachable revocation — adding the CA to the bundle doesn't override those algorithm policies. This is a class of corporate MITM (FortiGate, certain Trend Micro / Palo Alto deployments etc.) where the root cert was generated decades ago and can't be cycled by IT in any short timeframe.

Requested change — provide an explicit escape hatch

At least one of the following so enterprise users aren't locked out:

  1. CODEX_INSECURE_TLS=1 env var that maps to reqwest::ClientBuilder::danger_accept_invalid_certs(true) for every codex reqwest client (auth, chat, telemetry) and to tokio_tungstenite::Connector::NativeTls or equivalent for the WebSocket transport. Loud warning on startup when enabled, like Node logs on NODE_TLS_REJECT_UNAUTHORIZED=0.
  2. A --tls-backend=native flag / config that switches reqwest + tungstenite to native-tls (schannel / Security.framework / OpenSSL) instead of rustls. schannel and OpenSSL legacy mode accept SHA1; native-tls path was sufficient for codex ≤ 0.118 (when the dep tree had this fallback) and there's no policy reason it should be impossible now.
  3. Extend PR #20676's build_reqwest_client_with_env so the same SSL_CERT_FILE / CODEX_CA_CERTIFICATE detection is honored by the runtime chat reqwest client and is allowed to also disable rustls's signature-algorithm policy when the user explicitly opts in (e.g. CODEX_CA_CERTIFICATE_ALLOW_LEGACY=1).

A trust-store escape hatch behind an explicit env var matches what every other major HTTP client offers (NODE_TLS_REJECT_UNAUTHORIZED, curl -k, git -c http.sslVerify=false, pip --trusted-host). The current "no escape hatch" stance effectively locks out healthcare / financial / government users who cannot change their corporate MITM.

Workarounds users currently rely on

  • Run codex from outside the corporate network (home WiFi / cellular tether) — useless for daily work
  • Tailscale / VPN exit nodes — adds latency + corporate policy concerns
  • Use a different agent (Claude Code via Anthropic SDK in Node, OpenCode, aider) — works fine
  • Switch to OpenAI Platform API key + api.openai.com instead of ChatGPT auth + chatgpt.com — works if the corporate MITM happens to use a stronger cert chain for that host (FortiGate SHA256 in our case), but unreliable in general

Related

  • #6849 — login-only version of this issue, fixed by PR #20676 for the auth path
  • PR #20676 / commit 9e90552 — partial fix (login only)
  • codex-rs/codex-client/src/custom_ca.rs::build_reqwest_client_with_env — the existing pattern that should be extended

Happy to provide additional probe data (cert dumps, doctor output, hospital network probe matrix across 18 LLM hosts) if it helps.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

codex - 💡(How to fix) Fix Chat & WebSocket runtime have no TLS-bypass escape hatch — PR #20676 only fixed login (enterprise MITM still blocked)