Adonisjs API Security
Adonisjs Security Posture
Adonisjs provides a solid security foundation with built-in CSRF protection, input sanitization, and secure session management. The framework automatically escapes output in templates and includes rate limiting middleware. However, its default configuration assumes a trusted environment and developer responsibility for critical security decisions.
The framework's flexible middleware system and powerful Lucid ORM can introduce vulnerabilities if not properly configured. Adonisjs prioritizes developer experience over security defaults, meaning you get a functional API quickly but must actively harden it for production. The ORM's automatic query building, while convenient, can lead to BOLA (Broken Object Level Authorization) if developers rely on user-provided IDs without proper authorization checks.
Top 5 Security Pitfalls in Adonisjs
1. Missing Authorization Middleware
Adonisjs doesn't enforce authorization by default. Developers often create routes that fetch resources by ID without verifying the requesting user's permissions. This BOLA vulnerability is particularly dangerous because Lucid's simple query syntax makes it easy to write code that looks correct but exposes all records.
// Vulnerable code - no authorization check
async show({ params, auth }) {
const user = await User.find(params.id)
return user
}
// Secure version
async show({ params, auth }) {
const user = await User.find(params.id)
if (user.id !== auth.user.id) {
throw new Error('Unauthorized')
}
return user
}2. Insecure Default CORS Configuration
The default CORS settings in Adonisjs allow all origins, which is acceptable for development but dangerous in production. Many developers forget to update these settings before deployment, exposing APIs to cross-origin attacks.
// Default (insecure)
const cors = {
origin: ['*'],
methods: ['GET', 'HEAD', 'PUT', 'PATCH', 'POST', 'DELETE'],
credentials: true,
}
// Production-ready
const cors = {
origin: ['https://yourdomain.com'],
methods: ['GET', 'POST', 'PUT', 'DELETE'],
credentials: true,
maxAge: 86400,
}3. Unvalidated Route Parameters
Adonisjs route parameters are strings by default. Developers often use them directly in database queries without type validation, leading to type confusion attacks or unintended data exposure.
// Vulnerable - string comparison issues
async show({ params }) {
return await User.find(params.id) // params.id is a string
}
// Secure - explicit type conversion
async show({ params }) {
const userId = parseInt(params.id, 10)
if (isNaN(userId)) throw new Error('Invalid ID')
return await User.find(userId)
}4. Missing Rate Limiting on Authentication Endpoints
While Adonisjs includes rate limiting middleware, developers often forget to apply it to authentication routes. This omission enables brute-force attacks against login endpoints.
// Missing rate limiting (vulnerable)
Route.post('login', 'AuthController.login')
// Secure with rate limiting
Route.post('login', 'AuthController.login').middleware(['throttle:10,5m'])5. Insecure File Upload Handling
Adonisjs's file upload system doesn't validate file types or scan for malware by default. Attackers can upload executable files or scripts that get served from your domain, leading to XSS or remote code execution.
// Vulnerable - accepts any file type
async upload({ request }) {
const file = await request.file('file', {
size: '2mb',
})
await file.move(uploadsPath)
}
// Secure - whitelist file types
async upload({ request }) {
const file = await request.file('file', {
size: '2mb',
types: ['image'],
})
await file.move(uploadsPath)
}Security Hardening Checklist
Authentication & Authorization
★ Implement policy-based authorization using Adonisjs's built-in policies
★ Never trust route parameters - always validate and authorize
★ Use prepared statements or ORM methods that prevent SQL injection
★ Implement proper session management with secure cookies
Input Validation
★ Use Adonisjs's validator with strict schemas for all inputs
Example: const schema = schema.create({ email: schema.string({}, [rules.email()]) })
Validate file uploads with type whitelisting and size limits
Sanitize all user inputs before database operations
API Security Headers
★ Configure Content Security Policy headers
★ Set proper CORS policies for production
Add security headers: X-Frame-Options, X-Content-Type-Options, Referrer-Policy
Use Helmet.js for comprehensive header security
// app/Controllers/Http/RootController.js
class RootController {
async index({ response }) {
response.implicitEnd = false
response.safeHeader('X-Frame-Options', 'DENY')
response.safeHeader('X-Content-Type-Options', 'nosniff')
response.safeHeader('Referrer-Policy', 'strict-origin-when-cross-origin')
response.send('API is running')
}
}Rate Limiting & Monitoring
★ Apply rate limiting to all authentication and sensitive endpoints
Configure different limits for public vs private APIs
Implement request logging for audit trails
Set up alerting for unusual traffic patterns
Production Configuration
★ Never use debug mode in production
Configure proper error handling that doesn't leak stack traces
Use environment variables for secrets (API keys, database credentials)
Enable HTTPS with proper TLS configuration
Automated Security Testing
★ Scan your Adonisjs APIs with middleBrick before production deployment
middleBrick tests for BOLA, authentication bypass, and input validation issues specific to your API structure
Integrate middleBrick CLI into your CI/CD pipeline to catch regressions
Use the GitHub Action to automatically scan pull requests