From 791ab69a71e5c4d38be59750df15972ba2ef0461 Mon Sep 17 00:00:00 2001 From: starlet-dx <15929766099@163.com> Date: Wed, 30 Jul 2025 14:36:43 +0800 Subject: [PATCH] Fix CVE-2024-34069 --- CVE-2024-34069-1.patch | 143 +++++++++++++++++++++++++++++++++++++++++ CVE-2024-34069-2.patch | 99 ++++++++++++++++++++++++++++ python-werkzeug.spec | 7 +- 3 files changed, 248 insertions(+), 1 deletion(-) create mode 100644 CVE-2024-34069-1.patch create mode 100644 CVE-2024-34069-2.patch diff --git a/CVE-2024-34069-1.patch b/CVE-2024-34069-1.patch new file mode 100644 index 0000000..6824c8f --- /dev/null +++ b/CVE-2024-34069-1.patch @@ -0,0 +1,143 @@ +From: David Lord +Date: Thu, 2 May 2024 11:55:52 -0700 +Subject: restrict debugger trusted hosts + +Add 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. + +The debugger UI uses the full `document.location` instead of only `document.location.pathname`. + +Either of these fixes on their own mitigates the reported vulnerability. + +(cherry picked from commit 71b69dfb7df3d912e66bab87fbb1f21f83504967) +--- + docs/debug.rst | 35 ++++++++++++++++++++++++++++++----- + src/werkzeug/debug/__init__.py | 10 ++++++++++ + src/werkzeug/debug/shared/debugger.js | 4 ++-- + src/werkzeug/serving.py | 4 ++++ + 4 files changed, 46 insertions(+), 7 deletions(-) + +diff --git a/docs/debug.rst b/docs/debug.rst +index c553f99..a4dadac 100644 +--- a/docs/debug.rst ++++ b/docs/debug.rst +@@ -16,7 +16,8 @@ interactive debug console to execute code in any frame. + The debugger allows the execution of arbitrary code which makes it a + major security risk. **The debugger must never be used on production + machines. We cannot stress this enough. Do not enable the debugger +- in production.** ++ in production.** Production means anything that is not development, ++ and anything that is publicly accessible. + + .. note:: + +@@ -72,10 +73,9 @@ argument to get a detailed list of all the attributes it has. + Debugger PIN + ------------ + +-Starting with Werkzeug 0.11 the debug console is protected by a PIN. +-This is a security helper to make it less likely for the debugger to be +-exploited if you forget to disable it when deploying to production. The +-PIN based authentication is enabled by default. ++The debug console is protected by a PIN. This is a security helper to make it ++less likely for the debugger to be exploited if you forget to disable it when ++deploying to production. The PIN based authentication is enabled by default. + + The first time a console is opened, a dialog will prompt for a PIN that + is printed to the command line. The PIN is generated in a stable way +@@ -92,6 +92,31 @@ intended to make it harder for an attacker to exploit the debugger. + Never enable the debugger in production.** + + ++Allowed Hosts ++------------- ++ ++The debug console will only be served if the request comes from a trusted host. ++If a request comes from a browser page that is not served on a trusted URL, a ++400 error will be returned. ++ ++By default, ``localhost``, any ``.localhost`` subdomain, and ``127.0.0.1`` are ++trusted. ``run_simple`` will trust its ``hostname`` argument as well. To change ++this further, use the debug middleware directly rather than through ++``use_debugger=True``. ++ ++.. code-block:: python ++ ++ if os.environ.get("USE_DEBUGGER") in {"1", "true"}: ++ app = DebuggedApplication(app, evalex=True) ++ app.trusted_hosts = [...] ++ ++ run_simple("localhost", 8080, app) ++ ++**This feature is not meant to entirely secure the debugger. It is ++intended to make it harder for an attacker to exploit the debugger. ++Never enable the debugger in production.** ++ ++ + Pasting Errors + -------------- + +diff --git a/src/werkzeug/debug/__init__.py b/src/werkzeug/debug/__init__.py +index f9f6e85..fee67a0 100644 +--- a/src/werkzeug/debug/__init__.py ++++ b/src/werkzeug/debug/__init__.py +@@ -280,6 +280,14 @@ class DebuggedApplication(object): + else: + self.pin = None + ++ self.trusted_hosts = [".localhost", "127.0.0.1"] ++ """List of domains to allow requests to the debugger from. A leading dot ++ allows all subdomains. This only allows ``".localhost"`` domains by ++ default. ++ ++ .. versionadded:: 3.0.3 ++ """ ++ + @property + def pin(self): + if not hasattr(self, "_pin"): +@@ -466,6 +474,8 @@ class DebuggedApplication(object): + # form data! Otherwise the application won't have access to that data + # any more! + request = Request(environ) ++ request.trusted_hosts = self.trusted_hosts ++ assert request.host # will raise 400 error if not trusted + response = self.debug_application + if request.args.get("__debugger__") == "yes": + cmd = request.args.get("cmd") +diff --git a/src/werkzeug/debug/shared/debugger.js b/src/werkzeug/debug/shared/debugger.js +index ba267ed..0769dd7 100644 +--- a/src/werkzeug/debug/shared/debugger.js ++++ b/src/werkzeug/debug/shared/debugger.js +@@ -104,7 +104,7 @@ function initPinBox() { + btn.disabled = true; + $.ajax({ + dataType: 'json', +- url: document.location.pathname, ++ url: document.location, + data: {__debugger__: 'yes', cmd: 'pinauth', pin: pin, + s: SECRET}, + success: function(data) { +@@ -132,7 +132,7 @@ function initPinBox() { + function promptForPin() { + if (!EVALEX_TRUSTED) { + $.ajax({ +- url: document.location.pathname, ++ url: document.location, + data: {__debugger__: 'yes', cmd: 'printpin', s: SECRET} + }); + $('.pin-prompt').fadeIn(function() { +diff --git a/src/werkzeug/serving.py b/src/werkzeug/serving.py +index f2a0dc9..4c10ce9 100644 +--- a/src/werkzeug/serving.py ++++ b/src/werkzeug/serving.py +@@ -965,6 +965,10 @@ def run_simple( + from .debug import DebuggedApplication + + application = DebuggedApplication(application, use_evalex) ++ # Allow the specified hostname to use the debugger, in addition to ++ # localhost domains. ++ application.trusted_hosts.append(hostname) ++ + if static_files: + from .middleware.shared_data import SharedDataMiddleware + diff --git a/CVE-2024-34069-2.patch b/CVE-2024-34069-2.patch new file mode 100644 index 0000000..627fab8 --- /dev/null +++ b/CVE-2024-34069-2.patch @@ -0,0 +1,99 @@ +From: David Lord +Date: Fri, 3 May 2024 14:49:43 -0700 +Subject: only require trusted host for evalex + +(cherry picked from commit 890b6b62634fa61224222aee31081c61b054ff01) +--- + src/werkzeug/debug/__init__.py | 26 +++++++++++++++++++++----- + 1 file changed, 21 insertions(+), 5 deletions(-) + +diff --git a/src/werkzeug/debug/__init__.py b/src/werkzeug/debug/__init__.py +index fee67a0..f274207 100644 +--- a/src/werkzeug/debug/__init__.py ++++ b/src/werkzeug/debug/__init__.py +@@ -24,7 +24,9 @@ from os.path import join + + from .._compat import text_type + from .._internal import _log ++from ..exceptions import SecurityError + from ..http import parse_cookie ++from ..wsgi import host_is_trusted + from ..security import gen_salt + from ..wrappers import BaseRequest as Request + from ..wrappers import BaseResponse as Response +@@ -349,17 +351,24 @@ class DebuggedApplication(object): + else: + is_trusted = bool(self.check_pin_trust(environ)) + yield traceback.render_full( +- evalex=self.evalex, evalex_trusted=is_trusted, secret=self.secret ++ evalex=self.evalex and self.check_host_trust(environ), ++ evalex_trusted=is_trusted, secret=self.secret + ).encode("utf-8", "replace") + + traceback.log(environ["wsgi.errors"]) + + def execute_command(self, request, command, frame): + """Execute a command in a console.""" ++ if not self.check_host_trust(request.environ): ++ return SecurityError() ++ + return Response(frame.console.eval(command), mimetype="text/html") + + def display_console(self, request): + """Display a standalone shell.""" ++ if not self.check_host_trust(request.environ): ++ return SecurityError() # type: ignore[return-value] ++ + if 0 not in self.frames: + if self.console_init_func is None: + ns = {} +@@ -408,12 +417,18 @@ class DebuggedApplication(object): + return None + return (time.time() - PIN_TIME) < int(ts) + ++ def check_host_trust(self, environ): ++ return host_is_trusted(environ.get("HTTP_HOST"), self.trusted_hosts) ++ + def _fail_pin_auth(self): + time.sleep(5.0 if self._failed_pin_auth > 5 else 0.5) + self._failed_pin_auth += 1 + + def pin_auth(self, request): + """Authenticates with the pin.""" ++ if not self.check_host_trust(request.environ): ++ return SecurityError() # type: ignore[return-value] ++ + exhausted = False + auth = False + trust = self.check_pin_trust(request.environ) +@@ -459,8 +474,11 @@ class DebuggedApplication(object): + rv.delete_cookie(self.pin_cookie_name) + return rv + +- def log_pin_request(self): ++ def log_pin_request(self, request): + """Log the pin if needed.""" ++ if not self.check_host_trust(request.environ): ++ return SecurityError() # type: ignore[return-value] ++ + if self.pin_logging and self.pin is not None: + _log( + "info", " * To enable the debugger you need to enter the security pin:" +@@ -474,8 +492,6 @@ class DebuggedApplication(object): + # form data! Otherwise the application won't have access to that data + # any more! + request = Request(environ) +- request.trusted_hosts = self.trusted_hosts +- assert request.host # will raise 400 error if not trusted + response = self.debug_application + if request.args.get("__debugger__") == "yes": + cmd = request.args.get("cmd") +@@ -490,7 +506,7 @@ class DebuggedApplication(object): + elif cmd == "pinauth" and secret == self.secret: + response = self.pin_auth(request) + elif cmd == "printpin" and secret == self.secret: +- response = self.log_pin_request() ++ response = self.log_pin_request(request) + elif ( + self.evalex + and cmd is not None diff --git a/python-werkzeug.spec b/python-werkzeug.spec index 4620234..2d48d13 100644 --- a/python-werkzeug.spec +++ b/python-werkzeug.spec @@ -3,13 +3,15 @@ Name: python-werkzeug Summary: A comprehensive WSGI web application library Version: 1.0.1 -Release: 2 +Release: 3 License: BSD URL: https://github.com/pallets/werkzeug Source0: https://github.com/pallets/werkzeug/archive/1.0.1.tar.gz Patch0: Disable-tests-because-need-pytest-3.9.patch Patch1: CVE-2023-23934.patch Patch2: CVE-2023-25577.patch +Patch3: CVE-2024-34069-1.patch +Patch4: CVE-2024-34069-2.patch BuildArch: noarch %global _description\ @@ -125,6 +127,9 @@ popd %changelog +* Wed Jul 30 2025 yaoxin <1024769339@qq.com> - 1.0.1-3 +- Fix CVE-2024-34069 + * Mon Aug 14 2023 yaoxin - 1.0.1-2 - Fix CVE-2023-23934 and CVE-2023-25577 -- Gitee