HIGH path traversalhapidynamodb

Path Traversal in Hapi with Dynamodb

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

Path Traversal in a Hapi application that uses DynamoDB typically arises when user-controlled path segments are used to construct keys or query parameters without strict validation or canonicalization. Hapi routes often pass request parameters (e.g., params.id or query strings) into data access logic. If these values are concatenated into a DynamoDB key condition or used to build file-like identifiers (e.g., folder-based key names), an attacker can supply sequences like ../../../sensitive to escape intended namespace boundaries.

DynamoDB itself does not have a filesystem path concept, but path traversal manifests here through key design and access patterns. For example, a poorly designed partition key might embed a path hierarchy (e.g., tenantId/locale/resourceId). If an Hapi route builds a KeyConditionExpression using raw user input without sanitization, an attacker can manipulate the key traversal to target items outside their tenant or intended scope. This can lead to horizontal IDOR when multi-tenant data is stored under shared table prefixes and access checks are incomplete.

Consider an Hapi route that retrieves a user profile using a path-like identifier:

// Unsafe: directly using user input to build DynamoDB KeyConditionExpression
const key = `${tenantId}/${userId}`;
const params = {
  TableName: 'UserProfiles',
  KeyConditionExpression: 'pk = :pk',
  ExpressionAttributeValues: { ':pk': key },
};

If userId comes from an unvalidated parameter and includes path traversal sequences, an attacker can craft a userId such as ../../../admin/123, causing the partition key to resolve to a different tenant’s data. Even when using DynamoDB’s native key structure, logical path traversal occurs when authorization checks are performed after key construction, allowing an attacker to read or modify items they should not access.

Another scenario involves file-like object references stored in DynamoDB where the primary key includes a path derived from user input. If the Hapi service uses this key to later generate pre-signed URLs or invoke other services, traversal in the logical path can lead to unauthorized access across logical boundaries. While DynamoDB does not interpret path separators, the application’s mapping from logical paths to keys must be validated to prevent privilege escalation or data exposure.

Dynamodb-Specific Remediation in Hapi — concrete code fixes

To prevent path traversal in Hapi when working with DynamoDB, validate and sanitize all user input used to construct keys, KeyConditionExpression, or attribute values. Use allowlists for known identifiers and enforce strict character rules. Avoid concatenating raw user input into key strings; instead, use parameter binding and structured access patterns.

Below is a secure Hapi route example that validates and uses a numeric user ID to build a DynamoDB query:

const Hapi = require('@hapi/hapi');
const { DynamoDBClient, QueryCommand } = require('@aws-sdk/client-dynamodb');

const client = new DynamoDBClient({ region: 'us-east-1' });

const validateUserId = (value) => {
  // Allow only digits, ensuring no path traversal or injection
  return /^[0-9]+$/.test(value);
};

const server = Hapi.server({ port: 4000, host: 'localhost' });

server.route({
  method: 'GET',
  path: '/profiles/{tenantId}/{userId}',
  handler: async (request) => {
    const { tenantId, userId } = request.params;

    // Validate tenantId and userId to prevent path traversal
    if (!/^[a-zA-Z0-9_-]{1,64}$/.test(tenantId)) {
      throw Boom.badRequest('Invalid tenant identifier');
    }
    if (!validateUserId(userId)) {
      throw Boom.badRequest('Invalid user identifier');
    }

    const params = {
      TableName: 'UserProfiles',
      KeyConditionExpression: 'pk = :pk AND begins_with(sk, :sk)',
      ExpressionAttributeValues: {
        ':pk': { S: `tenant#${tenantId}` },
        ':sk': { S: `user#${userId}` },
      },
    };

    try {
      const command = new QueryCommand(params);
      const response = await client.send(command);
      return response.Items || [];
    } catch (error) {
      console.error('DynamoDB query error:', error);
      throw Boom.internal('Unable to retrieve profiles');
    }
  },
});

(async () => {
  await server.start();
  console.log('Server running on %s', server.info.uri);
})();

In this example, tenantId and userId are validated before being used in DynamoDB attribute values. The partition key is built using a controlled prefix (tenant#) and the validated tenantId, while the sort key uses a validated userId. This prevents path-like traversal by disallowing characters that could change namespace interpretation.

For broader protection, apply middleware in Hapi to normalize and reject unexpected input patterns, and ensure authorization logic re-validates tenant context on every request. Use DynamoDB’s native data types safely and avoid building key strings from concatenated user-controlled segments without strict checks.

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 occur in DynamoDB if the database itself doesn’t use paths?
Yes. Path traversal manifests logically in DynamoDB when application code constructs keys or queries using user input that includes separators, enabling attackers to access data outside intended tenant or namespace boundaries through improper key design.
What validation approach is recommended for identifiers used with DynamoDB in Hapi?
Use strict allowlists (e.g., alphanumeric plus limited symbols), enforce length limits, and avoid passing raw user input into key expressions. Validate inputs before building ExpressionAttributeValues and prefer parameterized queries over string concatenation.