HIGH jwt misconfigurationazure

Jwt Misconfiguration on Azure

How Jwt Misconfiguration Manifests in Azure

Azure JWT misconfigurations create attack surfaces that are particularly dangerous in cloud-native environments. The most common Azure-specific manifestation occurs when developers configure Azure AD authentication but fail to properly validate token audiences, issuers, or signing keys.

In Azure Function Apps, a typical misconfiguration looks like this:

// Vulnerable: Missing audience validation
[FunctionName("GetUser")]
public static async Task Run(
    [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "user/{id}")] HttpRequest req,
    string id,
    ILogger log)
{
    var token = req.Headers["Authorization"].ToString().Replace("Bearer ", "");
    var handler = new JwtSecurityTokenHandler();
    var tokenValidationParameters = new TokenValidationParameters
    {
        ValidateIssuer = true,
        ValidIssuer = "https://sts.windows.net/{tenant-id}/",
        ValidateAudience = false, // SECURITY RISK
        ValidateLifetime = true,
        ValidateIssuerSigningKey = true
    };
    
    var claimsPrincipal = handler.ValidateToken(token, tokenValidationParameters, out SecurityToken validatedToken);
    
    return new OkObjectResult(claimsPrincipal);
}

This configuration allows any token from the specified issuer to be accepted, regardless of whether it was intended for this specific API. An attacker can obtain a valid Azure AD token for a different service and use it to access this function.

Another Azure-specific pattern involves Azure API Management (APIM) policies that improperly handle JWT validation:

<!-- Vulnerable: Missing audience check in APIM policy -->
<policies>
    <inbound>
        <validate-jwt header-name="Authorization" failed-validation-httpcode="401" failed-validation-error-message="Unauthorized. Access token is missing or invalid.">
            <openid-config url="https://login.microsoftonline.com/{tenant-id}/.well-known/openid-configuration" />
            <required-claims>
                <claim name="aud" match="any" separator="," />
            </required-claims>
        </validate-jwt>
        <base />
    </inbound>
</policies>

The match="any" attribute allows tokens with any audience to pass validation, creating a BOLA (Broken Object Level Authorization) vulnerability where authenticated users can access resources they shouldn't have access to.

Azure App Service authentication also introduces unique misconfiguration opportunities. When using Easy Auth with JWT validation disabled:

// Vulnerable: Easy Auth with client-side JWT validation disabled
var token = req.Headers["X-MS-TOKEN-AAD-ACCESS-TOKEN"];
// No server-side validation performed
// Client-side JavaScript could validate token instead

This pattern relies on client-side validation, which is fundamentally insecure as attackers can bypass client-side checks entirely.

Azure-Specific Detection

Detecting JWT misconfigurations in Azure requires examining both configuration files and runtime behavior. Azure-specific detection focuses on the unique authentication patterns and services available in the Azure ecosystem.

For Azure Functions, middleBrick scans for these specific patterns:

{
  "azure_jwt_misconfiguration": {
    "function_app": {
      "validate_audience_missing": true,
      "audience_validation_disabled": false,
      "issuer_validation_incomplete": true,
      "signing_key_validation_missing": false
    },
    "severity": "high",
    "remediation": "Add ValidateAudience = true and specify ValidAudience parameter"
  }
}

Azure API Management policies require XML-based detection looking for specific attribute values:

<!-- What middleBrick looks for -->
<validate-jwt ... match="any" /> <!-- HIGH RISK -->
<validate-jwt ... require-expiration-time="false" /> <!-- MEDIUM RISK -->
<validate-jwt ... require-signed-tokens="false" /> <!-- CRITICAL -->

Azure App Service authentication can be detected by examining the WEBSITE_AUTH_PRESERVE_URL_FRAGMENTS and WEBSITE_AUTH_SIGNING_KEY app settings. Missing or misconfigured signing keys indicate potential vulnerabilities.

middleBrick's Azure-specific JWT scanning includes:

  • Analysis of Azure Function host.json authentication configurations
  • APIM policy XML validation for JWT attributes
  • App Service authentication settings inspection
  • Azure AD B2C policy validation for consumer-facing applications

The scanner tests for token replay attacks by attempting to use tokens from one Azure service against another, identifying when audience validation is insufficient to prevent cross-service token reuse.

Azure-Specific Remediation

Remediating JWT misconfigurations in Azure requires using platform-native features and following Azure security best practices. Here are Azure-specific fixes for the most common vulnerabilities:

For Azure Functions, implement proper JWT validation using the Azure Functions JWT middleware:

// Secure: Complete JWT validation in Azure Functions
using Microsoft.Azure.Functions.Worker;
using Microsoft.Azure.Functions.Worker.Http;
using Microsoft.Identity.Web;
using System.IdentityModel.Tokens.Jwt;

[Function("GetUserSecure")]
[Authorize]
public static async Task Run(
    [HttpTrigger(AuthorizationLevel.Function, "get", Route = "user/{id}")] HttpRequestData req,
    string id,
    FunctionContext executionContext)
{
    var token = req.Headers["Authorization"].Replace("Bearer ", "");
    var handler = new JwtSecurityTokenHandler();
    
    var tokenValidationParameters = new TokenValidationParameters
    {
        ValidateIssuer = true,
        ValidIssuer = "https://sts.windows.net/{tenant-id}/",
        ValidateAudience = true,
        ValidAudience = "api://your-api-identifier",
        ValidateLifetime = true,
        ValidateIssuerSigningKey = true,
        ValidIssuers = new[] { "https://sts.windows.net/{tenant-id}/" },
        IssuerSigningKeys = GetAzureADKeys() // Dynamically fetch from Azure
    };
    
    var claimsPrincipal = handler.ValidateToken(token, tokenValidationParameters, out SecurityToken validatedToken);
    
    // Verify audience matches expected API
    var audience = validatedToken.ValidAudience;
    if (audience != "api://your-api-identifier")
    {
        return new UnauthorizedResult();
    }
    
    return new OkObjectResult(claimsPrincipal);
}

private static IEnumerable GetAzureADKeys()
{
    // Fetch Azure AD signing keys dynamically
    var keys = new List();
    var config = new ConfigurationManager("https://login.microsoftonline.com/{tenant-id}/.well-known/openid-configuration");
    var openidConfig = config.GetConfigurationAsync().Result;
    keys.AddRange(openidConfig.SigningKeys);
    return keys;
}

For Azure API Management, use secure policy configurations:

<!-- Secure: Proper JWT validation in APIM -->
<validate-jwt header-name="Authorization" failed-validation-httpcode="401" failed-validation-error-message="Unauthorized" require-expiration-time="true" require-signed-tokens="true" clock-skew="PT5M">
    <openid-config url="https://login.microsoftonline.com/{tenant-id}/.well-known/openid-configuration" />
    <required-claims>
        <claim name="aud" match="all" separator=",">
            <value>api://your-api-identifier</value>
        </claim>
        <claim name="iss" match="all" separator=",">
            <value>https://sts.windows.net/{tenant-id}/</value>
        </claim>
    </required-claims>
</validate-jwt>

For Azure App Service with Easy Auth, implement server-side validation:

// Secure: Server-side JWT validation in App Service
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
using Microsoft.IdentityModel.Tokens;

public static async Task Run(HttpRequest req, ILogger log)
{
    string token = req.Headers["Authorization"].ToString().Replace("Bearer ", "");
    
    var configManager = new ConfigurationManager<OpenIdConnectConfiguration>(
        "https://login.microsoftonline.com/{tenant-id}/.well-known/openid-configuration",
        new OpenIdConnectConfigurationRetriever());
    
    var config = await configManager.GetConfigurationAsync();
    
    var validationParameters = new TokenValidationParameters
    {
        ValidateIssuer = true,
        ValidIssuer = config.Issuer,
        ValidateAudience = true,
        ValidAudience = "api://your-api-identifier",
        ValidateLifetime = true,
        IssuerSigningKeys = config.SigningKeys
    };
    
    var handler = new JwtSecurityTokenHandler();
    
    try
    {
        var claimsPrincipal = handler.ValidateToken(token, validationParameters, out SecurityToken validatedToken);
        return new OkObjectResult(claimsPrincipal);
    }
    catch (SecurityTokenInvalidLifetimeException)
    {
        return new UnauthorizedResult();
    }
    catch (SecurityTokenInvalidAudienceException)
    {
        return new UnauthorizedResult();
    }
}

Azure Key Vault integration provides secure key management for JWT validation:

// Secure: Using Azure Key Vault for JWT signing keys
using Azure.Security.KeyVault.Keys;
using Azure.Identity;

public static async Task Run(HttpRequest req, ILogger log)
{
    var keyVaultUri = "https://your-key-vault.vault.azure.net/";
    var client = new KeyClient(new Uri(keyVaultUri), new DefaultAzureCredential());
    
    var key = await client.GetKeyAsync("azure-ad-signing-keys");
    var ecKey = key.Value.Key.ToSecurityKey();
    
    var validationParameters = new TokenValidationParameters
    {
        ValidateIssuer = true,
        ValidIssuer = "https://sts.windows.net/{tenant-id}/",
        ValidateAudience = true,
        ValidateLifetime = true,
        IssuerSigningKey = ecKey
    };
    
    // Continue with validation
}

Related CWEs: authentication

CWE IDNameSeverity
CWE-287Improper Authentication CRITICAL
CWE-306Missing Authentication for Critical Function CRITICAL
CWE-307Brute Force HIGH
CWE-308Single-Factor Authentication MEDIUM
CWE-309Use of Password System for Primary Authentication MEDIUM
CWE-347Improper Verification of Cryptographic Signature HIGH
CWE-384Session Fixation HIGH
CWE-521Weak Password Requirements MEDIUM
CWE-613Insufficient Session Expiration MEDIUM
CWE-640Weak Password Recovery HIGH

Frequently Asked Questions

Why does Azure AD token validation require both issuer and audience checks?
Azure AD issues tokens that can be used across multiple services. Without audience validation, a token intended for one Azure service (like Microsoft Graph) could be used to access your API. The issuer check ensures the token comes from your specific Azure AD tenant, while the audience check ensures it was minted for your specific API. Both validations are required to prevent token replay attacks across Azure services.
How does middleBrick detect JWT misconfigurations in Azure Functions specifically?
middleBrick analyzes Azure Function host.json files for authentication configurations, examines C# code for missing ValidateAudience parameters, and tests runtime behavior by attempting to use tokens from different Azure services. The scanner specifically looks for patterns like missing audience validation, improper issuer configuration, and weak signing key validation that are common in Azure Function deployments.