HIGH broken authenticationfeathersjsdynamodb

Broken Authentication in Feathersjs with Dynamodb

Broken Authentication in Feathersjs with Dynamodb — how this specific combination creates or exposes the vulnerability

FeathersJS is a framework for real-time applications that often uses authentication hooks to manage identity and tokens. When integrating with Amazon DynamoDB as the user store, misconfigurations at the intersection of FeathersJS authentication logic and DynamoDB access patterns can lead to Broken Authentication. This occurs when identity verification, session handling, or credential validation rely on DynamoDB queries that are incomplete, improperly scoped, or bypassed due to missing authorization checks.

One common pattern is storing user records in a DynamoDB table keyed by user ID, with the partition key set to a user identifier (e.g., user_id). If FeathersJS authentication hooks do not enforce consistent ownership checks—relying only on the presence of a JWT or session cookie—an attacker can manipulate identifiers to access other users' records. For example, an authenticated request may include a user ID in the URL or query parameters, and if the FeathersJS service does not validate that the authenticated subject matches the requested ID, the DynamoDB query may return data for the wrong user, resulting in Insecure Direct Object Reference (IDOR), a subset of Broken Authentication.

Additionally, Weak Password Storage practices can amplify risk. If user passwords are stored in DynamoDB without strong adaptive hashing (e.g., using bcrypt or argon2), credential leakage or offline brute-force becomes feasible. FeathersJS authentication plugins may accept credentials and query DynamoDB with a simple email = :email filter, but if the response includes the password hash and the application layer does not properly compare hashes before issuing tokens, an attacker who can observe or intercept authentication responses may infer valid credentials.

DynamoDB-specific access patterns also contribute. Because DynamoDB does not enforce referential integrity, orphaned or stale tokens may remain in tables if revocation logic is not implemented. FeathersJS may maintain session or token records in DynamoDB; if these are not invalidated on logout or password change, an attacker can reuse them. Furthermore, unencrypted data at rest in DynamoDB combined with overly permissive IAM policies can allow unauthorized access to user credential material, enabling authentication bypass through credential replay.

Real-world attack patterns mirror OWASP API Top 10 #2 Broken Authentication. For instance, an attacker might probe endpoints with manipulated user IDs to enumerate valid accounts (IDOR), or attempt to exploit missing rate limiting on authentication endpoints to conduct credential stuffing. These issues are detectable through spec-aware scanning that cross-references OpenAPI definitions of authentication paths with runtime behavior, highlighting where DynamoDB queries do not align with expected subject ownership.

Dynamodb-Specific Remediation in Feathersjs — concrete code fixes

Remediation centers on ensuring that every DynamoDB data access is bound to the authenticated subject and that credential handling follows security best practices. Below are concrete code examples for a FeathersJS service using the AWS SDK for JavaScript v3.

1. Secure user lookup by authenticated subject

Always include the authenticated user ID in the DynamoDB key condition, rather than trusting request-supplied identifiers.

import { DynamoDBClient, GetCommand } from "@aws-sdk/client-dynamodb";
import { unmarshall } from "@aws-sdk/util-dynamodb";

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

async function getUserByIdentity(userId) {
  const command = new GetCommand({
    TableName: process.env.USERS_TABLE,
    Key: {
      user_id: { S: userId } // enforce partition key matches authenticated subject
    }
  });
  const response = await client.send(command);
  return response.Item ? unmarshall(response.Item) : null;
}

In a FeathersJS hook, bind params.user._id (set by authentication) to the query key, and reject requests where the provided ID does not match.

2. Parameterized queries to prevent injection and ensure scoping

Use DynamoDB condition expressions to enforce ownership within a single request, avoiding ambiguous scans.

import { DynamoDBClient, QueryCommand } from "@aws-sdk/client-dynamodb";
import { marshall, unmarshall } from "@aws-sdk/util-dynamodb";

async function findUserSessions(userId) {
  const command = new QueryCommand({
    TableName: process.env.SESSIONS_TABLE,
    KeyConditionExpression: "user_id = :uid",
    ExpressionAttributeValues: marshall({ ":uid": userId })
  });
  const response = await client.send(command);
  return response.Items.map(unmarshall);
}

Never construct DynamoDB expressions by concatenating user input. Always use expression attribute values to prevent injection and ensure the partition key is constrained to the authenticated user.

3. Strong password storage and verification

Store passwords using a dedicated hashing library and verify within the authentication hook before issuing tokens.

import bcrypt from "bcryptjs";

async function verifyPassword(inputPassword, storedHash) {
  return await bcrypt.compare(inputPassword, storedHash);
}

// In a custom authentication hook
async function localAuthenticate(email, password) {
  const user = await getUserByEmail(email); // uses secure DynamoDB query
  if (!user) throw new Error("Invalid credentials");
  const valid = await verifyPassword(password, user.password_hash);
  if (!valid) throw new Error("Invalid credentials");
  return { ...user, password_hash: undefined };
}

Ensure the DynamoDB table stores only the hash and never the plaintext password. Use sufficient work factors (e.g., salt rounds ≥ 10).

4. Token and session management with DynamoDB

Maintain revocable sessions by storing session records with TTL and binding them to subject identifiers. On logout, delete the specific session item.

import { DynamoDBClient, PutCommand, DeleteCommand } from "@aws-sdk/client-dynamodb";

async function createSession(userId, sessionId, expiresAt) {
  const command = new PutCommand({
    TableName: process.env.SESSIONS_TABLE,
    Item: {
      session_id: { S: sessionId },
      user_id: { S: userId },
      expires_at: { N: String(Math.floor(expiresAt.getTime() / 1000)) },
      created_at: { N: String(Math.floor(Date.now() / 1000)) }
    }
  });
  await client.send(command);
}

async function revokeSession(sessionId) {
  const command = new DeleteCommand({
    TableName: process.env.SESSIONS_TABLE,
    Key: {
      session_id: { S: sessionId }
    }
  });
  await client.send(command);
}

Configure DynamoDB Time to Live (TTL) on the session table to automatically purge expired sessions, reducing the window for token reuse.

5. Least-privilege IAM and encryption

Ensure the DynamoDB credentials used by FeathersJS have least privilege: only allow dynamodb:GetItem, dynamodb:Query, and dynamodb:PutItem on specific tables. Enable encryption at rest using AWS KMS and enforce TLS for all service communications.

Related CWEs: authentication

CWE IDNameSeverity
CWE-287Improper Authentication CRITICAL
CWE-306Missing Authentication for Critical Function CRITICAL
CWE-307Brute Force HIGH
CWE-308Single-Factor Authentication MEDIUM
CWE-309Use of Password System for Primary Authentication MEDIUM
CWE-347Improper Verification of Cryptographic Signature HIGH
CWE-384Session Fixation HIGH
CWE-521Weak Password Requirements MEDIUM
CWE-613Insufficient Session Expiration MEDIUM
CWE-640Weak Password Recovery HIGH

Frequently Asked Questions

How can I test if my FeathersJS + DynamoDB authentication is vulnerable to IDOR?
Use an authenticated session to query endpoints with altered user identifiers that do not belong to the subject of the token. If the response returns data for a different user without explicit ownership checks, the integration may be vulnerable. middleBrick can detect this by correlating OpenAPI parameter definitions with runtime DynamoDB queries.
Does enabling DynamoDB encryption at rest automatically fix Broken Authentication?
No. Encryption at rest protects data confidentiality but does not prevent authentication bypass or IDOR. You must still enforce subject-bound queries, secure password storage, and proper session invalidation in FeathersJS.