Server Side Template Injection¶
ID: py/template-injectionKind: path-problemSecurity severity: 9.3Severity: errorPrecision: highTags: - security - external/cwe/cwe-074Query suites: - python-code-scanning.qls - python-security-extended.qls - python-security-and-quality.qls
Click to see the query in the CodeQL repository
A template from a server templating engine such as Jinja constructed from user input can allow the user to execute arbitrary code using certain template features. It can also allow for cross-site scripting.
Recommendation¶
Ensure that an untrusted value is not used to directly construct a template. Jinja also providesSandboxedEnvironment that prohibits access to unsafe methods and attributes. This can be used if constructing a template from user input is absolutely necessary.
Example¶
In the following case,template is used to generate a Jinja2 template string. This can lead to remote code execution.
fromdjango.urlsimportpathfromdjango.httpimportHttpResponsefromjinja2importTemplate,escapedefa(request):template=request.GET['template']# BAD: Template is constructed from user input.t=Template(template)name=request.GET['name']html=t.render(name=escape(name))returnHttpResponse(html)urlpatterns=[path('a',a),]
The following is an example of a string that could be used to cause remote code execution when interpreted as a template:
{% for s in ().__class__.__base__.__subclasses__() %}{% if "warning" in s.__name__ %}{{s()._module.__builtins__['__import__']('os').system('cat /etc/passwd') }}{% endif %}{% endfor %}In the following case, user input is not used to construct the template. Instead, it is only used as the parameters to render the template, which is safe.
fromdjango.urlsimportpathfromdjango.httpimportHttpResponsefromjinja2importTemplate,escapedefa(request):# GOOD: Template is a constant, not constructed from user inputt=Template("Hello, {{name}}!")name=request.GET['name']html=t.render(name=escape(name))returnHttpResponse(html)urlpatterns=[path('a',a),]
In the following case, aSandboxedEnvironment is used, preventing remote code execution.
fromdjango.urlsimportpathfromdjango.httpimportHttpResponsefromjinja2importescapefromjinja2.sandboximportSandboxedEnvironmentdefa(request):env=SandboxedEnvironment()template=request.GET['template']# GOOD: A sandboxed environment is used to construct the template.t=env.from_string(template)name=request.GET['name']html=t.render(name=escape(name))returnHttpResponse(html)urlpatterns=[path('a',a),]
References¶
Portswigger:Server-Side Template Injection.
Common Weakness Enumeration:CWE-74.