Server-Side Template Injection
detect, understand, remediate
SSTI occurs when user input is embedded directly into server-side template code, allowing attackers to inject template expressions that execute arbitrary code on the server.
No credit card required. Free plan available forever.
What is server-side template injection?
Server-side template injection (SSTI) occurs when user-controlled input is embedded directly into a server-side template before rendering. Classified under CWE-1336, SSTI allows attackers to inject native template syntax that the template engine interprets and executes on the server. Unlike cross-site scripting, which targets the client browser, SSTI targets the server itself, making it significantly more dangerous.
Template engines such as Jinja2 (Python), Twig (PHP), Freemarker (Java), and Pug (Node.js) are designed to generate dynamic HTML by mixing static templates with data. When developers pass user input directly into the template string rather than the template context, attackers gain the ability to execute arbitrary expressions. In many template engines, this can be escalated from simple expression evaluation to full remote code execution.
The severity of SSTI is typically critical. Once an attacker achieves code execution through template injection, they can read files from the server, access environment variables containing database credentials and API keys, pivot to internal services, and establish persistent backdoors. Detection requires a combination of static code analysis to identify dangerous template construction patterns and runtime testing to confirm exploitability.
How it works
Identify template rendering
The attacker locates user input that is reflected in rendered pages, emails, PDF reports, or error messages. Inputs embedded in URLs, form fields, or API parameters are common targets.
Inject template syntax
The attacker submits template expressions like {{7*7}}, ${7*7}, or #{7*7} to determine which template engine is in use. A response containing "49" confirms server-side evaluation.
Confirm code execution
With the template engine identified, the attacker crafts engine-specific payloads to access built-in objects, call methods, and read server-side data such as environment variables or file contents.
Escalate to RCE
The attacker chains template engine features to achieve full remote code execution, running operating system commands, installing backdoors, or exfiltrating sensitive data from the server.
Common causes
User input concatenated into templates
Passing user-supplied strings directly into template strings (e.g., render_template_string(user_input) in Flask) instead of passing data as template variables. This is the most direct cause of SSTI.
Template engine misconfiguration
Running template engines without sandboxing or with overly permissive configurations that allow access to dangerous built-in functions, class loaders, or operating system interfaces.
Mixing data and code layers
Architectures where user content is stored and later rendered as a template rather than as static data. CMS platforms, email template builders, and report generators are common offenders.
Developer convenience shortcuts
Using template rendering as a quick way to generate personalized content (greetings, notifications, error messages) without considering that user-controlled values become executable code.
How to detect it
Automated detection
- SecPortal's code scanner identifies dangerous template construction patterns, including calls to render_template_string, Template(user_input), and similar functions across multiple languages
- SAST rules powered by Semgrep detect data flow from user input sources to template rendering sinks, catching SSTI vulnerabilities before code reaches production
- Fuzzing with template-specific payloads (polyglot strings covering Jinja2, Twig, Freemarker, and Pug syntax) can identify SSTI in running applications during authenticated scanning
Manual testing
- Submit mathematical expressions in common template syntaxes (e.g., {{7*7}}, $${7*7}, <%= 7*7 %>) and check if the response contains the computed result "49"
- Analyze error messages when malformed template syntax is submitted, as stack traces often reveal the template engine and version in use
- Use engine-specific exploitation payloads from resources like PayloadsAllTheThings to verify the depth of exploitation possible, from data leakage to full RCE
How to fix it
Use logic-less or sandboxed templates
Choose template engines that limit or eliminate code execution capabilities, such as Mustache or Handlebars. If using a full-featured engine like Jinja2, enable sandboxed mode to restrict access to dangerous objects and functions.
Never pass user input to template strings
Always pass user data as template context variables, never as part of the template source itself. Use render_template("page.html", name=user_input) rather than render_template_string("Hello " + user_input).
Implement strict input validation
Validate and sanitize all user input before it reaches any rendering pipeline. Reject or escape template-specific characters and syntax patterns (curly braces, angle brackets, dollar signs) based on the template engine in use.
Sandbox template engine execution
Run template rendering in a restricted environment with minimal permissions. Remove access to dangerous built-in classes, functions, and modules. In Jinja2, use SandboxedEnvironment; in Java, configure security managers for template engines.
Audit and scan template usage in CI/CD
Integrate SAST tools into your deployment pipeline to catch template injection patterns before they reach production. Review all code paths where user input flows into template rendering functions during security assessments.
Compliance impact
Related vulnerabilities
Detect template injection vulnerabilities
SecPortal's code scanner identifies unsafe template patterns across Jinja2, Twig, Freemarker, and other engines. Start free.
No credit card required. Free plan available forever.