Skip to content

[Backport v2] fix(auth): authenticate after same-host HTTPS upgradesΒ #1666

Closed

Description

@TerryHowe

Summary

#1663 fixed #1245 on main (v3): auth.Client could not resolve an authentication challenge received after a same-host redirect from the standard HTTP port to the standard HTTPS port. The v2 branch has the same defect and should get the same fix.

The defect on v2

registry/remote/auth/client.go on v2 carries the origin check from the GHSA-vh4v-2xq2-g5cg fix, without the repository refinement that main grew later:

https://github.com/oras-project/oras-go/blob/v2/registry/remote/auth/client.go#L512-L520

// If the challenge came from a different origin than originally requested
// (e.g. the request was redirected to another host or port), do not resolve
// or send the registry credentials to that origin.
// Reference: https://github.com/oras-project/oras-go/security/advisories/GHSA-vh4v-2xq2-g5cg
if resp.Request != nil && !sameHTTPOrigin(originalReq.URL, resp.Request.URL) {
    return resp, nil
}

sameHTTPOrigin compares the scheme, so an http:// β†’ https:// redirect on the same host fails the check and the 401 is returned unchanged.

#1245 reports this against v2 explicitly:

The v2.6.1 fix for GHSA-vh4v-2xq2-g5cg correctly prevents Authorization from being forwarded across an HTTP-origin change. However, it also prevents auth.Client from handling an authentication challenge received after a narrow, safe upgrade path.

So the behavior changed in v2.6.1 and is still present on v2. Registries that redirect http:// to https:// return 401 to any username/password or bearer flow.

What to backport

#1663. Its shape on main:

  • isHTTPSUpgrade β€” same host, HTTP standard port to HTTPS standard port
  • safeHTTPSUpgrade β€” validates every redirect hop, rejecting host changes, nonstandard ports, HTTPS downgrades, userinfo in the target, and a Host header that disagrees with the URL
  • Do retries at the HTTPS endpoint, preserving the redirected method and body, and validates a bearer realm against the HTTPS URL
  • Credentials obtained after an upgrade are not cached, because cache keys omit the scheme and a cached entry could later be replayed over HTTP

Authorization is still stripped on redirects, and every other origin change still blocks authentication.

One decision for whoever picks this up

It is not a clean cherry-pick. Comparing the branches:

  • v2 has: sameHTTPOrigin, canonicalHost, noCache, validateRealm, rewindRequestBody
  • v2 lacks: crossesRepository, withTokenRegistryURL

safeHTTPSUpgrade calls crossesRepository in its hop loop, and Do on main calls withTokenRegistryURL. Neither exists on v2. Two options:

  1. Drop the crossesRepository calls. Keeps the backport narrow and matches v2's current protection, which never checked repository crossing.
  2. Backport crossesRepository as well. Widens v2's security check beyond the redirect fix, which is a larger behavior change than this issue asks for.

Option 1 is the smaller change; option 2 brings v2 closer to main. Worth deciding deliberately rather than resolving it in a rebase.

Scope

If this should ship in v2.7.0 it affects #1660, which is open and otherwise ready. Otherwise it lands in v2.7.1.

Related

Activity

  1. TanvirTian commented on Oct 22, 2026

    @TanvirTian
    Contributor

    i'd like to work on this issue if no one is already working on it

  2. TerryHowe commented on Oct 22, 2026

    @TerryHowe
    MemberAuthor

    Done

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

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions