Skip to content

catalog/rest: OAuth bearer token and header.* defaults are re-sent on cross-origin redirects #2089

Description

@zeroshade

Problem

sessionTransport.RoundTrip (catalog/rest/rest.go:251-338 on main @ dd935d8) adds session credentials to every request it sends: the header.* / WithHeaders defaults (rest.go:257-268), the authManager header, typically Authorization: Bearer <catalog token> (rest.go:276-293), and the SigV4 signature (rest.go:295). The catalog http.Client is built with no CheckRedirect (rest.go:1074), so the default redirect policy applies and each redirect hop goes back through RoundTrip. If the catalog responds with a 3xx to a different host, that host receives the catalog bearer token and any header.* values.

Go's stdlib protection does not apply here. Client.do snapshots the headers of the initial request before the first send (makeHeadersCopier, net/http/client.go:772-776). On each redirect it copies that snapshot and drops Authorization, Www-Authenticate, Cookie, Cookie2, Proxy-Authorization and Proxy-Authenticate when the destination hostname is neither the initial hostname nor a subdomain of it (shouldCopyHeaderOnRedirect, client.go:1017-1039, applied at client.go:700-705 and 822-840). Our credentials are not in that snapshot because the transport adds them per hop inside RoundTrip, after the client has done its stripping, so the stdlib check never sees them. Custom header.* values are never treated as sensitive by stdlib, so they would be forwarded either way.

Reproduction

I ran a throwaway internal test against main. Catalog at http://127.0.0.1:<p1>, /v1/redirect returns 307 to http://localhost:<p2>/landing (different hostname). Catalog built with WithOAuthToken("SECRET-CATALOG-TOKEN") and WithAdditionalProps({"header.X-Api-Key": "SECRET-API-KEY"}), then cat.cl.Do(GET /v1/redirect).

  • Control, plain http.Client with Authorization set on the request before Do: the redirect target received Authorization="" (stripped by stdlib).
  • Catalog client: the redirect target received Authorization="Bearer SECRET-CATALOG-TOKEN" and X-Api-Key="SECRET-API-KEY".

Expected: neither value reaches a host other than the configured catalog origin.

Other implementations

  • pyiceberg uses requests, whose Session.rebuild_auth drops Authorization when a redirect changes host.

Proposed fix

In RoundTrip, apply the auth-manager header and the header.* defaults only when the request's scheme, host and effective port match the configured catalog origin, the same check #1999 adds for SigV4 (signingOrigin / sameOrigin). Reuse those helpers once #1999 lands. Add a two-host regression test like the one above that asserts the target receives neither header. Alternatively, a CheckRedirect that refuses cross-origin redirects would close it more bluntly.

Related

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions