MEDIUM log injectionexpressbasic auth

Log Injection in Express with Basic Auth

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

Log injection occurs when untrusted input is written directly into log entries without proper sanitization or formatting, allowing an attacker to forge log lines, obfuscate events, or inject additional metadata into logging systems. In Express applications that use HTTP Basic Authentication, the combination of raw header values, custom logging logic, and structured log formats can amplify the risk.

With Basic Auth, the client sends credentials in the Authorization header as Basic base64(username:password). If the application decodes this header and directly interpolates the username (or the full header) into logs without validation, an attacker can supply a username containing newline characters or structured delimiters (e.g., admin%0d%0aX-Forwarded-For:%201.2.3.4). Because logs often use line-based parsing, a injected newline can create a fabricated log entry that appears legitimate, potentially bypassing log-based monitoring rules.

Consider an Express route that logs authentication events by reading req.headers.authorization and the decoded username. If the username includes carriage returns or other control characters, and the logger writes each authentication attempt as a single logical line, the injected content can split or duplicate log entries. This can interfere with log aggregation tools that rely on consistent line structures, making it harder to detect genuine anomalies or correlate events. In distributed environments where logs are collected centrally, a single malicious username can propagate malformed entries across multiple services.

The interaction with structured logging formats (such as JSON) can either mitigate or exacerbate the issue. If the application constructs log objects and then serializes them, injecting newlines inside string fields can break JSON parsing for downstream consumers that read logs line-by-line. Conversely, if the logger concatenates fields manually (e.g., res.status(200).send('User: ' + username) and logs the result), control characters in the username can distort the output format and hide important context like timestamps or request IDs.

Log injection in this context does not directly enable remote code execution, but it undermines auditability, obscures attack evidence, and can support follow-on abuses such as log forging or evasion. Because Basic Auth credentials are often reused across services, a compromised username used in one endpoint can affect logging behavior elsewhere if the same logging pipeline processes multiple applications.

middleBrick scans for Log Injection by testing input vectors that reach log sinks, including headers that influence log generation. When Basic Auth headers are involved, the scanner checks whether decoded credential values are sanitized before inclusion in logs, and whether the application’s logging structure preserves integrity against newline and control-character injection.

Basic Auth-Specific Remediation in Express — concrete code fixes

Defensive handling of Basic Auth in Express requires validating and sanitizing any part of the credentials before they reach logging code. The safest approach is to avoid using raw user-controlled strings in logs entirely, or to ensure they are encoded and treated as opaque values.

Example of vulnerable code that directly logs the decoded username:

const authHeader = req.headers.authorization; // "Basic YWRtaW46cGFzc3dvcmQ=\nX-Injected: foo"
if (authHeader && authHeader.startsWith('Basic ')) {
  const decoded = Buffer.from(authHeader.slice(6), 'base64').toString('utf-8');
  const [username, password] = decoded.split(':');
  console.log('Authenticated user:', username); // Risk: username may contain newlines
  // ... proceed with authentication
}

An attacker can supply a username like admin%0d%0aX-Forwarded-For:%2010.0.0.1, which after Base64 encoding and decoding results in a string with embedded newlines that split the log line and inject a fabricated HTTP header-like field.

Safer approach: treat the username as an opaque identifier for logging, and avoid including raw decoded values. Use a sanitized representation such as hashing or truncation, and ensure newline characters are removed or escaped:

const authHeader = req.headers.authorization;
if (authHeader && authHeader.startsWith('Basic ')) {
  const decoded = Buffer.from(authHeader.slice(6), 'base64').toString('utf-8');
  const [username] = decoded.split(':');
  // Remove control characters to prevent log injection
  const safeUsername = username.replace(/[\r\n\u2028\u2029]/g, '');
  // Use a non-reversible representation for logging if possible
  const logId = safeUsername.substring(0, 16);
  console.log('Authenticated user', { logId, timestamp: new Date().toISOString() });
  // Proceed with authentication using the original username variable if needed
}

For applications that must retain the username in logs for audit purposes, encode problematic characters or use a structured logging library that handles escaping automatically. Also ensure that the logging layer does not treat injected newlines as record boundaries by using length-prefixed writes or structured formats that validate each entry.

middleBrick’s checks include verifying that header-derived values used in logging do not contain newline or carriage return characters, and that structured logging outputs remain parseable. The scanner can surface findings when raw credential components appear directly in console or file outputs, guiding teams to apply consistent sanitization.

Frequently Asked Questions

Can log injection via Basic Auth usernames affect log-based alerting?
Yes. If a username contains newline characters, it can split a single logical log entry into multiple lines, causing log parsers to mis-align timestamps, drop fields, or create false positive alerts. Always sanitize usernames before they reach line-oriented logging pipelines.
Does middleBrick test for log injection in authenticated endpoints?
middleBrick tests unauthenticated attack surfaces by default. For endpoints that rely on headers like Authorization, the scanner includes header-based inputs in its checks and evaluates whether resulting log-like outputs remain structured and free of injected control characters.