Skip to content

Commit 1e7921e

Browse files
author
Porcupiney Hairs
committed
add qhelp and fix tests.
1 parent 8e85dc7 commit 1e7921e

File tree

4 files changed

+93
-5
lines changed

4 files changed

+93
-5
lines changed
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
from django.urls import path
2+
from django.http import HttpResponse
3+
from jinja2 import Template as Jinja2_Template
4+
from jinja2 import Environment, DictLoader, escape
5+
6+
7+
def a(request):
8+
# Load the template
9+
template = request.GET['template']
10+
t = Jinja2_Template(template)
11+
name = request.GET['name']
12+
# Render the template with the context data
13+
html = t.render(name=escape(name))
14+
return HttpResponse(html)
15+
16+
17+
urlpatterns = [
18+
path('a', a),
19+
]
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
from django.urls import path
2+
from django.http import HttpResponse
3+
from jinja2 import Template as Jinja2_Template
4+
from jinja2 import Environment, DictLoader, escape
5+
6+
7+
def a(request):
8+
# Load the template
9+
template = request.GET['template']
10+
env = SandboxedEnvironment(undefined=StrictUndefined)
11+
t = env.from_string(template)
12+
name = request.GET['name']
13+
# Render the template with the context data
14+
html = t.render(name=escape(name))
15+
return HttpResponse(html)
16+
17+
18+
urlpatterns = [
19+
path('a', a),
20+
]
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<!DOCTYPE qhelp SYSTEM "qhelp.dtd">
2+
<qhelp>
3+
<overview>
4+
<p>
5+
Template Injection occurs when user input is embedded in a template in an unsafe manner.
6+
When an attacker is able to use native template syntax to inject a malicious payload into a template, which is then executed server-side is results in Server Side Template Injection.
7+
</p>
8+
</overview>
9+
<example>
10+
<p>Consider the example given below, an untrusted HTTP parameter `template` is used to generate a Jinja2 template string. This can lead to remote code execution. </p>
11+
<sample src="jinjaBad.py" />
12+
</example>
13+
<recommendation>
14+
<p>
15+
To fix this, ensure that an untrusted value is not used as a template. If the application requirements do not alow this, the Jinja sandbox environment can be used to evaluate untrusted code. In a sandbox, access to unsafe attributes and methods is prohibited. Hence,passing untrusted input to a sandboxed template is safe. Consider the example below, since it uses a `SandboxedEnvironment`, the code is not vulenrable to a Server Side Template Injection issue.
16+
<sample src="jinjaGood.py" />
17+
</p>
18+
</recommendation>
19+
<references>
20+
<li>Portswigger : [Server Side Template Injection](https://portswigger.net/web-security/server-side-template-injection)</li>
21+
</references>
22+
</qhelp>

python/ql/test/experimental/CWE-074/TemplateInjection.expected

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
edges
2-
| AirspeedSsti.py:13:16:13:27 | dict of externally controlled string | AirspeedSsti.py:13:16:13:43 | externally controlled string |
3-
| AirspeedSsti.py:13:16:13:27 | dict of externally controlled string | AirspeedSsti.py:13:16:13:43 | externally controlled string |
4-
| AirspeedSsti.py:13:16:13:43 | externally controlled string | AirspeedSsti.py:14:30:14:37 | externally controlled string |
5-
| AirspeedSsti.py:13:16:13:43 | externally controlled string | AirspeedSsti.py:14:30:14:37 | externally controlled string |
2+
| AirspeedSsti.py:10:16:10:27 | dict of externally controlled string | AirspeedSsti.py:10:16:10:43 | externally controlled string |
3+
| AirspeedSsti.py:10:16:10:27 | dict of externally controlled string | AirspeedSsti.py:10:16:10:43 | externally controlled string |
4+
| AirspeedSsti.py:10:16:10:43 | externally controlled string | AirspeedSsti.py:11:30:11:37 | externally controlled string |
5+
| AirspeedSsti.py:10:16:10:43 | externally controlled string | AirspeedSsti.py:11:30:11:37 | externally controlled string |
66
| ChevronSsti.py:10:16:10:27 | dict of externally controlled string | ChevronSsti.py:10:16:10:43 | externally controlled string |
77
| ChevronSsti.py:10:16:10:27 | dict of externally controlled string | ChevronSsti.py:10:16:10:43 | externally controlled string |
88
| ChevronSsti.py:10:16:10:43 | externally controlled string | ChevronSsti.py:11:27:11:34 | externally controlled string |
@@ -17,6 +17,22 @@ edges
1717
| DjangoTemplates.py:8:16:8:38 | externally controlled string | DjangoTemplates.py:9:18:9:25 | externally controlled string |
1818
| FlaskTemplate.py:17:41:17:52 | dict of externally controlled string | FlaskTemplate.py:17:41:17:68 | externally controlled string |
1919
| FlaskTemplate.py:17:41:17:52 | dict of externally controlled string | FlaskTemplate.py:17:41:17:68 | externally controlled string |
20+
| JinjaSsti.py:7:7:7:13 | django.request.HttpRequest | JinjaSsti.py:9:16:9:22 | django.request.HttpRequest |
21+
| JinjaSsti.py:7:7:7:13 | django.request.HttpRequest | JinjaSsti.py:9:16:9:22 | django.request.HttpRequest |
22+
| JinjaSsti.py:9:16:9:22 | django.request.HttpRequest | JinjaSsti.py:9:16:9:26 | django.http.request.QueryDict |
23+
| JinjaSsti.py:9:16:9:22 | django.request.HttpRequest | JinjaSsti.py:9:16:9:26 | django.http.request.QueryDict |
24+
| JinjaSsti.py:9:16:9:26 | django.http.request.QueryDict | JinjaSsti.py:9:16:9:38 | externally controlled string |
25+
| JinjaSsti.py:9:16:9:26 | django.http.request.QueryDict | JinjaSsti.py:9:16:9:38 | externally controlled string |
26+
| JinjaSsti.py:9:16:9:38 | externally controlled string | JinjaSsti.py:10:25:10:32 | externally controlled string |
27+
| JinjaSsti.py:9:16:9:38 | externally controlled string | JinjaSsti.py:10:25:10:32 | externally controlled string |
28+
| JinjaSsti.py:16:7:16:13 | django.request.HttpRequest | JinjaSsti.py:19:16:19:22 | django.request.HttpRequest |
29+
| JinjaSsti.py:16:7:16:13 | django.request.HttpRequest | JinjaSsti.py:19:16:19:22 | django.request.HttpRequest |
30+
| JinjaSsti.py:19:16:19:22 | django.request.HttpRequest | JinjaSsti.py:19:16:19:26 | django.http.request.QueryDict |
31+
| JinjaSsti.py:19:16:19:22 | django.request.HttpRequest | JinjaSsti.py:19:16:19:26 | django.http.request.QueryDict |
32+
| JinjaSsti.py:19:16:19:26 | django.http.request.QueryDict | JinjaSsti.py:19:16:19:38 | externally controlled string |
33+
| JinjaSsti.py:19:16:19:26 | django.http.request.QueryDict | JinjaSsti.py:19:16:19:38 | externally controlled string |
34+
| JinjaSsti.py:19:16:19:38 | externally controlled string | JinjaSsti.py:20:28:20:35 | externally controlled string |
35+
| JinjaSsti.py:19:16:19:38 | externally controlled string | JinjaSsti.py:20:28:20:35 | externally controlled string |
2036
| MakoSsti.py:6:10:6:16 | django.request.HttpRequest | MakoSsti.py:8:16:8:22 | django.request.HttpRequest |
2137
| MakoSsti.py:6:10:6:16 | django.request.HttpRequest | MakoSsti.py:8:16:8:22 | django.request.HttpRequest |
2238
| MakoSsti.py:8:16:8:22 | django.request.HttpRequest | MakoSsti.py:8:16:8:26 | django.http.request.QueryDict |
@@ -25,9 +41,20 @@ edges
2541
| MakoSsti.py:8:16:8:26 | django.http.request.QueryDict | MakoSsti.py:8:16:8:38 | externally controlled string |
2642
| MakoSsti.py:8:16:8:38 | externally controlled string | MakoSsti.py:9:27:9:34 | externally controlled string |
2743
| MakoSsti.py:8:16:8:38 | externally controlled string | MakoSsti.py:9:27:9:34 | externally controlled string |
44+
| TRender.py:5:13:5:19 | django.request.HttpRequest | TRender.py:6:16:6:22 | django.request.HttpRequest |
45+
| TRender.py:5:13:5:19 | django.request.HttpRequest | TRender.py:6:16:6:22 | django.request.HttpRequest |
46+
| TRender.py:6:16:6:22 | django.request.HttpRequest | TRender.py:6:16:6:26 | django.http.request.QueryDict |
47+
| TRender.py:6:16:6:22 | django.request.HttpRequest | TRender.py:6:16:6:26 | django.http.request.QueryDict |
48+
| TRender.py:6:16:6:26 | django.http.request.QueryDict | TRender.py:6:16:6:38 | externally controlled string |
49+
| TRender.py:6:16:6:26 | django.http.request.QueryDict | TRender.py:6:16:6:38 | externally controlled string |
50+
| TRender.py:6:16:6:38 | externally controlled string | TRender.py:7:24:7:31 | externally controlled string |
51+
| TRender.py:6:16:6:38 | externally controlled string | TRender.py:7:24:7:31 | externally controlled string |
2852
#select
29-
| AirspeedSsti.py:14:30:14:37 | template | AirspeedSsti.py:13:16:13:27 | dict of externally controlled string | AirspeedSsti.py:14:30:14:37 | externally controlled string | This Template depends on $@. | AirspeedSsti.py:13:16:13:27 | Attribute | a user-provided value |
53+
| AirspeedSsti.py:11:30:11:37 | template | AirspeedSsti.py:10:16:10:27 | dict of externally controlled string | AirspeedSsti.py:11:30:11:37 | externally controlled string | This Template depends on $@. | AirspeedSsti.py:10:16:10:27 | Attribute | a user-provided value |
3054
| ChevronSsti.py:11:27:11:34 | template | ChevronSsti.py:10:16:10:27 | dict of externally controlled string | ChevronSsti.py:11:27:11:34 | externally controlled string | This Template depends on $@. | ChevronSsti.py:10:16:10:27 | Attribute | a user-provided value |
3155
| DjangoTemplates.py:9:18:9:25 | template | DjangoTemplates.py:6:8:6:14 | django.request.HttpRequest | DjangoTemplates.py:9:18:9:25 | externally controlled string | This Template depends on $@. | DjangoTemplates.py:6:8:6:14 | request | a user-provided value |
3256
| FlaskTemplate.py:17:41:17:68 | Attribute() | FlaskTemplate.py:17:41:17:52 | dict of externally controlled string | FlaskTemplate.py:17:41:17:68 | externally controlled string | This Template depends on $@. | FlaskTemplate.py:17:41:17:52 | Attribute | a user-provided value |
57+
| JinjaSsti.py:10:25:10:32 | template | JinjaSsti.py:7:7:7:13 | django.request.HttpRequest | JinjaSsti.py:10:25:10:32 | externally controlled string | This Template depends on $@. | JinjaSsti.py:7:7:7:13 | request | a user-provided value |
58+
| JinjaSsti.py:20:28:20:35 | template | JinjaSsti.py:16:7:16:13 | django.request.HttpRequest | JinjaSsti.py:20:28:20:35 | externally controlled string | This Template depends on $@. | JinjaSsti.py:16:7:16:13 | request | a user-provided value |
3359
| MakoSsti.py:9:27:9:34 | template | MakoSsti.py:6:10:6:16 | django.request.HttpRequest | MakoSsti.py:9:27:9:34 | externally controlled string | This Template depends on $@. | MakoSsti.py:6:10:6:16 | request | a user-provided value |
60+
| TRender.py:7:24:7:31 | template | TRender.py:5:13:5:19 | django.request.HttpRequest | TRender.py:7:24:7:31 | externally controlled string | This Template depends on $@. | TRender.py:5:13:5:19 | request | a user-provided value |

0 commit comments

Comments
 (0)