HIGH cache poisoningadonisjsdynamodb

Cache Poisoning in Adonisjs with Dynamodb

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

Cache poisoning in the AdonisJS + DynamoDB context occurs when an attacker can influence cache keys or cached response data in a way that causes subsequent users to receive unintended or malicious responses. Because AdonisJS applications often use in-memory or external caches to avoid repeated DynamoDB requests, unsafe cache key construction or unchecked cache content can turn the cache into an attack surface.

DynamoDB does not execute code or interpret data, but the application logic that reads and writes items can be tricked into storing or retrieving attacker-controlled values. For example, if the cache key is derived directly from user-supplied input without normalization or strict validation, two requests that differ only in casing, encoding, or injected metadata may map to distinct logical entries. An attacker may cause a poisoned entry to overwrite a legitimate cached item, leading to data leakage or inconsistent behavior for other users.

In AdonisJS, common patterns that increase risk include:

  • Using raw request parameters such as req.params.id or req.query.slug as part of the cache key without normalization.
  • Caching entire query responses that include user-specific fields (e.g., tenant identifiers) without scoping the key to the tenant.
  • Storing DynamoDB query results or metadata in cache and failing to validate that the data shape matches expectations before reuse.

Consider an endpoint that caches user profile data with a key like profile:${userId}. If userId is taken directly from a URL parameter and not validated as a UUID or numeric ID, an attacker could request /profile/123%2F%2Fevil or otherwise manipulate the string, producing a separate cache entry that may be returned to other users under certain routing or collision conditions. DynamoDB will store and retrieve the item based on the exact key, so the poisoned cache entry persists across requests.

Another scenario involves multi-tenant applications where tenant context is not enforced in the cache key. An authenticated user in tenant A might request data that is cached under a key that does not include the tenant ID. If tenant B’s data is later stored under the same key, user A could temporarily see tenant B’s data from the cache. DynamoDB itself remains consistent, but the application’s caching strategy introduces the cross-tenant exposure.

Because middleBrick tests unauthenticated attack surfaces and includes input validation and data exposure checks, it can surface these cache poisoning risks by identifying weak cache-key construction and insufficient separation of cached responses across users or tenants.

Dynamodb-Specific Remediation in Adonisjs — concrete code fixes

To mitigate cache poisoning when using DynamoDB with AdonisJS, focus on deterministic cache keys, tenant-aware scoping, and strict validation of cached content. The following patterns assume you are using the AWS SDK for JavaScript v3 and a cache layer such as Redis or an in-memory store integrated into your AdonisJS provider.

1. Deterministic, normalized cache keys

Normalize inputs before constructing cache keys. Strip unnecessary whitespace, enforce expected formats, and hash complex inputs to produce stable keys.

import { sha256 } from '@aws-crypto/sha256-js';

function cacheKeyForProfile(inputId: string): string {
  // Normalize: trim, lowercase, and ensure expected format
  const normalized = inputId.trim().toLowerCase();
  // Optionally enforce format, e.g., UUID or integer pattern
  const stable = /^[a-f0-9-]+$/.test(normalized) ? normalized : sha256(normalized).toString('hex');
  return `profile:${stable}`;
}

2. Tenant-aware caching

Include tenant identifiers in cache keys to prevent cross-tenant data exposure. If your app resolves tenant from request headers or subdomains, incorporate it into the key.

function cacheKeyForUserData(tenantId: string, userId: string): string {
  const safeTenant = tenantId.trim().toLowerCase();
  const safeUser = userId.trim().toLowerCase();
  return `tenant:${safeTenant}:user:${safeUser}:profile`;
}

3. Validate and sanitize cached responses

Before using cached data, validate its structure and ownership. Do not trust cached entries to contain only expected fields.

import { DynamoDBClient, GetItemCommand } from '@aws-sdk/client-dynamodb';

const client = new DynamoDBClient({});

async function getValidatedProfile(cacheKey: string, userId: string) {
  const cached = await cache.get(cacheKey);
  if (cached && cached.userId === userId && typeof cached.name === 'string') {
    return cached;
  }
  // Fallback to DynamoDB
  const cmd = new GetItemCommand({
    TableName: 'Profiles',
    Key: { userId: { S: userId } },
  });
  const { Item } = await client.send(cmd);
  if (!Item) return null;
  const profile = {
    userId: Item.userId.S,
    name: Item.name.S,
    email: Item.email?.S ?? null,
  };
  await cache.set(cacheKey, profile, { ttl: 300 });
  return profile;
}

4. Use parameterized queries and avoid concatenation

When constructing queries that inform cache behavior, use condition expressions and key condition expressions with placeholders rather than string concatenation to avoid injection-style cache manipulation.

import { QueryCommandInput } from '@aws-sdk/client-dynamodb';

const queryInput: QueryCommandInput = {
  TableName: 'Articles',
  KeyConditionExpression: 'authorId = :authorId',
  ExpressionAttributeValues: {
    ':authorId': { S: authorId.trim() },
  },
};

5. MiddleBrick integrations

Use the middleBrick CLI to validate your endpoints against cache poisoning indicators. Run middlebrick scan <url> to get findings on input validation and data exposure related to caching behavior. If you automate security in pipelines, the GitHub Action can fail builds when risk scores exceed your threshold, and the Pro plan’s continuous monitoring can schedule regular scans as your API evolves.

Frequently Asked Questions

Can DynamoDB itself be poisoned, or is this only an application-layer issue?
DynamoDB stores and retrieves items exactly as keyed; it does not interpret or execute cached data. Cache poisoning is an application-layer issue that arises from unsafe cache-key construction and insufficient validation of cached content, not from DynamoDB behavior.
How does middleBrick detect cache poisoning risks in an API that uses DynamoDB?
middleBrick’s input validation and data exposure checks examine how cache keys are derived and whether cached responses are scoped correctly. It does not test internal caching implementations directly but flags weak key construction and missing tenant scoping that can lead to poisoning when combined with DynamoDB storage.