mirror of
https://github.com/openembedded/meta-openembedded.git
synced 2026-02-01 10:00:15 +00:00
Werkzeug is a comprehensive WSGI web application library. The debugger in affected versions of Werkzeug can allow an attacker to execute code on a developer's machine under some circumstances. This requires the attacker to get the developer to interact with a domain and subdomain they control, and enter the debugger PIN, but if they are successful it allows access to the debugger even if it is only running on localhost. This also requires the attacker to guess a URL in the developer's application that will trigger the debugger. This vulnerability is fixed in 3.0.3. Reference: https://nvd.nist.gov/vuln/detail/CVE-2024-34069 Upstream-patches:71b69dfb7d890b6b6263Signed-off-by: Soumya Sambu <soumya.sambu@windriver.com> Signed-off-by: Armin Kuster <akuster808@gmail.com>
121 lines
4.7 KiB
Diff
121 lines
4.7 KiB
Diff
From 890b6b62634fa61224222aee31081c61b054ff01 Mon Sep 17 00:00:00 2001
|
|
From: David Lord <davidism@gmail.com>
|
|
Date: Fri, 3 May 2024 14:49:43 -0700
|
|
Subject: [PATCH] only require trusted host for evalex
|
|
|
|
CVE: CVE-2024-34069
|
|
|
|
Upstream-Status: Backport [https://github.com/pallets/werkzeug/commit/890b6b62634fa61224222aee31081c61b054ff01]
|
|
|
|
Signed-off-by: Soumya Sambu <soumya.sambu@windriver.com>
|
|
---
|
|
src/werkzeug/debug/__init__.py | 25 ++++++++++++++++++++-----
|
|
src/werkzeug/sansio/utils.py | 2 +-
|
|
2 files changed, 21 insertions(+), 6 deletions(-)
|
|
|
|
diff --git a/src/werkzeug/debug/__init__.py b/src/werkzeug/debug/__init__.py
|
|
index 87e68c4..0302b24 100644
|
|
--- a/src/werkzeug/debug/__init__.py
|
|
+++ b/src/werkzeug/debug/__init__.py
|
|
@@ -16,7 +16,9 @@ from zlib import adler32
|
|
|
|
from .._internal import _log
|
|
from ..exceptions import NotFound
|
|
+from ..exceptions import SecurityError
|
|
from ..http import parse_cookie
|
|
+from ..sansio.utils import host_is_trusted
|
|
from ..security import gen_salt
|
|
from ..utils import send_file
|
|
from ..wrappers.request import Request
|
|
@@ -331,7 +333,7 @@ class DebuggedApplication:
|
|
|
|
is_trusted = bool(self.check_pin_trust(environ))
|
|
html = tb.render_debugger_html(
|
|
- evalex=self.evalex,
|
|
+ evalex=self.evalex and self.check_host_trust(environ),
|
|
secret=self.secret,
|
|
evalex_trusted=is_trusted,
|
|
)
|
|
@@ -359,10 +361,16 @@ class DebuggedApplication:
|
|
frame: t.Union[DebugFrameSummary, _ConsoleFrame],
|
|
) -> Response:
|
|
"""Execute a command in a console."""
|
|
+ if not self.check_host_trust(request.environ):
|
|
+ return SecurityError() # type: ignore[return-value]
|
|
+
|
|
return Response(frame.eval(command), mimetype="text/html")
|
|
|
|
def display_console(self, request: Request) -> Response:
|
|
"""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 = {}
|
|
@@ -411,12 +419,18 @@ class DebuggedApplication:
|
|
return None
|
|
return (time.time() - PIN_TIME) < int(ts)
|
|
|
|
+ def check_host_trust(self, environ: WSGIEnvironment) -> bool:
|
|
+ return host_is_trusted(environ.get("HTTP_HOST"), self.trusted_hosts)
|
|
+
|
|
def _fail_pin_auth(self) -> None:
|
|
time.sleep(5.0 if self._failed_pin_auth > 5 else 0.5)
|
|
self._failed_pin_auth += 1
|
|
|
|
def pin_auth(self, request: Request) -> Response:
|
|
"""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)
|
|
@@ -466,8 +480,11 @@ class DebuggedApplication:
|
|
rv.delete_cookie(self.pin_cookie_name)
|
|
return rv
|
|
|
|
- def log_pin_request(self) -> Response:
|
|
+ def log_pin_request(self, request: Request) -> Response:
|
|
"""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:"
|
|
@@ -483,8 +500,6 @@ class DebuggedApplication:
|
|
# 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")
|
|
@@ -496,7 +511,7 @@ class DebuggedApplication:
|
|
elif cmd == "pinauth" and secret == self.secret:
|
|
response = self.pin_auth(request) # type: ignore
|
|
elif cmd == "printpin" and secret == self.secret:
|
|
- response = self.log_pin_request() # type: ignore
|
|
+ response = self.log_pin_request(request) # type: ignore
|
|
elif (
|
|
self.evalex
|
|
and cmd is not None
|
|
diff --git a/src/werkzeug/sansio/utils.py b/src/werkzeug/sansio/utils.py
|
|
index 1b4d892..7e7b4d2 100644
|
|
--- a/src/werkzeug/sansio/utils.py
|
|
+++ b/src/werkzeug/sansio/utils.py
|
|
@@ -6,7 +6,7 @@ from ..urls import uri_to_iri
|
|
from ..urls import url_quote
|
|
|
|
|
|
-def host_is_trusted(hostname: str, trusted_list: t.Iterable[str]) -> bool:
|
|
+def host_is_trusted(hostname: str | None, trusted_list: t.Iterable[str]) -> bool:
|
|
"""Check if a host matches a list of trusted names.
|
|
|
|
:param hostname: The name to check.
|
|
--
|
|
2.40.0
|