Skip to content

transport: support bearer auth for the redirected host on cross-host redirect #2359

Description

@amitz-jfrog

Background

Issue #2333 reported that when a registry request is permanently redirected (A→B), and host B issues a 401 WWW-Authenticate: Bearer challenge with its own realm, go-containerregistry fetches a token from B's realm but fails to apply it to the retry against B.

PR #2337 fixed #2333 by unconditionally re-attaching the refreshed token. However, this introduced a credential-leak vulnerability: bearerTransport would forward the original registry's token (minted from A's realm) to the redirected host B. PR #2349 closed that vulnerability by re-gating the re-attach on `matchesHost`, which regressed #2333.

Use Case

A client is configured to pull from registry A, but a network policy or registry gateway permanently redirects all traffic from A to B. Both registries are legitimate and trusted in this deployment.

Observed HTTP Flow:

GET https://A/v2/target-repo/manifests/latest
→ 307 Location: https://B/v2/target-repo/manifests/latest

GET https://B/v2/target-repo/manifests/latest
→ 401 WWW-Authenticate: Bearer realm="https://B/auth/token",service="B"

GET https://B/auth/token?scope=...&service=B
→ 200 OK  (token minted by B's own realm)

GET https://A/v2/target-repo/manifests/latest   ← library retries against A
→ 307 Location: https://B/...

GET https://B/v2/target-repo/manifests/latest   ← B's token is NOT attached
→ 401 Unauthorized

Root Cause

bearerTransport is constructed once from the original registry's challenge (host A). Its realm, service, and credentials are pinned to A. On a cross-host 401 from B:

  1. refresh() re-mints a token from A's realm with A's credentials (B's challenge realm/service are ignored beyond scope)
  2. The matchesHost guard (restored by transport: do not re-attach bearer token after cross-host redirect #2349) correctly prevents forwarding A's token to B
  3. No mechanism exists to perform a per-host token exchange: fetch a token from B's own realm, with credentials for B, and apply it only to B

Expected Behavior

When the redirected host B returns a 401 WWW-Authenticate: Bearer challenge, the library should:

  1. Parse B's realm, service, and scope from the challenge
  2. Resolve credentials for B from the configured keychain
  3. Exchange a token against B's own realm
  4. Apply that token only to subsequent requests to B

A's credentials must never reach B. B's token must never leave B. This matches the per-host authentication model used by docker-ce and other OCI clients.

Security Invariant

This feature request must preserve the invariant closed by #2349: the original registry's token (minted from A's realm using A's credentials) must never be forwarded to the redirected host.

References

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