summaryrefslogtreecommitdiffstats
path: root/meta-python/recipes-devtools/python
diff options
context:
space:
mode:
authorGyorgy Sarvari <skandigraun@gmail.com>2026-02-04 17:29:18 +0100
committerAnuj Mittal <anuj.mittal@oss.qualcomm.com>2026-02-05 06:59:40 +0530
commit4ac10b5dbb564b6032ebfea1ec845809acc8b91a (patch)
treea60d21025cc126d5c530c599547ea90637c11c06 /meta-python/recipes-devtools/python
parent0b467f2380024891a9689080bf2ddb7a14171da0 (diff)
downloadmeta-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.patch134
-rw-r--r--meta-python/recipes-devtools/python/python3-aiohttp_3.12.15.bb1
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 @@
1From b330573c65db35ee1228615ec257619b49b918c7 Mon Sep 17 00:00:00 2001
2From: Gyorgy Sarvari <skandigraun@gmail.com>
3Date: Sat, 3 Jan 2026 01:55:05 +0000
4Subject: [PATCH] Reject static URLs that traverse outside static root (#11888)
5 (#11906)
6
7From: Sam Bull <git@sambull.org>
8
9(cherry picked from commit 63961fa77fa2443109f25c3d8ab94772d3878626)
10
11Co-authored-by: J. Nick Koston <nick@koston.org>
12
13CVE: CVE-2025-69226
14Upstream-Status: Backport [https://github.com/aio-libs/aiohttp/commit/f2a86fd5ac0383000d1715afddfa704413f0711e]
15Signed-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
23diff --git a/aiohttp/web_urldispatcher.py b/aiohttp/web_urldispatcher.py
24index 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(
73diff --git a/tests/test_urldispatch.py b/tests/test_urldispatch.py
74index 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)
107diff --git a/tests/test_web_sendfile_functional.py b/tests/test_web_sendfile_functional.py
108index 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()
120diff --git a/tests/test_web_urldispatcher.py b/tests/test_web_urldispatcher.py
121index 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
7SRC_URI += "file://CVE-2025-69224.patch \ 7SRC_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"
10SRC_URI[sha256sum] = "4fc61385e9c98d72fcdf47e6dd81833f47b2f77c114c29cd64a361be57a763a2" 11SRC_URI[sha256sum] = "4fc61385e9c98d72fcdf47e6dd81833f47b2f77c114c29cd64a361be57a763a2"
11 12