Improper Neutralization of HTTP Headers for Scripting Syntax
Summary
This is CWE-93's formal name for what's more commonly called CRLF injection or HTTP header injection: an application takes user input and writes it directly into a response header without stripping carriage-return/line-feed (\r\n) characters. Because CRLF is the delimiter HTTP uses between headers - and between the headers block and the body - an attacker who can smuggle a CRLF sequence into a header value can inject entirely new headers, or terminate the headers block early and start writing arbitrary response body content, all from what should have been a single header's value. The two named consequences are the same underlying bug: inject a Set-Cookie header to plant a session cookie of the attacker's choosing (session fixation), or inject enough content to fully split the response and control what the browser renders next (response splitting), including a fabricated HTML body that runs as if the real server sent it.
Top Affected Components / Targets
- Redirect endpoints that reflect a URL parameter into a
Locationheader - Any parameter reflected into a custom response header (caching hints, tracking IDs, localization)
- Set-Cookie construction that incorporates user-controlled input
Common Attack Vectors
- Inject
%0d%0a(URL-encoded CRLF) followed by a fabricated header into any parameter suspected of reaching a response header - Confirm by checking whether the injected header (e.g.
X-Injected: <marker>) appears verbatim as its own header line in the response, rather than being reflected inertly inside an existing header's value
Common Payloads
%0d%0aX-Injected: <marker>%0d%0aSet-Cookie: session=attacker-chosen-value%0d%0a%0d%0a<html>fabricated body</html>(full response-splitting variant)
Detection Strategy
Inject a CRLF sequence followed by a unique marker header into every discovered URL parameter, then parse the raw response for that marker header appearing as an independent header line (not merely reflected as literal text inside another header's value). A marker appearing as its own parsed header is unambiguous proof the server didn't strip the CRLF - there's no legitimate reason a raw \r\n sequence would ever need to survive into a header value, which keeps this a low-false-positive, purely structural check.
Tip: Testing tools that run these checks in parallel across every discovered endpoint can cut the time required substantially compared to fully manual testing, as long as they confirm findings with more than one signal to keep the false-positive rate down.
False-Positive Notes
The check requires the injected marker to parse as a genuine, separate response header - a framework that URL-decodes but then HTML-escapes or otherwise neutralizes the CRLF sequence before it reaches the header-writing code will not produce a real header injection and correctly won't be flagged.
How to Test
Manual Testing Methodology
Here is a systematic approach to identifying Improper Neutralization of HTTP Headers for Scripting Syntax vulnerabilities in a target application.
Before testing, map all input vectors that could be affected. Identify parameters, headers, cookies, and request bodies that interact with the vulnerable component. A proxy such as Burp Suite or OWASP ZAP, paired with normal browsing of the target, is usually enough to build this list.
Send a legitimate request and record the normal response: status code, content length, response time, and any identifying tokens. This baseline matters because it's what you'll compare later responses against once payloads are involved.
Inject test payloads into each identified input vector one at a time. Start with benign detection payloads before escalating to anything that could actually trigger the vulnerability. For Improper Neutralization of HTTP Headers for Scripting Syntax specifically, submit %0d%0a (and raw \r\n where the transport allows it) followed by a new header name/value or a fake log line into every parameter that ends up reflected in a response header, Set-Cookie value, redirect target, or logged field.
Compare the response against your baseline, looking specifically for an extra, attacker-defined header appearing in the raw HTTP response, a split response body, or a forged entry appearing in application logs.
Once a potential vulnerability is detected, confirm it with at least a few independent test cases to rule out coincidence. Document the exact request and response as proof. For Improper Neutralization of HTTP Headers for Scripting Syntax, a confirmed finding typically means showing that attacker-controlled input changes the application's behavior in a way that matters for security, not just that a payload was reflected somewhere harmless.
Real-World Impact
Real-World Impact
CRLF and HTTP header injection let an attacker insert carriage-return/line-feed sequences into a value that ends up in a raw HTTP header or a log line, splitting what should be a single header into multiple, or a single log entry into several. In a header context, this can inject entirely new response headers, split the response into two, or plant content the application never intended to serve — including a second, attacker-controlled response body.
The practical exploits built on this primitive include HTTP response splitting (poisoning what an intermediate cache stores and serves to other users), session fixation via an injected Set-Cookie header, and open-redirect-adjacent phishing via an injected Location header — the specific impact depends on which header ends up attacker-controlled.
In logs specifically, CRLF injection enables log forging: an attacker can fabricate fake log entries designed to mislead an investigator or hide evidence of the real attack among plausible-looking noise.
Prevention & Remediation
Prevention and Secure Coding
Preventing Improper Neutralization of HTTP Headers for Scripting Syntax takes a defense-in-depth approach — no single control below is sufficient alone, but together they close off both the primary path and the most common bypasses.
Reject CR/LF in header and log values outright. Strip or reject \r and \n characters from any user input that will be placed into an HTTP header value or a log line — don't attempt to escape them, reject the input.
Use framework header-setting APIs. Set headers and cookies through the framework's own API (which typically encodes or rejects invalid characters automatically) rather than concatenating raw strings into a header block.
Validate redirect and cookie values against a strict format. Where a value must go into a Location or Set-Cookie header, validate it against an allowlist format before use, not just against CR/LF.
Structured logging. Use a structured (e.g. JSON) logging format rather than freeform string concatenation, which makes log forging via embedded newlines far harder to pull off convincingly.