Using mark_safe() with f-strings or user input
Error message
Potential XSS vulnerability: mark_safe() used with dynamic content
Using mark_safe() with f-strings or any user-controlled values creates a cross-site scripting (XSS) vulnerability. An attacker can inject arbitrary HTML and JavaScript into the page. This is one of the most common and dangerous security mistakes in Django template development.
Affected versions: >=0.2.0
Solutions
Use format_html() for HTML attributes
Django's format_html() automatically escapes all arguments while keeping the format string safe. Use it whenever you need to insert dynamic values into HTML markup.
from django.utils.safestring import mark_safe
def render_badge(user_name):
return mark_safe(f'<span class="badge">{user_name}</span>')
from django.utils.html import format_html
def render_badge(user_name):
return format_html('<span class="badge">{}</span>', user_name)
Use json.dumps() for JavaScript contexts
When inserting values into JavaScript string contexts (e.g., inline scripts or data attributes parsed by JS), use json.dumps() instead of escape(). escape() does not handle backslashes, newlines, or quotes.
from django.utils.safestring import mark_safe
def render_config(config_dict):
return mark_safe(f'<script>var config = {config_dict};</script>')
import json
from django.utils.html import format_html
def render_config(config_dict):
safe_json = json.dumps(config_dict)
return format_html(
'<script>var config = {};</script>',
mark_safe(safe_json) # json.dumps output is safe
)