Format String in Django
How Format String Manifests in Django
Format string vulnerabilities in Django applications typically arise when user-controlled data is directly interpolated into string formatting operations without proper sanitization. In Django, this can occur in several contexts:
# Dangerous: User input directly in format string
user_input = request.GET.get('format')
template = f"User data: {user_input}"
The most common Django-specific manifestation involves str.format() with user-controlled format specifiers. Attackers can manipulate format specifiers to access object attributes or cause exceptions:
# Vulnerable: format_spec comes from user input
user_format = request.GET.get('format_spec')
value = 1234.5678
formatted = f"{value:{user_format}}" # User can control format
Django template rendering can also be affected when developers bypass the template system for performance or dynamic content generation:
# Dangerous: Dynamic template creation
user_template = request.GET.get('template')
dynamic_content = f"{user_template}"
Another Django-specific scenario involves model field formatting where user input controls display formats:
# Vulnerable: User controls date format
user_date_format = request.GET.get('date_format')
formatted_date = obj.date_field.strftime(user_date_format) # Format string injection
Format string issues can also appear in Django logging configurations where user input might influence log message formatting:
# Dangerous: User input in log format
user_format = request.GET.get('log_format')
logger.info(user_format % {'data': user_data})
Django-Specific Detection
Detecting format string vulnerabilities in Django requires both static analysis and runtime scanning. middleBrick's API security scanner specifically tests for format string injection by:
- Analyzing all string formatting operations in your Django views and templates
- Testing format specifiers with malicious payloads like
{__class__},{__init__}, and format width specifiers
# Scan your Django API with middleBrick
middlebrick scan https://your-django-app.com/api/user
middleBrick's scanner tests for format string vulnerabilities by injecting payloads into format specifiers and analyzing responses for information disclosure or application crashes. The scanner specifically looks for:
- Exception stack traces that reveal internal object structures
- Unexpected output containing sensitive data
- Application errors when format specifiers are manipulated
For Django applications, middleBrick also analyzes template rendering contexts to identify where user input might influence template formatting:
{
"format_string_vulnerabilities": {
"severity": "high",
"locations": [
"views.py:42 - User-controlled format_spec in f-string",
"templates/user_detail.html:15 - Dynamic format string"
],
"remediation": "Sanitize user input before using in format operations"
}
}
middleBrick's continuous monitoring (Pro plan) can automatically re-scan your Django APIs whenever code changes are deployed, ensuring format string vulnerabilities are caught before reaching production.
Django-Specific Remediation
Remediating format string vulnerabilities in Django requires strict input validation and avoiding dynamic format strings. Here are Django-specific solutions:
# Safe: Whitelist allowed format specifiers
ALLOWED_FORMATS = {
'price': '{:.2f}',
'percentage': '{:.1%}',
'date_short': '%Y-%m-%d',
'date_long': '%B %d, %Y'
}
def safe_format(request):
fmt_key = request.GET.get('format_key', 'price')
if fmt_key not in ALLOWED_FORMATS:
fmt_key = 'price' # Default to safe format
format_str = ALLOWED_FORMATS[fmt_key]
value = get_value_to_format()
return format_str.format(value)
For Django templates, use template tags and filters instead of dynamic formatting:
# Safe: Use Django template system
from django import template
@register.filter
def safe_format(value, format_type):
formats = {
'currency': '{:,.2f}',
'percent': '{:.1%}',
}
if format_type not in formats:
format_type = 'currency'
return formats[format_type].format(value)
For date formatting in Django models, use predefined format choices:
from django.db import models
from django.utils.dateformat import format
class Event(models.Model):
date = models.DateTimeField()
DATE_FORMATS = (
('short', 'YYYY-MM-DD'),
('long', 'F j, Y'),
('iso', 'c'),
)
def format_date(self, format_type='short'):
format_map = {
'short': 'Y-m-d',
'long': 'F j, Y',
'iso': 'c',
}
fmt = format_map.get(format_type, 'Y-m-d')
return format(self.date, fmt)
For logging in Django applications, use parameterized logging instead of string formatting:
import logging
logger = logging.getLogger(__name__)
def log_user_action(request):
user_id = request.user.id
action = request.GET.get('action', 'unknown')
# Safe: Parameterized logging
logger.info('User %s performed action: %s', user_id, action)
# Never: String formatting with user data
# logger.info('User %s performed action: %s' % (user_id, action)) # Vulnerable