flawopen.com/SSTI/Explained
What is server-side template injection?
Server-side template injection occurs when untrusted input is parsed as template source instead of passed as data. The impact depends on the engine, its configuration, and what the template can access: it may range from unintended expression evaluation to server-side code execution. Do not assume every SSTI reaches code execution.
# Python / Jinja2 template = f"Hello {name}!" return render_template_string(template) # Input: {{ 7*7 }} renders as "49" # This confirms expression evaluation; # impact still depends on engine access. // Java / Freemarker String tpl = "Welcome " + userName; new Template("t", tpl, cfg) .process(model, out);
# The template is a fixed string the # developer wrote. The user value is # passed in as a variable. return render_template( "greeting.html", name=name ) # Or with a literal template string: return render_template_string( "Hello {{ name }}!", name=name ) // Java equivalent: template from file, // user value in the model map.
The distinction that matters
Every template engine has two inputs: the template and the context data. The template is a program; the data is values that program reads. SSTI is the mistake of letting user input cross from the second category into the first.
This is the same structural error as SQL injection, where data is concatenated into query text, and as Log4Shell, where data reached an expression evaluator through a log message. In each case the fix has the same shape: keep the program fixed and pass untrusted values through a parameter channel.
When the vulnerable engine exposes powerful objects or methods to a template, an attacker may be able to reach sensitive application capabilities. Whether that leads to code execution depends on the engine, version, configuration, sandbox, and exposed data model. Other outcomes include disclosure or resource exhaustion. Treat user-controlled template source as active logic; do not rely on a sandbox alone without limiting accessible objects and rendering resources.
Template expression languages are designed to navigate object graphs — read properties, call methods, iterate collections. Given that, an attacker walks from any exposed object to the language runtime: in Python, through an object's class and its inheritance chain to reach module imports; in Java, through reflection to Runtime.getRuntime(). Sandboxed modes exist in several engines, and several have had sandbox escapes.
How to detect it
{{7*7}}
${7*7}
<%= 7*7 %>
#{7*7}
If a response contains 49 rather than the literal text, the input is being evaluated as template syntax. These short arithmetic probes can help identify evaluation in an authorized test environment; syntax differs among engines and is not a reliable fingerprint by itself.
FAQ
No. Client-side template injection runs in the victim's browser and may be an XSS variant. SSTI is evaluated on the server, in the application process. Its impact depends on the engine and exposed capabilities; server-side code execution is possible in some configurations, but not an automatic result of every SSTI.
No. Auto-escaping sanitises values being rendered; it does not stop a value from being parsed as template syntax in the first place. It protects against XSS in output, not against injection into the template source.
Treat user-supplied template source as executable logic and do not process it in the main application context by default. If the feature is necessary, use an engine designed for restricted templates, expose only minimal inert data, and apply CPU, memory, output-size, and timeout limits. A sandbox can reduce access but is not a complete security boundary on its own.
References
- CWE-1336 — Improper Neutralization of Special Elements Used in a Template Engine
- PortSwigger Web Security Academy — server-side template injection
- OWASP Testing Guide — testing for SSTI
- Is Jinja2's render_template_string() safe?
- Are Freemarker and Velocity templates safe with user input?
- Jinja documentation — Sandbox security considerations