HIGH cache poisoningadonisjsbasic auth

Cache Poisoning in Adonisjs with Basic Auth

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

Cache poisoning occurs when an attacker causes a cache to store malicious content that is then served to other users. In AdonisJS applications that use HTTP Basic Authentication, this risk can emerge when responses are cached based on incomplete or untrusted request attributes. If a cache key omits the Authorization header or normalizes it in a way that strips credentials, an authenticated response for one user might be reused for another user with different permissions.

For example, an endpoint that returns user-specific data might be cached with a key derived only from the request path and query parameters. When a Basic Auth request arrives, the cache layer may treat it as identical to a previous unauthenticated or differently authenticated request and return the cached response. This can leak one user’s data to another, effectively bypassing per-user authorization checks. In AdonisJS, this can happen if caching logic in the application or an upstream proxy/cache does not account for the Authorization header as part of the cache key.

The interaction with Basic Auth is notable because the header is base64-encoded but not encrypted; if intermediaries log or cache the full request—including the Authorization header—they might inadvertently store responses alongside credentials. Even without storing credentials, failing to include the header in the cache key can cause privilege confusion: an admin’s cached response could be served to a non-admin user who happens to hit the same normalized URL. This is a cache poisoning vector because the cached content is not isolated by authentication context, leading to unauthorized data exposure.

To detect this, scans such as those performed by middleBrick examine whether authenticated responses are being cached without incorporating the Authorization header into cache keys. The presence of public or shared caches that do not vary by credentials is a strong indicator. Because Basic Auth sends credentials on every request, any mismatch between the cached key and the actual authorization context can result in incorrect or sensitive content being returned.

Basic Auth-Specific Remediation in Adonisjs — concrete code fixes

To mitigate cache poisoning with Basic Auth in AdonisJS, ensure cache keys explicitly incorporate the Authorization header or a per-user derived value. Avoid caching sensitive responses in shared caches unless cache partitioning by credentials is guaranteed. Below are concrete remediation patterns and examples.

1. Do not cache responses that contain user-specific data

If an endpoint returns data scoped to the authenticated user, prevent it from being stored in shared caches. You can set headers to disallow caching by proxies or the browser cache.

import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'

export default class UsersController {
  public async me({ request, response, auth }: HttpContextContract) {
    const user = await auth.authenticate()
    // Prevent caching of user-specific responses
    response.header('Cache-Control', 'no-store, no-cache, must-revalidate, proxy-revalidate')
    response.header('Pragma', 'no-cache')
    response.header('Expires', '0')
    return { id: user.id, username: user.username }
  }
}

2. Include credentials in cache key when caching is required

If you must cache per-user data, derive a cache key that includes a user-specific identifier rather than relying on the raw Authorization header. Do not use the full Authorization header as a cache key in logs or caches. Instead, use a stable user ID or username.

import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
import { Cache } from '@ioc:Adonis/Core/Cache'

export default class ProfilesController {
  public async show({ params, auth }: HttpContextContract) {
    const user = await auth.authenticate()
    // Use a user-specific cache key, not the Authorization header
    const key = `profile:${user.id}`
    const cached = await Cache.getOrPut(key, async () => {
      // Expensive operation, safe because key is user-specific
      return computeProfileData(user)
    })
    return cached
  }
}

function computeProfileData(user: any) {
  return { preferences: {}, settings: {} }
}

3. Validate and normalize Authorization before caching

When integrating with cache layers that inspect requests, validate and normalize credentials safely. Do not store raw Authorization headers in cache metadata or logs. If you must pass credentials to an internal cache layer, use a token derived from the user identity rather than the Basic Auth token itself.

import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'

export default class ItemsController {
  public async index({ request, response, auth }: HttpContextContract) {
    const user = await auth.authenticate()
    // Derive a safe cache token from user identity
    const cacheToken = `user:${user.id}`
    // Use cacheToken in internal cache logic if needed
    response.header('X-Cache-Token', cacheToken)
    return { items: [] }
  }
}

4. Configure reverse proxy or CDN cache rules carefully

If using a reverse proxy or CDN, ensure cache rules vary by Authorization header or by a derived user identifier for authenticated endpoints. Avoid caching authenticated responses in a shared space without explicit partitioning.

# Example CDN/edge configuration concept (not AdonisJS code)
# Cache key expression: 
#   (protocol://host/path) + "?v=" + query_params + "&user=" + user_id
# Do NOT include raw Authorization header in cache keys.

Frequently Asked Questions

Can caching authenticated responses ever be safe in AdonisJS?
Yes, if responses are cached with a user-specific cache key (e.g., based on user ID) and sensitive data is not stored in shared caches. Always avoid caching responses that contain credentials or user-specific data in shared caches without strict partitioning.
Should I remove Basic Auth headers from logs to prevent cache poisoning?
Yes. Ensure Authorization headers are not written to logs, metrics, or cache metadata. Use derived identifiers (like user ID) for logging and cache keys, and enforce Cache-Control headers to prevent unwanted caching of authenticated responses.