Crlf Injection in Adonisjs with Api Keys
Crlf Injection in Adonisjs with Api Keys — how this specific combination creates or exposes the vulnerability
Crlf Injection (also known as HTTP response splitting) occurs when untrusted input containing carriage return (CR, \r) and line feed (\n) characters is reflected into HTTP headers. In AdonisJS, this often arises when building responses dynamically using user-controlled data, such as API key identifiers, request parameters, or custom headers. If an API key value or a key-derived header is concatenated into a header string without validation or sanitization, an attacker can inject additional headers or split the response by supplying a payload like abc123\r\nX-Injected: true.
Consider an AdonisJS route that uses an API key to select a tenant and then sets a custom header reflecting the key:
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
export default class ApiKeysController {
public async headerEcho({ request, response }: HttpContextContract) {
const apiKey = request.input('key')
// Vulnerable: apiKey is reflected directly into a custom header
response.header('X-API-Key', apiKey)
response.send({ ok: true })
}
}
If apiKey contains abc123\r\nX-Content-Type-Options: nosniff, the header line breaks and an additional header is injected, potentially bypassing browser protections. Another scenario involves logging or debugging endpoints that include the API key in a Location header during redirects:
export async function redirectByKey({ request, response }: HttpContextContract) {
const apiKey = request.input('key')
// Vulnerable: using API key in a redirect Location header
response.redirect(`/dashboard?key=${apiKey}`)
}
If the API key includes \r\nSet-Cookie: session=evil, a new cookie can be injected. Even though AdonisJS does not automatically parse or split headers, any developer code that places raw API key material into headers or URLs without sanitization creates a Crlf Injection surface. Because API keys often travel in query parameters, headers, or cookies, they become a common vector when reflected back in responses.
In the context of middleBrick’s 12 security checks, Crlf Injection is surfaced as a high-severity finding when the scanner detects header reflection patterns and unvalidated input sources. The tool cross-references OpenAPI/Swagger specifications to see whether header schemas expect sanitized values and flags discrepancies between spec definitions and runtime behavior. Note that middleBrick detects and reports these issues; remediation requires code changes by the developer.
Api Keys-Specific Remediation in Adonisjs — concrete code fixes
Remediation centers on never reflecting untrusted input into HTTP headers or URLs without strict validation and encoding. For API key handling, treat the key as an opaque identifier and avoid echoing it back in headers or redirects. Instead, use indirect mappings (e.g., lookup a key to a tenant ID) and ensure any output encoding is context-aware.
1. Avoid header reflection of API keys
Do not set headers using raw API key values. If you must associate metadata with a key, store it server-side and reference it indirectly:
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
export default class ApiKeysController {
public async safeEcho({ request, response }: HttpContextContract) {
const apiKey = request.input('key')
// Validate format (e.g., hex, length) without reflecting raw value
if (!/^[a-f0-9]{32}$/i.test(apiKey)) {
return response.badRequest({ error: 'Invalid API key format' })
}
// Lookup tenant or metadata server-side; do not reflect key in headers
const tenant = await Tenant.findByApiKey(apiKey)
if (!tenant) {
return response.unauthorized({ error: 'Invalid API key' })
}
// Safe: set a non-reflective header
response.header('X-Tenant-ID', tenant.id)
response.send({ ok: true })
}
}
2. Sanitize and encode when reflection is unavoidable
If you must include a key-derived value in a header or URL, strip CR/LF characters and apply appropriate encoding. For header values, remove line break characters and use a strict allowlist:
export function sanitizeHeaderValue(value: string): string {
return value.replace(/[\r\n]+/g, '')
}
// Usage
const safeKey = sanitizeHeaderValue(apiKey)
response.header('X-API-Key-Safe', safeKey)
For URLs (e.g., redirects), use proper URL construction methods that encode path segments and query parameters:
import { UrlBuilder } from '@ioc:Adonis/Core/Url'
export async function safeRedirect({ request, response }: HttpContextContract) {
const apiKey = request.input('key')
const safeKey = sanitizeHeaderValue(apiKey)
const url = new UrlBuilder()
.path('/dashboard')
.addQuery('key', safeKey)
.build()
response.redirect(url)
}
3. Validate and constrain API key formats
Enforce a strict pattern (e.g., alphanumeric, fixed length) and reject any input that does not conform. This reduces the attack surface and prevents encoded or obfuscated line breaks:
export function isValidApiKey(key: string): boolean {
// Example: 32-character hex string
return /^[a-f0-9]{32}$/i.test(key)
}
// In route handler
if (!isValidApiKey(apiKey)) {
return response.badRequest({ error: 'Malformed API key' })
}
These steps align with secure coding practices for header handling and help prevent Crlf Injection. middleBrick’s scans can highlight where API keys appear in header contexts, but fixing the root cause requires updating the application logic as shown.