Server-Side Template Injection (SSTI) occurs when user-supplied input is embedded directly into a template file and evaluated by a server-side template engine (such as Jinja2 in Python, Twig in PHP, or Freemarker in Java) rather than being passed as a separate template context variable.
The path from template evaluation to Remote Code Execution
Template engines often possess powerful reflection and object-introspection capabilities. When an attacker injects template syntax, they can traverse class hierarchies to reach underlying operating system execution primitives:
- Polyglot mathematical probes: injecting expressions like `{{7*7}}` or `${7*7}` to identify whether template evaluation occurs and determine the underlying engine.
- Jinja2 class traversal: climbing Python object hierarchies via `{{ ''.__class__.__mro__[1].__subclasses__() }}` to locate `subprocess.Popen` and execute arbitrary shell commands.
- Twig and Smarty escapes: invoking built-in filters and execution helpers like `{{_self.env.registerUndefinedFilterCallback('exec')}}{{_self.env.getFilter('id')}}`.
Remediation: context passing vs string concatenation
Never concatenate user input directly into template strings. Always pass user input as context parameters to pre-compiled static template files: `render_template('invoice.html', customer_name=user_input)` rather than `render_template_string('Hello ' + user_input)`.
Treat template injection with maximum severity. In almost every major engine, SSTI can be reliably escalated into full remote command execution.