Skip to main content
Offensive360
Home / Knowledge Base / Log Injection / Log Forging
Medium CWE-117 A09:2021 Security Logging and Monitoring Failures

Log Injection / Log Forging

Log injection allows attackers to insert fake log entries or newline characters into application logs, obscuring malicious activity and potentially attacking log management systems downstream.

Affects: C#JavaPythonJavaScriptPHPGo

What is Log Injection?

Log injection occurs when user-supplied input is written to application logs without sanitizing control characters, particularly newlines (\n, \r). An attacker can use this to forge legitimate-looking log entries, erase evidence of an attack, inject malicious content into log files, or — when logs are processed by downstream systems — trigger further attacks.

Beyond obscuring an incident, log injection can be particularly dangerous when logs are fed into SIEM tools, ELK Stack, or log parsers that interpret entries as commands, run scripts based on log content, or display logs in a web interface vulnerable to XSS.

The Log4Shell vulnerability (CVE-2021-44228) demonstrated the extreme end of this class: log entries that triggered JNDI lookups, resulting in RCE.

How exploitation works

An application logs failed login attempts:

logger.warn("Failed login for user: " + username);

An attacker submits alice\nINFO: Login succeeded for user: alice as the username. The resulting log file contains:

WARN  Failed login for user: alice
INFO  Login succeeded for user: alice   ← Forged entry

A security analyst reviewing the log sees a successful login and may not investigate further, even though no authentication occurred.

Vulnerable code examples

Java / Logback

// VULNERABLE: Unsanitized user input written directly to log
@PostMapping("/login")
public ResponseEntity<?> login(@RequestBody LoginRequest req) {
    if (!authService.authenticate(req.getUsername(), req.getPassword())) {
        log.warn("Failed login attempt for username: {}", req.getUsername()); // Tainted
        return ResponseEntity.status(401).build();
    }
    // ...
}

Python / logging

# VULNERABLE: User input with newlines reaches the log
import logging
logger = logging.getLogger(__name__)

def process_request(user_agent):
    logger.info(f"Request from: {user_agent}")  # Attacker controls User-Agent header

Secure code examples

Java — sanitize before logging

// SECURE: Strip newlines and control characters from logged user input
private static String sanitizeForLog(String input) {
    if (input == null) return "(null)";
    return input.replaceAll("[\r\n\t]", "_")
                .replaceAll("[\\p{Cntrl}]", "?")
                .substring(0, Math.min(input.length(), 200)); // Limit length
}

@PostMapping("/login")
public ResponseEntity<?> login(@RequestBody LoginRequest req) {
    String safeUsername = sanitizeForLog(req.getUsername());
    if (!authService.authenticate(req.getUsername(), req.getPassword())) {
        log.warn("Failed login attempt for username: {}", safeUsername);
        return ResponseEntity.status(401).build();
    }
    // ...
}

C# / Serilog — structured logging

// SECURE: Serilog structured logging — user input is stored as a property value,
// not concatenated into the message template. Avoids injection in structured log sinks.
Log.Warning("Failed login attempt for {Username}", username);
// Output: {"@mt": "Failed login attempt for {Username}", "Username": "alice\nhacker"}
// The newline is escaped in JSON output — injection is contained.

What Offensive360 detects

  • Unsanitized user input in log callslogger.info(), log.warn(), Console.WriteLine() receiving tainted strings without newline stripping
  • HTTP header values in logs — User-Agent, Referer, X-Forwarded-For, and other attacker-controlled headers logged without encoding
  • JNDI lookup patterns in log data — Detection of ${jndi: patterns or Log4j lookup syntax in logged values (Log4Shell-style)
  • String concatenation in log messages — Direct string concatenation (not structured logging) that embeds user input

Remediation guidance

  1. Strip or encode newlines — Replace \r, \n, and other control characters in any user input before writing to logs.

  2. Use structured logging — Log libraries like Serilog, Winston, and Logback (with structured output) store values as data fields rather than interpolating them into message strings, limiting injection scope.

  3. Limit logged value lengths — Truncate user-supplied values to a reasonable maximum length to prevent log flooding.

  4. Validate inputs early — Reject inputs containing control characters at the API boundary before they reach logging or processing code.

  5. Disable dangerous log framework features — Disable Log4j lookups (log4j2.formatMsgNoLookups=true) and similar features that evaluate log content as expressions.

References

By Offensive360 Security Research Reviewed: March 2026

Detect Log Injection / Log Forging automatically

Run Offensive360 SAST on your codebase to find this and 100+ other vulnerabilities.