Cache Poisoning in Aspnet
How Cache Poisoning Manifests in Aspnet
Cache poisoning in Aspnet occurs when malicious data is stored in the application's cache and subsequently served to other users. This vulnerability is particularly dangerous in Aspnet because the framework's caching mechanisms are widely used for performance optimization, creating multiple attack surfaces.
The most common Aspnet cache poisoning vector involves HTTP response splitting combined with Aspnet's Output Caching. When an attacker can inject CRLF sequences into cached responses, they can manipulate headers and inject malicious content. Consider this vulnerable Aspnet Core controller:
[HttpGet("/api/user/{id}")]
public IActionResult GetUser(int id) {
var user = _userService.GetById(id);
// Vulnerable: No input validation on user data
var response = new {
Name = user.Name,
Email = user.Email,
Bio = user.Bio // Could contain CRLF sequences
};
return Ok(response);
}If user.Bio contains %0D%0A sequences, the cached response can be split, allowing attackers to inject arbitrary headers or response bodies. When this poisoned cache entry is served to other users, they receive the manipulated content.
Another Aspnet-specific manifestation involves distributed cache poisoning through Redis or SQL Server cache providers. Aspnet's IDistributedCache interface makes it easy to swap cache implementations, but this also means poisoning can affect multiple application instances:
public class UserProfileController : ControllerBase {
private readonly IDistributedCache _cache;
public UserProfileController(IDistributedCache cache) {
_cache = cache;
}
[HttpGet("/profile/{username}")]
public async Task GetProfile(string username) {
var cacheKey = $"profile:{username}";
var cached = await _cache.GetStringAsync(cacheKey);
if (cached != null) {
return Content(cached, "application/json");
}
var profile = await _profileService.GetByUsername(username);
// Vulnerable: No validation before caching
await _cache.SetStringAsync(cacheKey, JsonSerializer.Serialize(profile));
return Ok(profile);
}
} Attackers can exploit this by creating usernames with special characters that, when cached and retrieved by other users, deliver poisoned content across the entire application farm.
ViewState tampering represents another Aspnet-specific cache poisoning variant. In traditional Aspnet Web Forms, ViewState data is often stored in hidden form fields and can be manipulated to inject malicious payloads that get cached and replayed:
<asp:TextBox ID="txtBio" runat="server" Text="<script>alert('XSS')</script>" />When this manipulated ViewState is processed and cached, subsequent users receive the injected script, leading to XSS attacks that persist through the caching layer.
Aspnet-Specific Detection
Detecting cache poisoning in Aspnet applications requires examining both the caching configuration and the data flow through cached endpoints. middleBrick's Aspnet-specific scanning identifies these vulnerabilities by analyzing runtime behavior and configuration patterns.
For Output Caching vulnerabilities, middleBrick examines controller actions for caching attributes and tests for CRLF injection:
// Scan with middleBrick CLI:
middlebrick scan https://yourapi.com/api/users/123 --output json
// middleBrick detects:
// - Caching attributes without validation
// - CRLF injection in cached responses
// - Missing Vary headers for user-specific content
The scanner actively probes cached endpoints with malicious payloads containing %0D%0A sequences and analyzes the responses for header injection or response splitting. It also checks for missing Vary headers that should differentiate cached content by user authentication status.
For distributed cache poisoning, middleBrick examines the cache provider configuration and tests for cross-user data leakage:
// middleBrick identifies:
// - IDistributedCache usage without validation
// - Missing cache key namespace isolation
// - Lack of cache entry validation before serving
The scanner creates test accounts with special characters in usernames and verifies whether cached content from one account can be accessed by another, indicating namespace pollution.
ViewState-related vulnerabilities are detected through analysis of form rendering and ViewState encryption settings:
// middleBrick checks:
// - ViewState encryption enabled (MAC3 or MAC4)
// - Validation enabled for ViewState
// - Absence of dangerous control properties
The scanner also examines memory cache usage patterns, identifying dangerous combinations like IMemoryCache with unvalidated user input as cache keys or values.
middleBrick's LLM/AI security module specifically tests for AI-assisted cache poisoning scenarios where LLM endpoints might be manipulated to generate malicious cache keys or poisoned content through prompt injection.
Aspnet-Specific Remediation
Securing Aspnet applications against cache poisoning requires implementing input validation, proper cache configuration, and secure coding practices specific to Aspnet's caching mechanisms.
For Output Caching, always validate and sanitize data before caching:
[HttpGet("/api/user/{id}")]
[ResponseCache(Duration = 300, VaryByQueryKeys = new[] { "id" })]
public IActionResult GetUser(int id) {
var user = _userService.GetById(id);
// Validate and sanitize user data
var safeResponse = new {
Name = Sanitize(user.Name),
Email = Sanitize(user.Email),
Bio = Sanitize(user.Bio, removeLineBreaks: true)
};
return Ok(safeResponse);
}
private string Sanitize(string input, bool removeLineBreaks = false) {
if (string.IsNullOrEmpty(input)) return input;
// Remove CRLF sequences to prevent response splitting
if (removeLineBreaks) {
input = input.Replace("
", "").Replace("
", " ");
}
// Encode HTML to prevent XSS in cached content
return WebUtility.HtmlEncode(input);
}
// Extension method for safe caching
public static class SafeCacheExtensions {
public static async Task GetOrCreateSafeAsync(
this IDistributedCache cache,
string key,
Func> factory,
TimeSpan? absoluteExpiration = null)
{
var cached = await cache.GetStringAsync(key);
if (cached != null) {
return JsonSerializer.Deserialize(cached);
}
var result = await factory();
// Validate result before caching
ValidateBeforeCache(result);
var options = new DistributedCacheEntryOptions();
if (absoluteExpiration.HasValue) {
options.AbsoluteExpirationRelativeToNow = absoluteExpiration.Value;
}
await cache.SetStringAsync(key, JsonSerializer.Serialize(result), options);
return result;
}
private static void ValidateBeforeCache(object obj) {
// Implement validation logic specific to your domain
// Example: Check for CRLF sequences, validate JSON structure
}
} For distributed caching scenarios, implement cache key isolation and validation:
public class UserProfileController : ControllerBase {
private readonly IDistributedCache _cache;
public UserProfileController(IDistributedCache cache) {
_cache = cache;
}
[HttpGet("/profile/{username}")]
public async Task GetProfile(string username) {
// Validate username format
if (!IsValidUsername(username)) {
return BadRequest("Invalid username format");
}
var cacheKey = $"profile:user:{username}";
var cached = await _cache.GetOrCreateSafeAsync(cacheKey, async () => {
var profile = await _profileService.GetByUsername(username);
// Additional validation for cached content
ValidateProfileContent(profile);
return profile;
});
return Ok(cached);
}
private bool IsValidUsername(string username) {
// Allow only alphanumeric and basic punctuation
return Regex.IsMatch(username, @"^[a-zA-Z0-9._-]{3,30}$");
}
private void ValidateProfileContent(UserProfile profile) {
// Check for malicious content
if (profile.Bio?.Contains("
") == true || profile.Bio?.Contains("
") == true) {
throw new InvalidOperationException("Profile content contains invalid characters");
}
}
} For traditional Aspnet Web Forms applications, enable ViewState validation and encryption:
<%@ Page Language="C#" AutoEventWireup="true" ValidateRequest="true" ViewStateEncryptionMode="Always" %>
<script runat="server">
protected void Page_Init(object sender, EventArgs e) {
// Enable ViewState MAC
ViewStateUserKey = User?.Identity?.Name ?? "anonymous";
}
protected void btnSubmit_Click(object sender, EventArgs e) {
// Validate ViewState before processing
if (!Page.IsValid) {
return;
}
// Process form data
}
</script>middleBrick Pro's continuous monitoring can automatically scan your Aspnet APIs on a schedule, alerting you to new cache poisoning vulnerabilities before they're exploited in production.