Safeguard
Security Guides•

HTTP response splitting: why echoing input into headers is risky

If user input reaches a response header with CR and LF intact, one response can look like two. What RFC 9112 says and how to defend, with a redirect example.

Safeguard Security Team
3 min read

Response splitting happens when an application copies untrusted input into a response header without removing carriage return and line feed characters. The attacker's input then ends the header section early, and one response looks like two. The reliable fix is to stop anything but your protocol library from writing those characters.

How the RFC describes it

RFC 9112 section 11.1 calls response splitting a common technique that uses CRLF injection. An attacker inserts encoded CR and LF characters that the application echoes into header fields, for example the Location header of a redirect. The application's single response then appears to be two, and the attacker controls the second.

Why that matters: a cache, proxy or browser that reads the stream as two responses can store or show attacker content for a URL the user trusts.

A typical vulnerable pattern

// Unsafe: next comes straight from the query string
res.setHeader("Location", req.query.next);
res.statusCode = 302;
res.end();

If next can carry encoded CR and LF bytes that get decoded before the header is written, the attacker injects extra headers or a second response. Modern runtimes often reject such values, but older stacks, custom servers and some proxies do not.

Why filtering is the weak defense

The RFC notes that filtering for strings like %0D and %0A is not reliable, because the application may decode or transform data in other ways before it reaches the header. A blocklist covers the encodings you thought of.

The stronger defense

The RFC phrases the better approach as preventing anything other than the server's core protocol libraries from sending a CR or LF within the header section. In practice:

  1. Set headers only through the framework API, never by concatenating raw header text.
  2. Make the framework reject any header value containing CR or LF, and fail closed.
  3. Validate redirect targets against an allow list of paths or hosts, which also stops open redirects. See safe patterns for login return URLs.
  4. Keep your HTTP server and libraries updated, since parser fixes land there.
  5. Log and alert on header write errors, which can be the first sign of probing.

Related parsing rules

The RFC adds that lenient status line parsing and obsolete line folding can also enable splitting. Strict parsers on every hop reduce the chance two components disagree. The same disagreement idea underlies request smuggling.

Review checklist

  • Search the code for places that set Location, Set-Cookie or custom headers from request data.
  • Confirm tests include values with encoded line breaks.
  • Check that any CDN or proxy in front also rejects them.

Where Safeguard fits

Safeguard does not inspect your live traffic. It scans the dependencies and SBOMs behind your web stack for known vulnerabilities and can gate pull requests with policies. Try the free scan at gold.safeguard.sh/scan.

Quick check

Is blocking the strings %0D and %0A enough?

No. The RFC says it is unreliable, because the application may decode or transform the data in other ways.

Which header is a classic injection point?

The Location header of a redirect, which the RFC uses as its example.

Sources

Last reviewed: 19 October 2026.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.