Regex Dos in Adonisjs
How Regex Dos Manifests in Adonisjs
Regex Denial of Service (ReDoS) in Adonisjs typically occurs when user-controlled input is passed to regular expressions that contain vulnerable patterns. The framework's middleware and validation layers can become attack vectors if not properly configured.
Consider this common Adonisjs controller pattern:
const { validate } = use('Validator')
class UserController {
async store({ request, response }) {
const data = request.post()
const rules = {
email: 'required|email',
username: 'required|regex:/^[a-zA-Z0-9_]+$/',
bio: 'regex:/^[\w\s.,!?]+$/'
}
const validation = await validate(data, rules)
if (validation.fails()) {
return response.badRequest(validation.messages())
}
// Process user data
}
}The vulnerability emerges when regex patterns contain nested quantifiers or ambiguous constructs. For example, a pattern like a(b|c+)+d can cause exponential backtracking when processing malicious input.
Adonisjs-specific attack vectors include:
- Route parameter validation using regex patterns in
start/routes.js - Middleware that validates request headers or query parameters
- Model query filters that use regex-like syntax
- Email validation patterns in forms
A practical attack scenario:
// Malicious input targeting vulnerable pattern
const payload = 'a' + 'b'.repeat(1000) + 'c' + 'd'.repeat(1000);
// If controller uses: /^[a-z]+(b|c+)+[d-z]+$/i
// This causes catastrophic backtrackingThe framework's default validation often uses regex patterns that, while convenient, can be problematic. The email rule, for instance, uses a complex regex that could theoretically be exploited, though practical exploitation is rare.
Adonisjs-Specific Detection
Detecting ReDoS in Adonisjs applications requires examining both the codebase and runtime behavior. middleBrick's API security scanner can identify vulnerable patterns through static analysis of your application's routes and validation rules.
Code-based detection patterns:
// Look for these patterns in your Adonisjs codebase
const vulnerablePatterns = [
/(a+)+b/, // Nested quantifiers
/(a|aa)+b/, // Alternating patterns
/(a*)*/ // Redundant quantifiers
]
// Scan your validation rules
const validationFiles = glob.sync('app/Validators/**/*.js')
validationFiles.forEach(file => {
const content = fs.readFileSync(file, 'utf8')
// Parse and analyze regex patterns
})Runtime detection using middleware:
class SecurityMiddleware {
async handle({ request, response }, next) {
const startTime = process.hrtime.bigint()
await next()
const duration = process.hrtime.bigint() - startTime
// Flag requests taking suspiciously long
if (duration > 100000000n) { // 100ms threshold
console.warn('Potential ReDoS detected:', {
url: request.url(),
duration: Number(duration) / 1000000,
userAgent: request.header('user-agent')
})
}
}
}middleBrick specifically scans for:
- Regex patterns in route definitions
- Validation rules with potentially vulnerable quantifiers
- Middleware that processes user input through regex
- Model query filters using regex-like syntax
The scanner analyzes your Adonisjs application's attack surface without requiring credentials or code access, making it ideal for testing deployed APIs.
Adonisjs-Specific Remediation
Fixing ReDoS in Adonisjs involves both immediate code changes and architectural improvements. Here's how to secure your application:
1. Use possessive quantifiers where supported:
// Instead of: /^[a-z]+(b|c+)+[d-z]+$/i
// Use atomic grouping (if supported) or limit input length
const safePattern = new RegExp('^[a-z]{1,50}(b|c+){1,10}[d-z]{1,50}$', 'i')
// In validation rules
const rules = {
username: `required|regex:${safePattern.source}`
}2. Implement input length limits:
class UserController {
async store({ request, response }) {
const data = request.post()
// Enforce maximum lengths before regex processing
if (data.username.length > 50) {
return response.badRequest({
error: 'Username exceeds maximum length'
})
}
const rules = {
email: 'required|email|max:100',
username: 'required|regex:/^[a-zA-Z0-9_]+$/',
bio: 'regex:/^[\w\s.,!?]{1,500}$/'
}
// ... rest of validation
}
}3. Use safe validation libraries:
const { validate } = use('Validator')
// Create a safe validator instance
const safeValidator = validate.extend('safeRegex', (value, [pattern]) => {
// Simple length check as first defense
if (value.length > 200) return false
try {
const regex = new RegExp(pattern)
return regex.test(value)
} catch (error) {
return false
}
})
// Use in your controller
const rules = {
customField: 'required|safeRegex:/^[a-z0-9_-]+$/'
}4. Implement timeout protection:
class RegexTimeoutMiddleware {
async handle({ request, response }, next) {
const timeout = setTimeout(() => {
return response.status(413).json({
error: 'Request processing timeout'
})
}, 100) // 100ms timeout
await next()
clearTimeout(timeout)
}
}5. Use middleBrick's continuous monitoring to ensure fixes remain effective:
// In your GitHub Actions workflow
- name: Run middleBrick security scan
uses: middlebrick/middlebrick-action@v1
with:
api_url: ${{ secrets.TEST_API_URL }}
fail_below_score: B
token: ${{ secrets.MIDDLEBRICK_TOKEN }}
continue-on-error: trueRemember that ReDoS prevention is about defense in depth: combine input validation, length limits, timeout protection, and regular security scanning to maintain a robust security posture.
Related CWEs: inputValidation
| CWE ID | Name | Severity |
|---|---|---|
| CWE-20 | Improper Input Validation | HIGH |
| CWE-22 | Path Traversal | HIGH |
| CWE-74 | Injection | CRITICAL |
| CWE-77 | Command Injection | CRITICAL |
| CWE-78 | OS Command Injection | CRITICAL |
| CWE-79 | Cross-site Scripting (XSS) | HIGH |
| CWE-89 | SQL Injection | CRITICAL |
| CWE-90 | LDAP Injection | HIGH |
| CWE-91 | XML Injection | HIGH |
| CWE-94 | Code Injection | CRITICAL |