HIGH crlf injectionexpressbasic auth

Crlf Injection in Express with Basic Auth

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

Crlf Injection occurs when an attacker can inject CRLF sequences (\r\n) into a header or status-line value, causing the header to be split and additional headers or a second response line to be injected. In Express, this typically arises when user-controlled input is reflected in HTTP headers without validation or sanitization. When Basic Authentication is used, the Authorization header is often parsed on the server to extract a username and password. If the application takes values derived from that parsing—such as a username, a display name, or a token—and writes them into other response headers, the attacker can supply CRLF sequences to smuggle new headers or even a crafted status line.

Consider an Express route that builds a custom header from the decoded Basic Auth username:

const express = require('express');
const app = express();
const authHeader = req.headers.authorization; // Basic base64(username:password)
if (authHeader && authHeader.startsWith('Basic ')) {
  const decoded = Buffer.from(authHeader.split(' ')[1], 'base64').toString('utf8');
  const [username] = decoded.split(':');
  // Vulnerable: username reflected into a custom header
  res.set('X-User-Name', username);
  res.send('OK');
}

If the username contains \r\n, the header injection can bypass intended header structure. For example, a username like alice\r\nX-Content-Type-Options: nosniff would cause the server to emit two headers: X-User-Name: alice and X-Content-Type-Options: nosniff. This can lead to response splitting, cache poisoning, or the injection of security-relevant headers that override safe defaults. In some configurations, a reflected status-line injection (e.g., injecting a crafted status reason) may also be possible when the status text is derived from user input and not properly sanitized.

Note that the presence of Basic Auth does not cause the vulnerability by itself; it is the combination of parsing credentials and then reflecting potentially untrusted data into other HTTP surfaces that creates the risk. Attackers may probe endpoints that use Basic Auth with crafted usernames or passwords containing CRLF sequences to confirm whether headers are split. Because this is a black-box scan, middleBrick tests such header manipulations among its 12 parallel security checks and reports findings related to Data Exposure and Input Validation, along with prioritized remediation guidance.

Basic Auth-Specific Remediation in Express — concrete code fixes

Remediation focuses on never reflecting untrusted input into HTTP headers and strictly validating or encoding any data that must be included in headers. For Basic Auth–protected endpoints, treat the decoded username and password as untrusted for any secondary use. Below are concrete, safe patterns.

1. Do not reflect Basic Auth fields into headers

The simplest and safest approach is to avoid using raw parsed credentials in headers. If you need to pass identity into downstream processing, use an internal identifier that is not derived from user-controlled input or ensure it is canonicalized and safe.

const express = require('express');
const app = express();
app.use((req, res, next) => {
  const authHeader = req.headers.authorization;
  if (authHeader && authHeader.startsWith('Basic ')) {
    const decoded = Buffer.from(authHeader.split(' ')[1], 'base64').toString('utf8');
    const [username] = decoded.split(':');
    // Keep username only for authentication decisions, not for header reflection
    req.authUser = username; // internal use only
  }
  next();
});

app.get('/profile', (req, res) => {
  // Safe: no user-controlled header reflection
  res.json({ message: 'Authenticated', user: req.authUser });
});

2. Sanitize and encode if you must include user input in headers

If you must include a value that originates from the client in a header, strip or encode CRLF characters and validate format strictly. For header names, only use known, static names. For header values, remove \r and \n and avoid allowing newline-like characters such as %0a and %0d in URL decoding scenarios.

function safeHeaderValue(value) {
  return value.replace(/[\r\n]+/g, '');
}

app.get('/set-header', (req, res) => {
  const authHeader = req.headers.authorization;
  if (authHeader && authHeader.startsWith('Basic ')) {
    const decoded = Buffer.from(authHeader.split(' ')[1], 'base64').toString('utf8');
    const [username] = decoded.split(':');
    const cleanName = safeHeaderValue(username);
    // Only set a known, safe header with a cleaned value
    res.set('X-Clean-User', cleanName);
  }
  res.send('OK');
});

3. Validate Basic Auth credentials with a strict format

Enforce that usernames and passwords conform to an expected character set (e.g., alphanumeric with a limited set of symbols) and reject any containing control characters or whitespace that could facilitate injection. This reduces the attack surface even if the values are not reflected.

const USERNAME_REGEX = /^[a-zA-Z0-9._-]{1,64}$/;
function validateBasicAuth(authHeader) {
  if (!authHeader || !authHeader.startsWith('Basic ')) return false;
  const decoded = Buffer.from(authHeader.split(' ')[1], 'base64').toString('utf8');
  const [username, password] = decoded.split(':');
  return USERNAME_REGEX.test(username) && password && password.length > 0;
}

app.use((req, res, next) => {
  if (!validateBasicAuth(req.headers.authorization)) {
    return res.status(400).send('Invalid authentication');
  }
  next();
});

These practices align with secure handling of headers and reduce risks related to Data Exposure and Input Validation. middleBrick scans can identify endpoints where user-controlled data may reach headers and will surface findings tied to Crlf Injection with remediation guidance. For ongoing protection, consider the Pro plan which enables continuous monitoring and configurable scanning schedules so that new endpoints are automatically assessed.

Frequently Asked Questions

Can an attacker exploit CRLF Injection without controlling the Authorization header in Basic Auth flows?
Yes. While the Authorization header itself is typically not reflected, attackers can supply CRLF sequences in other user-controlled inputs (e.g., username if derived from query parameters, cookies, or form data) that are later written into response headers. The vulnerability depends on how the application uses parsed values, not solely on the presence of Basic Auth.
Does middleBrick fix Crlf Injection findings automatically?
No. middleBrick detects and reports findings with remediation guidance but does not fix, patch, block, or remediate. Developers should apply the suggested code fixes, such as avoiding header reflection and sanitizing inputs, and re-scan to verify the issues are resolved.