HIGH path traversalexpressdynamodb

Path Traversal in Express with Dynamodb

Path Traversal in Express with Dynamodb — how this specific combination creates or exposes the vulnerability

Path Traversal occurs when an attacker manipulates a file or key path to access resources outside the intended directory or scope. In an Express API that uses DynamoDB as a backend, this typically surfaces through user-supplied parameters such as :filename, id, or key that are used to construct DynamoDB keys or query expressions without proper validation or escaping. Because DynamoDB stores data in a flat key-value model, logical path-like identifiers (e.g., tenantId/recordId or user/123/profile) can be abused if concatenated directly from request input, leading to unauthorized cross-partition or cross-object access.

An Express route that builds a DynamoDB KeyConditionExpression or a partition key from raw URL segments is vulnerable. For example, an endpoint like /users/:userId/profile may naïvely set Key = { PartitionKey: 'USER#' + req.params.userId }. If an attacker provides a crafted userId such as ../../../admin, and the application does not normalize or validate the parameter, the resulting key can traverse logical boundaries, potentially accessing other users’ data when the application’s key design uses hierarchical prefixes. DynamoDB itself does not interpret path separators, but the application logic that builds keys does; if those keys map to sensitive logical paths (e.g., ADMIN/audit/2024), data exposure occurs. This becomes critical when combined with insufficient authorization checks, effectively bypassing intended access controls.

Another scenario involves file-like references stored in DynamoDB, where object keys in an underlying storage layer (e.g., S3) are derived from user input. An Express endpoint that retrieves a document by id and uses that id to build an S3 key can allow path traversal if the id contains sequences like ../../secrets. Even when DynamoDB access is properly scoped, unsafe composition of storage paths leads to reading or overwriting unintended objects. The risk is amplified when the API exposes endpoints that accept multiple identifiers (e.g., /export/:tenantId/:reportName) without validating format or enforcing strict allowlists.

Middleware that performs naive string concatenation or uses deprecated path utilities can compound the issue. For instance, using path.join on user-controlled segments without canonicalization may not remove all traversal patterns when inputs contain encoded or mixed slashes. Since DynamoDB queries often rely on exact key matches, a malformed key can return no data in some cases, but in others, it may match a broader prefix than intended, returning multiple sensitive items. Therefore, the combination of Express routing, dynamic key construction, and DynamoDB’s partition key semantics creates a clear path for traversal when input validation and strict key design are omitted.

Dynamodb-Specific Remediation in Express — concrete code fixes

To mitigate Path Traversal in Express with DynamoDB, enforce strict input validation, canonicalize identifiers, and avoid direct concatenation of user input into DynamoDB keys or query expressions. Use allowlists for known-safe characters, enforce length limits, and normalize paths before using them as keys. Below are concrete, secure patterns for Express handlers.

Secure DynamoDB key construction

Always derive partition and sort keys from a controlled source, not raw user input. Use a mapping layer to translate validated identifiers to DynamoDB keys.

// Safe key construction in Express with DynamoDB DocumentClient
const { DynamoDBClient, GetCommand } = require('@aws-sdk/lib-dynamodb');
const client = new DynamoDBClient({ region: 'us-east-1' });

app.get('/users/:userId/profile', async (req, res) => {
  const { userId } = req.params;

  // Validate userId: alphanumeric + underscore, 3..36 chars
  if (!/^[A-Za-z0-9_]{3,36}$/.test(userId)) {
    return res.status(400).json({ error: 'Invalid user identifier' });
  }

  const command = new GetCommand({
    TableName: process.env.USERS_TABLE,
    Key: { PK: `USER#${userId}`, SK: 'PROFILE' },
  });

  try {
    const { Item } = await client.send(command);
    if (!Item) return res.status(404).json({ error: 'Not found' });
    res.json(Item);
  } catch (err) {
    res.status(500).json({ error: 'Internal server error' });
  }
});

Parameterized queries with condition expressions

Use ExpressionAttributeValues instead of string interpolation to avoid injection and traversal via crafted keys.

// Parameterized query to avoid path traversal in KeyConditionExpression
const { DynamoDBClient, QueryCommand } = require('@aws-sdk/lib-dynamodb');
const client = new DynamoDBClient({ region: 'us-east-1' });

app.get('/tenant/:tenantId/reports', async (req, res) => {
  const { tenantId } = req.params;

  if (!/^[A-Za-z0-9-]+$/.test(tenantId)) {
    return res.status(400).json({ error: 'Invalid tenant identifier' });
  }

  const command = new QueryCommand({
    TableName: process.env.REPORTS_TABLE,
    KeyConditionExpression: 'PK = :pk',
    ExpressionAttributeValues: {
      ':pk': `TENANT#${tenantId}`,
    },
  });

  try {
    const { Items } = await client.send(command);
    res.json(Items || []);
  } catch (err) {
    res.status(500).json({ error: 'Internal server error' });
  }
});

Safe file-like references for external storage

If your DynamoDB items reference objects in another storage system (e.g., S3), validate and scope the path before constructing storage keys.

// Validate and scope paths before using them to reference external objects
const path = require('path');

function safeStorageKey(base, userSupplied) {
  const normalized = path.normalize(userSupplied).replace(/^(\/|\.\.\/)/, '');
  return path.join(base, normalized);
}

app.get('/documents/:docId', async (req, res) => {
  const { docId } = req.params;
  if (!/^[A-Za-z0-9_-]+$/.test(docId)) {
    return res.status(400).json({ error: 'Invalid document identifier' });
  }

  const storageKey = safeStorageKey('tenant-assets', docId);
  // Use storageKey with S3 getObject, ensuring base directory containment
  res.json({ storageKey });
});

General defenses

  • Use allowlists for identifiers; reject any unexpected patterns.
  • Do not trust path.join alone to prevent traversal—validate and canonicalize inputs explicitly.
  • Scope DynamoDB access patterns to least privilege via partition key design, avoiding broad scans that could amplify traversal effects.

Related CWEs: inputValidation

CWE IDNameSeverity
CWE-20Improper Input Validation HIGH
CWE-22Path Traversal HIGH
CWE-74Injection CRITICAL
CWE-77Command Injection CRITICAL
CWE-78OS Command Injection CRITICAL
CWE-79Cross-site Scripting (XSS) HIGH
CWE-89SQL Injection CRITICAL
CWE-90LDAP Injection HIGH
CWE-91XML Injection HIGH
CWE-94Code Injection CRITICAL

Frequently Asked Questions

Can Path Traversal in Express with DynamoDB lead to unauthorized data access?
Yes. If user input is concatenated into DynamoDB keys or query expressions without validation, an attacker can traverse logical paths and access data belonging to other users or tenants.
Does middleBrick detect Path Traversal risks in Express APIs using DynamoDB?
middleBrick scans unauthenticated attack surfaces and includes input validation checks; findings include path traversal indicators with severity, prioritization, and remediation guidance per category.