If you're a returning visitor to our CTF Recaps, feel free to dive straight into the insights! For first-time explorers, let us quickly introduce you to the essence of these recaps. Wizer CTFs were introduced to challenge developers, encouraging them to adopt a hacker's mindset and thereby code more securely. This initiative is a pivotal part of our new security awareness training, specially crafted for development teams - Wizer's Secure Code Training for Developers!

After a challenge retires, our Wizer Wizard and CTO, Itzik Spitzen, crafts takeaways that offer valuable insights into the challenge, focusing on the defensive perspective for your script. Curious to test-drive a CTF before delving into the notes? Visit wizer-ctf.com – it's free, and there's something for all skill levels!


In this challenge, we identify an SSTI (Server-Side Template Injection) vulnerability which results in exposing a secret environment variable.

Description of code

Our code is an invite card creator that allows users to generate cards to invite others. It does it by using the EJS (Embedded Javascript) template engine. A user can provide a first-name, last-name and role, which will then result in a lovely invite card for that person. The code is intended to strictly limit the use of the following arguments <%=firstName%>, <%=lastName%> and <%=role%>, which it does pretty well. The code then uses the `ejs.render()` method to generate the card which is sent back to the API caller as a string.

What’s wrong with that approach?

The main flaw of the code is that it's passing through extended options as the 3rd argument to the `ejs.render()`, and by that, allowing the settings to be fully controlled through user input. If we read the manual, we can see that one could provide certain options which change the behavior of the library.

By reading the manual of that intended functionality here:

We can quickly spot an interesting setting which could be altered in order to potentially inject malicious code to run within the context of the app.

What would a successful SSTI attack look like in this case?

Once the attacker realizes that it's possible to alter the delimiters, the code which is restricting the arguments to specific ones is no longer relevant, an attacker could change the delimiter and then provide a new argument, one or more, which will be interpreted in the context of the app.
For example providing the following delimiters:

    "delimiter": ".",
    "openDelimiter": "[",
    "closeDelimiter": "]"

Then, providing a `[.<malicious code goes here>.]` argument, won't be restricted by the app code and will indeed run in the app. To achieve the goal of the game, a malicious code should read the `champ_key` and then, once known, the next API invocation could include the champ key and capture the flag.

So what?

Needless to point out that an SSTI is a remarkably capable attack, which allows an attacker to practically run malicious code within the context of a currently running app. Since it's a server side attack, an SSTI is a powerful entry point which could result in gaining unauthorized access to data from various sources (such as environment variables, database, other APIs which are accessible in that code etc.) and even executing shell commands remotely and potentially taking over the server.

Main Takeaways:

  • RTFM! Read The Freaking Manual!:
    Seriously, whenever using a library to perform anything, read the manual to understand what type of risks could be imposed by taking advantage of the various options it provides, and especially if user input is involved. In this case, the ability to change the library options using user input slipped through the cracks.
  • Avoid creation of template strings from user input:
    Always preset templates on the server and feed arguments under strict control and sanitization of user inputs. Some apps may require more flexibility, so if there's absolutely no way around it, the user-input template should be strictly sanitized and we need to make sure that the user doesn't have control over any extended or more powerful than intended options. Always remember that a template engine might have such loopholes or powerful intended behaviors by the nature of its designed purpose.
  • Attackers don't necessarily need access to the code to identify SSTI vulns:
    Experienced attackers can fairly easily map code which is using a template engine. Then based on the type of template engine, they already have the risks mapped and could effectively exploit them. This article is a great resource by PortSwigger (the company behind Burp Suite) about some of the attack strategies and best practices


Wanna join us on our next challenge? Sign up for our mailing list at wizer-ctf.com.


Past Challenges

CTFs For Developers