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-FLASK-XSS-001 --project .About This Rule
Understanding the vulnerability and how it is detected
This rule detects direct instantiation of jinja2.Environment or jinja2.Template in Flask applications. Flask wraps Jinja2 with a custom Environment that has autoescaping enabled for HTML templates (files ending in .html, .htm, .xml, .xhtml). When developers create a raw jinja2.Environment or jinja2.Template directly -- bypassing Flask's rendering pipeline -- they lose this autoescaping protection.
Without autoescaping, any template variable rendered with {{ variable }} is inserted into the HTML output as a raw string. If variable contains HTML metacharacters (<, >, ", ', &) from user input, those characters are rendered as HTML elements and attributes. An attacker who can control the variable value can inject arbitrary JavaScript that executes in the victim's browser -- a stored or reflected XSS vulnerability.
The autoescaping difference is subtle: Flask's render_template() renders {{ name }} as <script> if name is "<script>". A raw jinja2.Environment without autoescaping renders the same {{ name }} as <script>, which the browser executes.
The detection uses Or(calls("Environment"), calls("jinja2.Environment")) to match both the directly imported constructor form and the module-qualified form. This is an audit-grade rule that flags every direct Jinja2 Environment instantiation for manual review, since the presence of a raw Environment is a strong signal that autoescaping may not be configured.
Security Implications
Potential attack scenarios if this vulnerability is exploited
Reflected XSS via Unescaped Template Variables
User input rendered through a raw Jinja2 Environment without autoescaping is inserted directly into the HTML response. An attacker can craft a request with a parameter containing <script>alert(document.cookie)</script> and the script will execute in the victim's browser, stealing session cookies, redirecting to phishing pages, or performing actions on behalf of the victim.
Stored XSS via Database-Sourced Template Content
If templates are rendered from database content using a raw Jinja2 Environment, stored XSS is possible. An attacker who can write malicious HTML to a database field (through any injection or data import path) can have it rendered and executed in other users' browsers when they view the affected content.
Cookie Theft and Session Hijacking
XSS payloads can read document.cookie (for cookies without the HttpOnly flag) and exfiltrate session tokens to attacker-controlled servers. A successful XSS attack in a single unescaped template variable can compromise every active user session.
DOM-Based Defacement and Phishing
Injected JavaScript can rewrite page content, insert fake login forms, redirect users to phishing sites, or silently perform authenticated API calls on behalf of the victim.
How to Fix
Recommended remediation steps
- 1Use Flask's render_template() with .html template files for all HTML responses. Flask's Jinja2 Environment has autoescaping enabled for HTML by default.
- 2If you need to render templates outside Flask's request context (e.g., for email generation), configure the raw Jinja2 Environment with explicit autoescaping: Environment(autoescape=select_autoescape(['html', 'xml'])).
- 3Never construct template strings by concatenating user input. Pass user data as context variables to templates, where Jinja2 handles escaping.
- 4If you need raw HTML output from a trusted source, use Flask's Markup() (see PYTHON-FLASK-XSS-002) explicitly and document why the content is trusted.
- 5Implement Content-Security-Policy (CSP) headers as defense in depth. Even if XSS occurs, a strict CSP can prevent script execution.
Detection Scope
How Code Pathfinder analyzes your code for this vulnerability
This rule uses Or(calls("Environment"), calls("jinja2.Environment")) to match both the directly imported constructor (from jinja2 import Environment; Environment(...)) and the module-qualified form (jinja2.Environment(...)). This is a broad audit pattern -- every direct Jinja2 Environment instantiation is flagged for review to determine whether autoescaping is configured. Calls that explicitly pass autoescape=True or autoescape=select_autoescape([...]) may still be flagged; reviewers should verify the autoescaping configuration is correct for the use case. The rule operates at the call-site level without cross-file dataflow analysis.
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
Flask Explicit Unescape with Markup
Detects use of Markup() or markupsafe.Markup() which marks strings as safe HTML, bypassing Jinja2's autoescaping and introducing XSS risk if applied to user-controlled content.
Flask render_template_string Usage
Detects any use of render_template_string(), which renders Jinja2 templates from Python strings and is inherently adjacent to Server-Side Template Injection (SSTI) vulnerabilities.
Flask Server-Side Template Injection (SSTI)
User input from Flask request parameters flows to render_template_string() as part of the template source. Pass user data as template variables, never in the template string itself.
Frequently Asked Questions
Common questions about Flask Direct Use of Jinja2
New feature
Get these findings posted directly on your GitHub pull requests
The Flask Direct Use of Jinja2 rule runs in CI and posts inline review comments on the exact lines — no dashboard, no SARIF viewer.