Cache Poisoning in Laravel with Basic Auth
Cache Poisoning in Laravel with Basic Auth — how this specific combination creates or exposes the vulnerability
Cache poisoning occurs when an attacker causes an application to store malicious or incorrect data in a cache, which is then served to other users. In Laravel, this risk can be amplified when Basic Authentication is used as the primary gate for an endpoint that is also cached, whether by a CDN, reverse proxy, or application-level cache.
Consider a scenario where a route is protected only by HTTP Basic Auth and its response is cached based on the request URL without incorporating the Authorization header or user identity. Because the cache key may omit the credentials, a poisoned entry written by one user (or injected by an attacker) can be reused for other users. For example, if an authenticated attacker causes the cache to store a response containing sensitive data or malicious content under a shared key, subsequent unauthenticated or lower-privileged requests may receive that tainted response.
Laravel’s route caching (via php artisan route:cache) does not natively account for per-request headers like Authorization when generating cache keys for reverse-proxy or CDN caches. If caching is applied at a layer outside the application, the combination of static cache keys and Basic Auth can lead to privilege confusion: a cached response intended for one set of credentials might be served to another. Additionally, if query parameters or fragments that include credentials are improperly normalized, an attacker could manipulate these inputs to poison the cache with crafted content, such as malicious JSON or HTML that leads to data exposure or client-side execution in downstream consumers.
The LLM/AI Security checks available in middleBrick are particularly relevant here because they detect system prompt leakage and unauthorized output patterns that could indicate injected content being cached and returned. While middleBrick does not fix the underlying caching misconfiguration, its findings can highlight unexpected data exposure in LLM-facing endpoints that rely on cached responses, aligning with checks for Data Exposure and Unsafe Consumption.
Basic Auth-Specific Remediation in Laravel — concrete code fixes
To mitigate cache poisoning when using HTTP Basic Authentication in Laravel, ensure that cached responses are keyed with awareness of the Authorization header or user context, and avoid caching sensitive or user-specific responses unless necessary.
1. Avoid caching authenticated responses at shared layers
Do not cache responses behind Basic Auth at the CDN or reverse-proxy level unless you can guarantee strict isolation per credential. Instead, handle caching inside the application with per-user keys, or disable caching for authenticated routes.
// app/Http/Middleware/EnsureCacheControl.php
hasHeader('Authorization') && str_starts_with($request->header('Authorization'), 'Basic ')) {
$response->headers->set('Cache-Control', 'no-store, no-cache, must-revalidate, private');
$response->headers->set('Pragma', 'no-cache');
$response->headers->set('Expires', '0');
}
return $response;
}
}
2. Key cache entries by user or credential scope
If you must cache, incorporate the username or a hash of the Authorization header into the cache key to prevent cross-user contamination.
// app/Helpers/CacheHelper.php
hasHeader('Authorization')) {
$credential = hash('sha256', $request->header('Authorization'));
return "auth:$credential:$baseKey";
}
return $baseKey;
}
}
// Usage in a controller
use App\Helpers\CacheHelper;
public function profile(Request $request)
{
$key = CacheHelper::userAwareKey($request, 'user:profile');
return Cache::remember($key, 300, function () use ($request) {
// Perform user-specific operations, e.g., call an external API with Basic Auth
$username = base64_decode(explode(':', base64_decode(substr($request->header('Authorization'), 6)))[0]);
// Simulate an external call
return response()->json(['user' => $username, 'data' => 'safe']);
});
}
3. Validate and normalize inputs before caching
Ensure that query parameters, headers, and payloads used to construct cache keys are normalized and validated to prevent attackers from manipulating keys via crafted inputs.
// app/Http/Middleware/NormalizeCacheKey.php
query();
ksort($query);
$request->server->set('QUERY_STRING', http_build_query($query));
return $next($request);
}
}
4. Use middleware to enforce no-cache for sensitive Basic Auth routes
Apply a global or route-specific middleware to strip or prevent caching when Basic Auth is present.
// In routes/web.php or routes/api.php
Route::middleware(['auth.basic', 'cache.headers:no-store'])->group(function () {
Route::get('/secure/data', function () {
return response()->json(['message' => 'This response is not cached']);
});
});