Skip to content

Validate Azure region format to prevent region poisoning (fixes #6060)#6061

Merged
Robbie-Microsoft merged 5 commits into
mainfrom
rginsburg/region-validation
Jun 16, 2026
Merged

Validate Azure region format to prevent region poisoning (fixes #6060)#6061
Robbie-Microsoft merged 5 commits into
mainfrom
rginsburg/region-validation

Conversation

@Robbie-Microsoft

@Robbie-Microsoft Robbie-Microsoft commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Summary

Validates that an Azure region string contains only letters and digits (a single alphanumeric word) before it is used to build a token endpoint host. If the value is malformed, MSAL falls back to the global (non-regional) endpoint instead of using it. Fixes #6060.

Why this is a security fix

The configured region is prefixed onto the trusted {region}.login.microsoft.com suffix. A malformed or poisoned value (e.g. MSAL_FORCE_REGION="fake.com/x") would yield https://fake.com/x.login.microsoft.com, whose authority is fake.com — redirecting the token/credential request to an unintended host. Validating the region and falling back to global ensures the request never targets such a host.

Behavior: fall back to global (not fail-fast)

A malformed region is not a build-time error. Consistent with how MSAL already handles regions elsewhere (an unusable region falls back to global rather than failing the call), an invalid value is logged and ignored, and the request proceeds against the global endpoint. This keeps the change non-breaking while still closing the host-redirection vector — the request is never sent to the tampered URL described in #6060.

Changes

  • RegionManager.IsValidRegionName — single source of truth. A compiled, anchored regex (\A[a-zA-Z0-9]+\z) that is ASCII-only by design: it uses an explicit [a-zA-Z0-9] class (not \w/\d, which are Unicode-aware and would allow Unicode digits/homoglyphs) and anchors with \A...\z rather than ^...$ so a trailing newline cannot slip through.
  • RegionManager.GetAzureRegionAsync — for a user-provided / MSAL_FORCE_REGION region, validate the format before returning it; an invalid value logs an error and returns null (→ global endpoint). The auto-detect sentinel is handled before this check, so auto-discovery is unaffected.
  • RegionManager.ValidateRegion — used by the REGION_NAME env var and IMDS body paths — delegates to IsValidRegionName and rejects malformed values (falls back to global).
  • Defense-in-depthRegionAndMtlsDiscoveryProvider (the single point where the regional host is actually constructed) re-validates the region; a malformed value is logged and ignored so it can never alter the authority host.

Telemetry note

For a user-provided region, region auto-discovery still runs for telemetry before the fallback decision, so ApiEvent.RegionUsed records the provided string and RegionOutcome is set to UserProvidedValid/UserProvidedInvalid as usual. The actual routing for a malformed value is global — that is the security guarantee. Fallback tests therefore assert on the resolved token endpoint (global URL), not on RegionUsed.

Tests

  • WithAzureRegion(...) and MSAL_FORCE_REGION with malformed values (fake.com/x, fake.com?x, fake.com#x, east@us, east.us, east us) fall back to the global token endpoint.
  • A valid alphanumeric region continues to route to the regional endpoint.
  • REGION_NAME/env-var special-character rejection in RegionDiscoveryProviderTests.
  • WithAzureRegion(null/empty) still throws ArgumentNullException (pre-existing).
  • Existing region/mTLS/telemetry suites pass (clean build, TreatWarningsAsErrors).

Robbie-Microsoft and others added 2 commits June 11, 2026 17:17
Region short names are always alphanumeric single words. Previously a
region read from WithAzureRegion, the MSAL_FORCE_REGION env variable, the
REGION_NAME env variable, or IMDS was only loosely checked (or, for
MSAL_FORCE_REGION, not checked at all), so a value such as 'attacker.com/x'
could be prefixed onto '{region}.login.microsoft.com' and redirect the
token endpoint host.

- Add RegionManager.IsValidRegionName enforcing letters/digits only
- WithAzureRegion and MSAL_FORCE_REGION now throw MsalError.InvalidRegion on invalid input
- Tighten RegionManager.ValidateRegion (REGION_NAME + IMDS) to reject special characters
- Add MsalError.InvalidRegion + message and PublicAPI entries
- Tests for builder, env-variable, and helper validation

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…check

- Normalize WithAzureRegion and MSAL_FORCE_REGION values (strip spaces,
  lower-case) consistently with the REGION_NAME auto-detection path, so
  'East Us' is accepted everywhere instead of throwing on some paths.
- Extract the duplicated validate-or-throw logic into a single private
  NormalizeAndValidateRegion helper; sentinels are passed through unchanged.
- Defense-in-depth: re-validate the region at the single point where the
  regional authority host is constructed (RegionAndMtlsDiscoveryProvider),
  ignoring any malformed value and falling back to global.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings June 11, 2026 21:31
@Robbie-Microsoft Robbie-Microsoft requested a review from a team as a code owner June 11, 2026 21:31

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request addresses a security issue where a malformed/attacker-controlled Azure region value could be used to “poison” the computed token endpoint host. It introduces strict (ASCII) alphanumeric validation for region short names and applies it consistently across configuration, environment-variable handling, auto-detection, and the final host construction point.

Changes:

  • Introduces RegionManager.IsValidRegionName (ASCII letters/digits only) and uses it for region validation during region discovery.
  • Updates ConfidentialClientApplicationBuilder to normalize (strip spaces + lowercase) and fail fast with MsalClientException (MsalError.InvalidRegion) for invalid region formats from WithAzureRegion(...) and MSAL_FORCE_REGION.
  • Adds defense-in-depth validation at the point where the regional host is constructed, plus unit tests and public API surface tracking for the new error code.

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated no comments.

Show a summary per file
File Description
tests/Microsoft.Identity.Test.Unit/PublicApiTests/ClientCredentialWithRegionTests.cs Adds builder/env-var validation + normalization test coverage and verifies new invalid_region error code.
tests/Microsoft.Identity.Test.Unit/CoreTests/RegionDiscoveryProviderTests.cs Adds unit tests for IsValidRegionName and ensures poisoned REGION_NAME is ignored (fallback to global).
src/client/Microsoft.Identity.Client/PublicApi/netstandard2.0/PublicAPI.Unshipped.txt Tracks new public API constant MsalError.InvalidRegion.
src/client/Microsoft.Identity.Client/PublicApi/net8.0/PublicAPI.Unshipped.txt Tracks new public API constant MsalError.InvalidRegion.
src/client/Microsoft.Identity.Client/PublicApi/net8.0-ios/PublicAPI.Unshipped.txt Tracks new public API constant MsalError.InvalidRegion.
src/client/Microsoft.Identity.Client/PublicApi/net8.0-android/PublicAPI.Unshipped.txt Tracks new public API constant MsalError.InvalidRegion.
src/client/Microsoft.Identity.Client/PublicApi/net472/PublicAPI.Unshipped.txt Tracks new public API constant MsalError.InvalidRegion.
src/client/Microsoft.Identity.Client/PublicApi/net462/PublicAPI.Unshipped.txt Tracks new public API constant MsalError.InvalidRegion.
src/client/Microsoft.Identity.Client/MsalErrorMessage.cs Adds an internal error message template describing the invalid region format requirement.
src/client/Microsoft.Identity.Client/MsalError.cs Adds public MsalError.InvalidRegion with XML docs describing cause/mitigation.
src/client/Microsoft.Identity.Client/Instance/Region/RegionManager.cs Replaces URI-based validation with strict ASCII alphanumeric validation via IsValidRegionName.
src/client/Microsoft.Identity.Client/Instance/Discovery/RegionAndMtlsDiscoveryProvider.cs Re-validates region before constructing the regional host (defense-in-depth) and falls back to global on invalid input.
src/client/Microsoft.Identity.Client/AppConfig/ConfidentialClientApplicationBuilder.cs Centralizes normalization + validation into NormalizeAndValidateRegion and throws invalid_region for invalid user/env inputs.

Per review feedback, validate the user-provided/forced Azure region format and
fall back to the global (non-regional) endpoint when invalid, rather than
throwing. This keeps the behavior non-breaking while still ensuring a poisoned
region (e.g. one containing host/path/special characters) is never prefixed
onto the trusted '{region}.login.microsoft.com' suffix. Removes the now-unused
MsalError.InvalidRegion / MsalErrorMessage.InvalidRegionFormat constants and
reworks tests to assert global routing. Renames test keyword 'attacker' to 'fake'.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Comment thread src/client/Microsoft.Identity.Client/Instance/Region/RegionManager.cs Outdated
Replaces the per-character loop in RegionManager.IsValidRegionName with a
compiled, anchored regex. Uses an explicit [a-zA-Z0-9] class (not \w/\d, which
are Unicode-aware) and \A...\z anchors (not ^...$, which would let a trailing
newline through) to preserve the ASCII-only security guarantee. Adds tests for
trailing/embedded newlines and Unicode digits.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings June 11, 2026 22:56

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature Request] Validate the region string when reading from the user or env variable

4 participants