Distributed Denial Of Service in Adonisjs with Basic Auth
Distributed Denial Of Service in Adonisjs with Basic Auth — how this specific combination creates or exposes the vulnerability
A DDoS vector in AdonisJS when Basic Auth is used arises from the interaction between authentication handling and resource consumption. When Basic Auth is enabled, every HTTP request carries an Authorization: Basic <base64> header. AdonisJS parses this on each request before routing or controller execution. If an endpoint performs expensive operations — such as querying the database, hashing passwords with a high work factor, or validating complex payloads — an attacker can open many concurrent connections with valid or invalid credentials. The server spends CPU and memory cycles on authentication and business logic for each connection, and under sustained load this can exhaust thread pools, event-loop lag, or database connection limits, leading to service unavailability.
Because the scan categories include Authentication and BOLA/IDOR, middleBrick tests unauthenticated attack surfaces and flags endpoints where authentication checks do not limit resource usage. Basic Auth does not inherently rate-limit or throttle; without additional controls, an open endpoint can be hammered. The scanner also checks Rate Limiting and Input Validation to surface cases where malformed credentials or large request bodies trigger expensive parsing or rejection paths that consume disproportionate resources.
Real-world patterns observed in practice include repeated POSTs to login routes with costly bcrypt rounds, or endpoints that load associations for every authenticated request without caching. These amplify CPU and memory use. Because OpenAPI/Swagger spec analysis (with full $ref resolution) is run in parallel with runtime checks, middleBrick can correlate spec-defined auth requirements with observed behavior to highlight routes where authentication is present but rate limits or input constraints are missing, which is a factor in DDoS risk.
Basic Auth-Specific Remediation in Adonisjs — concrete code fixes
Remediation focuses on reducing per-request cost and enforcing usage limits while preserving Basic Auth for selected routes. Use environment-controlled work factors for password hashing, add concurrency caps, and enforce rate limits on authentication endpoints.
1) Use environment-controlled hashing and avoid expensive work on every request
Configure the password provider to use a tunable number of rounds, and avoid re-hashing on each request. For login, validate credentials efficiently:
import { Hash } from '@ioc:Adonis/Core/Hash';
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext';
export default class AuthController {
public async login({ request, auth, response }: HttpContextContract) {
const { username, password } = request.only(['username', 'password']);
const user = await User.findBy('username', username);
if (!user) {
// Return a constant-time dummy check to mitigate timing attacks
await Hash.make('dummy');
return response.unauthorized({ message: 'Invalid credentials' });
}
const passwordMatch = await Hash.verify(user.password, password);
if (!passwordMatch) {
return response.unauthorized({ message: 'Invalid credentials' });
}
// issue session or token
return response.ok({ token: 'xxx' });
}
}This example avoids expensive operations on the request path unless the username exists, and uses a dummy hash to keep timing behavior consistent.
2) Apply rate limiting to authentication routes
Use AdonisJS middleware to throttle login and token endpoints. A simple in-memory or Redis-based limiter prevents connection floods:
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext';
import { middleware } from '@ioc:Adonis/Core/Route';
// Example route definition with rate limiting
Route.post('/login', 'AuthController.login')
.middleware('throttle:login,3,1m'); // 3 attempts per minute per IP
// Custom throttle middleware (simplified)
import { Exception } from '@poppinss/utils';
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext';
export const throttle = (limit: number, window: string) => {
return async (ctx: HttpContextContract, next: () => Promise) => {
const key = `throttle:${ctx.request.ip}:${ctx.request.url()}`;
// pseudo-code: increment key with expiry, reject if over limit
const current = await RateLimit.get(key);
if (current >= limit) {
throw new Exception('Too Many Requests', 429, 'E_RATE_LIMIT');
}
await RateLimit.incr(key);
await next();
};
};
Adjust the window and limit based on your expected traffic and acceptable risk. For Basic Auth, also consider limiting concurrent connections per IP at the infrastructure level (e.g., load balancer or Node.js cluster settings).
3) Validate and sanitize inputs early to avoid expensive parsing
Ensure that request bodies and query parameters are validated before they trigger heavy operations. Use Joi or Yup schemas to reject malformed payloads quickly:
import { schema } from '@ioc:Adonis/Core/Validator';
const loginSchema = schema.create({
username: schema.string.optional({}, [ rules.alpha() ]),
password: schema.string({}, [ rules.minLength(8) ]),
});
export default class AuthController {
public async login({ request, response }: HttpContextContract) {
try {
const payload = request.validate({ schema: loginSchema });
// proceed with authentication
} catch (error) {
return response.badRequest({ message: 'Invalid input' });
}
}
}
By rejecting invalid inputs early, you reduce CPU cycles spent on parsing and hashing malformed data. Combine these measures with continuous monitoring (Pro plan) to detect abnormal authentication patterns that may indicate an ongoing DDoS attempt.