flawopen.com/SSTI/Explained
It happens when user input is concatenated into the template instead of passed in as data. Template engines evaluate expressions, so controlling the template means controlling an expression evaluator — which in most engines reaches the language runtime and becomes remote code execution.
# Python / Jinja2 template = f"Hello {name}!" return render_template_string(template) # Input: {{ 7*7 }} → renders "49" # That confirms evaluation, and from # there the object graph is reachable. // 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.
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.
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.
{{7*7}} ${7*7} <%= 7*7 %> #{7*7}
If a response contains 49 rather than the literal text, the input is being evaluated. The differing syntaxes also fingerprint the engine — {{ }} for Jinja2/Twig/Handlebars, ${ } for Freemarker and Thymeleaf, <%= %> for ERB and EJS.
No. Client-side template injection runs in the victim's browser and is an XSS variant. SSTI runs on your server, in your application process, with your application's privileges — the impact is typically full compromise of the host rather than the session.
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 template editing as equivalent to granting code execution on the server, and gate it accordingly. A "logic-less" engine such as Mustache is a much better choice for user-supplied templates than a general-purpose one.