HIGH api rate abusefeathersjsmongodb

Api Rate Abuse in Feathersjs with Mongodb

Api Rate Abuse in Feathersjs with Mongodb — how this specific combination creates or exposes the vulnerability

FeathersJS is a framework that typically exposes REST and real-time endpoints backed by services, commonly using an adapter to persist data in Mongodb. When rate limiting is missing or misconfigured, an attacker can send many requests to a single service (e.g., authentication or high-cost aggregation endpoints) and overload the backend or degrade the experience for legitimate users. Because FeathersJS relies on Mongodb for storage and queries, a high request rate translates into many concurrent database operations, which can saturate connection pools, increase latency, and expose noisy failure paths that aid reconnaissance.

The vulnerability arises from a combination of three dimensions:

  • API design: FeathersJS auto-generates CRUD routes and can expose endpoints that perform unbounded queries or accept user-controlled filters. Without server-side limits, these endpoints are susceptible to bulk enumeration and resource exhaustion.
  • Mongodb behavior: Operations such as find, aggregate, and countDocuments can be expensive when unindexed or when filters match many documents. Under high concurrency, this increases CPU and I/O on the database and can trigger long-running operations or timeouts.
  • Transport and client patterns: If clients retry on failure or if fronting layers (load balancers, API gateways) buffer requests, the effective load on the FeathersJS + Mongodb stack can spike unexpectedly, amplifying the impact of missing rate controls.

Real-world patterns that increase risk include:

  • Unauthenticated endpoints that allow creating or updating resources (e.g., public signups or message posting) without per-identity throttling.
  • Use of $where, large $in clauses, or unindexed field lookups in Mongodb that cause collection scans under load.
  • WebSocket or real-time channels in FeathersJS that broadcast or echo messages without per-connection rate caps, enabling message flooding.

An attacker can probe such endpoints to observe response behavior, discover data patterns, or degrade service availability. Because FeathersJS often serves as a lightweight API layer, relying on Mongodb for persistence, the database becomes a natural choke point when rate limits are absent.

Mongodb-Specific Remediation in Feathersjs — concrete code fixes

Remediation focuses on applying rate limits at the FeathersJS service layer, validating and constraining Mongodb queries, and ensuring indexes align with common filter shapes. Below are concrete, working examples for a FeathersJS service using the MongoDB adapter.

1. Apply rate limits at the service hook

Use a hook to track identifiers (e.g., IP or user ID) and enforce a maximum number of requests within a time window. This example uses a simple in-memory map for demonstration; in production, use a shared store (e.g., Redis) in multi-instance deployments.

// src/hooks/rate-limit.js
const RATE_LIMIT_WINDOW_MS = 60_000; // 1 minute
const MAX_REQUESTS = 30;
const bucket = new Map();

function rateLimit(hook) {
  const context = hook.context;
  const source = context.params.provider === 'websocket' ? context.params.socketId : (context.params.headers['x-forwarded-for'] || context.params.ip);
  if (!source) return Promise.resolve(hook);

  const now = Date.now();
  const key = `${source}:${context.path}`;
  const record = bucket.get(key) || { count: 0, start: now };

  if (now - record.start > RATE_LIMIT_WINDOW_MS) {
    record.count = 0;
    record.start = now;
  }
  record.count += 1;

  if (record.count > MAX_REQUESTS) {
    throw new Error('Rate limit exceeded');
  }

  bucket.set(key, record);
  return Promise.resolve(hook);
}

module.exports = { rateLimit };

Register the hook on the service:

// src/services/messages/messages.hooks.js
const { rateLimit } = require('./rate-limit');

module.exports = {
  before: {
    all: [rateLimit],
    find: [],
    get: [],
    create: []
  },
  after: { all: [] },
  error: { all: [] }
};

2. Constrain and validate Mongodb queries

Avoid unbounded queries and ensure filters are limited in scope. Use explicit projection and whitelisted query shapes.

// src/services/items/items.service.js with constrained Mongodb adapter usage
const { MongoClient } = require('mongodb');
const url = 'mongodb://localhost:27017';
const client = new MongoClient(url);

module.exports = {
  async find(params) {
    await client.connect();
    const db = client.db('appdb');
    const collection = db.collection('items');

    // Whitelist allowed fields to prevent deep nesting attacks
    const allowedFields = new Set(['name', 'category', 'tags']);
    const filter = {};
    if (params.query.search) {
      // Use text index; avoid $where
      filter.$and = [
        { $or: [{ name: { $regex: params.query.search, $options: 'i' } }] }
      ];
    }

    // Enforce pagination to cap returned documents
    const limit = Math.min(parseInt(params.query.limit) || 50, 100);
    const skip = parseInt(params.query.skip) || 0;

    // Use indexes; ensure { category: 1, createdAt: -1 } exists
    const cursor = collection.find(filter).project({ name: 1, category: 1 }).skip(skip).limit(limit);
    const results = await cursor.toArray();
    await client.close();
    return results;
  },

  async create(data, params) {
    await client.connect();
    const db = client.db('appdb');
    const collection = db.collection('items');

    // Validate input shape to avoid injection or malformed writes
    const allowedKeys = new Set(['name', 'category', 'tags']);
    const doc = { $and: [] };
    for (const key of Object.keys(data)) {
      if (!allowedKeys.has(key)) continue;
      doc.$and.push({ [key]: data[key] });
    }
    // Example of safe insert with schema checks
    const result = await collection.insertOne({
      name: data.name,
      category: data.category,
      tags: Array.isArray(data.tags) ? data.tags : [],
      createdAt: new Date()
    });
    await client.close();
    return result.ops[0];
  }
};

3. Ensure indexes for query shape and aggregation safety

Create indexes that support common filter and sort patterns. For aggregations, avoid stages that cause in-memory sorts on large datasets without limits.

// Example Mongodb index commands (run once)
db.items.createIndex({ category: 1, createdAt: -1 });
db.items.createIndex({ name: 'text', tags: 'text' });

In FeathersJS, prefer service-level $limit and $sort over raw aggregation when possible, and avoid $where or regex on unindexed fields under high load.

Frequently Asked Questions

Does middleBrick analyze rate‑limit configurations in FeathersJS services?
middleBrick scans the runtime behavior of your API endpoints and reports on rate‑limiting findings; it does not inspect source code or configuration files directly.
Can middleBrick test Mongodb query safety for injection and performance issues?
middleBrick focuses on network‑level and API‑surface testing. It validates observable behaviors such as data exposure and injection indicators, but it does not perform static analysis of Mongodb query logic.