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-AUDIT-008 --project .About This Rule
Understanding the vulnerability and how it is detected
This rule detects any use of render_template_string() or flask.render_template_string() in Flask applications. Unlike render_template(), which loads templates from files on disk, render_template_string() compiles and renders a Jinja2 template from a Python string passed at runtime. This creates a structural risk: if any portion of that string originates from user input, the application has a Server-Side Template Injection (SSTI) vulnerability.
SSTI in Jinja2 is critical-severity. Jinja2 templates have access to Python's object model, and attackers can use template expressions like {{ config }} to leak configuration, or {{ ''.__class__.__mro__[1].__subclasses__() }} to traverse the class hierarchy and reach os.system or subprocess for remote code execution.
This is an audit-grade rule. Not every render_template_string() call is vulnerable -- if the template string is a hardcoded literal with no user-controlled components, there is no SSTI risk. However, every use of render_template_string() is worth reviewing to confirm that the template string is fully controlled by the developer and never interpolated with user data.
The detection uses Or(calls("render_template_string"), calls("flask.render_template_string")) to catch both the directly imported function and the module-qualified call form.
Security Implications
Potential attack scenarios if this vulnerability is exploited
Server-Side Template Injection Leading to Remote Code Execution
If user input is included in the template string passed to render_template_string(), an attacker can inject Jinja2 expressions that traverse Python's object hierarchy to reach os.system, subprocess.Popen, or other code execution primitives. This is a critical-severity vulnerability with widespread exploitation.
Configuration and Secret Leakage via Template Expressions
Even without achieving code execution, an attacker can inject {{ config }} or {{ config.SECRET_KEY }} to extract Flask's full configuration dictionary from the running application, including secret keys, database URIs, and API credentials.
File System Read Access
Jinja2 template injection can be chained to read arbitrary files: by reaching Python's open() built-in through the class hierarchy, an attacker can read /etc/passwd, application source code, or private key files.
Harder to Audit Than File-Based Templates
Template strings defined in Python code are harder to audit than template files in a dedicated directory. Security reviewers scanning the templates/ directory for unsafe patterns will miss vulnerabilities in render_template_string() calls in Python source.
How to Fix
Recommended remediation steps
- 1Replace render_template_string() with render_template() using a static HTML file in the templates/ directory. User input is passed as context variables, not embedded in the template.
- 2If you must use render_template_string() for dynamically constructed templates (e.g., email templates stored in a database), ensure the template string comes from a trusted internal source and is never derived from user input, even partially.
- 3Audit every render_template_string() call to trace the origin of the template argument. If any f-string interpolation, .format(), or string concatenation with a user-derived value is present, the call is vulnerable.
- 4Enable Jinja2 sandboxing (SandboxedEnvironment) if you genuinely need to render user-provided template content.
- 5Add automated SSTI testing to your security test suite for any endpoint that uses render_template_string().
Detection Scope
How Code Pathfinder analyzes your code for this vulnerability
This rule uses Or(calls("render_template_string"), calls("flask.render_template_string")) to match both the direct import form (from flask import render_template_string; render_template_string(...)) and the module-qualified form (flask.render_template_string(...)). This is a broad audit pattern -- every call to render_template_string() is flagged regardless of whether user input is demonstrably present in the template string. The rule surfaces all uses for manual review rather than attempting dataflow analysis of the template string argument. For a dataflow rule that specifically traces user input into render_template_string(), see PYTHON-FLASK-SEC-014 (SSTI via tainted template string).
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 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.
Flask Direct Use of Jinja2
Detects direct use of jinja2.Environment or jinja2.Template, which bypasses Flask's automatic HTML autoescaping and can lead to XSS vulnerabilities.
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.
Frequently Asked Questions
Common questions about Flask render_template_string Usage
New feature
Get these findings posted directly on your GitHub pull requests
The Flask render_template_string Usage rule runs in CI and posts inline review comments on the exact lines — no dashboard, no SARIF viewer.