diff mbox series

[meta-python,scarthgap,2/8] python3-django: patch CVE-2025-26699

Message ID 20251022061803.887676-2-ankur.tyagi85@gmail.com
State New
Headers show
Series [meta-python,scarthgap,1/8] python3-django: upgrade 4.2.18 -> 4.2.20 | expand

Commit Message

Ankur Tyagi Oct. 22, 2025, 6:17 a.m. UTC
This fixes a regression in Django 4.2.20, introduced when fixing CVE-2025-26699

Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
---
 .../CVE-2025-26699.patch                      | 102 ++++++++++++++++++
 .../python/python3-django_4.2.20.bb           |   4 +
 2 files changed, 106 insertions(+)
 create mode 100644 meta-python/recipes-devtools/python/python3-django-4.2.20/CVE-2025-26699.patch

Comments

Gyorgy Sarvari Oct. 22, 2025, 9:48 a.m. UTC | #1
The patch looks correct and necessary to me, but I find the commit
subject and the CVE tag in the patch somewhat misleading. The CVE is
patched in 4.2.20, this patch is a fix for a regression that was caused
by the fix, but otherwise not related to the CVE.

I think the patch should just come as it is, with and explanation of
what is it, but without referring to it as a CVE fix.

On 10/22/25 08:17, Ankur Tyagi via lists.openembedded.org wrote:
> This fixes a regression in Django 4.2.20, introduced when fixing CVE-2025-26699
>
> Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
> ---
>  .../CVE-2025-26699.patch                      | 102 ++++++++++++++++++
>  .../python/python3-django_4.2.20.bb           |   4 +
>  2 files changed, 106 insertions(+)
>  create mode 100644 meta-python/recipes-devtools/python/python3-django-4.2.20/CVE-2025-26699.patch
>
> diff --git a/meta-python/recipes-devtools/python/python3-django-4.2.20/CVE-2025-26699.patch b/meta-python/recipes-devtools/python/python3-django-4.2.20/CVE-2025-26699.patch
> new file mode 100644
> index 0000000000..54a43b123d
> --- /dev/null
> +++ b/meta-python/recipes-devtools/python/python3-django-4.2.20/CVE-2025-26699.patch
> @@ -0,0 +1,102 @@
> +From 3407ea136bd619591d259221d8712b72b3f3b9a0 Mon Sep 17 00:00:00 2001
> +From: Matti Pohjanvirta <matti.pohjanvirta@iki.fi>
> +Date: Sun, 20 Apr 2025 18:22:51 +0300
> +Subject: [PATCH] [4.2.x] Fixed #36341 -- Preserved whitespaces in wordwrap
> + template filter.
> +
> +Regression in 55d89e25f4115c5674cdd9b9bcba2bb2bb6d820b.
> +
> +This work improves the django.utils.text.wrap() function to ensure that
> +empty lines and lines with whitespace only are kept instead of being
> +dropped.
> +
> +Thanks Matti Pohjanvirta for the report and fix.
> +
> +Co-authored-by: Natalia <124304+nessita@users.noreply.github.com>
> +
> +Backport of 1e9db35836d42a3c72f3d1015c2f302eb6fee046 from main.
> +
> +CVE: CVE-2025-26699
> +Upstream-Status: Backport [https://github.com/django/django/commit/e61e3daaf037507211028494d61f24382be31e5a]
> +(cherry picked from commit e61e3daaf037507211028494d61f24382be31e5a)
> +Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
> +---
> + django/utils/text.py                          | 13 +++++-
> + .../filter_tests/test_wordwrap.py             | 41 +++++++++++++++++++
> + 2 files changed, 52 insertions(+), 2 deletions(-)
> +
> +diff --git a/django/utils/text.py b/django/utils/text.py
> +index 81ae88dc76..b018f2601f 100644
> +--- a/django/utils/text.py
> ++++ b/django/utils/text.py
> +@@ -102,10 +102,19 @@ def wrap(text, width):
> +         width=width,
> +         break_long_words=False,
> +         break_on_hyphens=False,
> ++        replace_whitespace=False,
> +     )
> +     result = []
> +-    for line in text.splitlines(True):
> +-        result.extend(wrapper.wrap(line))
> ++    for line in text.splitlines():
> ++        wrapped = wrapper.wrap(line)
> ++        if not wrapped:
> ++            # If `line` contains only whitespaces that are dropped, restore it.
> ++            result.append(line)
> ++        else:
> ++            result.extend(wrapped)
> ++    if text.endswith("\n"):
> ++        # If `text` ends with a newline, preserve it.
> ++        result.append("")
> +     return "\n".join(result)
> + 
> + 
> +diff --git a/tests/template_tests/filter_tests/test_wordwrap.py b/tests/template_tests/filter_tests/test_wordwrap.py
> +index 4afa1dd234..1692332e1e 100644
> +--- a/tests/template_tests/filter_tests/test_wordwrap.py
> ++++ b/tests/template_tests/filter_tests/test_wordwrap.py
> +@@ -89,3 +89,44 @@ class FunctionTests(SimpleTestCase):
> +             "I'm afraid",
> +             wordwrap(long_text, 10),
> +         )
> ++
> ++    def test_wrap_preserve_newlines(self):
> ++        cases = [
> ++            (
> ++                "this is a long paragraph of text that really needs to be wrapped\n\n"
> ++                "that is followed by another paragraph separated by an empty line\n",
> ++                "this is a long paragraph of\ntext that really needs to be\nwrapped\n\n"
> ++                "that is followed by another\nparagraph separated by an\nempty line\n",
> ++                30,
> ++            ),
> ++            ("\n\n\n", "\n\n\n", 5),
> ++            ("\n\n\n\n\n\n", "\n\n\n\n\n\n", 5),
> ++        ]
> ++        for text, expected, width in cases:
> ++            with self.subTest(text=text):
> ++                self.assertEqual(wordwrap(text, width), expected)
> ++
> ++    def test_wrap_preserve_whitespace(self):
> ++        width = 5
> ++        width_spaces = " " * width
> ++        cases = [
> ++            (
> ++                f"first line\n{width_spaces}\nsecond line",
> ++                f"first\nline\n{width_spaces}\nsecond\nline",
> ++            ),
> ++            (
> ++                "first line\n \t\t\t \nsecond line",
> ++                "first\nline\n \t\t\t \nsecond\nline",
> ++            ),
> ++            (
> ++                f"first line\n{width_spaces}\nsecond line\n\nthird{width_spaces}\n",
> ++                f"first\nline\n{width_spaces}\nsecond\nline\n\nthird\n",
> ++            ),
> ++            (
> ++                f"first line\n{width_spaces}{width_spaces}\nsecond line",
> ++                f"first\nline\n{width_spaces}{width_spaces}\nsecond\nline",
> ++            ),
> ++        ]
> ++        for text, expected in cases:
> ++            with self.subTest(text=text):
> ++                self.assertEqual(wordwrap(text, width), expected)
> diff --git a/meta-python/recipes-devtools/python/python3-django_4.2.20.bb b/meta-python/recipes-devtools/python/python3-django_4.2.20.bb
> index 3fb8b03224..0b9ff1b8c0 100644
> --- a/meta-python/recipes-devtools/python/python3-django_4.2.20.bb
> +++ b/meta-python/recipes-devtools/python/python3-django_4.2.20.bb
> @@ -1,6 +1,10 @@
>  require python-django.inc
>  inherit setuptools3
>  
> +SRC_URI += " \
> +    file://CVE-2025-26699.patch \
> +"
> +
>  SRC_URI[sha256sum] = "92bac5b4432a64532abb73b2ac27203f485e40225d2640a7fbef2b62b876e789"
>  
>  RDEPENDS:${PN} += "\
>
> -=-=-=-=-=-=-=-=-=-=-=-
> Links: You receive all messages sent to this group.
> View/Reply Online (#120885): https://lists.openembedded.org/g/openembedded-devel/message/120885
> Mute This Topic: https://lists.openembedded.org/mt/115888203/6084445
> Group Owner: openembedded-devel+owner@lists.openembedded.org
> Unsubscribe: https://lists.openembedded.org/g/openembedded-devel/unsub [skandigraun@gmail.com]
> -=-=-=-=-=-=-=-=-=-=-=-
>
diff mbox series

Patch

diff --git a/meta-python/recipes-devtools/python/python3-django-4.2.20/CVE-2025-26699.patch b/meta-python/recipes-devtools/python/python3-django-4.2.20/CVE-2025-26699.patch
new file mode 100644
index 0000000000..54a43b123d
--- /dev/null
+++ b/meta-python/recipes-devtools/python/python3-django-4.2.20/CVE-2025-26699.patch
@@ -0,0 +1,102 @@ 
+From 3407ea136bd619591d259221d8712b72b3f3b9a0 Mon Sep 17 00:00:00 2001
+From: Matti Pohjanvirta <matti.pohjanvirta@iki.fi>
+Date: Sun, 20 Apr 2025 18:22:51 +0300
+Subject: [PATCH] [4.2.x] Fixed #36341 -- Preserved whitespaces in wordwrap
+ template filter.
+
+Regression in 55d89e25f4115c5674cdd9b9bcba2bb2bb6d820b.
+
+This work improves the django.utils.text.wrap() function to ensure that
+empty lines and lines with whitespace only are kept instead of being
+dropped.
+
+Thanks Matti Pohjanvirta for the report and fix.
+
+Co-authored-by: Natalia <124304+nessita@users.noreply.github.com>
+
+Backport of 1e9db35836d42a3c72f3d1015c2f302eb6fee046 from main.
+
+CVE: CVE-2025-26699
+Upstream-Status: Backport [https://github.com/django/django/commit/e61e3daaf037507211028494d61f24382be31e5a]
+(cherry picked from commit e61e3daaf037507211028494d61f24382be31e5a)
+Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
+---
+ django/utils/text.py                          | 13 +++++-
+ .../filter_tests/test_wordwrap.py             | 41 +++++++++++++++++++
+ 2 files changed, 52 insertions(+), 2 deletions(-)
+
+diff --git a/django/utils/text.py b/django/utils/text.py
+index 81ae88dc76..b018f2601f 100644
+--- a/django/utils/text.py
++++ b/django/utils/text.py
+@@ -102,10 +102,19 @@ def wrap(text, width):
+         width=width,
+         break_long_words=False,
+         break_on_hyphens=False,
++        replace_whitespace=False,
+     )
+     result = []
+-    for line in text.splitlines(True):
+-        result.extend(wrapper.wrap(line))
++    for line in text.splitlines():
++        wrapped = wrapper.wrap(line)
++        if not wrapped:
++            # If `line` contains only whitespaces that are dropped, restore it.
++            result.append(line)
++        else:
++            result.extend(wrapped)
++    if text.endswith("\n"):
++        # If `text` ends with a newline, preserve it.
++        result.append("")
+     return "\n".join(result)
+ 
+ 
+diff --git a/tests/template_tests/filter_tests/test_wordwrap.py b/tests/template_tests/filter_tests/test_wordwrap.py
+index 4afa1dd234..1692332e1e 100644
+--- a/tests/template_tests/filter_tests/test_wordwrap.py
++++ b/tests/template_tests/filter_tests/test_wordwrap.py
+@@ -89,3 +89,44 @@ class FunctionTests(SimpleTestCase):
+             "I'm afraid",
+             wordwrap(long_text, 10),
+         )
++
++    def test_wrap_preserve_newlines(self):
++        cases = [
++            (
++                "this is a long paragraph of text that really needs to be wrapped\n\n"
++                "that is followed by another paragraph separated by an empty line\n",
++                "this is a long paragraph of\ntext that really needs to be\nwrapped\n\n"
++                "that is followed by another\nparagraph separated by an\nempty line\n",
++                30,
++            ),
++            ("\n\n\n", "\n\n\n", 5),
++            ("\n\n\n\n\n\n", "\n\n\n\n\n\n", 5),
++        ]
++        for text, expected, width in cases:
++            with self.subTest(text=text):
++                self.assertEqual(wordwrap(text, width), expected)
++
++    def test_wrap_preserve_whitespace(self):
++        width = 5
++        width_spaces = " " * width
++        cases = [
++            (
++                f"first line\n{width_spaces}\nsecond line",
++                f"first\nline\n{width_spaces}\nsecond\nline",
++            ),
++            (
++                "first line\n \t\t\t \nsecond line",
++                "first\nline\n \t\t\t \nsecond\nline",
++            ),
++            (
++                f"first line\n{width_spaces}\nsecond line\n\nthird{width_spaces}\n",
++                f"first\nline\n{width_spaces}\nsecond\nline\n\nthird\n",
++            ),
++            (
++                f"first line\n{width_spaces}{width_spaces}\nsecond line",
++                f"first\nline\n{width_spaces}{width_spaces}\nsecond\nline",
++            ),
++        ]
++        for text, expected in cases:
++            with self.subTest(text=text):
++                self.assertEqual(wordwrap(text, width), expected)
diff --git a/meta-python/recipes-devtools/python/python3-django_4.2.20.bb b/meta-python/recipes-devtools/python/python3-django_4.2.20.bb
index 3fb8b03224..0b9ff1b8c0 100644
--- a/meta-python/recipes-devtools/python/python3-django_4.2.20.bb
+++ b/meta-python/recipes-devtools/python/python3-django_4.2.20.bb
@@ -1,6 +1,10 @@ 
 require python-django.inc
 inherit setuptools3
 
+SRC_URI += " \
+    file://CVE-2025-26699.patch \
+"
+
 SRC_URI[sha256sum] = "92bac5b4432a64532abb73b2ac27203f485e40225d2640a7fbef2b62b876e789"
 
 RDEPENDS:${PN} += "\