diff --git a/CVE-2024-34069-only-require-trusted-host-for-evalex.patch b/CVE-2024-34069-only-require-trusted-host-for-evalex.patch deleted file mode 100644 index 62170a291ee1bc2c1288cfba55cc27084c386e5e..0000000000000000000000000000000000000000 --- a/CVE-2024-34069-only-require-trusted-host-for-evalex.patch +++ /dev/null @@ -1,119 +0,0 @@ -From 890b6b62634fa61224222aee31081c61b054ff01 Mon Sep 17 00:00:00 2001 -From: David Lord -Date: Fri, 3 May 2024 14:49:43 -0700 -Subject: [PATCH] only require trusted host for evalex - ---- - 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 e779fd9..8952342 100644 ---- a/src/werkzeug/debug/__init__.py -+++ b/src/werkzeug/debug/__init__.py -@@ -18,7 +18,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 -@@ -350,7 +352,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, - ) -@@ -378,6 +380,9 @@ 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] -+ - contexts = self.frame_contexts.get(id(frame), []) - - with ExitStack() as exit_stack: -@@ -388,6 +393,9 @@ class DebuggedApplication: - - 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 = {} -@@ -440,12 +448,18 @@ class DebuggedApplication: - return None - return (time.time() - PIN_TIME) < 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) -@@ -495,8 +509,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:" -@@ -512,8 +529,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") -@@ -525,7 +540,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 e639dcb..468f926 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.41.0 - diff --git a/CVE-2024-34069-restrict-debugger-trusted-hosts.patch b/CVE-2024-34069-restrict-debugger-trusted-hosts.patch deleted file mode 100644 index 497ba9c519119a603f86eb5f6686cc27760960ab..0000000000000000000000000000000000000000 --- a/CVE-2024-34069-restrict-debugger-trusted-hosts.patch +++ /dev/null @@ -1,144 +0,0 @@ -From 71b69dfb7df3d912e66bab87fbb1f21f83504967 Mon Sep 17 00:00:00 2001 -From: David Lord -Date: Thu, 2 May 2024 11:55:52 -0700 -Subject: [PATCH] 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. ---- - docs/debug.rst | 35 +++++++++++++++++++++++---- - src/werkzeug/debug/__init__.py | 10 ++++++++ - src/werkzeug/debug/shared/debugger.js | 4 +-- - src/werkzeug/serving.py | 3 +++ - 4 files changed, 45 insertions(+), 7 deletions(-) - -diff --git a/docs/debug.rst b/docs/debug.rst -index 25a9f0b..d842135 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 24d19bb..e779fd9 100644 ---- a/src/werkzeug/debug/__init__.py -+++ b/src/werkzeug/debug/__init__.py -@@ -296,6 +296,14 @@ class DebuggedApplication: - else: - self.pin = None - -+ self.trusted_hosts: list[str] = [".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) -> t.Optional[str]: - if not hasattr(self, "_pin"): -@@ -504,6 +512,8 @@ 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") -diff --git a/src/werkzeug/debug/shared/debugger.js b/src/werkzeug/debug/shared/debugger.js -index 2354f03..bee079f 100644 ---- a/src/werkzeug/debug/shared/debugger.js -+++ b/src/werkzeug/debug/shared/debugger.js -@@ -48,7 +48,7 @@ function initPinBox() { - btn.disabled = true; - - fetch( -- `${document.location.pathname}?__debugger__=yes&cmd=pinauth&pin=${pin}&s=${encodedSecret}` -+ `${document.location}?__debugger__=yes&cmd=pinauth&pin=${pin}&s=${encodedSecret}` - ) - .then((res) => res.json()) - .then(({auth, exhausted}) => { -@@ -79,7 +79,7 @@ function promptForPin() { - if (!EVALEX_TRUSTED) { - const encodedSecret = encodeURIComponent(SECRET); - fetch( -- `${document.location.pathname}?__debugger__=yes&cmd=printpin&s=${encodedSecret}` -+ `${document.location}?__debugger__=yes&cmd=printpin&s=${encodedSecret}` - ); - const pinPrompt = document.getElementsByClassName("pin-prompt")[0]; - fadeIn(pinPrompt); -diff --git a/src/werkzeug/serving.py b/src/werkzeug/serving.py -index 2a2e74d..19ed250 100644 ---- a/src/werkzeug/serving.py -+++ b/src/werkzeug/serving.py -@@ -1028,6 +1028,9 @@ def run_simple( - from .debug import DebuggedApplication - - application = DebuggedApplication(application, evalex=use_evalex) -+ # Allow the specified hostname to use the debugger, in addition to -+ # localhost domains. -+ application.trusted_hosts.append(hostname) - - if not is_running_from_reloader(): - fd = None --- -2.41.0 - diff --git a/Werkzeug-2.2.3.tar.gz b/Werkzeug-2.2.3.tar.gz deleted file mode 100644 index b87ab26ca991e90f9e4269a5674b712dedd66608..0000000000000000000000000000000000000000 Binary files a/Werkzeug-2.2.3.tar.gz and /dev/null differ diff --git a/preserve-any-existing-PYTHONPATH-in-tests.patch b/preserve-any-existing-PYTHONPATH-in-tests.patch new file mode 100644 index 0000000000000000000000000000000000000000..f70e6fcc9b724caa4d1575c4641ec8f2e61fa7b7 --- /dev/null +++ b/preserve-any-existing-PYTHONPATH-in-tests.patch @@ -0,0 +1,34 @@ +From b88042cfb32866a00d39b678bb224eb55ecf53c1 Mon Sep 17 00:00:00 2001 +From: Lumir Balhar +Date: Tue, 22 Jun 2021 22:10:17 +0200 +Subject: [PATCH] Preserve any existing PYTHONPATH in tests + +--- + tests/conftest.py | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +diff --git a/tests/conftest.py b/tests/conftest.py +index 4ad1ff23..7200d286 100644 +--- a/tests/conftest.py ++++ b/tests/conftest.py +@@ -118,9 +118,15 @@ def dev_server(xprocess, request, tmp_path): + class Starter(ProcessStarter): + args = [sys.executable, run_path, name, json.dumps(kwargs)] + # Extend the existing env, otherwise Windows and CI fails. +- # Modules will be imported from tmp_path for the reloader. ++ # Modules will be imported from tmp_path for the reloader ++ # but any existing PYTHONPATH is preserved. + # Unbuffered output so the logs update immediately. +- env = {**os.environ, "PYTHONPATH": str(tmp_path), "PYTHONUNBUFFERED": "1"} ++ original_python_path = os.getenv("PYTHONPATH") ++ if original_python_path: ++ new_python_path = os.pathsep.join((original_python_path, str(tmp_path))) ++ else: ++ new_python_path = str(tmp_path) ++ env = {**os.environ, "PYTHONPATH": new_python_path, "PYTHONUNBUFFERED": "1"} + + @cached_property + def pattern(self): +-- +2.31.1 + diff --git a/python-werkzeug.spec b/python-werkzeug.spec index 56a37b9169aff7a75e5cec2134d82504f314d363..a5a6513bb12a092431e8349621acdc6fc6cc5904 100644 --- a/python-werkzeug.spec +++ b/python-werkzeug.spec @@ -1,29 +1,24 @@ %global _empty_manifest_terminate_build 0 +%global pypi_name werkzeug + Name: python-werkzeug -Version: 2.2.3 -Release: 2 +Version: 3.0.6 +Release: 1 Summary: The comprehensive WSGI web application library. License: BSD-3-Clause -URL: https://palletsprojects.com/p/werkzeug/ -Source0: https://files.pythonhosted.org/packages/source/W/Werkzeug/Werkzeug-2.2.3.tar.gz -# for test -Source1: https://github.com/Yelp/ephemeral-port-reserve/blob/master/ephemeral_port_reserve.py - -Patch01: CVE-2024-34069-restrict-debugger-trusted-hosts.patch -Patch02: CVE-2024-34069-only-require-trusted-host-for-evalex.patch - -BuildArch: noarch -BuildRequires: python3-werkzeug python3-markupsafe - -Requires: python3-pytest -Requires: python3-pytest-xprocess -Requires: python3-pytest-timeout -Requires: python3-coverage -Requires: python3-tox -Requires: python3-sphinx -Requires: python3-pallets-sphinx-themes -Requires: python3-sphinx-issues -Requires: python3-watchdog +URL: https://github.com/pallets/werkzeug +Source0: %{url}/archive/%{version}/%{pypi_name}-%{version}.tar.gz +Patch0: preserve-any-existing-PYTHONPATH-in-tests.patch + +BuildArch: noarch +BuildRequires: python3-devel +BuildRequires: python3-setuptools +BuildRequires: python3-pip +BuildRequires: python3-wheel +BuildRequires: python3-hatchling +BuildRequires: python3-flit-core +BuildRequires: python3-markupsafe +BuildRequires: python3-ephemeral-port-reserve %description *werkzeug* German noun: "tool". Etymology: *werk* ("work"), *zeug* ("stuff") @@ -62,10 +57,20 @@ BuildRequires: python3-pytest BuildRequires: python3-pytest-xprocess BuildRequires: python3-pytest-timeout BuildRequires: python3-requests -BuildRequires: python3-devel BuildRequires: python3-cryptography BuildRequires: python3-greenlet -BuildRequires: python3-setuptools +BuildRequires: python3-watchdog +BuildRequires: python3-time-machine +BuildRequires: python3-pytest-mock +BuildRequires: python3-pytest-cov +BuildRequires: python3-pytest-rerunfailures +BuildRequires: python3-pytest-flake8 +BuildRequires: python3-hypothesis +BuildRequires: python3-pytest-xdist +BuildRequires: python3-pytest-datadir +BuildRequires: python3-pytest-asyncio +BuildRequires: python3-anyio +BuildRequires: python3-pytest-trio %description -n python3-werkzeug *werkzeug* German noun: "tool". Etymology: *werk* ("work"), *zeug* ("stuff") Werkzeug is a comprehensive `WSGI`_ web application library. It began as @@ -130,50 +135,48 @@ providing more structure and patterns for defining powerful applications. %prep -%autosetup -n Werkzeug-%{version} -p1 -cp %{SOURCE1} %{_builddir}/Werkzeug-%{version}/tests/ +%autosetup -n werkzeug-%{version} -p1 %build -%py3_build +%pyproject_build %install -%py3_install +%pyproject_install install -d -m755 %{buildroot}/%{_pkgdocdir} if [ -d doc ]; then cp -arf doc %{buildroot}/%{_pkgdocdir}; fi if [ -d docs ]; then cp -arf docs %{buildroot}/%{_pkgdocdir}; fi if [ -d example ]; then cp -arf example %{buildroot}/%{_pkgdocdir}; fi if [ -d examples ]; then cp -arf examples %{buildroot}/%{_pkgdocdir}; fi pushd %{buildroot} -if [ -d usr/lib ]; then - find usr/lib -type f -printf "/%h/%f\n" >> filelist.lst -fi -if [ -d usr/lib64 ]; then - find usr/lib64 -type f -printf "/%h/%f\n" >> filelist.lst -fi -if [ -d usr/bin ]; then - find usr/bin -type f -printf "/%h/%f\n" >> filelist.lst -fi -if [ -d usr/sbin ]; then - find usr/sbin -type f -printf "/%h/%f\n" >> filelist.lst -fi touch doclist.lst if [ -d usr/share/man ]; then find usr/share/man -type f -printf "/%h/%f.gz\n" >> doclist.lst fi popd -mv %{buildroot}/filelist.lst . mv %{buildroot}/doclist.lst . %check PYTHONPATH=%{buildroot}%{python3_sitelib} pytest -k 'not (test_serving)' -%files -n python3-werkzeug -f filelist.lst -%dir %{python3_sitelib}/* +%files -n python3-werkzeug +%license LICENSE.txt +%doc README.md CHANGES.rst +%{python3_sitelib}/werkzeug +%{python3_sitelib}/werkzeug-*.dist-info/ %files help -f doclist.lst %{_docdir}/* %changelog +* Thu Oct 31 2024 Dongxing Wang - 3.0.6-1 +- Update package to version 3.0.6 + Fix how max_form_memory_size is applied when parsing large non-file fields. + The Watchdog reloader ignores file closed no write events. + Logging works with client addresses containing an IPv6 scope. + Ignore invalid authorization parameters. + Improve type annotation fore SharedDataMiddleware. + Make reloader more robust when "" is in sys.path. + * Tue May 07 2024 yinyongkang - 2.2.3-2 - fix CVE-2024-34069 diff --git a/werkzeug-3.0.6.tar.gz b/werkzeug-3.0.6.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..5013b259c42e0f9e9d5bfa59d8ecb6d1dd45f5b2 Binary files /dev/null and b/werkzeug-3.0.6.tar.gz differ