Jinja2 template injection is server-side template injection (SSTI) in the Jinja2 engine used by Flask and other Python apps. It happens when user input is concatenated into the template source and rendered, so {{ ... }} expressions from the attacker execute on the server. From there an attacker reads the Flask config (which often holds secrets), walks Python objects, and reaches OS command execution. The fix is to pass user input as template data, never as template source.
What Jinja2 template injection is
Jinja2 renders templates by evaluating expressions inside {{ }} and {% %}. The vulnerability appears when the template string itself is built from user input, for example render_template_string('Hello ' + name) or an f-string that drops user data into the template body. Now the user controls template syntax, not just template data, so their expressions are evaluated with the privileges of the app. This is a specific, high-impact case of server-side template injection (SSTI).
How it works and example
The standard probe is a math expression only a template engine would evaluate: send {{7*7}}, and if the response contains 49, input is being rendered as a template. On Jinja2 an attacker then escalates from expression evaluation to code execution by reaching Python builtins through object attributes, for example {{ config.__class__.__init__.__globals__['os'].popen('id').read() }} or {{ cycler.__init__.__globals__.os.popen('id').read() }}. Simply rendering {{ config }} often dumps the Flask configuration, including SECRET_KEY and database credentials. Payloads are shown here for defensive testing.
How to fix it
Never build a template out of user input. Keep templates as static files and pass user data through the render context, for example render_template('page.html', name=name), so input is treated as data and escaped, not as template code. If you truly must render user-supplied templates, use Jinja2's SandboxedEnvironment, but treat it as defence in depth because sandbox escapes have existed; the safer stance is not to render untrusted templates at all. Note that autoescaping protects against XSS in the output, it does not prevent SSTI.
References
- [1]OWASP Web Security Testing Guide(OWASP)
- [2]MITRE CWE-1336: Server-Side Template Injection(MITRE CWE)
- [3]Jinja2 sandbox documentation(Pallets)
- [4]OWASP Top 10(OWASP)
If any user input reaches a template string, Jinja2 SSTI is in your threat model. Talk to a security expert about testing it end to end.