MEDIUM adonisjsapi key enumeration

Api Key Enumeration in Adonisjs

How Api Key Enumeration Manifests in Adonisjs

In Adonisjs applications, API key enumeration often occurs through misconfigured authentication endpoints or middleware that inadvertently reveals whether a provided API key exists. A common pattern involves routes using Adonisjs' built-in auth middleware with API guard strategies, where error responses differ based on key validity. For example, a login endpoint might return 401 Unauthorized for invalid keys but 403 Forbidden or a validation error for valid keys lacking permissions, enabling attackers to distinguish valid keys via response analysis.

Consider an Adonisjs controller method handling API key validation:

// app/Controllers/Http/AuthController.js
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'

export default class AuthController {
  async validateKey({ request, response }: HttpContextContract) {
    const apiKey = request.input('api_key')
    const user = await Database.from('api_keys').where('key', apiKey).first()

    if (!user) {
      return response.unauthorized({ error: 'Invalid API key' }) // Distinct response
    }

    // Key exists but check permissions
    if (!user.hasPermission('access_resource')) {
      return response.forbidden({ error: 'Insufficient permissions' }) // Different status/code
    }

    return response.ok({ message: 'Access granted' })
  }
}

Here, 401 vs 403 responses allow enumeration. Attackers automate requests with guessed or leaked keys (e.g., from GitHub repos) and observe status codes to build a list of valid keys. This is particularly risky in Adonisjs due to its convention-over-configuration approach—developers may overlook subtle response differences when using Response methods like unauthorized() or forbidden() without standardizing error formats.

Another vector appears in Adonisjs' BasicAuth or custom API guard implementations where ExceptionHandler sends detailed errors in development, leaking validation logic. Real-world parallels include CVE-2021-32626 in Laravel Sanctum (similar token guard), where timing differences enabled enumeration—Adonisjs apps are susceptible to analogous logic flaws if not audited.

Adonisjs-Specific Detection

Detecting API key enumeration in Adonisjs requires analyzing both code patterns and runtime behavior. Static analysis can spot inconsistent error responses in controllers or middleware, but dynamic testing is essential to confirm exploitability. middleBrick identifies this issue during its unauthenticated black-box scan by probing API endpoints with varied API key values and analyzing response differences.

When scanning an Adonisjs API, middleBrick’s Input Validation and Authentication checks (two of its 12 parallel tests) send sequences like:

  • Valid API key (if discoverable via passive recon)
  • Random invalid key
  • Key with correct format but invalid signature
  • Empty or malformed key

It then compares status codes, response times, and body content. For Adonisjs specifically, it flags endpoints where:

  • 401 vs 403 responses occur for invalid vs valid-but-restricted keys
  • Error messages differ (e.g., "Key not found" vs "Invalid key format")
  • Response headers vary (e.g., presence of WWW-Authenticate only on certain failures)

For instance, if scanning https://api.example.com/v1/data with header Authorization: ApiKey test yields 401 { "error": "Invalid API key" } while Authorization: ApiKey valid_key_here returns 403 { "error": "Access denied" }, middleBrick reports an API key enumeration risk under the Authentication category.

Developers can also detect this locally by reviewing Adonisjs middleware. Check start/kernel.ts for custom API guards and ensure ExceptionHandler (in start/exception.ts) normalizes errors. middleBrick’s CLI (middlebrick scan https://api.example.com) or GitHub Action automates this in CI/CD, providing JSON output with severity and remediation guidance tailored to the finding.

Adonisjs-Specific Remediation

Fixing API key enumeration in Adonisjs requires standardizing error responses and avoiding user-input discrimination in authentication flows. Leverage Adonisjs’ built-in features to ensure consistent behavior regardless of key validity.

First, centralize API key validation using a custom middleware that returns uniform errors. Instead of scattering checks across controllers, create a dedicated guard:

// app/Middleware/ApiKeyValidator.ts
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
import { Exception } from '@poppinss/utils'

 export default class ApiKeyValidator {
   async handle({ request, response }: HttpContextContract, next: () => Promise) {
     const apiKey = request.header('authorization')?.replace('ApiKey ', '')

     if (!apiKey) {
       return response.unauthorized({ error: 'Authentication required' })
     }

     const keyRecord = await Database.from('api_keys').where('key', apiKey).first()

     // Always perform same operations to avoid timing leaks
     const isValid = !!keyRecord
     const hasPermission = keyRecord ? keyRecord.hasPermission('access_resource') : false

     // Simulate delay to prevent timing attacks (optional but recommended)
     await new Promise(resolve => setTimeout(resolve, 10))

     if (!isValid || !hasPermission) {
       return response.unauthorized({ error: 'Invalid credentials' }) // Same message/status
     }

     request.apiKey = keyRecord
     await next()
   }
 }

Register this middleware in start/kernel.ts for API routes:

// start/kernel.ts
Server.middleware.register([
  // ...
  {
    name: 'ApiKeyValidator',
    middleware: 'App/Middleware/ApiKeyValidator'
  }
])

This ensures 401 Unauthorized with identical messaging for missing, invalid, or permission-deficient keys. Additionally, normalize error handling in start/exception.ts:

// start/exception.ts
import Exception from '@ioc:Adonis/Core/Exception'

Exception.handle(async (error, { response }) => {
  if (error.code === 'E_INVALID_API_KEY') {
    return response.unauthorized({ error: 'Authentication failed' })
  }
  // ...
})

Finally, use environment variables for key storage (via dotenv) and rotate keys regularly. Validate fixes by rescanning with middleBrick—its dashboard will show improved Authentication scores and eliminated enumeration findings under the Input Validation category.

Frequently Asked Questions

How does middleBrick differentiate API key enumeration from brute force attacks in Adonisjs apps?
middleBrick identifies enumeration by analyzing response differences for valid vs invalid keys (e.g., 401 vs 403), while brute force detection focuses on rapid-fire attempts against the same endpoint. For Adonisjs, it checks if error messages or status codes leak key validity during low-volume probes, which indicates enumeration risk even without high request rates.
Can Adonisjs' built-in Auth middleware prevent API key enumeration, or do I need custom solutions?
Adonisjs' default Auth middleware (e.g., API guard) may still leak information if not configured uniformly—such as using different error responses for 'user not found' vs 'invalid password'. To prevent enumeration, you must customize the guard or middleware to return identical errors for all failure cases, as shown in the remediation section, since the built-in tools alone don’t guarantee response consistency.