mirror of
https://github.com/openai/codex.git
synced 2026-10-24 18:18:41 +00:00
Preserve __oailb routing cookies in ChatGPT HTTP clients (#43895)
## What changed Add `__oailb` to the shared ChatGPT infrastructure cookie allowlist so clients store and replay the routing cookie on subsequent requests. Document its inclusion in the process-local cookie jar. ## Testing Add a regression test covering replay on a matching path, rejection outside the cookie's host, path, and HTTPS scope, and removal with `Max-Age=0`. GitOrigin-RevId: abcb888e8867d94fdf0f7d346fded8eaafdc52ae
This commit is contained in:
@@ -8,9 +8,9 @@ use reqwest::header::HeaderValue;
|
||||
use crate::chatgpt_hosts::is_allowed_chatgpt_host;
|
||||
|
||||
// WARNING: this HTTP cookie store is process-global and may be shared across auth contexts.
|
||||
// It must only ever contain Cloudflare infrastructure cookies. Never extend this
|
||||
// store to persist ChatGPT account, session, auth, or other user-specific cookie
|
||||
// data.
|
||||
// It must only ever contain Cloudflare infrastructure cookies and the `__oailb`
|
||||
// routing cookie. Never extend this store to persist ChatGPT account, session,
|
||||
// auth, or other user-specific cookie data.
|
||||
static SHARED_CHATGPT_CLOUDFLARE_COOKIE_STORE: LazyLock<Arc<ChatGptCloudflareCookieStore>> =
|
||||
LazyLock::new(|| Arc::new(ChatGptCloudflareCookieStore::default()));
|
||||
|
||||
@@ -96,12 +96,13 @@ impl CookieStore for ChatGptCookieStore {
|
||||
}
|
||||
}
|
||||
|
||||
/// Adds the process-local ChatGPT Cloudflare cookie jar used by Codex HTTP clients.
|
||||
/// Adds the process-local ChatGPT infrastructure cookie jar used by Codex HTTP clients.
|
||||
///
|
||||
/// WARNING: this jar is global within the process. It is only acceptable because it hardcodes a
|
||||
/// small allowlist of Cloudflare cookie names and refuses all other ChatGPT cookies. Do not store
|
||||
/// ChatGPT account, session, auth, or other user-specific cookies here. If a future caller needs
|
||||
/// those cookies, the store must be scoped to the auth/session owner instead of shared globally.
|
||||
/// small allowlist of Cloudflare cookie names plus `__oailb` for routing, and refuses all other
|
||||
/// ChatGPT cookies. Do not store ChatGPT account, session, auth, or other user-specific cookies
|
||||
/// here. If a future caller needs those cookies, the store must be scoped to the auth/session
|
||||
/// owner instead of shared globally.
|
||||
pub fn with_chatgpt_cloudflare_cookie_store(
|
||||
builder: reqwest::ClientBuilder,
|
||||
) -> reqwest::ClientBuilder {
|
||||
@@ -155,6 +156,7 @@ fn only_cloudflare_cookies(header: HeaderValue) -> Option<HeaderValue> {
|
||||
}
|
||||
|
||||
fn is_allowed_cloudflare_cookie_name(name: &str) -> bool {
|
||||
// `__oailb` is an OpenAI infrastructure routing cookie, not an authentication cookie.
|
||||
// Keep this allowlist aligned with Cloudflare's documented service cookies:
|
||||
// https://developers.cloudflare.com/fundamentals/reference/policies-compliances/cloudflare-cookies/
|
||||
matches!(
|
||||
@@ -164,6 +166,7 @@ fn is_allowed_cloudflare_cookie_name(name: &str) -> bool {
|
||||
| "__cfruid"
|
||||
| "__cfseq"
|
||||
| "__cfwaitingroom"
|
||||
| "__oailb"
|
||||
| "_cfuvid"
|
||||
| "cf_clearance"
|
||||
| "cf_ob_info"
|
||||
@@ -265,6 +268,37 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn oailb_cookies_are_replayed_with_scope_and_expiration() {
|
||||
let store = ChatGptCloudflareCookieStore::default();
|
||||
let url = reqwest::Url::parse("https://chatgpt.com/backend-api/codex/responses").unwrap();
|
||||
let cookie = HeaderValue::from_static(
|
||||
"__oailb=route; Path=/backend-api; Max-Age=3600; Secure; HttpOnly; SameSite=Lax",
|
||||
);
|
||||
store.set_cookies(&mut std::iter::once(&cookie), &url);
|
||||
|
||||
let followup_url = reqwest::Url::parse("https://chatgpt.com/backend-api/ps/mcp").unwrap();
|
||||
assert_eq!(
|
||||
store.cookies(&followup_url),
|
||||
Some(HeaderValue::from_static("__oailb=route"))
|
||||
);
|
||||
for outside_scope in [
|
||||
"https://chatgpt.com/",
|
||||
"https://other.chatgpt.com/backend-api/ps/mcp",
|
||||
"https://api.openai.com/backend-api/ps/mcp",
|
||||
"http://chatgpt.com/backend-api/ps/mcp",
|
||||
] {
|
||||
let outside_scope = reqwest::Url::parse(outside_scope).unwrap();
|
||||
assert_eq!(store.cookies(&outside_scope), None);
|
||||
}
|
||||
|
||||
let expired = HeaderValue::from_static(
|
||||
"__oailb=; Path=/backend-api; Max-Age=0; Secure; HttpOnly; SameSite=Lax",
|
||||
);
|
||||
store.set_cookies(&mut std::iter::once(&expired), &url);
|
||||
assert_eq!(store.cookies(&followup_url), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ignores_non_chatgpt_cookies() {
|
||||
let store = ChatGptCloudflareCookieStore::default();
|
||||
|
||||
Reference in New Issue
Block a user