Skip to content

Commit 4f27652

Browse files
committed
[5.0.x] Fixed CVE-2025-26699 -- Mitigated potential DoS in wordwrap template filter.
Thanks sw0rd1ight for the report. Backport of 55d89e2 from main.
1 parent e8d4030 commit 4f27652

File tree

4 files changed

+33
-18
lines changed

4 files changed

+33
-18
lines changed

django/utils/text.py

+10-18
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import gzip
22
import re
33
import secrets
4+
import textwrap
45
import unicodedata
56
from gzip import GzipFile
67
from gzip import compress as gzip_compress
@@ -97,24 +98,15 @@ def wrap(text, width):
9798
``width``.
9899
"""
99100

100-
def _generator():
101-
for line in text.splitlines(True): # True keeps trailing linebreaks
102-
max_width = min((line.endswith("\n") and width + 1 or width), width)
103-
while len(line) > max_width:
104-
space = line[: max_width + 1].rfind(" ") + 1
105-
if space == 0:
106-
space = line.find(" ") + 1
107-
if space == 0:
108-
yield line
109-
line = ""
110-
break
111-
yield "%s\n" % line[: space - 1]
112-
line = line[space:]
113-
max_width = min((line.endswith("\n") and width + 1 or width), width)
114-
if line:
115-
yield line
116-
117-
return "".join(_generator())
101+
wrapper = textwrap.TextWrapper(
102+
width=width,
103+
break_long_words=False,
104+
break_on_hyphens=False,
105+
)
106+
result = []
107+
for line in text.splitlines(True):
108+
result.extend(wrapper.wrap(line))
109+
return "\n".join(result)
118110

119111

120112
def add_truncation_text(text, truncate=None):

docs/releases/4.2.20.txt

+6
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,9 @@ Django 4.2.20 release notes
55
*March 6, 2025*
66

77
Django 4.2.20 fixes a security issue with severity "moderate" in 4.2.19.
8+
9+
CVE-2025-26699: Potential denial-of-service vulnerability in ``django.utils.text.wrap()``
10+
=========================================================================================
11+
12+
The ``wrap()`` and :tfilter:`wordwrap` template filter were subject to a
13+
potential denial-of-service attack when used with very long strings.

docs/releases/5.0.13.txt

+6
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,9 @@ Django 5.0.13 release notes
55
*March 6, 2025*
66

77
Django 5.0.13 fixes a security issue with severity "moderate" in 5.0.12.
8+
9+
CVE-2025-26699: Potential denial-of-service vulnerability in ``django.utils.text.wrap()``
10+
=========================================================================================
11+
12+
The ``wrap()`` and :tfilter:`wordwrap` template filter were subject to a
13+
potential denial-of-service attack when used with very long strings.

tests/template_tests/filter_tests/test_wordwrap.py

+11
Original file line numberDiff line numberDiff line change
@@ -78,3 +78,14 @@ def test_wrap_lazy_string(self):
7878
"this is a long\nparagraph of\ntext that\nreally needs\nto be wrapped\n"
7979
"I'm afraid",
8080
)
81+
82+
def test_wrap_long_text(self):
83+
long_text = (
84+
"this is a long paragraph of text that really needs"
85+
" to be wrapped I'm afraid " * 20_000
86+
)
87+
self.assertIn(
88+
"this is a\nlong\nparagraph\nof text\nthat\nreally\nneeds to\nbe wrapped\n"
89+
"I'm afraid",
90+
wordwrap(long_text, 10),
91+
)

0 commit comments

Comments
 (0)