HIGH crlf injectionadonisjsbasic auth

Crlf Injection in Adonisjs with Basic Auth

Crlf Injection in Adonisjs with Basic Auth — how this specific combination creates or exposes the vulnerability

Crlf Injection occurs when an attacker can inject carriage return (CR, \r) and line feed (\n) characters into a header or status line, causing the server to prematurely terminate the current header and inject additional headers or split responses. In AdonisJS, this risk is heightened when Basic Authentication is used because the Authorization header value is often parsed and reflected into server-generated responses or logs without sufficient sanitization.

When a client sends a request like Authorization: Basic dXNlcjpwYXNz, AdonisJS decodes the Base64 payload to obtain user:pass. If the application uses this decoded value directly in a response header, status text, or log entry—such as constructing a WWW-Authenticate challenge or echoing credentials for debugging—an attacker can supply a password containing \r\n sequences. For example, a crafted password like pass\r\nX-Injected: malicious can cause the server to emit a second header, potentially enabling HTTP response splitting, cache poisoning, or cross-site scripting when the response is later rendered in a browser.

The vulnerability is not inherent to Basic Auth itself, but to the way user-controlled data (the decoded password) is handled. If downstream code uses the credential string to build headers, set res.header(), or write to logs without validation, the injected CRLF can alter the structure of the HTTP message. This can lead to response splitting, where an attacker causes the server to send additional content, or header injection, which may expose sensitive information or bypass intended security controls. AdonisJS does not automatically sanitize decoded Basic Auth credentials, so developers must treat these values as untrusted input.

Basic Auth-Specific Remediation in Adonisjs — concrete code fixes

To mitigate Crlf Injection when using Basic Authentication in AdonisJS, ensure that any user-controlled data—especially decoded credentials—is sanitized before being used in headers, status lines, or logs. Below are concrete, safe patterns for handling Basic Auth in AdonisJS.

1. Safe Basic Auth parsing and header construction

When validating credentials, decode the Authorization header and immediately sanitize any values that could be reflected into headers or responses. Use Node.js built-in methods to remove or encode CRLF characters.

import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'

export default class AuthController {
  public async login({ request, response }: HttpContextContract) {
    const authHeader = request.headers().authorization
    if (!authHeader || !authHeader.startsWith('Basic ')) {
      return response.unauthorized()
    }

    const base64 = authHeader.split(' ')[1]
    const decoded = Buffer.from(base64, 'base64').toString('utf-8')
    const [username, password] = decoded.split(':')

    // Critical: strip CRLF to prevent injection
    const safeUsername = username.replace(/[\r\n]/g, '')
    const safePassword = password.replace(/[\r\n]/g, '')

    // Perform your authentication logic with safeUsername/safePassword
    const user = await User.findBy('email', safeUsername)
    if (!user || user.password !== hash(safePassword)) {
      return response.unauthorized()
    }

    // Construct WWW-Authenticate safely (do not echo user input)
    response.header('WWW-Authenticate', 'Basic realm="Application", charset="UTF-8"')
    return response.ok({ token: 'secure-jwt-token' })
  }
}

2. Avoid echoing credentials in responses or logs

Never include raw or partially sanitized credentials in JSON responses or log entries. If logging is required for auditing, redact or hash sensitive values.

import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
import Logger from '@ioc:Adonis/Core/Logger'

export default class SessionController {
  public async store({ request }: HttpContextContract) {
    const authHeader = request.headers().authorization
    const base64 = authHeader.split(' ')[1]
    const decoded = Buffer.from(base64, 'base64').toString('utf-8')
    const [username] = decoded.split(':')

    // Safe logging: avoid raw credentials
    Logger.info('Authentication attempt', { username: username.replace(/[\r\n]/g, '') })

    // Continue with authentication flow...
  }
}

3. Validate and normalize input early

Use AdonisJS schema validation to enforce constraints on usernames and passwords, rejecting values that contain control characters.

import { schema } from '@ioc:Adonis/Core/Validator'

const authSchema = schema.create({
  username: schema.string({}, [ rules.regex({ pattern: /^[^\r\n]+$/ }) ]),
  password: schema.string({}, [ rules.regex({ pattern: /^[^\r\n]+$/ }) ])
})

export const validateAuth = async (ctx: HttpContextContract) => {
  const payload = await ctx.validate({ schema: authSchema })
  // payload.username and payload.password are guaranteed to be free of CRLF
}

Frequently Asked Questions

Can Crlf Injection be exploited through the Basic Auth password even if the application does not explicitly echo the password in headers?
Yes. If the application uses the decoded password in any header construction, logging, or error messages—such as building a WWW-Authenticate challenge or writing to audit logs—injected CRLF can split responses or inject headers. Always sanitize before using user-controlled strings in any header or log output.
Does AdonisJS provide built-in sanitization for Basic Auth credentials to prevent CRLF Injection?
No. AdonisJS does not automatically strip or encode CRLF characters from decoded Basic Auth credentials. Developers must explicitly validate and sanitize these values before using them in headers, status lines, or logs.