From 6a0ddf1f3ec38611d3fb5365ee82182f52120882 Mon Sep 17 00:00:00 2001 From: Joe Farebrother Date: Wed, 20 Nov 2024 14:50:35 +0000 Subject: [PATCH] Add tests for jinja --- .../src/Security/CWE-074/TemplateInjection.ql | 19 ++++++++++++ .../CWE-074-TemplateInjection/JinjaSsti.py | 31 +++++++++++++++++++ .../TemplateInjection.expected | 16 ++++++++++ .../TemplateInjection.qlref | 1 + 4 files changed, 67 insertions(+) create mode 100644 python/ql/src/Security/CWE-074/TemplateInjection.ql create mode 100644 python/ql/test/query-tests/Security/CWE-074-TemplateInjection/JinjaSsti.py create mode 100644 python/ql/test/query-tests/Security/CWE-074-TemplateInjection/TemplateInjection.expected create mode 100644 python/ql/test/query-tests/Security/CWE-074-TemplateInjection/TemplateInjection.qlref diff --git a/python/ql/src/Security/CWE-074/TemplateInjection.ql b/python/ql/src/Security/CWE-074/TemplateInjection.ql new file mode 100644 index 000000000000..125478c801c8 --- /dev/null +++ b/python/ql/src/Security/CWE-074/TemplateInjection.ql @@ -0,0 +1,19 @@ +/** + * @name Server Side Template Injection + * @description Using user-controlled data to create a template can lead to remote code execution or cross site scripting. + * @kind path-problem + * @problem.severity error + * @precision high + * @id py/template-injection + * @tags security + * external/cwe/cwe-074 + */ + +import python +import semmle.python.security.dataflow.TemplateInjectionQuery +import TemplateInjectionFlow::PathGraph + +from TemplateInjectionFlow::PathNode source, TemplateInjectionFlow::PathNode sink +where TemplateInjectionFlow::flowPath(source, sink) +select sink.getNode(), source, sink, "This Template construction depends on $@.", source.getNode(), + "user-provided value" diff --git a/python/ql/test/query-tests/Security/CWE-074-TemplateInjection/JinjaSsti.py b/python/ql/test/query-tests/Security/CWE-074-TemplateInjection/JinjaSsti.py new file mode 100644 index 000000000000..f1fe834e4936 --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-074-TemplateInjection/JinjaSsti.py @@ -0,0 +1,31 @@ +from django.urls import path +from django.http import HttpResponse +from jinja2 import Template +from jinja2 import Environment, DictLoader, escape + + +def a(request): + # Load the template + template = request.GET['template'] + t = Template(template) # BAD: Template constructed from user input + name = request.GET['name'] + # Render the template with the context data + html = t.render(name=escape(name)) + return HttpResponse(html) + +def b(request): + import jinja2 + # Load the template + template = request.GET['template'] + env = Environment() + t = env.from_string(template) # BAD: Template constructed from user input + name = request.GET['name'] + # Render the template with the context data + html = t.render(name=escape(name)) + return HttpResponse(html) + + +urlpatterns = [ + path('a', a), + path('b', b) +] diff --git a/python/ql/test/query-tests/Security/CWE-074-TemplateInjection/TemplateInjection.expected b/python/ql/test/query-tests/Security/CWE-074-TemplateInjection/TemplateInjection.expected new file mode 100644 index 000000000000..3a833787a982 --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-074-TemplateInjection/TemplateInjection.expected @@ -0,0 +1,16 @@ +edges +| JinjaSsti.py:7:7:7:13 | ControlFlowNode for request | JinjaSsti.py:9:5:9:12 | ControlFlowNode for template | provenance | AdditionalTaintStep | +| JinjaSsti.py:9:5:9:12 | ControlFlowNode for template | JinjaSsti.py:10:18:10:25 | ControlFlowNode for template | provenance | | +| JinjaSsti.py:16:7:16:13 | ControlFlowNode for request | JinjaSsti.py:19:5:19:12 | ControlFlowNode for template | provenance | AdditionalTaintStep | +| JinjaSsti.py:19:5:19:12 | ControlFlowNode for template | JinjaSsti.py:21:25:21:32 | ControlFlowNode for template | provenance | | +nodes +| JinjaSsti.py:7:7:7:13 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | +| JinjaSsti.py:9:5:9:12 | ControlFlowNode for template | semmle.label | ControlFlowNode for template | +| JinjaSsti.py:10:18:10:25 | ControlFlowNode for template | semmle.label | ControlFlowNode for template | +| JinjaSsti.py:16:7:16:13 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | +| JinjaSsti.py:19:5:19:12 | ControlFlowNode for template | semmle.label | ControlFlowNode for template | +| JinjaSsti.py:21:25:21:32 | ControlFlowNode for template | semmle.label | ControlFlowNode for template | +subpaths +#select +| JinjaSsti.py:10:18:10:25 | ControlFlowNode for template | JinjaSsti.py:7:7:7:13 | ControlFlowNode for request | JinjaSsti.py:10:18:10:25 | ControlFlowNode for template | This Template construction depends on $@. | JinjaSsti.py:7:7:7:13 | ControlFlowNode for request | user-provided value | +| JinjaSsti.py:21:25:21:32 | ControlFlowNode for template | JinjaSsti.py:16:7:16:13 | ControlFlowNode for request | JinjaSsti.py:21:25:21:32 | ControlFlowNode for template | This Template construction depends on $@. | JinjaSsti.py:16:7:16:13 | ControlFlowNode for request | user-provided value | diff --git a/python/ql/test/query-tests/Security/CWE-074-TemplateInjection/TemplateInjection.qlref b/python/ql/test/query-tests/Security/CWE-074-TemplateInjection/TemplateInjection.qlref new file mode 100644 index 000000000000..ead6bb469c6a --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-074-TemplateInjection/TemplateInjection.qlref @@ -0,0 +1 @@ +Security/CWE-074/TemplateInjection.ql \ No newline at end of file