Django XSS via Direct HttpResponse with User Input

HIGH

User input flows directly to HttpResponse without HTML escaping, enabling Cross-Site Scripting (XSS) attacks.

Rule Information

Language
Python
Category
Django
Author
Shivasurya
Shivasurya
Last Updated
2026-03-22
Tags
pythondjangoxsshttpresponsehtml-injectiontaint-analysisinter-proceduralCWE-79OWASP-A03
CWE References

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-050 --project .
1
2
3
4
5
6
7
8
9
10
11
12
13
rule.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45

About This Rule

Understanding the vulnerability and how it is detected

This rule detects Cross-Site Scripting (XSS) vulnerabilities in Django applications where untrusted user input from HTTP request parameters flows directly into HttpResponse() without HTML escaping.

Django's template engine provides automatic HTML escaping by default, which is why rendering user input through templates is safe. However, when developers bypass the template system and construct HTML strings manually in views, passing them to HttpResponse(), they take on the responsibility of escaping user input that the template engine would otherwise handle automatically.

XSS vulnerabilities allow attackers to inject malicious JavaScript that executes in the victim's browser context, enabling session theft, credential harvesting, keylogging, DOM manipulation, and phishing within the legitimate application's origin.

Security Implications

Potential attack scenarios if this vulnerability is exploited

1

Session Cookie Theft and Account Takeover

Injected JavaScript can access document.cookie and send session cookies to attacker-controlled servers. If the application's session cookies do not have the HttpOnly flag set, this leads to complete account takeover without requiring the user's credentials.

2

Credential Harvesting via DOM Manipulation

Injected scripts can dynamically modify the page DOM to add fake login forms or overlay phishing content within the trusted application domain. Users filling out these fake forms send credentials directly to the attacker, bypassing browser security warnings about fake sites.

3

Stored XSS as a Secondary Vector

If the user-controlled value eventually flows from the database to HttpResponse (second-order XSS), the injection payload persists and executes every time any user views the affected page, amplifying the attack across the entire user base.

4

CSRF Token Exfiltration

XSS can extract CSRF tokens from the page and use them to submit state-changing requests with full CSRF protection bypassed, enabling fund transfers, account changes, and other sensitive operations on behalf of authenticated users.

How to Fix

Recommended remediation steps

  • 1Use Django's template system (render() or TemplateResponse) for all HTML responses; templates auto-escape variables by default.
  • 2When HttpResponse must be used with dynamic content, escape all user-controlled values with django.utils.html.escape() before inclusion.
  • 3For API responses that do not render HTML, use JsonResponse which escapes HTML entities in JSON values.
  • 4Never concatenate request parameters directly into HTML strings, even for "simple" values like names or IDs.
  • 5Ensure response Content-Type is set appropriately (text/html for templates, application/json for APIs) to prevent MIME sniffing-based XSS.

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"). The sink is the first argument (HTML content, tracked via .tracks(0)) of calls("HttpResponse") and calls("django.http.HttpResponse"). Sanitizers include calls("django.utils.html.escape"), calls("django.utils.html.strip_tags"), and calls("bleach.clean"). The rule follows taint across file and module boundaries.

Compliance & Standards

Industry frameworks and regulations that require detection of this vulnerability

CWE Top 25
CWE-79 ranked #2 in 2023 Most Dangerous Software Weaknesses
OWASP Top 10
A03:2021 - Injection (XSS is a sub-category)
PCI DSS v4.0
Requirement 6.2.4 - protect against XSS attacks
NIST SP 800-53
SI-10: Information Input Validation; SI-15: Information Output Filtering
GDPR Article 32
Technical measures to ensure security of processing including protection of user data

References

External resources and documentation

Similar Rules

Explore related security rules for Python

Frequently Asked Questions

Common questions about Django XSS via Direct HttpResponse with User Input

Django's template engine escapes variables when rendering template files ({{ variable }}). When you construct HTML strings in Python code and pass them to HttpResponse() directly, the template engine never sees the data. Auto-escaping only applies within the template rendering system. Raw HttpResponse() with concatenated strings receives no automatic escaping.
django.utils.html.escape() converts the five HTML special characters: <, >, &, single quote, and double quote to their HTML entity equivalents. This is sufficient to prevent XSS in HTML content and attribute values when applied to user input. It does not prevent XSS in JavaScript contexts (inside <script> tags) or CSS contexts -- for those, use different escaping strategies or avoid including user input in those contexts entirely.
Yes, if you have properly escaped the string first. The pattern escape(user_input) followed by mark_safe() of the result is safe because escape() has already converted all dangerous characters. However, applying mark_safe() first and then concatenating unescaped user input is unsafe -- mark_safe() on a partial string does not protect subsequent concatenation.
Django's built-in views and the admin interface use the template system for all HTML rendering, so they do not trigger this rule. The rule specifically targets cases where user input reaches HttpResponse() through code paths that bypass the template engine, which typically means custom views that return inline HTML.
Either migrate to a template (create an HTML template file, pass all dynamic values as context, and use render()) or escape each user-controlled value with escape() before incorporating it into the HTML string. If the HTML structure itself is complex, the template approach is safer and more maintainable.
CSP is a defense-in-depth measure that can mitigate XSS impact but is not a substitute for fixing the underlying vulnerability. CSP can be misconfigured, bypassed through allowed script sources, or absent in older browsers. Fix the source of the vulnerability by escaping output, and add CSP as an additional protection layer.

New feature

Get these findings posted directly on your GitHub pull requests

The Django XSS via Direct HttpResponse with User Input rule runs in CI and posts inline review comments on the exact lines — no dashboard, no SARIF viewer.

See how it works