HIGH regex dosdjango

Regex Dos in Django

How Regex Dos Manifests in Django

Regex DoS (Denial of Service) attacks in Django exploit the fact that certain regular expressions can take exponential time to process when given malicious input. This vulnerability, also known as ReDoS (Regular Expression Denial of Service), occurs when an attacker crafts input that forces the regex engine into catastrophic backtracking.

In Django applications, regex DoS commonly appears in several critical areas:

  • URL routing: Django's URL resolver uses regex patterns to match incoming requests. A malicious URL can cause the router to consume excessive CPU time.
  • Model field validation: Custom validators using regex can be exploited through form submissions or API payloads.
  • Template rendering: Django templates support regex filters that can be abused with crafted input.
  • Middleware processing: Request/response middleware that applies regex transformations can become a bottleneck.

The classic attack pattern involves creating input that matches the regex in multiple ways, forcing the engine to explore all possible match combinations. For example, consider this vulnerable Django URL pattern:

from django.urls import path

urlpatterns = [
    path('user/', views.user_detail),  # Vulnerable to ReDoS
    path('search/', views.search),  # Also vulnerable
]

An attacker could send a request like /user/a[b-a]*/b where the character class [b-a] is invalid but forces catastrophic backtracking in Django's URL resolver. The slug converter uses regex under the hood, making it susceptible to this attack.

Another common pattern is in model validation:

import re
from django.db import models

class UserProfile(models.Model):
    email = models.EmailField()
    vanity_url = models.CharField(max_length=100, validators=[
        # Vulnerable: nested quantifiers can cause exponential time
        RegexValidator(
            regex=r'^[a-z0-9]+(-[a-z0-9]+)*$',
            message='Invalid URL format'
        )
    ])

The pattern (-[a-z0-9]+)* contains nested quantifiers that can be exploited with carefully crafted input containing many alternations.

Django-Specific Detection

Detecting regex DoS vulnerabilities in Django requires both static code analysis and dynamic testing. Here are Django-specific detection methods:

Static Analysis: Review your codebase for regex patterns in these Django-specific locations:

# Check URL patterns for vulnerable regex
from django.urls import URLPattern

def is_vulnerable_regex(pattern: str) -> bool:
    # Look for nested quantifiers, alternation-heavy patterns
    nested_quantifiers = r'([*+?]|(?:match|replace|search)).*b(?:match|replace|search)'
    return bool(re.search(nested_quantifiers, pattern))

# Scan URL patterns
for pattern in urlpatterns:
    if isinstance(pattern, URLPattern):
        regex_pattern = pattern.pattern.regex.pattern
        if is_vulnerable_regex(regex_pattern):
            print(f'Vulnerable URL pattern: {regex_pattern}')

Dynamic Testing with middleBrick: middleBrick's black-box scanning approach is particularly effective for detecting runtime regex DoS vulnerabilities in Django applications. The scanner tests your API endpoints with specially crafted payloads designed to trigger catastrophic backtracking.

middleBrick's regex DoS detection includes:

  • Testing URL resolvers with pathological patterns
  • Submitting form data with crafted strings to trigger model validators
  • Analyzing template rendering paths for regex filter abuse
  • Monitoring response times to detect abnormal processing delays

The scanner provides a security risk score (A–F) and specific findings with severity levels. For example, a vulnerable URL pattern might be flagged as:

Finding: Catastrophic backtracking in URL routing
Severity: High
Location: /user/<slug:id>
Impact: Attacker can cause 100% CPU usage with crafted URLs
Remediation: Replace nested quantifiers with atomic groups

Performance Monitoring: Set up monitoring to detect regex DoS attacks in production:

from django.middleware import MiddlewareMixin
import time

class RegexMonitoringMiddleware(MiddlewareMixin):
    def process_view(self, request, view_func, view_args, view_kwargs):
        start_time = time.time()
        
        response = view_func(request, *view_args, **view_kwargs)
        
        elapsed = time.time() - start_time
        if elapsed > 1.0:  # Threshold in seconds
            # Log potential regex DoS attempt
            logger.warning(
                f'Potential regex DoS detected: {request.path} '
                f'took {elapsed:.2f}s'
            )
        return response

Django-Specific Remediation

Remediating regex DoS vulnerabilities in Django requires both immediate fixes and architectural changes. Here are Django-specific approaches:

1. Use Atomic Groups for Vulnerable Patterns: Atomic groups prevent backtracking by committing to a match once it's found:

from django import forms
from django.core.validators import RegexValidator

# Vulnerable pattern (nested quantifiers)
vulnerable = r'^[a-z0-9]+(-[a-z0-9]+)*$'

# Fixed with atomic groups
fixed = r'^(?>[a-z0-9]+)(?:-(?>[a-z0-9]+))*$'

class SafeForm(forms.Form):
    vanity_url = forms.CharField(
        max_length=100,
        validators=[
            RegexValidator(
                regex=fixed,
                message='Invalid URL format'
            )
        ]
    )

2. Replace Complex Regex with Simpler Validation: For URL routing, use Django's built-in converters when possible:

# Instead of vulnerable slug with complex regex
urlpatterns = [
    path('user/<slug:id>', views.user_detail),  # Potentially vulnerable
    
    # Use path converter for simple alphanumeric IDs
    path('user/<str:id>', views.user_detail_safe),  # Safer
]

3. Implement Input Length Limits: Add maximum length constraints to prevent exponential blowup:

from django import forms

class BoundedForm(forms.Form):
    # Limit input to 50 characters max
    vanity_url = forms.CharField(
        max_length=50,
        validators=[
            RegexValidator(
                regex=r'^[a-z0-9]+(-[a-z0-9]+)*$',  # Still vulnerable but bounded
                message='Invalid URL format'
            )
        ]
    )
    
    def clean_vanity_url(self):
        data = self.cleaned_data['vanity_url']
        if len(data) > 50:
            raise forms.ValidationError('Input too long')
        return data

4. Use Django's Built-in Validation: Leverage Django's native validators instead of custom regex:

from django.core.validators import EmailValidator
from django import forms

class SafeEmailForm(forms.Form):
    email = forms.EmailField(
        validators=[EmailValidator()],  # Django's optimized validator
        max_length=254  # Standard max email length
    )
    
    # Avoid custom regex for email validation
    # email = forms.CharField(validators=[
    #     RegexValidator(regex=r'^...$', message='Invalid email')
    # ])

5. Implement Rate Limiting: Use Django middleware to prevent repeated attacks:

from django.middleware import MiddlewareMixin
from django.core.cache import cache
import time

class RateLimitingMiddleware(MiddlewareMixin):
    def process_request(self, request):
        key = f'request_count:{request.META.get("REMOTE_ADDR")}'
        count = cache.get(key, 0)
        
        if count > 10:  # Max 10 requests per period
            return HttpResponse('Rate limit exceeded', status=429)
        
        cache.set(key, count + 1, timeout=60)  # 1-minute window
        return None

6. Use Safe Libraries: For complex validation, use libraries designed to prevent ReDoS:

# Instead of vulnerable regex
import re

# Use safe alternatives
from django.core.validators import validate_slug
from django.utils.html import strip_tags

def safe_validation(value):
    # Validate without regex
    if not validate_slug(value):
        raise ValidationError('Invalid format')
    
    # Or use length-based validation
    if len(value) > 100:
        raise ValidationError('Input too long')
    
    return True

Related CWEs: inputValidation

CWE IDNameSeverity
CWE-20Improper Input Validation HIGH
CWE-22Path Traversal HIGH
CWE-74Injection CRITICAL
CWE-77Command Injection CRITICAL
CWE-78OS Command Injection CRITICAL
CWE-79Cross-site Scripting (XSS) HIGH
CWE-89SQL Injection CRITICAL
CWE-90LDAP Injection HIGH
CWE-91XML Injection HIGH
CWE-94Code Injection CRITICAL

Frequently Asked Questions

How can I test my Django application for regex DoS vulnerabilities?
Use middleBrick's black-box scanning to test your API endpoints. The scanner tests URL patterns, form submissions, and template rendering paths with specially crafted payloads designed to trigger catastrophic backtracking. It provides a security risk score and specific findings with severity levels, helping you identify vulnerable regex patterns without needing to inspect your source code.
Are Django's built-in URL converters safe from regex DoS attacks?
Most built-in converters like , , and are implemented safely and don't use vulnerable regex patterns. However, the converter does use regex internally and can be vulnerable to ReDoS. For maximum safety, use for simple alphanumeric IDs or implement custom converters with strict validation and length limits.