summaryrefslogtreecommitdiffstats
path: root/meta-python/recipes-devtools/python
diff options
context:
space:
mode:
Diffstat (limited to 'meta-python/recipes-devtools/python')
-rw-r--r--meta-python/recipes-devtools/python/python3-werkzeug/CVE-2024-34069-0001.patch149
-rw-r--r--meta-python/recipes-devtools/python/python3-werkzeug/CVE-2024-34069-0002.patch120
-rw-r--r--meta-python/recipes-devtools/python/python3-werkzeug_2.1.1.bb4
3 files changed, 272 insertions, 1 deletions
diff --git a/meta-python/recipes-devtools/python/python3-werkzeug/CVE-2024-34069-0001.patch b/meta-python/recipes-devtools/python/python3-werkzeug/CVE-2024-34069-0001.patch
new file mode 100644
index 0000000000..74b39df3a3
--- /dev/null
+++ b/meta-python/recipes-devtools/python/python3-werkzeug/CVE-2024-34069-0001.patch
@@ -0,0 +1,149 @@
1From 71b69dfb7df3d912e66bab87fbb1f21f83504967 Mon Sep 17 00:00:00 2001
2From: David Lord <davidism@gmail.com>
3Date: Thu, 2 May 2024 11:55:52 -0700
4Subject: [PATCH] restrict debugger trusted hosts
5
6Add a list of `trusted_hosts` to the `DebuggedApplication` middleware. It defaults to only allowing `localhost`, `.localhost` subdomains, and `127.0.0.1`. `run_simple(use_debugger=True)` adds its `hostname` argument to the trusted list as well. The middleware can be used directly to further modify the trusted list in less common development scenarios.
7
8The debugger UI uses the full `document.location` instead of only `document.location.pathname`.
9
10Either of these fixes on their own mitigates the reported vulnerability.
11
12CVE: CVE-2024-34069
13
14Upstream-Status: Backport [https://github.com/pallets/werkzeug/commit/71b69dfb7df3d912e66bab87fbb1f21f83504967]
15
16Signed-off-by: Soumya Sambu <soumya.sambu@windriver.com>
17---
18 docs/debug.rst | 35 +++++++++++++++++++++++----
19 src/werkzeug/debug/__init__.py | 10 ++++++++
20 src/werkzeug/debug/shared/debugger.js | 4 +--
21 src/werkzeug/serving.py | 3 +++
22 4 files changed, 45 insertions(+), 7 deletions(-)
23
24diff --git a/docs/debug.rst b/docs/debug.rst
25index 25a9f0b..d842135 100644
26--- a/docs/debug.rst
27+++ b/docs/debug.rst
28@@ -16,7 +16,8 @@ interactive debug console to execute code in any frame.
29 The debugger allows the execution of arbitrary code which makes it a
30 major security risk. **The debugger must never be used on production
31 machines. We cannot stress this enough. Do not enable the debugger
32- in production.**
33+ in production.** Production means anything that is not development,
34+ and anything that is publicly accessible.
35
36 .. note::
37
38@@ -72,10 +73,9 @@ argument to get a detailed list of all the attributes it has.
39 Debugger PIN
40 ------------
41
42-Starting with Werkzeug 0.11 the debug console is protected by a PIN.
43-This is a security helper to make it less likely for the debugger to be
44-exploited if you forget to disable it when deploying to production. The
45-PIN based authentication is enabled by default.
46+The debug console is protected by a PIN. This is a security helper to make it
47+less likely for the debugger to be exploited if you forget to disable it when
48+deploying to production. The PIN based authentication is enabled by default.
49
50 The first time a console is opened, a dialog will prompt for a PIN that
51 is printed to the command line. The PIN is generated in a stable way
52@@ -92,6 +92,31 @@ intended to make it harder for an attacker to exploit the debugger.
53 Never enable the debugger in production.**
54
55
56+Allowed Hosts
57+-------------
58+
59+The debug console will only be served if the request comes from a trusted host.
60+If a request comes from a browser page that is not served on a trusted URL, a
61+400 error will be returned.
62+
63+By default, ``localhost``, any ``.localhost`` subdomain, and ``127.0.0.1`` are
64+trusted. ``run_simple`` will trust its ``hostname`` argument as well. To change
65+this further, use the debug middleware directly rather than through
66+``use_debugger=True``.
67+
68+.. code-block:: python
69+
70+ if os.environ.get("USE_DEBUGGER") in {"1", "true"}:
71+ app = DebuggedApplication(app, evalex=True)
72+ app.trusted_hosts = [...]
73+
74+ run_simple("localhost", 8080, app)
75+
76+**This feature is not meant to entirely secure the debugger. It is
77+intended to make it harder for an attacker to exploit the debugger.
78+Never enable the debugger in production.**
79+
80+
81 Pasting Errors
82 --------------
83
84diff --git a/src/werkzeug/debug/__init__.py b/src/werkzeug/debug/__init__.py
85index 49001e0..87e68c4 100644
86--- a/src/werkzeug/debug/__init__.py
87+++ b/src/werkzeug/debug/__init__.py
88@@ -290,6 +290,14 @@ class DebuggedApplication:
89 self._pin, self._pin_cookie = pin_cookie # type: ignore
90 return self._pin
91
92+ self.trusted_hosts: list[str] = [".localhost", "127.0.0.1"]
93+ """List of domains to allow requests to the debugger from. A leading dot
94+ allows all subdomains. This only allows ``".localhost"`` domains by
95+ default.
96+
97+ .. versionadded:: 3.0.3
98+ """
99+
100 @pin.setter
101 def pin(self, value: str) -> None:
102 self._pin = value
103@@ -475,6 +483,8 @@ class DebuggedApplication:
104 # form data! Otherwise the application won't have access to that data
105 # any more!
106 request = Request(environ)
107+ request.trusted_hosts = self.trusted_hosts
108+ assert request.host # will raise 400 error if not trusted
109 response = self.debug_application
110 if request.args.get("__debugger__") == "yes":
111 cmd = request.args.get("cmd")
112diff --git a/src/werkzeug/debug/shared/debugger.js b/src/werkzeug/debug/shared/debugger.js
113index 2354f03..bee079f 100644
114--- a/src/werkzeug/debug/shared/debugger.js
115+++ b/src/werkzeug/debug/shared/debugger.js
116@@ -48,7 +48,7 @@ function initPinBox() {
117 btn.disabled = true;
118
119 fetch(
120- `${document.location.pathname}?__debugger__=yes&cmd=pinauth&pin=${pin}&s=${encodedSecret}`
121+ `${document.location}?__debugger__=yes&cmd=pinauth&pin=${pin}&s=${encodedSecret}`
122 )
123 .then((res) => res.json())
124 .then(({auth, exhausted}) => {
125@@ -79,7 +79,7 @@ function promptForPin() {
126 if (!EVALEX_TRUSTED) {
127 const encodedSecret = encodeURIComponent(SECRET);
128 fetch(
129- `${document.location.pathname}?__debugger__=yes&cmd=printpin&s=${encodedSecret}`
130+ `${document.location}?__debugger__=yes&cmd=printpin&s=${encodedSecret}`
131 );
132 const pinPrompt = document.getElementsByClassName("pin-prompt")[0];
133 fadeIn(pinPrompt);
134diff --git a/src/werkzeug/serving.py b/src/werkzeug/serving.py
135index a19d4bd..84b0664 100644
136--- a/src/werkzeug/serving.py
137+++ b/src/werkzeug/serving.py
138@@ -1038,6 +1038,9 @@ def run_simple(
139 from .debug import DebuggedApplication
140
141 application = DebuggedApplication(application, evalex=use_evalex)
142+ # Allow the specified hostname to use the debugger, in addition to
143+ # localhost domains.
144+ application.trusted_hosts.append(hostname)
145
146 if not is_running_from_reloader():
147 s = prepare_socket(hostname, port)
148--
1492.40.0
diff --git a/meta-python/recipes-devtools/python/python3-werkzeug/CVE-2024-34069-0002.patch b/meta-python/recipes-devtools/python/python3-werkzeug/CVE-2024-34069-0002.patch
new file mode 100644
index 0000000000..37d5ba47c7
--- /dev/null
+++ b/meta-python/recipes-devtools/python/python3-werkzeug/CVE-2024-34069-0002.patch
@@ -0,0 +1,120 @@
1From 890b6b62634fa61224222aee31081c61b054ff01 Mon Sep 17 00:00:00 2001
2From: David Lord <davidism@gmail.com>
3Date: Fri, 3 May 2024 14:49:43 -0700
4Subject: [PATCH] only require trusted host for evalex
5
6CVE: CVE-2024-34069
7
8Upstream-Status: Backport [https://github.com/pallets/werkzeug/commit/890b6b62634fa61224222aee31081c61b054ff01]
9
10Signed-off-by: Soumya Sambu <soumya.sambu@windriver.com>
11---
12 src/werkzeug/debug/__init__.py | 25 ++++++++++++++++++++-----
13 src/werkzeug/sansio/utils.py | 2 +-
14 2 files changed, 21 insertions(+), 6 deletions(-)
15
16diff --git a/src/werkzeug/debug/__init__.py b/src/werkzeug/debug/__init__.py
17index 87e68c4..0302b24 100644
18--- a/src/werkzeug/debug/__init__.py
19+++ b/src/werkzeug/debug/__init__.py
20@@ -16,7 +16,9 @@ from zlib import adler32
21
22 from .._internal import _log
23 from ..exceptions import NotFound
24+from ..exceptions import SecurityError
25 from ..http import parse_cookie
26+from ..sansio.utils import host_is_trusted
27 from ..security import gen_salt
28 from ..utils import send_file
29 from ..wrappers.request import Request
30@@ -331,7 +333,7 @@ class DebuggedApplication:
31
32 is_trusted = bool(self.check_pin_trust(environ))
33 html = tb.render_debugger_html(
34- evalex=self.evalex,
35+ evalex=self.evalex and self.check_host_trust(environ),
36 secret=self.secret,
37 evalex_trusted=is_trusted,
38 )
39@@ -359,10 +361,16 @@ class DebuggedApplication:
40 frame: t.Union[DebugFrameSummary, _ConsoleFrame],
41 ) -> Response:
42 """Execute a command in a console."""
43+ if not self.check_host_trust(request.environ):
44+ return SecurityError() # type: ignore[return-value]
45+
46 return Response(frame.eval(command), mimetype="text/html")
47
48 def display_console(self, request: Request) -> Response:
49 """Display a standalone shell."""
50+ if not self.check_host_trust(request.environ):
51+ return SecurityError() # type: ignore[return-value]
52+
53 if 0 not in self.frames:
54 if self.console_init_func is None:
55 ns = {}
56@@ -411,12 +419,18 @@ class DebuggedApplication:
57 return None
58 return (time.time() - PIN_TIME) < int(ts)
59
60+ def check_host_trust(self, environ: WSGIEnvironment) -> bool:
61+ return host_is_trusted(environ.get("HTTP_HOST"), self.trusted_hosts)
62+
63 def _fail_pin_auth(self) -> None:
64 time.sleep(5.0 if self._failed_pin_auth > 5 else 0.5)
65 self._failed_pin_auth += 1
66
67 def pin_auth(self, request: Request) -> Response:
68 """Authenticates with the pin."""
69+ if not self.check_host_trust(request.environ):
70+ return SecurityError() # type: ignore[return-value]
71+
72 exhausted = False
73 auth = False
74 trust = self.check_pin_trust(request.environ)
75@@ -466,8 +480,11 @@ class DebuggedApplication:
76 rv.delete_cookie(self.pin_cookie_name)
77 return rv
78
79- def log_pin_request(self) -> Response:
80+ def log_pin_request(self, request: Request) -> Response:
81 """Log the pin if needed."""
82+ if not self.check_host_trust(request.environ):
83+ return SecurityError() # type: ignore[return-value]
84+
85 if self.pin_logging and self.pin is not None:
86 _log(
87 "info", " * To enable the debugger you need to enter the security pin:"
88@@ -483,8 +500,6 @@ class DebuggedApplication:
89 # form data! Otherwise the application won't have access to that data
90 # any more!
91 request = Request(environ)
92- request.trusted_hosts = self.trusted_hosts
93- assert request.host # will raise 400 error if not trusted
94 response = self.debug_application
95 if request.args.get("__debugger__") == "yes":
96 cmd = request.args.get("cmd")
97@@ -496,7 +511,7 @@ class DebuggedApplication:
98 elif cmd == "pinauth" and secret == self.secret:
99 response = self.pin_auth(request) # type: ignore
100 elif cmd == "printpin" and secret == self.secret:
101- response = self.log_pin_request() # type: ignore
102+ response = self.log_pin_request(request) # type: ignore
103 elif (
104 self.evalex
105 and cmd is not None
106diff --git a/src/werkzeug/sansio/utils.py b/src/werkzeug/sansio/utils.py
107index 1b4d892..7e7b4d2 100644
108--- a/src/werkzeug/sansio/utils.py
109+++ b/src/werkzeug/sansio/utils.py
110@@ -6,7 +6,7 @@ from ..urls import uri_to_iri
111 from ..urls import url_quote
112
113
114-def host_is_trusted(hostname: str, trusted_list: t.Iterable[str]) -> bool:
115+def host_is_trusted(hostname: str | None, trusted_list: t.Iterable[str]) -> bool:
116 """Check if a host matches a list of trusted names.
117
118 :param hostname: The name to check.
119--
1202.40.0
diff --git a/meta-python/recipes-devtools/python/python3-werkzeug_2.1.1.bb b/meta-python/recipes-devtools/python/python3-werkzeug_2.1.1.bb
index fc0789a73e..12f6dff17d 100644
--- a/meta-python/recipes-devtools/python/python3-werkzeug_2.1.1.bb
+++ b/meta-python/recipes-devtools/python/python3-werkzeug_2.1.1.bb
@@ -13,7 +13,9 @@ LIC_FILES_CHKSUM = "file://LICENSE.rst;md5=5dc88300786f1c214c1e9827a5229462"
13PYPI_PACKAGE = "Werkzeug" 13PYPI_PACKAGE = "Werkzeug"
14 14
15SRC_URI += "file://CVE-2023-25577.patch \ 15SRC_URI += "file://CVE-2023-25577.patch \
16 file://CVE-2023-23934.patch" 16 file://CVE-2023-23934.patch \
17 file://CVE-2024-34069-0001.patch \
18 file://CVE-2024-34069-0002.patch"
17 19
18SRC_URI[sha256sum] = "f8e89a20aeabbe8a893c24a461d3ee5dad2123b05cc6abd73ceed01d39c3ae74" 20SRC_URI[sha256sum] = "f8e89a20aeabbe8a893c24a461d3ee5dad2123b05cc6abd73ceed01d39c3ae74"
19 21