Skip to main content

Overview

CRLF Injection occurs when an attacker can inject Carriage Return (CR, %0d, \r) and Line Feed (LF, %0a, \n) characters into an application’s output that is included in an HTTP response header. Since CR+LF sequences (\r\n) are used to separate headers and delimit the start of the response body in HTTP/1.1, injecting them allows an attacker to add fake headers or even inject content into the response body. This can lead to HTTP Response Splitting, Cross-Site Scripting (XSS), session fixation, or cache poisoning. 📄✂️

Business Impact

CRLF Injection enables several other attacks:
  • Cross-Site Scripting (XSS): By injecting CRLF sequences followed by HTML/JavaScript into the response body.
  • Session Fixation: By injecting a Set-Cookie header with a session ID they control.
  • Cache Poisoning: By crafting a response that gets stored in intermediate caches, affecting other users.
  • Phishing/Defacement: By injecting custom content into the response body.
  • Information Disclosure: By manipulating headers (e.g., Location) to redirect requests or expose internal details.

Reference Details

CWE ID: CWE-113 OWASP Top 10 (2021): A03:2021 - Injection Severity: Medium to High (depending on the resulting attack)

Framework-Specific Analysis and Remediation

This vulnerability happens when user-supplied data is directly included in HTTP response headers without proper sanitization to remove or encode CR (\r) and LF (\n) characters. Common sinks include custom header values, redirect URLs (Location header), and cookie values (Set-Cookie header). Modern web frameworks and libraries often provide some level of automatic protection by validating or encoding header values, but vulnerabilities can still occur in custom code or older/misconfigured setups. The primary defense is output encoding/sanitization specifically targeting CR and LF characters in any data destined for headers.

Framework Context

Manually setting headers in Django/Flask using user input without sanitization. Django’s built-in HttpResponseRedirect generally handles the Location header safely, but custom headers are a risk.

Vulnerable Scenario 1: Custom Header Reflection

A view reflects a user-provided parameter in a custom header.

Vulnerable Scenario 2: Unvalidated Redirect URL

Constructing a redirect URL using potentially tainted input (less common with Django’s built-in redirect, but possible in custom logic).

Mitigation and Best Practices

Avoid reflecting user input directly into headers. If necessary, sanitize the input by removing or encoding \r and \n characters. Use Django’s built-in HttpResponseRedirect or redirect() shortcut which handles URL validation for the Location header.

Secure Code Example

Testing Strategy

Identify all instances where user input is incorporated into response headers (response['Header-Name'] = user_input). Submit URL-encoded CRLF sequences (%0d%0a) followed by test headers (e.g., Injected-Header: test) or HTML content (%0d%0a%0d%0a<script>...). Use curl -v or browser developer tools to inspect the raw response headers and body for unexpected content.