HIGH dictionary attackadonisjsapi keys

Dictionary Attack in Adonisjs with Api Keys

Dictionary Attack in Adonisjs with Api Keys — how this specific combination creates or exposes the vulnerability

A dictionary attack against an AdonisJS API that relies on API keys can occur when the authentication layer accepts a wide range of candidate values without limiting attempts or detecting abnormal request patterns. AdonisJS does not enforce rate limiting on authentication routes by default, so an attacker can submit many key guesses in rapid succession. If the application responds differently depending on whether a candidate key is valid (e.g., 200 vs 401, or revealing user context), this behavior becomes an oracle that accelerates the guessing process.

In AdonisJS, API keys are often validated via a provider or guard that loads a record from the database. A typical implementation might look up the key and attach the associated user or scope to the request. If the lookup is performed with a plain query without constant-time comparison, subtle timing differences can leak information. Moreover, if routes protected by the API key guard do not apply per-route or per-scope rate limits, an authenticated attacker with a low-privilege key can probe adjacent endpoints to map the API surface and escalate abuse.

The combination of weak key generation (predictable entropy), lack of attempt throttling, and verbose error messages compounds the risk. For example, an attacker using a common wordlist can iterate through likely keys while monitoring response status codes and timing. Successful guesses provide persistent access until the key is rotated. Because the API key is often stored as a bearer token, interception via logs or network sniffing further amplifies exposure. The attack maps to the OWASP API Security Top 10 categories, particularly BOLA/IDOR when access controls are insufficient and Authentication issues when brute-force resistance is missing.

middleBrick scans identify such patterns by testing unauthenticated attack surfaces and comparing responses across multiple guesses, highlighting deviations that indicate oracle behavior. Findings include missing rate limiting on authentication paths, inconsistent status codes, and overly broad key scopes that enable lateral movement. Remediation focuses on hardening the authentication flow rather than attempting to block attacks at the network edge.

Api Keys-Specific Remediation in Adonisjs — concrete code fixes

To secure API keys in AdonisJS, apply rate limiting at the authentication endpoint, enforce constant-time comparisons, and scope keys with minimal privileges. Below are concrete changes and code examples.

1. Apply rate limiting to the key validation route

Use AdonisJS middleware to limit attempts per IP or API key prefix. This reduces the feasibility of dictionary attacks.

// start/handle.ts or a dedicated RateLimitProvider
import { middleware } from '@adonisjs/core'
import { createRateLimiter } from '@ioc:Adonis/Addons/RateLimiter'

const apiKeyLimiter = createRateLimiter({
  throttleKey: (ctx) => {
    // Use IP or a partial key for throttling before validation
    return ctx.request.ip()
  },
  attempts: 5,
  window: 60, // 5 minutes
  response: {
    code: 429,
    message: 'Too many attempts, try again later',
  },
})

export const rateLimit = middleware(apiKeyLimiter)

Apply the middleware to your authentication route in routes.ts:

Route.post('auth/verify-key', 'KeyController.verify').middleware([rateLimit])

2. Use constant-time comparison for key validation

Avoid branching on key validity. Use a constant-time comparison utility to prevent timing leaks.

import { constantTimeCompare } from '@ioc:Utils/crypto'

export const verifyKey = async (candidate: string, userId: number) => {
  const storedKey = await ApiKey.query().where({ user_id: userId }).first()
  if (!storedKey) {
    // Still run comparison to keep timing consistent
    constantTimeCompare(candidate, 'dummy_key_with_same_length')
    return null
  }
  const isValid = constantTimeCompare(candidate, storedKey.key)
  return isValid ? storedKey : null
}

3. Generate keys with sufficient entropy and bind scope

Create keys using cryptographically secure randomness and associate them with specific scopes or permissions.

import { randomBytes } from 'node:crypto'

export const generateApiKey = () => {
  return randomBytes(32).toString('hex') // 256-bit entropy
}

// Example schema for ApiKey model
// table.string('key').unique().notNullable()
// table.string('scope').notNullable() // e.g., "read:reports,write:logs"

4. Enforce strict authorization checks in controllers

Ensure that each route validates scope and ownership, avoiding reliance on the key alone.

import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'

export default class ReportsController {
  public async show({ params, auth }: HttpContextContract) {
    const key = await auth.authenticate()
    // Verify scope includes 'read:reports'
    if (!key.scopes.includes('read:reports')) {
      throw new ForbiddenException('Insufficient scope')
    }
    return Report.query().where('user_id', key.userId).exec()
  }
}

5. Centralize error responses

Return uniform messages and status codes to prevent oracle behavior.

Route.post('auth/verify-key', async ({ response }: HttpContextContract) => {
  const { key } = request.body()
  const userKey = await verifyKey(key, request.only(['userId']))
  if (!userKey) {
    return response.status(401).json({ message: 'Invalid credentials' })
  }
  // issue a short-lived token or proceed
})

6. Rotate keys and monitor usage

Implement a rotation policy and log attempts to detect ongoing probing.

// Example schedule task to flag excessive failures
import { ScheduledTask } from '@ioc:Adonis/Addons/Scheduler'
export default class RotateKeysTask {
  public async handle() {
    // revoke keys with repeated failures in the last window
  }
}

Frequently Asked Questions

How does AdonisJS handle API key validation by default, and why is it risky?
AdonisJS does not provide built-in brute-force protection for API key endpoints. If a key lookup returns different HTTP status codes or timing differences based on validity, and if routes lack per-key rate limits, attackers can perform dictionary attacks with high efficiency.
Can middleware alone stop dictionary attacks on API keys in AdonisJS?
Middleware can enforce rate limits and uniform responses, but it must be combined with secure key storage, constant-time comparison, and scope-based authorization. Relying solely on middleware without fixing validation logic may reduce exposure but does not eliminate the underlying risk.