1 How SSTI Works
Server-Side Template Injection (SSTI) occurs when user-supplied input is embedded directly into a template string that is then rendered by the template engine. Instead of being treated as data, the input is interpreted as template syntax — allowing an attacker to run arbitrary expressions.
Vulnerable Flask/Jinja2 example:
from flask import Flask, request, render_template_string
app = Flask(__name__)
@app.route('/greet')
def greet():
name = request.args.get('name', 'World')
# DANGER: user input is part of the template string itself
template = f"<h1>Hello, {name}!</h1>"
return render_template_string(template)
An attacker sends ?name={{7*7}}. The server renders <h1>Hello, 49!</h1> — proving that Jinja2 evaluated the expression. This is the classic detection payload.
Template engines that are vulnerable when fed user input:
- Python: Jinja2, Mako, Chameleon
- PHP: Smarty, Twig, Blade
- Java: Freemarker, Velocity, Thymeleaf
- JavaScript: Pug, Handlebars, EJS
- Ruby: ERB
Detection payloads vary by engine. {{7*7}} = 49 in Jinja2/Twig; 49 = 49 in Freemarker; #{7*7} = 49 in Ruby ERB.