HIGH denial of servicefeathersjsdynamodb

Denial Of Service in Feathersjs with Dynamodb

Denial Of Service in Feathersjs with Dynamodb — how this specific combination creates or exposes the vulnerability

FeathersJS is a framework for building JavaScript APIs and real-time applications. When FeathersJS services are backed by DynamoDB, certain application-level patterns can create denial-of-service (DoS) risks even though DynamoDB itself is a managed service. DoS in this combination typically arises from unbounded queries, missing pagination, tight loops that generate excessive request volume, and missing client-side guards that cause repeated or amplified requests to DynamoDB.

One common pattern is a service that queries DynamoDB without server-side pagination or limit enforcement. If a client requests a list without specifying $limit or if the service defaults to scanning a large table segment, the runtime can generate many strongly consistent reads or exhaust memory while assembling large result sets. In a FeathersJS hook or service method, failing to enforce a reasonable cap on params.query.$limit or not applying a default cap enables an authenticated or unauthenticated attacker to force heavy read usage, increasing cost and latency and potentially triggering AWS account-side throttling or errors that manifest as a DoS to legitimate users.

Another DoS vector is the N+1 query pattern in nested service calls. For example, a FeathersJS service might retrieve a list of items from DynamoDB and then, for each item, perform an additional get or query to fetch related data. If an endpoint returns hundreds of rows and each row triggers an extra DynamoDB operation, the total request volume can spike quickly, consuming Lambda concurrency or backend compute and causing timeouts or degraded response times. This pattern often appears when developers use FeathersJS hooks or models to enrich data without batching or caching, inadvertently turning a single logical request into many small DynamoDB calls.

Real-world attack scenarios mirror standard OWASP API Top 10 risks such as excessive data exposure and broken function-level authorization, but the DoS impact manifests through consumed read capacity, Lambda duration, and connection pool exhaustion. For instance, an unauthenticated endpoint that accepts arbitrary filter criteria without input validation can allow an attacker to submit deeply nested or inefficient queries that scan large portions of a DynamoDB table. Similarly, missing rate limiting at the FeathersJS layer can allow rapid, repeated calls that amplify the load on DynamoDB. Because DynamoDB does not block requests by default, the service must enforce sensible limits, batch operations, and validate inputs to avoid creating a self-inflicted DoS condition.

Dynamodb-Specific Remediation in Feathersjs — concrete code fixes

Remediation focuses on bounding requests, batching where possible, validating inputs, and applying sensible defaults in FeathersJS services that use DynamoDB. The following examples show concrete, working patterns.

1. Enforce pagination and limits in service params

Ensure every query to DynamoDB respects a maximum page size. In a FeathersJS service, read params.query and coerce or cap $limit before building the DynamoDB request.

const { DynamoDBDocumentClient, QueryCommand } = require("@aws-sdk/lib-dynamodb");
const ddbDocClient = DynamoDBDocumentClient.from(client);

class TodoService {
  constructor({ table, maxLimit = 50 }) {
    this.table = table;
    this.maxLimit = maxLimit;
  }

  async find(params) {
    const query = params.query || {};
    const limit = Math.min(
      Number(query.$limit) || 10,
      this.maxLimit
    );
    const lastKey = query.$lastKey ? JSON.parse(query.$lastKey) : undefined;

    const command = new QueryCommand({
      TableName: this.table,
      KeyConditionExpression: "userId = :uid",
      ExpressionAttributeValues: {
        ":uid": params.user.id,
      },
      Limit: limit,
      ExclusiveStartKey: lastKey || undefined,
    });

    const { Items, LastEvaluatedKey } = await ddbDocClient.send(command);
    return {
      total: Items.length,
      limit,
      skip: 0,
      data: Items,
      ...(LastEvaluatedKey && { next: { $lastKey: JSON.stringify(LastEvaluatedKey) } }),
    };
  }
}
module.exports = function (app) {
  app.use("/todos", new TodoService({ table: process.env.TODO_TABLE }));
};

2. Batch reads to avoid N+1 queries

Replace per-item get calls with a batch get using BatchGetCommand. In a Feathers hook or a custom method, collect IDs and fetch them in a single DynamoDB operation.

const { DynamoDBDocumentClient, BatchGetCommand } = require("@aws-sdk/lib-dynamodb");
const ddbDocClient = DynamoDBDocumentClient.from(client);

async function getRelatedItems(ids) {
  const command = new BatchGetCommand({
    RequestItems: {
      [process.env.RELATED_TABLE]: {
        Keys: ids.map((id) => ({ id })),
      },
    },
  });
  const { Responses } = await ddbDocClient.send(command);
  return Responses[process.env.RELATED_TABLE] || [];
}

// Usage in a Feathers before hook
app.service("items").hooks({
  before: {
    async find(context) {
      const ids = context.result.data.map((r) => r.relatedId);
      const related = await getRelatedItems(ids);
      const map = new Map(related.map((r) => [r.id, r]));
      context.result.data = context.result.data.map((row) => ({
        ...row,
        relatedData: map.get(row.relatedId) || null,
      }));
      return context;
    },
  },
});

3. Validate and sanitize query inputs

Reject or sanitize filter values that could trigger large scans. For queries that use a filter on non-key attributes, enforce allowlists and reject overly broad expressions that could scan the table.

app.service("reports").hooks({
  before: {
    find(context) {
      const query = context.params.query || {};
      if (query.status && !["open", "closed", "pending"].includes(query.status)) {
        throw new Error("Invalid status filter");
      }
      if (query.$limit && Number(query.$limit) > 100) {
        query.$limit = 100;
      }
      if (query.$sort) {
        // Only allow sorting on indexed fields
        const allowedSort = ["createdAt", "updatedAt"];
        const sortField = query.$sort.split(":")[0];
        if (!allowedSort.includes(sortField)) {
          throw new Error("Sorting on this field is not allowed");
        }
      }
      return context;
    },
  },
});

4. Apply rate limiting and circuit-breaker patterns at the Feathers layer

Use in-memory or external rate limiting to prevent bursts that amplify DynamoDB load. While FeathersJS does not include built-in rate limiting, you can integrate a lightweight middleware or use package-level guards to limit requests per user/IP within a sliding window.

const rateLimit = new Map();
function rateLimitMiddleware(max = 30, windowMs = 60_000) {
  return function (context, next) {
    const user = context.params.user?.id || context.params.ip || "anonymous";
    const now = Date.now();
    const entry = rateLimit.get(user) || { count: 0, reset: now + windowMs };
    if (now > entry.reset) {
      entry.count = 0;
      entry.reset = now + windowMs;
    }
    entry.count += 1;
    if (entry.count > max) {
      const err = new Error("Too many requests");
      err.status = 429;
      throw err;
    }
    rateLimit.set(user, entry);
    return next();
  };
}
app.use(rateLimitMiddleware(30, 60_000));

5. Use DynamoDB features to reduce fan-out load

Design your table and queries to minimize repeated scans. Use sparse indexes, projection expressions to return only required attributes, and DAX or caching for hot keys. In FeathersJS, prefer selective projections via params.query.$select and avoid returning every attribute by default.

app.service("messages").find({
  query: {
    $select: "messageId,content,timestamp",
    $limit: 20,
    userId: "user-123",
  },
});

Related CWEs: resourceConsumption

CWE IDNameSeverity
CWE-400Uncontrolled Resource Consumption HIGH
CWE-770Allocation of Resources Without Limits MEDIUM
CWE-799Improper Control of Interaction Frequency MEDIUM
CWE-835Infinite Loop HIGH
CWE-1050Excessive Platform Resource Consumption MEDIUM

Frequently Asked Questions

Can DoS risks in FeathersJS with DynamoDB be detected by middleBrick scans?
middleBrick scans the unauthenticated attack surface and can flag missing input validation, missing limits on list endpoints, and signs of excessive query patterns that commonly precede DoS conditions. Findings include severity and remediation guidance.
Does middleBrick fix DoS findings automatically?
middleBrick detects and reports findings with remediation guidance; it does not fix, patch, block, or remediate. Developers should apply the suggested code changes and limits to harden the service.