Skip to main content
Vulnerability Database/CVE-2024-27351

CVE-2024-27351: Django Truncator ReDoS Vulnerability

CVE-2024-27351 is a regular expression denial-of-service vulnerability in Django's text truncation functionality that allows attackers to cause service disruption. This article covers technical details, affected versions, and mitigation strategies.

Published:

CVE-2024-27351 Overview

CVE-2024-27351 is a regular expression denial-of-service (ReDoS) vulnerability in the Django web framework. The flaw affects the django.utils.text.Truncator.words() method when called with html=True, as well as the truncatewords_html template filter. Attackers can supply a crafted input string containing sequences of open brackets that trigger catastrophic backtracking in the underlying regular expression, exhausting CPU resources. The issue is classified under CWE-1333 (Inefficient Regular Expression Complexity) and represents an incomplete fix for the earlier CVE-2019-14232 and CVE-2023-43665 vulnerabilities. Django 3.2.25, 4.2.11, and 5.0.3 remediate the issue by replacing the vulnerable regex pattern with a state-machine class.

Critical Impact

Remote unauthenticated attackers can trigger CPU exhaustion in Django applications that render user-controlled text through truncatewords_html, degrading availability of the affected service.

Affected Products

  • Django 3.2 before 3.2.25
  • Django 4.2 before 4.2.11
  • Django 5.0 before 5.0.3

Discovery Timeline

  • 2024-03-04 - Django project publishes security release addressing the flaw
  • 2024-03-15 - CVE-2024-27351 published to NVD
  • 2026-06-17 - Last updated in NVD database

Technical Details for CVE-2024-27351

Vulnerability Analysis

The vulnerability exists in Django's text truncation utilities used to shorten HTML content while preserving tag structure. The Truncator.words() method, when invoked with html=True, iterates over input using a regular expression designed to match either an HTML tag or a non-whitespace word. The truncation logic is commonly reached through user-supplied content rendered in templates via the truncatewords_html filter. An attacker who can influence such rendered text can force the application to spend excessive CPU time on a single request.

Because processing is synchronous, one malicious request can occupy a worker process for seconds or longer. Repeated requests can degrade or halt service availability. The issue is a follow-up to CVE-2019-14232 and CVE-2023-43665, where prior mitigations did not eliminate all catastrophic backtracking paths.

Root Cause

The root cause lies in the pattern re_words = _lazy_re_compile(r"<[^>]+?>|([^<>\s]+)", re.S) in django/utils/text.py. When applied to input consisting of many consecutive < characters without matching > closers, the regex engine backtracks extensively while attempting to match the <[^>]+?> alternative. This produces algorithmic complexity that grows super-linearly with input size.

Attack Vector

Exploitation requires the target application to pass attacker-controlled text through Truncator.words(html=True) or the truncatewords_html template filter. Any endpoint that renders untrusted content, such as comment fields, blog previews, or user profile bios, may be exploitable. The attack requires user interaction in the sense that a request must render the malicious content, but no authentication is required in the typical case.

python
# Django security patch replacing the vulnerable regex
# Source: https://github.com/django/django/commit/3394fc6132436eca89e997083bae9985fb7e761e

# ----- Begin security-related performance workaround -----
#
# We used to have, below
#
# re_words = _lazy_re_compile(r"<[^>]+?>|([^<>\s]+)", re.S)
#
# But it was shown that this regex, in the way we use it here, has some
# catastrophic edge-case performance features. Namely, when it is applied to
# text with only open brackets "<<<...". The class below provides the services
# and correct answers for the use cases, but in these edge cases does it much
# faster.
re_notag = _lazy_re_compile(r"([^<>\s]+)", re.S)
re_prt = _lazy_re_compile(r"<|([^<>\s]+)", re.S)


class WordsRegex:
    @staticmethod
    def search(text, pos):
        # Look for "<" or a non-tag word.
        partial = re_prt.search(text, pos)
        if partial is None or partial[1] is not None:
            return partial

        # "<" was found, look for a closing ">".
        end = text.find(">", partial.end(0))

The patch replaces the single alternation-based regex with a smaller matcher combined with an explicit substring search, eliminating the catastrophic backtracking path. See the Django commit for 4.2.x for the equivalent fix in that branch.

Detection Methods for CVE-2024-27351

Indicators of Compromise

  • Sustained CPU saturation on Django worker processes tied to individual HTTP requests.
  • Application requests containing large runs of unmatched < characters submitted to endpoints that render HTML previews.
  • Elevated response latency or worker timeouts on endpoints that invoke truncatewords_html.

Detection Strategies

  • Inventory Django applications and confirm installed versions using pip show django or dependency lockfiles.
  • Search project code and templates for references to truncatewords_html and Truncator.words(html=True) on user-controlled input.
  • Baseline normal request duration and alert on statistical outliers for endpoints that render user-generated content.

Monitoring Recommendations

  • Enable Django request logging with timing metrics and forward to a centralized analytics platform.
  • Configure application performance monitoring to flag single requests consuming disproportionate CPU time.
  • Track upstream WSGI/ASGI worker timeouts and 502/504 gateway errors correlated with specific request patterns.

How to Mitigate CVE-2024-27351

Immediate Actions Required

  • Upgrade Django to a fixed release: 3.2.25, 4.2.11, or 5.0.3 or later.
  • Rebuild and redeploy application containers and virtual environments to ensure the patched wheel is loaded.
  • Audit templates and view logic for direct use of truncatewords_html on unauthenticated inputs and apply length limits at the input layer.

Patch Information

The Django project released fixes on March 4, 2024, covering the 3.2.x, 4.2.x, and 5.0.x branches. Details are available in the Django Security Release Notes and the Django Weblog Security Releases. The upstream fixes are implemented in commits 072963e4, 3394fc61, and 3c9a2771. Fedora users should apply the updated packages announced in the Fedora Package Announcement.

Workarounds

  • Enforce strict maximum length on any input passed to truncatewords_html before invoking the filter.
  • Strip or normalize HTML input server-side using a dedicated sanitizer before storing or rendering.
  • Place a request-body size limit and per-request CPU/time budget at the reverse proxy or WSGI layer.
bash
# Upgrade Django to a patched release
pip install --upgrade "Django>=5.0.3"
# or, for the 4.2 LTS series
pip install --upgrade "Django>=4.2.11,<5.0"
# or, for the 3.2 LTS series
pip install --upgrade "Django>=3.2.25,<4.0"

# Verify the installed version
python -c "import django; print(django.get_version())"

Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

Default Legacy - Prefooter | Experience the World’s Most Advanced Cybersecurity Platform

Experience the Most Advanced Cybersecurity Platform

See how the world’s most intelligent, autonomous cybersecurity platform can protect your organization today and into the future.