HIGH data exposureazure

Data Exposure on Azure

How Data Exposure Manifests in Azure

Data exposure in Azure APIs often stems from misconfigured Azure services, improper handling of sensitive data in Azure-specific contexts, and overlooked security settings in Azure's managed services. Understanding these Azure-specific manifestations is crucial for preventing data breaches.

One common pattern involves Azure Key Vault secrets inadvertently exposed through API responses. Developers sometimes cache or log Key Vault responses without proper sanitization, creating a direct path for credential theft. For example:

// Vulnerable: Exposing Key Vault secrets in API response
[HttpGet("secrets/{name}")]
public async Task<ActionResult> GetSecret(string name)
{
    var secret = await _keyVaultClient.GetSecretAsync(name);
    return Ok(new { Secret = secret.Value }); // Direct exposure!
}

Another Azure-specific scenario involves Azure Storage SAS (Shared Access Signature) tokens being mishandled. SAS tokens grant granular access to storage resources, and when embedded in API responses or client-side code, they become attack vectors:

// Vulnerable: Exposing SAS tokens to clients
const blobService = AzureStorage.createBlobService();
const sasToken = blobService.generateSharedAccessSignature(
    'mycontainer', 
    'myfile.txt', 
    { permissions: 'r', expiry: new Date(Date.now() + 3600000) }
);
return { url: blobService.getUrl('mycontainer', 'myfile.txt', sasToken) };

Azure Functions present unique data exposure risks when using the req object. Developers often log request bodies containing sensitive data without filtering:

// Vulnerable: Logging sensitive data in Azure Functions
public static async Task<HttpResponseMessage> Run(
    HttpRequestMessage req, 
    TraceWriter log)
{
    var body = await req.Content.ReadAsStringAsync();
    log.Info($"Request body: {body}"); // Could contain PII, tokens, etc.
    
    return req.CreateResponse(HttpStatusCode.OK);
}

Azure API Management exposes another attack surface. Policies that log request and response bodies without redaction can capture sensitive data:

<!-- Vulnerable: Logging sensitive data in API Management policies -->
<log-to-eventhub>
    <message>
        <forwarded-for/>
        <method/>
        <url/>
        <status-code/>
        <response-content>@{(string)context.Variables["message"]}</response-content>
    </message>
</log-to-eventhub>

Azure's Managed Identity system, while secure by default, can lead to data exposure when credentials are improperly scoped or when identity tokens are exposed in API responses:

# Vulnerable: Exposing identity tokens
@app.route('/auth-token')
def get_auth_token():
    credentials = DefaultAzureCredential()
    token = credentials.get_token('https://management.azure.com/.default')
    return {'token': token.token}  # Direct exposure of access token

Azure-Specific Detection

Detecting data exposure in Azure APIs requires both manual code review and automated scanning that understands Azure's unique patterns. middleBrick's Azure-aware scanning identifies these specific vulnerabilities without requiring credentials or access to your Azure subscription.

middleBrick tests for Azure-specific data exposure patterns including:

  • Key Vault secret exposure in API responses
  • SAS token leakage in client responses
  • Azure Functions log data containing sensitive information
  • API Management policies that log sensitive data
  • Managed Identity token exposure
  • Azure Storage connection strings in responses
  • Azure AD token leakage

The scanner actively probes your API endpoints for these patterns using a black-box approach. For Key Vault testing, middleBrick sends requests to endpoints that might interact with Azure Key Vault and analyzes responses for secret patterns:

{
  "category": "Data Exposure",
  "severity": "High",
  "finding": "Azure Key Vault secret exposure detected",
  "description": "API endpoint /api/secrets/{name} returns raw Key Vault secret values without authorization checks.",
  "remediation": "Implement proper authorization checks and return only metadata about secrets, not their values."
}

For SAS token detection, middleBrick analyzes response bodies for Azure Storage SAS token patterns and tests whether tokens are properly scoped:

{
  "category": "Data Exposure",
  "severity": "Medium",
  "finding": "SAS token with excessive permissions detected",
  "description": "SAS token returned to client includes write permissions (sw) when only read access was needed.",
  "remediation": "Scope SAS tokens to minimum required permissions and implement short expiry times."
}

middleBrick also detects Azure-specific logging vulnerabilities by analyzing API responses and error messages for patterns that suggest sensitive data logging:

{
  "category": "Data Exposure",
  "severity": "High",
  "finding": "Azure Functions logging vulnerability",
  "description": "API logs request bodies without sanitization, potentially exposing PII and authentication tokens.",
  "remediation": "Implement request body filtering and log only non-sensitive metadata."
}

The scanner's OpenAPI analysis complements runtime testing by examining your API specification for Azure-specific security annotations and identifying endpoints that should be protected but lack proper security schemes:

Azure ServiceCommon Exposure PatternDetection Method
Azure Key VaultSecret value exposureResponse pattern matching
Azure StorageSAS token leakageSAS token regex scanning
Azure FunctionsLog data exposureError message analysis
API ManagementPolicy loggingResponse content analysis
Managed IdentityToken exposureToken pattern detection

Azure-Specific Remediation

Remediating data exposure in Azure APIs requires leveraging Azure's native security features and following Azure-specific best practices. Here are code examples for common Azure data exposure scenarios:

For Key Vault secrets, never return raw secret values. Instead, use Azure's built-in authorization and return only metadata:

[HttpGet("secrets/{name}")]
public async Task<ActionResult> GetSecretMetadata(string name)
{
    // Check if caller has permission to access this secret
    var authResult = await _keyVaultClient.CheckAccessPolicyAsync(name);
    if (!authResult.HasAccess) 
    {
        return Forbid();
    }
    
    // Return metadata only, not the secret value
    var secretProperties = await _keyVaultClient.GetSecretPropertiesAsync(name);
    return Ok(new 
    {
        Name = secretProperties.Name,
        Created = secretProperties.Created,
        Updated = secretProperties.Updated,
        RecoveryLevel = secretProperties.RecoveryLevel
    });
}

For SAS tokens, implement proper scoping and use Azure's token utilities to avoid exposure:

public static class SasTokenHelper
{
    public static string GenerateSecureSasToken(string containerName, string blobName)
    {
        // Create a policy with minimum required permissions
        var sasConstraints = new SharedAccessBlobPolicy
        {
            SharedAccessStartTime = DateTime.UtcNow.AddMinutes(-15),
            SharedAccessExpiryTime = DateTime.UtcNow.AddMinutes(30),
            Permissions = SharedAccessBlobPermissions.Read
        };
        
        // Generate token without exposing it to clients
        var blobService = new BlobServiceClient(connectionString);
        var containerClient = blobService.GetBlobContainerClient(containerName);
        var blobClient = containerClient.GetBlobClient(blobName);
        
        // Return only the signed URI, not the token itself
        return blobClient.GenerateUri(BlobSasBuilder.Parse(sasConstraints));
    }
}

For Azure Functions, implement request body filtering before logging:

public static class LoggingHelper
{
    private static readonly string[] SensitiveFields = 
        { "password", "token", "key", "secret", "creditcard" };
    
    public static string SanitizeRequestBody(string body)
    {
        if (string.IsNullOrEmpty(body)) return body;
        
        try
        {
            var json = JObject.Parse(body);
            foreach (var field in SensitiveFields)
            {
                if (json.SelectToken(field) != null)
                {
                    json.SelectToken(field).Replace("REDACTED");
                }
            }
            return json.ToString();
        }
        catch
        {
            // If not JSON, attempt to redact common patterns
            return Regex.Replace(body, 
                @"(password|token|key|secret)=[^&\s]+", 
                "$1=REDACTED", 
                RegexOptions.IgnoreCase);
        }
    }
}

// In your function
public static async Task<HttpResponseMessage> Run(
    HttpRequestMessage req, 
    TraceWriter log)
{
    var body = await req.Content.ReadAsStringAsync();
    var sanitizedBody = LoggingHelper.SanitizeRequestBody(body);
    log.Info($"Request body: {sanitizedBody}");
    
    return req.CreateResponse(HttpStatusCode.OK);
}

For API Management, use Azure's built-in policy features to redact sensitive data:

<!-- Redact sensitive data in API Management -->
<log-to-eventhub>
    <message>
        <forwarded-for/>
        <method/>
        <url/>
        <status-code/>
        <response-content>
            @{
                var content = (string)context.Variables["message"];
                // Redact common sensitive patterns
                content = Regex.Replace(content, 
                    @"(password|token|key|secret)=[^&\s]+", 
                    "$1=REDACTED", 
                    RegexOptions.IgnoreCase);
                return content;
            }</response-content>
    </message>
</log-to-eventhub>

For Managed Identity scenarios, use Azure's client libraries that handle tokens securely without exposing them:

from azure.identity import DefaultAzureCredential
from azure.keyvault.secrets import SecretClient

# Secure pattern: token never exposed to application code
credential = DefaultAzureCredential()
secret_client = SecretClient(vault_url=VAULT_URL, credential=credential)

# The token is handled internally by the SDK
secret = secret_client.get_secret("my-secret")

Azure also provides Data Protection APIs for encrypting sensitive data at rest and in transit. Use these instead of custom encryption:

using Microsoft.AspNetCore.DataProtection;

public class SecureDataService
{
    private readonly IDataProtector _protector;
    
    public SecureDataService(IDataProtectionProvider provider)
    {
        _protector = provider.CreateProtector("MySecureData");
    }
    
    public string ProtectSensitiveData(string sensitiveData)
    {
        return _protector.Protect(sensitiveData);
    }
    
    public string UnprotectSensitiveData(string protectedData)
    {
        return _protector.Unprotect(protectedData);
    }
}

Related CWEs: dataExposure

CWE IDNameSeverity
CWE-200Exposure of Sensitive Information HIGH
CWE-209Error Information Disclosure MEDIUM
CWE-213Exposure of Sensitive Information Due to Incompatible Policies HIGH
CWE-215Insertion of Sensitive Information Into Debugging Code MEDIUM
CWE-312Cleartext Storage of Sensitive Information HIGH
CWE-359Exposure of Private Personal Information (PII) HIGH
CWE-522Insufficiently Protected Credentials CRITICAL
CWE-532Insertion of Sensitive Information into Log File MEDIUM
CWE-538Insertion of Sensitive Information into Externally-Accessible File HIGH
CWE-540Inclusion of Sensitive Information in Source Code HIGH

Frequently Asked Questions

How does middleBrick detect Azure Key Vault secret exposure without access to my Azure subscription?
middleBrick uses black-box scanning techniques to analyze API responses for patterns that indicate Key Vault secret exposure. The scanner sends requests to your API endpoints and examines the responses for raw secret values, Key Vault-specific headers, or authentication patterns that suggest secrets are being returned directly. No Azure credentials or subscription access are required - middleBrick only analyzes the data your API returns to unauthenticated requests.
Can middleBrick scan Azure Functions running in a consumption plan?
Yes, middleBrick can scan any Azure Functions endpoint that is publicly accessible via HTTP. The scanner doesn't need to know the function is running on Azure - it simply sends HTTP requests to the function's URL and analyzes the responses. This works for consumption plans, premium plans, or any other Azure Functions hosting configuration as long as the function has an HTTP trigger and is accessible from the internet.