HIGH cache poisoningsailsapi keys

Cache Poisoning in Sails with Api Keys

Cache Poisoning in Sails with Api Keys — how this specific combination creates or exposes the vulnerability

Cache poisoning in Sails occurs when an attacker causes cached responses to be stored with attacker-controlled data, leading to other users receiving malicious or incorrect content. When API keys are used for identification but not properly validated or scoped, a Sails endpoint may cache a response keyed by the API key and later serve that cached response to a different consumer. This can happen if the cache key does not include a tenant or user context, or if the implementation trusts API key parameters that an attacker can influence.

In Sails, caching is often implemented via policies or services that store HTTP responses or computed data. If a route like /api/v1/reports uses an API key header or query parameter to identify access rights but caches the response without including the API key or a derived tenant identifier in the cache key, one consumer’s cached data can be served to another consumer. For example, an authenticated service account with a valid API key could receive cached data intended for another account if the cache improperly uses only the endpoint path or a shared key.

Attack patterns enabled by this combination include:

  • Cross-tenant data leakage: A response cached for one API key is served to another, exposing sensitive information.
  • Cache injection: Manipulating parameters that influence cache key generation so that attacker-controlled content is stored and subsequently served.
  • Authorization bypass via cache: If authorization checks are performed only at the origin but caching occurs afterward, cached responses may skip those checks.

To illustrate, consider a Sails controller that caches responses based on URL and query parameters but does not include the API key in the cache key. An attacker who discovers or guesses another party’s API key might craft requests that cause the shared cache to store responses keyed by that key, leading to inadvertent data exposure when the legitimate key holder’s requests are served poisoned cache entries.

Real-world parallels include misconfigured CDN or reverse-proxy caches where query parameters such as api_key are omitted from cache keys, allowing one user’s data to be retrieved by another. This aligns with common web cache poisoning techniques where non-unique inputs are improperly trusted.

Api Keys-Specific Remediation in Sails — concrete code fixes

Remediation focuses on ensuring cache keys incorporate the API key or a derived, immutable tenant/scope identifier, and that authorization is enforced before caching. Avoid using user-influenced parameters directly in cache keys without normalization and strict validation.

Example secure Sails controller with explicit cache key composition and authorization checks:

// api/controllers/ReportController.js
module.exports = {
  async getReport(req, res) {
    const apiKey = req.headers['x-api-key'];
    if (!apiKey) {
      return res.unauthorized('Missing API key');
    }

    // Validate and normalize the API key (e.g., look up associated tenant)
    const account = await ApiKey.findOne({ key: apiKey });
    if (!account) {
      return res.unauthorized('Invalid API key');
    }

    // Build a cache key that includes tenant/account to prevent cross-tenant poisoning
    const cacheKey = `report:${account.id}:${req.param('reportId')}`;
    const cached = await CacheService.get(cacheKey);
    if (cached) {
      return res.ok(cached);
    }

    // Perform authorization for the specific report
    const allowed = await ReportsPolicy.canView(req, account);
    if (!allowed) {
      return res.forbidden('Access denied');
    }

    const report = await Reports.getReport(req.param('reportId'));
    await CacheService.setex(cacheKey, 300, report); // cache with tenant-aware key
    return res.ok(report);
  }
};

Key practices:

  • Include the tenant or account identifier derived from the API key in the cache key.
  • Validate and normalize the API key before use; do not trust raw input values for cache control.
  • Perform authorization checks before retrieving or storing cache entries.
  • If using HTTP caching headers, ensure Vary headers include the API key or an equivalent scope indicator to prevent shared caches from returning inappropriate responses.

When integrating with infrastructure-level caching (e.g., CDN or reverse proxy), configure cache keys to incorporate the API key or a hashed tenant identifier, and avoid caching responses for privileged or sensitive endpoints without strict scoping.

Frequently Asked Questions

How can I test whether my Sails API is vulnerable to cache poisoning via API keys?
Use a scanner like middleBrick which includes unauthenticated and authenticated checks for cache poisoning indicators. Manually verify that cache keys include tenant or API key scope and that authorization is enforced prior to caching.
Does using API keys alone prevent cache poisoning in Sails?
No. API keys must be incorporated into cache key design and validated for scope; simply requiring a key does not prevent cross-tenant caching issues if the cache key is not tenant-aware.