Skip to content

Commit a0f8e2f

Browse files
authored
Python: Modernise py/jinja2/autoescape-false
A simple rewrite to use API graphs instead. The handling of falsy values is potentially a bit more restrictive now, as it only accounts for local flow. We should probably figure out a better way of capturing this pattern, but I felt that this was out of scope for the present PR.
1 parent 234a36f commit a0f8e2f

File tree

1 file changed

+14
-12
lines changed

1 file changed

+14
-12
lines changed

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

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
*/
1313

1414
import python
15+
import semmle.python.dataflow.new.DataFlow
16+
import semmle.python.ApiGraphs
1517

1618
/*
1719
* Jinja 2 Docs:
@@ -25,25 +27,25 @@ import python
2527
* safe1_tmpl = Template('Hello {{ name }}!', autoescape=True)
2628
*/
2729

28-
ClassValue jinja2EnvironmentOrTemplate() {
29-
result = Value::named("jinja2.Environment")
30+
private API::Node jinja2EnvironmentOrTemplate() {
31+
result = API::moduleImport("jinja2").getMember("Environment")
3032
or
31-
result = Value::named("jinja2.Template")
33+
result = API::moduleImport("jinja2").getMember("Template")
3234
}
3335

34-
ControlFlowNode getAutoEscapeParameter(CallNode call) { result = call.getArgByName("autoescape") }
36+
DataFlow::Node getAutoEscapeParameter(DataFlow::CallCfgNode call) {
37+
result = call.getArgByName("autoescape")
38+
}
3539

36-
from CallNode call
40+
from DataFlow::CallCfgNode call
3741
where
38-
call.getFunction().pointsTo(jinja2EnvironmentOrTemplate()) and
39-
not exists(call.getNode().getStarargs()) and
40-
not exists(call.getNode().getKwargs()) and
42+
call = jinja2EnvironmentOrTemplate().getACall() and
43+
not exists(call.asCfgNode().(CallNode).getNode().getStarargs()) and
44+
not exists(call.asCfgNode().(CallNode).getNode().getKwargs()) and
4145
(
4246
not exists(getAutoEscapeParameter(call))
4347
or
44-
exists(Value isFalse |
45-
getAutoEscapeParameter(call).pointsTo(isFalse) and
46-
isFalse.getDefiniteBooleanValue() = false
47-
)
48+
any(DataFlow::LocalSourceNode n | n.asExpr().(ImmutableLiteral).booleanValue() = false)
49+
.flowsTo(getAutoEscapeParameter(call))
4850
)
4951
select call, "Using jinja2 templates with autoescape=False can potentially allow XSS attacks."

0 commit comments

Comments
 (0)