Vulnerability Overview
User input submitted to an announcement field was passed directly into a Jinja2 template engine and rendered as code rather than treated as data. This allowed injection of arbitrary Python expressions, culminating in Remote Code Execution (RCE) and full server file system access.
Confirming SSTI
The challenge description referenced "templating" — an immediate indicator to test for SSTI. The standard detection payload was submitted to the announcement input:
{{7*7}}Rather than rendering the literal string, the server returned 49 — confirming that user input was being executed by the template engine.
Fingerprinting the Template Engine
Different template engines handle expression evaluation differently. To confirm Jinja2 specifically:
{{7*'7'}}Output: 7777777. Jinja2 repeats a string when multiplied by an integer, producing this exact result. This confirmed a Python + Jinja2 backend, which means access to Python's full object hierarchy is available through template expressions.
Escalating to Remote Code Execution
Jinja2 allows traversal of Python's object graph through __globals__ and __builtins__. The following payload imported the os module and executed an arbitrary shell command:
{{request.application.__globals__.__builtins__.__import__('os').popen('ls').read()}}The directory listing revealed a file named flag. Reading it directly:
{{request.application.__globals__.__builtins__.__import__('os').popen('cat flag').read()}}Root Cause
The application passed raw user input as a template string to be rendered, rather than passing it as a variable within a safe template. The distinction is critical:
# VULNERABLE — user input becomes executable code
template = Template(user_input)
result = template.render()
# SAFE — user input is data, never code
template = Template("Announcement: {{ message }}")
result = template.render(message=user_input)| Control | Implementation |
|---|---|
| Never render user input as a template | Pass user data as a variable to a static template string |
| Enable Jinja2 sandboxing | Use SandboxedEnvironment to restrict object traversal |
| Input validation | Reject or escape {{, }}, and __ sequences at the application layer |