Tplmap: Automating Server-Side Template Injection Exploitation Across 15+ Engines
Hook
A single curl request returning ‘49’ instead of ‘{{7*7}}’ might seem like a quirky XSS variant, but it’s actually your gateway to complete server takeover through Server-Side Template Injection.
Context
Server-Side Template Injection emerged as a critical vulnerability class when developers began concatenating user input directly into template strings rather than passing variables through template contexts. Unlike traditional injection attacks that target databases or operating systems directly, SSTI exploits the template rendering engine itself—turning what appears to be a simple reflection vulnerability into remote code execution. The challenge for security researchers was the sheer diversity of template engines: Jinja2 and Mako in Python, ERB and Slim in Ruby, Smarty and Twig in PHP, plus numerous JavaScript engines like Nunjucks and Pug. Each engine has unique syntax, different sandbox implementations, and specific escape techniques. Manual testing required deep knowledge of each engine’s internals and attack vectors.
Tplmap emerged from this complexity as a specialized penetration testing tool that automates both detection and exploitation. Built on research from James Kett’s foundational work on SSTI and enriched with original sandbox escape techniques, it systematically probes web application parameters with engine-specific payloads, fingerprints the underlying template engine, and automatically chains exploitation techniques to achieve shell access. The tool bridges the gap between knowing SSTI exists as a vulnerability class and actually exploiting it in real-world scenarios where you don’t know which of 15+ possible engines you’re facing.
Technical Insight
Tplmap’s architecture revolves around a plugin system where each template engine gets its own detection and exploitation module. The tool operates in distinct phases: injection point discovery, engine fingerprinting, and capability-based exploitation. During detection, it injects polyglot payloads that behave differently across engines—for instance, {{7*7}} renders as ‘49’ in Jinja2 but may error or pass through unchanged in other engines. The tool tracks these behavioral signatures to identify the specific engine and version.
The README provides a perfect example of the vulnerability pattern tplmap targets. Consider this Flask application using Jinja2 unsafely:
from flask import Flask, request
from jinja2 import Environment
app = Flask(__name__)
Jinja2 = Environment()
@app.route("/page")
def page():
name = request.values.get('name')
# VULNERABLE: Concatenating user input to template string
output = Jinja2.from_string('Hello ' + name + '!').render()
# SAFE: Pass variable through template context
# Jinja2.from_string('Hello {{name}}!').render(name = name)
return output
The vulnerability is subtle but devastating. By concatenating user input directly into the template string, you’re allowing users to inject template directives that execute during rendering. The safe approach passes the variable through the template context where it’s treated as data, not code.
When you run tplmap against a vulnerable endpoint, it systematically tests each plugin:
$ ./tplmap.py -u 'http://www.target.com/page?name=John'
[+] Testing if GET parameter 'name' is injectable
[+] Smarty plugin is testing rendering with tag '{*}'
[+] Mako plugin is testing rendering with tag '${*}'
[+] Jinja2 plugin is testing rendering with tag '{{*}}'
[+] Jinja2 plugin has confirmed injection with tag '{{*}}'
Once an engine is identified, tplmap selects appropriate exploitation techniques. For Jinja2, it appears to leverage Python’s introspection capabilities to escape the sandbox, likely accessing object hierarchy attributes to find classes that provide file system or subprocess access. This is engine-specific knowledge encoded into each plugin—Smarty requires different techniques, while JavaScript engines like Nunjucks appear to exploit different mechanisms.
The tool’s post-exploitation capabilities are impressive. After confirming injection, tplmap offers a pseudo-shell interface:
$ ./tplmap.py --os-shell -u 'http://www.target.com/page?name=John'
[+] Run commands on the operating system.
linux $ whoami
www
linux $ cat /etc/passwd
root:x:0:0:root:/root:/bin/bash
Under the hood, each shell command appears to be wrapped in an engine-specific payload that executes the command and returns output through the HTTP response. For blind injection scenarios where output isn’t reflected, tplmap supports time-based techniques, as indicated by its blind injection capabilities.
The architecture also handles context-aware injection. Template injection doesn’t always occur in raw text contexts—sometimes user input lands inside template comments, attribute values, or other contexts. The tool’s detection phase appears to test various injection contexts and adjust payload syntax accordingly.
Gotcha
The elephant in the room: tplmap is explicitly no longer maintained. The author states upfront that the project isn’t actively developed, though pull requests are accepted if they pass the test suite. This has real implications. Template engines evolve, security patches land, and exploitation techniques get discovered and mitigated. The README’s engine compatibility table reveals the reality—Twig versions above 1.19 aren’t exploitable, secured Smarty configurations block attacks, and newer Dust.js versions (above dustjs-helpers@1.5.0) have closed the holes. If you’re testing modern applications with updated dependencies, many of tplmap’s exploits simply won’t work.
Blind injection support, while technically present according to the capabilities table, can be painfully slow. When the application doesn’t reflect output and you’re relying on time-based or out-of-band techniques, each command might take seconds or minutes to execute and verify. The pseudo-terminal experience degrades significantly in blind scenarios. Additionally, the tool’s effectiveness depends heavily on the target’s security posture. Applications with properly configured Web Application Firewalls, restrictive outbound network policies, or hardened template engine configurations will block many standard payloads. Tplmap automates the common cases brilliantly, but edge cases—custom template engines, non-standard configurations, or novel sandbox implementations—still require manual analysis and custom payload development.
Verdict
Use tplmap if you’re conducting penetration tests on web applications, especially legacy systems or CTF challenges where SSTI is suspected. It’s invaluable for quickly determining whether a reflection point is exploitable and which engine you’re dealing with, saving hours of manual payload crafting. The automated exploitation capabilities provide immediate value once a vulnerability is confirmed, and the tool’s research foundation makes it an excellent reference for understanding SSTI techniques across different engines. Skip tplmap if you need actively maintained tooling with support for the latest template engine versions, if you’re exclusively testing modern applications with current dependencies (where documented exploits are likely patched), or if you require vendor-backed security tools for compliance reasons. For production security assessments on up-to-date stacks, you’ll likely need to supplement tplmap with manual testing using current payload collections and research.