Api Rate Abuse in Adonisjs with Mutual Tls
Api Rate Abuse in Adonisjs with Mutual Tls — how this specific combination creates or exposes the vulnerability
Rate abuse in AdonisJS when mutual TLS (mTLS) is in use involves two intersecting dimensions: application-level rate controls and transport-layer identity verification. AdonisJS does not enforce mTLS itself; the web server or reverse proxy (for example, Caddy or Nginx) terminates TLS and presents a client certificate to AdonisJS only after validating it. If rate limits are enforced only inside AdonisJS, an attacker can bypass them by cycling through many valid client certificates, each of which is accepted by the mTLS handshake, while the application still sees distinct authenticated identities.
Consider a scenario where an endpoint that returns sensitive profile data has a route-based rate limit using AdonisJS RateLimiter. If the mTLS configuration does not enforce strong client identity binding to a stable attribute (for example, a serial number or subject common name), an attacker can obtain or generate many valid certificates and rotate them across requests. Each request presents a different client certificate, so the in-application rate limiter may treat them as separate, legitimate users. This is a BFLA/Privilege Escalation concern combined with insufficient transport binding: the server authenticates the client, but the application does not correlate identity with a consistent, server-side notion of rate.
Moreover, mutual TLS can create a false sense of security. Because TLS-level authentication happens before the application processes requests, logging and monitoring may attribute traffic to the certificate subject rather than to a stable user or API key. Without additional correlation (for example, mapping certificate attributes to an account ID and enforcing per-identity rate limits at a layer outside AdonisJS), attackers can exploit this gap. They may also target unauthenticated LLM endpoints if your AdonisJS application exposes AI features; mTLS alone does not prevent prompt injection or cost exploitation in those endpoints.
Real-world attack patterns include rapid creation of short-lived certificates via an automated enrollment process or compromised intermediate CAs, and the use of these certificates to perform reconnaissance or data scraping while avoiding IP-based rate limits. This maps to OWASP API Top 10 controls around authentication and rate limiting, and can conflict with expectations in frameworks that assume application-level enforcement is sufficient. Even with mTLS, you must enforce identity-aware rate limiting at the edge or via an API gateway that can extract and normalize the client certificate attributes before requests reach AdonisJS.
middleBrick can detect this class of risk by correlating unauthenticated scan findings with OpenAPI specifications that describe mTLS expectations and rate-limit definitions. It runs checks across Authentication, Rate Limiting, and LLM/AI Security to highlight gaps where transport-layer identity is not consistently mapped to application-level controls, providing prioritized findings with remediation guidance.
Mutual Tls-Specific Remediation in Adonisjs — concrete code fixes
To remediate rate abuse in AdonisJS with mTLS, bind client identity to rate-limiting logic and enforce identity consistency at the edge. Do not rely solely on in-application rate limiters that use request attributes which can be trivially rotated (such as IP or self-reported user IDs).
First, configure your TLS termination layer (for example, Caddy or Nginx) to require and validate client certificates. Then extract stable certificate attributes and forward them as headers so AdonisJS can use them for rate limiting. Below is an example Caddyfile that enforces mTLS and sets a custom header with the certificate common name:
tls internal
routes {
header_up X-Client-Cert-CN {ssl.cert.organizational_unit}
header_up X-Client-Cert-Serial {ssl.cert.serial}
reverse_proxy localhost:3333
}
In AdonisJS, create a rate limiter that uses the forwarded certificate serial or CN to enforce per-identity limits. This ensures that rotating certificates does not circumvent limits:
// start/hooks.ts
import { defineConfig } from '@adonisjs/core/app'
import RateLimiter from '@adonisjs/limiter'
export default defineConfig({
limiter: {
rateLimit: RateLimiter.make([
{
name: 'profile-endpoint',
identifier: (ctx) => {
// Use the certificate serial or CN forwarded by the edge
return ctx.request.header().get('x-client-cert-cn') || ctx.request.header().get('x-client-cert-serial')
},
limit: 60,
duration: 60
}
])
}
})
// controllers/ProfileController.ts
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
import { rateLimit } from '@adonisjs/limiter/helpers'
export default class ProfilesController {
@rateLimit({ name: 'profile-endpoint' })
public async show({ request }: HttpContextContract) {
const subject = request.header('x-client-cert-cn')
return { profile: `Data for ${subject}`, issuedAt: new Date().toISOString() }
}
}
For stronger binding, normalize certificate attributes at the edge and store a mapping (for example, certificate serial to user ID) in a fast store such as Redis. Then enforce rate limits using that stable mapping rather than the raw certificate fields, which prevents attackers from cycling through many certificates mapped to the same logical identity.
Additionally, audit and monitor unauthenticated LLM endpoints separately. Even with mTLS on main routes, ensure that any AI-related routes have their own authentication and rate controls, and that output scanning is in place to detect PII or API keys in LLM responses. middleBrick’s LLM/AI Security checks can help surface missing protections in these endpoints.
Finally, validate your configuration using scans that include both Authentication and Rate Limiting checks. middleBrick’s GitHub Action can integrate these validations into CI/CD, failing builds if risk scores drop below your configured threshold, while the MCP Server allows you to scan APIs directly from your IDE during development.