diff options
Diffstat (limited to 'meta-python/recipes-devtools/python/python3-django/CVE-2025-32873.patch')
| -rw-r--r-- | meta-python/recipes-devtools/python/python3-django/CVE-2025-32873.patch | 107 |
1 files changed, 107 insertions, 0 deletions
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 | |||
