Skip to content

Azure api-key header is forwarded across cross-origin redirects (httpx strips Authorization but not custom auth headers) #3516

Description

@Har1sh-k

Summary

The SDK builds its default httpx client with follow_redirects=True (src/openai/_base_client.py:838) and does not strip any headers of its own on redirect. httpx's cross-origin redirect protection removes Authorization (and Cookie) when the origin changes, but it does not remove custom headers. The Azure integration authenticates with a custom api-key header (src/openai/lib/azure.py), so on a cross-origin redirect the Azure api-key is forwarded to the new origin, while an Authorization: Bearer credential in the same position would be stripped.

This is a defense-in-depth gap rather than a leak that fires in normal operation: the Azure OpenAI data-plane returns JSON, not cross-origin redirects, so a redirect has to be introduced by a gateway/proxy in front of the endpoint or by a malicious/compromised host. But the asymmetry (a sensitive auth header that survives a cross-origin redirect where Authorization would not) is worth closing.

Reproduction

Confirmed on openai==2.46.0 with httpx==0.28.1.

import httpx
# host A responds 302 -> a DIFFERENT origin (host B); host B records what it received.
with httpx.Client(follow_redirects=True) as c:
    c.get("http://host-a/v1/models",
          headers={"Authorization": "Bearer CANARY", "api-key": "CANARY-APIKEY"})
# host B receives:
#   Authorization : None            <- httpx stripped it (cross-origin protection)
#   api-key       : CANARY-APIKEY   <- forwarded to the other origin

The same holds through the real client: AzureOpenAI(api_key=..., azure_endpoint="http://host-a") following a cross-origin 302 delivers the api-key to host B.

Why the two headers differ

httpx's redirect logic only knows the standard credential headers (Authorization, Cookie). The Azure overlay authenticates with api-key, which httpx does not recognize as sensitive, so it rides along on cross-origin redirects.

Related

This is the redirect-path sibling of the unconditional Azure credential issue fixed in openai/openai-go#698 (first-party bearer sent to the Azure host). That one was addressed at the overlay; this one is about custom auth headers surviving a cross-origin redirect, which is a slightly different code path.

Suggested fix

Any one of the following closes it:

  1. On a cross-origin redirect, strip the SDK's own sensitive headers (e.g. api-key) in addition to whatever httpx already removes, mirroring httpx's Authorization/Cookie handling for custom auth headers.
  2. Default the SDK's httpx client to follow_redirects=False (the API does not rely on redirects), or scope redirect-following to same-origin.
  3. Add a regression test asserting that api-key is absent on a cross-origin redirect target, alongside the existing Azure auth tests.

More generally, an SDK that authenticates via a non-Authorization header while following redirects should treat that header as redirect-sensitive.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions