flawopen.com/SSTI/Jinja2
Is Jinja2's render_template_string() safe?
Treat render_template_string() as safe only when its template source is a literal controlled by the application. If untrusted input is inserted into that source before Jinja parses it, the result is server-side template injection (SSTI). In Flask's default, unsandboxed Jinja environment, impact can include code execution, depending on reachable objects, configuration, and the exact application; it is not automatic in every deployment.
# All four are the same bug render_template_string(f"Hi {name}") render_template_string("Hi " + name) render_template_string("Hi %s" % name) render_template_string("Hi {}".format(name)) # A very common real-world shape: @app.errorhandler(404) def not_found(e): return render_template_string( f"<h1>No such page: " f"{request.path}</h1>" ), 404 # The URL path is attacker-controlled.
# Template is a literal; the user value # arrives as a named context variable render_template_string( "Hi {{ name }}", name=name ) # Better still, a real template file render_template("greeting.html", name=name) # For the 404 case, no template # evaluation is needed at all: return render_template("404.html", path=request.path), 404
Why attacker-controlled template source matters
Flask makes application globals such as config, request, and session available in templates by default. If an attacker controls the template source, Jinja evaluates their template expressions with the objects available to that environment. The impact depends on which objects and capabilities the application exposes. A harmless arithmetic expression can confirm that evaluation occurred, but that alone does not establish code execution or prove what data is reachable.
A template may expose sensitive values if the application put them in the context. For example, Flask's config object can include a SECRET_KEY or database settings, but deployments differ. Avoid placing secrets in data visible to templates, and do not treat output escaping as a boundary around template evaluation.
CVE-2024-56201: a separate Jinja compiler issue
This is a separate Jinja compiler vulnerability, not a prerequisite for ordinary SSTI: CVE-2024-56201 affects Jinja 3.0.0 through 3.1.4 when an attacker can control both a template's contents and its filename. Under that condition, arbitrary Python code execution was possible even with the sandbox. Jinja 3.1.5 fixed the issue. Check the advisory and upgrade if your application accepts attacker-authored templates or filenames.
Where this tends to appear
Rarely in a main page handler, where developers use template files. It shows up in error handlers that echo the requested path, admin features that render user-authored email or notification templates, multi-tenant "custom branding" features, and debug or preview endpoints that were never intended to ship.
FAQ
No. Autoescaping escapes rendered values to prevent XSS in the output. It does not prevent a user-supplied string from being compiled as template source. The two controls address different stages.
Jinja provides SandboxedEnvironment for user-authored templates, but its documentation warns that it is not perfect security. Pass only the data the template needs, avoid objects with side effects, and enforce CPU, memory, and process limits outside the template engine. A sandbox does not make it safe to interpolate untrusted input into a template before parsing.
Search for render_template_string and inspect whether its first argument is a fixed application-owned template string. User values should be passed as named context variables, or rendered by a template file. Also review APIs that compile templates dynamically, including controls over template names.