new file mode 100644
@@ -0,0 +1,106 @@
+From e88f7376fe68dbf4ebaf11fad1513ce700b45860 Mon Sep 17 00:00:00 2001
+From: Sarah Boyce <42296566+sarahboyce@users.noreply.github.com>
+Date: Tue, 25 Feb 2025 09:40:54 +0100
+Subject: [PATCH] Fixed CVE-2025-26699 -- Mitigated potential DoS in wordwrap
+ template filter.
+
+Thanks sw0rd1ight for the report.
+
+Backport of 55d89e25f4115c5674cdd9b9bcba2bb2bb6d820b from main.
+
+CVE: CVE-2025-26699
+
+Upstream-Status: Backport
+https://github.com/django/django/commit/e88f7376fe68dbf4ebaf11fad1513ce700b45860
+
+Signed-off-by: Sarah Boyce <42296566+sarahboyce@users.noreply.github.com>
+Signed-off-by: Saravanan <saravanan.kadambathursubramaniyam@windriver.com>
+---
+ django/utils/text.py | 27 +++++++------------
+ docs/releases/3.2.25.txt | 6 +++++
+ .../filter_tests/test_wordwrap.py | 11 ++++++++
+ 3 files changed, 27 insertions(+), 17 deletions(-)
+
+diff --git a/django/utils/text.py b/django/utils/text.py
+index 88da9a2..cabd76f 100644
+--- a/django/utils/text.py
++++ b/django/utils/text.py
+@@ -1,5 +1,6 @@
+ import html.entities
+ import re
++import textwrap
+ import unicodedata
+ import warnings
+ from gzip import GzipFile
+@@ -91,23 +92,15 @@ def wrap(text, width):
+ Don't wrap long words, thus the output text may have lines longer than
+ ``width``.
+ """
+- def _generator():
+- for line in text.splitlines(True): # True keeps trailing linebreaks
+- max_width = min((line.endswith('\n') and width + 1 or width), width)
+- while len(line) > max_width:
+- space = line[:max_width + 1].rfind(' ') + 1
+- if space == 0:
+- space = line.find(' ') + 1
+- if space == 0:
+- yield line
+- line = ''
+- break
+- yield '%s\n' % line[:space - 1]
+- line = line[space:]
+- max_width = min((line.endswith('\n') and width + 1 or width), width)
+- if line:
+- yield line
+- return ''.join(_generator())
++ wrapper = textwrap.TextWrapper(
++ width=width,
++ break_long_words=False,
++ break_on_hyphens=False,
++ )
++ result = []
++ for line in text.splitlines(True):
++ result.extend(wrapper.wrap(line))
++ return "\n".join(result)
+
+
+ class Truncator(SimpleLazyObject):
+diff --git a/docs/releases/3.2.25.txt b/docs/releases/3.2.25.txt
+index a3a9098..f8d9ce2 100644
+--- a/docs/releases/3.2.25.txt
++++ b/docs/releases/3.2.25.txt
+@@ -15,6 +15,12 @@ CVE-2024-27351: Potential regular expression denial-of-service in ``django.utils
+ regular expression denial-of-service attack using a suitably crafted string
+ (follow up to :cve:`2019-14232` and :cve:`2023-43665`).
+
++CVE-2025-26699: Potential denial-of-service vulnerability in ``django.utils.text.wrap()``
++=========================================================================================
++
++The ``wrap()`` and :tfilter:`wordwrap` template filter were subject to a
++potential denial-of-service attack when used with very long strings.
++
+ Bugfixes
+ ========
+
+diff --git a/tests/template_tests/filter_tests/test_wordwrap.py b/tests/template_tests/filter_tests/test_wordwrap.py
+index 02f8605..f61842c 100644
+--- a/tests/template_tests/filter_tests/test_wordwrap.py
++++ b/tests/template_tests/filter_tests/test_wordwrap.py
+@@ -51,3 +51,14 @@ class FunctionTests(SimpleTestCase):
+ ), 14),
+ 'this is a long\nparagraph of\ntext that\nreally needs\nto be wrapped\nI\'m afraid',
+ )
++
++ def test_wrap_long_text(self):
++ long_text = (
++ "this is a long paragraph of text that really needs"
++ " to be wrapped I'm afraid " * 20_000
++ )
++ self.assertIn(
++ "this is a\nlong\nparagraph\nof text\nthat\nreally\nneeds to\nbe wrapped\n"
++ "I'm afraid",
++ wordwrap(long_text, 10),
++ )
+--
+2.40.0
+
new file mode 100644
@@ -0,0 +1,107 @@
+From e88f7376fe68dbf4ebaf11fad1513ce700b45860 Mon Sep 17 00:00:00 2001
+From: Sarah Boyce <42296566+sarahboyce@users.noreply.github.com>
+Date: Tue, 25 Feb 2025 09:40:54 +0100
+Subject: [PATCH] Fixed CVE-2025-26699 -- Mitigated potential DoS in wordwrap
+ template filter.
+
+Thanks sw0rd1ight for the report.
+
+Backport of 55d89e25f4115c5674cdd9b9bcba2bb2bb6d820b from main.
+
+CVE: CVE-2025-26699
+
+Upstream-Status: Backport
+https://github.com/django/django/commit/e88f7376fe68dbf4ebaf11fad1513ce700b45860
+
+Signed-off-by: Sarah Boyce <42296566+sarahboyce@users.noreply.github.com>
+Signed-off-by: Saravanan <saravanan.kadambathursubramaniyam@windriver.com>
+
+%% original patch: CVE-2025-26699.patch
+---
+ django/utils/text.py | 28 ++++++++-----------
+ docs/releases/2.2.28.txt | 6 ++++
+ .../filter_tests/test_wordwrap.py | 12 ++++++++
+ 3 files changed, 29 insertions(+), 17 deletions(-)
+
+diff --git a/django/utils/text.py b/django/utils/text.py
+index 2c4040e..c474d56 100644
+--- a/django/utils/text.py
++++ b/django/utils/text.py
+@@ -1,5 +1,6 @@
+ import html.entities
+ import re
++import textwrap
+ import unicodedata
+ from gzip import GzipFile
+ from io import BytesIO
+@@ -88,23 +89,16 @@ def wrap(text, width):
+ Don't wrap long words, thus the output text may have lines longer than
+ ``width``.
+ """
+- def _generator():
+- for line in text.splitlines(True): # True keeps trailing linebreaks
+- max_width = min((line.endswith('\n') and width + 1 or width), width)
+- while len(line) > max_width:
+- space = line[:max_width + 1].rfind(' ') + 1
+- if space == 0:
+- space = line.find(' ') + 1
+- if space == 0:
+- yield line
+- line = ''
+- break
+- yield '%s\n' % line[:space - 1]
+- line = line[space:]
+- max_width = min((line.endswith('\n') and width + 1 or width), width)
+- if line:
+- yield line
+- return ''.join(_generator())
++
++ wrapper = textwrap.TextWrapper(
++ width=width,
++ break_long_words=False,
++ break_on_hyphens=False,
++ )
++ result = []
++ for line in text.splitlines(True):
++ result.extend(wrapper.wrap(line))
++ return "\n".join(result)
+
+
+ class Truncator(SimpleLazyObject):
+diff --git a/docs/releases/2.2.28.txt b/docs/releases/2.2.28.txt
+index 7227452..7096d13 100644
+--- a/docs/releases/2.2.28.txt
++++ b/docs/releases/2.2.28.txt
+@@ -99,3 +99,9 @@ CVE-2024-27351: Potential regular expression denial-of-service in ``django.utils
+ regular expression denial-of-service attack using a suitably crafted string
+ (follow up to :cve:`2019-14232` and :cve:`2023-43665`).
+
++CVE-2025-26699: Potential denial-of-service vulnerability in ``django.utils.text.wrap()``
++=========================================================================================
++
++The ``wrap()`` and :tfilter:`wordwrap` template filter were subject to a
++potential denial-of-service attack when used with very long strings.
++
+diff --git a/tests/template_tests/filter_tests/test_wordwrap.py b/tests/template_tests/filter_tests/test_wordwrap.py
+index 02f8605..e6f2afb 100644
+--- a/tests/template_tests/filter_tests/test_wordwrap.py
++++ b/tests/template_tests/filter_tests/test_wordwrap.py
+@@ -51,3 +51,15 @@ class FunctionTests(SimpleTestCase):
+ ), 14),
+ 'this is a long\nparagraph of\ntext that\nreally needs\nto be wrapped\nI\'m afraid',
+ )
++
++ def test_wrap_long_text(self):
++ long_text = (
++ "this is a long paragraph of text that really needs"
++ " to be wrapped I'm afraid " * 20_000
++ )
++ self.assertIn(
++ "this is a\nlong\nparagraph\nof text\nthat\nreally\nneeds to\nbe wrapped\n"
++ "I'm afraid",
++ wordwrap(long_text, 10),
++ )
++
+--
+2.40.0
+
@@ -25,6 +25,7 @@ SRC_URI += "file://CVE-2023-31047.patch \
file://CVE-2024-45231.patch \
file://CVE-2024-53907.patch \
file://CVE-2024-27351.patch \
+ file://CVE-2025-26699.patch \
"
SRC_URI[sha256sum] = "0200b657afbf1bc08003845ddda053c7641b9b24951e52acd51f6abda33a7413"
@@ -6,6 +6,9 @@ SRC_URI[sha256sum] = "7ca38a78654aee72378594d63e51636c04b8e28574f5505dff630895b5
RDEPENDS:${PN} += "\
${PYTHON_PN}-sqlparse \
"
+SRC_URI += "\
+ file://CVE-2025-26699.patch \
+"
# Set DEFAULT_PREFERENCE so that the LTS version of django is built by
# default. To build the 3.x branch,
Reference: https://nvd.nist.gov/vuln/detail/CVE-2025-26699 Upstream-patch: https://github.com/django/django/commit/e88f7376fe68dbf4ebaf11fad1513ce700b45860 Signed-off-by: Saravanan <saravanan.kadambathursubramaniyam@windriver.com> --- .../CVE-2025-26699.patch | 106 +++++++++++++++++ .../python3-django/CVE-2025-26699.patch | 107 ++++++++++++++++++ .../python/python3-django_2.2.28.bb | 1 + .../python/python3-django_3.2.25.bb | 3 + 4 files changed, 217 insertions(+) create mode 100644 meta-python/recipes-devtools/python/python3-django-3.2.25/CVE-2025-26699.patch create mode 100644 meta-python/recipes-devtools/python/python3-django/CVE-2025-26699.patch