diff --git a/python-django-5.2.7-CVE-2025-64458.patch b/python-django-5.2.7-CVE-2025-64458.patch new file mode 100644 index 0000000000000000000000000000000000000000..959918525573c17221efbb518bbc86cbe4dfeb3d --- /dev/null +++ b/python-django-5.2.7-CVE-2025-64458.patch @@ -0,0 +1,65 @@ +From 4f5d904b63751dea9ffc3b0e046404a7fa5881ac Mon Sep 17 00:00:00 2001 +From: Jacob Walls +Date: Thu, 16 Oct 2025 16:28:33 -0400 +Subject: [PATCH] [5.2.x] Fixed CVE-2025-64458 -- Mitigated potential DoS in + HttpResponseRedirect/HttpResponsePermanentRedirect on Windows. + +Thanks Seokchan Yoon for the report, Markus Holtermann for the +triage, and Jake Howard for the review. + +Follow-up to CVE-2025-27556 and 39e2297210d9d2938c75fc911d45f0e863dc4821. + +Backport of c880530ddd4fabd5939bab0e148bebe36699432a from main. +--- + django/http/response.py | 9 +++++++-- + tests/httpwrappers/tests.py | 2 ++ + 5 files changed, 37 insertions(+), 4 deletions(-) + +diff --git a/django/http/response.py b/django/http/response.py +index 4a0ea6701375..9f4bd6af9075 100644 +--- a/django/http/response.py ++++ b/django/http/response.py +@@ -22,7 +22,7 @@ + from django.utils.datastructures import CaseInsensitiveMapping + from django.utils.encoding import iri_to_uri + from django.utils.functional import cached_property +-from django.utils.http import content_disposition_header, http_date ++from django.utils.http import MAX_URL_LENGTH, content_disposition_header, http_date + from django.utils.regex_helper import _lazy_re_compile + + _charset_from_content_type_re = _lazy_re_compile( +@@ -630,7 +630,12 @@ class HttpResponseRedirectBase(HttpResponse): + def __init__(self, redirect_to, preserve_request=False, *args, **kwargs): + super().__init__(*args, **kwargs) + self["Location"] = iri_to_uri(redirect_to) +- parsed = urlsplit(str(redirect_to)) ++ redirect_to_str = str(redirect_to) ++ if len(redirect_to_str) > MAX_URL_LENGTH: ++ raise DisallowedRedirect( ++ f"Unsafe redirect exceeding {MAX_URL_LENGTH} characters" ++ ) ++ parsed = urlsplit(redirect_to_str) + if preserve_request: + self.status_code = self.status_code_preserve_request + if parsed.scheme and parsed.scheme not in self.allowed_schemes: + +diff --git a/tests/httpwrappers/tests.py b/tests/httpwrappers/tests.py +index f85d33e82338..f62a9d9bba39 100644 +--- a/tests/httpwrappers/tests.py ++++ b/tests/httpwrappers/tests.py +@@ -24,6 +24,7 @@ + ) + from django.test import SimpleTestCase + from django.utils.functional import lazystr ++from django.utils.http import MAX_URL_LENGTH + + + class QueryDictTests(SimpleTestCase): +@@ -490,6 +491,7 @@ def test_unsafe_redirect(self): + 'data:text/html,', + "mailto:test@example.com", + "file:///etc/passwd", ++ "é" * (MAX_URL_LENGTH + 1), + ] + for url in bad_urls: + with self.assertRaises(DisallowedRedirect): diff --git a/python-django-5.2.7-CVE-2025-64459.patch b/python-django-5.2.7-CVE-2025-64459.patch new file mode 100644 index 0000000000000000000000000000000000000000..719f7acd1fe3d5793fbb135615ebda2f00f3ba32 --- /dev/null +++ b/python-django-5.2.7-CVE-2025-64459.patch @@ -0,0 +1,49 @@ +From 6703f364d767e949c5b0e4016433ef75063b4f9b Mon Sep 17 00:00:00 2001 +From: Jacob Walls +Date: Wed, 24 Sep 2025 15:54:51 -0400 +Subject: [PATCH] [5.2.x] Fixed CVE-2025-64459 -- Prevented SQL injections in + Q/QuerySet via the _connector kwarg. + +Thanks cyberstan for the report, Sarah Boyce, Adam Johnson, Simon +Charette, and Jake Howard for the reviews. + +Backport of c880530ddd4fabd5939bab0e148bebe36699432a from main. +--- + django/db/models/query_utils.py | 4 ++++ + tests/queries/test_q.py | 5 +++++ + 5 files changed, 30 insertions(+) + +diff --git a/django/db/models/query_utils.py b/django/db/models/query_utils.py +index d219c5fb0e1b..9d237cdc7760 100644 +--- a/django/db/models/query_utils.py ++++ b/django/db/models/query_utils.py +@@ -48,8 +48,12 @@ class Q(tree.Node): + XOR = "XOR" + default = AND + conditional = True ++ connectors = (None, AND, OR, XOR) + + def __init__(self, *args, _connector=None, _negated=False, **kwargs): ++ if _connector not in self.connectors: ++ connector_reprs = ", ".join(f"{conn!r}" for conn in self.connectors[1:]) ++ raise ValueError(f"_connector must be one of {connector_reprs}, or None.") + super().__init__( + children=[*args, *sorted(kwargs.items())], + connector=_connector, + +diff --git a/tests/queries/test_q.py b/tests/queries/test_q.py +index 1a62aca06114..52200b2ecff1 100644 +--- a/tests/queries/test_q.py ++++ b/tests/queries/test_q.py +@@ -272,6 +272,11 @@ def test_create_helper(self): + Q(*items, _connector=connector), + ) + ++ def test_connector_validation(self): ++ msg = f"_connector must be one of {Q.AND!r}, {Q.OR!r}, {Q.XOR!r}, or None." ++ with self.assertRaisesMessage(ValueError, msg): ++ Q(_connector="evil") ++ + def test_referenced_base_fields(self): + # Make sure Q.referenced_base_fields retrieves all base fields from + # both filters and F expressions. diff --git a/python-django.spec b/python-django.spec index d5dee087510a86e93049c0bcb2e722726a1c1847..a507655fe6fec27e06742804dc71292cf3be4c82 100644 --- a/python-django.spec +++ b/python-django.spec @@ -4,13 +4,16 @@ Summary: A high-level Python Web framework Name: python-django Version: 5.2.7 -Release: 1%{?dist} +Release: 2%{?dist} License: BSD URL: https://www.djangoproject.com/ Source0: https://github.com/django/django/archive/refs/tags/django-%{version}.tar.gz %define pyproject_build /usr/bin/python3 -mpip wheel --verbose --progress-bar off --disable-pip-version-check --use-pep517 --no-build-isolation --no-deps --wheel-dir ./pyproject-wheeldir . +Patch001: python-django-5.2.7-CVE-2025-64458.patch +Patch002: python-django-5.2.7-CVE-2025-64459.patch + BuildArch: noarch @@ -123,6 +126,10 @@ python3 runtests.py --settings=test_sqlite --verbosity=2 --parallel 1 %changelog +* Mon Nov 10 2025 Shop You - 5.2.7-2 +- [Type] security +- [DESC] Fix CVE-2025-64458 and CVE-2025-64459 + * Thu Oct 9 2025 bbrucezhang - 5.2.7-1 - [Type] security - [DESC] Update to 5.2.7 for fix CVE-2025-57833 and CVE-2024-56374