I am learning pentesting, currently studying Server Side Template Injection. I understood there are two types of SSTI - plaintext context and code context - but struggle to understand what exactly is the practical difference between them.

For posterity, I'm using the OWASP Web Security Testing Guide as source here.

Regarding plaintext context it says:

The first step in testing SSTI in plaintext context is to construct common template expressions used by various template engines as payloads and monitor server responses to identify which template expression was executed by the server.

I think this is rather clear. In plaintext context, the input is inserted directly into a template, similar to this (pseudocode):

engine.render('Hello {{name}}')

Hence when we can control the content of name, we might be able to insert a HTML script tag, making it look like XSS at first, e.g. we could set name to Jon Doe <script>alert(1)</script>. To validate its SSTI, something like Jon {{7*7}} Doe can be used. When it comes back as Jon 49 Doe, the template expression has been executed and we gained some knowledge about the template engine used, either through error messages or by the delimiters that worked.

Now when it comes to code context, the example given is this:

First, the tester constructs the request that result either blank or error server responses. In the example below the HTTP GET parameter is inserted info the variable personal_greeting in a template statement:

Hello user01

Using the following payload - the server response is blank “Hello”:


In the next step is to break out of the template statement and injecting HTML tag after it using the following payload

Hello user01 <tag>

I imagine a URL similar to https://example.com?username=user01}}<script>alert(1)</script> with the following pseudocode on the server:

var personal_greeting = $GET["username"]
engine.render('Hello {{personal_greeting}}')

According to the example, the output would be something like

Hello user01<script>alert(1)</script>

My Questions:

  1. Why is personal_greeting=username<tag> supposed to come back as blank "Hello"?
  2. Why is there a need to break out of the template statement?
  3. Wouldn't a template engine throw an error, given the code context example, because there is one }} too many after we break out of the template statement?
  4. Why does it make a difference if the value of a GET parameter is inserted directly into a template vs its saved in a variable first (effectively aliasing it)?

1 Answer 1


Maybe find a better guide, SSTI often gives remote code exec. Polluting this issue with XSS is focussing on a less impactful outcome of successful exploitation

  1. Because it's trying to lookup a non existing value which returns nothing/null
  2. So you can take control of the template, otherwise you get a null per the previous answer
  3. It might, it depends on the parser. The parser probably only looks for }} after finding {{. By injecting }} you balance the lookup and the trailing }} might be considered text
  4. This would be implementation specific
  • Thanks! Your reply helped me to see SSTI in new light. I was rather focused on XSS but you're right, RCE is much more important. Regarding 1: What kind of lookup are you referring to? I was under the impression the URL would look like this: https://example.com?username=user01<script>. I don't get why the value shouldn't exist.
    – Sven
    Commented Sep 14, 2022 at 11:28
  • Because it's doing a template lookup of {{user01<tag>}} which is an undefined variable (and most likely also not a valid variable name), whereas {{username}} is a defined variable. Maybe take a look at this resource and try it for yourself in a lab, portswigger.net/research/server-side-template-injection. If you still have questions after you can open a new question with a more narrow focus and supporting code to enable better answers.
    – wireghoul
    Commented Sep 14, 2022 at 23:22
  • Thanks for the explanation and guidance, will do!
    – Sven
    Commented Sep 15, 2022 at 14:22

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .