Denial Of Service in Adonisjs with Api Keys

Denial Of Service in Adonisjs with Api Keys — how this specific combination creates or exposes the vulnerability

A Denial of Service (DoS) scenario in AdonisJS when API keys are used centers on how authenticated routes validate and consume keys before business logic runs. If key validation is performed synchronously on every request without rate limiting or request size controls, an attacker can saturate the event loop and database connections by flooding the endpoint with invalid or valid keys, causing legitimate requests to time out. This is especially relevant when API keys are verified against a database or cache lookup that becomes a bottleneck under high concurrency.

In AdonisJS, routes often rely on middleware or an auth provider to resolve API keys. If the key validation step performs expensive operations—such as querying the database for every request, resolving scopes eagerly, or iterating over large related collections—an attacker can craft many concurrent requests that each trigger the same costly work. For example, a route that loads a key, then eagerly loads permissions, plans, and audit logs can amplify CPU and memory usage. The unauthenticated attack surface tested by middleBrick includes such authentication pathways; without rate limiting or request throttling, the system can exhaust resources and degrade availability.

Additionally, if API keys grant access to heavy read operations or file exports, an authenticated request triggered by a single key can consume significant bandwidth and response time. Combine this with missing input validation on parameters (e.g., large query filters or file exports), and a single crafted request can trigger server-side processing that ties up event loop threads. The interplay between key-based authentication and unprotected endpoints can transform a normal lookup into a vector for resource exhaustion, which aligns with BFLA/Privilege Escalation and Rate Limiting checks in middleBrick’s 12 parallel security scans.

Api Keys-Specific Remediation in Adonisjs — concrete code fixes

To mitigate DoS risks tied to API keys in AdonisJS, apply rate limiting at the route or global level, enforce request size caps, and ensure key validation is efficient and non-blocking. Prefer lightweight token lookups with caching, and avoid eager loading of heavy relations during authentication. Below are concrete patterns you can apply.

1. Rate limiting with the built-in Throttle provider

AdonisJS provides a throttle provider to limit repeated requests per key. Configure it to scope limits by key identifier so a flood from one key does not affect others.

// start/hooks.ts
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
import { throttle } from '@ioc:Adonis/Addons/Throttle'

export const middleware = () => {
  return {
    throttle: throttle({ windowMs: 60_000, max: 120 }) // 120 requests per minute per key
  }
}

2. Efficient key validation with cache and early exit

Validate API keys using a cached lookup to reduce database load. If the key is invalid, respond early to avoid unnecessary work.

// controllers/AuthController.ts
import ApiKey from 'App/Models/ApiKey'
import Cache from '@ioc:Adonis/Addons/Cache'

export default class AuthController {
  public async validateKey({ request, response }: HttpContextContract) {
    const key = request.header('X-API-Key')
    if (!key) {
      return response.unauthorized()
    }

    const cached = await Cache.get(`apikey:${key}`)
    if (cached) {
      request.apiKey = cached
      return
    }

    const entity = await ApiKey.query()
      .where('key', key)
      .preload('scopes') // keep preloads minimal
      .first()

    if (!entity) {
      response.status(401).json({ error: 'invalid_key' })
      return
    }

    await Cache.put(`apikey:${key}`, entity, '15m')
    request.apiKey = entity
  }
}

3. Limiting payload and export endpoints

Impose strict limits on request body size and the volume of data exported per key. Use AdonisJS built-in body parser limits and conditional checks before heavy processing.

// middleware/BodyLimit.ts
import { Exception } from '@ioc:Adonis/Core/Core'

export const bodyLimit = (maxBytes: number) => {
  return async ({ request, response, next }: HttpContextContract) => {
    if (request.hasBody()) {
      const size = request.getBodySize()
      if (size && size > maxBytes) {
        throw new Exception('Payload too large', 413, 'E_PAYLOAD_TOO_LARGE')
      }
    }
    await next()
  }
}

// routes.ts
import Route from '@ioc:Adonis/Core/Route'
import { bodyLimit } from 'App/Middleware/BodyLimit'

Route.post('export', [AuthController.exportData])
  .use(bodyLimit(50 * 1024 * 1024)) // 50 MB cap
  .middleware(['auth:api'])

4. Asynchronous logging and non-blocking audit trails

Defer audit logging to avoid blocking the response path. Use AdonisJS's Event emitter to offload write operations.

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