Skip to content

Commit 9c75a39

Browse files
committed
Python: Extend command-injection to handle fabric.api.execute
1 parent e04d1ff commit 9c75a39

File tree

3 files changed

+53
-0
lines changed

3 files changed

+53
-0
lines changed

python/ql/src/Security/CWE-078/CommandInjection.ql

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ class CommandInjectionConfiguration extends TaintTracking::Configuration {
3232

3333
override predicate isExtension(TaintTracking::Extension extension) {
3434
extension instanceof FirstElementFlow
35+
or
36+
extension instanceof FabricExecuteExtension
3537
}
3638
}
3739

python/ql/src/semmle/python/security/injection/Command.qll

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,3 +231,41 @@ class FabricV1Commands extends CommandSink {
231231

232232
override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind }
233233
}
234+
235+
/**
236+
* An extension that propagates taint from the arguments of `fabric.api.execute(func, arg0, arg1, ...)`
237+
* to the parameters of `func`, since this will call `func(arg0, arg1, ...)`.
238+
*/
239+
class FabricExecuteExtension extends DataFlowExtension::DataFlowNode {
240+
CallNode call;
241+
242+
FabricExecuteExtension() {
243+
call = Value::named("fabric.api.execute").getACall() and
244+
(
245+
this = call.getArg(any(int i | i > 0))
246+
or
247+
this = call.getArgByName(any(string s | not s = "task"))
248+
)
249+
}
250+
251+
override ControlFlowNode getASuccessorNode(TaintKind fromkind, TaintKind tokind) {
252+
tokind = fromkind and
253+
exists(CallableValue func |
254+
(
255+
call.getArg(0).pointsTo(func)
256+
or
257+
call.getArgByName("task").pointsTo(func)
258+
) and
259+
exists(int i |
260+
// execute(func, arg0, arg1) => func(arg0, arg1)
261+
this = call.getArg(i) and
262+
result = func.getParameter(i - 1)
263+
)
264+
or
265+
exists(string name |
266+
this = call.getArgByName(name) and
267+
result = func.getParameterByName(name)
268+
)
269+
)
270+
}
271+
}

python/ql/test/library-tests/security/fabric-v1-execute/Taint.qll

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import python
22
import semmle.python.dataflow.TaintTracking
33
import semmle.python.security.strings.Untrusted
4+
import semmle.python.security.injection.Command
45

56
class SimpleSource extends TaintSource {
67
SimpleSource() { this.(NameNode).getId() = "TAINTED_STRING" }
@@ -9,3 +10,15 @@ class SimpleSource extends TaintSource {
910

1011
override string toString() { result = "taint source" }
1112
}
13+
14+
class FabricExecuteTestConfiguration extends TaintTracking::Configuration {
15+
FabricExecuteTestConfiguration() { this = "FabricExecuteTestConfiguration" }
16+
17+
override predicate isSource(TaintTracking::Source source) { source instanceof SimpleSource }
18+
19+
override predicate isSink(TaintTracking::Sink sink) { sink instanceof CommandSink }
20+
21+
override predicate isExtension(TaintTracking::Extension extension) {
22+
extension instanceof FabricExecuteExtension
23+
}
24+
}

0 commit comments

Comments
 (0)