HIGH cache poisoningaspnetbearer tokens

Cache Poisoning in Aspnet with Bearer Tokens

Cache Poisoning in Aspnet with Bearer Tokens — how this specific combination creates or exposes the vulnerability

Cache poisoning occurs when an attacker causes a cache to store malicious content, leading other users to receive harmful responses. In ASP.NET applications that use Bearer Tokens for authorization, a dangerous pattern is to include the Authorization header, which contains the Bearer Token, in the cache key. If the application uses the full request URI—including query parameters and headers—as the cache key, two different tokens for the same user or different users can map to the same cached entry. This effectively leaks one user’s protected data to another user or causes the application to serve private data under a public cache entry.

Consider an ASP.NET Core endpoint that caches responses by the full path and Authorization header. An attacker can register with a unique Bearer Token and observe the cache key generated by the framework or middleware. If the cache key does not differentiate between public and private data, a second user with a different Bearer Token may receive the first user’s cached response, exposing personal or sensitive information. This violates the principle of separation between authenticated sessions and can lead to unauthorized data disclosure, a common finding in BOLA/IDOR checks run by middleBrick.

Another scenario involves query parameters that include user identifiers while the Authorization header carries the Bearer Token. If the caching layer uses the query string as part of the key but ignores the distinction between public and private headers, an attacker can manipulate identifiers to poison the cache for other users. For example, an endpoint like /api/orders?user=123 might cache results keyed on the query parameter, while the Bearer Token in the header provides the actual authorization context. If the cache key ignores the header, a request with a manipulated user ID and a valid Bearer Token might retrieve cached data belonging to user 123, even when the attacker’s token does not authorize access. This directly maps to findings from middleBrick’s BOLA/IDOR and Authentication checks, which highlight improper cache segregation.

Such vulnerabilities are exacerbated when responses contain sensitive headers or cookies and are stored in shared caches. ASP.NET applications that rely on in-memory or distributed caches without explicit header exclusion can inadvertently store responses that include authentication context tied to a specific Bearer Token. middleBrick’s Data Exposure and Property Authorization checks are designed to detect these weaknesses by correlating runtime behavior with OpenAPI specifications, ensuring that cached responses do not leak token-bound data across users or roles.

Bearer Tokens-Specific Remediation in Aspnet — concrete code fixes

To remediate cache poisoning when using Bearer Tokens in ASP.NET, ensure that cache keys exclude sensitive authorization headers and that responses with private data are never cached publicly. Use explicit cache policies that differentiate by user identity but do not incorporate the raw Bearer Token. Below are concrete code examples demonstrating secure caching patterns.

Exclude Authorization Header from Cache Key

Configure caching so that the Authorization header is not part of the cache key. In ASP.NET Core, you can customize the cache key using VaryByHeader carefully and avoid including Authorization. Instead, vary by a user identifier extracted from the token claims after validation.

services.AddControllers()
    .AddCacheProfile("SecureProfile", options =>
    {
        options.VaryByRule = "user_id"; // derived from validated claims
        options.NoStore = false;
        options.Duration = 300;
    });

Use Policy-Based Caching with Claims

After validating the Bearer Token, extract user claims and use them to build a safe cache key. This ensures that each user’s cached data remains isolated without relying on the header itself.

var userId = User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
if (!string.IsNullOrEmpty(userId))
{
    var cacheKey = $"orders_{userId}";
    var cached = await cache.GetOrCreateAsync(cacheKey, async entry =>
    {
        entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(5);
        return await fetchOrders(userId);
    });
    return Ok(cache);
}

Disable Caching for Private Endpoints

For endpoints that return sensitive data protected by Bearer Tokens, explicitly disable caching to prevent any possibility of poisoning. This is critical for endpoints that do not need public caching.

[HttpGet("/api/profile")]
[ResponseCache(NoStore = true, Duration = 0, Location = ResponseCacheLocation.None)]
public IActionResult GetProfile()
{
    var userId = User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
    var profile = _service.GetProfile(userId);
    return Ok(profile);
}

Validate Token Scope and Cache Segregation

Ensure that caching logic respects token scope and that responses are not shared across different authorization contexts. Use middleware to enforce that cached responses are only served when the requesting token’s scope matches the token used to generate the cache entry.

app.Use(async (context, next)
{
    var token = context.Request.Headers["Authorization"].ToString().Replace("Bearer ", "");
    var scope = TokenValidator.GetScope(token);
    // validate scope and cache segregation here
    await next.Invoke();
});

Configure Distributed Cache with Key Prefixing

When using a distributed cache, apply key prefixing that incorporates user identity and excludes raw tokens. This prevents key collisions and reduces cross-user cache pollution.

services.AddStackExchangeRedisCache(options =>
{
    options.Configuration = "localhost:6379";
    options.InstanceName = "SecureCache_";
});
// Later in code: $"SecureCache_orders_{userId}"

These practices align with middleBrick’s checks for BFLA/Privilege Escalation and Unsafe Consumption by ensuring that authorization context is never embedded in cache keys and that cached responses are properly isolated. Developers can verify their configurations using middleBrick’s CLI to scan endpoints and confirm that no sensitive headers are included in cache logic.

Frequently Asked Questions

How does including the Authorization header in the cache key lead to cache poisoning?
Including the Authorization header, which carries the Bearer Token, in the cache key can map different tokens to the same cached entry. This causes one user’s private data to be served to another user when the cache key collides, resulting in unauthorized data disclosure.
What is the safest caching approach for endpoints protected by Bearer Tokens in ASP.NET?
The safest approach is to exclude the Authorization header from cache keys, vary caching by a user identifier derived from validated token claims, and disable caching for sensitive endpoints using ResponseCache with NoStore. This prevents cross-user cache pollution and ensures private data remains isolated.