Skip to content

Commit e88f737

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

File tree

3 files changed

+27
-18
lines changed

3 files changed

+27
-18
lines changed

django/utils/text.py

Lines changed: 10 additions & 18 deletions
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
class Truncator(SimpleLazyObject):

docs/releases/4.2.20.txt

Lines changed: 6 additions & 0 deletions
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.

tests/template_tests/filter_tests/test_wordwrap.py

Lines changed: 11 additions & 0 deletions
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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy