SSTI (Server-Side Template Injection)
User input rendered through a template engine like a template tag. Reaching {{ or {% in user-controlled content lets an attacker reach the template runtime and pivot to RCE.
What it catches
- Jinja2 / Django:
{{ ... }},{% ... %},{{ config }},{{ self.__init__ }} - Twig:
{{ _self }},{{ dump() }} - Freemarker:
${...},<#assign> - ERB / EJS:
<%= ... %>,<% ... %> - Pug / Jade:
#{ ... } - Python dunder chains:
__class__.__mro__,__subclasses__,__globals__,__builtins__ - Encoded variants via NFKC + multi-decode
Sample payload
// Before (display name field)
"{{ ''.__class__.__mro__[2].__subclasses__()[59].__init__.__globals__['os'].popen('id').read() }}"
// After (sanitize)
""
// In block mode: 403, vector=ssti, rule=patterns.ssti.jinja-curly
Configuration
app.use(arcis({
block: true,
sanitize: { ssti: { enabled: true } }
}));
Disable
app.post('/admin/template-preview', arcis({ sanitize: { ssti: false } }), handler);
References
Defense-in-depth. Never render user input through your template engine. Use template literals or string interpolation only for trusted strings. Arcis catches obvious attempts; sandboxed template engines (Jinja2's SandboxedEnvironment) close the rest.