diff -Nru python-django-3.2.18/debian/changelog python-django-3.2.18/debian/changelog
--- python-django-3.2.18/debian/changelog 2023-09-15 12:39:57.000000000 +0000
+++ python-django-3.2.18/debian/changelog 2023-09-27 17:00:07.000000000 +0000
@@ -1,3 +1,12 @@
+python-django (3:3.2.18-1ubuntu0.5) lunar-security; urgency=medium
+
+ * SECURITY UPDATE: DoS possibility in django.utils.text.Truncator
+ - debian/patches/CVE-2023-43665.patch: limit size of input strings in
+ django/utils/text.py, tests/utils_tests/test_text.py.
+ - CVE-2023-43665
+
+ -- Marc Deslauriers Wed, 27 Sep 2023 13:00:07 -0400
+
python-django (3:3.2.18-1ubuntu0.4) lunar-security; urgency=medium
* SECURITY UPDATE: DoS in django.utils.encoding.uri_to_iri()
diff -Nru python-django-3.2.18/debian/patches/CVE-2023-43665.patch python-django-3.2.18/debian/patches/CVE-2023-43665.patch
--- python-django-3.2.18/debian/patches/CVE-2023-43665.patch 1970-01-01 00:00:00.000000000 +0000
+++ python-django-3.2.18/debian/patches/CVE-2023-43665.patch 2023-09-27 17:00:01.000000000 +0000
@@ -0,0 +1,208 @@
+From 9931bc592f255064ee0d31b54fc32e62f13b5eeb 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.
+---
+ django/utils/text.py | 18 ++++++++++++++++-
+ docs/ref/templates/builtins.txt | 20 +++++++++++++++++++
+ docs/releases/3.2.22.txt | 25 +++++++++++++++++++++++
+ docs/releases/index.txt | 1 +
+ tests/utils_tests/test_text.py | 35 ++++++++++++++++++++++++---------
+ 5 files changed, 89 insertions(+), 10 deletions(-)
+ create mode 100644 docs/releases/3.2.22.txt
+
+#diff --git a/docs/ref/templates/builtins.txt b/docs/ref/templates/builtins.txt
+#index 22509a2a7e..a6fd97175b 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/docs/releases/3.2.22.txt b/docs/releases/3.2.22.txt
+#new file mode 100644
+#index 0000000000..cfedc41de8
+#--- /dev/null
+#+++ b/docs/releases/3.2.22.txt
+#@@ -0,0 +1,25 @@
+#+===========================
+#+Django 3.2.22 release notes
+#+===========================
+#+
+#+*October 4, 2023*
+#+
+#+Django 3.2.22 fixes a security issue with severity "moderate" in 3.2.21.
+#+
+#+CVE-2023-43665: Denial-of-service possibility in ``django.utils.text.Truncator``
+#+================================================================================
+#+
+#+Following the fix for :cve:`2019-14232`, the regular expressions used in the
+#+implementation of ``django.utils.text.Truncator``'s ``chars()`` and ``words()``
+#+methods (with ``html=True``) were revised and improved. However, these regular
+#+expressions still exhibited linear backtracking complexity, so when given a
+#+very long, potentially malformed HTML input, the evaluation would still be
+#+slow, leading to a potential denial of service vulnerability.
+#+
+#+The ``chars()`` and ``words()`` methods are used to implement the
+#+:tfilter:`truncatechars_html` and :tfilter:`truncatewords_html` template
+#+filters, which were thus also vulnerable.
+#+
+#+The input processed by ``Truncator``, when operating in HTML mode, has been
+#+limited to the first five million characters in order to avoid potential
+#+performance and memory issues.
+#diff --git a/docs/releases/index.txt b/docs/releases/index.txt
+#index e0ae1b1580..b35f225b53 100644
+#--- a/docs/releases/index.txt
+#+++ b/docs/releases/index.txt
+#@@ -25,6 +25,7 @@ versions of the documentation contain the release notes for any later releases.
+# .. toctree::
+# :maxdepth: 1
+#
+#+ 3.2.22
+# 3.2.21
+# 3.2.20
+# 3.2.19
+diff --git a/django/utils/text.py b/django/utils/text.py
+index baa44f279e..83e258fa81 100644
+--- a/django/utils/text.py
++++ b/django/utils/text.py
+@@ -60,7 +60,14 @@ def _generator():
+ 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 @@ def _truncate_html(self, length, truncate, text, truncate_len, words):
+ 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 @@ def _truncate_html(self, length, truncate, text, truncate_len, words):
+ # 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/tests/utils_tests/test_text.py b/tests/utils_tests/test_text.py
+index d2a94fcdab..0a6f0bc3f2 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 @@ def test_truncate_chars(self):
+ # 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 @@ def test_truncate_html_words(self):
+ 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'
diff -Nru python-django-3.2.18/debian/patches/series python-django-3.2.18/debian/patches/series
--- python-django-3.2.18/debian/patches/series 2023-09-15 12:39:51.000000000 +0000
+++ python-django-3.2.18/debian/patches/series 2023-09-27 17:00:01.000000000 +0000
@@ -13,3 +13,4 @@
CVE-2023-36053.patch
fix-url-validator.patch
CVE-2023-41164.patch
+CVE-2023-43665.patch