aiohttp: CRLF injection in multipart headers
Description
CRLF injection in aiohttp's multipart header handling allows header injection when user input is passed to MultipartWriter.append or Payload.headers.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
CRLF injection in aiohttp's multipart header handling allows header injection when user input is passed to MultipartWriter.append or Payload.headers.
Vulnerability
A CRLF injection vulnerability exists in the aiohttp library (versions <= 3.13.5) within the MultipartWriter.append() method and the Payload.headers property. When an application passes attacker-controlled strings as header values or names, the library does not sanitize the input for \r, \n, or null bytes before constructing multipart boundaries, allowing an attacker to inject arbitrary headers into the HTTP request. The vulnerable code path is reachable only if the application actively passes unsanitized user input to these specific API calls [1][2].
Exploitation
An attacker must find an application that uses aiohttp and passes unvalidated user input into either MultipartWriter.append(headers=...) or directly into Payload.headers dict. The attacker can then include CR (\r), LF (\n), or null bytes in the input, which when processed by _binary_headers will result in injected header lines. No authentication or special network position is required beyond normal access to the application's user-controllable input fields that feed into these functions. The fix includes parameterized tests that demonstrate injection attempts with \r, \n, and \x00 in both header names and values [3].
Impact
Successful exploitation allows an attacker to modify the request by injecting additional HTTP headers or altering the content structure. This could lead to request smuggling, cache poisoning, or bypassing security controls depending on the downstream handling. The impact is limited to header injection in multipart requests; it is not a direct remote code execution or data disclosure vulnerability. The severity is rated low by the maintainers due to the prerequisite condition of the application passing unsanitized user input into specific aiohttp APIs [1][2].
Mitigation
The vulnerability is fixed in commit bf88077, which adds validation in _binary_headers to reject any header value or name containing \r, \n, or \x00 characters with a ValueError matching "header injection" [3]. Users should upgrade to aiohttp version > 3.13.5. As a workaround, applications should sanitize all user input before passing it to MultipartWriter.append(), Payload.headers, or any header-related parameters, ensuring that no CR, LF, or null bytes are present [1][2].
AI Insight generated on Jun 15, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected products
2Patches
1bf88077ebb14[PR #12719/879d48d1 backport][3.14] Reject invalid bytes in multipart/payload headers (#12720)
3 files changed · +21 −3
aiohttp/payload.py+5 −3 modified@@ -23,6 +23,7 @@ parse_mimetype, sentinel, ) +from .http_writer import _safe_header from .streams import StreamReader from .typedefs import JSONBytesEncoder, JSONEncoder, _CIMultiDict @@ -197,9 +198,10 @@ def headers(self) -> _CIMultiDict: @property def _binary_headers(self) -> bytes: return ( - "".join([k + ": " + v + "\r\n" for k, v in self.headers.items()]).encode( - "utf-8" - ) + "".join( + _safe_header(k) + ": " + _safe_header(v) + "\r\n" + for k, v in self.headers.items() + ).encode("utf-8") + b"\r\n" )
CHANGES/12706.bugfix.rst+1 −0 added@@ -0,0 +1 @@ +Fixed invalid bytes being allowed in multipart/payload headers -- by :user:`Dreamsorcerer`.
tests/test_payload.py+15 −0 modified@@ -101,6 +101,21 @@ def test_payload_content_type() -> None: assert p.content_type == "application/json" +@pytest.mark.parametrize("bad_byte", ("\r", "\n", "\x00")) +def test_binary_headers_reject_injection_in_value(bad_byte: str) -> None: + p = Payload("test", headers={"X-Custom": f"value{bad_byte}Injected: bad"}) + with pytest.raises(ValueError, match="header injection"): + p._binary_headers + + +@pytest.mark.parametrize("bad_byte", ("\r", "\n", "\x00")) +def test_binary_headers_reject_injection_in_name(bad_byte: str) -> None: + p = Payload("test") + p.headers[f"X-Custom{bad_byte}Injected"] = "value" + with pytest.raises(ValueError, match="header injection"): + p._binary_headers + + def test_bytes_payload_default_content_type() -> None: p = payload.BytesPayload(b"data") assert p.content_type == "application/octet-stream"
Vulnerability mechanics
Root cause
"Missing validation of header name and value bytes allows injection of CR/LF characters, enabling HTTP header injection."
Attack vector
An attacker who can control strings passed into `MultipartWriter.append(headers=...)` or `Payload.headers` can inject carriage return (`\r`) or newline (`\n`) characters to break out of the intended header line and inject arbitrary additional HTTP headers or alter the request body. This is a classic HTTP header injection attack [CWE-113]. The attacker must have the ability to supply unsanitized input to these header parameters, which is described as an 'unlikely situation' in the advisory.
Affected code
The vulnerability resides in `aiohttp/payload.py` in the `_binary_headers` property, which concatenates header names and values directly without sanitization. The patch introduces a call to `_safe_header()` from `http_writer` to reject bytes `\r`, `\n`, and `\x00` in both header names and values.
What the fix does
The patch modifies `_binary_headers` in `payload.py` to pass each header name and value through `_safe_header()` before concatenation. `_safe_header()` raises a `ValueError` if the input contains `\r`, `\n`, or `\x00` bytes, preventing an attacker from injecting line breaks into the serialized header block. The corresponding tests verify that both header names and values containing these bad bytes are rejected with a 'header injection' error.
Preconditions
- inputThe application must pass user-controlled strings into `MultipartWriter.append(headers=...)` or `Payload.headers`.
- inputThe attacker-supplied string must contain `\r`, `\n`, or `\x00` bytes to break out of the header line.
Generated on Jun 15, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
3News mentions
0No linked articles in our index yet.