Skip to main content
Server-Side Template Injection (SSTI) occurs when user input is embedded directly into a template that is subsequently rendered by the server. If the input reaches the template engine unsanitised, the engine executes it as code during rendering.

Confirming SSTI

Inject the universal test string to provoke a syntax error in any popular template engine:
If the application returns a server error or mangled output, the parameter is likely passed to a template engine. Follow up with arithmetic payloads to confirm execution.

Identifying the Template Engine

Inject arithmetic payloads and follow the response to narrow down the engine. Start with ${7*7}. If not executed, try {{7*7}}. If that executes, try {{7*'7'}} to tell Jinja2 (repeats the string) from Twig (returns 49).

Jinja2

Jinja2 is used in Python web frameworks (Flask, Django). Any library already imported by the application is accessible in payloads.

Information Disclosure

Local File Read

Remote Code Execution

If os is not already imported, __import__ handles it inline.

Twig

Twig is the template engine for PHP. The _self keyword exposes limited internal information.

Information Disclosure

Local File Read

Twig itself has no file-read function, but Symfony’s file_excerpt filter exposes one:

Remote Code Execution

Twig’s filter() passes the array element as an argument to the named PHP function.

Handlebars

Handlebars is a JavaScript template engine common in Node.js applications. It has a sandbox, but this.constructor.constructor exposes the native Function constructor, which evaluates arbitrary JavaScript strings and breaks out of the sandbox entirely.

Confirming SSTI

If any of these return [object Object] or a function reference rather than the raw string, Handlebars is rendering the input.

Remote Code Execution

Use #with to shift context to the Function constructor, then call it with a JavaScript string to execute:
Chained form using process.env to confirm code execution before running commands:
Reverse shell variant:
The payload works because Handlebars’ #with helper shifts the block context to whatever value is passed. Passing the result of Function('return ...')() executes arbitrary JS and makes the result the new context, which is then printed with {{this}}.

SSTImap

SSTImap automates SSTI detection and exploitation across 17 template engines.

Payload Reference