Server-Side Template Injection (SSTI) Guide
Overview
Server-Side Template Injection (SSTI) occurs when user-controlled input is embedded directly into a server-side template and evaluated as code. This vulnerability can lead to information disclosure, arbitrary file access, or even remote code execution (RCE).
Template engines are designed to render dynamic content by combining templates with data. However, when untrusted input is injected into templates without proper sanitization, attackers can manipulate the rendering logic and execute arbitrary code on the server.
Constructing an SSTI Attack
1. Detection Phase
A. Identify User Input Reflection
Locate areas where user input is reflected in the server response. These can often be discovered via manual inspection or interception proxies such as Burp Suite.
B. Fuzz with Polyglot Payloads
Use polyglot payloads containing syntax elements from multiple template engines to detect potential SSTI:
POST /endpoint HTTP/1.1
Host: vulnerable-site.com
parameter=$%\.
If the server’s response changes, produces an error, or displays evaluated expressions, SSTI may be present.
C. Observe Server Responses
Indicators of SSTI include:
- Evaluated expressions (e.g.,
${7*7}→49) - Template syntax errors
- Stack traces or framework-specific messages
- Incomplete or malformed responses
2. Syntax Testing: Determine Template Context
A. Plaintext Context
Test with simple arithmetic expressions:
${7*7}
<%= 7*7 %>
#{7*7}
If the output returns 49, your payload was evaluated — confirming SSTI.
B. Expression Context
When user input is directly inserted into an active expression, attempt to break the syntax:
engine.render("Hello +greeting+", data)
Then test with:
/greeting=data.username
/greeting=data.username}}hello
If closing the expression (}}) affects rendering or triggers an error, SSTI is likely.
Identification Phase: Determine the Template Engine
Once SSTI is verified, identifying the specific template engine is crucial for crafting engine-specific payloads.
A. Trigger and Analyze Errors
Inject malformed expressions:
${}
<%= %>
${foobar}
<%= foobar %>
${7/0}
<%= 7/0 %>
Error messages or stack traces may reveal the engine name (e.g., Jinja2, Twig, Freemarker, etc.).
B. Test Engine-Specific Syntax
If no explicit error message appears, test common syntaxes for popular engines:
=${7*3}
=
=<%= 7*3 %>
If a specific syntax evaluates correctly (21), it identifies the underlying template engine.
Exploitation Phase
Step 1: Review Documentation
Study engine-specific documentation or resources like HackTricks to identify:
- Built-in objects and filters
- Sandbox restrictions and bypasses
- Known exploit primitives
Step 2: Enumerate Accessible Objects
Attempt to access key objects:
If unavailable, perform brute-force enumeration using SecLists or Burp Intruder wordlists of potential variables and object attributes such as:
__class__, __mro__, __subclasses__
Step 3: Execute Payloads
Once internal objects are accessible, escalate to RCE or file access.
Example (Jinja2):
Tools
Tplmap
Tplmap automates the detection and exploitation of SSTI vulnerabilities.
Usage Examples:
python2.7 tplmap.py -u 'http://target.com/page?name=John*' --os-shell
python2.7 tplmap.py -u "http://target.com/page?user=*&comment=hello"
python2.7 tplmap.py -u "http://target.com/ti?user=InjectHere*&comment=A" --level 5 -e jade
Summary: SSTI Exploitation Workflow
1. Identify user input reflection
2. Inject polyglot payload: $%\.
3. Test for evaluation (, ${7*7}, <%= 7*7 %>)
4. Observe output or error to confirm SSTI
5. Determine the template engine by syntax or stack trace
6. Enumerate internal objects
7. Exploit: Execute commands, read files, escalate privileges
Summary Notes: “Template Engines Injection 101” by 0xAwali
Source: Template Engines Injection 101 – @0xAwali
🔍 Overview
The post explores how Server-Side Template Injection (SSTI) vulnerabilities arise, how to detect them, and how different engines behave under injection. It also provides payloads and error-based fingerprinting methods for accurate engine identification.
⚙️ Covered Template Engines
| Language | Template Engines |
|---|---|
| JavaScript | EJS, Handlebars, Vue, Pug |
| Python | Jinja2, Tornado, Django, Mako |
| Ruby | ERB, Slim, HAML |
| PHP | Twig, Smarty, Blade |
| Java | Velocity, Freemarker, Thymeleaf |
| Go | text/template, html/template |
📊 Language Summaries
JavaScript Summary:
Python Summary:
Ruby Summary:
PHP Summary:
Java Summary:
Go Summary:
🧩 Universal Payloads
After analysis, it was observed that 15 universal payloads could detect or exploit most template engines:
🧠 Key Concepts
- SSTI Definition: Untrusted input executed in the server’s template engine.
- Goal: Achieve arbitrary code execution or sensitive data access.
- Risk: Leads to RCE, file disclosure, and system compromise.
🧰 Practice Resources
- PortSwigger’s SSTI Labs
- Hackmanit’s Template Injection Playground
- Official documentation for each template engine
Ideal for CTF participants, bug bounty hunters, and security professionals.
⚠️ Ethical Use
Always test SSTI only in authorized environments such as CTFs, labs, or your own applications. Never use these payloads against live systems without explicit permission.
📚 Takeaway
This article by @0xAwali provides one of the most comprehensive overviews of SSTI, covering detection, identification, and exploitation across multiple programming languages.
References
- HackTricks SSTI Guide
- A Pentester’s Guide to SSTI – Medium
- OWASP Template Injection Cheat Sheet
- Tplmap GitHub Repository