Server-Side Template Injection (SSTI): The Complete Practical Guide
What Is Server-Side Template Injection?
How template engines work, the difference between passing a variable and concatenating into the template, why that becomes RCE, and where SSTI hides.
Published
Before you can detect or exploit SSTI, you need a clear picture of what a template engine does and exactly where the bug lives. The whole vulnerability is one design decision: whether user input is handed to the engine as data or baked into the template as code. This page builds that picture. Practice as you read on a free live target.
Template engines in 60 seconds
Applications rarely build HTML (or emails, or PDFs) by hand. They use a template engine: a document full of static text with placeholders and small bits of logic that the engine fills in with data at render time. A greeting template might hold a placeholder for a username, a loop over a list of orders, and a conditional that shows a banner to admins. The engine takes the template plus a bag of data (the "context") and produces the final output.
Crucially, capable engines are not just doing string substitution. They let the template author read object attributes, call methods, and use built-in functions, because real pages need that logic. That power is fine when only trusted developers write templates. It becomes a weapon when an attacker can inject template syntax.
The one distinction that matters: variable vs template
Here is the entire bug, in two lines of Python using Jinja2:
# SAFE: name is passed as data in the context, never parsed as template code
Template("Hello {{ name }}").render(name=user_input)
# VULNERABLE: user_input is concatenated INTO the template source
Template("Hello " + user_input).render()In the safe version, the template is a fixed string with a name placeholder, and your input fills that placeholder as inert data. In the vulnerable version, your input is part of the template, so if you send template syntax, the engine evaluates it. Submit the 7-times-7 expression as your input and the vulnerable version renders Hello 49, because the engine computed it.
Every SSTI in the wild is some form of that second line: input reaching the template string rather than the context.
Why it escalates to code execution
Once your input is evaluated as template code, you are no longer limited to arithmetic. The engine exposes the host language's objects, and from an ordinary object you can often navigate to something dangerous: a module that spawns processes, a function that reads files, a global that imports libraries. On Python engines that path runs through object attributes to os.popen. On Java engines it runs through reflection to Runtime.exec. The engine built the door, and SSTI walks you through it. The engine-specific routes are covered in the exploitation spokes.
Where SSTI hides
SSTI is easy to miss because the "template" is often not an obvious web page. Any feature where a server builds output from a template and lets user input into the template string is a candidate:
- Emails: welcome messages, notifications, and password-reset mails are usually templated, and often let users influence a name or subject.
- Generated documents: PDFs, invoices, and reports built from a template.
- Error and notification pages: custom messages that echo input.
- Dynamic themes and layouts: anywhere a user customizes how output is rendered.
- Filenames and metadata: values that flow into a templated export.
Many of these never render the result back to you directly, which is why they are a common home for blind SSTI.
SSTI vs client-side template injection
They sound alike and are not the same. Client-side template injection happens in a browser framework (classic AngularJS sandbox escapes are the famous example) and its impact is browser-bound, in the family of cross-site scripting. Server-side template injection runs in the engine on the server, so it reaches the host and tends toward remote code execution. When your probe computes, the first question is always: did the server do that, or the browser? That distinction is the subject of the next page.
Where to go next
Now that you know what SSTI is and where it hides, learn to find it in detection and confirmation, then fingerprint the engine in identifying the engine. Or try a probe on a free live target.
← Back to Server-Side Template Injection (SSTI): The Complete Practical Guide