CVE-2025-26699
Executive Summary
CVE-2025-26699 is a denial-of-service (DoS) vulnerability in the Django web framework affecting the django.utils.text.wrap() method and the wordwrap template filter. An attacker can submit a very long string to these functions, causing excessive CPU consumption and potentially crashing the server. The vulnerability is rated with a CVSS score of 5.0 (Medium) and has a low EPSS score (0.0%), indicating that exploitation is not currently widespread. However, due to the widespread use of Django, the risk of targeted attacks remains.
This record — and 170,000+ others — are available via the ValtersIT API. One endpoint replaces five: NVD + GitHub CVE + CISA KEV + EPSS + Nuclei + Exploit-DB, unified.
No signup required
Supply Chain & Package Security
Django is a Python package distributed via PyPI. Organizations using Django should verify their dependency versions and ensure they are not using an affected version. The vulnerability is introduced in the source code of the Django package itself, not a third-party dependency. Patching requires updating the Django package to a secure version.
CVSS Breakdown & Threat Level
- CVSS Vector: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L
- Base Score: 5.0 (Medium)
- Attack Vector: Network (AV:N) – The vulnerability can be exploited remotely.
- Attack Complexity: Low (AC:L) – No special conditions are required.
- Privileges Required: None (PR:N) – No authentication is needed.
- User Interaction: None (UI:N) – The victim does not need to perform any action.
- Scope: Unchanged (S:U) – The vulnerable component and the impacted component are the same.
- Confidentiality Impact: None (C:N) – No data is exposed.
- Integrity Impact: None (I:N) – No data is modified.
- Availability Impact: Low (A:L) – The service may become slow or unresponsive, but not completely unavailable.
Threat Level: Medium. The vulnerability is easy to exploit remotely without authentication, but the impact is limited to availability.
Deep Dive & Mechanics
The vulnerability resides in the django.utils.text.wrap() function and the wordwrap template filter. These functions are designed to wrap long strings at a specified width. The issue occurs when a very long string (e.g., hundreds of thousands of characters) is passed to these functions. The algorithm used to perform the wrapping has a time complexity that grows quadratically with the length of the input string. This means that processing a sufficiently long string can consume excessive CPU resources, leading to a denial-of-service condition.
The vulnerable code path is triggered whenever user-supplied data is passed to the wordwrap filter in a Django template or directly to the wrap() function in Python code. Common scenarios include:
- Rendering user-generated content in templates using
{{ user_input|wordwrap:80 }}. - Using
django.utils.text.wrap()in views or other backend code to format user-provided text.
An attacker can craft a request that includes a very long string in a parameter that is subsequently processed by these functions. The server will then spend a significant amount of CPU time trying to wrap the string, potentially blocking other requests.
Vulnerable vs. Patched Code
The vulnerable code is in django/utils/text.py. The wrap() function uses a loop that repeatedly slices the string, which is inefficient for long strings.
Vulnerable Code (simplified):
def wrap(text, width):
lines = []
while text:
if len(text) <= width:
lines.append(text)
break
# Find a space to break at
space = text.rfind(' ', 0, width + 1)
if space == -1:
space = width
lines.append(text[:space])
text = text[space:].lstrip()
return '\n'.join(lines)
Patched Code (simplified):
def wrap(text, width):
lines = []
while text:
if len(text) <= width:
lines.append(text)
break
# Find a space to break at
space = text.rfind(' ', 0, width + 1)
if space == -1:
space = width
lines.append(text[:space])
text = text[space:].lstrip()
# Additional check to prevent quadratic behavior
if len(text) > 100000:
# Fallback to a more efficient algorithm
text = _fast_wrap(text, width)
return '\n'.join(lines)
The patch introduces a length check and a fallback to a more efficient algorithm (_fast_wrap) for very long strings, preventing the quadratic time complexity.
Exploitation & Lab Setup
Red Team (Exploitation)
Prerequisites:
- A Django application using an affected version (4.2.x < 4.2.20, 5.0.x < 5.0.13, or 5.1.x < 5.1.7).
- An endpoint that uses the
wordwrapfilter ordjango.utils.text.wrap()with user-controlled input.
Exploitation Steps:
- Identify an endpoint that renders user input with the
wordwrapfilter. For example, a comment form that displays user comments with{{ comment|wordwrap:80 }}. - Craft a POST request with a very long string (e.g., 500,000 characters) in the relevant parameter.
- Send the request. The server will become unresponsive for a period of time, potentially blocking other requests.
Example Python Script:
import requests
url = "http://target.com/submit_comment/"
payload = {"comment": "A" * 500000}
response = requests.post(url, data=payload)
print("Request sent. Server may be slow.")
Blue Team (Detection & Defense)
Detection:
- Monitor for requests with unusually long strings in parameters that are processed by
wordwraporwrap(). - Set up alerts for high CPU usage on web servers.
- Use Web Application Firewall (WAF) rules to block requests with excessively long strings.
Defense:
- Immediately upgrade Django to a patched version (4.2.20, 5.0.13, or 5.1.7).
- If patching is not immediately possible, implement input validation to limit the length of strings passed to
wordwraporwrap(). - Consider using a reverse proxy or load balancer to mitigate DoS attacks.
Indicators of Compromise (IOCs)
Network IOCs:
- HTTP requests with a single parameter containing a string of 100,000+ characters.
- Unusually high CPU usage on the Django server.
- Slow response times or timeouts for legitimate requests.
Host IOCs:
- Django process consuming 100% CPU for an extended period.
- Log entries showing requests with very long strings.
File IOCs:
- No specific file-based IOCs, as the vulnerability is exploited in memory.
Detection Engineering
YARA Rule
rule CVE_2025_26699_Django_Wordwrap_DoS {
meta:
description = "Detects potential exploitation of CVE-2025-26699 via very long strings in Django requests"
author = "Valters IT"
date = "2025-03-01"
reference = "https://nvd.nist.gov/vuln/detail/CVE-2025-26699"
strings:
$long_string = /[A-Za-z0-9\s]{100000,}/
condition:
$long_string
}
Sigma Rule
title: CVE-2025-26699 Django Wordwrap DoS
id: 12345678-1234-1234-1234-123456789012
status: experimental
description: Detects HTTP requests with very long strings that may exploit CVE-2025-26699
author: Valters IT
date: 2025/03/01
logsource:
category: webserver
product: apache
detection:
selection:
c-uri|contains:
- "comment"
- "text"
- "message"
sc-bytes|gte: 100000
condition: selection
falsepositives:
- Legitimate large file uploads
level: medium
Suricata Rule
alert http any any -> any any (msg:"CVE-2025-26699 Django Wordwrap DoS Attempt"; flow:to_server; content:"POST"; http_method; content:"comment="; http_client_body; pcre:"/[A-Za-z0-9\s]{100000,}/"; classtype:attempted-dos; sid:1000001; rev:1;)
Remediation & Mitigation
Immediate Actions:
- Patch: Upgrade Django to version 4.2.20, 5.0.13, or 5.1.7 (or later).
- Workaround: If patching is not possible, implement input validation to limit the length of strings passed to
wordwraporwrap(). For example, truncate strings to 10,000 characters before processing.
Long-term Actions:
- Implement a Web Application Firewall (WAF) to block requests with excessively long strings.
- Monitor for unusual CPU usage patterns.
- Regularly update dependencies to the latest secure versions.
Valters IT Signature:
Valters IT
Senior DevSecOps Engineer
Cyber Threat Intelligence Expert