HIGH cache poisoningexpressbasic auth

Cache Poisoning in Express with Basic Auth

Cache Poisoning in Express with Basic Auth — how this specific combination creates or exposes the vulnerability

Cache poisoning in Express when Basic Authentication is used occurs when an attacker can cause a shared cache to store responses that are personalized or sensitive to one user and then serve those responses to other users. This typically happens when the application does not properly include authorization or Vary headers, allowing a cache key to be reused across different authenticated contexts.

With Basic Auth, credentials are sent in the Authorization header as Basic base64(username:password). If responses for different users with distinct authorization states share the same cache key — for example, when the cache key ignores the Authorization header or the Vary header — an authenticated user may receive a cached response intended for another user. This can lead to information disclosure, such as one user seeing another user’s data, or an unauthenticated attacker leveraging a cached authenticated response in certain proxy setups.

In Express, this risk is amplified when caching is implemented at a layer outside the application (e.g., a CDN or reverse proxy) and the application does not explicitly differentiate cached content by authentication status. For instance, a route that returns user-specific data might omit the Vary: Authorization header, causing a cache to treat requests with different Authorization headers as equivalent. Additionally, if the application uses query parameters to convey authorization tokens or session identifiers without instructing caches to vary on those parameters, cached content can be incorrectly reused.

Consider an endpoint /api/profile that returns user details. If an authenticated request with Authorization: Basic dXNlcjpwYXNz (user:password) is cached without accounting for the authorization context, a subsequent request from a different user or an unauthenticated request might receive the first user’s data. This violates the principle that authenticated and unauthenticated responses must be treated as distinct resources by caches.

To detect this class of issue, scans evaluate whether responses that include authentication headers appropriately influence cache keys and whether Vary headers are present and accurate. They also check whether sensitive data appears in responses that could be stored and later served to unintended recipients through cache reuse.

Basic Auth-Specific Remediation in Express — concrete code fixes

To mitigate cache poisoning with Basic Auth in Express, ensure that responses are appropriately segregated by authentication state using HTTP headers and, when necessary, application-level controls. The following practices and code examples help secure endpoints that use Basic Authentication.

1. Include Vary: Authorization for authenticated responses

When a route responds differently based on the presence or value of the Authorization header, include Vary: Authorization. This instructs caches to maintain separate entries for different authorization states.

const express = require('express');
const app = express();

app.get('/api/profile', (req, res) => {
  res.set('Vary', 'Authorization');
  // Perform Basic Auth validation
  const authHeader = req.headers['authorization'];
  if (!authHeader || !isValidBasicAuth(authHeader)) {
    res.status(401).set('WWW-Authenticate', 'Basic realm="Access"').send('Unauthorized');
    return;
  }
  const user = getUserFromAuth(authHeader);
  res.json({ username: user.username, email: user.email });
});

function isValidBasicAuth(header) {
  try {
    const base64 = header.split(' ')[1];
    const decoded = Buffer.from(base64, 'base64').toString('utf-8');
    const [username, password] = decoded.split(':');
    // Validate against a secure store (example placeholder)
    return username === 'alice' && password === 'correct-horse-battery-staple';
  } catch (e) {
    return false;
  }
}

function getUserFromAuth(header) {
  const base64 = header.split(' ')[1];
  const decoded = Buffer.from(base64, 'base64').toString('utf-8');
  const [username] = decoded.split(':');
  return { username };
}

app.listen(3000, () => console.log('Server running on port 3000'));

2. Avoid caching sensitive or user-specific responses

For responses that contain user-specific data, prevent caching by setting cache-control headers that disallow storage by shared caches.

app.get('/api/private', (req, res) => {
  res.set({
    'Cache-Control': 'no-store, no-cache, must-revalidate, proxy-revalidate',
    'Vary': 'Authorization'
  });
  const authHeader = req.headers['authorization'];
  if (!isValidBasicAuth(authHeader)) {
    res.status(401).set('WWW-Authenticate', 'Basic realm="Access"').send('Unauthorized');
    return;
  }
  const user = getUserFromAuth(authHeader);
  res.json({ secret: 'user-specific data', username: user.username });
});

3. Do not rely on query parameters for authorization without Vary

If you must use query parameters to convey authorization tokens (not recommended for Basic Auth), ensure that caching layers vary on those parameters. Prefer using headers instead.

4. Use strong authentication mechanisms and HTTPS

Always serve Basic Auth over HTTPS to prevent credential interception. Consider more robust authentication schemes (e.g., token-based auth with proper cache controls) for modern applications.

These measures reduce the risk of cached content leaking across users and help ensure that caches respect authentication boundaries. Regular scans can verify that Vary headers are present and that sensitive endpoints are not improperly cached.

Frequently Asked Questions

How can I verify that my Express routes are not vulnerable to cache poisoning with Basic Auth?
Run scans that include checks for missing or incorrect Vary: Authorization headers and inspect cached response behavior. Ensure authenticated responses set appropriate cache-control headers and vary on the Authorization header.
Does middleBrick test for cache poisoning in authenticated routes?
Yes, scans evaluate whether responses that include authentication headers are properly isolated in caching scenarios and whether Vary headers are present and accurate.