Interactive Playground
Experiment with the vulnerable code and security rule below. Edit the code to see how the rule detects different vulnerability patterns.
pathfinder scan --ruleset python/PYTHON-DJANGO-SEC-060 --project .About This Rule
Understanding the vulnerability and how it is detected
This rule detects HTML injection vulnerabilities in Django applications where untrusted user input from HTTP request parameters flows into HTML email body content constructed for Django's EmailMessage class without proper sanitization.
When user-controlled data is included in HTML email content without escaping, attackers can inject malicious HTML that renders when the recipient opens the email. While modern webmail clients (Gmail, Outlook.com) strip JavaScript from email HTML for security, HTML injection without script execution is still exploitable for phishing attacks -- injecting fake login forms, manipulating the visual appearance of the email, or adding malicious links that lead to credential theft.
Additionally, some desktop email clients and corporate email systems render HTML more permissively, potentially allowing JavaScript execution. The safe approach is to escape user input in HTML emails using the same techniques used for web output.
Security Implications
Potential attack scenarios if this vulnerability is exploited
Phishing via Email HTML Injection
An attacker who controls any text that appears in an HTML email can inject HTML to overlay fake content on top of the legitimate email body. Adding a fake "Verify your password" form with an attacker-controlled action URL inside a legitimate-looking company email is a highly effective phishing vector.
Malicious Link Injection
HTML injection in emails allows inserting hyperlinks with deceptive display text but attacker-controlled href attributes. Recipients who see a link labeled "Reset your password here" may not check the actual URL, particularly on mobile devices where URLs are hidden.
JavaScript Execution in Permissive Email Clients
While major webmail services strip scripts, some corporate email servers, Outlook desktop client configurations, and older email systems render HTML with JavaScript. Organizations with mixed email client environments should treat email HTML injection with the same severity as browser XSS.
Content Spoofing and Brand Impersonation
An attacker who triggers an application to send an HTML email with injected content can make legitimate company emails appear to contain fraudulent information, damaging brand trust and potentially creating legal liability.
How to Fix
Recommended remediation steps
- 1Render HTML emails using Django template files which auto-escape all {{ variable }} interpolations by default.
- 2When constructing HTML email content in Python code, escape all user-controlled values with django.utils.html.escape() before inclusion.
- 3Use EmailMultiAlternatives to send both a plain text and HTML version; generate the plain text version from the escaped HTML using strip_tags().
- 4Validate email addresses with Django's EmailValidator before using them as recipients.
- 5Consider using a dedicated email templating service that enforces sanitization, or a library like premailer for CSS inlining that also performs escaping.
Detection Scope
How Code Pathfinder analyzes your code for this vulnerability
This rule performs inter-procedural taint analysis with global scope. Sources include calls("request.GET.get"), calls("request.POST.get"), calls("request.GET.__getitem__"), calls("request.POST.__getitem__"), calls("request.body"), and calls("request.read"). Sinks include the body argument of calls("EmailMessage") and calls("EmailMultiAlternatives") when content_subtype is 'html', and the attach_alternative() call with 'text/html' mimetype (tracked via .tracks(0)). Sanitizers include calls("django.utils.html.escape"), calls("django.template.loader.render_to_string"), and calls("bleach.clean").
Compliance & Standards
Industry frameworks and regulations that require detection of this vulnerability
References
External resources and documentation
Similar Rules
Explore related security rules for Python
Django XSS via Direct HttpResponse with User Input
User input flows directly to HttpResponse without HTML escaping, enabling Cross-Site Scripting (XSS) attacks.
Django mark_safe() Usage Audit
mark_safe() bypasses Django's automatic HTML escaping. Audit all usages to confirm content is properly sanitized before being marked safe.
Django XSS in send_mail html_message Parameter
User input flows into the html_message parameter of send_mail() without sanitization, enabling HTML injection in emails.
Frequently Asked Questions
Common questions about Django XSS in HTML Email Body via EmailMessage
New feature
Get these findings posted directly on your GitHub pull requests
The Django XSS in HTML Email Body via EmailMessage rule runs in CI and posts inline review comments on the exact lines — no dashboard, no SARIF viewer.