HTTP Response Splitting
Also Known As
response splitting
header splitting
CRLF response split
TL;DR
Injecting CRLF sequences into HTTP headers causes the server to emit two separate responses, enabling cache poisoning and XSS.
Explanation
HTTP Response Splitting is an escalation of CRLF injection. By injecting \r\n\r\n into a header value, an attacker can terminate the first response and craft an entirely fabricated second response — including its own headers and body. Shared proxies and caches may store the attacker-injected second response and serve it to other users. Modern PHP (7.4+) strips newlines from header() calls, but older code or custom header-writing functions remain vulnerable. Always sanitise header values and use framework-level response objects rather than raw header() calls.
How It's Exploited
An attacker submits a redirect URL containing \r\n\r\n followed by a crafted HTML body. A proxy caches the fabricated response and serves the malicious content to every subsequent visitor who requests the same URL.
Common Misconception
✗ Modern frameworks are immune to response splitting. Most are, but custom header() calls or third-party libraries accepting unvalidated user input can still be vulnerable.
Why It Matters
Injecting newline characters into HTTP response headers allows an attacker to craft a second HTTP response, potentially poisoning caches or injecting malicious content for other users.
Common Mistakes
- Reflecting user input into any HTTP header without stripping \r and \n characters.
- URL-decoding values before passing to header() without re-stripping control characters.
- Not realising this is the underlying mechanism behind CRLF injection and header injection.
- Trusting that PHP's header() function sanitises its input — it does not in all versions.
Code Examples
✗ Vulnerable
// User input injected into header — response splitting:
$lang = $_GET['lang']; // Attacker: en\r\nHTTP/1.1 200 OK\r\n...
header('Content-Language: ' . $lang);
// Results in a second fabricated HTTP response
// Safe:
$lang = preg_replace('/[\r\n]/', '', $_GET['lang']);
header('Content-Language: ' . $lang);
✓ Fixed
// Validate and encode header values before sending:
function safeRedirect(string $url): void {
// Validate URL — only allow safe schemes and known domains:
$parsed = parse_url($url);
if (!in_array($parsed['scheme'] ?? '', ['http', 'https'], true)) {
throw new InvalidArgumentException('Invalid URL scheme');
}
// PHP 7.4+ header() strips CR/LF — but be explicit:
$safeUrl = preg_replace('/[\r\n]/', '', $url);
header('Location: ' . $safeUrl, true, 302);
exit;
}
// For custom headers:
$safeValue = preg_replace('/[\r\n\0]/', '', $userInput);
header('X-Custom: ' . $safeValue);
Tags
🤝 Adopt this term
£79/year · your link shown here
Added
15 Mar 2026
Edited
22 Mar 2026
Views
21
🤖 AI Guestbook educational data only
|
|
Last 30 days
Agents 0
No pings yet today
No pings yesterday
Amazonbot 6
ChatGPT 3
Google 2
Majestic 1
Perplexity 1
Ahrefs 1
Also referenced
How they use it
crawler 14
Related categories
⚡
DEV INTEL
Tools & Severity
🟠 High
⚙ Fix effort: Low
⚡ Quick Fix
PHP 7.4+ automatically strips CR/LF from header values — for older PHP, strip \r and \n from any user input before using it in header() calls
📦 Applies To
PHP 5.0+
web
api
🔗 Prerequisites
🔍 Detection Hints
header() with user-controlled value containing potential CRLF; Location header built from user input without CR/LF stripping; PHP < 7.4 not stripping newlines
Auto-detectable:
✓ Yes
semgrep
owasp-zap
⚠ Related Problems
🤖 AI Agent
Confidence: High
False Positives: Low
✓ Auto-fixable
Fix: Low
Context: Line
CWE-113
CWE-93