From 67bf97cd1dfa513c8b6374905ee225b4d46cdf20 Mon Sep 17 00:00:00 2001 From: Sam Bull Date: Mon, 13 Nov 2023 22:13:06 +0000 Subject: [PATCH] Disallow arbitrary sequence types in version (#7835) Upstream-Status: Backport [https://github.com/aio-libs/aiohttp/commit/1e86b777e61cf4eefc7d92fa57fa19dcc676013b] CVE: CVE-2023-49081 Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Signed-off-by: Jiaying Song --- CHANGES/7835.bugfix | 1 + aiohttp/client_reqrep.py | 4 ++-- tests/test_client_request.py | 18 +++++++++++++++--- 3 files changed, 18 insertions(+), 5 deletions(-) create mode 100644 CHANGES/7835.bugfix diff --git a/CHANGES/7835.bugfix b/CHANGES/7835.bugfix new file mode 100644 index 0000000..4ce3af4 --- /dev/null +++ b/CHANGES/7835.bugfix @@ -0,0 +1 @@ +Fixed arbitrary sequence types being allowed to inject headers via version parameter -- by :user:`Dreamsorcerer` diff --git a/aiohttp/client_reqrep.py b/aiohttp/client_reqrep.py index 987d68f..d3cd77e 100644 --- a/aiohttp/client_reqrep.py +++ b/aiohttp/client_reqrep.py @@ -661,8 +661,8 @@ class ClientRequest: self.headers[hdrs.CONNECTION] = connection # status + headers - status_line = "{0} {1} HTTP/{2[0]}.{2[1]}".format( - self.method, path, self.version + status_line = "{0} {1} HTTP/{v.major}.{v.minor}".format( + self.method, path, v=self.version ) await writer.write_headers(status_line, self.headers) diff --git a/tests/test_client_request.py b/tests/test_client_request.py index 9eeb933..009f1a0 100644 --- a/tests/test_client_request.py +++ b/tests/test_client_request.py @@ -20,6 +20,7 @@ from aiohttp.client_reqrep import ( _merge_ssl_params, ) from aiohttp.helpers import PY_311 +from aiohttp.http import HttpVersion from aiohttp.test_utils import make_mocked_coro @@ -576,18 +577,18 @@ async def test_connection_header(loop, conn) -> None: req.headers.clear() req.keep_alive.return_value = True - req.version = (1, 1) + req.version = HttpVersion(1, 1) req.headers.clear() await req.send(conn) assert req.headers.get("CONNECTION") is None - req.version = (1, 0) + req.version = HttpVersion(1, 0) req.headers.clear() await req.send(conn) assert req.headers.get("CONNECTION") == "keep-alive" req.keep_alive.return_value = False - req.version = (1, 1) + req.version = HttpVersion(1, 1) req.headers.clear() await req.send(conn) assert req.headers.get("CONNECTION") == "close" @@ -1113,6 +1114,17 @@ async def test_close(loop, buf, conn) -> None: await req.close() resp.close() +async def test_bad_version(loop: Any, conn: Any) -> None: + req = ClientRequest( + "GET", + URL("http://python.org"), + loop=loop, + headers={"Connection": "Close"}, + version=("1", "1\r\nInjected-Header: not allowed"), + ) + + with pytest.raises(AttributeError): + await req.send(conn) async def test_custom_response_class(loop, conn) -> None: class CustomResponse(ClientResponse): -- 2.25.1