{"record":{"id":"c02cf187ee997e1b","repo":"zeroclaw-labs/zeroclaw","slug":"xai-oauth-discovery-returned-untrusted-label-e","errorCode":null,"errorMessage":"xAI OAuth discovery returned untrusted {label}: {endpoint}","messagePattern":"xAI OAuth discovery returned untrusted (.+?): (.+?)","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/zeroclaw-providers/src/auth/xai_oauth.rs","lineNumber":564,"sourceCode":"        .ok()\n        .or_else(|| {\n            base64::engine::general_purpose::URL_SAFE\n                .decode(payload)\n                .ok()\n        })?;\n    serde_json::from_slice(&bytes).ok()\n}\n\nfn require_trusted_endpoint(endpoint: &str, label: &str) -> Result<String> {\n    let url = reqwest::Url::parse(endpoint).with_context(|| format!(\"Invalid xAI {label}\"))?;\n    if url.scheme() != \"https\" {\n        anyhow::bail!(\"xAI OAuth discovery returned non-HTTPS {label}\");\n    }\n    let host = url.host_str().unwrap_or_default();\n    if host == \"x.ai\" || host.ends_with(\".x.ai\") {\n        return Ok(endpoint.to_string());\n    }\n    anyhow::bail!(\"xAI OAuth discovery returned untrusted {label}: {endpoint}\")\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn authorize_url_contains_xai_oauth_params() {\n        let pkce = PkceState {\n            code_verifier: \"verifier\".into(),\n            code_challenge: \"challenge\".into(),\n            state: \"state\".into(),\n        };\n        let url = build_authorize_url(\"https://auth.x.ai/oauth2/authorize\", &pkce);\n        assert!(url.contains(\"client_id=b1a00492-073a-47ea-816f-4c329264a828\"));\n        assert!(url.contains(\n            \"scope=openid%20profile%20email%20offline_access%20grok-cli%3Aaccess%20api%3Aaccess\"\n        ));","sourceCodeStart":546,"sourceCodeEnd":582,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-providers/src/auth/xai_oauth.rs#L546-L582","documentation":"After the HTTPS check, require_trusted_endpoint pins the host of every xAI OAuth endpoint to exactly x.ai or a subdomain of x.ai. It fires when the endpoint host is anything else, refusing to exchange codes or tokens against a foreign authorization server even over valid HTTPS. This blocks DNS-hijack and phishing discovery responses.","triggerScenarios":"The discovery document advertises an endpoint whose host is not x.ai / *.x.ai, and any discovery-consuming flow (token exchange, device-code start or poll) then rejects it before sending credentials.","commonSituations":"DNS hijack or hosts-file override for x.ai; corporate proxy rewriting discovery JSON; a stale or custom discovery cache pointing at old or test hosts; attempting to point the xAI client at a private xAI-compatible IdP on another domain.","solutions":["Confirm nothing repoints xAI endpoints at another domain; reset to the official x.ai endpoints","Check DNS resolution of x.ai on this machine (hosts file, VPN split-DNS, corporate proxy)","Retry the discovery fetch to rule out a transient poisoned response","If you run a private xAI-compatible IdP, this client is intentionally unusable with it - use the generic OAuth flow instead"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// Optional pre-flight: pin the host allowlist in your own wiring too\nlet host = reqwest::Url::parse(endpoint)?\n    .host_str()\n    .unwrap_or_default()\n    .to_string();\nif !(host == \"x.ai\" || host.ends_with(\".x.ai\")) {\n    anyhow::bail!(\"refusing xAI endpoint on foreign host: {host}\");\n}","typeGuard":null,"tryCatchPattern":"match exchange_code_for_tokens(&ctx, &code, &verifier).await {\n    Ok(tokens) => { /* store TokenSet */ }\n    Err(e) if e.to_string().contains(\"untrusted\") => {\n        // do not retry; investigate DNS/proxy and surface to the user\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Do not point the xAI client at xAI-compatible IdPs on other domains - the allowlist is intentional","Check hosts-file and VPN split-DNS entries when xAI auth suddenly fails with this error","Cache discovery responses only from verifiable https x.ai fetches","Treat this as a phishing/hijack signal and audit the environment before retrying"],"tags":["oauth","xai","allowlist","security","rust"],"backgroundTag":"oauth-endpoint-allowlist-violation","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}