Skip to content

Commit eefb45c

Browse files
committed
Python: jinja2-without-escaping query: Clean up query and account for Template class in tests.
1 parent dff36e2 commit eefb45c

File tree

4 files changed

+21
-19
lines changed

4 files changed

+21
-19
lines changed

python/ql/src/Security/CWE-079/Jinja2WithoutEscaping.ql

Lines changed: 10 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -12,29 +12,20 @@
1212

1313
import python
1414

15-
predicate jinja2Environment(Object callable, int autoescape) {
16-
exists(ModuleObject jinja2 |
17-
jinja2.getName() = "jinja2" |
18-
jinja2.getAttribute("Environment") = callable and
19-
callable.(ClassObject).getPyClass().getInitMethod().getArg(autoescape+1).asName().getId() = "autoescape"
20-
or
21-
exists(ModuleObject environment |
22-
environment.getAttribute("Template") = callable and
23-
callable.(ClassObject).lookupAttribute("__new__").(FunctionObject).getFunction().getArg(autoescape+1).asName().getId() = "autoescape"
24-
)
15+
ClassObject jinja2EnvironmentOrTemplate() {
16+
exists(ModuleObject jinja2, string name |
17+
jinja2.getName() = "jinja2" and
18+
jinja2.getAttribute(name) = result |
19+
name = "Environment" or
20+
name = "Template"
2521
)
2622
}
2723

2824
ControlFlowNode getAutoEscapeParameter(CallNode call) {
2925
exists(Object callable |
3026
call.getFunction().refersTo(callable) |
31-
jinja2Environment(callable, _) and
27+
callable = jinja2EnvironmentOrTemplate() and
3228
result = call.getArgByName("autoescape")
33-
or
34-
exists(int arg |
35-
jinja2Environment(callable, arg) and
36-
result = call.getArg(arg)
37-
)
3829
)
3930
}
4031

@@ -46,11 +37,12 @@ not exists(call.getNode().getKwargs()) and
4637
not exists(getAutoEscapeParameter(call)) and
4738
exists(Object env |
4839
call.getFunction().refersTo(env) and
49-
jinja2Environment(env, _)
40+
env = jinja2EnvironmentOrTemplate()
5041
)
5142
or
5243
exists(Object isFalse |
53-
getAutoEscapeParameter(call).refersTo(isFalse) and isFalse.booleanValue() = false
44+
getAutoEscapeParameter(call).refersTo(isFalse) and isFalse.booleanValue() = false
5445
)
5546
)
47+
5648
select call, "Using jinja2 templates with autoescape=False can potentially allow XSS attacks."

python/ql/test/query-tests/Security/CWE-079/Jinja2WithoutEscaping.expected

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@
22
| jinja2_escaping.py:41:5:41:29 | ControlFlowNode for Environment() | Using jinja2 templates with autoescape=False can potentially allow XSS attacks. |
33
| jinja2_escaping.py:43:1:43:3 | ControlFlowNode for E() | Using jinja2 templates with autoescape=False can potentially allow XSS attacks. |
44
| jinja2_escaping.py:44:1:44:15 | ControlFlowNode for E() | Using jinja2 templates with autoescape=False can potentially allow XSS attacks. |
5+
| jinja2_escaping.py:53:15:53:43 | ControlFlowNode for Template() | Using jinja2 templates with autoescape=False can potentially allow XSS attacks. |

python/ql/test/query-tests/Security/CWE-079/jinja2_escaping.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11

22
Environment(loader=templateLoader, autoescape=fake_func())
33
from flask import Flask, request, make_response, escape
4-
from jinja2 import Environment, select_autoescape, FileSystemLoader
4+
from jinja2 import Environment, select_autoescape, FileSystemLoader, Template
55

66
app = Flask(__name__)
77
loader = FileSystemLoader( searchpath="templates/" )
@@ -49,3 +49,7 @@ def checked(cond=False):
4949
if cond:
5050
e = Environment(autoescape=cond) # GOOD
5151

52+
53+
unsafe_tmpl = Template('Hello {{ name }}!')
54+
safe1_tmpl = Template('Hello {{ name }}!', autoescape=True)
55+
safe2_tmpl = Template('Hello {{ name }}!', autoescape=select_autoescape())

python/ql/test/query-tests/Security/lib/jinja2.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@ class Environment(object):
44
def __init__(self, loader, autoescape):
55
pass
66

7+
class Template(object):
8+
9+
def __init__(self, source, autoescape):
10+
pass
11+
712
def select_autoescape(files=[]):
813
def autoescape(template_name):
914
pass

0 commit comments

Comments
 (0)