diff --git a/backport-CVE-2025-27556.patch b/backport-CVE-2025-27556.patch new file mode 100644 index 0000000000000000000000000000000000000000..d7590f2ab5b1fdc5c2e18190572290c580bbf34c --- /dev/null +++ b/backport-CVE-2025-27556.patch @@ -0,0 +1,121 @@ +From edc2716d01a6fdd84b173c02031695231bcee1f8 Mon Sep 17 00:00:00 2001 +From: Sarah Boyce <42296566+sarahboyce@users.noreply.github.com> +Date: Thu, 6 Mar 2025 15:24:56 +0100 +Subject: [PATCH] [5.1.x] Fixed CVE-2025-27556 -- Mitigated potential DoS in + url_has_allowed_host_and_scheme() on Windows. + +Thank you sw0rd1ight for the report. + +Backport of 39e2297210d9d2938c75fc911d45f0e863dc4821 from main. + +Origin: https://github.com/django/django/commit/edc2716d01a6fdd84b173c02031695231bcee1f8 +--- + django/core/validators.py | 3 ++- + django/utils/html.py | 3 +-- + django/utils/http.py | 6 +++++- + tests/utils_tests/test_http.py | 16 ++++++++++++++++ + 4 files changed, 24 insertions(+), 4 deletions(-) + +diff --git a/django/core/validators.py b/django/core/validators.py +index 8732ddf..2979f3a 100644 +--- a/django/core/validators.py ++++ b/django/core/validators.py +@@ -7,6 +7,7 @@ from urllib.parse import urlsplit, urlunsplit + from django.core.exceptions import ValidationError + from django.utils.deconstruct import deconstructible + from django.utils.encoding import punycode ++from django.utils.http import MAX_URL_LENGTH + from django.utils.ipv6 import is_valid_ipv6_address + from django.utils.regex_helper import _lazy_re_compile + from django.utils.translation import gettext_lazy as _ +@@ -155,7 +156,7 @@ class URLValidator(RegexValidator): + message = _("Enter a valid URL.") + schemes = ["http", "https", "ftp", "ftps"] + unsafe_chars = frozenset("\t\r\n") +- max_length = 2048 ++ max_length = MAX_URL_LENGTH + + def __init__(self, schemes=None, **kwargs): + super().__init__(**kwargs) +diff --git a/django/utils/html.py b/django/utils/html.py +index ff8684f..8892b9a 100644 +--- a/django/utils/html.py ++++ b/django/utils/html.py +@@ -11,7 +11,7 @@ from django.core.exceptions import SuspiciousOperation + from django.utils.deprecation import RemovedInDjango60Warning + from django.utils.encoding import punycode + from django.utils.functional import Promise, cached_property, keep_lazy, keep_lazy_text +-from django.utils.http import RFC3986_GENDELIMS, RFC3986_SUBDELIMS ++from django.utils.http import MAX_URL_LENGTH, RFC3986_GENDELIMS, RFC3986_SUBDELIMS + from django.utils.regex_helper import _lazy_re_compile + from django.utils.safestring import SafeData, SafeString, mark_safe + from django.utils.text import normalize_newlines +@@ -39,7 +39,6 @@ VOID_ELEMENTS = frozenset( + ) + ) + +-MAX_URL_LENGTH = 2048 + MAX_STRIP_TAGS_DEPTH = 50 + + +diff --git a/django/utils/http.py b/django/utils/http.py +index 78dfee7..87c2ac0 100644 +--- a/django/utils/http.py ++++ b/django/utils/http.py +@@ -37,6 +37,7 @@ ASCTIME_DATE = _lazy_re_compile(r"^\w{3} %s %s %s %s$" % (__M, __D2, __T, __Y)) + + RFC3986_GENDELIMS = ":/?#[]@" + RFC3986_SUBDELIMS = "!$&'()*+,;=" ++MAX_URL_LENGTH = 2048 + + + def urlencode(query, doseq=False): +@@ -272,7 +273,10 @@ def url_has_allowed_host_and_scheme(url, allowed_hosts, require_https=False): + def _url_has_allowed_host_and_scheme(url, allowed_hosts, require_https=False): + # Chrome considers any URL with more than two slashes to be absolute, but + # urlparse is not so flexible. Treat any url with three slashes as unsafe. +- if url.startswith("///"): ++ if url.startswith("///") or len(url) > MAX_URL_LENGTH: ++ # urlparse does not perform validation of inputs. Unicode normalization ++ # is very slow on Windows and can be a DoS attack vector. ++ # https://docs.python.org/3/library/urllib.parse.html#url-parsing-security + return False + try: + url_info = urlparse(url) +diff --git a/tests/utils_tests/test_http.py b/tests/utils_tests/test_http.py +index 68df046..838ff7e 100644 +--- a/tests/utils_tests/test_http.py ++++ b/tests/utils_tests/test_http.py +@@ -6,6 +6,7 @@ from unittest import mock + from django.test import SimpleTestCase + from django.utils.datastructures import MultiValueDict + from django.utils.http import ( ++ MAX_URL_LENGTH, + base36_to_int, + content_disposition_header, + escape_leading_slashes, +@@ -273,6 +274,21 @@ class URLHasAllowedHostAndSchemeTests(unittest.TestCase): + False, + ) + ++ def test_max_url_length(self): ++ allowed_host = "example.com" ++ max_extra_characters = "é" * (MAX_URL_LENGTH - len(allowed_host) - 1) ++ max_length_boundary_url = f"{allowed_host}/{max_extra_characters}" ++ cases = [ ++ (max_length_boundary_url, True), ++ (max_length_boundary_url + "ú", False), ++ ] ++ for url, expected in cases: ++ with self.subTest(url=url): ++ self.assertIs( ++ url_has_allowed_host_and_scheme(url, allowed_hosts={allowed_host}), ++ expected, ++ ) ++ + + class URLSafeBase64Tests(unittest.TestCase): + def test_roundtrip(self): +-- +2.49.0 + diff --git a/python-django.spec b/python-django.spec index dc2e974c545f035b9cb6c342c31e4f536d7ae113..c0719102979bf2a8b0174322d38264e81f146202 100644 --- a/python-django.spec +++ b/python-django.spec @@ -1,13 +1,15 @@ %global _empty_manifest_terminate_build 0 Name: python-django Version: 5.1.5 -Release: 2 +Release: 3 Summary: A high-level Python Web framework that encourages rapid development and clean, pragmatic design. License: Apache-2.0 and Python-2.0 and BSD-3-Clause URL: https://www.djangoproject.com/ Source0: https://files.pythonhosted.org/packages/source/d/Django/Django-%{version}.tar.gz -Patch0001: backport-CVE-2025-26699.patch +# Security fix +Patch3000: backport-CVE-2025-26699.patch +Patch3001: backport-CVE-2025-27556.patch BuildArch: noarch %description @@ -76,6 +78,9 @@ mv %{buildroot}/doclist.lst . %{_docdir}/* %changelog +* Mon Apr 07 2025 yaoxin <1024769339@qq.com> - 5.1.5-3 +- Fix CVE-2025-27556 + * Mon Mar 10 2025 changtao - 5.1.5-2 - Type:CVE - CVE:CVE-2025-26699