HIGH rate limiting bypassadonisjsapi keys

Rate Limiting Bypass in Adonisjs with Api Keys

Rate Limiting Bypass in Adonisjs with Api Keys — how this specific combination creates or exposes the vulnerability

A rate limiting bypass in an AdonisJS application that uses API keys commonly arises when limits are enforced per route or per IP, but not consistently tied to the authenticated API key identity. AdonisJS does not apply rate limiting automatically to API key validation logic unless explicitly configured. If API key verification occurs after the rate limit check, or if the limit is scoped to IP address rather than to the key itself, an attacker can rotate keys to exhaust the quota without being throttled.

Consider an endpoint that first validates the API key header to determine the associated tenant or user, then performs business logic. If rate limiting is implemented at the route level using a generic in-memory store or a shared Redis counter without including the API key as part of the rate limit key, requests from different keys are counted separately. This allows an attacker with multiple keys to issue parallel or sequential requests, each appearing within the allowed limit, while cumulatively overwhelming the backend.

Insecure implementations may also leak information via response timing or status codes. If a key is rejected due to being disabled or revoked before the rate limiter runs, the response may differ from a valid key that has hit its quota, enabling enumeration. Similarly, missing validation on the key format can lead to key confusion or injection, where an attacker substitutes a valid key for another identity, bypassing tenant isolation and rate limits that depend on identity.

A concrete attack pattern involves an unauthenticated probe of the API to discover key acceptance behavior, followed by rapid cycling of keys to exploit the lack of a composite key+identifier rate limit. This maps to common OWASP API Top 10 categories such as Broken Object Level Authorization (BOLA) and excessive resource consumption, and may be observable in scans that flag missing rate limiting on authenticated paths or inconsistent limits across authentication methods.

middleBrick detects this class of risk by correlating OpenAPI/Swagger specifications (including $ref resolution for securitySchemes and path items) with runtime behavior across the unauthenticated attack surface. The tool checks whether rate limiting is applied before authentication, whether the limit scope includes the API key, and whether responses vary in ways that disclose key validity. Findings include severity, contextual guidance, and references to frameworks such as OWASP API Top 10 to support remediation planning.

Api Keys-Specific Remediation in Adonisjs — concrete code fixes

To remediate rate limiting bypass risks when using API keys in AdonisJS, enforce limits on the key itself and ensure validation occurs before business logic. Use a stable key extraction method and make the rate limit key include the normalized key value to prevent key rotation abuse.

Example secure API key setup with consistent identification and rate limiting:

// config/api_keys.ts
export default {
  provider: 'redis',
  keyHeader: 'X-API-Key',
  rateLimitWindowMs: 60_000,
  rateLimitMax: 100,
};

Middleware that validates the key early and binds rate limiting to the key:

// start/hooks/api-key-middleware.ts
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
import ApiKeyService from 'App/Services/ApiKeyService'
import RateLimiter from 'App/Services/RateLimiter'

export default async function apiKeyMiddleware(ctx: HttpContextContract) {
  const key = ctx.request.header('X-API-Key')
  if (!key || typeof key !== 'string') {
    return ctx.response.unauthorized({ error: 'api_key_missing' })
  }

  const identity = await ApiKeyService.lookupByKey(key.trim())
  if (!identity || identity.status !== 'active') {
    return ctx.response.unauthorized({ error: 'invalid_api_key' })
  }

  const allowed = await RateLimiter.allow({
    subject: identity.id,
    windowMs: 60_000,
    max: 100,
    keyPrefix: 'apikey_rl',
  })
  if (!allowed) {
    return ctx.response.tooManyRequests({ error: 'rate_limit_exceeded' })
  }

  ctx.auth.user = identity.user
  await ctx.next()
}

Rate limiter service using Redis with the API key identity as part of the key to ensure shared quota enforcement:

// app/Services/RateLimiter.ts
import Redis from '@ioc:Adonis/Addons/Redis'

export default class RateLimiter {
  static async allow(params: { subject: string; windowMs: number; max: number; keyPrefix: string }) {
    const { subject, windowMs, max, keyPrefix } = params
    const key = `${keyPrefix}:${subject}`
    const current = await Redis.incr(key)
    if (current === 1) {
      await Redis.expire(key, Math.ceil(windowMs / 1000))
    }
    return current <= max
  }
}

In routes definition, apply the middleware before sensitive routes and avoid duplicating limits at the route level without key scope:

// start/routes.ts
Route.group(() => {
  Route.get('/reports/:id', ReportsController.show)
  Route.post('/data', DataController.store)
})
  .middleware(['apiKey'])
  .prefix('api/v1')

Additionally, normalize keys before storage and comparison to avoid case-sensitive bypasses, and ensure that the same key value always maps to the same identity. When using multiple environments or tenants, include a tenant or environment prefix in the rate limit key to prevent cross-tenant quota sharing. middleBrick supports scanning these configurations by analyzing the OpenAPI spec and runtime behavior; its dashboard can track scores over time, while the CLI allows integration into scripts and the GitHub Action can fail builds if security thresholds are not met.

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

How does including the API key in the rate limit key prevent bypasses?
Including the API key (or a normalized identity derived from it) in the rate limit key ensures that quotas are bound to the authenticated key rather than to IP or route alone. This prevents attackers from rotating keys or sharing a single key to exhaust limits, because each distinct key has its own independent count.
What should I verify in an OpenAPI spec to ensure rate limiting is correctly scoped to API keys?
Check that securitySchemes define an apiKey type and that paths requiring keys reference this scheme. Confirm that servers and paths do not omit security requirements for some operations, and validate that x-rate-limit or vendor extensions (if used) are consistently applied to key-authenticated routes. middleBrick can correlate these spec definitions with runtime findings to highlight missing or inconsistent rate limiting.