Crlf Injection in Adonisjs (Typescript)
Crlf Injection in Adonisjs with Typescript
Crlf Injection occurs when an attacker can inject carriage return (CR, \r) and line feed (\n) sequences into an HTTP header or response, causing header injection, response splitting, or cache poisoning. AdonisJS, a Node.js web framework built around HTTP abstractions, can be vulnerable when user-controlled input is reflected into headers or status lines without proper sanitization. In a Typescript-based AdonisJS project, controllers typically handle requests and construct responses using framework helpers like response.header() or by directly setting status codes. If a developer passes unchecked input—such as a query parameter or form field—into these methods, an attacker can supply values like example.com\r\nSet-Cookie: auth=evil, causing the injected header to be appended to the response. Because Typescript compiles to JavaScript and does not inherently validate header values, the vulnerability maps directly to the underlying Node.js HTTP layer. AdonisJS utilities for building redirects or JSON responses often chain methods (e.g., response.redirect()), and if the URL or status is derived from user input, CRLF characters can break header integrity. This can lead to HTTP response splitting (splitting the response into multiple responses) or the injection of arbitrary headers, such as Location or Set-Cookie. The risk is especially pronounced when the framework’s route handlers do not validate or sanitize inputs before they reach header-setting logic. Attack patterns mirror classic CRLF injection techniques, where an attacker manipulates the protocol layer to inject malicious headers or split the response stream. Because AdonisJS often exposes endpoints that return user-influenced data (e.g., redirect URLs or dynamic headers), developers must treat any input flowing into header construction as untrusted. Even when using Typescript’s strong typing, runtime values remain unchecked unless explicitly validated, so the framework does not prevent these injections by default.
Typescript-Specific Remediation in Adonisjs
Remediation in AdonisJS with Typescript centers on strict input validation, output encoding, and avoiding the direct reflection of user input into HTTP headers or status lines. Use framework validation schemas (e.g., schema-based validation with schema from @ioc:AdonisJS/Validator) to enforce allowed formats for inputs that may affect headers or redirects. Never concatenate or interpolate user input into header keys or values; instead, use whitelisting for safe values. For redirects, prefer passing only validated URLs and rely on AdonisJS’s built-in helpers that do not allow header injection. Below are concrete Typescript examples demonstrating secure practices.
Insecure Example
The following code reflects a user-controlled next query parameter into a redirect, enabling CRLF injection:
import { HttpContextContract } from '@ioc:Adonisjs/Core/HttpContext'
export default class AuthController {
public redirectAfterLogin({ request, response }: HttpContextContract) {
const nextUrl = request.input('next', '/dashboard')
// Vulnerable: user input directly used in redirect URL
return response.redirect(nextUrl)
}
}
Secure Remediation
Validate and sanitize the input, ensuring it does not contain CRLF characters and conforms to expected patterns:
import { HttpContextContract } from '@ioc:Adonisjs/Core/HttpContext'
import { schema, rules } from '@ioc:Adonisjs/Core/Validator'
const redirectSchema = schema.create({
next: schema.string.optional({}, [
rules.url({ trim: true }),
rules.maxLength(2048),
// Ensure no CRLF characters are present
rules.regex(/^[^\r\n]*$/)
])
})
export default class AuthController {
public async redirectAfterLogin({ request, response, validator }: HttpContextContract) {
const payload = await validator.validate({ schema: redirectSchema })
const nextUrl = payload.next || '/dashboard'
// Safe: validated URL without CRLF
return response.redirect(nextUrl)
}
}
For header-setting operations, avoid user input entirely or sanitize rigorously:
import { HttpContextContract } from '@ioc:Adonisjs/Core/HttpContext'
export default class HeaderController {
public setCustomHeader({ request, response }: HttpContextContract) {
const userValue = request.input('label', 'default')
// Remove any CR or LF characters
const sanitized = userValue.replace(/[\r\n]/g, '')
response.header('X-Custom-Value', sanitized)
response.send({ status: 'ok' })
}
}
Additionally, use AdonisJS’s built-in helpers for common operations (e.g., response.unauthorized() for redirects to login) to reduce manual header handling. When integrating with external services or APIs, ensure outbound requests do not propagate unsanitized values into headers, as this can affect both client and server sides.