What is CRLF Injection? Ways to Exploit, Examples and Impact

Master CRLF injection techniques, from HTTP response splitting to log poisoning. Learn how to secure your infrastructure with this comprehensive guide.

What is CRLF Injection? Ways to Exploit, Examples and Impact

In the world of web security, some of the most devastating vulnerabilities arise from the simplest oversights. CRLF injection is a classic example of such a flaw. While it might seem like a minor formatting issue, it can serve as a gateway to high-severity attacks like Cross-Site Scripting (XSS), cache poisoning, and session hijacking. Understanding how these invisible characters can be manipulated is essential for any developer or security professional aiming to secure modern web applications.

What is CRLF Injection?

To understand CRLF injection, we must first define the acronym. CRLF stands for Carriage Return (CR, ASCII 13, \r) and Line Feed (LF, ASCII 10, \n). These are non-printable characters used to signify the end of a line or a new line of text. In the context of the HTTP protocol, the CRLF sequence (\r\n) is critically important. It is used to separate different headers in an HTTP request or response and to separate the headers from the message body.

An HTTP response typically looks like this:

HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 155

<html>...</html>

Notice the double CRLF (\r\n\r\n) between the headers and the body. This is the standard marker that tells the browser or the server where the metadata ends and the actual content begins. A CRLF injection vulnerability occurs when an application takes user-supplied input and embeds it into an HTTP header without proper sanitization. If an attacker can successfully inject the \r\n sequence, they can effectively "break out" of the intended header and start writing their own headers or even a completely new response body.

How CRLF Injection Works

Most CRLF vulnerabilities are found in functions that handle redirection or logging. For example, consider a website that redirects users based on a lang parameter:

https://example.com/redirect?url=dashboard

The server-side code might look like this in a vulnerable PHP application:

<?php
  $location = $_GET['url'];
  header("Location: /" . $location);
?>

Under normal circumstances, the server sends a header like Location: /dashboard. However, if an attacker provides a malicious string containing URL-encoded CRLF characters (%0D%0A), the output changes.

If the input is dashboard%0D%0ASet-Cookie:sessionid=12345, the resulting HTTP header becomes:

Location: /dashboard
Set-Cookie:sessionid=12345

Because the server interpreted the injected %0D%0A as a literal line break, it added a new, unauthorized header to the response. This is the fundamental mechanism of CRLF injection.

Common Exploitation Scenarios

CRLF injection is rarely the end goal of an attacker; rather, it is a primitive used to achieve more complex exploits. Below are the most common ways this vulnerability is leveraged in the wild.

1. HTTP Response Splitting

HTTP Response Splitting is the most severe form of CRLF injection. By injecting a double CRLF sequence (%0D%0A%0D%0A), an attacker can terminate the headers of the original response and start an entirely new response that they control.

Payload Example:
?url=foobar%0D%0A%0D%0A<html><script>alert('XSS')</script></html>

When the browser receives this, it sees the first response (the redirect) followed immediately by a second "split" response containing the attacker's HTML. Depending on how the browser and intermediary proxies handle this, the attacker can serve arbitrary content to the victim.

2. Cross-Site Scripting (XSS) via CRLF

As seen in the response splitting example, CRLF can lead directly to XSS. Even if the application has filters against <script> tags in the body, an attacker might be able to inject a Content-Type: text/html header followed by a body containing malicious JavaScript. This bypasses many traditional XSS protections because the attacker is creating the entire environment in which the script runs.

3. Log Injection and Poisoning

Applications often log user input for debugging or security auditing. If an application logs a username or a URL without sanitizing CRLF characters, an attacker can inject fake log entries.

Vulnerable Code (Node.js):

console.log("User failed login: " + user_input);

Attack Payload:
admin%0D%0A[INFO] User admin logged in successfully

This makes the log file look like this:

[ERROR] User failed login: admin
[INFO] User admin logged in successfully

This can be used to deceive system administrators, hide malicious activity, or even exploit vulnerabilities in log analysis tools that might be susceptible to further injection when parsing the poisoned logs. Tools like Jsmon can help you monitor your infrastructure to ensure that unexpected changes in application behavior, which might be caused by such injections, are caught early.

By injecting a Set-Cookie header, an attacker can force a specific session ID onto a user's browser. This is known as session fixation. If the user then logs in using that session ID, the attacker (who already knows the ID) can take over the account.

Payload:
%0D%0ASet-Cookie: sessionid=attacker_controlled_id; Path=/; HttpOnly

Real-World Impact

The impact of CRLF injection varies based on the environment but generally includes:

  • Information Disclosure: Stealing session cookies or sensitive data via XSS.
  • Phishing: Redirecting users to a malicious site that looks identical to the original, but with a custom body injected via response splitting.
  • Cache Poisoning: If a web cache (like a CDN or Varnish) caches the "split" response, every user who visits that URL will receive the attacker's malicious content until the cache expires.
  • Bypassing Security Controls: Overriding security headers like Content-Security-Policy (CSP) by injecting a new, more permissive CSP header later in the response.

How to Detect CRLF Injection

Detecting CRLF injection requires testing all points where user input is reflected in HTTP headers.

Manual Testing

You can manually test for this by using a proxy like Burp Suite. Intercept a request and modify a parameter to include %0D%0AInjected-Header: test. Check the response to see if Injected-Header appears as a legitimate header in the raw response view. If it does, the application is vulnerable.

Automated Scanning

Many automated vulnerability scanners look for CRLF injection by sending various encoded sequences and checking the response headers. However, simple scanners often miss context-dependent injections. Using a comprehensive attack surface management platform like Jsmon allows you to maintain a continuous view of your external assets, making it easier to identify where new endpoints are added that might lack these crucial security checks.

Prevention and Mitigation

Preventing CRLF injection is straightforward if followed consistently across the development lifecycle.

1. Sanitize and Validate Input

Never trust user input. Always strip or encode carriage returns (\r) and line feeds (\n) before using them in any header-related functions. Most modern web frameworks provide built-in functions to handle redirects and header setting safely.

2. Use Modern Libraries

In many modern languages, standard libraries have been updated to prevent CRLF injection automatically. For example, in newer versions of Java's HttpServletResponse.sendRedirect(), if you attempt to pass a string with CRLF characters, the library will throw an exception or strip the characters. Always ensure your language runtimes and frameworks are up to date.

3. Disable Unnecessary Headers

If your application doesn't need to dynamically generate headers based on user input, don't do it. Hardcode redirects where possible or use a whitelist of allowed redirection targets.

4. Implement a Content Security Policy (CSP)

While CSP doesn't prevent CRLF injection itself, a strong policy can mitigate the impact of XSS attacks that result from response splitting by restricting where scripts can be loaded from.

Conclusion

CRLF injection is a reminder that the fundamentals of web protocols still matter. Even as we move toward more complex web architectures, the way headers are parsed remains a critical security boundary. By understanding how attackers use simple characters like \r and \n to manipulate server responses, developers can build more resilient applications. Continuous monitoring and a proactive approach to security are your best defenses against these types of flaws.

To proactively monitor your organization's external attack surface and catch exposures like CRLF injection before attackers do, try Jsmon.