summaryrefslogtreecommitdiffstats
path: root/meta-python/recipes-devtools/python/python3-django-3.2.25/CVE-2024-53907.patch
blob: 577f042b0ab04c136482579dd6c086a87e48f612 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
From 790eb058b0716c536a2f2e8d1c6d5079d776c22b Mon Sep 17 00:00:00 2001
From: Marc Deslauriers <marc.deslauriers@ubuntu.com>
Date: Wed, 30 Apr 2025 10:34:27 -0400
Subject: [PATCH] Fixed CVE-2024-53907 -- Mitigated potential DoS in
 strip_tags().

Thanks to jiangniao for the report, and Shai Berger and Natalia Bidart
for the reviews.

CVE: CVE-2024-53907

Upstream-Status: Backport
https://github.com/django/django/commit/790eb058b0716c536a2f2e8d1c6d5079d776c22b

Signed-off-by: Saravanan <saravanan.kadambathursubramaniyam@windriver.com>
---
 django/utils/html.py           | 10 ++++++++--
 docs/releases/3.2.25.txt       | 16 ++++++++++++++++
 tests/utils_tests/test_html.py |  7 +++++++
 3 files changed, 31 insertions(+), 2 deletions(-)

diff --git a/django/utils/html.py b/django/utils/html.py
index 44c6b7b..5887bf1 100644
--- a/django/utils/html.py
+++ b/django/utils/html.py
@@ -8,6 +8,7 @@ from urllib.parse import (
     parse_qsl, quote, unquote, urlencode, urlsplit, urlunsplit,
 )
 
+from django.core.exceptions import SuspiciousOperation
 from django.utils.encoding import punycode
 from django.utils.functional import Promise, keep_lazy, keep_lazy_text
 from django.utils.http import RFC3986_GENDELIMS, RFC3986_SUBDELIMS
@@ -30,6 +31,7 @@ simple_url_2_re = _lazy_re_compile(
 )
 
 MAX_URL_LENGTH = 2048
+MAX_STRIP_TAGS_DEPTH = 50
 
 
 @keep_lazy(str, SafeString)
@@ -181,15 +183,19 @@ def _strip_once(value):
 @keep_lazy_text
 def strip_tags(value):
     """Return the given HTML with all tags stripped."""
-    # Note: in typical case this loop executes _strip_once once. Loop condition
-    # is redundant, but helps to reduce number of executions of _strip_once.
     value = str(value)
+    # Note: in typical case this loop executes _strip_once twice (the second
+    # execution does not remove any more tags).
+    strip_tags_depth = 0
     while '<' in value and '>' in value:
+        if strip_tags_depth >= MAX_STRIP_TAGS_DEPTH:
+            raise SuspiciousOperation
         new_value = _strip_once(value)
         if value.count('<') == new_value.count('<'):
             # _strip_once wasn't able to detect more tags.
             break
         value = new_value
+        strip_tags_depth += 1
     return value
 
 
diff --git a/docs/releases/3.2.25.txt b/docs/releases/3.2.25.txt
index 67dc8a2..f21bb47 100644
--- a/docs/releases/3.2.25.txt
+++ b/docs/releases/3.2.25.txt
@@ -66,6 +66,22 @@ CVE-2024-41991: Potential denial-of-service vulnerability in ``django.utils.html
 subject to a potential denial-of-service attack via certain inputs with a very
 large number of Unicode characters.
 
+CVE-2024-53907: Denial-of-service possibility in ``strip_tags()``
+=================================================================
+
+:func:`~django.utils.html.strip_tags` would be extremely slow to evaluate
+certain inputs containing large sequences of nested incomplete HTML entities.
+The ``strip_tags()`` method is used to implement the corresponding
+:tfilter:`striptags` template filter, which was thus also vulnerable.
+
+``strip_tags()`` now has an upper limit of recursive calls to ``HTMLParser``
+before raising a :exc:`.SuspiciousOperation` exception.
+
+Remember that absolutely NO guarantee is provided about the results of
+``strip_tags()`` being HTML safe. So NEVER mark safe the result of a
+``strip_tags()`` call without escaping it first, for example with
+:func:`django.utils.html.escape`.
+
 Bugfixes
 ========
 
diff --git a/tests/utils_tests/test_html.py b/tests/utils_tests/test_html.py
index 93458ac..231f5d8 100644
--- a/tests/utils_tests/test_html.py
+++ b/tests/utils_tests/test_html.py
@@ -1,6 +1,7 @@
 import os
 from datetime import datetime
 
+from django.core.exceptions import SuspiciousOperation
 from django.test import SimpleTestCase
 from django.utils.functional import lazystr
 from django.utils.html import (
@@ -92,12 +93,18 @@ class TestUtilsHtml(SimpleTestCase):
             ('<script>alert()</script>&h', 'alert()h'),
             ('><!' + ('&' * 16000) + 'D', '><!' + ('&' * 16000) + 'D'),
             ('X<<<<br>br>br>br>X', 'XX'),
+            ("<" * 50 + "a>" * 50, ""),
         )
         for value, output in items:
             with self.subTest(value=value, output=output):
                 self.check_output(strip_tags, value, output)
                 self.check_output(strip_tags, lazystr(value), output)
 
+    def test_strip_tags_suspicious_operation(self):
+        value = "<" * 51 + "a>" * 51, "<a>"
+        with self.assertRaises(SuspiciousOperation):
+            strip_tags(value)
+
     def test_strip_tags_files(self):
         # Test with more lengthy content (also catching performance regressions)
         for filename in ('strip_tags1.html', 'strip_tags2.txt'):
-- 
2.40.0