diff --git a/CVE-2022-34265.patch b/CVE-2022-34265.patch
deleted file mode 100644
index 3d4f452e08f999e126286f2217083e5c68fc71fa..0000000000000000000000000000000000000000
--- a/CVE-2022-34265.patch
+++ /dev/null
@@ -1,109 +0,0 @@
-From a9010fe5555e6086a9d9ae50069579400ef0685e Mon Sep 17 00:00:00 2001
-From: Mariusz Felisiak 
-Date: Wed, 22 Jun 2022 12:44:04 +0200
-Subject: [PATCH] [3.2.x] Fixed CVE-2022-34265 -- Protected
- Trunc(kind)/Extract(lookup_name) against SQL injection.
-
-Thanks Takuto Yoshikai (Aeye Security Lab) for the report.
----
- django/db/backends/base/operations.py         |  3 ++
- django/db/models/functions/datetime.py        |  4 +++
- docs/releases/3.2.14.txt                      | 11 ++++++
- .../datetime/test_extract_trunc.py            | 34 +++++++++++++++++++
- 4 files changed, 52 insertions(+)
-
-diff --git a/django/db/backends/base/operations.py b/django/db/backends/base/operations.py
-index 0fcc607bcfb0..cdcd9885ba27 100644
---- a/django/db/backends/base/operations.py
-+++ b/django/db/backends/base/operations.py
-@@ -9,6 +9,7 @@
- from django.db.backends import utils
- from django.utils import timezone
- from django.utils.encoding import force_str
-+from django.utils.regex_helper import _lazy_re_compile
- 
- 
- class BaseDatabaseOperations:
-@@ -53,6 +54,8 @@ class BaseDatabaseOperations:
-     # Prefix for EXPLAIN queries, or None EXPLAIN isn't supported.
-     explain_prefix = None
- 
-+    extract_trunc_lookup_pattern = _lazy_re_compile(r"[\w\-_()]+")
-+
-     def __init__(self, connection):
-         self.connection = connection
-         self._cache = None
-diff --git a/django/db/models/functions/datetime.py b/django/db/models/functions/datetime.py
-index 90e6f41be057..47651d281f19 100644
---- a/django/db/models/functions/datetime.py
-+++ b/django/db/models/functions/datetime.py
-@@ -41,6 +41,8 @@ def __init__(self, expression, lookup_name=None, tzinfo=None, **extra):
-         super().__init__(expression, **extra)
- 
-     def as_sql(self, compiler, connection):
-+        if not connection.ops.extract_trunc_lookup_pattern.fullmatch(self.lookup_name):
-+            raise ValueError("Invalid lookup_name: %s" % self.lookup_name)
-         sql, params = compiler.compile(self.lhs)
-         lhs_output_field = self.lhs.output_field
-         if isinstance(lhs_output_field, DateTimeField):
-@@ -192,6 +194,8 @@ def __init__(self, expression, output_field=None, tzinfo=None, is_dst=None, **ex
-         super().__init__(expression, output_field=output_field, **extra)
- 
-     def as_sql(self, compiler, connection):
-+        if not connection.ops.extract_trunc_lookup_pattern.fullmatch(self.kind):
-+            raise ValueError("Invalid kind: %s" % self.kind)
-         inner_sql, inner_params = compiler.compile(self.lhs)
-         tzname = None
-         if isinstance(self.lhs.output_field, DateTimeField):
-diff --git a/tests/db_functions/datetime/test_extract_trunc.py b/tests/db_functions/datetime/test_extract_trunc.py
-index 258600127f93..27ed3ae63ee5 100644
---- a/tests/db_functions/datetime/test_extract_trunc.py
-+++ b/tests/db_functions/datetime/test_extract_trunc.py
-@@ -177,6 +177,23 @@ def test_extract_year_lessthan_lookup(self):
-                 self.assertEqual(qs.count(), 1)
-                 self.assertGreaterEqual(str(qs.query).lower().count('extract'), 2)
- 
-+    def test_extract_lookup_name_sql_injection(self):
-+        start_datetime = datetime(2015, 6, 15, 14, 30, 50, 321)
-+        end_datetime = datetime(2016, 6, 15, 14, 10, 50, 123)
-+        if settings.USE_TZ:
-+            start_datetime = timezone.make_aware(start_datetime)
-+            end_datetime = timezone.make_aware(end_datetime)
-+        self.create_model(start_datetime, end_datetime)
-+        self.create_model(end_datetime, start_datetime)
-+
-+        msg = "Invalid lookup_name: "
-+        with self.assertRaisesMessage(ValueError, msg):
-+            DTModel.objects.filter(
-+                start_datetime__year=Extract(
-+                    "start_datetime", "day' FROM start_datetime)) OR 1=1;--"
-+                )
-+            ).exists()
-+
-     def test_extract_func(self):
-         start_datetime = datetime(2015, 6, 15, 14, 30, 50, 321)
-         end_datetime = datetime(2016, 6, 15, 14, 10, 50, 123)
-@@ -620,6 +637,23 @@ def test_extract_second_func(self):
-         )
-         self.assertEqual(DTModel.objects.filter(start_datetime__second=ExtractSecond('start_datetime')).count(), 2)
- 
-+    def test_trunc_lookup_name_sql_injection(self):
-+        start_datetime = datetime(2015, 6, 15, 14, 30, 50, 321)
-+        end_datetime = datetime(2016, 6, 15, 14, 10, 50, 123)
-+        if settings.USE_TZ:
-+            start_datetime = timezone.make_aware(start_datetime)
-+            end_datetime = timezone.make_aware(end_datetime)
-+        self.create_model(start_datetime, end_datetime)
-+        self.create_model(end_datetime, start_datetime)
-+        msg = "Invalid kind: "
-+        with self.assertRaisesMessage(ValueError, msg):
-+            DTModel.objects.filter(
-+                start_datetime__date=Trunc(
-+                    "start_datetime",
-+                    "year', start_datetime)) OR 1=1;--",
-+                )
-+            ).exists()
-+
-     def test_trunc_func(self):
-         start_datetime = datetime(2015, 6, 15, 14, 30, 50, 321)
-         end_datetime = datetime(2016, 6, 15, 14, 10, 50, 123)
diff --git a/CVE-2023-23969.patch b/CVE-2023-23969.patch
deleted file mode 100644
index 13dc1bb1428f1fb3a2f59e5cd899821762a05c56..0000000000000000000000000000000000000000
--- a/CVE-2023-23969.patch
+++ /dev/null
@@ -1,100 +0,0 @@
-From 80353a42e41fd22933184a30f2e2c04d0c274c83 Mon Sep 17 00:00:00 2001
-From: starlet-dx <15929766099@163.com>
-Date: Mon, 13 Feb 2023 19:31:46 +0800
-Subject: [PATCH 1/1] [3.2.x] Fixed CVE-2023-23969 -- Prevented DoS with pathological values for Accept-Language.
-
-The parsed values of Accept-Language headers are cached in order to avoid repetitive parsing. This leads to a potential denial-of-service vector via excessive memory usage if the raw value of Accept-Language headers is very large.
-
-Accept-Language headers are now limited to a maximum length in order to avoid this issue.
----
- django/utils/translation/trans_real.py | 32 +++++++++++++++++++++++++-
- tests/i18n/tests.py                    | 12 ++++++++++
- 2 files changed, 43 insertions(+), 1 deletion(-)
-
-diff --git a/django/utils/translation/trans_real.py b/django/utils/translation/trans_real.py
-index 8042f6f..b262a50 100644
---- a/django/utils/translation/trans_real.py
-+++ b/django/utils/translation/trans_real.py
-@@ -30,6 +30,11 @@ _default = None
- # magic gettext number to separate context from message
- CONTEXT_SEPARATOR = "\x04"
- 
-+# Maximum number of characters that will be parsed from the Accept-Language
-+# header to prevent possible denial of service or memory exhaustion attacks.
-+# About 10x longer than the longest value shown on MDN’s Accept-Language page.
-+ACCEPT_LANGUAGE_HEADER_MAX_LENGTH = 500
-+
- # Format of Accept-Language header values. From RFC 2616, section 14.4 and 3.9
- # and RFC 3066, section 2.1
- accept_language_re = _lazy_re_compile(r'''
-@@ -556,7 +561,7 @@ def get_language_from_request(request, check_path=False):
- 
- 
- @functools.lru_cache(maxsize=1000)
--def parse_accept_lang_header(lang_string):
-+def _parse_accept_lang_header(lang_string):
-     """
-     Parse the lang_string, which is the body of an HTTP Accept-Language
-     header, and return a tuple of (lang, q-value), ordered by 'q' values.
-@@ -578,3 +583,28 @@ def parse_accept_lang_header(lang_string):
-         result.append((lang, priority))
-     result.sort(key=lambda k: k[1], reverse=True)
-     return tuple(result)
-+
-+
-+def parse_accept_lang_header(lang_string):
-+    """
-+    Parse the value of the Accept-Language header up to a maximum length.
-+
-+    The value of the header is truncated to a maximum length to avoid potential
-+    denial of service and memory exhaustion attacks. Excessive memory could be
-+    used if the raw value is very large as it would be cached due to the use of
-+    functools.lru_cache() to avoid repetitive parsing of common header values.
-+    """
-+    # If the header value doesn't exceed the maximum allowed length, parse it.
-+    if len(lang_string) <= ACCEPT_LANGUAGE_HEADER_MAX_LENGTH:
-+        return _parse_accept_lang_header(lang_string)
-+
-+    # If there is at least one comma in the value, parse up to the last comma
-+    # before the max length, skipping any truncated parts at the end of the
-+    # header value.
-+    index = lang_string.rfind(",", 0, ACCEPT_LANGUAGE_HEADER_MAX_LENGTH)
-+    if index > 0:
-+        return _parse_accept_lang_header(lang_string[:index])
-+
-+    # Don't attempt to parse if there is only one language-range value which is
-+    # longer than the maximum allowed length and so truncated.
-+    return ()
-diff --git a/tests/i18n/tests.py b/tests/i18n/tests.py
-index 7edceb1..f379f8f 100644
---- a/tests/i18n/tests.py
-+++ b/tests/i18n/tests.py
-@@ -1352,6 +1352,14 @@ class MiscTests(SimpleTestCase):
-             ('de;q=0.', [('de', 0.0)]),
-             ('en; q=1,', [('en', 1.0)]),
-             ('en; q=1.0, * ; q=0.5', [('en', 1.0), ('*', 0.5)]),
-+            (
-+                'en' + '-x' * 20,
-+                [('en-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x', 1.0)],
-+            ),
-+            (
-+                ', '.join(['en; q=1.0'] * 20),
-+                [('en', 1.0)] * 20,
-+            ),
-             # Bad headers
-             ('en-gb;q=1.0000', []),
-             ('en;q=0.1234', []),
-@@ -1367,6 +1375,10 @@ class MiscTests(SimpleTestCase):
-             ('12-345', []),
-             ('', []),
-             ('en;q=1e0', []),
-+            # Invalid as language-range value too long.
-+            ('xxxxxxxx' + '-xxxxxxxx' * 500, []),
-+            # Header value too long, only parse up to limit.
-+            (', '.join(['en; q=1.0'] * 500), [('en', 1.0)] * 45),
-         ]
-         for value, expected in tests:
-             with self.subTest(value=value):
--- 
-2.30.0
-
diff --git a/CVE-2023-24580.patch b/CVE-2023-24580.patch
deleted file mode 100644
index 9f23a5499be925bf9981a635994e041bdd10e554..0000000000000000000000000000000000000000
--- a/CVE-2023-24580.patch
+++ /dev/null
@@ -1,401 +0,0 @@
-From a665ed5179f5bbd3db95ce67286d0192eff041d8 Mon Sep 17 00:00:00 2001
-From: Markus Holtermann 
-Date: Tue, 13 Dec 2022 10:27:39 +0100
-Subject: [PATCH] [3.2.x] Fixed CVE-2023-24580 -- Prevented DoS with too many
- uploaded files.
-
-Thanks to Jakob Ackermann for the report.
----
- django/conf/global_settings.py              |  4 ++
- django/core/exceptions.py                   |  9 +++
- django/core/handlers/exception.py           |  4 +-
- django/http/multipartparser.py              | 62 +++++++++++++++++----
- django/http/request.py                      |  6 +-
- docs/ref/exceptions.txt                     |  5 ++
- docs/ref/settings.txt                       | 23 ++++++++
- docs/releases/3.2.18.txt                    | 10 +++-
- tests/handlers/test_exception.py            | 28 +++++++++-
- tests/requests/test_data_upload_settings.py | 51 ++++++++++++++++-
- 10 files changed, 184 insertions(+), 18 deletions(-)
-
-diff --git a/django/conf/global_settings.py b/django/conf/global_settings.py
-index cf9fae496e3a..4a27887a8f04 100644
---- a/django/conf/global_settings.py
-+++ b/django/conf/global_settings.py
-@@ -303,6 +303,10 @@ def gettext_noop(s):
- # SuspiciousOperation (TooManyFieldsSent) is raised.
- DATA_UPLOAD_MAX_NUMBER_FIELDS = 1000
- 
-+# Maximum number of files encoded in a multipart upload that will be read
-+# before a SuspiciousOperation (TooManyFilesSent) is raised.
-+DATA_UPLOAD_MAX_NUMBER_FILES = 100
-+
- # Directory in which upload streamed files will be temporarily saved. A value of
- # `None` will make Django use the operating system's default temporary directory
- # (i.e. "/tmp" on *nix systems).
-diff --git a/django/core/exceptions.py b/django/core/exceptions.py
-index 673d004d5756..83161a58cd66 100644
---- a/django/core/exceptions.py
-+++ b/django/core/exceptions.py
-@@ -58,6 +58,15 @@ class TooManyFieldsSent(SuspiciousOperation):
-     pass
- 
- 
-+class TooManyFilesSent(SuspiciousOperation):
-+    """
-+    The number of fields in a GET or POST request exceeded
-+    settings.DATA_UPLOAD_MAX_NUMBER_FILES.
-+    """
-+
-+    pass
-+
-+
- class RequestDataTooBig(SuspiciousOperation):
-     """
-     The size of the request (excluding any file uploads) exceeded
-diff --git a/django/core/handlers/exception.py b/django/core/handlers/exception.py
-index 3005a5eccb11..2ecc2a0fd697 100644
---- a/django/core/handlers/exception.py
-+++ b/django/core/handlers/exception.py
-@@ -9,7 +9,7 @@
- from django.core import signals
- from django.core.exceptions import (
-     BadRequest, PermissionDenied, RequestDataTooBig, SuspiciousOperation,
--    TooManyFieldsSent,
-+    TooManyFieldsSent, TooManyFilesSent,
- )
- from django.http import Http404
- from django.http.multipartparser import MultiPartParserError
-@@ -88,7 +88,7 @@ def response_for_exception(request, exc):
-             exc_info=sys.exc_info(),
-         )
-     elif isinstance(exc, SuspiciousOperation):
--        if isinstance(exc, (RequestDataTooBig, TooManyFieldsSent)):
-+        if isinstance(exc, (RequestDataTooBig, TooManyFieldsSent, TooManyFilesSent)):
-             # POST data can't be accessed again, otherwise the original
-             # exception would be raised.
-             request._mark_post_parse_error()
-diff --git a/django/http/multipartparser.py b/django/http/multipartparser.py
-index 35a54f4ca12e..d8a304d4babe 100644
---- a/django/http/multipartparser.py
-+++ b/django/http/multipartparser.py
-@@ -14,6 +14,7 @@
- from django.conf import settings
- from django.core.exceptions import (
-     RequestDataTooBig, SuspiciousMultipartForm, TooManyFieldsSent,
-+    TooManyFilesSent,
- )
- from django.core.files.uploadhandler import (
-     SkipFile, StopFutureHandlers, StopUpload,
-@@ -38,6 +39,7 @@ class InputStreamExhausted(Exception):
- RAW = "raw"
- FILE = "file"
- FIELD = "field"
-+FIELD_TYPES = frozenset([FIELD, RAW])
- 
- 
- class MultiPartParser:
-@@ -102,6 +104,22 @@ def __init__(self, META, input_data, upload_handlers, encoding=None):
-         self._upload_handlers = upload_handlers
- 
-     def parse(self):
-+        # Call the actual parse routine and close all open files in case of
-+        # errors. This is needed because if exceptions are thrown the
-+        # MultiPartParser will not be garbage collected immediately and
-+        # resources would be kept alive. This is only needed for errors because
-+        # the Request object closes all uploaded files at the end of the
-+        # request.
-+        try:
-+            return self._parse()
-+        except Exception:
-+            if hasattr(self, "_files"):
-+                for _, files in self._files.lists():
-+                    for fileobj in files:
-+                        fileobj.close()
-+            raise
-+
-+    def _parse(self):
-         """
-         Parse the POST data and break it into a FILES MultiValueDict and a POST
-         MultiValueDict.
-@@ -147,6 +165,8 @@ def parse(self):
-         num_bytes_read = 0
-         # To count the number of keys in the request.
-         num_post_keys = 0
-+        # To count the number of files in the request.
-+        num_files = 0
-         # To limit the amount of data read from the request.
-         read_size = None
-         # Whether a file upload is finished.
-@@ -162,6 +182,20 @@ def parse(self):
-                     old_field_name = None
-                     uploaded_file = True
- 
-+                if (
-+                    item_type in FIELD_TYPES and
-+                    settings.DATA_UPLOAD_MAX_NUMBER_FIELDS is not None
-+                ):
-+                    # Avoid storing more than DATA_UPLOAD_MAX_NUMBER_FIELDS.
-+                    num_post_keys += 1
-+                    # 2 accounts for empty raw fields before and after the
-+                    # last boundary.
-+                    if settings.DATA_UPLOAD_MAX_NUMBER_FIELDS + 2 < num_post_keys:
-+                        raise TooManyFieldsSent(
-+                            "The number of GET/POST parameters exceeded "
-+                            "settings.DATA_UPLOAD_MAX_NUMBER_FIELDS."
-+                        )
-+
-                 try:
-                     disposition = meta_data['content-disposition'][1]
-                     field_name = disposition['name'].strip()
-@@ -174,15 +208,6 @@ def parse(self):
-                 field_name = force_str(field_name, encoding, errors='replace')
- 
-                 if item_type == FIELD:
--                    # Avoid storing more than DATA_UPLOAD_MAX_NUMBER_FIELDS.
--                    num_post_keys += 1
--                    if (settings.DATA_UPLOAD_MAX_NUMBER_FIELDS is not None and
--                            settings.DATA_UPLOAD_MAX_NUMBER_FIELDS < num_post_keys):
--                        raise TooManyFieldsSent(
--                            'The number of GET/POST parameters exceeded '
--                            'settings.DATA_UPLOAD_MAX_NUMBER_FIELDS.'
--                        )
--
-                     # Avoid reading more than DATA_UPLOAD_MAX_MEMORY_SIZE.
-                     if settings.DATA_UPLOAD_MAX_MEMORY_SIZE is not None:
-                         read_size = settings.DATA_UPLOAD_MAX_MEMORY_SIZE - num_bytes_read
-@@ -208,6 +233,16 @@ def parse(self):
- 
-                     self._post.appendlist(field_name, force_str(data, encoding, errors='replace'))
-                 elif item_type == FILE:
-+                    # Avoid storing more than DATA_UPLOAD_MAX_NUMBER_FILES.
-+                    num_files += 1
-+                    if (
-+                        settings.DATA_UPLOAD_MAX_NUMBER_FILES is not None and
-+                        num_files > settings.DATA_UPLOAD_MAX_NUMBER_FILES
-+                    ):
-+                        raise TooManyFilesSent(
-+                            "The number of files exceeded "
-+                            "settings.DATA_UPLOAD_MAX_NUMBER_FILES."
-+                        )
-                     # This is a file, use the handler...
-                     file_name = disposition.get('filename')
-                     if file_name:
-@@ -276,8 +311,13 @@ def parse(self):
-                         # Handle file upload completions on next iteration.
-                         old_field_name = field_name
-                 else:
--                    # If this is neither a FIELD or a FILE, just exhaust the stream.
--                    exhaust(stream)
-+                    # If this is neither a FIELD nor a FILE, exhaust the field
-+                    # stream. Note: There could be an error here at some point,
-+                    # but there will be at least two RAW types (before and
-+                    # after the other boundaries). This branch is usually not
-+                    # reached at all, because a missing content-disposition
-+                    # header will skip the whole boundary.
-+                    exhaust(field_stream)
-         except StopUpload as e:
-             self._close_files()
-             if not e.connection_reset:
-diff --git a/django/http/request.py b/django/http/request.py
-index 195341ec4b69..b6cd7a372f14 100644
---- a/django/http/request.py
-+++ b/django/http/request.py
-@@ -12,7 +12,9 @@
-     DisallowedHost, ImproperlyConfigured, RequestDataTooBig, TooManyFieldsSent,
- )
- from django.core.files import uploadhandler
--from django.http.multipartparser import MultiPartParser, MultiPartParserError
-+from django.http.multipartparser import (
-+    MultiPartParser, MultiPartParserError, TooManyFilesSent,
-+)
- from django.utils.datastructures import (
-     CaseInsensitiveMapping, ImmutableList, MultiValueDict,
- )
-@@ -360,7 +362,7 @@ def _load_post_and_files(self):
-                 data = self
-             try:
-                 self._post, self._files = self.parse_file_upload(self.META, data)
--            except MultiPartParserError:
-+            except (MultiPartParserError, TooManyFilesSent):
-                 # An error occurred while parsing POST data. Since when
-                 # formatting the error the request handler might access
-                 # self.POST, set self._post and self._file to prevent
-diff --git a/docs/ref/exceptions.txt b/docs/ref/exceptions.txt
-index 2f5aa64b9d9d..7d34025cd65c 100644
---- a/docs/ref/exceptions.txt
-+++ b/docs/ref/exceptions.txt
-@@ -84,12 +84,17 @@ Django core exception classes are defined in ``django.core.exceptions``.
-     * ``SuspiciousMultipartForm``
-     * ``SuspiciousSession``
-     * ``TooManyFieldsSent``
-+    * ``TooManyFilesSent``
- 
-     If a ``SuspiciousOperation`` exception reaches the ASGI/WSGI handler level
-     it is logged at the ``Error`` level and results in
-     a :class:`~django.http.HttpResponseBadRequest`. See the :doc:`logging
-     documentation ` for more information.
- 
-+.. versionchanged:: 3.2.18
-+
-+    ``SuspiciousOperation`` is raised when too many files are submitted.
-+
- ``PermissionDenied``
- --------------------
- 
-diff --git a/docs/ref/settings.txt b/docs/ref/settings.txt
-index 9bfadbc89bd2..9173009c94d5 100644
---- a/docs/ref/settings.txt
-+++ b/docs/ref/settings.txt
-@@ -1063,6 +1063,28 @@ could be used as a denial-of-service attack vector if left unchecked. Since web
- servers don't typically perform deep request inspection, it's not possible to
- perform a similar check at that level.
- 
-+.. setting:: DATA_UPLOAD_MAX_NUMBER_FILES
-+
-+``DATA_UPLOAD_MAX_NUMBER_FILES``
-+--------------------------------
-+
-+.. versionadded:: 3.2.18
-+
-+Default: ``100``
-+
-+The maximum number of files that may be received via POST in a
-+``multipart/form-data`` encoded request before a
-+:exc:`~django.core.exceptions.SuspiciousOperation` (``TooManyFiles``) is
-+raised. You can set this to ``None`` to disable the check. Applications that
-+are expected to receive an unusually large number of file fields should tune
-+this setting.
-+
-+The number of accepted files is correlated to the amount of time and memory
-+needed to process the request. Large requests could be used as a
-+denial-of-service attack vector if left unchecked. Since web servers don't
-+typically perform deep request inspection, it's not possible to perform a
-+similar check at that level.
-+
- .. setting:: DATABASE_ROUTERS
- 
- ``DATABASE_ROUTERS``
-@@ -3671,6 +3693,7 @@ HTTP
- ----
- * :setting:`DATA_UPLOAD_MAX_MEMORY_SIZE`
- * :setting:`DATA_UPLOAD_MAX_NUMBER_FIELDS`
-+* :setting:`DATA_UPLOAD_MAX_NUMBER_FILES`
- * :setting:`DEFAULT_CHARSET`
- * :setting:`DISALLOWED_USER_AGENTS`
- * :setting:`FORCE_SCRIPT_NAME`
-diff --git a/tests/handlers/test_exception.py b/tests/handlers/test_exception.py
-index 0c1e76399045..7de2edaeea34 100644
---- a/tests/handlers/test_exception.py
-+++ b/tests/handlers/test_exception.py
-@@ -1,6 +1,8 @@
- from django.core.handlers.wsgi import WSGIHandler
- from django.test import SimpleTestCase, override_settings
--from django.test.client import FakePayload
-+from django.test.client import (
-+    BOUNDARY, MULTIPART_CONTENT, FakePayload, encode_multipart,
-+)
- 
- 
- class ExceptionHandlerTests(SimpleTestCase):
-@@ -25,3 +27,27 @@ def test_data_upload_max_memory_size_exceeded(self):
-     def test_data_upload_max_number_fields_exceeded(self):
-         response = WSGIHandler()(self.get_suspicious_environ(), lambda *a, **k: None)
-         self.assertEqual(response.status_code, 400)
-+
-+    @override_settings(DATA_UPLOAD_MAX_NUMBER_FILES=2)
-+    def test_data_upload_max_number_files_exceeded(self):
-+        payload = FakePayload(
-+            encode_multipart(
-+                BOUNDARY,
-+                {
-+                    "a.txt": "Hello World!",
-+                    "b.txt": "Hello Django!",
-+                    "c.txt": "Hello Python!",
-+                },
-+            )
-+        )
-+        environ = {
-+            "REQUEST_METHOD": "POST",
-+            "CONTENT_TYPE": MULTIPART_CONTENT,
-+            "CONTENT_LENGTH": len(payload),
-+            "wsgi.input": payload,
-+            "SERVER_NAME": "test",
-+            "SERVER_PORT": "8000",
-+        }
-+
-+        response = WSGIHandler()(environ, lambda *a, **k: None)
-+        self.assertEqual(response.status_code, 400)
-diff --git a/tests/requests/test_data_upload_settings.py b/tests/requests/test_data_upload_settings.py
-index 44897cc9fa97..ded778b42286 100644
---- a/tests/requests/test_data_upload_settings.py
-+++ b/tests/requests/test_data_upload_settings.py
-@@ -1,11 +1,14 @@
- from io import BytesIO
- 
--from django.core.exceptions import RequestDataTooBig, TooManyFieldsSent
-+from django.core.exceptions import (
-+    RequestDataTooBig, TooManyFieldsSent, TooManyFilesSent,
-+)
- from django.core.handlers.wsgi import WSGIRequest
- from django.test import SimpleTestCase
- from django.test.client import FakePayload
- 
- TOO_MANY_FIELDS_MSG = 'The number of GET/POST parameters exceeded settings.DATA_UPLOAD_MAX_NUMBER_FIELDS.'
-+TOO_MANY_FILES_MSG = 'The number of files exceeded settings.DATA_UPLOAD_MAX_NUMBER_FILES.'
- TOO_MUCH_DATA_MSG = 'Request body exceeded settings.DATA_UPLOAD_MAX_MEMORY_SIZE.'
- 
- 
-@@ -166,6 +169,52 @@ def test_no_limit(self):
-             self.request._load_post_and_files()
- 
- 
-+class DataUploadMaxNumberOfFilesMultipartPost(SimpleTestCase):
-+    def setUp(self):
-+        payload = FakePayload(
-+            "\r\n".join(
-+                [
-+                    "--boundary",
-+                    (
-+                        'Content-Disposition: form-data; name="name1"; '
-+                        'filename="name1.txt"'
-+                    ),
-+                    "",
-+                    "value1",
-+                    "--boundary",
-+                    (
-+                        'Content-Disposition: form-data; name="name2"; '
-+                        'filename="name2.txt"'
-+                    ),
-+                    "",
-+                    "value2",
-+                    "--boundary--",
-+                ]
-+            )
-+        )
-+        self.request = WSGIRequest(
-+            {
-+                "REQUEST_METHOD": "POST",
-+                "CONTENT_TYPE": "multipart/form-data; boundary=boundary",
-+                "CONTENT_LENGTH": len(payload),
-+                "wsgi.input": payload,
-+            }
-+        )
-+
-+    def test_number_exceeded(self):
-+        with self.settings(DATA_UPLOAD_MAX_NUMBER_FILES=1):
-+            with self.assertRaisesMessage(TooManyFilesSent, TOO_MANY_FILES_MSG):
-+                self.request._load_post_and_files()
-+
-+    def test_number_not_exceeded(self):
-+        with self.settings(DATA_UPLOAD_MAX_NUMBER_FILES=2):
-+            self.request._load_post_and_files()
-+
-+    def test_no_limit(self):
-+        with self.settings(DATA_UPLOAD_MAX_NUMBER_FILES=None):
-+            self.request._load_post_and_files()
-+
-+
- class DataUploadMaxNumberOfFieldsFormPost(SimpleTestCase):
-     def setUp(self):
-         payload = FakePayload("\r\n".join(['a=1&a=2&a=3', '']))
diff --git a/CVE-2023-31047.patch b/CVE-2023-31047.patch
deleted file mode 100644
index bdcf26b8987a65ef9e6052269892893840c09bfa..0000000000000000000000000000000000000000
--- a/CVE-2023-31047.patch
+++ /dev/null
@@ -1,322 +0,0 @@
-From 6bb2e1ac607b1a399e1d7bd3650c04a586e6746e Mon Sep 17 00:00:00 2001
-From: starlet-dx <15929766099@163.com>
-Date: Tue, 16 May 2023 10:00:42 +0800
-Subject: [PATCH 1/1] [3.2.x] Fixed CVE-2023-31047, Fixed #31710 -- Prevented
- potential bypass of validation when uploading multiple files using one form
- field.
-
-Thanks Moataz Al-Sharida and nawaik for reports.
-
-Co-authored-by: Shai Berger 
-Co-authored-by: nessita <124304+nessita@users.noreply.github.com>
-
-Origin:
-https://github.com/django/django/commit/eed53d0011622e70b936e203005f0e6f4ac48965
----
- django/forms/widgets.py                       | 26 ++++++-
- docs/topics/http/file-uploads.txt             | 65 ++++++++++++++++--
- .../forms_tests/field_tests/test_filefield.py | 68 ++++++++++++++++++-
- .../widget_tests/test_clearablefileinput.py   |  5 ++
- .../widget_tests/test_fileinput.py            | 44 ++++++++++++
- 5 files changed, 200 insertions(+), 8 deletions(-)
-
-diff --git a/django/forms/widgets.py b/django/forms/widgets.py
-index 1b1c143..8ef8255 100644
---- a/django/forms/widgets.py
-+++ b/django/forms/widgets.py
-@@ -378,16 +378,40 @@ class MultipleHiddenInput(HiddenInput):
- 
- class FileInput(Input):
-     input_type = 'file'
-+    allow_multiple_selected = False
-     needs_multipart_form = True
-     template_name = 'django/forms/widgets/file.html'
- 
-+    def __init__(self, attrs=None):
-+        if (
-+            attrs is not None and
-+            not self.allow_multiple_selected and
-+            attrs.get("multiple", False)
-+        ):
-+            raise ValueError(
-+                "%s doesn't support uploading multiple files."
-+                % self.__class__.__qualname__
-+            )
-+        if self.allow_multiple_selected:
-+            if attrs is None:
-+                attrs = {"multiple": True}
-+            else:
-+                attrs.setdefault("multiple", True)
-+        super().__init__(attrs)
-+
-     def format_value(self, value):
-         """File input never renders a value."""
-         return
- 
-     def value_from_datadict(self, data, files, name):
-         "File widgets take data from FILES, not POST"
--        return files.get(name)
-+        getter = files.get
-+        if self.allow_multiple_selected:
-+            try:
-+                getter = files.getlist
-+            except AttributeError:
-+                pass
-+        return getter(name)
- 
-     def value_omitted_from_data(self, data, files, name):
-         return name not in files
-diff --git a/docs/topics/http/file-uploads.txt b/docs/topics/http/file-uploads.txt
-index ca272d7..4388594 100644
---- a/docs/topics/http/file-uploads.txt
-+++ b/docs/topics/http/file-uploads.txt
-@@ -126,19 +126,54 @@ model::
-             form = UploadFileForm()
-         return render(request, 'upload.html', {'form': form})
- 
-+.. _uploading_multiple_files:
-+
- Uploading multiple files
- ------------------------
- 
--If you want to upload multiple files using one form field, set the ``multiple``
--HTML attribute of field's widget:
-+..
-+    Tests in tests.forms_tests.field_tests.test_filefield.MultipleFileFieldTest
-+    should be updated after any changes in the following snippets.
-+
-+If you want to upload multiple files using one form field, create a subclass
-+of the field's widget and set the ``allow_multiple_selected`` attribute on it
-+to ``True``.
-+
-+In order for such files to be all validated by your form (and have the value of
-+the field include them all), you will also have to subclass ``FileField``. See
-+below for an example.
-+
-+.. admonition:: Multiple file field
-+
-+    Django is likely to have a proper multiple file field support at some point
-+    in the future.
- 
- .. code-block:: python
-     :caption: forms.py
- 
-     from django import forms
- 
-+
-+    class MultipleFileInput(forms.ClearableFileInput):
-+        allow_multiple_selected = True
-+
-+
-+    class MultipleFileField(forms.FileField):
-+        def __init__(self, *args, **kwargs):
-+            kwargs.setdefault("widget", MultipleFileInput())
-+            super().__init__(*args, **kwargs)
-+
-+        def clean(self, data, initial=None):
-+            single_file_clean = super().clean
-+            if isinstance(data, (list, tuple)):
-+                result = [single_file_clean(d, initial) for d in data]
-+            else:
-+                result = single_file_clean(data, initial)
-+            return result
-+
-+
-     class FileFieldForm(forms.Form):
--        file_field = forms.FileField(widget=forms.ClearableFileInput(attrs={'multiple': True}))
-+        file_field = MultipleFileField()
- 
- Then override the ``post`` method of your
- :class:`~django.views.generic.edit.FormView` subclass to handle multiple file
-@@ -158,14 +193,32 @@ uploads:
-         def post(self, request, *args, **kwargs):
-             form_class = self.get_form_class()
-             form = self.get_form(form_class)
--            files = request.FILES.getlist('file_field')
-             if form.is_valid():
--                for f in files:
--                    ...  # Do something with each file.
-                 return self.form_valid(form)
-             else:
-                 return self.form_invalid(form)
- 
-+        def form_valid(self, form):
-+            files = form.cleaned_data["file_field"]
-+            for f in files:
-+                ...  # Do something with each file.
-+            return super().form_valid()
-+
-+.. warning::
-+
-+   This will allow you to handle multiple files at the form level only. Be
-+   aware that you cannot use it to put multiple files on a single model
-+   instance (in a single field), for example, even if the custom widget is used
-+   with a form field related to a model ``FileField``.
-+
-+.. versionchanged:: 3.2.19
-+
-+   In previous versions, there was no support for the ``allow_multiple_selected``
-+   class attribute, and users were advised to create the widget with the HTML
-+   attribute ``multiple`` set through the ``attrs`` argument. However, this
-+   caused validation of the form field to be applied only to the last file
-+   submitted, which could have adverse security implications.
-+
- Upload Handlers
- ===============
- 
-diff --git a/tests/forms_tests/field_tests/test_filefield.py b/tests/forms_tests/field_tests/test_filefield.py
-index 2db106e..b54febd 100644
---- a/tests/forms_tests/field_tests/test_filefield.py
-+++ b/tests/forms_tests/field_tests/test_filefield.py
-@@ -2,7 +2,8 @@ import pickle
- 
- from django.core.exceptions import ValidationError
- from django.core.files.uploadedfile import SimpleUploadedFile
--from django.forms import FileField
-+from django.core.validators import validate_image_file_extension
-+from django.forms import FileField, FileInput
- from django.test import SimpleTestCase
- 
- 
-@@ -83,3 +84,68 @@ class FileFieldTest(SimpleTestCase):
- 
-     def test_file_picklable(self):
-         self.assertIsInstance(pickle.loads(pickle.dumps(FileField())), FileField)
-+
-+
-+class MultipleFileInput(FileInput):
-+    allow_multiple_selected = True
-+
-+
-+class MultipleFileField(FileField):
-+    def __init__(self, *args, **kwargs):
-+        kwargs.setdefault("widget", MultipleFileInput())
-+        super().__init__(*args, **kwargs)
-+
-+    def clean(self, data, initial=None):
-+        single_file_clean = super().clean
-+        if isinstance(data, (list, tuple)):
-+            result = [single_file_clean(d, initial) for d in data]
-+        else:
-+            result = single_file_clean(data, initial)
-+        return result
-+
-+
-+class MultipleFileFieldTest(SimpleTestCase):
-+    def test_file_multiple(self):
-+        f = MultipleFileField()
-+        files = [
-+            SimpleUploadedFile("name1", b"Content 1"),
-+            SimpleUploadedFile("name2", b"Content 2"),
-+        ]
-+        self.assertEqual(f.clean(files), files)
-+
-+    def test_file_multiple_empty(self):
-+        f = MultipleFileField()
-+        files = [
-+            SimpleUploadedFile("empty", b""),
-+            SimpleUploadedFile("nonempty", b"Some Content"),
-+        ]
-+        msg = "'The submitted file is empty.'"
-+        with self.assertRaisesMessage(ValidationError, msg):
-+            f.clean(files)
-+        with self.assertRaisesMessage(ValidationError, msg):
-+            f.clean(files[::-1])
-+
-+    def test_file_multiple_validation(self):
-+        f = MultipleFileField(validators=[validate_image_file_extension])
-+
-+        good_files = [
-+            SimpleUploadedFile("image1.jpg", b"fake JPEG"),
-+            SimpleUploadedFile("image2.png", b"faux image"),
-+            SimpleUploadedFile("image3.bmp", b"fraudulent bitmap"),
-+        ]
-+        self.assertEqual(f.clean(good_files), good_files)
-+
-+        evil_files = [
-+            SimpleUploadedFile("image1.sh", b"#!/bin/bash -c 'echo pwned!'\n"),
-+            SimpleUploadedFile("image2.png", b"faux image"),
-+            SimpleUploadedFile("image3.jpg", b"fake JPEG"),
-+        ]
-+
-+        evil_rotations = (
-+            evil_files[i:] + evil_files[:i]  # Rotate by i.
-+            for i in range(len(evil_files))
-+        )
-+        msg = "File extension “sh” is not allowed. Allowed extensions are: "
-+        for rotated_evil_files in evil_rotations:
-+            with self.assertRaisesMessage(ValidationError, msg):
-+                f.clean(rotated_evil_files)
-diff --git a/tests/forms_tests/widget_tests/test_clearablefileinput.py b/tests/forms_tests/widget_tests/test_clearablefileinput.py
-index dee44c4..6cf1476 100644
---- a/tests/forms_tests/widget_tests/test_clearablefileinput.py
-+++ b/tests/forms_tests/widget_tests/test_clearablefileinput.py
-@@ -176,3 +176,8 @@ class ClearableFileInputTest(WidgetTest):
-         self.assertIs(widget.value_omitted_from_data({}, {}, 'field'), True)
-         self.assertIs(widget.value_omitted_from_data({}, {'field': 'x'}, 'field'), False)
-         self.assertIs(widget.value_omitted_from_data({'field-clear': 'y'}, {}, 'field'), False)
-+
-+    def test_multiple_error(self):
-+        msg = "ClearableFileInput doesn't support uploading multiple files."
-+        with self.assertRaisesMessage(ValueError, msg):
-+            ClearableFileInput(attrs={"multiple": True})
-diff --git a/tests/forms_tests/widget_tests/test_fileinput.py b/tests/forms_tests/widget_tests/test_fileinput.py
-index 8eec262..8068f70 100644
---- a/tests/forms_tests/widget_tests/test_fileinput.py
-+++ b/tests/forms_tests/widget_tests/test_fileinput.py
-@@ -1,4 +1,6 @@
-+from django.core.files.uploadedfile import SimpleUploadedFile
- from django.forms import FileInput
-+from django.utils.datastructures import MultiValueDict
- 
- from .base import WidgetTest
- 
-@@ -24,3 +26,45 @@ class FileInputTest(WidgetTest):
-         # user to keep the existing, initial value.
-         self.assertIs(self.widget.use_required_attribute(None), True)
-         self.assertIs(self.widget.use_required_attribute('resume.txt'), False)
-+
-+    def test_multiple_error(self):
-+        msg = "FileInput doesn't support uploading multiple files."
-+        with self.assertRaisesMessage(ValueError, msg):
-+            FileInput(attrs={"multiple": True})
-+
-+    def test_value_from_datadict_multiple(self):
-+        class MultipleFileInput(FileInput):
-+            allow_multiple_selected = True
-+
-+        file_1 = SimpleUploadedFile("something1.txt", b"content 1")
-+        file_2 = SimpleUploadedFile("something2.txt", b"content 2")
-+        # Uploading multiple files is allowed.
-+        widget = MultipleFileInput(attrs={"multiple": True})
-+        value = widget.value_from_datadict(
-+            data={"name": "Test name"},
-+            files=MultiValueDict({"myfile": [file_1, file_2]}),
-+            name="myfile",
-+        )
-+        self.assertEqual(value, [file_1, file_2])
-+        # Uploading multiple files is not allowed.
-+        widget = FileInput()
-+        value = widget.value_from_datadict(
-+            data={"name": "Test name"},
-+            files=MultiValueDict({"myfile": [file_1, file_2]}),
-+            name="myfile",
-+        )
-+        self.assertEqual(value, file_2)
-+
-+    def test_multiple_default(self):
-+        class MultipleFileInput(FileInput):
-+            allow_multiple_selected = True
-+
-+        tests = [
-+            (None, True),
-+            ({"class": "myclass"}, True),
-+            ({"multiple": False}, False),
-+        ]
-+        for attrs, expected in tests:
-+            with self.subTest(attrs=attrs):
-+                widget = MultipleFileInput(attrs=attrs)
-+                self.assertIs(widget.attrs["multiple"], expected)
--- 
-2.30.0
-
diff --git a/CVE-2023-36053.patch b/CVE-2023-36053.patch
deleted file mode 100644
index e0dc2aee91b335e499eb897dfb82475df68c00ac..0000000000000000000000000000000000000000
--- a/CVE-2023-36053.patch
+++ /dev/null
@@ -1,244 +0,0 @@
-From 454f2fb93437f98917283336201b4048293f7582 Mon Sep 17 00:00:00 2001
-From: Mariusz Felisiak 
-Date: Wed, 14 Jun 2023 12:23:06 +0200
-Subject: [PATCH] [3.2.x] Fixed CVE-2023-36053 -- Prevented potential ReDoS in
- EmailValidator and URLValidator.
-
-Thanks Seokchan Yoon for reports.
----
- django/core/validators.py                     |  7 ++++--
- django/forms/fields.py                        |  3 +++
- docs/ref/forms/fields.txt                     |  7 +++++-
- docs/ref/validators.txt                       | 25 ++++++++++++++++++-
- docs/releases/3.2.20.txt                      |  7 +++++-
- .../field_tests/test_emailfield.py            |  5 +++-
- tests/forms_tests/tests/test_forms.py         | 19 +++++++++-----
- tests/validators/tests.py                     | 11 ++++++++
- 8 files changed, 72 insertions(+), 12 deletions(-)
-
-diff --git a/django/core/validators.py b/django/core/validators.py
-index 731ccf2d4690..b9b58dfa6176 100644
---- a/django/core/validators.py
-+++ b/django/core/validators.py
-@@ -93,6 +93,7 @@ class URLValidator(RegexValidator):
-     message = _('Enter a valid URL.')
-     schemes = ['http', 'https', 'ftp', 'ftps']
-     unsafe_chars = frozenset('\t\r\n')
-+    max_length = 2048
- 
-     def __init__(self, schemes=None, **kwargs):
-         super().__init__(**kwargs)
-@@ -100,7 +101,7 @@ def __init__(self, schemes=None, **kwargs):
-             self.schemes = schemes
- 
-     def __call__(self, value):
--        if not isinstance(value, str):
-+        if not isinstance(value, str) or len(value) > self.max_length:
-             raise ValidationError(self.message, code=self.code, params={'value': value})
-         if self.unsafe_chars.intersection(value):
-             raise ValidationError(self.message, code=self.code, params={'value': value})
-@@ -210,7 +211,9 @@ def __init__(self, message=None, code=None, allowlist=None, *, whitelist=None):
-             self.domain_allowlist = allowlist
- 
-     def __call__(self, value):
--        if not value or '@' not in value:
-+        # The maximum length of an email is 320 characters per RFC 3696
-+        # section 3.
-+        if not value or '@' not in value or len(value) > 320:
-             raise ValidationError(self.message, code=self.code, params={'value': value})
- 
-         user_part, domain_part = value.rsplit('@', 1)
-diff --git a/django/forms/fields.py b/django/forms/fields.py
-index 0214d60c1cf1..8adb09e38294 100644
---- a/django/forms/fields.py
-+++ b/django/forms/fields.py
-@@ -540,6 +540,9 @@ class EmailField(CharField):
-     default_validators = [validators.validate_email]
- 
-     def __init__(self, **kwargs):
-+        # The default maximum length of an email is 320 characters per RFC 3696
-+        # section 3.
-+        kwargs.setdefault("max_length", 320)
-         super().__init__(strip=True, **kwargs)
- 
- 
-diff --git a/docs/ref/forms/fields.txt b/docs/ref/forms/fields.txt
-index 9438214a28ce..5b485f215384 100644
---- a/docs/ref/forms/fields.txt
-+++ b/docs/ref/forms/fields.txt
-@@ -592,7 +592,12 @@ For each field, we describe the default widget used if you don't specify
-     * Error message keys: ``required``, ``invalid``
- 
-     Has three optional arguments ``max_length``, ``min_length``, and
--    ``empty_value`` which work just as they do for :class:`CharField`.
-+    ``empty_value`` which work just as they do for :class:`CharField`. The
-+    ``max_length`` argument defaults to 320 (see :rfc:`3696#section-3`).
-+
-+    .. versionchanged:: 3.2.20
-+
-+        The default value for ``max_length`` was changed to 320 characters.
- 
- ``FileField``
- -------------
-diff --git a/docs/ref/validators.txt b/docs/ref/validators.txt
-index 50761e5a425c..b22762b17b93 100644
---- a/docs/ref/validators.txt
-+++ b/docs/ref/validators.txt
-@@ -130,6 +130,11 @@ to, or in lieu of custom ``field.clean()`` methods.
-     :param code: If not ``None``, overrides :attr:`code`.
-     :param allowlist: If not ``None``, overrides :attr:`allowlist`.
- 
-+    An :class:`EmailValidator` ensures that a value looks like an email, and
-+    raises a :exc:`~django.core.exceptions.ValidationError` with
-+    :attr:`message` and :attr:`code` if it doesn't. Values longer than 320
-+    characters are always considered invalid.
-+
-     .. attribute:: message
- 
-         The error message used by
-@@ -158,13 +163,19 @@ to, or in lieu of custom ``field.clean()`` methods.
-         The undocumented ``domain_whitelist`` attribute is deprecated. Use
-         ``domain_allowlist`` instead.
- 
-+    .. versionchanged:: 3.2.20
-+
-+        In older versions, values longer than 320 characters could be
-+        considered valid.
-+
- ``URLValidator``
- ----------------
- 
- .. class:: URLValidator(schemes=None, regex=None, message=None, code=None)
- 
-     A :class:`RegexValidator` subclass that ensures a value looks like a URL,
--    and raises an error code of ``'invalid'`` if it doesn't.
-+    and raises an error code of ``'invalid'`` if it doesn't. Values longer than
-+    :attr:`max_length` characters are always considered invalid.
- 
-     Loopback addresses and reserved IP spaces are considered valid. Literal
-     IPv6 addresses (:rfc:`3986#section-3.2.2`) and Unicode domains are both
-@@ -181,6 +192,18 @@ to, or in lieu of custom ``field.clean()`` methods.
- 
-         .. _valid URI schemes: https://www.iana.org/assignments/uri-schemes/uri-schemes.xhtml
- 
-+    .. attribute:: max_length
-+
-+        .. versionadded:: 3.2.20
-+
-+        The maximum length of values that could be considered valid. Defaults
-+        to 2048 characters.
-+
-+    .. versionchanged:: 3.2.20
-+
-+        In older versions, values longer than 2048 characters could be
-+        considered valid.
-+
- ``validate_email``
- ------------------
- 
-diff --git a/tests/forms_tests/field_tests/test_emailfield.py b/tests/forms_tests/field_tests/test_emailfield.py
-index 8b85e4dcc144..19d315205d7e 100644
---- a/tests/forms_tests/field_tests/test_emailfield.py
-+++ b/tests/forms_tests/field_tests/test_emailfield.py
-@@ -9,7 +9,10 @@ class EmailFieldTest(FormFieldAssertionsMixin, SimpleTestCase):
- 
-     def test_emailfield_1(self):
-         f = EmailField()
--        self.assertWidgetRendersTo(f, 'Yes 
- No 
- 
--Email:  Email:  
- Age:   """
-         )
-@@ -2840,7 +2847,7 @@ class Person(Form):
- Yes 
- No 
-     
--Email:  
-+Email:  
- 
- Age: 
- 
"""
-@@ -2859,7 +2866,7 @@ class Person(Form):
- No 
- 
- Email: 
-- Age: 
-  Name: 
- Enter a valid email address.
Email: 
-+Email: 
- 
- Comment: 
""")
- 
-diff --git a/tests/validators/tests.py b/tests/validators/tests.py
-index e39d0e3a1cef..1065727a974e 100644
---- a/tests/validators/tests.py
-+++ b/tests/validators/tests.py
-@@ -59,6 +59,7 @@
- 
-     (validate_email, 'example@atm.%s' % ('a' * 64), ValidationError),
-     (validate_email, 'example@%s.atm.%s' % ('b' * 64, 'a' * 63), ValidationError),
-+    (validate_email, "example@%scom" % (("a" * 63 + ".") * 100), ValidationError),
-     (validate_email, None, ValidationError),
-     (validate_email, '', ValidationError),
-     (validate_email, 'abc', ValidationError),
-@@ -246,6 +247,16 @@
-     (URLValidator(), None, ValidationError),
-     (URLValidator(), 56, ValidationError),
-     (URLValidator(), 'no_scheme', ValidationError),
-+    (
-+        URLValidator(),
-+        "http://example." + ("a" * 63 + ".") * 1000 + "com",
-+        ValidationError,
-+    ),
-+    (
-+        URLValidator(),
-+        "http://userid:password" + "d" * 2000 + "@example.aaaaaaaaaaaaa.com",
-+        None,
-+    ),
-     # Newlines and tabs are not accepted.
-     (URLValidator(), 'http://www.djangoproject.com/\n', ValidationError),
-     (URLValidator(), 'http://[::ffff:192.9.5.5]\n', ValidationError),
diff --git a/CVE-2023-41164.patch b/CVE-2023-41164.patch
deleted file mode 100644
index ad4bd06c8699a093321834ef337f6cbfae1dd30e..0000000000000000000000000000000000000000
--- a/CVE-2023-41164.patch
+++ /dev/null
@@ -1,83 +0,0 @@
-From 6f030b1149bd8fa4ba90452e77cb3edc095ce54e Mon Sep 17 00:00:00 2001
-From: Mariusz Felisiak 
-Date: Tue, 22 Aug 2023 08:53:03 +0200
-Subject: [PATCH] [3.2.x] Fixed CVE-2023-41164 -- Fixed potential DoS in
- django.utils.encoding.uri_to_iri().
-
-Thanks MProgrammer (https://hackerone.com/mprogrammer) for the report.
-
-Origin: https://github.com/django/django/commit/6f030b1149bd8fa4ba90452e77cb3edc095ce54e
-
-Co-authored-by: nessita <124304+nessita@users.noreply.github.com>
----
- django/utils/encoding.py           |  6 ++++--
- docs/releases/3.2.21.txt           |  7 ++++++-
- tests/utils_tests/test_encoding.py | 21 ++++++++++++++++++++-
- 3 files changed, 30 insertions(+), 4 deletions(-)
-
-diff --git a/django/utils/encoding.py b/django/utils/encoding.py
-index e1ebacef4705..c5c4463b1c22 100644
---- a/django/utils/encoding.py
-+++ b/django/utils/encoding.py
-@@ -229,6 +229,7 @@ def repercent_broken_unicode(path):
-     repercent-encode any octet produced that is not part of a strictly legal
-     UTF-8 octet sequence.
-     """
-+    changed_parts = []
-     while True:
-         try:
-             path.decode()
-@@ -236,9 +237,10 @@ def repercent_broken_unicode(path):
-             # CVE-2019-14235: A recursion shouldn't be used since the exception
-             # handling uses massive amounts of memory
-             repercent = quote(path[e.start:e.end], safe=b"/#%[]=:;$&()+,!?*@'~")
--            path = path[:e.start] + repercent.encode() + path[e.end:]
-+            changed_parts.append(path[:e.start] + repercent.encode())
-+            path = path[e.end:]
-         else:
--            return path
-+            return b"".join(changed_parts) + path
- 
- 
- def filepath_to_uri(path):
-diff --git a/tests/utils_tests/test_encoding.py b/tests/utils_tests/test_encoding.py
-index 36f2d8665f3c..42779050cb3a 100644
---- a/tests/utils_tests/test_encoding.py
-+++ b/tests/utils_tests/test_encoding.py
-@@ -1,9 +1,10 @@
- import datetime
-+import inspect
- import sys
- import unittest
- from pathlib import Path
- from unittest import mock
--from urllib.parse import quote_plus
-+from urllib.parse import quote, quote_plus
- 
- from django.test import SimpleTestCase
- from django.utils.encoding import (
-@@ -101,6 +102,24 @@ def test_repercent_broken_unicode_recursion_error(self):
-         except RecursionError:
-             self.fail('Unexpected RecursionError raised.')
- 
-+    def test_repercent_broken_unicode_small_fragments(self):
-+        data = b"test\xfctest\xfctest\xfc"
-+        decoded_paths = []
-+
-+        def mock_quote(*args, **kwargs):
-+            # The second frame is the call to repercent_broken_unicode().
-+            decoded_paths.append(inspect.currentframe().f_back.f_locals["path"])
-+            return quote(*args, **kwargs)
-+
-+        with mock.patch("django.utils.encoding.quote", mock_quote):
-+            self.assertEqual(repercent_broken_unicode(data), b"test%FCtest%FCtest%FC")
-+
-+        # decode() is called on smaller fragment of the path each time.
-+        self.assertEqual(
-+            decoded_paths,
-+            [b"test\xfctest\xfctest\xfc", b"test\xfctest\xfc", b"test\xfc"],
-+        )
-+
- 
- class TestRFC3987IEncodingUtils(unittest.TestCase):
-
diff --git a/CVE-2023-43665.patch b/CVE-2023-43665.patch
deleted file mode 100644
index 523934e792255f63dbf6fd4ae0e75fc8010e4110..0000000000000000000000000000000000000000
--- a/CVE-2023-43665.patch
+++ /dev/null
@@ -1,168 +0,0 @@
-From ccdade1a0262537868d7ca64374de3d957ca50c5 Mon Sep 17 00:00:00 2001
-From: Natalia <124304+nessita@users.noreply.github.com>
-Date: Tue, 19 Sep 2023 09:51:48 -0300
-Subject: [PATCH] [3.2.x] Fixed CVE-2023-43665 -- Mitigated potential DoS in
- django.utils.text.Truncator when truncating HTML text.
-
-Thanks Wenchao Li of Alibaba Group for the report.
-
-Origin:
-https://github.com/django/django/commit/ccdade1a0262537868d7ca64374de3d957ca50c5
----
- django/utils/text.py            | 18 ++++++++++++++++-
- docs/ref/templates/builtins.txt | 20 +++++++++++++++++++
- tests/utils_tests/test_text.py  | 35 ++++++++++++++++++++++++---------
- 3 files changed, 63 insertions(+), 10 deletions(-)
-
-diff --git a/django/utils/text.py b/django/utils/text.py
-index baa44f2..83e258f 100644
---- a/django/utils/text.py
-+++ b/django/utils/text.py
-@@ -60,7 +60,14 @@ def wrap(text, width):
- class Truncator(SimpleLazyObject):
-     """
-     An object used to truncate text, either by characters or words.
-+
-+    When truncating HTML text (either chars or words), input will be limited to
-+    at most `MAX_LENGTH_HTML` characters.
-     """
-+
-+    # 5 million characters are approximately 4000 text pages or 3 web pages.
-+    MAX_LENGTH_HTML = 5_000_000
-+
-     def __init__(self, text):
-         super().__init__(lambda: str(text))
- 
-@@ -157,6 +164,11 @@ class Truncator(SimpleLazyObject):
-         if words and length <= 0:
-             return ''
- 
-+        size_limited = False
-+        if len(text) > self.MAX_LENGTH_HTML:
-+            text = text[: self.MAX_LENGTH_HTML]
-+            size_limited = True
-+
-         html4_singlets = (
-             'br', 'col', 'link', 'base', 'img',
-             'param', 'area', 'hr', 'input'
-@@ -206,10 +218,14 @@ class Truncator(SimpleLazyObject):
-                 # Add it to the start of the open tags list
-                 open_tags.insert(0, tagname)
- 
-+        truncate_text = self.add_truncation_text("", truncate)
-+
-         if current_len <= length:
-+            if size_limited and truncate_text:
-+                text += truncate_text
-             return text
-+
-         out = text[:end_text_pos]
--        truncate_text = self.add_truncation_text('', truncate)
-         if truncate_text:
-             out += truncate_text
-         # Close any tags still open
-diff --git a/docs/ref/templates/builtins.txt b/docs/ref/templates/builtins.txt
-index 22509a2..a6fd971 100644
---- a/docs/ref/templates/builtins.txt
-+++ b/docs/ref/templates/builtins.txt
-@@ -2348,6 +2348,16 @@ If ``value`` is ``"Joel is a slug
"``, the output will be
- 
- Newlines in the HTML content will be preserved.
- 
-+.. admonition:: Size of input string
-+
-+    Processing large, potentially malformed HTML strings can be
-+    resource-intensive and impact service performance. ``truncatechars_html``
-+    limits input to the first five million characters.
-+
-+.. versionchanged:: 3.2.22
-+
-+    In older versions, strings over five million characters were processed.
-+
- .. templatefilter:: truncatewords
- 
- ``truncatewords``
-@@ -2386,6 +2396,16 @@ If ``value`` is ``"Joel is a slug
"``, the output will be
- 
- Newlines in the HTML content will be preserved.
- 
-+.. admonition:: Size of input string
-+
-+    Processing large, potentially malformed HTML strings can be
-+    resource-intensive and impact service performance. ``truncatewords_html``
-+    limits input to the first five million characters.
-+
-+.. versionchanged:: 3.2.22
-+
-+    In older versions, strings over five million characters were processed.
-+
- .. templatefilter:: unordered_list
- 
- ``unordered_list``
-diff --git a/tests/utils_tests/test_text.py b/tests/utils_tests/test_text.py
-index d2a94fc..0a6f0bc 100644
---- a/tests/utils_tests/test_text.py
-+++ b/tests/utils_tests/test_text.py
-@@ -1,5 +1,6 @@
- import json
- import sys
-+from unittest.mock import patch
- 
- from django.core.exceptions import SuspiciousFileOperation
- from django.test import SimpleTestCase, ignore_warnings
-@@ -90,11 +91,17 @@ class TestUtilsText(SimpleTestCase):
-         # lazy strings are handled correctly
-         self.assertEqual(text.Truncator(lazystr('The quick brown fox')).chars(10), 'The quick…')
- 
--    def test_truncate_chars_html(self):
-+    @patch("django.utils.text.Truncator.MAX_LENGTH_HTML", 10_000)
-+    def test_truncate_chars_html_size_limit(self):
-+        max_len = text.Truncator.MAX_LENGTH_HTML
-+        bigger_len = text.Truncator.MAX_LENGTH_HTML + 1
-+        valid_html = "Joel is a slug
"  # 14 chars
-         perf_test_values = [
--            (('', None),
--            ('&' * 50000, '&' * 9 + '…'),
--            ('_X<<<<<<<<<<<>', None),
-+            ("", None),
-+            ("", "", None),
-+            (valid_html * bigger_len, "Joel is a…
"),  # 10 chars
-         ]
-         for value, expected in perf_test_values:
-             with self.subTest(value=value):
-@@ -152,15 +159,25 @@ class TestUtilsText(SimpleTestCase):
-         truncator = text.Truncator('I <3 python, what about you?
')
-         self.assertEqual('I <3 python,…
', truncator.words(3, html=True))
- 
-+    @patch("django.utils.text.Truncator.MAX_LENGTH_HTML", 10_000)
-+    def test_truncate_words_html_size_limit(self):
-+        max_len = text.Truncator.MAX_LENGTH_HTML
-+        bigger_len = text.Truncator.MAX_LENGTH_HTML + 1
-+        valid_html = "Joel is a slug
"  # 4 words
-         perf_test_values = [
--            ('',
--            '&' * 50000,
--            '_X<<<<<<<<<<<>',
-+            ("", None),
-+            ("", "", None),
-+            (valid_html * bigger_len, valid_html * 12 + "Joel is…
"),  # 50 words
-         ]
--        for value in perf_test_values:
-+        for value, expected in perf_test_values:
-             with self.subTest(value=value):
-                 truncator = text.Truncator(value)
--                self.assertEqual(value, truncator.words(50, html=True))
-+                self.assertEqual(
-+                    expected if expected else value, truncator.words(50, html=True)
-+                )
- 
-     def test_wrap(self):
-         digits = '1234 67 9'
--- 
-2.30.0
-
diff --git a/CVE-2023-46695.patch b/CVE-2023-46695.patch
deleted file mode 100644
index 30f6c6ff13aabe3bfd23b5d3baea2b7652aac0e3..0000000000000000000000000000000000000000
--- a/CVE-2023-46695.patch
+++ /dev/null
@@ -1,62 +0,0 @@
-From f9a7fb8466a7ba4857eaf930099b5258f3eafb2b Mon Sep 17 00:00:00 2001
-From: Mariusz Felisiak 
-Date: Tue, 17 Oct 2023 11:48:32 +0200
-Subject: [PATCH] [3.2.x] Fixed CVE-2023-46695 -- Fixed potential DoS in
- UsernameField on Windows.
-
-Thanks MProgrammer (https://hackerone.com/mprogrammer) for the report.
----
- django/contrib/auth/forms.py   | 10 +++++++++-
- tests/auth_tests/test_forms.py |  8 +++++++-
- 2 files changed, 16 insertions(+), 2 deletions(-)
-
-diff --git a/django/contrib/auth/forms.py b/django/contrib/auth/forms.py
-index 20d8922..fb7cfda 100644
---- a/django/contrib/auth/forms.py
-+++ b/django/contrib/auth/forms.py
-@@ -62,7 +62,15 @@ class ReadOnlyPasswordHashField(forms.Field):
- 
- class UsernameField(forms.CharField):
-     def to_python(self, value):
--        return unicodedata.normalize('NFKC', super().to_python(value))
-+        value = super().to_python(value)
-+        if self.max_length is not None and len(value) > self.max_length:
-+            # Normalization can increase the string length (e.g.
-+            # "ff" -> "ff", "½" -> "1⁄2") but cannot reduce it, so there is no
-+            # point in normalizing invalid data. Moreover, Unicode
-+            # normalization is very slow on Windows and can be a DoS attack
-+            # vector.
-+            return value
-+        return unicodedata.normalize("NFKC", value)
- 
-     def widget_attrs(self, widget):
-         return {
-diff --git a/tests/auth_tests/test_forms.py b/tests/auth_tests/test_forms.py
-index 7a731be..c0e1975 100644
---- a/tests/auth_tests/test_forms.py
-+++ b/tests/auth_tests/test_forms.py
-@@ -5,7 +5,7 @@ from unittest import mock
- from django.contrib.auth.forms import (
-     AdminPasswordChangeForm, AuthenticationForm, PasswordChangeForm,
-     PasswordResetForm, ReadOnlyPasswordHashField, ReadOnlyPasswordHashWidget,
--    SetPasswordForm, UserChangeForm, UserCreationForm,
-+    SetPasswordForm, UserChangeForm, UserCreationForm, UsernameField,
- )
- from django.contrib.auth.models import User
- from django.contrib.auth.signals import user_login_failed
-@@ -132,6 +132,12 @@ class UserCreationFormTest(TestDataMixin, TestCase):
-         self.assertNotEqual(user.username, ohm_username)
-         self.assertEqual(user.username, 'testΩ')  # U+03A9 GREEK CAPITAL LETTER OMEGA
- 
-+    def test_invalid_username_no_normalize(self):
-+        field = UsernameField(max_length=254)
-+        # Usernames are not normalized if they are too long.
-+        self.assertEqual(field.to_python("½" * 255), "½" * 255)
-+        self.assertEqual(field.to_python("ff" * 254), "ff" * 254)
-+
-     def test_duplicate_normalized_unicode(self):
-         """
-         To prevent almost identical usernames, visually identical but differing
--- 
-2.30.0
-
diff --git a/CVE-2024-24680.patch b/CVE-2024-24680.patch
deleted file mode 100644
index 3d8ab4dcf517deafb344c24af51b17eba0d159cf..0000000000000000000000000000000000000000
--- a/CVE-2024-24680.patch
+++ /dev/null
@@ -1,204 +0,0 @@
-From c1171ffbd570db90ca206c30f8e2b9f691243820 Mon Sep 17 00:00:00 2001
-From: Adam Johnson 
-Date: Mon, 22 Jan 2024 13:21:13 +0000
-Subject: [PATCH] [3.2.x] Fixed CVE-2024-24680 -- Mitigated potential DoS in
- intcomma template filter.
-
-Thanks Seokchan Yoon for the report.
-
-Co-authored-by: Mariusz Felisiak 
-Co-authored-by: Natalia <124304+nessita@users.noreply.github.com>
-Co-authored-by: Shai Berger 
----
- .../contrib/humanize/templatetags/humanize.py |  13 +-
- tests/humanize_tests/tests.py                 | 140 ++++++++++++++++--
- 2 files changed, 135 insertions(+), 18 deletions(-)
-
-diff --git a/django/contrib/humanize/templatetags/humanize.py b/django/contrib/humanize/templatetags/humanize.py
-index 753a0d9..238aaf2 100644
---- a/django/contrib/humanize/templatetags/humanize.py
-+++ b/django/contrib/humanize/templatetags/humanize.py
-@@ -70,12 +70,13 @@ def intcomma(value, use_l10n=True):
-             return intcomma(value, False)
-         else:
-             return number_format(value, use_l10n=True, force_grouping=True)
--    orig = str(value)
--    new = re.sub(r"^(-?\d+)(\d{3})", r'\g<1>,\g<2>', orig)
--    if orig == new:
--        return new
--    else:
--        return intcomma(new, use_l10n)
-+    result = str(value)
-+    match = re.match(r"-?\d+", result)
-+    if match:
-+        prefix = match[0]
-+        prefix_with_commas = re.sub(r"\d{3}", r"\g<0>,", prefix[::-1])[::-1]
-+        result = prefix_with_commas + result[len(prefix) :]
-+    return result
- 
- 
- # A tuple of standard large number to their converters
-diff --git a/tests/humanize_tests/tests.py b/tests/humanize_tests/tests.py
-index a0d16bb..3c22787 100644
---- a/tests/humanize_tests/tests.py
-+++ b/tests/humanize_tests/tests.py
-@@ -66,28 +66,144 @@ class HumanizeTests(SimpleTestCase):
- 
-     def test_intcomma(self):
-         test_list = (
--            100, 1000, 10123, 10311, 1000000, 1234567.25, '100', '1000',
--            '10123', '10311', '1000000', '1234567.1234567',
--            Decimal('1234567.1234567'), None,
-+            100,
-+            -100,
-+            1000,
-+            -1000,
-+            10123,
-+            -10123,
-+            10311,
-+            -10311,
-+            1000000,
-+            -1000000,
-+            1234567.25,
-+            -1234567.25,
-+            "100",
-+            "-100",
-+            "1000",
-+            "-1000",
-+            "10123",
-+            "-10123",
-+            "10311",
-+            "-10311",
-+            "1000000",
-+            "-1000000",
-+            "1234567.1234567",
-+            "-1234567.1234567",
-+            Decimal("1234567.1234567"),
-+            Decimal("-1234567.1234567"),
-+            None,
-+            "1234567",
-+            "-1234567",
-+            "1234567.12",
-+            "-1234567.12",
-+            "the quick brown fox jumped over the lazy dog",
-         )
-         result_list = (
--            '100', '1,000', '10,123', '10,311', '1,000,000', '1,234,567.25',
--            '100', '1,000', '10,123', '10,311', '1,000,000', '1,234,567.1234567',
--            '1,234,567.1234567', None,
-+            "100",
-+            "-100",
-+            "1,000",
-+            "-1,000",
-+            "10,123",
-+            "-10,123",
-+            "10,311",
-+            "-10,311",
-+            "1,000,000",
-+            "-1,000,000",
-+            "1,234,567.25",
-+            "-1,234,567.25",
-+            "100",
-+            "-100",
-+            "1,000",
-+            "-1,000",
-+            "10,123",
-+            "-10,123",
-+            "10,311",
-+            "-10,311",
-+            "1,000,000",
-+            "-1,000,000",
-+            "1,234,567.1234567",
-+            "-1,234,567.1234567",
-+            "1,234,567.1234567",
-+            "-1,234,567.1234567",
-+            None,
-+            "1,234,567",
-+            "-1,234,567",
-+            "1,234,567.12",
-+            "-1,234,567.12",
-+            "the quick brown fox jumped over the lazy dog",
-         )
-         with translation.override('en'):
-             self.humanize_tester(test_list, result_list, 'intcomma')
- 
-     def test_l10n_intcomma(self):
-         test_list = (
--            100, 1000, 10123, 10311, 1000000, 1234567.25, '100', '1000',
--            '10123', '10311', '1000000', '1234567.1234567',
--            Decimal('1234567.1234567'), None,
-+            100,
-+            -100,
-+            1000,
-+            -1000,
-+            10123,
-+            -10123,
-+            10311,
-+            -10311,
-+            1000000,
-+            -1000000,
-+            1234567.25,
-+            -1234567.25,
-+            "100",
-+            "-100",
-+            "1000",
-+            "-1000",
-+            "10123",
-+            "-10123",
-+            "10311",
-+            "-10311",
-+            "1000000",
-+            "-1000000",
-+            "1234567.1234567",
-+            "-1234567.1234567",
-+            Decimal("1234567.1234567"),
-+            -Decimal("1234567.1234567"),
-+            None,
-+            "1234567",
-+            "-1234567",
-+            "1234567.12",
-+            "-1234567.12",
-+            "the quick brown fox jumped over the lazy dog",
-         )
-         result_list = (
--            '100', '1,000', '10,123', '10,311', '1,000,000', '1,234,567.25',
--            '100', '1,000', '10,123', '10,311', '1,000,000', '1,234,567.1234567',
--            '1,234,567.1234567', None,
-+            "100",
-+            "-100",
-+            "1,000",
-+            "-1,000",
-+            "10,123",
-+            "-10,123",
-+            "10,311",
-+            "-10,311",
-+            "1,000,000",
-+            "-1,000,000",
-+            "1,234,567.25",
-+            "-1,234,567.25",
-+            "100",
-+            "-100",
-+            "1,000",
-+            "-1,000",
-+            "10,123",
-+            "-10,123",
-+            "10,311",
-+            "-10,311",
-+            "1,000,000",
-+            "-1,000,000",
-+            "1,234,567.1234567",
-+            "-1,234,567.1234567",
-+            "1,234,567.1234567",
-+            "-1,234,567.1234567",
-+            None,
-+            "1,234,567",
-+            "-1,234,567",
-+            "1,234,567.12",
-+            "-1,234,567.12",
-+            "the quick brown fox jumped over the lazy dog",
-         )
-         with self.settings(USE_L10N=True, USE_THOUSAND_SEPARATOR=False):
-             with translation.override('en'):
--- 
-2.33.0
-
diff --git a/CVE-2024-27351.patch b/CVE-2024-27351.patch
deleted file mode 100644
index 606f75529c7e55207151494400c465390f714941..0000000000000000000000000000000000000000
--- a/CVE-2024-27351.patch
+++ /dev/null
@@ -1,122 +0,0 @@
-From 072963e4c4d0b3a7a8c5412bc0c7d27d1a9c3521 Mon Sep 17 00:00:00 2001
-From: Shai Berger 
-Date: Mon, 19 Feb 2024 13:56:37 +0100
-Subject: [PATCH] [3.2.x] Fixed CVE-2024-27351 -- Prevented potential ReDoS in
- Truncator.words().
-
-Thanks Seokchan Yoon for the report.
-
-Co-Authored-By: Mariusz Felisiak 
----
- django/utils/text.py           | 57 ++++++++++++++++++++++++++++++++--
- tests/utils_tests/test_text.py | 26 ++++++++++++++++
- 2 files changed, 81 insertions(+), 2 deletions(-)
-
-diff --git a/django/utils/text.py b/django/utils/text.py
-index 83e258f..88da9a2 100644
---- a/django/utils/text.py
-+++ b/django/utils/text.py
-@@ -18,8 +18,61 @@ def capfirst(x):
-     return x and str(x)[0].upper() + str(x)[1:]
- 
- 
--# Set up regular expressions
--re_words = _lazy_re_compile(r'<[^>]+?>|([^<>\s]+)', re.S)
-+# ----- Begin security-related performance workaround -----
-+
-+# We used to have, below
-+#
-+# re_words = _lazy_re_compile(r"<[^>]+?>|([^<>\s]+)", re.S)
-+#
-+# But it was shown that this regex, in the way we use it here, has some
-+# catastrophic edge-case performance features. Namely, when it is applied to
-+# text with only open brackets "<<<...". The class below provides the services
-+# and correct answers for the use cases, but in these edge cases does it much
-+# faster.
-+re_notag = _lazy_re_compile(r"([^<>\s]+)", re.S)
-+re_prt = _lazy_re_compile(r"<|([^<>\s]+)", re.S)
-+
-+
-+class WordsRegex:
-+    @staticmethod
-+    def search(text, pos):
-+        # Look for "<" or a non-tag word.
-+        partial = re_prt.search(text, pos)
-+        if partial is None or partial[1] is not None:
-+            return partial
-+
-+        # "<" was found, look for a closing ">".
-+        end = text.find(">", partial.end(0))
-+        if end < 0:
-+            # ">" cannot be found, look for a word.
-+            return re_notag.search(text, pos + 1)
-+        else:
-+            # "<" followed by a ">" was found -- fake a match.
-+            end += 1
-+            return FakeMatch(text[partial.start(0): end], end)
-+
-+
-+class FakeMatch:
-+    __slots__ = ["_text", "_end"]
-+
-+    def end(self, group=0):
-+        assert group == 0, "This specific object takes only group=0"
-+        return self._end
-+
-+    def __getitem__(self, group):
-+        if group == 1:
-+            return None
-+        assert group == 0, "This specific object takes only group in {0,1}"
-+        return self._text
-+
-+    def __init__(self, text, end):
-+        self._text, self._end = text, end
-+
-+
-+# ----- End security-related performance workaround -----
-+
-+# Set up regular expressions.
-+re_words = WordsRegex
- re_chars = _lazy_re_compile(r'<[^>]+?>|(.)', re.S)
- re_tag = _lazy_re_compile(r'<(/)?(\S+?)(?:(\s*/)|\s.*?)?>', re.S)
- re_newlines = _lazy_re_compile(r'\r\n|\r')  # Used in normalize_newlines
-diff --git a/tests/utils_tests/test_text.py b/tests/utils_tests/test_text.py
-index 0a6f0bc..758919c 100644
---- a/tests/utils_tests/test_text.py
-+++ b/tests/utils_tests/test_text.py
-@@ -159,6 +159,32 @@ class TestUtilsText(SimpleTestCase):
-         truncator = text.Truncator('I <3 python, what about you?
')
-         self.assertEqual('I <3 python,…
', truncator.words(3, html=True))
- 
-+        # Only open brackets.
-+        test = "<" * 60_000
-+        truncator = text.Truncator(test)
-+        self.assertEqual(truncator.words(1, html=True), test)
-+
-+        # Tags with special chars in attrs.
-+        truncator = text.Truncator(
-+            """Hello, my dear lady! """
-+        )
-+        self.assertEqual(
-+            """Hello, my dear… """,
-+            truncator.words(3, html=True),
-+        )
-+
-+        # Tags with special non-latin chars in attrs.
-+        truncator = text.Truncator("""Hello, my dear lady!
""")
-+        self.assertEqual(
-+            """Hello, my dear…
""",
-+            truncator.words(3, html=True),
-+        )
-+
-+        # Misplaced brackets.
-+        truncator = text.Truncator("hello >< world")
-+        self.assertEqual(truncator.words(1, html=True), "hello…")
-+        self.assertEqual(truncator.words(2, html=True), "hello >< world")
-+
-     @patch("django.utils.text.Truncator.MAX_LENGTH_HTML", 10_000)
-     def test_truncate_words_html_size_limit(self):
-         max_len = text.Truncator.MAX_LENGTH_HTML
--- 
-2.33.0
-
diff --git a/3.2.12.tar.gz b/Django-4.2.15.tar.gz
similarity index 53%
rename from 3.2.12.tar.gz
rename to Django-4.2.15.tar.gz
index 6233704040e9580429c8f4a1a77a5311ed24db39..c77fade850f7089ec82208edd58c16b145e211f3 100644
Binary files a/3.2.12.tar.gz and b/Django-4.2.15.tar.gz differ
diff --git a/backport-CVE-2022-36359.patch b/backport-CVE-2022-36359.patch
deleted file mode 100644
index 97dc3ff6ee85773ee3922c0a9caa77c368d95a43..0000000000000000000000000000000000000000
--- a/backport-CVE-2022-36359.patch
+++ /dev/null
@@ -1,74 +0,0 @@
-From 8c5a1dfe34ea52cc2af21064a8654bfaa8b7a012 Mon Sep 17 00:00:00 2001
-From: Carlton Gibson 
-Date: Wed, 27 Jul 2022 10:27:42 +0200
-Subject: [PATCH] [3.2.x] Fixed CVE-2022-36359: Escaped filename in
- Content-Disposition header.
-
-Thanks to Motoyasu Saburi for the report.
----
- django/http/response.py              |  4 +++-
- docs/releases/3.2.15.txt             |  8 ++++++-
- tests/responses/test_fileresponse.py | 35 ++++++++++++++++++++++++++++
- 3 files changed, 45 insertions(+), 2 deletions(-)
-
-diff --git a/django/http/response.py b/django/http/response.py
-index 1c22edaff3..73f87d7bda 100644
---- a/django/http/response.py
-+++ b/django/http/response.py
-@@ -485,7 +485,9 @@ class FileResponse(StreamingHttpResponse):
-             disposition = 'attachment' if self.as_attachment else 'inline'
-             try:
-                 filename.encode('ascii')
--                file_expr = 'filename="{}"'.format(filename)
-+                file_expr = 'filename="{}"'.format(
-+                    filename.replace('\\', '\\\\').replace('"', r'\"')
-+                )
-             except UnicodeEncodeError:
-                 file_expr = "filename*=utf-8''{}".format(quote(filename))
-             self.headers['Content-Disposition'] = '{}; {}'.format(disposition, file_expr)
-diff --git a/tests/responses/test_fileresponse.py b/tests/responses/test_fileresponse.py
-index 46d407bdf5..b4ef82ef3e 100644
---- a/tests/responses/test_fileresponse.py
-+++ b/tests/responses/test_fileresponse.py
-@@ -89,3 +89,38 @@ class FileResponseTests(SimpleTestCase):
-             response.headers['Content-Disposition'],
-             "attachment; filename*=utf-8''%E7%A5%9D%E6%82%A8%E5%B9%B3%E5%AE%89.odt"
-         )
-+
-+    def test_content_disposition_escaping(self):
-+        # fmt: off
-+        tests = [
-+            (
-+                'multi-part-one";\" dummy".txt',
-+                r"multi-part-one\";\" dummy\".txt"
-+            ),
-+        ]
-+        # fmt: on
-+        # Non-escape sequence backslashes are path segments on Windows, and are
-+        # eliminated by an os.path.basename() check in FileResponse.
-+        if sys.platform != "win32":
-+            # fmt: off
-+            tests += [
-+                (
-+                    'multi-part-one\\";\" dummy".txt',
-+                    r"multi-part-one\\\";\" dummy\".txt"
-+                ),
-+                (
-+                    'multi-part-one\\";\\\" dummy".txt',
-+                    r"multi-part-one\\\";\\\" dummy\".txt"
-+                )
-+            ]
-+            # fmt: on
-+        for filename, escaped in tests:
-+            with self.subTest(filename=filename, escaped=escaped):
-+                response = FileResponse(
-+                    io.BytesIO(b"binary content"), filename=filename, as_attachment=True
-+                )
-+                response.close()
-+                self.assertEqual(
-+                    response.headers["Content-Disposition"],
-+                    f'attachment; filename="{escaped}"',
-+                )
--- 
-2.36.1
-
diff --git a/python-django.spec b/python-django.spec
index 8f6c515fa2bbb3d7057e5eeec2c9e00d4433d19c..aa3ef771213e3d7701f883cc9d31508f9dba6e98 100644
--- a/python-django.spec
+++ b/python-django.spec
@@ -1,28 +1,11 @@
 %global _empty_manifest_terminate_build 0
 Name:		python-django
-Version:	3.2.12
-Release:	10
+Version:	4.2.15
+Release:	1
 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://github.com/django/django/archive/refs/tags/%{version}.tar.gz
-
-#https://github.com/django/django/commit/a9010fe5555e6086a9d9ae50069579400ef0685e
-Patch0:         CVE-2022-34265.patch
-Patch1:         backport-CVE-2022-36359.patch
-Patch2:         CVE-2023-23969.patch
-Patch3:         CVE-2023-24580.patch
-Patch4:         CVE-2023-31047.patch
-Patch5:         CVE-2023-36053.patch
-Patch6:         CVE-2023-41164.patch
-# https://github.com/django/django/commit/ccdade1a0262537868d7ca64374de3d957ca50c5
-Patch7:         CVE-2023-43665.patch
-# https://github.com/django/django/commit/f9a7fb8466a7ba4857eaf930099b5258f3eafb2b
-Patch8:         CVE-2023-46695.patch
-# https://github.com/django/django/commit/c1171ffbd570db90ca206c30f8e2b9f691243820
-Patch9:         CVE-2024-24680.patch
-# https://github.com/django/django/commit/072963e4c4d0b3a7a8c5412bc0c7d27d1a9c3521
-Patch10:        CVE-2024-27351.patch
+Source0:        https://files.pythonhosted.org/packages/source/d/Django/Django-%{version}.tar.gz
 
 BuildArch:	noarch
 %description
@@ -49,7 +32,7 @@ Provides:	python3-Django-doc
 Development documents and examples for Django
 
 %prep
-%autosetup -n django-%{version} -p1
+%autosetup -n Django-%{version} -p1
 
 %build
 %py3_build
@@ -89,6 +72,19 @@ mv %{buildroot}/doclist.lst .
 %{_docdir}/*
 
 %changelog
+* Thu Aug 08 2024 yaoxin  - 4.2.15-1
+- Update to 4.2.15
+  * CVE-2024-41989: Memory exhaustion in ``django.utils.numberformat.floatformat()``
+  * CVE-2024-41990: Potential denial-of-service vulnerability in ``django.utils.html.urlize()``
+  * CVE-2024-41991: Potential denial-of-service vulnerability in ``django.utils.html.urlize()`` and ``AdminURLFieldWidget``
+  * CVE-2024-42005: Potential SQL injection in ``QuerySet.values()`` and ``values_list()``
+  * Fixed a regression in Django 4.2.14 that caused a crash in ``LocaleMiddleware`` when processing a language code over 500 characters
+  * CVE-2024-38875: Potential denial-of-service vulnerability in django.utils.html.urlize()
+  * CVE-2024-39329: Username enumeration through timing difference for users with unusable passwords
+  * CVE-2024-39330: Potential directory-traversal via Storage.save()
+  * CVE-2024-39614: Potential denial-of-service vulnerability in get_supported_language_variant()
+  * Fixed a crash in Django 4.2 when validating email max line lengths with content decoded using the surrogateescape error handling scheme
+
 * Tue Mar 05 2024 yaoxin  - 3.2.12-10
 - Fix CVE-2024-27351