Api Rate Abuse in Adonisjs with Saml
Api Rate Abuse in Adonisjs with Saml — how this specific combination creates or exposes the vulnerability
AdonisJS is a Node.js web framework that often uses an ecosystem of authentication providers. When integrating SAML for identity federation, developers commonly rely on community packages (for example, @adonisjs/saml or similar) to handle the protocol. These packages typically plug into AdonisJS middleware to protect routes and validate assertions, but they do not inherently enforce API rate limits on the endpoints they guard.
Rate abuse becomes a risk when SAML-protected routes are publicly reachable and lack request throttling. An unauthenticated attacker can repeatedly initiate SAML authentication requests or probe the Assertion Consumer Service (ACS) endpoint without meaningful cost or detection. Without explicit rate controls, this can lead to authentication flooding, elevated server load, or potential account enumeration via timing or error responses.
The vulnerability is not in SAML itself but in how the routes consuming SAML assertions are exposed in AdonisJS. Routes using the SAML middleware may bypass generic application-level rate limiters if they are defined outside the limiter scope or if the limiter is configured only for JSON APIs rather than SAML endpoints. Additionally, metadata endpoints (e.g., IdP metadata or Single Logout Service) are often publicly accessible and rarely rate-limited, enabling attackers to harvest configuration details for further abuse.
Consider an AdonisJS route file that protects an ACS endpoint but does not apply rate limiting:
import Route from '@ioc:Adonis/Core/Route'
import Saml from '@ioc:Community/saml'
Route.post(
'/saml/acs',
async ({ request, response }) => {
const samlResponse = request.input('SAMLResponse')
const profile = await Saml.validateResponse(samlResponse)
// handle login
return response.redirect('/dashboard')
}
).as('saml.acs')
An attacker can send many POST requests with malformed or missing SAMLResponse values, triggering repeated parsing and validation attempts. If error handling produces distinguishable timing differences or verbose logs, this may facilitate account enumeration or denial-of-service conditions.
Furthermore, the combination of SAML and AdonisJS can expose metadata endpoints that describe endpoints, certificates, and protocol bindings. If these are served without rate limits, an attacker can use them to map the integration and refine injection or replay attempts.
To mitigate, apply rate limiting specifically to SAML routes and metadata endpoints, ensure consistent error handling that does not leak information, and validate that middleware ordering does not bypass global protections. Continuous scanning with a tool like middleBrick can detect missing rate controls on SAML endpoints and map findings to frameworks such as OWASP API Security Top 10 and PCI-DSS requirements.
Saml-Specific Remediation in Adonisjs — concrete code fixes
Remediation focuses on three areas: route-level throttling, metadata protection, and consistent error handling. Below are concrete AdonisJS examples that integrate rate limiting with SAML routes.
1. Apply rate limiting to the ACS endpoint
Use AdonisJS middleware to enforce a threshold on requests per IP for the ACS route. This reduces the risk of flooding while preserving legitimate login flows.
import Route from '@ioc:Adonis/Core/Route'
import Saml from '@ioc:Community/saml'
import RateLimiter from '@ioc:Adonis/Addons/RateLimiter'
Route.post(
'/saml/acs',
async ({ request, response }) => {
const samlResponse = request.input('SAMLResponse')
if (!samlResponse) {
return response.badRequest({ error: 'Missing SAMLResponse' })
}
const profile = await Saml.validateResponse(samlResponse)
return response.redirect('/dashboard')
}
)
.as('saml.acs')
.middleware('rateLimit')
// In start/rateLimiter.ts
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
import RateLimiter from '@ioc:Adonis/Addons/RateLimiter'
export const handle = RateLimiter.make({
throttleKey: (ctx: HttpContextContract) => {
return ctx.request.ip()
},
permits: 10,
duration: 60, // 10 requests per 60 seconds per IP
})
2. Protect metadata and discovery endpoints
Metadata endpoints should also be rate-limited and served over HTTPS. Consider restricting access by validating referrer or using short-lived cache headers.
import Route from '@ioc:Adonis/Core/RateLimiter'
import Route from '@ioc:Adonis/Core/Route'
Route.get('/saml/metadata', async ({ response }) => {
const metadata = `
MIIC...
`
response.header('Cache-Control', 'max-age=3600')
response.send(metadata)
}).as('saml.metadata').middleware('rateLimit')
3. Standardize error handling to avoid timing leaks
Ensure that validation and parsing errors follow a consistent path and do not introduce variable delays that could aid timing-based attacks.
import Route from '@ioc:Adonis/Core/Route'
import Saml from '@ioc:Community/saml'
Route.post(
'/saml/acs',
async ({ request, response }) => {
try {
const samlResponse = request.input('SAMLResponse')
if (!samlResponse) throw new Error('missing_response')
const profile = await Saml.validateResponse(samlResponse)
return response.redirect('/dashboard')
} catch ( error ) {
// Avoid branching on error type in a way that changes timing significantly
return response.unauthorized({ error: 'invalid_saml' })
}
}
).as('saml.acs').middleware('rateLimit')
These examples demonstrate how to integrate SAML flows with explicit rate controls in AdonisJS. For broader coverage, middleBrick can scan your SAML-protected endpoints and surface missing rate limits as part of its security checks, aligning findings with standards such as OWASP API Top 10 and PCI-DSS.