Server-Side Template Injection (SSTI)
What Is This Vulnerability?
Server-side template injection occurs when user input is embedded directly into a template engine's template string rather than passed as a data parameter. This allows attackers to inject template directives that the engine evaluates on the server, potentially leading to information disclosure, file reads, or full remote code execution.
Why It Happens
Developers sometimes construct template strings dynamically by concatenating user input with template syntax. This happens when generating personalized emails, dynamic pages, or reports where the template itself is built at runtime instead of using the template engine's variable substitution mechanism safely.
Example Code
from flask import Flask, request, render_template_string
app = Flask(__name__)
@app.route("/greet")
def greet():
name = request.args.get("name", "World")
template = f"<h1>Hello {name}!</h1>"
return render_template_string(template)from flask import Flask, request, render_template_string
app = Flask(__name__)
@app.route("/greet")
def greet():
name = request.args.get("name", "World")
template = "<h1>Hello {{ name }}!</h1>"
return render_template_string(template, name=name)How Hackers Exploit It
An attacker submits template syntax as input, such as {{7*7}} for Jinja2. If the response shows 49 instead of the literal string, the engine is evaluating the expression. From there, the attacker escalates to reading files ({{config.items()}}), accessing environment variables, or achieving remote code execution by traversing Python's class hierarchy to reach os.popen().
How to Fix It
Never insert user input directly into template strings. Always pass user data as context variables using the template engine's built-in parameter mechanism. If you must use dynamic templates, use a sandboxed template environment like Jinja2's SandboxedEnvironment. Restrict access to dangerous attributes and methods in the template context.