Improper Neutralization of CRLF Sequences ('CRLF Injection')
Description
CRLF Injection is a vulnerability that occurs when software constructs output records using externally-influenced input but does not neutralize or incorrectly neutralizes Carriage Return (CR, \r, %0d) and Line Feed (LF, \n, %0a) characters. In HTTP and many text-based protocols, CRLF sequences delimit headers and separate headers from body content. Attackers exploit this vulnerability to inject arbitrary headers, split HTTP responses, manipulate log files, or alter the structure of protocol messages. HTTP Response Splitting is a particularly dangerous form of CRLF injection that enables cache poisoning, cross-site scripting, and session hijacking attacks.
Risk
CRLF injection enables powerful attacks depending on the context. In HTTP responses, attackers can inject additional headers including Set-Cookie for session fixation, Location for redirect attacks, or security headers to disable protections. HTTP Response Splitting allows injecting complete fake responses that may be cached by proxies, enabling widespread attacks against other users. In email headers, CRLF injection enables email header injection for spam relay or spoofing. Log injection can corrupt log files, inject false entries to cover tracks, or exploit log viewers vulnerable to terminal escape sequences. The simplicity of exploitation combined with potentially severe impact makes this a high-priority vulnerability class.
Solution
Strip or encode all CR and LF characters from user input before including it in HTTP headers, log messages, email headers, or other line-delimited contexts. Use framework-provided functions for setting HTTP headers that automatically handle encoding. Validate that user input does not contain unexpected line terminators. For URLs and redirect destinations, validate against allowlists of permitted domains and paths. Implement proper output encoding for the specific context (URL encoding for URL parameters, header encoding for HTTP headers). Use modern web frameworks that prevent CRLF injection by default in header-setting functions.
Common Consequences
| Impact | Details |
|---|---|
| Integrity | Scope: Integrity HTTP Response Splitting enables injection of arbitrary content including malicious JavaScript, fake login pages, or misleading information. |
| Access Control | Scope: Access Control Session fixation through injected Set-Cookie headers can enable account hijacking and unauthorized access. |
| Confidentiality | Scope: Confidentiality Cache poisoning through response splitting can expose other users' data or redirect them to malicious sites. |
Example Code + Solution Code
Vulnerable Code
from flask import Flask, request, redirect, make_response
app = Flask(__name__)
@app.route('/redirect')
def vulnerable_redirect():
# VULNERABLE: User input directly in Location header
# Attack: url=http://example.com%0d%0aSet-Cookie:%20session=malicious
url = request.args.get('url')
response = make_response('Redirecting...')
response.headers['Location'] = url # CRLF injection possible
response.status_code = 302
return response
@app.route('/setlang')
def set_language():
# VULNERABLE: User input in cookie without sanitization
# Attack: lang=en%0d%0aSet-Cookie:%20admin=true
lang = request.args.get('lang')
response = make_response('Language set')
response.headers['Set-Cookie'] = f'language={lang}'
return response
Fixed Code
from flask import Flask, request, redirect, make_response, abort
import re
from urllib.parse import urlparse
app = Flask(__name__)
def sanitize_header_value(value):
"""Remove CRLF characters from header values"""
if value is None:
return None
# Remove CR, LF, and null bytes
return re.sub(r'[\r\n\x00]', '', value)
def validate_redirect_url(url):
"""Validate redirect URL against allowlist"""
allowed_domains = ['example.com', 'trusted.com']
try:
parsed = urlparse(url)
if parsed.scheme not in ['http', 'https']:
return None
if parsed.netloc not in allowed_domains:
return None
return url
except:
return None
@app.route('/redirect')
def safe_redirect():
url = request.args.get('url', '')
# Sanitize CRLF characters
url = sanitize_header_value(url)
# Validate against allowlist
safe_url = validate_redirect_url(url)
if not safe_url:
abort(400, 'Invalid redirect URL')
# Use framework's redirect function (adds protection)
return redirect(safe_url)
@app.route('/setlang')
def safe_set_language():
lang = request.args.get('lang', 'en')
# Validate against allowlist
allowed_languages = ['en', 'de', 'fr', 'es', 'ja']
if lang not in allowed_languages:
lang = 'en'
# Use response.set_cookie() instead of manual header
response = make_response('Language set')
response.set_cookie('language', lang, httponly=True, secure=True)
return response
Exploited in the Wild
HTTP Response Splitting Attacks (Web Applications, Historical)
CRLF injection enabling HTTP Response Splitting has been exploited against various web applications to perform cache poisoning attacks, where malicious responses are cached by proxy servers and served to other users.
Tools to test/exploit
-
Burp Suite — web security testing platform with CRLF injection detection in headers and responses.
-
CRLFuzz — automated CRLF injection vulnerability scanner.
CVE Examples
-
CVE-2023-27350 — PaperCut CRLF injection in print job handling.
-
CVE-2021-33026 — Flask-Caching CRLF injection in cache key handling.
References
-
MITRE. "CWE-93: Improper Neutralization of CRLF Sequences." https://cwe.mitre.org/data/definitions/93.html
-
OWASP. "HTTP Response Splitting." https://owasp.org/www-community/attacks/HTTP_Response_Splitting