Server-side template injection (SSTI) is a web vulnerability that occurs when a server-side template engine uses user-supplied data to generate dynamic HTML content without proper validation or escaping. This can allow an attacker to inject malicious code into a template, which is then executed server-side.

In cases where remote code execution is impossible, an attacker can still use server-side template injection as the basis for other attacks, like reading sensitive data or performing XSS attacks.

Identify SSTI vulnerability

The first step in testing SSTI is to construct common template expressions used by different template engines as payloads and monitor the server's response to identify which template expression was executed by the server. This polyglot payload will trigger an error in the presence of an SSTI vulnerability ${{<%[%'"}}%\.

You can try the template-engines-expression.txt wordlist and these ones:

[% var %]

Identify its context

The injection can occur in two distinct contexts, which must be identified to exploit this vulnerability.

Plaintext context

In most template languages, you can insert content into a template either by using HTML tags directly or by using the template's own syntax, which will be converted to HTML on the back-end before the HTTP response is sent to the user. For example, in Freemarker, the line render('Hello There! ' + username) would be converted to something like Hello Carlos in the HTML that is sent to the user's web browser.

Note: This feature can sometimes be exploited for cross-site scripting (XSS) attacks and is often mistaken for a simple XSS vulnerability. However, by attempting to set mathematical operations as the value of a parameter, it is possible to test whether a given input is also a potential entry point for a server-side template injection attack.

Code context

In this context, the user input is placed within a template expression-like engine.render("Hello {{"+username+"}}", data).

One way to test for the presence of a server-side template injection vulnerability is first to try injecting arbitrary HTML tags such as <img> or <tag> into the value of a parameter, in order to determine whether the input is vulnerable to a direct cross-site scripting (XSS) attack. If the HTML is not properly escaped or sanitized, it may be possible to exploit the vulnerability to inject malicious code into the generated output. This can help to confirm whether the parameter is a potential entry point for a template injection attack.

If the attempt to perform an XSS attack did not work. The next step is to try to break out of the template syntax and inject additional HTML using common templating syntax. For example, an attacker might try to inject a <script> tag or other malicious code after the template statement. If the template engine allows this injection, it may be vulnerable to template injection attacks.

Finally, if that leads to an error or blank output, it might be you are using the wrong syntax for the engine language that is executing the web application. However, if the output is rendered correctly, along with the arbitrary HTML, that is a key indication that the vulnerability exists.

Identify the Templating Engine

To identify the template engine, the simplest method is submitting invalid syntax, hoping that the error message will tell you exactly what the template engine is.

Another alternative is to manually test different language-specific payloads and study how they are interpreted by the engine. To do so, you can use this decision tree made by James Kettle.

Template decision tree


Then, once discovered the templating engine, you can try to retrieve special variables of the template engine with the template-engines-special-vars wordlist or perform code execution using these payloads.


Last updated