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.
This commit is contained in:
Taus
2022-05-12 12:52:03 +00:00
committed by GitHub
parent 234a36ff61
commit a0f8e2f0b1

View File

@@ -12,6 +12,8 @@
*/
import python
import semmle.python.dataflow.new.DataFlow
import semmle.python.ApiGraphs
/*
* Jinja 2 Docs:
@@ -25,25 +27,25 @@ import python
* safe1_tmpl = Template('Hello {{ name }}!', autoescape=True)
*/
ClassValue jinja2EnvironmentOrTemplate() {
result = Value::named("jinja2.Environment")
private API::Node jinja2EnvironmentOrTemplate() {
result = API::moduleImport("jinja2").getMember("Environment")
or
result = Value::named("jinja2.Template")
result = API::moduleImport("jinja2").getMember("Template")
}
ControlFlowNode getAutoEscapeParameter(CallNode call) { result = call.getArgByName("autoescape") }
DataFlow::Node getAutoEscapeParameter(DataFlow::CallCfgNode call) {
result = call.getArgByName("autoescape")
}
from CallNode call
from DataFlow::CallCfgNode call
where
call.getFunction().pointsTo(jinja2EnvironmentOrTemplate()) and
not exists(call.getNode().getStarargs()) and
not exists(call.getNode().getKwargs()) and
call = jinja2EnvironmentOrTemplate().getACall() and
not exists(call.asCfgNode().(CallNode).getNode().getStarargs()) and
not exists(call.asCfgNode().(CallNode).getNode().getKwargs()) and
(
not exists(getAutoEscapeParameter(call))
or
exists(Value isFalse |
getAutoEscapeParameter(call).pointsTo(isFalse) and
isFalse.getDefiniteBooleanValue() = false
)
any(DataFlow::LocalSourceNode n | n.asExpr().(ImmutableLiteral).booleanValue() = false)
.flowsTo(getAutoEscapeParameter(call))
)
select call, "Using jinja2 templates with autoescape=False can potentially allow XSS attacks."