Home Features Docs Blog Examples FAQ
DJE-001 Critical Security

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.

security template xss

Affected versions: >=0.2.0

Solutions

Recommended

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.

Before (problematic)
from django.utils.safestring import mark_safe

def render_badge(user_name):
    return mark_safe(f'<span class="badge">{user_name}</span>')
After (fixed)
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.

Before (problematic)
from django.utils.safestring import mark_safe

def render_config(config_dict):
    return mark_safe(f'<script>var config = {config_dict};</script>')
After (fixed)
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
    )