CVE-2026-50338: Spring Cloud Azure B2C Cross-Issuer Authentication Bypass
Overview
| CVE | CVE-2026-50338 |
| Component | spring-cloud-azure-autoconfigure (AadB2cResourceServerAutoConfiguration, AadB2cTrustedIssuerRepository) |
| Affected | spring-cloud-azure-starter-active-directory-b2c 1.0.0 through 5.19.0 |
| Fixed | July 2026 Security Update (PR #49252) |
| Class | CWE-287 (Improper Authentication) |
| CVSS v3.1 | 8.2 (High) |
| Found by | Lukas 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:30callssuper(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-107installs onlyaud,issuer, andtimestampvalidators. NoJwtClaimValidatorontid. - 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, andconsumersare 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-.../"
}