← Notes

CVE-2026-50338: Spring Cloud Azure B2C Cross-Issuer Authentication Bypass

Overview

CVECVE-2026-50338
Componentspring-cloud-azure-autoconfigure (AadB2cResourceServerAutoConfiguration, AadB2cTrustedIssuerRepository)
Affectedspring-cloud-azure-starter-active-directory-b2c 1.0.0 through 5.19.0
FixedJuly 2026 Security Update (PR #49252)
ClassCWE-287 (Improper Authentication)
CVSS v3.18.2 (High)
Found byLukas Johannes Moeller (@JohannesLks)

TL;DR

Spring Cloud Azure's B2C resource-server validator inherits AAD-line trusted issuers from its parent class and installs no tid claim validator. An AAD client_credentials token from the same tenant authenticates against a B2C-protected API endpoint. The fix for the identical defect in the AAD twin (CVE-2026-33117, PR #49033) modified only the AAD path; the B2C path remained vulnerable.

Root Cause

PR #49033 added four controls to the AAD resource server after CVE-2026-33117. The B2C twin was not touched:

  • Cross-issuer trust: AadB2cTrustedIssuerRepository.java:30 calls super(tenantId), whose parent unconditionally adds six AAD-line issuers (login.microsoftonline.com, sts.windows.net, sts.chinacloudapi.cn, v1 and v2 each) per tenant.
  • No tid validator: AadB2cResourceServerAutoConfiguration.java:94-107 installs only aud, issuer, and timestamp validators. No JwtClaimValidator on tid.
  • Broken aud predicate: The audience check at line 103 uses validAudiences::containsAll, which is vacuously true on an empty audience set and accepts any subset otherwise.
  • No tenant-id guard: common, organizations, and consumers are accepted silently and propagate as /common/{,v2.0} into the trusted-issuer set.

Impact

A low-privilege attacker in the same Entra tenant (or any tenant when tenant-id=common is configured) mints an AAD client_credentials token with the B2C app's client-id as audience. The B2C resource server accepts it because the AAD issuer is in its trusted set, the tid claim is never checked, and the audience predicate is vacuous. The attacker authenticates as a service principal against a B2C-only API.

With tenant-id=common, any Entra tenant's token is accepted.

Live Proof (excerpt)

=== Step 1: B2C resource server rejects unauthenticated requests ===
GET /profile (no token): HTTP 401

=== Step 2: Mint AAD token (client_credentials) ===
Attacker app in same tenant mints token:
  iss: https://sts.windows.net/2acb9c20-.../
  aud: api://d610cf54-...  (B2C app client-id)
  tid: 2acb9c20-...

=== Step 3: POST AAD token to B2C-protected endpoint ===
HTTP 200
{
    "subject": "81fa7d73-...",
    "issuer": "https://sts.windows.net/2acb9c20-.../"
}