diff options
Diffstat (limited to 'meta-python/recipes-devtools/python')
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 @@ | |||
| 1 | From 71b69dfb7df3d912e66bab87fbb1f21f83504967 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: David Lord <davidism@gmail.com> | ||
| 3 | Date: Thu, 2 May 2024 11:55:52 -0700 | ||
| 4 | Subject: [PATCH] restrict debugger trusted hosts | ||
| 5 | |||
| 6 | 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. | ||
| 7 | |||
| 8 | The debugger UI uses the full `document.location` instead of only `document.location.pathname`. | ||
| 9 | |||
| 10 | Either of these fixes on their own mitigates the reported vulnerability. | ||
| 11 | |||
| 12 | CVE: CVE-2024-34069 | ||
| 13 | |||
| 14 | Upstream-Status: Backport [https://github.com/pallets/werkzeug/commit/71b69dfb7df3d912e66bab87fbb1f21f83504967] | ||
| 15 | |||
| 16 | Signed-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 | |||
| 24 | diff --git a/docs/debug.rst b/docs/debug.rst | ||
| 25 | index 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 | |||
| 84 | diff --git a/src/werkzeug/debug/__init__.py b/src/werkzeug/debug/__init__.py | ||
| 85 | index 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") | ||
| 112 | diff --git a/src/werkzeug/debug/shared/debugger.js b/src/werkzeug/debug/shared/debugger.js | ||
| 113 | index 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); | ||
| 134 | diff --git a/src/werkzeug/serving.py b/src/werkzeug/serving.py | ||
| 135 | index 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 | -- | ||
| 149 | 2.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 @@ | |||
| 1 | From 890b6b62634fa61224222aee31081c61b054ff01 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: David Lord <davidism@gmail.com> | ||
| 3 | Date: Fri, 3 May 2024 14:49:43 -0700 | ||
| 4 | Subject: [PATCH] only require trusted host for evalex | ||
| 5 | |||
| 6 | CVE: CVE-2024-34069 | ||
| 7 | |||
| 8 | Upstream-Status: Backport [https://github.com/pallets/werkzeug/commit/890b6b62634fa61224222aee31081c61b054ff01] | ||
| 9 | |||
| 10 | Signed-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 | |||
| 16 | diff --git a/src/werkzeug/debug/__init__.py b/src/werkzeug/debug/__init__.py | ||
| 17 | index 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 | ||
| 106 | diff --git a/src/werkzeug/sansio/utils.py b/src/werkzeug/sansio/utils.py | ||
| 107 | index 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 | -- | ||
| 120 | 2.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" | |||
| 13 | PYPI_PACKAGE = "Werkzeug" | 13 | PYPI_PACKAGE = "Werkzeug" |
| 14 | 14 | ||
| 15 | SRC_URI += "file://CVE-2023-25577.patch \ | 15 | SRC_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 | ||
| 18 | SRC_URI[sha256sum] = "f8e89a20aeabbe8a893c24a461d3ee5dad2123b05cc6abd73ceed01d39c3ae74" | 20 | SRC_URI[sha256sum] = "f8e89a20aeabbe8a893c24a461d3ee5dad2123b05cc6abd73ceed01d39c3ae74" |
| 19 | 21 | ||
