diff options
| author | Saravanan <saravanan.kadambathursubramaniyam@windriver.com> | 2025-12-04 19:21:06 +0530 |
|---|---|---|
| committer | Gyorgy Sarvari <skandigraun@gmail.com> | 2025-12-05 15:29:59 +0100 |
| commit | e2da1298ac289c855abb073e6499be590d09ecd0 (patch) | |
| tree | b8971460b53d3ae886c4a216c1439d3371cc9ca5 /meta-python | |
| parent | ee59faebac7de6ac25416bb887689ffc34d2ff4a (diff) | |
| download | meta-openembedded-e2da1298ac289c855abb073e6499be590d09ecd0.tar.gz | |
python3-django: fix CVE-2025-32873
Reference:
https://nvd.nist.gov/vuln/detail/CVE-2025-32873
Upstream-patch:
https://github.com/django/django/commit/9cd8028f3e38dca8e51c1388f474eecbe7d6ca3c/
Signed-off-by: Saravanan <saravanan.kadambathursubramaniyam@windriver.com>
Signed-off-by: Gyorgy Sarvari <skandigraun@gmail.com>
Diffstat (limited to 'meta-python')
4 files changed, 219 insertions, 0 deletions
diff --git a/meta-python/recipes-devtools/python/python3-django-3.2.25/CVE-2025-32873.patch b/meta-python/recipes-devtools/python/python3-django-3.2.25/CVE-2025-32873.patch new file mode 100644 index 0000000000..ae417c92c1 --- /dev/null +++ b/meta-python/recipes-devtools/python/python3-django-3.2.25/CVE-2025-32873.patch | |||
| @@ -0,0 +1,110 @@ | |||
| 1 | From 9cd8028f3e38dca8e51c1388f474eecbe7d6ca3c Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Marc Deslauriers <marc.deslauriers@ubuntu.com> | ||
| 3 | Date: Wed, 30 Apr 2025 10:34:27 -0400 | ||
| 4 | Subject: [PATCH] Fixed CVE-2025-32873 -- Mitigated potential DoS in | ||
| 5 | strip_tags(). | ||
| 6 | |||
| 7 | Thanks to Elias Myllymaki for the report, and Shai Berger and Jake | ||
| 8 | Howard for the reviews. | ||
| 9 | |||
| 10 | Co-authored-by: Natalia <124304+nessita@users.noreply.github.com> | ||
| 11 | |||
| 12 | Backport of 9f3419b from main. | ||
| 13 | |||
| 14 | CVE: CVE-2025-32873 | ||
| 15 | |||
| 16 | Upstream-Status: Backport | ||
| 17 | https://github.com/django/django/commit/9cd8028f3e38dca8e51c1388f474eecbe7d6ca3c/ | ||
| 18 | |||
| 19 | Signed-off-by: Saravanan <saravanan.kadambathursubramaniyam@windriver.com> | ||
| 20 | --- | ||
| 21 | django/utils/html.py | 6 ++++++ | ||
| 22 | docs/releases/3.2.25.txt | 11 +++++++++++ | ||
| 23 | tests/utils_tests/test_html.py | 15 ++++++++++++++- | ||
| 24 | 3 files changed, 31 insertions(+), 1 deletion(-) | ||
| 25 | |||
| 26 | diff --git a/django/utils/html.py b/django/utils/html.py | ||
| 27 | index 5887bf1..1a3033e 100644 | ||
| 28 | --- a/django/utils/html.py | ||
| 29 | +++ b/django/utils/html.py | ||
| 30 | @@ -33,6 +33,9 @@ simple_url_2_re = _lazy_re_compile( | ||
| 31 | MAX_URL_LENGTH = 2048 | ||
| 32 | MAX_STRIP_TAGS_DEPTH = 50 | ||
| 33 | |||
| 34 | +# HTML tag that opens but has no closing ">" after 1k+ chars. | ||
| 35 | +long_open_tag_without_closing_re = _lazy_re_compile(r"<[a-zA-Z][^>]{1000,}") | ||
| 36 | + | ||
| 37 | |||
| 38 | @keep_lazy(str, SafeString) | ||
| 39 | def escape(text): | ||
| 40 | @@ -184,6 +187,9 @@ def _strip_once(value): | ||
| 41 | def strip_tags(value): | ||
| 42 | """Return the given HTML with all tags stripped.""" | ||
| 43 | value = str(value) | ||
| 44 | + for long_open_tag in long_open_tag_without_closing_re.finditer(value): | ||
| 45 | + if long_open_tag.group().count("<") >= MAX_STRIP_TAGS_DEPTH: | ||
| 46 | + raise SuspiciousOperation | ||
| 47 | # Note: in typical case this loop executes _strip_once twice (the second | ||
| 48 | # execution does not remove any more tags). | ||
| 49 | strip_tags_depth = 0 | ||
| 50 | diff --git a/docs/releases/3.2.25.txt b/docs/releases/3.2.25.txt | ||
| 51 | index f21bb47..2e113cc 100644 | ||
| 52 | --- a/docs/releases/3.2.25.txt | ||
| 53 | +++ b/docs/releases/3.2.25.txt | ||
| 54 | @@ -82,6 +82,17 @@ Remember that absolutely NO guarantee is provided about the results of | ||
| 55 | ``strip_tags()`` call without escaping it first, for example with | ||
| 56 | :func:`django.utils.html.escape`. | ||
| 57 | |||
| 58 | +CVE-2025-32873: Denial-of-service possibility in ``strip_tags()`` | ||
| 59 | +================================================================= | ||
| 60 | + | ||
| 61 | +:func:`~django.utils.html.strip_tags` would be slow to evaluate certain inputs | ||
| 62 | +containing large sequences of incomplete HTML tags. This function is used to | ||
| 63 | +implement the :tfilter:`striptags` template filter, which was thus also | ||
| 64 | +vulnerable. | ||
| 65 | + | ||
| 66 | +:func:`~django.utils.html.strip_tags` now raises a :exc:`.SuspiciousOperation` | ||
| 67 | +exception if it encounters an unusually large number of unclosed opening tags. | ||
| 68 | + | ||
| 69 | Bugfixes | ||
| 70 | ======== | ||
| 71 | |||
| 72 | diff --git a/tests/utils_tests/test_html.py b/tests/utils_tests/test_html.py | ||
| 73 | index 231f5d8..5c2de01 100644 | ||
| 74 | --- a/tests/utils_tests/test_html.py | ||
| 75 | +++ b/tests/utils_tests/test_html.py | ||
| 76 | @@ -94,17 +94,30 @@ class TestUtilsHtml(SimpleTestCase): | ||
| 77 | ('><!' + ('&' * 16000) + 'D', '><!' + ('&' * 16000) + 'D'), | ||
| 78 | ('X<<<<br>br>br>br>X', 'XX'), | ||
| 79 | ("<" * 50 + "a>" * 50, ""), | ||
| 80 | + (">" + "<a" * 500 + "a", ">" + "<a" * 500 + "a"), | ||
| 81 | + ("<a" * 49 + "a" * 951, "<a" * 49 + "a" * 951), | ||
| 82 | + ("<" + "a" * 1_002, "<" + "a" * 1_002), | ||
| 83 | ) | ||
| 84 | for value, output in items: | ||
| 85 | with self.subTest(value=value, output=output): | ||
| 86 | self.check_output(strip_tags, value, output) | ||
| 87 | self.check_output(strip_tags, lazystr(value), output) | ||
| 88 | |||
| 89 | - def test_strip_tags_suspicious_operation(self): | ||
| 90 | + def test_strip_tags_suspicious_operation_max_depth(self): | ||
| 91 | value = "<" * 51 + "a>" * 51, "<a>" | ||
| 92 | with self.assertRaises(SuspiciousOperation): | ||
| 93 | strip_tags(value) | ||
| 94 | |||
| 95 | + def test_strip_tags_suspicious_operation_large_open_tags(self): | ||
| 96 | + items = [ | ||
| 97 | + ">" + "<a" * 501, | ||
| 98 | + "<a" * 50 + "a" * 950, | ||
| 99 | + ] | ||
| 100 | + for value in items: | ||
| 101 | + with self.subTest(value=value): | ||
| 102 | + with self.assertRaises(SuspiciousOperation): | ||
| 103 | + strip_tags(value) | ||
| 104 | + | ||
| 105 | def test_strip_tags_files(self): | ||
| 106 | # Test with more lengthy content (also catching performance regressions) | ||
| 107 | for filename in ('strip_tags1.html', 'strip_tags2.txt'): | ||
| 108 | -- | ||
| 109 | 2.40.0 | ||
| 110 | |||
diff --git a/meta-python/recipes-devtools/python/python3-django/CVE-2025-32873.patch b/meta-python/recipes-devtools/python/python3-django/CVE-2025-32873.patch new file mode 100644 index 0000000000..701f9b5746 --- /dev/null +++ b/meta-python/recipes-devtools/python/python3-django/CVE-2025-32873.patch | |||
| @@ -0,0 +1,107 @@ | |||
| 1 | From 9cd8028f3e38dca8e51c1388f474eecbe7d6ca3c Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Marc Deslauriers <marc.deslauriers@ubuntu.com> | ||
| 3 | Date: Wed, 30 Apr 2025 10:34:27 -0400 | ||
| 4 | Subject: [PATCH] Fixed CVE-2025-32873 -- Mitigated potential DoS in | ||
| 5 | strip_tags(). | ||
| 6 | |||
| 7 | Thanks to Elias Myllymaki for the report, and Shai Berger and Jake | ||
| 8 | Howard for the reviews. | ||
| 9 | |||
| 10 | Co-authored-by: Natalia <124304+nessita@users.noreply.github.com> | ||
| 11 | |||
| 12 | Backport of 9f3419b519799d69f2aba70b9d25abe2e70d03e0 from main. | ||
| 13 | |||
| 14 | CVE: CVE-2025-32873 | ||
| 15 | |||
| 16 | Upstream-Status: Backport | ||
| 17 | https://github.com/django/django/commit/9cd8028f3e38dca8e51c1388f474eecbe7d6ca3c | ||
| 18 | |||
| 19 | Signed-off-by: Saravanan <saravanan.kadambathursubramaniyam@windriver.com> | ||
| 20 | --- | ||
| 21 | django/utils/html.py | 6 ++++++ | ||
| 22 | docs/releases/2.2.28.txt | 11 +++++++++++ | ||
| 23 | tests/utils_tests/test_html.py | 15 ++++++++++++++- | ||
| 24 | 3 files changed, 31 insertions(+), 1 deletion(-) | ||
| 25 | |||
| 26 | diff --git a/django/utils/html.py b/django/utils/html.py | ||
| 27 | index 0d5ffd2..858a517 100644 | ||
| 28 | --- a/django/utils/html.py | ||
| 29 | +++ b/django/utils/html.py | ||
| 30 | @@ -37,6 +37,9 @@ _html_escapes = { | ||
| 31 | ord("'"): ''', | ||
| 32 | } | ||
| 33 | |||
| 34 | +# HTML tag that opens but has no closing ">" after 1k+ chars. | ||
| 35 | +long_open_tag_without_closing_re = _lazy_re_compile(r"<[a-zA-Z][^>]{1000,}") | ||
| 36 | + | ||
| 37 | |||
| 38 | @keep_lazy(str, SafeText) | ||
| 39 | def escape(text): | ||
| 40 | @@ -188,6 +191,9 @@ def _strip_once(value): | ||
| 41 | def strip_tags(value): | ||
| 42 | """Return the given HTML with all tags stripped.""" | ||
| 43 | value = str(value) | ||
| 44 | + for long_open_tag in long_open_tag_without_closing_re.finditer(value): | ||
| 45 | + if long_open_tag.group().count("<") >= MAX_STRIP_TAGS_DEPTH: | ||
| 46 | + raise SuspiciousOperation | ||
| 47 | # Note: in typical case this loop executes _strip_once twice (the second | ||
| 48 | # execution does not remove any more tags). | ||
| 49 | strip_tags_depth = 0 | ||
| 50 | diff --git a/docs/releases/2.2.28.txt b/docs/releases/2.2.28.txt | ||
| 51 | index 3503f38..1676bbd 100644 | ||
| 52 | --- a/docs/releases/2.2.28.txt | ||
| 53 | +++ b/docs/releases/2.2.28.txt | ||
| 54 | @@ -143,3 +143,14 @@ directory-traversal via certain inputs when calling :meth:`save() | ||
| 55 | |||
| 56 | Built-in ``Storage`` sub-classes were not affected by this vulnerability. | ||
| 57 | |||
| 58 | +CVE-2025-32873: Denial-of-service possibility in ``strip_tags()`` | ||
| 59 | +================================================================= | ||
| 60 | + | ||
| 61 | +:func:`~django.utils.html.strip_tags` would be slow to evaluate certain inputs | ||
| 62 | +containing large sequences of incomplete HTML tags. This function is used to | ||
| 63 | +implement the :tfilter:`striptags` template filter, which was thus also | ||
| 64 | +vulnerable. | ||
| 65 | + | ||
| 66 | +:func:`~django.utils.html.strip_tags` now raises a :exc:`.SuspiciousOperation` | ||
| 67 | +exception if it encounters an unusually large number of unclosed opening tags. | ||
| 68 | + | ||
| 69 | diff --git a/tests/utils_tests/test_html.py b/tests/utils_tests/test_html.py | ||
| 70 | index 2f412e1..653deb2 100644 | ||
| 71 | --- a/tests/utils_tests/test_html.py | ||
| 72 | +++ b/tests/utils_tests/test_html.py | ||
| 73 | @@ -92,17 +92,30 @@ class TestUtilsHtml(SimpleTestCase): | ||
| 74 | ('><!' + ('&' * 16000) + 'D', '><!' + ('&' * 16000) + 'D'), | ||
| 75 | ('X<<<<br>br>br>br>X', 'XX'), | ||
| 76 | ("<" * 50 + "a>" * 50, ""), | ||
| 77 | + (">" + "<a" * 500 + "a", ">" + "<a" * 500 + "a"), | ||
| 78 | + ("<a" * 49 + "a" * 951, "<a" * 49 + "a" * 951), | ||
| 79 | + ("<" + "a" * 1_002, "<" + "a" * 1_002), | ||
| 80 | ) | ||
| 81 | for value, output in items: | ||
| 82 | with self.subTest(value=value, output=output): | ||
| 83 | self.check_output(strip_tags, value, output) | ||
| 84 | self.check_output(strip_tags, lazystr(value), output) | ||
| 85 | |||
| 86 | - def test_strip_tags_suspicious_operation(self): | ||
| 87 | + def test_strip_tags_suspicious_operation_max_depth(self): | ||
| 88 | value = "<" * 51 + "a>" * 51, "<a>" | ||
| 89 | with self.assertRaises(SuspiciousOperation): | ||
| 90 | strip_tags(value) | ||
| 91 | |||
| 92 | + def test_strip_tags_suspicious_operation_large_open_tags(self): | ||
| 93 | + items = [ | ||
| 94 | + ">" + "<a" * 501, | ||
| 95 | + "<a" * 50 + "a" * 950, | ||
| 96 | + ] | ||
| 97 | + for value in items: | ||
| 98 | + with self.subTest(value=value): | ||
| 99 | + with self.assertRaises(SuspiciousOperation): | ||
| 100 | + strip_tags(value) | ||
| 101 | + | ||
| 102 | def test_strip_tags_files(self): | ||
| 103 | # Test with more lengthy content (also catching performance regressions) | ||
| 104 | for filename in ('strip_tags1.html', 'strip_tags2.txt'): | ||
| 105 | -- | ||
| 106 | 2.40.0 | ||
| 107 | |||
diff --git a/meta-python/recipes-devtools/python/python3-django_2.2.28.bb b/meta-python/recipes-devtools/python/python3-django_2.2.28.bb index b5b2570ddb..87830e4bc3 100644 --- a/meta-python/recipes-devtools/python/python3-django_2.2.28.bb +++ b/meta-python/recipes-devtools/python/python3-django_2.2.28.bb | |||
| @@ -30,6 +30,7 @@ SRC_URI += "file://CVE-2023-31047.patch \ | |||
| 30 | file://CVE-2025-57833.patch \ | 30 | file://CVE-2025-57833.patch \ |
| 31 | file://CVE-2024-39329.patch \ | 31 | file://CVE-2024-39329.patch \ |
| 32 | file://CVE-2024-39330.patch \ | 32 | file://CVE-2024-39330.patch \ |
| 33 | file://CVE-2025-32873.patch \ | ||
| 33 | " | 34 | " |
| 34 | 35 | ||
| 35 | SRC_URI[sha256sum] = "0200b657afbf1bc08003845ddda053c7641b9b24951e52acd51f6abda33a7413" | 36 | SRC_URI[sha256sum] = "0200b657afbf1bc08003845ddda053c7641b9b24951e52acd51f6abda33a7413" |
diff --git a/meta-python/recipes-devtools/python/python3-django_3.2.25.bb b/meta-python/recipes-devtools/python/python3-django_3.2.25.bb index 04dbe1cd19..68b60a784e 100644 --- a/meta-python/recipes-devtools/python/python3-django_3.2.25.bb +++ b/meta-python/recipes-devtools/python/python3-django_3.2.25.bb | |||
| @@ -14,6 +14,7 @@ SRC_URI += "\ | |||
| 14 | file://CVE-2024-39330.patch \ | 14 | file://CVE-2024-39330.patch \ |
| 15 | file://CVE-2024-41991.patch \ | 15 | file://CVE-2024-41991.patch \ |
| 16 | file://CVE-2024-53907.patch \ | 16 | file://CVE-2024-53907.patch \ |
| 17 | file://CVE-2025-32873.patch \ | ||
| 17 | " | 18 | " |
| 18 | 19 | ||
| 19 | # Set DEFAULT_PREFERENCE so that the LTS version of django is built by | 20 | # Set DEFAULT_PREFERENCE so that the LTS version of django is built by |
