diff options
| author | Gyorgy Sarvari <skandigraun@gmail.com> | 2026-02-04 17:29:18 +0100 |
|---|---|---|
| committer | Anuj Mittal <anuj.mittal@oss.qualcomm.com> | 2026-02-05 06:59:40 +0530 |
| commit | 4ac10b5dbb564b6032ebfea1ec845809acc8b91a (patch) | |
| tree | a60d21025cc126d5c530c599547ea90637c11c06 /meta-python/recipes-devtools/python | |
| parent | 0b467f2380024891a9689080bf2ddb7a14171da0 (diff) | |
| download | meta-openembedded-4ac10b5dbb564b6032ebfea1ec845809acc8b91a.tar.gz | |
python3-aiohttp: patch CVE-2025-69226
Details: https://nvd.nist.gov/vuln/detail/CVE-2025-69226
Backport the patch that is referenced by the NVD advisory.
Signed-off-by: Gyorgy Sarvari <skandigraun@gmail.com>
Signed-off-by: Anuj Mittal <anuj.mittal@oss.qualcomm.com>
Diffstat (limited to 'meta-python/recipes-devtools/python')
| -rw-r--r-- | meta-python/recipes-devtools/python/python3-aiohttp/CVE-2025-69226.patch | 134 | ||||
| -rw-r--r-- | meta-python/recipes-devtools/python/python3-aiohttp_3.12.15.bb | 1 |
2 files changed, 135 insertions, 0 deletions
diff --git a/meta-python/recipes-devtools/python/python3-aiohttp/CVE-2025-69226.patch b/meta-python/recipes-devtools/python/python3-aiohttp/CVE-2025-69226.patch new file mode 100644 index 0000000000..6786546f25 --- /dev/null +++ b/meta-python/recipes-devtools/python/python3-aiohttp/CVE-2025-69226.patch | |||
| @@ -0,0 +1,134 @@ | |||
| 1 | From b330573c65db35ee1228615ec257619b49b918c7 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Gyorgy Sarvari <skandigraun@gmail.com> | ||
| 3 | Date: Sat, 3 Jan 2026 01:55:05 +0000 | ||
| 4 | Subject: [PATCH] Reject static URLs that traverse outside static root (#11888) | ||
| 5 | (#11906) | ||
| 6 | |||
| 7 | From: Sam Bull <git@sambull.org> | ||
| 8 | |||
| 9 | (cherry picked from commit 63961fa77fa2443109f25c3d8ab94772d3878626) | ||
| 10 | |||
| 11 | Co-authored-by: J. Nick Koston <nick@koston.org> | ||
| 12 | |||
| 13 | CVE: CVE-2025-69226 | ||
| 14 | Upstream-Status: Backport [https://github.com/aio-libs/aiohttp/commit/f2a86fd5ac0383000d1715afddfa704413f0711e] | ||
| 15 | Signed-off-by: Gyorgy Sarvari <skandigraun@gmail.com> | ||
| 16 | --- | ||
| 17 | aiohttp/web_urldispatcher.py | 18 +++++++++--------- | ||
| 18 | tests/test_urldispatch.py | 18 +++++++++++++++++- | ||
| 19 | tests/test_web_sendfile_functional.py | 2 +- | ||
| 20 | tests/test_web_urldispatcher.py | 4 ++-- | ||
| 21 | 4 files changed, 29 insertions(+), 13 deletions(-) | ||
| 22 | |||
| 23 | diff --git a/aiohttp/web_urldispatcher.py b/aiohttp/web_urldispatcher.py | ||
| 24 | index 28ae251..a121656 100644 | ||
| 25 | --- a/aiohttp/web_urldispatcher.py | ||
| 26 | +++ b/aiohttp/web_urldispatcher.py | ||
| 27 | @@ -7,6 +7,7 @@ import html | ||
| 28 | import inspect | ||
| 29 | import keyword | ||
| 30 | import os | ||
| 31 | +import platform | ||
| 32 | import re | ||
| 33 | import sys | ||
| 34 | import warnings | ||
| 35 | @@ -94,6 +95,7 @@ ROUTE_RE: Final[Pattern[str]] = re.compile( | ||
| 36 | ) | ||
| 37 | PATH_SEP: Final[str] = re.escape("/") | ||
| 38 | |||
| 39 | +IS_WINDOWS: Final[bool] = platform.system() == "Windows" | ||
| 40 | |||
| 41 | _ExpectHandler = Callable[[Request], Awaitable[Optional[StreamResponse]]] | ||
| 42 | _Resolve = Tuple[Optional["UrlMappingMatchInfo"], Set[str]] | ||
| 43 | @@ -649,7 +651,12 @@ class StaticResource(PrefixResource): | ||
| 44 | async def resolve(self, request: Request) -> _Resolve: | ||
| 45 | path = request.rel_url.path_safe | ||
| 46 | method = request.method | ||
| 47 | - if not path.startswith(self._prefix2) and path != self._prefix: | ||
| 48 | + # We normalise here to avoid matches that traverse below the static root. | ||
| 49 | + # e.g. /static/../../../../home/user/webapp/static/ | ||
| 50 | + norm_path = os.path.normpath(path) | ||
| 51 | + if IS_WINDOWS: | ||
| 52 | + norm_path = norm_path.replace("\\", "/") | ||
| 53 | + if not norm_path.startswith(self._prefix2) and norm_path != self._prefix: | ||
| 54 | return None, set() | ||
| 55 | |||
| 56 | allowed_methods = self._allowed_methods | ||
| 57 | @@ -666,14 +673,7 @@ class StaticResource(PrefixResource): | ||
| 58 | return iter(self._routes.values()) | ||
| 59 | |||
| 60 | async def _handle(self, request: Request) -> StreamResponse: | ||
| 61 | - rel_url = request.match_info["filename"] | ||
| 62 | - filename = Path(rel_url) | ||
| 63 | - if filename.anchor: | ||
| 64 | - # rel_url is an absolute name like | ||
| 65 | - # /static/\\machine_name\c$ or /static/D:\path | ||
| 66 | - # where the static dir is totally different | ||
| 67 | - raise HTTPForbidden() | ||
| 68 | - | ||
| 69 | + filename = request.match_info["filename"] | ||
| 70 | unresolved_path = self._directory.joinpath(filename) | ||
| 71 | loop = asyncio.get_running_loop() | ||
| 72 | return await loop.run_in_executor( | ||
| 73 | diff --git a/tests/test_urldispatch.py b/tests/test_urldispatch.py | ||
| 74 | index ba6bdff..e329ea2 100644 | ||
| 75 | --- a/tests/test_urldispatch.py | ||
| 76 | +++ b/tests/test_urldispatch.py | ||
| 77 | @@ -1,4 +1,5 @@ | ||
| 78 | import pathlib | ||
| 79 | +import platform | ||
| 80 | import re | ||
| 81 | from collections.abc import Container, Iterable, Mapping, MutableMapping, Sized | ||
| 82 | from typing import NoReturn | ||
| 83 | @@ -1041,7 +1042,22 @@ async def test_405_for_resource_adapter(router) -> None: | ||
| 84 | assert (None, {"HEAD", "GET"}) == ret | ||
| 85 | |||
| 86 | |||
| 87 | -async def test_check_allowed_method_for_found_resource(router) -> None: | ||
| 88 | +@pytest.mark.skipif(platform.system() == "Windows", reason="Different path formats") | ||
| 89 | +async def test_static_resource_outside_traversal(router: web.UrlDispatcher) -> None: | ||
| 90 | + """Test relative path traversing outside root does not resolve.""" | ||
| 91 | + static_file = pathlib.Path(aiohttp.__file__) | ||
| 92 | + request_path = "/st" + "/.." * (len(static_file.parts) - 2) + str(static_file) | ||
| 93 | + assert pathlib.Path(request_path).resolve() == static_file | ||
| 94 | + | ||
| 95 | + resource = router.add_static("/st", static_file.parent) | ||
| 96 | + ret = await resource.resolve(make_mocked_request("GET", request_path)) | ||
| 97 | + # Should not resolve, otherwise filesystem information may be leaked. | ||
| 98 | + assert (None, set()) == ret | ||
| 99 | + | ||
| 100 | + | ||
| 101 | +async def test_check_allowed_method_for_found_resource( | ||
| 102 | + router: web.UrlDispatcher, | ||
| 103 | +) -> None: | ||
| 104 | handler = make_handler() | ||
| 105 | resource = router.add_resource("/") | ||
| 106 | resource.add_route("GET", handler) | ||
| 107 | diff --git a/tests/test_web_sendfile_functional.py b/tests/test_web_sendfile_functional.py | ||
| 108 | index 0325a46..3207623 100644 | ||
| 109 | --- a/tests/test_web_sendfile_functional.py | ||
| 110 | +++ b/tests/test_web_sendfile_functional.py | ||
| 111 | @@ -638,7 +638,7 @@ async def test_static_file_directory_traversal_attack(aiohttp_client) -> None: | ||
| 112 | |||
| 113 | url_abspath = "/static/" + str(full_path.resolve()) | ||
| 114 | resp = await client.get(url_abspath) | ||
| 115 | - assert 403 == resp.status | ||
| 116 | + assert resp.status == 404 | ||
| 117 | await resp.release() | ||
| 118 | |||
| 119 | await client.close() | ||
| 120 | diff --git a/tests/test_web_urldispatcher.py b/tests/test_web_urldispatcher.py | ||
| 121 | index ee60b69..7de3ea5 100644 | ||
| 122 | --- a/tests/test_web_urldispatcher.py | ||
| 123 | +++ b/tests/test_web_urldispatcher.py | ||
| 124 | @@ -838,8 +838,8 @@ async def test_static_absolute_url( | ||
| 125 | here = pathlib.Path(__file__).parent | ||
| 126 | app.router.add_static("/static", here) | ||
| 127 | client = await aiohttp_client(app) | ||
| 128 | - resp = await client.get("/static/" + str(file_path.resolve())) | ||
| 129 | - assert resp.status == 403 | ||
| 130 | + async with client.get("/static/" + str(file_path.resolve())) as resp: | ||
| 131 | + assert resp.status == 404 | ||
| 132 | |||
| 133 | |||
| 134 | async def test_for_issue_5250( | ||
diff --git a/meta-python/recipes-devtools/python/python3-aiohttp_3.12.15.bb b/meta-python/recipes-devtools/python/python3-aiohttp_3.12.15.bb index 9a45eecb8c..16429c9d86 100644 --- a/meta-python/recipes-devtools/python/python3-aiohttp_3.12.15.bb +++ b/meta-python/recipes-devtools/python/python3-aiohttp_3.12.15.bb | |||
| @@ -6,6 +6,7 @@ LIC_FILES_CHKSUM = "file://LICENSE.txt;md5=748073912af33aa59430d3702aa32d41" | |||
| 6 | 6 | ||
| 7 | SRC_URI += "file://CVE-2025-69224.patch \ | 7 | SRC_URI += "file://CVE-2025-69224.patch \ |
| 8 | file://CVE-2025-69225.patch \ | 8 | file://CVE-2025-69225.patch \ |
| 9 | file://CVE-2025-69226.patch \ | ||
| 9 | " | 10 | " |
| 10 | SRC_URI[sha256sum] = "4fc61385e9c98d72fcdf47e6dd81833f47b2f77c114c29cd64a361be57a763a2" | 11 | SRC_URI[sha256sum] = "4fc61385e9c98d72fcdf47e6dd81833f47b2f77c114c29cd64a361be57a763a2" |
| 11 | 12 | ||
