Validate realm returned in the container auth handshake#54225
Merged
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
This PR hardens container registry Bearer authentication by validating the realm URI returned in WWW-Authenticate challenges before using it for a token request, reducing the chance of credential exfiltration/SSRF via malicious or malformed realm values.
Changes:
- Add realm URI validation (scheme allowlist + blocked IP-literal ranges + IDN/unicode-dot canonicalization hardening) and plumb the validated URI into token/OAuth flows.
- Introduce
InvalidAuthResponseExceptionplus new localized strings for clearer failures when registries return unsafe auth challenges. - Expand unit tests to cover validation edge cases and an end-to-end “don’t follow malicious realm” scenario.
Reviewed changes
Copilot reviewed 18 out of 19 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| test/Microsoft.NET.Build.Containers.UnitTests/AuthHandshakeMessageHandlerTests.cs | Adds unit and end-to-end coverage for realm validation, and updates handler construction for new isInsecureRegistry parameter. |
| src/Containers/Microsoft.NET.Build.Containers/AuthHandshakeMessageHandler.cs | Adds ValidateRealmUri and blocked-network logic; passes validated realm into token/OAuth requests; extends handler ctor to include isInsecureRegistry. |
| src/Containers/Microsoft.NET.Build.Containers/Exceptions/InvalidAuthResponseException.cs | Adds a dedicated exception type for invalid/malicious registry auth responses. |
| src/Containers/Microsoft.NET.Build.Containers/Registry/DefaultRegistryAPI.cs | Wires isInsecureRegistry into AuthHandshakeMessageHandler construction. |
| src/Containers/Microsoft.NET.Build.Containers/Resources/Strings.resx | Adds new resource strings for invalid auth response reporting. |
| src/Containers/Microsoft.NET.Build.Containers/Resources/Strings.Designer.cs | Regenerates strongly-typed accessors for the new resource strings. |
| src/Containers/Microsoft.NET.Build.Containers/Resources/xlf/Strings.cs.xlf | Adds new trans-units for auth-response validation strings. |
| src/Containers/Microsoft.NET.Build.Containers/Resources/xlf/Strings.de.xlf | Adds new trans-units for auth-response validation strings. |
| src/Containers/Microsoft.NET.Build.Containers/Resources/xlf/Strings.es.xlf | Adds new trans-units for auth-response validation strings. |
| src/Containers/Microsoft.NET.Build.Containers/Resources/xlf/Strings.fr.xlf | Adds new trans-units for auth-response validation strings. |
| src/Containers/Microsoft.NET.Build.Containers/Resources/xlf/Strings.it.xlf | Adds new trans-units for auth-response validation strings. |
| src/Containers/Microsoft.NET.Build.Containers/Resources/xlf/Strings.ja.xlf | Adds new trans-units for auth-response validation strings. |
| src/Containers/Microsoft.NET.Build.Containers/Resources/xlf/Strings.ko.xlf | Adds new trans-units for auth-response validation strings. |
| src/Containers/Microsoft.NET.Build.Containers/Resources/xlf/Strings.pl.xlf | Adds new trans-units for auth-response validation strings. |
| src/Containers/Microsoft.NET.Build.Containers/Resources/xlf/Strings.pt-BR.xlf | Adds new trans-units for auth-response validation strings. |
| src/Containers/Microsoft.NET.Build.Containers/Resources/xlf/Strings.ru.xlf | Adds new trans-units for auth-response validation strings. |
| src/Containers/Microsoft.NET.Build.Containers/Resources/xlf/Strings.tr.xlf | Adds new trans-units for auth-response validation strings. |
| src/Containers/Microsoft.NET.Build.Containers/Resources/xlf/Strings.zh-Hans.xlf | Adds new trans-units for auth-response validation strings. |
| src/Containers/Microsoft.NET.Build.Containers/Resources/xlf/Strings.zh-Hant.xlf | Adds new trans-units for auth-response validation strings. |
Files not reviewed (1)
- src/Containers/Microsoft.NET.Build.Containers/Resources/Strings.Designer.cs: Language not supported
baronfel
approved these changes
May 7, 2026
Member
baronfel
left a comment
There was a problem hiding this comment.
I have no notes - this is a beautiful PR. Thanks for the thorough documentation on the new APIs, and the comprehensive test suite showing the behaviors.
When this merges/backports we'll need to go update the docs on MS Learn, so I added the documentation label as a reminder.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
When a container registry returns a
401 Unauthorizedwith a bearer challenge,AuthHandshakeMessageHandlerpreviously used the realm URL as-is to fetch a bearer token. Because that URL is supplied by the registry response, the handler effectively trusted any value the registry put there - including malformed or malicious URLs.This change adds a
ValidateRealmUrimethod that validates the realm before using it in in a subsequent request. The validator rejects the realm if any of the following are true:https(orhttp, but only when the registry is configured as insecure).Uri.IdnHostcanonicalizes back to a blocked IPv4 literal (i.e., what the runtime would actually connect to).Why not just require the realm host to equal the registry host? Because it would break authentication against essentially every major public registry. This host-separation pattern is the normal shape of OCI bearer auth, not an edge case. For example, Docker Hub's registry (registry-1.docker.io) uses auth.docker.io for its bearer realm.
Why an exception for matching IP literals when the registry is insecure? Private/on-prem dev registries routinely return a realm whose host equals the registry host. Rejecting that would break that dev workflow. The exception is narrowly scoped: the realm host must match the registry host, and the insecure registry flag must already have been set, meaning the operator has explicitly opted in to talking to that registry over an insecure channel.