File CVE-2023-49082.patch of Package python-aiohttp.32033
From 4fbe0f2770ee62236b386f820e06f1e86ee1b1a4 Mon Sep 17 00:00:00 2001
From: Ben Kallus <49924171+kenballus@users.noreply.github.com>
Date: Wed, 18 Oct 2023 06:22:20 -0400
Subject: [PATCH] Stop accepting `\x80-\xff` in header names; stop accepting
`\n` as separating whitespace in status-lines (#7719)
This PR updates the python HTTP parser to stop accepting `\x80-\xff` in
header names and stop accepting `\n` as separating whitespace in
status-lines. Both of these are not allowed in the RFCs.
Only users of seriously misbehaving clients would notice a change in
behavior for this patch. If a client sends non-ascii UTF-8 within header
names, their messages will now 400. Note that (nearly) arbitrary values
are still allowed within header values. Most HTTP servers (Apache,
Nginx, IIS, Node) do not accept UTF-8 within header names because of the
risk of control character injection.
---------
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
---
CHANGES/7719.bugfix | 1 +
aiohttp/http_parser.py | 6 ++++--
tests/test_http_parser.py | 7 +++++++
3 files changed, 12 insertions(+), 2 deletions(-)
create mode 100644 CHANGES/7719.bugfix
diff --git a/CHANGES/7719.bugfix b/CHANGES/7719.bugfix
new file mode 100644
index 00000000..b5474398
--- /dev/null
+++ b/CHANGES/7719.bugfix
@@ -0,0 +1 @@
+Update parser to disallow invalid characters in header field names and stop accepting LF as a request line separator.
diff --git a/aiohttp/http_parser.py b/aiohttp/http_parser.py
index 91e01f43..ee0022e4 100644
--- a/aiohttp/http_parser.py
+++ b/aiohttp/http_parser.py
@@ -78,7 +78,9 @@ ASCIISET: Final[Set[str]] = set(string.printable)
# token = 1*tchar
METHRE: Final[Pattern[str]] = re.compile(r"[!#$%&'*+\-.^_`|~0-9A-Za-z]+")
VERSRE: Final[Pattern[str]] = re.compile(r"HTTP/(\d).(\d)")
-HDRRE: Final[Pattern[bytes]] = re.compile(rb"[\x00-\x1F\x7F()<>@,;:\[\]={} \t\"\\]")
+HDRRE: Final[Pattern[bytes]] = re.compile(
+ rb"[\x00-\x1F\x7F-\xFF()<>@,;:\[\]={} \t\"\\]"
+)
HEXDIGIT = re.compile(rb"[0-9a-fA-F]+")
@@ -565,7 +567,7 @@ class HttpRequestParser(HttpParser[RawRequestMessage]):
# request line
line = lines[0].decode("utf-8", "surrogateescape")
try:
- method, path, version = line.split(maxsplit=2)
+ method, path, version = line.split(" ", maxsplit=2)
except ValueError:
raise BadStatusLine(line) from None
diff --git a/tests/test_http_parser.py b/tests/test_http_parser.py
index 4b185c9e..d08b708c 100644
--- a/tests/test_http_parser.py
+++ b/tests/test_http_parser.py
@@ -179,6 +179,7 @@ def test_cve_2023_37276(parser) -> None:
"Baz: abc\x00def",
"Foo : bar", # https://www.rfc-editor.org/rfc/rfc9112.html#section-5.1-2
"Foo\t: bar",
+ "\xffoo: bar",
),
)
def test_bad_headers(parser, hdr: str) -> None:
@@ -655,6 +656,12 @@ def test_http_request_bad_status_line(parser) -> None:
assert r"\n" not in exc_info.value.message
+def test_http_request_bad_status_line_whitespace(parser: Any) -> None:
+ text = b"GET\n/path\fHTTP/1.1\r\n\r\n"
+ with pytest.raises(http_exceptions.BadStatusLine):
+ parser.feed_data(text)
+
+
def test_http_request_upgrade(parser) -> None:
text = (
b"GET /test HTTP/1.1\r\n"
--
2.43.0