Crlf Injection in Adonisjs
How Crlf Injection Manifests in Adonisjs
Crlf injection in Adonisjs occurs when user-controlled input containing carriage return (\r) or line feed (\n) characters is incorporated into HTTP headers without proper sanitization. This vulnerability allows attackers to inject additional headers or split existing headers, potentially leading to HTTP response splitting, session fixation, or cache poisoning.
In Adonisjs applications, Crlf injection commonly appears in several contexts:
- Response headers set from user input (e.g., custom headers, redirects)
- Cookie manipulation through header injection
- Content-Disposition headers with user-controlled filenames
- Location headers in redirects
- Custom authentication headers
Consider this vulnerable Adonisjs pattern:
class UserController {
async redirectWithParam({ request, response }) {
const redirectUrl = request.input('url');
response.redirect(redirectUrl); // Vulnerable if url contains CRLF
}
async setCustomHeader({ request, response }) {
const headerValue = request.input('header');
response.set(headerValue); // CRLF injection possible
}
async downloadFile({ request, response }) {
const filename = request.input('filename');
response
.attachment(filename, 'application/octet-stream')
.header('Content-Disposition', `attachment; filename="${filename}"`); // CRLF injection vector
}
}The vulnerability becomes exploitable when user input flows directly into header-setting methods without validation. For example, submitting a filename like report.pdf%0d%0aX-Custom-Header: malicious-value could inject arbitrary headers.
Adonisjs's response object methods like set(), header(), attachment(), and redirect() are all potential injection points if they receive unvalidated user input.
Adonisjs-Specific Detection
Detecting Crlf injection in Adonisjs requires examining both the application code and runtime behavior. Here are Adonisjs-specific detection approaches:
Code Analysis
Review your controllers for patterns where user input directly flows to response methods. Look for:
grep -r "response\.(set|header|redirect|attachment)" app/Controllers | grep -E "(request|params|input)"Automated Scanning with middleBrick
middleBrick's API security scanner includes specific Crlf injection detection for Node.js/Express-like frameworks including Adonisjs. The scanner tests for:
- Response splitting attempts via crafted header values
- Cookie manipulation through header injection
- Location header manipulation in redirects
- Content-Disposition header injection
To scan your Adonisjs API:
npx middlebrick scan https://your-api.com/api/usersThe scan tests unauthenticated endpoints by submitting payloads containing CRLF sequences and analyzing responses for header injection indicators. middleBrick provides a security score (0-100) and specific findings with remediation guidance.
Manual Testing
Test your endpoints with encoded CRLF payloads:
curl -X POST https://your-api.com/api/upload \
-H "Content-Type: application/json" \
-d '{"filename": "test.txt%0d%0aSet-Cookie: test=malicious"}'Look for unexpected headers in responses or changes in behavior. The %0d%0a sequence represents CRLF in URL encoding.
Middleware Validation
Adonisjs allows creating validation middleware. Here's a Crlf detection middleware:
const { regex } = use('@ioc:Adonis/Core/Helpers');
export class CrlfProtection {
async handle({ request, response }, next) {
const crlfPattern = /%0D%0A|%0A%0D|\r\n|\n\r|\r|\n/i;
const params = request.all();
const hasCrlf = Object.values(params).some(value => {
if (typeof value === 'string') {
return crlfPattern.test(value);
}
return false;
});
if (hasCrlf) {
return response.badRequest('Invalid characters detected in request');
}
await next();
}
}Register this middleware in start/kernel.ts to protect your routes.
Adonisjs-Specific Remediation
Remediating Crlf injection in Adonisjs requires a defense-in-depth approach combining input validation, output encoding, and secure coding practices.
Input Validation
Validate and sanitize all user inputs that might affect headers:
import { schema } from '@ioc:Adonis/Core/Validator';
export const FileUploadSchema = schema.create({
filename: schema.string.optional({
trim: true,
escape: true,
}, [
rules.blacklist(['%0d', '%0a', '\r', '\n', '\u000d', '\u000a']),
rules.maxLength(255),
]),
});
// In your controller
export default class FileController {
async upload({ request, response }) {
const payload = await request.validate({
schema: FileUploadSchema,
});
// Safe to use payload.filename
response.attachment(payload.filename);
}
}Header Sanitization
Create a utility for safe header setting:
export class SafeHeaders {
static sanitizeHeader(value) {
if (typeof value !== 'string') return value;
return value
.replace(/\r/g, '')
.replace(/\n/g, '')
.replace(/%0D/gi, '')
.replace(/%0A/gi, '')
.trim();
}
static setSafeHeader(response, headerName, value) {
const sanitizedValue = SafeHeaders.sanitizeHeader(value);
response.header(headerName, sanitizedValue);
}
}
// Usage in controller
export default class UserController {
async setCustomHeader({ request, response }) {
const headerValue = request.input('header');
SafeHeaders.setSafeHeader(response, 'X-Custom-Header', headerValue);
}
}Secure Redirects
Validate redirect URLs before using them:
export default class RedirectController {
async safeRedirect({ request, response }) {
const redirectUrl = request.input('url');
// Validate URL - only allow same-origin redirects
const baseUrl = new URL(process.env.APP_URL);
let targetUrl;
try {
targetUrl = new URL(redirectUrl, baseUrl);
if (targetUrl.origin !== baseUrl.origin) {
throw new Error('Invalid redirect URL');
}
} catch (error) {
return response.badRequest('Invalid redirect URL');
}
response.redirect(targetUrl.pathname);
}
}Middleware Protection
Apply Crlf protection globally:
// start/kernel.ts
const globalMiddleware = [
'Adonis/Core/BodyParser',
'App/Middleware/CrlfProtection',
'Adonis/Core/Auth',
// ... other middleware
];
// app/Middleware/CrlfProtection.js
export class CrlfProtection {
async handle({ request, response }, next) {
const crlfPattern = /%0D%0A|%0A%0D|\r\n|\n\r|\r|\n/i;
const dangerous = ['filename', 'url', 'header', 'location'];
for (const [key, value] of Object.entries(request.all())) {
if (dangerous.includes(key) && typeof value === 'string' && crlfPattern.test(value)) {
return response.badRequest('Invalid characters detected');
}
}
await next();
}
}Content Security Policy
Add CSP headers to mitigate impact of any successful injection:
// In your middleware or route handler
response
.header('X-Content-Type-Options', 'nosniff')
.header('X-Frame-Options', 'DENY')
.header('Content-Security-Policy', "default-src 'self'");For comprehensive protection, combine these approaches and regularly scan your Adonisjs API with middleBrick to verify that Crlf injection vulnerabilities are properly mitigated.