mirror of
https://github.com/github/codeql.git
synced 2025-12-20 18:56:32 +01:00
Merge branch 'main' of github.com:github/codeql into python-port-stacktrace-exosure
This commit is contained in:
@@ -41,6 +41,7 @@ private import semmle.python.objects.ObjectInternal
|
||||
* A callable that is considered a "safe" external API from a security perspective.
|
||||
*/
|
||||
class SafeExternalAPI extends Unit {
|
||||
/** Gets a callable that is considered a "safe" external API from a security perspective. */
|
||||
abstract DataFlowPrivate::DataFlowCallable getSafeCallable();
|
||||
}
|
||||
|
||||
|
||||
@@ -10,25 +10,25 @@
|
||||
*/
|
||||
|
||||
import python
|
||||
import semmle.python.dataflow.new.DataFlow
|
||||
import semmle.python.ApiGraphs
|
||||
|
||||
private ModuleValue theParamikoClientModule() { result = Value::named("paramiko.client") }
|
||||
|
||||
private ClassValue theParamikoSSHClientClass() {
|
||||
result = theParamikoClientModule().attr("SSHClient")
|
||||
private API::Node unsafe_paramiko_policy(string name) {
|
||||
name in ["AutoAddPolicy", "WarningPolicy"] and
|
||||
result = API::moduleImport("paramiko").getMember("client").getMember(name)
|
||||
}
|
||||
|
||||
private ClassValue unsafe_paramiko_policy(string name) {
|
||||
(name = "AutoAddPolicy" or name = "WarningPolicy") and
|
||||
result = theParamikoClientModule().attr(name)
|
||||
private API::Node paramikoSSHClientInstance() {
|
||||
result = API::moduleImport("paramiko").getMember("client").getMember("SSHClient").getReturn()
|
||||
}
|
||||
|
||||
from CallNode call, ControlFlowNode arg, string name
|
||||
from DataFlow::CallCfgNode call, DataFlow::Node arg, string name
|
||||
where
|
||||
call =
|
||||
theParamikoSSHClientClass().lookup("set_missing_host_key_policy").(FunctionValue).getACall() and
|
||||
arg = call.getAnArg() and
|
||||
// see http://docs.paramiko.org/en/stable/api/client.html#paramiko.client.SSHClient.set_missing_host_key_policy
|
||||
call = paramikoSSHClientInstance().getMember("set_missing_host_key_policy").getACall() and
|
||||
arg in [call.getArg(0), call.getArgByName("policy")] and
|
||||
(
|
||||
arg.pointsTo(unsafe_paramiko_policy(name)) or
|
||||
arg.pointsTo().getClass() = unsafe_paramiko_policy(name)
|
||||
arg = unsafe_paramiko_policy(name).getAUse() or
|
||||
arg = unsafe_paramiko_policy(name).getReturn().getAUse()
|
||||
)
|
||||
select call, "Setting missing host key policy to " + name + " may be unsafe."
|
||||
|
||||
@@ -11,8 +11,9 @@
|
||||
*/
|
||||
|
||||
import python
|
||||
import semmle.python.ApiGraphs
|
||||
|
||||
FunctionValue temporary_name_function(string mod, string function) {
|
||||
API::Node temporary_name_function(string mod, string function) {
|
||||
(
|
||||
mod = "tempfile" and function = "mktemp"
|
||||
or
|
||||
@@ -23,9 +24,9 @@ FunctionValue temporary_name_function(string mod, string function) {
|
||||
function = "tempnam"
|
||||
)
|
||||
) and
|
||||
result = Module::named(mod).attr(function)
|
||||
result = API::moduleImport(mod).getMember(function)
|
||||
}
|
||||
|
||||
from Call c, string mod, string function
|
||||
where temporary_name_function(mod, function).getACall().getNode() = c
|
||||
where temporary_name_function(mod, function).getACall().asExpr() = c
|
||||
select c, "Call to deprecated function " + mod + "." + function + " may be insecure."
|
||||
|
||||
@@ -24,6 +24,9 @@ Avoid deserialization of untrusted data if at all possible. If the
|
||||
architecture permits it then use other formats instead of serialized objects,
|
||||
for example JSON.
|
||||
</p>
|
||||
<p>
|
||||
If you need to use YAML, use the <code>yaml.safe_load</code> function.
|
||||
</p>
|
||||
</recommendation>
|
||||
|
||||
<example>
|
||||
|
||||
@@ -92,6 +92,11 @@ module API {
|
||||
*/
|
||||
Node getReturn() { result = getASuccessor(Label::return()) }
|
||||
|
||||
/**
|
||||
* Gets a node representing a subclass of the class represented by this node.
|
||||
*/
|
||||
Node getASubclass() { result = getASuccessor(Label::subclass()) }
|
||||
|
||||
/**
|
||||
* Gets a string representation of the lexicographically least among all shortest access paths
|
||||
* from the root to this node.
|
||||
@@ -312,12 +317,11 @@ module API {
|
||||
* For instance, `prefix_member("foo.bar", "baz", "foo.bar.baz")` would hold.
|
||||
*/
|
||||
private predicate prefix_member(TApiNode base, string member, TApiNode sub) {
|
||||
exists(string base_str, string sub_str |
|
||||
base = MkModuleImport(base_str) and
|
||||
exists(string sub_str, string regexp |
|
||||
regexp = "(.+)[.]([^.]+)" and
|
||||
base = MkModuleImport(sub_str.regexpCapture(regexp, 1)) and
|
||||
member = sub_str.regexpCapture(regexp, 2) and
|
||||
sub = MkModuleImport(sub_str)
|
||||
|
|
||||
base_str + "." + member = sub_str and
|
||||
not member.matches("%.%")
|
||||
)
|
||||
}
|
||||
|
||||
@@ -351,13 +355,19 @@ module API {
|
||||
// the relationship between `pred` and `ref`.
|
||||
use(base, src) and pred = trackUseNode(src)
|
||||
|
|
||||
// Reading an attribute on a node that is a use of `base`:
|
||||
// Referring to an attribute on a node that is a use of `base`:
|
||||
lbl = Label::memberFromRef(ref) and
|
||||
ref = pred.getAnAttributeRead()
|
||||
ref = pred.getAnAttributeReference()
|
||||
or
|
||||
// Calling a node that is a use of `base`
|
||||
lbl = Label::return() and
|
||||
ref = pred.getACall()
|
||||
or
|
||||
// Subclassing a node
|
||||
lbl = Label::subclass() and
|
||||
exists(DataFlow::Node superclass | pred.flowsTo(superclass) |
|
||||
ref.asExpr().(ClassExpr).getABase() = superclass.asExpr()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -468,4 +478,6 @@ private module Label {
|
||||
|
||||
/** Gets the `return` edge label. */
|
||||
string return() { result = "getReturn()" }
|
||||
|
||||
string subclass() { result = "getASubclass()" }
|
||||
}
|
||||
|
||||
@@ -373,6 +373,9 @@ module HTTP {
|
||||
* requests for this route, if any. These automatically become a `RemoteFlowSource`.
|
||||
*/
|
||||
Parameter getARoutedParameter() { result = range.getARoutedParameter() }
|
||||
|
||||
/** Gets a string that identifies the framework used for this route setup. */
|
||||
string getFramework() { result = range.getFramework() }
|
||||
}
|
||||
|
||||
/** Provides a class for modeling new HTTP routing APIs. */
|
||||
@@ -407,6 +410,9 @@ module HTTP {
|
||||
* requests for this route, if any. These automatically become a `RemoteFlowSource`.
|
||||
*/
|
||||
abstract Parameter getARoutedParameter();
|
||||
|
||||
/** Gets a string that identifies the framework used for this route setup. */
|
||||
abstract string getFramework();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -426,6 +432,9 @@ module HTTP {
|
||||
* requests, if any. These automatically become a `RemoteFlowSource`.
|
||||
*/
|
||||
Parameter getARoutedParameter() { result = range.getARoutedParameter() }
|
||||
|
||||
/** Gets a string that identifies the framework used for this route setup. */
|
||||
string getFramework() { result = range.getFramework() }
|
||||
}
|
||||
|
||||
/** Provides a class for modeling new HTTP request handlers. */
|
||||
@@ -444,6 +453,9 @@ module HTTP {
|
||||
* requests, if any. These automatically become a `RemoteFlowSource`.
|
||||
*/
|
||||
abstract Parameter getARoutedParameter();
|
||||
|
||||
/** Gets a string that identifies the framework used for this request handler. */
|
||||
abstract string getFramework();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -456,13 +468,17 @@ module HTTP {
|
||||
result = rs.getARoutedParameter() and
|
||||
result in [this.getArg(_), this.getArgByName(_)]
|
||||
}
|
||||
|
||||
override string getFramework() { result = rs.getFramework() }
|
||||
}
|
||||
|
||||
/** A parameter that will receive parts of the url when handling an incoming request. */
|
||||
private class RoutedParameter extends RemoteFlowSource::Range, DataFlow::ParameterNode {
|
||||
RoutedParameter() { this.getParameter() = any(RequestHandler handler).getARoutedParameter() }
|
||||
RequestHandler handler;
|
||||
|
||||
override string getSourceType() { result = "RoutedParameter" }
|
||||
RoutedParameter() { this.getParameter() = handler.getARoutedParameter() }
|
||||
|
||||
override string getSourceType() { result = handler.getFramework() + " RoutedParameter" }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -180,7 +180,7 @@ private newtype TTypeTracker = MkTypeTracker(Boolean hasCall, OptionalAttributeN
|
||||
* It is recommended that all uses of this type are written in the following form,
|
||||
* for tracking some type `myType`:
|
||||
* ```
|
||||
* DataFlow::Node myType(DataFlow::TypeTracker t) {
|
||||
* DataFlow::LocalSourceNode myType(DataFlow::TypeTracker t) {
|
||||
* t.start() and
|
||||
* result = < source of myType >
|
||||
* or
|
||||
@@ -189,7 +189,7 @@ private newtype TTypeTracker = MkTypeTracker(Boolean hasCall, OptionalAttributeN
|
||||
* )
|
||||
* }
|
||||
*
|
||||
* DataFlow::Node myType() { result = myType(DataFlow::TypeTracker::end()) }
|
||||
* DataFlow::Node myType() { myType(DataFlow::TypeTracker::end()).flowsTo(result) }
|
||||
* ```
|
||||
*
|
||||
* Instead of `result = myType(t2).track(t2, t)`, you can also use the equivalent
|
||||
@@ -324,3 +324,144 @@ module TypeTracker {
|
||||
*/
|
||||
TypeTracker end() { result.end() }
|
||||
}
|
||||
|
||||
private newtype TTypeBackTracker = MkTypeBackTracker(Boolean hasReturn, OptionalAttributeName attr)
|
||||
|
||||
/**
|
||||
* Summary of the steps needed to back-track a use of a value to a given dataflow node.
|
||||
*
|
||||
* This can for example be used to track callbacks that are passed to a certain API,
|
||||
* so we can model specific parameters of that callback as having a certain type.
|
||||
*
|
||||
* Note that type back-tracking does not provide a source/sink relation, that is,
|
||||
* it may determine that a node will be used in an API call somewhere, but it won't
|
||||
* determine exactly where that use was, or the path that led to the use.
|
||||
*
|
||||
* It is recommended that all uses of this type are written in the following form,
|
||||
* for back-tracking some callback type `myCallback`:
|
||||
*
|
||||
* ```
|
||||
* DataFlow::LocalSourceNode myCallback(DataFlow::TypeBackTracker t) {
|
||||
* t.start() and
|
||||
* result = (< some API call >).getArgument(< n >).getALocalSource()
|
||||
* or
|
||||
* exists (DataFlow::TypeBackTracker t2 |
|
||||
* result = myCallback(t2).backtrack(t2, t)
|
||||
* )
|
||||
* }
|
||||
*
|
||||
* DataFlow::LocalSourceNode myCallback() { result = myCallback(DataFlow::TypeBackTracker::end()) }
|
||||
* ```
|
||||
*
|
||||
* Instead of `result = myCallback(t2).backtrack(t2, t)`, you can also use the equivalent
|
||||
* `t2 = t.step(result, myCallback(t2))`. If you additionally want to track individual
|
||||
* intra-procedural steps, use `t2 = t.smallstep(result, myCallback(t2))`.
|
||||
*/
|
||||
class TypeBackTracker extends TTypeBackTracker {
|
||||
Boolean hasReturn;
|
||||
string attr;
|
||||
|
||||
TypeBackTracker() { this = MkTypeBackTracker(hasReturn, attr) }
|
||||
|
||||
/** Gets the summary resulting from prepending `step` to this type-tracking summary. */
|
||||
TypeBackTracker prepend(StepSummary step) {
|
||||
step = LevelStep() and result = this
|
||||
or
|
||||
step = CallStep() and hasReturn = false and result = this
|
||||
or
|
||||
step = ReturnStep() and result = MkTypeBackTracker(true, attr)
|
||||
or
|
||||
exists(string p | step = LoadStep(p) and attr = "" and result = MkTypeBackTracker(hasReturn, p))
|
||||
or
|
||||
step = StoreStep(attr) and result = MkTypeBackTracker(hasReturn, "")
|
||||
}
|
||||
|
||||
/** Gets a textual representation of this summary. */
|
||||
string toString() {
|
||||
exists(string withReturn, string withAttr |
|
||||
(if hasReturn = true then withReturn = "with" else withReturn = "without") and
|
||||
(if attr != "" then withAttr = " with attribute " + attr else withAttr = "") and
|
||||
result = "type back-tracker " + withReturn + " return steps" + withAttr
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this is the starting point of type tracking.
|
||||
*/
|
||||
predicate start() { hasReturn = false and attr = "" }
|
||||
|
||||
/**
|
||||
* Holds if this is the end point of type tracking.
|
||||
*/
|
||||
predicate end() { attr = "" }
|
||||
|
||||
/**
|
||||
* INTERNAL. DO NOT USE.
|
||||
*
|
||||
* Holds if this type has been back-tracked into a call through return edge.
|
||||
*/
|
||||
boolean hasReturn() { result = hasReturn }
|
||||
|
||||
/**
|
||||
* Gets a type tracker that starts where this one has left off to allow continued
|
||||
* tracking.
|
||||
*
|
||||
* This predicate is only defined if the type has not been tracked into an attribute.
|
||||
*/
|
||||
TypeBackTracker continue() { attr = "" and result = this }
|
||||
|
||||
/**
|
||||
* Gets the summary that corresponds to having taken a backwards
|
||||
* heap and/or inter-procedural step from `nodeTo` to `nodeFrom`.
|
||||
*/
|
||||
pragma[inline]
|
||||
TypeBackTracker step(LocalSourceNode nodeFrom, LocalSourceNode nodeTo) {
|
||||
exists(StepSummary summary |
|
||||
StepSummary::step(nodeFrom, nodeTo, summary) and
|
||||
this = result.prepend(summary)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the summary that corresponds to having taken a backwards
|
||||
* local, heap and/or inter-procedural step from `nodeTo` to `nodeFrom`.
|
||||
*
|
||||
* Unlike `TypeBackTracker::step`, this predicate exposes all edges
|
||||
* in the flowgraph, and not just the edges between
|
||||
* `LocalSourceNode`s. It may therefore be less performant.
|
||||
*
|
||||
* Type tracking predicates using small steps typically take the following form:
|
||||
* ```ql
|
||||
* DataFlow::Node myType(DataFlow::TypeBackTracker t) {
|
||||
* t.start() and
|
||||
* result = < some API call >.getArgument(< n >)
|
||||
* or
|
||||
* exists (DataFlow::TypeBackTracker t2 |
|
||||
* t = t2.smallstep(result, myType(t2))
|
||||
* )
|
||||
* }
|
||||
*
|
||||
* DataFlow::Node myType() {
|
||||
* result = myType(DataFlow::TypeBackTracker::end())
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
pragma[inline]
|
||||
TypeBackTracker smallstep(Node nodeFrom, Node nodeTo) {
|
||||
exists(StepSummary summary |
|
||||
StepSummary::smallstep(nodeFrom, nodeTo, summary) and
|
||||
this = result.prepend(summary)
|
||||
)
|
||||
or
|
||||
typePreservingStep(nodeFrom, nodeTo) and
|
||||
this = result
|
||||
}
|
||||
}
|
||||
|
||||
/** Provides predicates for implementing custom `TypeBackTracker`s. */
|
||||
module TypeBackTracker {
|
||||
/**
|
||||
* Gets a valid end point of type back-tracking.
|
||||
*/
|
||||
TypeBackTracker end() { result.end() }
|
||||
}
|
||||
|
||||
@@ -159,7 +159,9 @@ private class SetAttrCallAsAttrWrite extends AttrWrite, CfgNode {
|
||||
* Instances of this class correspond to the `NameNode` for `attr`, and also gives access to `value` by
|
||||
* virtue of being a `DefinitionNode`.
|
||||
*/
|
||||
private class ClassAttributeAssignmentNode extends DefinitionNode, NameNode { }
|
||||
private class ClassAttributeAssignmentNode extends DefinitionNode, NameNode {
|
||||
ClassAttributeAssignmentNode() { this.getScope() = any(ClassExpr c).getInnerScope() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An attribute assignment via a class field, e.g.
|
||||
|
||||
@@ -3598,6 +3598,7 @@ private module FlowExploration {
|
||||
or
|
||||
exists(PartialPathNodeRev mid |
|
||||
revPartialPathStep(mid, node, sc1, sc2, ap, config) and
|
||||
not clearsContent(node, ap.getHead()) and
|
||||
not fullBarrier(node, config) and
|
||||
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
||||
)
|
||||
@@ -3611,6 +3612,7 @@ private module FlowExploration {
|
||||
exists(PartialPathNodeFwd mid |
|
||||
partialPathStep(mid, node, cc, sc1, sc2, ap, config) and
|
||||
not fullBarrier(node, config) and
|
||||
not clearsContent(node, ap.getHead().getContent()) and
|
||||
if node instanceof CastingNode
|
||||
then compatibleTypes(getNodeType(node), ap.getType())
|
||||
else any()
|
||||
|
||||
@@ -3598,6 +3598,7 @@ private module FlowExploration {
|
||||
or
|
||||
exists(PartialPathNodeRev mid |
|
||||
revPartialPathStep(mid, node, sc1, sc2, ap, config) and
|
||||
not clearsContent(node, ap.getHead()) and
|
||||
not fullBarrier(node, config) and
|
||||
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
||||
)
|
||||
@@ -3611,6 +3612,7 @@ private module FlowExploration {
|
||||
exists(PartialPathNodeFwd mid |
|
||||
partialPathStep(mid, node, cc, sc1, sc2, ap, config) and
|
||||
not fullBarrier(node, config) and
|
||||
not clearsContent(node, ap.getHead().getContent()) and
|
||||
if node instanceof CastingNode
|
||||
then compatibleTypes(getNodeType(node), ap.getType())
|
||||
else any()
|
||||
|
||||
@@ -3598,6 +3598,7 @@ private module FlowExploration {
|
||||
or
|
||||
exists(PartialPathNodeRev mid |
|
||||
revPartialPathStep(mid, node, sc1, sc2, ap, config) and
|
||||
not clearsContent(node, ap.getHead()) and
|
||||
not fullBarrier(node, config) and
|
||||
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
||||
)
|
||||
@@ -3611,6 +3612,7 @@ private module FlowExploration {
|
||||
exists(PartialPathNodeFwd mid |
|
||||
partialPathStep(mid, node, cc, sc1, sc2, ap, config) and
|
||||
not fullBarrier(node, config) and
|
||||
not clearsContent(node, ap.getHead().getContent()) and
|
||||
if node instanceof CastingNode
|
||||
then compatibleTypes(getNodeType(node), ap.getType())
|
||||
else any()
|
||||
|
||||
@@ -3598,6 +3598,7 @@ private module FlowExploration {
|
||||
or
|
||||
exists(PartialPathNodeRev mid |
|
||||
revPartialPathStep(mid, node, sc1, sc2, ap, config) and
|
||||
not clearsContent(node, ap.getHead()) and
|
||||
not fullBarrier(node, config) and
|
||||
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
||||
)
|
||||
@@ -3611,6 +3612,7 @@ private module FlowExploration {
|
||||
exists(PartialPathNodeFwd mid |
|
||||
partialPathStep(mid, node, cc, sc1, sc2, ap, config) and
|
||||
not fullBarrier(node, config) and
|
||||
not clearsContent(node, ap.getHead().getContent()) and
|
||||
if node instanceof CastingNode
|
||||
then compatibleTypes(getNodeType(node), ap.getType())
|
||||
else any()
|
||||
|
||||
@@ -1508,6 +1508,8 @@ predicate forReadStep(CfgNode nodeFrom, Content c, Node nodeTo) {
|
||||
c instanceof ListElementContent
|
||||
or
|
||||
c instanceof SetElementContent
|
||||
or
|
||||
c instanceof TupleElementContent
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -125,6 +125,19 @@ class Node extends TNode {
|
||||
*/
|
||||
pragma[inline]
|
||||
Node track(TypeTracker t2, TypeTracker t) { t = t2.step(this, result) }
|
||||
|
||||
/**
|
||||
* Gets a node that may flow into this one using one heap and/or interprocedural step.
|
||||
*
|
||||
* See `TypeBackTracker` for more details about how to use this.
|
||||
*/
|
||||
pragma[inline]
|
||||
LocalSourceNode backtrack(TypeBackTracker t2, TypeBackTracker t) { t2 = t.step(result, this) }
|
||||
|
||||
/**
|
||||
* Gets a local source node from which data may flow to this node in zero or more local steps.
|
||||
*/
|
||||
LocalSourceNode getALocalSource() { result.flowsTo(this) }
|
||||
}
|
||||
|
||||
/** A data-flow node corresponding to an SSA variable. */
|
||||
@@ -165,6 +178,23 @@ class CfgNode extends Node, TCfgNode {
|
||||
override Location getLocation() { result = node.getLocation() }
|
||||
}
|
||||
|
||||
/** A data-flow node corresponding to a `CallNode` in the control-flow graph. */
|
||||
class CallCfgNode extends CfgNode {
|
||||
override CallNode node;
|
||||
|
||||
/**
|
||||
* Gets the data-flow node for the function component of the call corresponding to this data-flow
|
||||
* node.
|
||||
*/
|
||||
Node getFunction() { result.asCfgNode() = node.getFunction() }
|
||||
|
||||
/** Gets the data-flow node corresponding to the i'th argument of the call corresponding to this data-flow node */
|
||||
Node getArg(int i) { result.asCfgNode() = node.getArg(i) }
|
||||
|
||||
/** Gets the data-flow node corresponding to the named argument of the call corresponding to this data-flow node */
|
||||
Node getArgByName(string name) { result.asCfgNode() = node.getArgByName(name) }
|
||||
}
|
||||
|
||||
/**
|
||||
* An expression, viewed as a node in a data flow graph.
|
||||
*
|
||||
@@ -481,7 +511,7 @@ class LocalSourceNode extends Node {
|
||||
/**
|
||||
* Gets a call to this node.
|
||||
*/
|
||||
Node getACall() { Cached::call(this, result) }
|
||||
CallCfgNode getACall() { Cached::call(this, result) }
|
||||
}
|
||||
|
||||
cached
|
||||
@@ -526,10 +556,10 @@ private module Cached {
|
||||
* Holds if `func` flows to the callee of `call`.
|
||||
*/
|
||||
cached
|
||||
predicate call(LocalSourceNode func, Node call) {
|
||||
predicate call(LocalSourceNode func, CallCfgNode call) {
|
||||
exists(CfgNode n |
|
||||
func.flowsTo(n) and
|
||||
n.asCfgNode() = call.asCfgNode().(CallNode).getFunction()
|
||||
n = call.getFunction()
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -544,7 +574,12 @@ newtype TContent =
|
||||
/** An element of a set. */
|
||||
TSetElementContent() or
|
||||
/** An element of a tuple at a specific index. */
|
||||
TTupleElementContent(int index) { exists(any(TupleNode tn).getElement(index)) } or
|
||||
TTupleElementContent(int index) {
|
||||
exists(any(TupleNode tn).getElement(index))
|
||||
or
|
||||
// Arguments can overflow and end up in the starred parameter tuple.
|
||||
exists(any(CallNode cn).getArg(index))
|
||||
} or
|
||||
/** An element of a dictionary under a specific key. */
|
||||
TDictionaryElementContent(string key) {
|
||||
key = any(KeyValuePair kvp).getKey().(StrConst).getS()
|
||||
|
||||
@@ -1975,6 +1975,14 @@ private module Django {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the last decorator call for the function `func`, if `func` has decorators.
|
||||
*/
|
||||
private Expr lastDecoratorCall(Function func) {
|
||||
result = func.getDefinition().(FunctionExpr).getADecoratorCall() and
|
||||
not exists(Call other_decorator | other_decorator.getArg(0) = result)
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// routing modeling
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -1987,7 +1995,18 @@ private module Django {
|
||||
*/
|
||||
private DataFlow::Node djangoRouteHandlerFunctionTracker(DataFlow::TypeTracker t, Function func) {
|
||||
t.start() and
|
||||
result = DataFlow::exprNode(func.getDefinition())
|
||||
(
|
||||
not exists(func.getADecorator()) and
|
||||
result.asExpr() = func.getDefinition()
|
||||
or
|
||||
// If the function has decorators, we still want to model the function as being
|
||||
// the request handler for a route setup. In such situations, we must track the
|
||||
// last decorator call instead of the function itself.
|
||||
//
|
||||
// Note that this means that we blindly ignore what the decorator actually does to
|
||||
// the function, which seems like an OK tradeoff.
|
||||
result.asExpr() = lastDecoratorCall(func)
|
||||
)
|
||||
or
|
||||
exists(DataFlow::TypeTracker t2 |
|
||||
result = djangoRouteHandlerFunctionTracker(t2, func).track(t2, t)
|
||||
@@ -2005,18 +2024,15 @@ private module Django {
|
||||
result = djangoRouteHandlerFunctionTracker(DataFlow::TypeTracker::end(), func)
|
||||
}
|
||||
|
||||
/** A django View class defined in project code. */
|
||||
class DjangoViewClassDef extends Class {
|
||||
DjangoViewClassDef() { this.getABase() = django::views::generic::View::subclassRef().asExpr() }
|
||||
|
||||
/** Gets a function that could handle incoming requests, if any. */
|
||||
DjangoRouteHandler getARequestHandler() {
|
||||
// TODO: This doesn't handle attribute assignment. Should be OK, but analysis is not as complete as with
|
||||
// points-to and `.lookup`, which would handle `post = my_post_handler` inside class def
|
||||
result = this.getAMethod() and
|
||||
result.getName() = HTTP::httpVerbLower()
|
||||
}
|
||||
|
||||
/**
|
||||
* In order to recognize a class as being a django view class, based on the `as_view`
|
||||
* call, we need to be able to track such calls on _any_ class. This is provided by
|
||||
* the member predicates of this QL class.
|
||||
*
|
||||
* As such, a Python class being part of `DjangoViewClassHelper` doesn't signify that
|
||||
* we model it as a django view class.
|
||||
*/
|
||||
class DjangoViewClassHelper extends Class {
|
||||
/** Gets a reference to this class. */
|
||||
private DataFlow::Node getARef(DataFlow::TypeTracker t) {
|
||||
t.start() and
|
||||
@@ -2051,15 +2067,69 @@ private module Django {
|
||||
DataFlow::Node asViewResult() { result = asViewResult(DataFlow::TypeTracker::end()) }
|
||||
}
|
||||
|
||||
/** A class that we consider a django View class. */
|
||||
abstract class DjangoViewClass extends DjangoViewClassHelper {
|
||||
/** Gets a function that could handle incoming requests, if any. */
|
||||
Function getARequestHandler() {
|
||||
// TODO: This doesn't handle attribute assignment. Should be OK, but analysis is not as complete as with
|
||||
// points-to and `.lookup`, which would handle `post = my_post_handler` inside class def
|
||||
result = this.getAMethod() and
|
||||
result.getName() = HTTP::httpVerbLower()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a reference to instances of this class, originating from a self parameter of
|
||||
* a method defined on this class.
|
||||
*
|
||||
* Note: TODO: This doesn't take MRO into account
|
||||
* Note: TODO: This doesn't take staticmethod/classmethod into account
|
||||
*/
|
||||
private DataFlow::Node getASelfRef(DataFlow::TypeTracker t) {
|
||||
t.start() and
|
||||
result.(DataFlow::ParameterNode).getParameter() = this.getAMethod().getArg(0)
|
||||
or
|
||||
exists(DataFlow::TypeTracker t2 | result = this.getASelfRef(t2).track(t2, t))
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a reference to instances of this class, originating from a self parameter of
|
||||
* a method defined on this class.
|
||||
*
|
||||
* Note: TODO: This doesn't take MRO into account
|
||||
* Note: TODO: This doesn't take staticmethod/classmethod into account
|
||||
*/
|
||||
DataFlow::Node getASelfRef() { result = this.getASelfRef(DataFlow::TypeTracker::end()) }
|
||||
}
|
||||
|
||||
/**
|
||||
* A class that is used in a route-setup, with `<class>.as_view()`, therefore being
|
||||
* considered a django View class.
|
||||
*/
|
||||
class DjangoViewClassFromRouteSetup extends DjangoViewClass {
|
||||
DjangoViewClassFromRouteSetup() {
|
||||
exists(DjangoRouteSetup setup | setup.getViewArg() = this.asViewResult())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A class that has a super-type which is a django View class, therefore also
|
||||
* becoming a django View class.
|
||||
*/
|
||||
class DjangoViewClassFromSuperClass extends DjangoViewClass {
|
||||
DjangoViewClassFromSuperClass() {
|
||||
this.getABase() = django::views::generic::View::subclassRef().asExpr()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A function that is a django route handler, meaning it handles incoming requests
|
||||
* with the django framework.
|
||||
*/
|
||||
private class DjangoRouteHandler extends Function {
|
||||
DjangoRouteHandler() {
|
||||
exists(djangoRouteHandlerFunctionTracker(this))
|
||||
exists(DjangoRouteSetup route | route.getViewArg() = djangoRouteHandlerFunctionTracker(this))
|
||||
or
|
||||
any(DjangoViewClassDef vc).getARequestHandler() = this
|
||||
any(DjangoViewClass vc).getARequestHandler() = this
|
||||
}
|
||||
|
||||
/** Gets the index of the request parameter. */
|
||||
@@ -2083,18 +2153,20 @@ private module Django {
|
||||
final override DjangoRouteHandler getARequestHandler() {
|
||||
djangoRouteHandlerFunctionTracker(result) = getViewArg()
|
||||
or
|
||||
exists(DjangoViewClassDef vc |
|
||||
exists(DjangoViewClass vc |
|
||||
getViewArg() = vc.asViewResult() and
|
||||
result = vc.getARequestHandler()
|
||||
)
|
||||
}
|
||||
|
||||
override string getFramework() { result = "Django" }
|
||||
}
|
||||
|
||||
/** A request handler defined in a django view class, that has no known route. */
|
||||
private class DjangoViewClassHandlerWithoutKnownRoute extends HTTP::Server::RequestHandler::Range,
|
||||
DjangoRouteHandler {
|
||||
DjangoViewClassHandlerWithoutKnownRoute() {
|
||||
exists(DjangoViewClassDef vc | vc.getARequestHandler() = this) and
|
||||
exists(DjangoViewClass vc | vc.getARequestHandler() = this) and
|
||||
not exists(DjangoRouteSetup setup | setup.getARequestHandler() = this)
|
||||
}
|
||||
|
||||
@@ -2105,6 +2177,8 @@ private module Django {
|
||||
result in [this.getArg(_), this.getArgByName(_)] and
|
||||
not result = any(int i | i <= this.getRequestParamIndex() | this.getArg(i))
|
||||
}
|
||||
|
||||
override string getFramework() { result = "Django" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2267,6 +2341,46 @@ private module Django {
|
||||
override string getSourceType() { result = "django.http.request.HttpRequest" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A read of the `request` attribute on a reference to an instance of a View class,
|
||||
* which is the request being processed currently.
|
||||
*
|
||||
* See https://docs.djangoproject.com/en/3.1/topics/class-based-views/generic-display/#dynamic-filtering
|
||||
*/
|
||||
private class DjangoViewClassRequestAttributeRead extends django::http::request::HttpRequest::InstanceSource,
|
||||
RemoteFlowSource::Range, DataFlow::Node {
|
||||
DjangoViewClassRequestAttributeRead() {
|
||||
exists(DataFlow::AttrRead read | this = read |
|
||||
read.getObject() = any(DjangoViewClass vc).getASelfRef() and
|
||||
read.getAttributeName() = "request"
|
||||
)
|
||||
}
|
||||
|
||||
override string getSourceType() {
|
||||
result = "django.http.request.HttpRequest (attribute on self in View class)"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A read of the `args` or `kwargs` attribute on a reference to an instance of a View class,
|
||||
* which contains the routed parameters captured from the URL route.
|
||||
*
|
||||
* See https://docs.djangoproject.com/en/3.1/topics/class-based-views/generic-display/#dynamic-filtering
|
||||
*/
|
||||
private class DjangoViewClassRoutedParamsAttributeRead extends RemoteFlowSource::Range,
|
||||
DataFlow::Node {
|
||||
DjangoViewClassRoutedParamsAttributeRead() {
|
||||
exists(DataFlow::AttrRead read | this = read |
|
||||
read.getObject() = any(DjangoViewClass vc).getASelfRef() and
|
||||
read.getAttributeName() in ["args", "kwargs"]
|
||||
)
|
||||
}
|
||||
|
||||
override string getSourceType() {
|
||||
result = "django routed param from attribute on self in View class"
|
||||
}
|
||||
}
|
||||
|
||||
private class DjangoHttpRequstAdditionalTaintStep extends TaintTracking::AdditionalTaintStep {
|
||||
override predicate step(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
|
||||
nodeFrom = django::http::request::HttpRequest::instance() and
|
||||
|
||||
@@ -9,295 +9,98 @@ private import semmle.python.dataflow.new.RemoteFlowSources
|
||||
private import semmle.python.dataflow.new.TaintTracking
|
||||
private import semmle.python.Concepts
|
||||
private import semmle.python.frameworks.Werkzeug
|
||||
private import semmle.python.ApiGraphs
|
||||
|
||||
/**
|
||||
* Provides models for the `flask` PyPI package.
|
||||
* See https://flask.palletsprojects.com/en/1.1.x/.
|
||||
*/
|
||||
private module FlaskModel {
|
||||
// ---------------------------------------------------------------------------
|
||||
// flask
|
||||
// ---------------------------------------------------------------------------
|
||||
/** Gets a reference to the `flask` module. */
|
||||
private DataFlow::Node flask(DataFlow::TypeTracker t) {
|
||||
t.start() and
|
||||
result = DataFlow::importNode("flask")
|
||||
or
|
||||
exists(DataFlow::TypeTracker t2 | result = flask(t2).track(t2, t))
|
||||
}
|
||||
|
||||
/** Gets a reference to the `flask` module. */
|
||||
DataFlow::Node flask() { result = flask(DataFlow::TypeTracker::end()) }
|
||||
|
||||
/**
|
||||
* Gets a reference to the attribute `attr_name` of the `flask` module.
|
||||
* WARNING: Only holds for a few predefined attributes.
|
||||
*/
|
||||
private DataFlow::Node flask_attr(DataFlow::TypeTracker t, string attr_name) {
|
||||
attr_name in ["request", "make_response", "Response", "views", "redirect"] and
|
||||
(
|
||||
t.start() and
|
||||
result = DataFlow::importNode("flask" + "." + attr_name)
|
||||
or
|
||||
t.startInAttr(attr_name) and
|
||||
result = flask()
|
||||
)
|
||||
or
|
||||
// Due to bad performance when using normal setup with `flask_attr(t2, attr_name).track(t2, t)`
|
||||
// we have inlined that code and forced a join
|
||||
exists(DataFlow::TypeTracker t2 |
|
||||
exists(DataFlow::StepSummary summary |
|
||||
flask_attr_first_join(t2, attr_name, result, summary) and
|
||||
t = t2.append(summary)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flask_attr_first_join(
|
||||
DataFlow::TypeTracker t2, string attr_name, DataFlow::Node res, DataFlow::StepSummary summary
|
||||
) {
|
||||
DataFlow::StepSummary::step(flask_attr(t2, attr_name), res, summary)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a reference to the attribute `attr_name` of the `flask` module.
|
||||
* WARNING: Only holds for a few predefined attributes.
|
||||
*/
|
||||
private DataFlow::Node flask_attr(string attr_name) {
|
||||
result = flask_attr(DataFlow::TypeTracker::end(), attr_name)
|
||||
}
|
||||
|
||||
/** Provides models for the `flask` module. */
|
||||
module flask {
|
||||
/** Gets a reference to the `flask.request` object. */
|
||||
DataFlow::Node request() { result = flask_attr("request") }
|
||||
|
||||
/** Gets a reference to the `flask.make_response` function. */
|
||||
DataFlow::Node make_response() { result = flask_attr("make_response") }
|
||||
module Flask {
|
||||
/** Provides models for flask view classes (defined in the `flask.views` module) */
|
||||
module Views {
|
||||
/**
|
||||
* Provides models for the `flask.views.View` class and subclasses.
|
||||
*
|
||||
* See https://flask.palletsprojects.com/en/1.1.x/views/#basic-principle.
|
||||
*/
|
||||
module View {
|
||||
/** Gets a reference to the `flask.views.View` class or any subclass. */
|
||||
API::Node subclassRef() {
|
||||
result =
|
||||
API::moduleImport("flask")
|
||||
.getMember("views")
|
||||
.getMember([
|
||||
"View",
|
||||
// MethodView is a known subclass
|
||||
"MethodView"
|
||||
])
|
||||
.getASubclass*()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides models for the `flask.Flask` class
|
||||
* Provides models for the `flask.views.MethodView` class and subclasses.
|
||||
*
|
||||
* See https://flask.palletsprojects.com/en/1.1.x/api/#flask.Flask.
|
||||
* See https://flask.palletsprojects.com/en/1.1.x/views/#method-based-dispatching.
|
||||
*/
|
||||
module Flask {
|
||||
/** Gets a reference to the `flask.Flask` class. */
|
||||
private DataFlow::Node classRef(DataFlow::TypeTracker t) {
|
||||
t.start() and
|
||||
result = DataFlow::importNode("flask.Flask")
|
||||
or
|
||||
t.startInAttr("Flask") and
|
||||
result = flask()
|
||||
or
|
||||
exists(DataFlow::TypeTracker t2 | result = classRef(t2).track(t2, t))
|
||||
}
|
||||
|
||||
/** Gets a reference to the `flask.Flask` class. */
|
||||
DataFlow::Node classRef() { result = classRef(DataFlow::TypeTracker::end()) }
|
||||
|
||||
/**
|
||||
* A source of instances of `flask.Flask`, extend this class to model new instances.
|
||||
*
|
||||
* This can include instantiations of the class, return values from function
|
||||
* calls, or a special parameter that will be set when functions are called by an external
|
||||
* library.
|
||||
*
|
||||
* Use the predicate `Flask::instance()` to get references to instances of `flask.Flask`.
|
||||
*/
|
||||
abstract class InstanceSource extends DataFlow::Node { }
|
||||
|
||||
/** A direct instantiation of `flask.Flask`. */
|
||||
private class ClassInstantiation extends InstanceSource, DataFlow::CfgNode {
|
||||
override CallNode node;
|
||||
|
||||
ClassInstantiation() { node.getFunction() = classRef().asCfgNode() }
|
||||
}
|
||||
|
||||
/** Gets a reference to an instance of `flask.Flask` (a flask application). */
|
||||
private DataFlow::Node instance(DataFlow::TypeTracker t) {
|
||||
t.start() and
|
||||
result instanceof InstanceSource
|
||||
or
|
||||
exists(DataFlow::TypeTracker t2 | result = instance(t2).track(t2, t))
|
||||
}
|
||||
|
||||
/** Gets a reference to an instance of `flask.Flask` (a flask application). */
|
||||
DataFlow::Node instance() { result = instance(DataFlow::TypeTracker::end()) }
|
||||
|
||||
/**
|
||||
* Gets a reference to the attribute `attr_name` of an instance of `flask.Flask` (a flask application).
|
||||
* WARNING: Only holds for a few predefined attributes.
|
||||
*/
|
||||
private DataFlow::Node instance_attr(DataFlow::TypeTracker t, string attr_name) {
|
||||
attr_name in ["route", "add_url_rule", "make_response"] and
|
||||
t.startInAttr(attr_name) and
|
||||
result = flask::Flask::instance()
|
||||
or
|
||||
// Due to bad performance when using normal setup with `instance_attr(t2, attr_name).track(t2, t)`
|
||||
// we have inlined that code and forced a join
|
||||
exists(DataFlow::TypeTracker t2 |
|
||||
exists(DataFlow::StepSummary summary |
|
||||
instance_attr_first_join(t2, attr_name, result, summary) and
|
||||
t = t2.append(summary)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate instance_attr_first_join(
|
||||
DataFlow::TypeTracker t2, string attr_name, DataFlow::Node res,
|
||||
DataFlow::StepSummary summary
|
||||
) {
|
||||
DataFlow::StepSummary::step(instance_attr(t2, attr_name), res, summary)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a reference to the attribute `attr_name` of an instance of `flask.Flask` (a flask application).
|
||||
* WARNING: Only holds for a few predefined attributes.
|
||||
*/
|
||||
private DataFlow::Node instance_attr(string attr_name) {
|
||||
result = instance_attr(DataFlow::TypeTracker::end(), attr_name)
|
||||
}
|
||||
|
||||
/** Gets a reference to the `route` method on an instance of `flask.Flask`. */
|
||||
DataFlow::Node route() { result = instance_attr("route") }
|
||||
|
||||
/** Gets a reference to the `add_url_rule` method on an instance of `flask.Flask`. */
|
||||
DataFlow::Node add_url_rule() { result = instance_attr("add_url_rule") }
|
||||
|
||||
/** Gets a reference to the `make_response` method on an instance of `flask.Flask`. */
|
||||
// HACK: We can't call this predicate `make_response` since shadowing is
|
||||
// completely disallowed in QL. I added an underscore to move things forward for
|
||||
// now :(
|
||||
DataFlow::Node make_response_() { result = instance_attr("make_response") }
|
||||
|
||||
/** Gets a reference to the `response_class` attribute on the `flask.Flask` class or an instance. */
|
||||
private DataFlow::Node response_class(DataFlow::TypeTracker t) {
|
||||
t.startInAttr("response_class") and
|
||||
result in [classRef(), instance()]
|
||||
or
|
||||
exists(DataFlow::TypeTracker t2 | result = response_class(t2).track(t2, t))
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a reference to the `response_class` attribute on the `flask.Flask` class or an instance.
|
||||
*
|
||||
* See https://flask.palletsprojects.com/en/1.1.x/api/#flask.Flask.response_class
|
||||
*/
|
||||
DataFlow::Node response_class() { result = response_class(DataFlow::TypeTracker::end()) }
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// flask.views
|
||||
// -------------------------------------------------------------------------
|
||||
/** Gets a reference to the `flask.views` module. */
|
||||
DataFlow::Node views() { result = flask_attr("views") }
|
||||
|
||||
/** Provides models for the `flask.views` module */
|
||||
module views {
|
||||
/**
|
||||
* Gets a reference to the attribute `attr_name` of the `flask.views` module.
|
||||
* WARNING: Only holds for a few predefined attributes.
|
||||
*/
|
||||
private DataFlow::Node views_attr(DataFlow::TypeTracker t, string attr_name) {
|
||||
attr_name in ["View", "MethodView"] and
|
||||
(
|
||||
t.start() and
|
||||
result = DataFlow::importNode("flask.views" + "." + attr_name)
|
||||
or
|
||||
t.startInAttr(attr_name) and
|
||||
result = views()
|
||||
)
|
||||
or
|
||||
// Due to bad performance when using normal setup with `views_attr(t2, attr_name).track(t2, t)`
|
||||
// we have inlined that code and forced a join
|
||||
exists(DataFlow::TypeTracker t2 |
|
||||
exists(DataFlow::StepSummary summary |
|
||||
views_attr_first_join(t2, attr_name, result, summary) and
|
||||
t = t2.append(summary)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate views_attr_first_join(
|
||||
DataFlow::TypeTracker t2, string attr_name, DataFlow::Node res,
|
||||
DataFlow::StepSummary summary
|
||||
) {
|
||||
DataFlow::StepSummary::step(views_attr(t2, attr_name), res, summary)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a reference to the attribute `attr_name` of the `flask.views` module.
|
||||
* WARNING: Only holds for a few predefined attributes.
|
||||
*/
|
||||
private DataFlow::Node views_attr(string attr_name) {
|
||||
result = views_attr(DataFlow::TypeTracker::end(), attr_name)
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides models for the `flask.views.View` class and subclasses.
|
||||
*
|
||||
* See https://flask.palletsprojects.com/en/1.1.x/views/#basic-principle.
|
||||
*/
|
||||
module View {
|
||||
/** Gets a reference to the `flask.views.View` class or any subclass. */
|
||||
private DataFlow::Node subclassRef(DataFlow::TypeTracker t) {
|
||||
t.start() and
|
||||
result = views_attr(["View", "MethodView"])
|
||||
or
|
||||
// subclasses in project code
|
||||
result.asExpr().(ClassExpr).getABase() = subclassRef(t.continue()).asExpr()
|
||||
or
|
||||
exists(DataFlow::TypeTracker t2 | result = subclassRef(t2).track(t2, t))
|
||||
}
|
||||
|
||||
/** Gets a reference to the `flask.views.View` class or any subclass. */
|
||||
DataFlow::Node subclassRef() { result = subclassRef(DataFlow::TypeTracker::end()) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides models for the `flask.views.MethodView` class and subclasses.
|
||||
*
|
||||
* See https://flask.palletsprojects.com/en/1.1.x/views/#method-based-dispatching.
|
||||
*/
|
||||
module MethodView {
|
||||
/** Gets a reference to the `flask.views.View` class or any subclass. */
|
||||
private DataFlow::Node subclassRef(DataFlow::TypeTracker t) {
|
||||
t.start() and
|
||||
result = views_attr("MethodView")
|
||||
or
|
||||
// subclasses in project code
|
||||
result.asExpr().(ClassExpr).getABase() = subclassRef(t.continue()).asExpr()
|
||||
or
|
||||
exists(DataFlow::TypeTracker t2 | result = subclassRef(t2).track(t2, t))
|
||||
}
|
||||
|
||||
/** Gets a reference to the `flask.views.View` class or any subclass. */
|
||||
DataFlow::Node subclassRef() { result = subclassRef(DataFlow::TypeTracker::end()) }
|
||||
module MethodView {
|
||||
/** Gets a reference to the `flask.views.MethodView` class or any subclass. */
|
||||
API::Node subclassRef() {
|
||||
result =
|
||||
API::moduleImport("flask").getMember("views").getMember("MethodView").getASubclass*()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides models for flask applications (instances of the `flask.Flask` class).
|
||||
*
|
||||
* See https://flask.palletsprojects.com/en/1.1.x/api/#flask.Flask.
|
||||
*/
|
||||
module FlaskApp {
|
||||
/** Gets a reference to the `flask.Flask` class. */
|
||||
API::Node classRef() { result = API::moduleImport("flask").getMember("Flask") }
|
||||
|
||||
/** Gets a reference to an instance of `flask.Flask` (a flask application). */
|
||||
API::Node instance() { result = classRef().getReturn() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides models for flask blueprints (instances of the `flask.Blueprint` class).
|
||||
*
|
||||
* See https://flask.palletsprojects.com/en/1.1.x/api/#flask.Blueprint.
|
||||
*/
|
||||
module Blueprint {
|
||||
/** Gets a reference to the `flask.Blueprint` class. */
|
||||
API::Node classRef() { result = API::moduleImport("flask").getMember("Blueprint") }
|
||||
|
||||
/** Gets a reference to an instance of `flask.Blueprint`. */
|
||||
API::Node instance() { result = classRef().getReturn() }
|
||||
}
|
||||
|
||||
/** Gets a reference to the `flask.request` object. */
|
||||
API::Node request() { result = API::moduleImport("flask").getMember("request") }
|
||||
|
||||
/**
|
||||
* Provides models for the `flask.Response` class
|
||||
*
|
||||
* See https://flask.palletsprojects.com/en/1.1.x/api/#flask.Response.
|
||||
*/
|
||||
module Response {
|
||||
/** Gets a reference to the `flask.Response` class. */
|
||||
private DataFlow::Node classRef(DataFlow::TypeTracker t) {
|
||||
t.start() and
|
||||
result in [flask_attr("Response"), flask::Flask::response_class()]
|
||||
/**
|
||||
* Gets a reference to the `flask.Response` class, possibly through the
|
||||
* `response_class` class attribute on a flask application (which by is an alias for
|
||||
* `flask.Response` by default).
|
||||
*/
|
||||
API::Node classRef() {
|
||||
result = API::moduleImport("flask").getMember("Response")
|
||||
or
|
||||
exists(DataFlow::TypeTracker t2 | result = classRef(t2).track(t2, t))
|
||||
result = [FlaskApp::classRef(), FlaskApp::instance()].getMember("response_class")
|
||||
}
|
||||
|
||||
/** Gets a reference to the `flask.Response` class. */
|
||||
DataFlow::Node classRef() { result = classRef(DataFlow::TypeTracker::end()) }
|
||||
|
||||
/**
|
||||
* INTERNAL: Do not use.
|
||||
*
|
||||
* A source of instances of `flask.Response`, extend this class to model new instances.
|
||||
*
|
||||
* This can include instantiations of the class, return values from function
|
||||
@@ -309,23 +112,21 @@ private module FlaskModel {
|
||||
abstract class InstanceSource extends HTTP::Server::HttpResponse::Range, DataFlow::Node { }
|
||||
|
||||
/** A direct instantiation of `flask.Response`. */
|
||||
private class ClassInstantiation extends InstanceSource, DataFlow::CfgNode {
|
||||
override CallNode node;
|
||||
private class ClassInstantiation extends InstanceSource, DataFlow::CallCfgNode {
|
||||
ClassInstantiation() { this = classRef().getACall() }
|
||||
|
||||
ClassInstantiation() { node.getFunction() = classRef().asCfgNode() }
|
||||
|
||||
override DataFlow::Node getBody() { result.asCfgNode() = node.getArg(0) }
|
||||
override DataFlow::Node getBody() { result = this.getArg(0) }
|
||||
|
||||
override string getMimetypeDefault() { result = "text/html" }
|
||||
|
||||
/** Gets the argument passed to the `mimetype` parameter, if any. */
|
||||
private DataFlow::Node getMimetypeArg() {
|
||||
result.asCfgNode() in [node.getArg(3), node.getArgByName("mimetype")]
|
||||
result in [this.getArg(3), this.getArgByName("mimetype")]
|
||||
}
|
||||
|
||||
/** Gets the argument passed to the `content_type` parameter, if any. */
|
||||
private DataFlow::Node getContentTypeArg() {
|
||||
result.asCfgNode() in [node.getArg(4), node.getArgByName("content_type")]
|
||||
result in [this.getArg(4), this.getArgByName("content_type")]
|
||||
}
|
||||
|
||||
override DataFlow::Node getMimetypeOrContentTypeArg() {
|
||||
@@ -337,8 +138,32 @@ private module FlaskModel {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to either `flask.make_response` function, or the `make_response` method on
|
||||
* an instance of `flask.Flask`. This creates an instance of the `flask_response`
|
||||
* class (class-attribute on a flask application), which by default is
|
||||
* `flask.Response`.
|
||||
*
|
||||
* See
|
||||
* - https://flask.palletsprojects.com/en/1.1.x/api/#flask.Flask.make_response
|
||||
* - https://flask.palletsprojects.com/en/1.1.x/api/#flask.make_response
|
||||
*/
|
||||
private class FlaskMakeResponseCall extends InstanceSource, DataFlow::CallCfgNode {
|
||||
FlaskMakeResponseCall() {
|
||||
this = API::moduleImport("flask").getMember("make_response").getACall()
|
||||
or
|
||||
this = FlaskApp::instance().getMember("make_response").getACall()
|
||||
}
|
||||
|
||||
override DataFlow::Node getBody() { result = this.getArg(0) }
|
||||
|
||||
override string getMimetypeDefault() { result = "text/html" }
|
||||
|
||||
override DataFlow::Node getMimetypeOrContentTypeArg() { none() }
|
||||
}
|
||||
|
||||
/** Gets a reference to an instance of `flask.Response`. */
|
||||
private DataFlow::Node instance(DataFlow::TypeTracker t) {
|
||||
private DataFlow::LocalSourceNode instance(DataFlow::TypeTracker t) {
|
||||
t.start() and
|
||||
result instanceof InstanceSource
|
||||
or
|
||||
@@ -346,15 +171,23 @@ private module FlaskModel {
|
||||
}
|
||||
|
||||
/** Gets a reference to an instance of `flask.Response`. */
|
||||
DataFlow::Node instance() { result = instance(DataFlow::TypeTracker::end()) }
|
||||
DataFlow::Node instance() { instance(DataFlow::TypeTracker::end()).flowsTo(result) }
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// routing modeling
|
||||
// ---------------------------------------------------------------------------
|
||||
/** A flask View class defined in project code. */
|
||||
class FlaskViewClassDef extends Class {
|
||||
FlaskViewClassDef() { this.getABase() = flask::views::View::subclassRef().asExpr() }
|
||||
/**
|
||||
* A class that is a subclass of the `flask.views.View` class,
|
||||
* thereby being able to handle incoming HTTP requests.
|
||||
*/
|
||||
class FlaskViewClass extends Class {
|
||||
API::Node api_node;
|
||||
|
||||
FlaskViewClass() {
|
||||
this.getABase() = Views::View::subclassRef().getAUse().asExpr() and
|
||||
api_node.getAnImmediateUse().asExpr().(ClassExpr) = this.getParent()
|
||||
}
|
||||
|
||||
/** Gets a function that could handle incoming requests, if any. */
|
||||
Function getARequestHandler() {
|
||||
@@ -364,42 +197,22 @@ private module FlaskModel {
|
||||
result.getName() = "dispatch_request"
|
||||
}
|
||||
|
||||
/** Gets a reference to this class. */
|
||||
private DataFlow::Node getARef(DataFlow::TypeTracker t) {
|
||||
t.start() and
|
||||
result.asExpr().(ClassExpr) = this.getParent()
|
||||
or
|
||||
exists(DataFlow::TypeTracker t2 | result = this.getARef(t2).track(t2, t))
|
||||
}
|
||||
|
||||
/** Gets a reference to this class. */
|
||||
DataFlow::Node getARef() { result = this.getARef(DataFlow::TypeTracker::end()) }
|
||||
|
||||
/** Gets a reference to the `as_view` classmethod of this class. */
|
||||
private DataFlow::Node asViewRef(DataFlow::TypeTracker t) {
|
||||
t.startInAttr("as_view") and
|
||||
result = this.getARef()
|
||||
or
|
||||
exists(DataFlow::TypeTracker t2 | result = this.asViewRef(t2).track(t2, t))
|
||||
}
|
||||
|
||||
/** Gets a reference to the `as_view` classmethod of this class. */
|
||||
DataFlow::Node asViewRef() { result = this.asViewRef(DataFlow::TypeTracker::end()) }
|
||||
|
||||
/** Gets a reference to the result of calling the `as_view` classmethod of this class. */
|
||||
private DataFlow::Node asViewResult(DataFlow::TypeTracker t) {
|
||||
t.start() and
|
||||
result.asCfgNode().(CallNode).getFunction() = this.asViewRef().asCfgNode()
|
||||
or
|
||||
exists(DataFlow::TypeTracker t2 | result = asViewResult(t2).track(t2, t))
|
||||
}
|
||||
|
||||
/** Gets a reference to the result of calling the `as_view` classmethod of this class. */
|
||||
DataFlow::Node asViewResult() { result = asViewResult(DataFlow::TypeTracker::end()) }
|
||||
/**
|
||||
* INTERNAL: Do not use.
|
||||
* Gets a reference to the result of calling the `as_view` classmethod of this class.
|
||||
*/
|
||||
API::Node asViewResult() { result = api_node.getMember("as_view").getReturn() }
|
||||
}
|
||||
|
||||
class FlaskMethodViewClassDef extends FlaskViewClassDef {
|
||||
FlaskMethodViewClassDef() { this.getABase() = flask::views::MethodView::subclassRef().asExpr() }
|
||||
/**
|
||||
* A class that is a subclass of the `flask.views.MethodView` class.
|
||||
* thereby being able to handle incoming HTTP requests.
|
||||
*/
|
||||
class FlaskMethodViewClass extends FlaskViewClass {
|
||||
FlaskMethodViewClass() {
|
||||
this.getABase() = Views::MethodView::subclassRef().getAUse().asExpr() and
|
||||
api_node.getAnImmediateUse().asExpr().(ClassExpr) = this.getParent()
|
||||
}
|
||||
|
||||
override Function getARequestHandler() {
|
||||
result = super.getARequestHandler()
|
||||
@@ -435,42 +248,46 @@ private module FlaskModel {
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override string getFramework() { result = "Flask" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to the `route` method on an instance of `flask.Flask`.
|
||||
* A call to the `route` method on an instance of `flask.Flask` or an instance of `flask.Blueprint`.
|
||||
*
|
||||
* See https://flask.palletsprojects.com/en/1.1.x/api/#flask.Flask.route
|
||||
*/
|
||||
private class FlaskAppRouteCall extends FlaskRouteSetup, DataFlow::CfgNode {
|
||||
override CallNode node;
|
||||
|
||||
FlaskAppRouteCall() { node.getFunction() = flask::Flask::route().asCfgNode() }
|
||||
private class FlaskAppRouteCall extends FlaskRouteSetup, DataFlow::CallCfgNode {
|
||||
FlaskAppRouteCall() {
|
||||
this = FlaskApp::instance().getMember("route").getACall()
|
||||
or
|
||||
this = Blueprint::instance().getMember("route").getACall()
|
||||
}
|
||||
|
||||
override DataFlow::Node getUrlPatternArg() {
|
||||
result.asCfgNode() in [node.getArg(0), node.getArgByName("rule")]
|
||||
result in [this.getArg(0), this.getArgByName("rule")]
|
||||
}
|
||||
|
||||
override Function getARequestHandler() { result.getADecorator().getAFlowNode() = node }
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to the `add_url_rule` method on an instance of `flask.Flask`.
|
||||
* A call to the `add_url_rule` method on an instance of `flask.Flask` or an instance of `flask.Blueprint`.
|
||||
*
|
||||
* See https://flask.palletsprojects.com/en/1.1.x/api/#flask.Flask.add_url_rule
|
||||
*/
|
||||
private class FlaskAppAddUrlRuleCall extends FlaskRouteSetup, DataFlow::CfgNode {
|
||||
override CallNode node;
|
||||
|
||||
FlaskAppAddUrlRuleCall() { node.getFunction() = flask::Flask::add_url_rule().asCfgNode() }
|
||||
private class FlaskAppAddUrlRuleCall extends FlaskRouteSetup, DataFlow::CallCfgNode {
|
||||
FlaskAppAddUrlRuleCall() {
|
||||
this = FlaskApp::instance().getMember("add_url_rule").getACall()
|
||||
or
|
||||
this = Blueprint::instance().getMember("add_url_rule").getACall()
|
||||
}
|
||||
|
||||
override DataFlow::Node getUrlPatternArg() {
|
||||
result.asCfgNode() in [node.getArg(0), node.getArgByName("rule")]
|
||||
result in [this.getArg(0), this.getArgByName("rule")]
|
||||
}
|
||||
|
||||
DataFlow::Node getViewArg() {
|
||||
result.asCfgNode() in [node.getArg(2), node.getArgByName("view_func")]
|
||||
}
|
||||
DataFlow::Node getViewArg() { result in [this.getArg(2), this.getArgByName("view_func")] }
|
||||
|
||||
override Function getARequestHandler() {
|
||||
exists(DataFlow::LocalSourceNode func_src |
|
||||
@@ -478,8 +295,8 @@ private module FlaskModel {
|
||||
func_src.asExpr().(CallableExpr) = result.getDefinition()
|
||||
)
|
||||
or
|
||||
exists(FlaskViewClassDef vc |
|
||||
getViewArg() = vc.asViewResult() and
|
||||
exists(FlaskViewClass vc |
|
||||
getViewArg() = vc.asViewResult().getAUse() and
|
||||
result = vc.getARequestHandler()
|
||||
)
|
||||
}
|
||||
@@ -488,7 +305,7 @@ private module FlaskModel {
|
||||
/** A request handler defined in a django view class, that has no known route. */
|
||||
private class FlaskViewClassHandlerWithoutKnownRoute extends HTTP::Server::RequestHandler::Range {
|
||||
FlaskViewClassHandlerWithoutKnownRoute() {
|
||||
exists(FlaskViewClassDef vc | vc.getARequestHandler() = this) and
|
||||
exists(FlaskViewClass vc | vc.getARequestHandler() = this) and
|
||||
not exists(FlaskRouteSetup setup | setup.getARequestHandler() = this)
|
||||
}
|
||||
|
||||
@@ -499,70 +316,52 @@ private module FlaskModel {
|
||||
result in [this.getArg(_), this.getArgByName(_)] and
|
||||
not result = this.getArg(0)
|
||||
}
|
||||
|
||||
override string getFramework() { result = "Flask" }
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// flask.Request taint modeling
|
||||
// ---------------------------------------------------------------------------
|
||||
// TODO: Do we even need this class? :|
|
||||
/**
|
||||
* A source of remote flow from a flask request.
|
||||
*
|
||||
* See https://flask.palletsprojects.com/en/1.1.x/api/#flask.Request
|
||||
*/
|
||||
private class RequestSource extends RemoteFlowSource::Range {
|
||||
RequestSource() { this = flask::request() }
|
||||
private class FlaskRequestSource extends RemoteFlowSource::Range {
|
||||
FlaskRequestSource() {
|
||||
this = request().getAUse() and
|
||||
not any(Import imp).contains(this.asExpr()) and
|
||||
not exists(ControlFlowNode def | this.asVar().getSourceVariable().hasDefiningNode(def) |
|
||||
any(Import imp).contains(def.getNode())
|
||||
)
|
||||
}
|
||||
|
||||
override string getSourceType() { result = "flask.request" }
|
||||
}
|
||||
|
||||
private module FlaskRequestTracking {
|
||||
/** Gets a reference to the `get_data` attribute of a Flask request. */
|
||||
private DataFlow::Node get_data(DataFlow::TypeTracker t) {
|
||||
t.startInAttr("get_data") and
|
||||
result = flask::request()
|
||||
or
|
||||
exists(DataFlow::TypeTracker t2 | result = get_data(t2).track(t2, t))
|
||||
}
|
||||
|
||||
/** Gets a reference to the `get_data` attribute of a Flask request. */
|
||||
DataFlow::Node get_data() { result = get_data(DataFlow::TypeTracker::end()) }
|
||||
|
||||
/** Gets a reference to the `get_json` attribute of a Flask request. */
|
||||
private DataFlow::Node get_json(DataFlow::TypeTracker t) {
|
||||
t.startInAttr("get_json") and
|
||||
result = flask::request()
|
||||
or
|
||||
exists(DataFlow::TypeTracker t2 | result = get_json(t2).track(t2, t))
|
||||
}
|
||||
|
||||
/** Gets a reference to the `get_json` attribute of a Flask request. */
|
||||
DataFlow::Node get_json() { result = get_json(DataFlow::TypeTracker::end()) }
|
||||
|
||||
/** Gets a reference to either of the `get_json` or `get_data` attributes of a Flask request. */
|
||||
DataFlow::Node tainted_methods(string attr_name) {
|
||||
result = get_data() and
|
||||
attr_name = "get_data"
|
||||
or
|
||||
result = get_json() and
|
||||
attr_name = "get_json"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A source of remote flow from attributes from a flask request.
|
||||
* Taint propagation for a flask request.
|
||||
*
|
||||
* See https://flask.palletsprojects.com/en/1.1.x/api/#flask.Request
|
||||
*/
|
||||
private class RequestInputAccess extends RemoteFlowSource::Range {
|
||||
string attr_name;
|
||||
|
||||
RequestInputAccess() {
|
||||
// attributes
|
||||
exists(AttrNode attr |
|
||||
this.asCfgNode() = attr and attr.getObject(attr_name) = flask::request().asCfgNode()
|
||||
|
|
||||
attr_name in [
|
||||
private class FlaskRequestAdditionalTaintStep extends TaintTracking::AdditionalTaintStep {
|
||||
override predicate step(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
|
||||
// Methods
|
||||
exists(string method_name | method_name in ["get_data", "get_json"] |
|
||||
// Method access
|
||||
nodeFrom = request().getAUse() and
|
||||
nodeTo = request().getMember(method_name).getAnImmediateUse()
|
||||
or
|
||||
// Method call
|
||||
nodeFrom = request().getMember(method_name).getAUse() and
|
||||
nodeTo.(DataFlow::CallCfgNode).getFunction() = nodeFrom
|
||||
)
|
||||
or
|
||||
// Attributes
|
||||
nodeFrom = request().getAUse() and
|
||||
exists(DataFlow::AttrRead read | nodeTo = read and read.getObject() = nodeFrom |
|
||||
read.getAttributeName() in [
|
||||
// str
|
||||
"path", "full_path", "base_url", "url", "access_control_request_method",
|
||||
"content_encoding", "content_md5", "content_type", "data", "method", "mimetype",
|
||||
@@ -598,63 +397,29 @@ private module FlaskModel {
|
||||
"headers"
|
||||
]
|
||||
)
|
||||
or
|
||||
// methods (needs special handling to track bound-methods -- see `FlaskRequestMethodCallsAdditionalTaintStep` below)
|
||||
this = FlaskRequestTracking::tainted_methods(attr_name)
|
||||
}
|
||||
|
||||
override string getSourceType() { result = "flask.request input" }
|
||||
}
|
||||
|
||||
private class FlaskRequestMethodCallsAdditionalTaintStep extends TaintTracking::AdditionalTaintStep {
|
||||
override predicate step(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
|
||||
// NOTE: `request -> request.tainted_method` part is handled as part of RequestInputAccess
|
||||
// tainted_method -> tainted_method()
|
||||
nodeFrom = FlaskRequestTracking::tainted_methods(_) and
|
||||
nodeTo.asCfgNode().(CallNode).getFunction() = nodeFrom.asCfgNode()
|
||||
}
|
||||
}
|
||||
|
||||
private class RequestInputMultiDict extends RequestInputAccess,
|
||||
Werkzeug::werkzeug::datastructures::MultiDict::InstanceSource {
|
||||
RequestInputMultiDict() { attr_name in ["args", "values", "form", "files"] }
|
||||
private class RequestAttrMultiDict extends Werkzeug::werkzeug::datastructures::MultiDict::InstanceSource {
|
||||
string attr_name;
|
||||
|
||||
RequestAttrMultiDict() {
|
||||
attr_name in ["args", "values", "form", "files"] and
|
||||
this = request().getMember(attr_name).getAnImmediateUse()
|
||||
}
|
||||
}
|
||||
|
||||
private class RequestInputFiles extends RequestInputMultiDict {
|
||||
RequestInputFiles() { attr_name = "files" }
|
||||
private class RequestAttrFiles extends RequestAttrMultiDict {
|
||||
// TODO: Somehow specify that elements of `RequestAttrFiles` are
|
||||
// Werkzeug::werkzeug::datastructures::FileStorage and should have those additional taint steps
|
||||
// AND that the 0-indexed argument to its' save method is a sink for path-injection.
|
||||
// https://werkzeug.palletsprojects.com/en/1.0.x/datastructures/#werkzeug.datastructures.FileStorage.save
|
||||
RequestAttrFiles() { attr_name = "files" }
|
||||
}
|
||||
|
||||
// TODO: Somehow specify that elements of `RequestInputFiles` are
|
||||
// Werkzeug::werkzeug::datastructures::FileStorage and should have those additional taint steps
|
||||
// AND that the 0-indexed argument to its' save method is a sink for path-injection.
|
||||
// https://werkzeug.palletsprojects.com/en/1.0.x/datastructures/#werkzeug.datastructures.FileStorage.save
|
||||
// ---------------------------------------------------------------------------
|
||||
// Response modeling
|
||||
// Implicit response from returns of flask request handlers
|
||||
// ---------------------------------------------------------------------------
|
||||
/**
|
||||
* A call to either `flask.make_response` function, or the `make_response` method on
|
||||
* an instance of `flask.Flask`.
|
||||
*
|
||||
* See
|
||||
* - https://flask.palletsprojects.com/en/1.1.x/api/#flask.Flask.make_response
|
||||
* - https://flask.palletsprojects.com/en/1.1.x/api/#flask.make_response
|
||||
*/
|
||||
private class FlaskMakeResponseCall extends HTTP::Server::HttpResponse::Range, DataFlow::CfgNode {
|
||||
override CallNode node;
|
||||
|
||||
FlaskMakeResponseCall() {
|
||||
node.getFunction() = flask::make_response().asCfgNode()
|
||||
or
|
||||
node.getFunction() = flask::Flask::make_response_().asCfgNode()
|
||||
}
|
||||
|
||||
override DataFlow::Node getBody() { result.asCfgNode() = node.getArg(0) }
|
||||
|
||||
override string getMimetypeDefault() { result = "text/html" }
|
||||
|
||||
override DataFlow::Node getMimetypeOrContentTypeArg() { none() }
|
||||
}
|
||||
|
||||
private class FlaskRouteHandlerReturn extends HTTP::Server::HttpResponse::Range, DataFlow::CfgNode {
|
||||
FlaskRouteHandlerReturn() {
|
||||
exists(Function routeHandler |
|
||||
@@ -670,19 +435,20 @@ private module FlaskModel {
|
||||
override string getMimetypeDefault() { result = "text/html" }
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// flask.redirect
|
||||
// ---------------------------------------------------------------------------
|
||||
/**
|
||||
* A call to the `flask.redirect` function.
|
||||
*
|
||||
* See https://flask.palletsprojects.com/en/1.1.x/api/#flask.redirect
|
||||
*/
|
||||
private class FlaskRedirectCall extends HTTP::Server::HttpRedirectResponse::Range,
|
||||
DataFlow::CfgNode {
|
||||
override CallNode node;
|
||||
|
||||
FlaskRedirectCall() { node.getFunction() = flask_attr("redirect").asCfgNode() }
|
||||
DataFlow::CallCfgNode {
|
||||
FlaskRedirectCall() { this = API::moduleImport("flask").getMember("redirect").getACall() }
|
||||
|
||||
override DataFlow::Node getRedirectLocation() {
|
||||
result.asCfgNode() in [node.getArg(0), node.getArgByName("location")]
|
||||
result in [this.getArg(0), this.getArgByName("location")]
|
||||
}
|
||||
|
||||
override DataFlow::Node getBody() { none() }
|
||||
|
||||
@@ -1630,6 +1630,8 @@ private module Stdlib {
|
||||
}
|
||||
|
||||
override Parameter getARoutedParameter() { none() }
|
||||
|
||||
override string getFramework() { result = "Stdlib" }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -486,7 +486,9 @@ private module Tornado {
|
||||
}
|
||||
|
||||
/** A tornado route setup. */
|
||||
abstract class TornadoRouteSetup extends HTTP::Server::RouteSetup::Range { }
|
||||
abstract class TornadoRouteSetup extends HTTP::Server::RouteSetup::Range {
|
||||
override string getFramework() { result = "Tornado" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A regex that is used to set up a route.
|
||||
@@ -561,6 +563,8 @@ private module Tornado {
|
||||
result in [this.getArg(_), this.getArgByName(_)] and
|
||||
not result = this.getArg(0)
|
||||
}
|
||||
|
||||
override string getFramework() { result = "Tornado" }
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
@@ -29,7 +29,13 @@ private module Yaml {
|
||||
* For example, using `attr_name = "load"` will get all uses of `yaml.load`.
|
||||
*/
|
||||
private DataFlow::Node yaml_attr(DataFlow::TypeTracker t, string attr_name) {
|
||||
attr_name in ["load", "SafeLoader", "BaseLoader"] and
|
||||
attr_name in [
|
||||
// functions
|
||||
"load", "load_all", "full_load", "full_load_all", "unsafe_load", "unsafe_load_all",
|
||||
"safe_load", "safe_load_all",
|
||||
// Classes
|
||||
"SafeLoader", "BaseLoader"
|
||||
] and
|
||||
(
|
||||
t.start() and
|
||||
result = DataFlow::importNode("yaml." + attr_name)
|
||||
@@ -68,13 +74,22 @@ private module Yaml {
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to `yaml.load`
|
||||
* A call to any of the loading functions in `yaml` (`load`, `load_all`, `full_load`,
|
||||
* `full_load_all`, `unsafe_load`, `unsafe_load_all`, `safe_load`, `safe_load_all`)
|
||||
*
|
||||
* See https://pyyaml.org/wiki/PyYAMLDocumentation (you will have to scroll down).
|
||||
*/
|
||||
private class YamlLoadCall extends Decoding::Range, DataFlow::CfgNode {
|
||||
override CallNode node;
|
||||
string func_name;
|
||||
|
||||
YamlLoadCall() { node.getFunction() = Yaml::yaml::yaml_attr("load").asCfgNode() }
|
||||
YamlLoadCall() {
|
||||
func_name in [
|
||||
"load", "load_all", "full_load", "full_load_all", "unsafe_load", "unsafe_load_all",
|
||||
"safe_load", "safe_load_all"
|
||||
] and
|
||||
node.getFunction() = Yaml::yaml::yaml_attr(func_name).asCfgNode()
|
||||
}
|
||||
|
||||
/**
|
||||
* This function was thought safe from the 5.1 release in 2017, when the default loader was changed to `FullLoader`.
|
||||
@@ -84,10 +99,16 @@ private class YamlLoadCall extends Decoding::Range, DataFlow::CfgNode {
|
||||
* See https://github.com/yaml/pyyaml/wiki/PyYAML-yaml.load(input)-Deprecation for more details.
|
||||
*/
|
||||
override predicate mayExecuteInput() {
|
||||
func_name in ["full_load", "full_load_all", "unsafe_load", "unsafe_load_all"]
|
||||
or
|
||||
func_name in ["load", "load_all"] and
|
||||
// If the `Loader` is not set to either `SafeLoader` or `BaseLoader` or not set at all,
|
||||
// then the default loader will be used, which is not safe.
|
||||
not node.getArgByName("Loader") =
|
||||
Yaml::yaml::yaml_attr(["SafeLoader", "BaseLoader"]).asCfgNode()
|
||||
not exists(DataFlow::Node loader_arg |
|
||||
loader_arg.asCfgNode() in [node.getArg(1), node.getArgByName("Loader")]
|
||||
|
|
||||
loader_arg = Yaml::yaml::yaml_attr(["SafeLoader", "BaseLoader"])
|
||||
)
|
||||
}
|
||||
|
||||
override DataFlow::Node getAnInput() { result.asCfgNode() = node.getArg(0) }
|
||||
|
||||
@@ -79,3 +79,24 @@ def f():
|
||||
from unknown import * #$ use=moduleImport("unknown")
|
||||
|
||||
hello() #$ MISSING: use=moduleImport("unknown").getMember("hello").getReturn()
|
||||
|
||||
|
||||
# Subclasses
|
||||
|
||||
from flask.views import View #$ use=moduleImport("flask").getMember("views").getMember("View")
|
||||
|
||||
class MyView(View): #$ use=moduleImport("flask").getMember("views").getMember("View").getASubclass()
|
||||
myvar = 45 #$ use=moduleImport("flask").getMember("views").getMember("View").getASubclass().getMember("myvar")
|
||||
def my_method(self): #$ use=moduleImport("flask").getMember("views").getMember("View").getASubclass().getMember("my_method")
|
||||
pass
|
||||
|
||||
instance = MyView() #$ use=moduleImport("flask").getMember("views").getMember("View").getASubclass().getReturn()
|
||||
|
||||
def internal():
|
||||
from pflask.views import View #$ use=moduleImport("pflask").getMember("views").getMember("View")
|
||||
class IntMyView(View): #$ use=moduleImport("pflask").getMember("views").getMember("View").getASubclass()
|
||||
my_internal_var = 35 #$ use=moduleImport("pflask").getMember("views").getMember("View").getASubclass().getMember("my_internal_var")
|
||||
def my_internal_method(self): #$ use=moduleImport("pflask").getMember("views").getMember("View").getASubclass().getMember("my_internal_method")
|
||||
pass
|
||||
|
||||
int_instance = IntMyView() #$ use=moduleImport("pflask").getMember("views").getMember("View").getASubclass().getReturn()
|
||||
|
||||
@@ -336,7 +336,17 @@ edges
|
||||
| test.py:673:9:673:14 | ControlFlowNode for Tuple [Tuple element at index 0] | test.py:673:9:673:9 | SSA variable x |
|
||||
| test.py:673:9:673:14 | IterableSequence [Tuple element at index 0] | test.py:673:9:673:14 | ControlFlowNode for Tuple [Tuple element at index 0] |
|
||||
| test.py:673:19:673:20 | ControlFlowNode for tl [List element, Tuple element at index 0] | test.py:673:9:673:14 | IterableSequence [Tuple element at index 0] |
|
||||
| test.py:748:16:748:21 | ControlFlowNode for SOURCE | test.py:751:10:751:36 | ControlFlowNode for return_from_inner_scope() |
|
||||
| test.py:678:39:678:42 | ControlFlowNode for args [Tuple element at index 0] | test.py:679:14:679:17 | ControlFlowNode for args [Tuple element at index 0] |
|
||||
| test.py:678:39:678:42 | ControlFlowNode for args [Tuple element at index 1] | test.py:679:14:679:17 | ControlFlowNode for args [Tuple element at index 1] |
|
||||
| test.py:679:7:679:9 | SSA variable arg | test.py:680:10:680:12 | ControlFlowNode for arg |
|
||||
| test.py:679:14:679:17 | ControlFlowNode for args [Tuple element at index 0] | test.py:679:7:679:9 | SSA variable arg |
|
||||
| test.py:679:14:679:17 | ControlFlowNode for args [Tuple element at index 1] | test.py:679:7:679:9 | SSA variable arg |
|
||||
| test.py:685:7:685:12 | ControlFlowNode for SOURCE | test.py:686:51:686:51 | ControlFlowNode for s |
|
||||
| test.py:686:3:686:52 | PosOverflowNode for iterate_star_args() [Tuple element at index 0] | test.py:678:39:678:42 | ControlFlowNode for args [Tuple element at index 0] |
|
||||
| test.py:686:3:686:52 | PosOverflowNode for iterate_star_args() [Tuple element at index 1] | test.py:678:39:678:42 | ControlFlowNode for args [Tuple element at index 1] |
|
||||
| test.py:686:43:686:48 | ControlFlowNode for SOURCE | test.py:686:3:686:52 | PosOverflowNode for iterate_star_args() [Tuple element at index 0] |
|
||||
| test.py:686:51:686:51 | ControlFlowNode for s | test.py:686:3:686:52 | PosOverflowNode for iterate_star_args() [Tuple element at index 1] |
|
||||
| test.py:757:16:757:21 | ControlFlowNode for SOURCE | test.py:760:10:760:36 | ControlFlowNode for return_from_inner_scope() |
|
||||
nodes
|
||||
| datamodel.py:38:6:38:17 | ControlFlowNode for f() | semmle.label | ControlFlowNode for f() |
|
||||
| datamodel.py:38:8:38:13 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
|
||||
@@ -735,8 +745,19 @@ nodes
|
||||
| test.py:673:9:673:14 | IterableSequence [Tuple element at index 0] | semmle.label | IterableSequence [Tuple element at index 0] |
|
||||
| test.py:673:19:673:20 | ControlFlowNode for tl [List element, Tuple element at index 0] | semmle.label | ControlFlowNode for tl [List element, Tuple element at index 0] |
|
||||
| test.py:674:14:674:14 | ControlFlowNode for x | semmle.label | ControlFlowNode for x |
|
||||
| test.py:748:16:748:21 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
|
||||
| test.py:751:10:751:36 | ControlFlowNode for return_from_inner_scope() | semmle.label | ControlFlowNode for return_from_inner_scope() |
|
||||
| test.py:678:39:678:42 | ControlFlowNode for args [Tuple element at index 0] | semmle.label | ControlFlowNode for args [Tuple element at index 0] |
|
||||
| test.py:678:39:678:42 | ControlFlowNode for args [Tuple element at index 1] | semmle.label | ControlFlowNode for args [Tuple element at index 1] |
|
||||
| test.py:679:7:679:9 | SSA variable arg | semmle.label | SSA variable arg |
|
||||
| test.py:679:14:679:17 | ControlFlowNode for args [Tuple element at index 0] | semmle.label | ControlFlowNode for args [Tuple element at index 0] |
|
||||
| test.py:679:14:679:17 | ControlFlowNode for args [Tuple element at index 1] | semmle.label | ControlFlowNode for args [Tuple element at index 1] |
|
||||
| test.py:680:10:680:12 | ControlFlowNode for arg | semmle.label | ControlFlowNode for arg |
|
||||
| test.py:685:7:685:12 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
|
||||
| test.py:686:3:686:52 | PosOverflowNode for iterate_star_args() [Tuple element at index 0] | semmle.label | PosOverflowNode for iterate_star_args() [Tuple element at index 0] |
|
||||
| test.py:686:3:686:52 | PosOverflowNode for iterate_star_args() [Tuple element at index 1] | semmle.label | PosOverflowNode for iterate_star_args() [Tuple element at index 1] |
|
||||
| test.py:686:43:686:48 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
|
||||
| test.py:686:51:686:51 | ControlFlowNode for s | semmle.label | ControlFlowNode for s |
|
||||
| test.py:757:16:757:21 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
|
||||
| test.py:760:10:760:36 | ControlFlowNode for return_from_inner_scope() | semmle.label | ControlFlowNode for return_from_inner_scope() |
|
||||
#select
|
||||
| datamodel.py:38:6:38:17 | ControlFlowNode for f() | datamodel.py:38:8:38:13 | ControlFlowNode for SOURCE | datamodel.py:38:6:38:17 | ControlFlowNode for f() | Flow found |
|
||||
| datamodel.py:71:6:71:24 | ControlFlowNode for Attribute() | datamodel.py:71:15:71:20 | ControlFlowNode for SOURCE | datamodel.py:71:6:71:24 | ControlFlowNode for Attribute() | Flow found |
|
||||
@@ -841,4 +862,6 @@ nodes
|
||||
| test.py:667:16:667:16 | ControlFlowNode for y | test.py:663:33:663:38 | ControlFlowNode for SOURCE | test.py:667:16:667:16 | ControlFlowNode for y | Flow found |
|
||||
| test.py:674:14:674:14 | ControlFlowNode for x | test.py:672:12:672:17 | ControlFlowNode for SOURCE | test.py:674:14:674:14 | ControlFlowNode for x | Flow found |
|
||||
| test.py:674:14:674:14 | ControlFlowNode for x | test.py:672:33:672:38 | ControlFlowNode for SOURCE | test.py:674:14:674:14 | ControlFlowNode for x | Flow found |
|
||||
| test.py:751:10:751:36 | ControlFlowNode for return_from_inner_scope() | test.py:748:16:748:21 | ControlFlowNode for SOURCE | test.py:751:10:751:36 | ControlFlowNode for return_from_inner_scope() | Flow found |
|
||||
| test.py:680:10:680:12 | ControlFlowNode for arg | test.py:685:7:685:12 | ControlFlowNode for SOURCE | test.py:680:10:680:12 | ControlFlowNode for arg | Flow found |
|
||||
| test.py:680:10:680:12 | ControlFlowNode for arg | test.py:686:43:686:48 | ControlFlowNode for SOURCE | test.py:680:10:680:12 | ControlFlowNode for arg | Flow found |
|
||||
| test.py:760:10:760:36 | ControlFlowNode for return_from_inner_scope() | test.py:757:16:757:21 | ControlFlowNode for SOURCE | test.py:760:10:760:36 | ControlFlowNode for return_from_inner_scope() | Flow found |
|
||||
|
||||
@@ -675,6 +675,15 @@ def test_iterable_star_unpacking_in_for_2():
|
||||
SINK_F(y) # The list itself is not tainted (and is here empty)
|
||||
SINK_F(z)
|
||||
|
||||
def iterate_star_args(first, second, *args):
|
||||
for arg in args:
|
||||
SINK(arg) #$ flow="SOURCE, l:+5 -> arg" flow="SOURCE, l:+6 -> arg"
|
||||
|
||||
# FP reported here: https://github.com/github/codeql-python-team/issues/49
|
||||
@expects(2)
|
||||
def test_overflow_iteration():
|
||||
s = SOURCE
|
||||
iterate_star_args(NONSOURCE, NONSOURCE, SOURCE, s)
|
||||
|
||||
def test_deep_callgraph():
|
||||
# port of python/ql/test/library-tests/taint/general/deep.py
|
||||
@@ -781,3 +790,9 @@ def test_reverse_read_subscript_cls():
|
||||
l = [withA]
|
||||
l[0].setA(SOURCE)
|
||||
SINK(withA.a) #$ MISSING:flow="SOURCE, l:-1 -> self.a"
|
||||
|
||||
@expects(3)
|
||||
def test_with_default_param_value(x=SOURCE, /, y=SOURCE, *, z=SOURCE):
|
||||
SINK(x) #$ MISSING:flow="SOURCE, l:-1 -> x"
|
||||
SINK(y) #$ MISSING:flow="SOURCE, l:-2 -> y"
|
||||
SINK(z) #$ MISSING:flow="SOURCE, l:-3 -> z"
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
module_tracker
|
||||
| import_as_attr.py:1:6:1:11 | ControlFlowNode for ImportExpr |
|
||||
module_attr_tracker
|
||||
| import_as_attr.py:0:0:0:0 | ModuleVariableNode for Global Variable attr_ref in Module import_as_attr |
|
||||
| import_as_attr.py:1:20:1:35 | ControlFlowNode for ImportMember |
|
||||
| import_as_attr.py:1:28:1:35 | GSSA Variable attr_ref |
|
||||
| import_as_attr.py:3:1:3:1 | GSSA Variable x |
|
||||
|
||||
@@ -2,16 +2,18 @@ import python
|
||||
import semmle.python.dataflow.new.DataFlow
|
||||
import semmle.python.dataflow.new.TypeTracker
|
||||
|
||||
DataFlow::Node module_tracker(TypeTracker t) {
|
||||
DataFlow::LocalSourceNode module_tracker(TypeTracker t) {
|
||||
t.start() and
|
||||
result = DataFlow::importNode("module")
|
||||
or
|
||||
exists(TypeTracker t2 | result = module_tracker(t2).track(t2, t))
|
||||
}
|
||||
|
||||
query DataFlow::Node module_tracker() { result = module_tracker(DataFlow::TypeTracker::end()) }
|
||||
query DataFlow::Node module_tracker() {
|
||||
module_tracker(DataFlow::TypeTracker::end()).flowsTo(result)
|
||||
}
|
||||
|
||||
DataFlow::Node module_attr_tracker(TypeTracker t) {
|
||||
DataFlow::LocalSourceNode module_attr_tracker(TypeTracker t) {
|
||||
t.startInAttr("attr") and
|
||||
result = module_tracker()
|
||||
or
|
||||
@@ -19,5 +21,5 @@ DataFlow::Node module_attr_tracker(TypeTracker t) {
|
||||
}
|
||||
|
||||
query DataFlow::Node module_attr_tracker() {
|
||||
result = module_attr_tracker(DataFlow::TypeTracker::end())
|
||||
module_attr_tracker(DataFlow::TypeTracker::end()).flowsTo(result)
|
||||
}
|
||||
|
||||
@@ -56,6 +56,41 @@ def test_import():
|
||||
y # $tracked
|
||||
mymodule.z # $tracked
|
||||
|
||||
|
||||
def to_inner_scope():
|
||||
x = tracked # $tracked
|
||||
def foo():
|
||||
y = x # $ MISSING: tracked
|
||||
return y # $ MISSING: tracked
|
||||
also_x = foo() # $ MISSING: tracked
|
||||
print(also_x) # $ MISSING: tracked
|
||||
|
||||
|
||||
def my_decorator(func):
|
||||
# This part doesn't make any sense in a normal decorator, but just shows how we
|
||||
# handle type-tracking
|
||||
|
||||
func() # $tracked
|
||||
|
||||
def wrapper():
|
||||
print("before function call")
|
||||
val = func() # $ MISSING: tracked
|
||||
print("after function call")
|
||||
return val # $ MISSING: tracked
|
||||
return wrapper
|
||||
|
||||
@my_decorator
|
||||
def get_tracked2():
|
||||
return tracked # $tracked
|
||||
|
||||
@my_decorator
|
||||
def unrelated_func():
|
||||
return "foo"
|
||||
|
||||
def use_funcs_with_decorators():
|
||||
x = get_tracked2() # $ MISSING: tracked
|
||||
y = unrelated_func()
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
def expects_int(x): # $int
|
||||
|
||||
@@ -6,7 +6,7 @@ import TestUtilities.InlineExpectationsTest
|
||||
// -----------------------------------------------------------------------------
|
||||
// tracked
|
||||
// -----------------------------------------------------------------------------
|
||||
DataFlow::Node tracked(TypeTracker t) {
|
||||
DataFlow::LocalSourceNode tracked(TypeTracker t) {
|
||||
t.start() and
|
||||
result.asCfgNode() = any(NameNode n | n.getId() = "tracked")
|
||||
or
|
||||
@@ -20,7 +20,7 @@ class TrackedTest extends InlineExpectationsTest {
|
||||
|
||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
exists(DataFlow::Node e, TypeTracker t |
|
||||
e = tracked(t) and
|
||||
tracked(t).flowsTo(e) and
|
||||
// Module variables have no sensible location, and hence can't be annotated.
|
||||
not e instanceof DataFlow::ModuleVariableNode and
|
||||
tag = "tracked" and
|
||||
@@ -34,14 +34,14 @@ class TrackedTest extends InlineExpectationsTest {
|
||||
// -----------------------------------------------------------------------------
|
||||
// int + str
|
||||
// -----------------------------------------------------------------------------
|
||||
DataFlow::Node int_type(TypeTracker t) {
|
||||
DataFlow::LocalSourceNode int_type(TypeTracker t) {
|
||||
t.start() and
|
||||
result.asCfgNode() = any(CallNode c | c.getFunction().(NameNode).getId() = "int")
|
||||
or
|
||||
exists(TypeTracker t2 | result = int_type(t2).track(t2, t))
|
||||
}
|
||||
|
||||
DataFlow::Node string_type(TypeTracker t) {
|
||||
DataFlow::LocalSourceNode string_type(TypeTracker t) {
|
||||
t.start() and
|
||||
result.asCfgNode() = any(CallNode c | c.getFunction().(NameNode).getId() = "str")
|
||||
or
|
||||
@@ -55,7 +55,7 @@ class TrackedIntTest extends InlineExpectationsTest {
|
||||
|
||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
exists(DataFlow::Node e, TypeTracker t |
|
||||
e = int_type(t) and
|
||||
int_type(t).flowsTo(e) and
|
||||
tag = "int" and
|
||||
location = e.getLocation() and
|
||||
value = t.getAttr() and
|
||||
@@ -71,7 +71,7 @@ class TrackedStringTest extends InlineExpectationsTest {
|
||||
|
||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
exists(DataFlow::Node e, TypeTracker t |
|
||||
e = string_type(t) and
|
||||
string_type(t).flowsTo(e) and
|
||||
tag = "str" and
|
||||
location = e.getLocation() and
|
||||
value = t.getAttr() and
|
||||
@@ -83,7 +83,7 @@ class TrackedStringTest extends InlineExpectationsTest {
|
||||
// -----------------------------------------------------------------------------
|
||||
// tracked_self
|
||||
// -----------------------------------------------------------------------------
|
||||
DataFlow::Node tracked_self(TypeTracker t) {
|
||||
DataFlow::LocalSourceNode tracked_self(TypeTracker t) {
|
||||
t.start() and
|
||||
exists(Function f |
|
||||
f.isMethod() and
|
||||
@@ -101,7 +101,7 @@ class TrackedSelfTest extends InlineExpectationsTest {
|
||||
|
||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
exists(DataFlow::Node e, TypeTracker t |
|
||||
e = tracked_self(t) and
|
||||
tracked_self(t).flowsTo(e) and
|
||||
// Module variables have no sensible location, and hence can't be annotated.
|
||||
not e instanceof DataFlow::ModuleVariableNode and
|
||||
tag = "tracked_self" and
|
||||
@@ -117,7 +117,7 @@ class TrackedSelfTest extends InlineExpectationsTest {
|
||||
// -----------------------------------------------------------------------------
|
||||
// This modeling follows the same pattern that we currently use in our real library modeling.
|
||||
/** Gets a reference to `foo` (fictive module). */
|
||||
private DataFlow::Node foo(DataFlow::TypeTracker t) {
|
||||
private DataFlow::LocalSourceNode foo(DataFlow::TypeTracker t) {
|
||||
t.start() and
|
||||
result = DataFlow::importNode("foo")
|
||||
or
|
||||
@@ -125,10 +125,10 @@ private DataFlow::Node foo(DataFlow::TypeTracker t) {
|
||||
}
|
||||
|
||||
/** Gets a reference to `foo` (fictive module). */
|
||||
DataFlow::Node foo() { result = foo(DataFlow::TypeTracker::end()) }
|
||||
DataFlow::Node foo() { foo(DataFlow::TypeTracker::end()).flowsTo(result) }
|
||||
|
||||
/** Gets a reference to `foo.bar` (fictive module). */
|
||||
private DataFlow::Node foo_bar(DataFlow::TypeTracker t) {
|
||||
private DataFlow::LocalSourceNode foo_bar(DataFlow::TypeTracker t) {
|
||||
t.start() and
|
||||
result = DataFlow::importNode("foo.bar")
|
||||
or
|
||||
@@ -139,10 +139,10 @@ private DataFlow::Node foo_bar(DataFlow::TypeTracker t) {
|
||||
}
|
||||
|
||||
/** Gets a reference to `foo.bar` (fictive module). */
|
||||
DataFlow::Node foo_bar() { result = foo_bar(DataFlow::TypeTracker::end()) }
|
||||
DataFlow::Node foo_bar() { foo_bar(DataFlow::TypeTracker::end()).flowsTo(result) }
|
||||
|
||||
/** Gets a reference to `foo.bar.baz` (fictive attribute on `foo.bar` module). */
|
||||
private DataFlow::Node foo_bar_baz(DataFlow::TypeTracker t) {
|
||||
private DataFlow::LocalSourceNode foo_bar_baz(DataFlow::TypeTracker t) {
|
||||
t.start() and
|
||||
result = DataFlow::importNode("foo.bar.baz")
|
||||
or
|
||||
@@ -153,7 +153,7 @@ private DataFlow::Node foo_bar_baz(DataFlow::TypeTracker t) {
|
||||
}
|
||||
|
||||
/** Gets a reference to `foo.bar.baz` (fictive attribute on `foo.bar` module). */
|
||||
DataFlow::Node foo_bar_baz() { result = foo_bar_baz(DataFlow::TypeTracker::end()) }
|
||||
DataFlow::Node foo_bar_baz() { foo_bar_baz(DataFlow::TypeTracker::end()).flowsTo(result) }
|
||||
|
||||
class TrackedFooBarBaz extends InlineExpectationsTest {
|
||||
TrackedFooBarBaz() { this = "TrackedFooBarBaz" }
|
||||
|
||||
@@ -1,82 +1,88 @@
|
||||
| taint_test.py:7 | ok | test_taint | bar |
|
||||
| taint_test.py:7 | ok | test_taint | foo |
|
||||
| taint_test.py:8 | ok | test_taint | baz |
|
||||
| taint_test.py:14 | ok | test_taint | request |
|
||||
| taint_test.py:16 | ok | test_taint | request.body |
|
||||
| taint_test.py:17 | ok | test_taint | request.path |
|
||||
| taint_test.py:18 | ok | test_taint | request.path_info |
|
||||
| taint_test.py:22 | ok | test_taint | request.method |
|
||||
| taint_test.py:24 | ok | test_taint | request.encoding |
|
||||
| taint_test.py:25 | ok | test_taint | request.content_type |
|
||||
| taint_test.py:28 | ok | test_taint | request.content_params |
|
||||
| taint_test.py:29 | ok | test_taint | request.content_params["key"] |
|
||||
| taint_test.py:30 | ok | test_taint | request.content_params.get(..) |
|
||||
| taint_test.py:34 | ok | test_taint | request.GET |
|
||||
| taint_test.py:35 | ok | test_taint | request.GET["key"] |
|
||||
| taint_test.py:36 | ok | test_taint | request.GET.get(..) |
|
||||
| taint_test.py:37 | fail | test_taint | request.GET.getlist(..) |
|
||||
| taint_test.py:38 | fail | test_taint | request.GET.getlist(..)[0] |
|
||||
| taint_test.py:39 | ok | test_taint | request.GET.pop(..) |
|
||||
| taint_test.py:40 | ok | test_taint | request.GET.pop(..)[0] |
|
||||
| taint_test.py:41 | ok | test_taint | request.GET.popitem()[0] |
|
||||
| taint_test.py:42 | ok | test_taint | request.GET.popitem()[1] |
|
||||
| taint_test.py:43 | ok | test_taint | request.GET.popitem()[1][0] |
|
||||
| taint_test.py:44 | fail | test_taint | request.GET.dict() |
|
||||
| taint_test.py:45 | fail | test_taint | request.GET.dict()["key"] |
|
||||
| taint_test.py:46 | fail | test_taint | request.GET.urlencode() |
|
||||
| taint_test.py:49 | ok | test_taint | request.POST |
|
||||
| taint_test.py:52 | ok | test_taint | request.COOKIES |
|
||||
| taint_test.py:53 | ok | test_taint | request.COOKIES["key"] |
|
||||
| taint_test.py:54 | ok | test_taint | request.COOKIES.get(..) |
|
||||
| taint_test.py:57 | ok | test_taint | request.FILES |
|
||||
| taint_test.py:58 | ok | test_taint | request.FILES["key"] |
|
||||
| taint_test.py:59 | fail | test_taint | request.FILES["key"].content_type |
|
||||
| taint_test.py:60 | fail | test_taint | request.FILES["key"].content_type_extra |
|
||||
| taint_test.py:61 | fail | test_taint | request.FILES["key"].content_type_extra["key"] |
|
||||
| taint_test.py:62 | fail | test_taint | request.FILES["key"].charset |
|
||||
| taint_test.py:63 | fail | test_taint | request.FILES["key"].name |
|
||||
| taint_test.py:64 | fail | test_taint | request.FILES["key"].file |
|
||||
| taint_test.py:65 | fail | test_taint | request.FILES["key"].file.read() |
|
||||
| taint_test.py:67 | ok | test_taint | request.FILES.get(..) |
|
||||
| taint_test.py:68 | fail | test_taint | request.FILES.get(..).name |
|
||||
| taint_test.py:69 | fail | test_taint | request.FILES.getlist(..) |
|
||||
| taint_test.py:70 | fail | test_taint | request.FILES.getlist(..)[0] |
|
||||
| taint_test.py:71 | fail | test_taint | request.FILES.getlist(..)[0].name |
|
||||
| taint_test.py:72 | fail | test_taint | request.FILES.dict() |
|
||||
| taint_test.py:73 | fail | test_taint | request.FILES.dict()["key"] |
|
||||
| taint_test.py:74 | fail | test_taint | request.FILES.dict()["key"].name |
|
||||
| taint_test.py:77 | ok | test_taint | request.META |
|
||||
| taint_test.py:78 | ok | test_taint | request.META["HTTP_USER_AGENT"] |
|
||||
| taint_test.py:79 | ok | test_taint | request.META.get(..) |
|
||||
| taint_test.py:82 | ok | test_taint | request.headers |
|
||||
| taint_test.py:83 | ok | test_taint | request.headers["user-agent"] |
|
||||
| taint_test.py:84 | ok | test_taint | request.headers["USER_AGENT"] |
|
||||
| taint_test.py:87 | ok | test_taint | request.resolver_match |
|
||||
| taint_test.py:88 | fail | test_taint | request.resolver_match.args |
|
||||
| taint_test.py:89 | fail | test_taint | request.resolver_match.args[0] |
|
||||
| taint_test.py:90 | fail | test_taint | request.resolver_match.kwargs |
|
||||
| taint_test.py:91 | fail | test_taint | request.resolver_match.kwargs["key"] |
|
||||
| taint_test.py:93 | fail | test_taint | request.get_full_path() |
|
||||
| taint_test.py:94 | fail | test_taint | request.get_full_path_info() |
|
||||
| taint_test.py:98 | fail | test_taint | request.read() |
|
||||
| taint_test.py:99 | fail | test_taint | request.readline() |
|
||||
| taint_test.py:100 | fail | test_taint | request.readlines() |
|
||||
| taint_test.py:101 | fail | test_taint | request.readlines()[0] |
|
||||
| taint_test.py:102 | fail | test_taint | ListComp |
|
||||
| taint_test.py:108 | ok | test_taint | args |
|
||||
| taint_test.py:109 | ok | test_taint | args[0] |
|
||||
| taint_test.py:110 | ok | test_taint | kwargs |
|
||||
| taint_test.py:111 | ok | test_taint | kwargs["key"] |
|
||||
| taint_test.py:115 | ok | test_taint | request.current_app |
|
||||
| taint_test.py:120 | ok | test_taint | request.get_host() |
|
||||
| taint_test.py:121 | ok | test_taint | request.get_port() |
|
||||
| taint_test.py:128 | fail | test_taint | request.build_absolute_uri() |
|
||||
| taint_test.py:129 | fail | test_taint | request.build_absolute_uri(..) |
|
||||
| taint_test.py:8 | ok | test_taint | bar |
|
||||
| taint_test.py:8 | ok | test_taint | foo |
|
||||
| taint_test.py:9 | ok | test_taint | baz |
|
||||
| taint_test.py:15 | ok | test_taint | request |
|
||||
| taint_test.py:17 | ok | test_taint | request.body |
|
||||
| taint_test.py:18 | ok | test_taint | request.path |
|
||||
| taint_test.py:19 | ok | test_taint | request.path_info |
|
||||
| taint_test.py:23 | ok | test_taint | request.method |
|
||||
| taint_test.py:25 | ok | test_taint | request.encoding |
|
||||
| taint_test.py:26 | ok | test_taint | request.content_type |
|
||||
| taint_test.py:29 | ok | test_taint | request.content_params |
|
||||
| taint_test.py:30 | ok | test_taint | request.content_params["key"] |
|
||||
| taint_test.py:31 | ok | test_taint | request.content_params.get(..) |
|
||||
| taint_test.py:35 | ok | test_taint | request.GET |
|
||||
| taint_test.py:36 | ok | test_taint | request.GET["key"] |
|
||||
| taint_test.py:37 | ok | test_taint | request.GET.get(..) |
|
||||
| taint_test.py:38 | fail | test_taint | request.GET.getlist(..) |
|
||||
| taint_test.py:39 | fail | test_taint | request.GET.getlist(..)[0] |
|
||||
| taint_test.py:40 | ok | test_taint | request.GET.pop(..) |
|
||||
| taint_test.py:41 | ok | test_taint | request.GET.pop(..)[0] |
|
||||
| taint_test.py:42 | ok | test_taint | request.GET.popitem()[0] |
|
||||
| taint_test.py:43 | ok | test_taint | request.GET.popitem()[1] |
|
||||
| taint_test.py:44 | ok | test_taint | request.GET.popitem()[1][0] |
|
||||
| taint_test.py:45 | fail | test_taint | request.GET.dict() |
|
||||
| taint_test.py:46 | fail | test_taint | request.GET.dict()["key"] |
|
||||
| taint_test.py:47 | fail | test_taint | request.GET.urlencode() |
|
||||
| taint_test.py:50 | ok | test_taint | request.POST |
|
||||
| taint_test.py:53 | ok | test_taint | request.COOKIES |
|
||||
| taint_test.py:54 | ok | test_taint | request.COOKIES["key"] |
|
||||
| taint_test.py:55 | ok | test_taint | request.COOKIES.get(..) |
|
||||
| taint_test.py:58 | ok | test_taint | request.FILES |
|
||||
| taint_test.py:59 | ok | test_taint | request.FILES["key"] |
|
||||
| taint_test.py:60 | fail | test_taint | request.FILES["key"].content_type |
|
||||
| taint_test.py:61 | fail | test_taint | request.FILES["key"].content_type_extra |
|
||||
| taint_test.py:62 | fail | test_taint | request.FILES["key"].content_type_extra["key"] |
|
||||
| taint_test.py:63 | fail | test_taint | request.FILES["key"].charset |
|
||||
| taint_test.py:64 | fail | test_taint | request.FILES["key"].name |
|
||||
| taint_test.py:65 | fail | test_taint | request.FILES["key"].file |
|
||||
| taint_test.py:66 | fail | test_taint | request.FILES["key"].file.read() |
|
||||
| taint_test.py:68 | ok | test_taint | request.FILES.get(..) |
|
||||
| taint_test.py:69 | fail | test_taint | request.FILES.get(..).name |
|
||||
| taint_test.py:70 | fail | test_taint | request.FILES.getlist(..) |
|
||||
| taint_test.py:71 | fail | test_taint | request.FILES.getlist(..)[0] |
|
||||
| taint_test.py:72 | fail | test_taint | request.FILES.getlist(..)[0].name |
|
||||
| taint_test.py:73 | fail | test_taint | request.FILES.dict() |
|
||||
| taint_test.py:74 | fail | test_taint | request.FILES.dict()["key"] |
|
||||
| taint_test.py:75 | fail | test_taint | request.FILES.dict()["key"].name |
|
||||
| taint_test.py:78 | ok | test_taint | request.META |
|
||||
| taint_test.py:79 | ok | test_taint | request.META["HTTP_USER_AGENT"] |
|
||||
| taint_test.py:80 | ok | test_taint | request.META.get(..) |
|
||||
| taint_test.py:83 | ok | test_taint | request.headers |
|
||||
| taint_test.py:84 | ok | test_taint | request.headers["user-agent"] |
|
||||
| taint_test.py:85 | ok | test_taint | request.headers["USER_AGENT"] |
|
||||
| taint_test.py:88 | ok | test_taint | request.resolver_match |
|
||||
| taint_test.py:89 | fail | test_taint | request.resolver_match.args |
|
||||
| taint_test.py:90 | fail | test_taint | request.resolver_match.args[0] |
|
||||
| taint_test.py:91 | fail | test_taint | request.resolver_match.kwargs |
|
||||
| taint_test.py:92 | fail | test_taint | request.resolver_match.kwargs["key"] |
|
||||
| taint_test.py:94 | fail | test_taint | request.get_full_path() |
|
||||
| taint_test.py:95 | fail | test_taint | request.get_full_path_info() |
|
||||
| taint_test.py:99 | fail | test_taint | request.read() |
|
||||
| taint_test.py:100 | fail | test_taint | request.readline() |
|
||||
| taint_test.py:101 | fail | test_taint | request.readlines() |
|
||||
| taint_test.py:102 | fail | test_taint | request.readlines()[0] |
|
||||
| taint_test.py:103 | fail | test_taint | ListComp |
|
||||
| taint_test.py:109 | ok | test_taint | args |
|
||||
| taint_test.py:110 | ok | test_taint | args[0] |
|
||||
| taint_test.py:111 | ok | test_taint | kwargs |
|
||||
| taint_test.py:112 | ok | test_taint | kwargs["key"] |
|
||||
| taint_test.py:116 | ok | test_taint | request.current_app |
|
||||
| taint_test.py:121 | ok | test_taint | request.get_host() |
|
||||
| taint_test.py:122 | ok | test_taint | request.get_port() |
|
||||
| taint_test.py:129 | fail | test_taint | request.build_absolute_uri() |
|
||||
| taint_test.py:130 | fail | test_taint | request.build_absolute_uri(..) |
|
||||
| taint_test.py:133 | ok | test_taint | request.build_absolute_uri(..) |
|
||||
| taint_test.py:131 | fail | test_taint | request.build_absolute_uri(..) |
|
||||
| taint_test.py:134 | ok | test_taint | request.build_absolute_uri(..) |
|
||||
| taint_test.py:142 | ok | test_taint | request.get_signed_cookie(..) |
|
||||
| taint_test.py:135 | ok | test_taint | request.build_absolute_uri(..) |
|
||||
| taint_test.py:143 | ok | test_taint | request.get_signed_cookie(..) |
|
||||
| taint_test.py:144 | ok | test_taint | request.get_signed_cookie(..) |
|
||||
| taint_test.py:148 | fail | test_taint | request.get_signed_cookie(..) |
|
||||
| taint_test.py:145 | ok | test_taint | request.get_signed_cookie(..) |
|
||||
| taint_test.py:149 | fail | test_taint | request.get_signed_cookie(..) |
|
||||
| taint_test.py:150 | fail | test_taint | request.get_signed_cookie(..) |
|
||||
| taint_test.py:157 | ok | some_method | self.request |
|
||||
| taint_test.py:158 | ok | some_method | self.request.GET["key"] |
|
||||
| taint_test.py:160 | ok | some_method | self.args |
|
||||
| taint_test.py:161 | ok | some_method | self.args[0] |
|
||||
| taint_test.py:163 | ok | some_method | self.kwargs |
|
||||
| taint_test.py:164 | ok | some_method | self.kwargs["key"] |
|
||||
|
||||
@@ -3,6 +3,7 @@ from django.urls import path, re_path
|
||||
from django.http import HttpResponse, HttpResponseRedirect, JsonResponse, HttpResponseNotFound
|
||||
from django.views import View
|
||||
import django.views.generic.base
|
||||
from django.views.decorators.http import require_GET
|
||||
|
||||
|
||||
def url_match_xss(request, foo, bar, no_taint=None): # $requestHandler routedParameter=foo routedParameter=bar
|
||||
@@ -105,6 +106,10 @@ urlpatterns = [
|
||||
path("not_valid/<not_valid!>", not_valid_identifier), # $routeSetup="not_valid/<not_valid!>"
|
||||
]
|
||||
|
||||
################################################################################
|
||||
# Deprecated django.conf.urls.url
|
||||
################################################################################
|
||||
|
||||
# This version 1.x way of defining urls is deprecated in Django 3.1, but still works
|
||||
from django.conf.urls import url
|
||||
|
||||
@@ -116,9 +121,32 @@ urlpatterns = [
|
||||
]
|
||||
|
||||
|
||||
################################################################################
|
||||
# Special stuff
|
||||
################################################################################
|
||||
|
||||
class PossiblyNotRouted(View):
|
||||
# Even if our analysis can't find a route-setup for this class, we should still
|
||||
# consider it to be a handle incoming HTTP requests
|
||||
|
||||
def get(self, request, possibly_not_routed=42): # $ requestHandler routedParameter=possibly_not_routed
|
||||
return HttpResponse('PossiblyNotRouted get: {}'.format(possibly_not_routed)) # $HttpResponse
|
||||
|
||||
|
||||
@require_GET
|
||||
def with_decorator(request, foo): # $ requestHandler routedParameter=foo
|
||||
pass
|
||||
|
||||
urlpatterns = [
|
||||
path("with_decorator/<foo>", with_decorator), # $ routeSetup="with_decorator/<foo>"
|
||||
]
|
||||
|
||||
class UnknownViewSubclass(UnknownViewSuperclass):
|
||||
# Although we don't know for certain that this class is a django view class, the fact that it's
|
||||
# used with `as_view()` in the routing setup should be enough that we treat it as such.
|
||||
def get(self, request): # $ requestHandler
|
||||
pass
|
||||
|
||||
urlpatterns = [
|
||||
path("UnknownViewSubclass/", UnknownViewSubclass.as_view()), # $ routeSetup="UnknownViewSubclass/"
|
||||
]
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
"""testing views for Django 2.x and 3.x"""
|
||||
from django.urls import path
|
||||
from django.http import HttpRequest
|
||||
from django.views import View
|
||||
|
||||
|
||||
def test_taint(request: HttpRequest, foo, bar, baz=None): # $requestHandler routedParameter=foo routedParameter=bar
|
||||
@@ -150,7 +151,22 @@ def test_taint(request: HttpRequest, foo, bar, baz=None): # $requestHandler rou
|
||||
)
|
||||
|
||||
|
||||
class ClassView(View):
|
||||
def some_method(self):
|
||||
ensure_tainted(
|
||||
self.request,
|
||||
self.request.GET["key"],
|
||||
|
||||
self.args,
|
||||
self.args[0],
|
||||
|
||||
self.kwargs,
|
||||
self.kwargs["key"],
|
||||
)
|
||||
|
||||
|
||||
# fake setup, you can't actually run this
|
||||
urlpatterns = [
|
||||
path("test-taint/<foo>/<bar>", test_taint), # $routeSetup="test-taint/<foo>/<bar>"
|
||||
path("test-taint/<foo>/<bar>", test_taint), # $ routeSetup="test-taint/<foo>/<bar>"
|
||||
path("ClassView/", ClassView.as_view()), # $ routeSetup="ClassView/"
|
||||
]
|
||||
|
||||
@@ -30,4 +30,5 @@ class MyCustomViewBaseClass(View):
|
||||
|
||||
class MyViewHandlerWithCustomInheritance(MyCustomViewBaseClass):
|
||||
def get(self, request: HttpRequest): # $ requestHandler
|
||||
print(self.request.GET)
|
||||
return HttpResponse("MyViewHandlerWithCustomInheritance: GET") # $ HttpResponse
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
import flask
|
||||
|
||||
bp3 = flask.Blueprint("bp3", __name__)
|
||||
|
||||
@bp3.route("/bp3/example") # $ routeSetup="/bp3/example"
|
||||
def bp3_example(): # $ requestHandler
|
||||
return "bp 3 example" # $ HttpResponse
|
||||
@@ -93,5 +93,32 @@ class WithoutKnownRoute2(MethodView):
|
||||
pass
|
||||
|
||||
|
||||
# Blueprints
|
||||
#
|
||||
# see https://flask.palletsprojects.com/en/1.1.x/blueprints/
|
||||
|
||||
bp1 = flask.Blueprint("bp1", __name__)
|
||||
|
||||
@bp1.route("/bp1/example/<foo>") # $ routeSetup="/bp1/example/<foo>"
|
||||
def bp1_example(foo): # $ requestHandler routedParameter=foo
|
||||
return "bp 1 example foo={}".format(foo) # $ HttpResponse
|
||||
|
||||
app.register_blueprint(bp1) # by default, URLs of blueprints are not prefixed
|
||||
|
||||
|
||||
bp2 = flask.Blueprint("bp2", __name__)
|
||||
|
||||
@bp2.route("/example") # $ routeSetup="/example"
|
||||
def bp2_example(): # $ requestHandler
|
||||
return "bp 2 example" # $ HttpResponse
|
||||
|
||||
app.register_blueprint(bp2, url_prefix="/bp2") # but it is possible to add a URL prefix
|
||||
|
||||
|
||||
from external_blueprint import bp3
|
||||
app.register_blueprint(bp3)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
print(app.url_map)
|
||||
app.run(debug=True)
|
||||
|
||||
@@ -2,5 +2,15 @@ import yaml
|
||||
from yaml import SafeLoader
|
||||
|
||||
yaml.load(payload) # $decodeInput=payload decodeOutput=Attribute() decodeFormat=YAML decodeMayExecuteInput
|
||||
yaml.load(payload, SafeLoader) # $ decodeInput=payload decodeOutput=Attribute() decodeFormat=YAML
|
||||
yaml.load(payload, Loader=SafeLoader) # $decodeInput=payload decodeOutput=Attribute() decodeFormat=YAML
|
||||
yaml.load(payload, Loader=yaml.BaseLoader) # $decodeInput=payload decodeOutput=Attribute() decodeFormat=YAML
|
||||
|
||||
yaml.safe_load(payload) # $ decodeInput=payload decodeOutput=Attribute() decodeFormat=YAML
|
||||
yaml.unsafe_load(payload) # $ decodeInput=payload decodeOutput=Attribute() decodeFormat=YAML decodeMayExecuteInput
|
||||
yaml.full_load(payload) # $ decodeInput=payload decodeOutput=Attribute() decodeFormat=YAML decodeMayExecuteInput
|
||||
|
||||
yaml.load_all(payload) # $ decodeInput=payload decodeOutput=Attribute() decodeFormat=YAML decodeMayExecuteInput
|
||||
yaml.safe_load_all(payload) # $ decodeInput=payload decodeOutput=Attribute() decodeFormat=YAML
|
||||
yaml.unsafe_load_all(payload) # $ decodeInput=payload decodeOutput=Attribute() decodeFormat=YAML decodeMayExecuteInput
|
||||
yaml.full_load_all(payload) # $ decodeInput=payload decodeOutput=Attribute() decodeFormat=YAML decodeMayExecuteInput
|
||||
|
||||
@@ -6,3 +6,6 @@
|
||||
| test.py:45:1:45:35 | format() | Surplus named argument for string format. An argument named 'z' is provided, but it is not required by $@. | test.py:39:14:39:18 | Str | any format used. |
|
||||
| test.py:46:1:46:34 | Attribute() | Surplus named argument for string format. An argument named 'z' is provided, but it is not required by $@. | test.py:37:14:37:18 | Str | any format used. |
|
||||
| test.py:46:1:46:34 | Attribute() | Surplus named argument for string format. An argument named 'z' is provided, but it is not required by $@. | test.py:39:14:39:18 | Str | any format used. |
|
||||
| unknown_format_string.py:9:12:9:30 | Attribute() | Surplus named argument for string format. An argument named 'b' is provided, but it is not required by $@. | unknown_format_string.py:8:15:8:19 | Str | format "{a}" |
|
||||
| unknown_format_string.py:17:12:17:30 | Attribute() | Surplus named argument for string format. An argument named 'b' is provided, but it is not required by $@. | unknown_format_string.py:16:15:16:19 | Str | format "{a}" |
|
||||
| unknown_format_string.py:25:12:25:30 | Attribute() | Surplus named argument for string format. An argument named 'b' is provided, but it is not required by $@. | unknown_format_string.py:24:15:24:19 | Str | format "{a}" |
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
# FP Reported in https://github.com/github/codeql/issues/2650
|
||||
|
||||
def possibly_unknown_format_string1(x):
|
||||
user_specified = unknown_function()
|
||||
if user_specified:
|
||||
fmt = user_specified
|
||||
else:
|
||||
fmt = "{a}"
|
||||
return fmt.format(a=1,b=2)
|
||||
|
||||
def possibly_unknown_format_string2(x):
|
||||
user_specified = input()
|
||||
if user_specified:
|
||||
fmt = user_specified
|
||||
else:
|
||||
fmt = "{a}"
|
||||
return fmt.format(a=1,b=2)
|
||||
|
||||
|
||||
def possibly_unknown_format_string3(x):
|
||||
if unknown_function():
|
||||
fmt = input()
|
||||
else:
|
||||
fmt = "{a}"
|
||||
return fmt.format(a=1,b=2)
|
||||
@@ -1,7 +1,7 @@
|
||||
edges
|
||||
| test.py:13:16:13:27 | ControlFlowNode for Attribute | test.py:15:36:15:39 | ControlFlowNode for data |
|
||||
| test.py:13:16:13:22 | ControlFlowNode for request | test.py:15:36:15:39 | ControlFlowNode for data |
|
||||
nodes
|
||||
| test.py:13:16:13:27 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| test.py:13:16:13:22 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| test.py:15:36:15:39 | ControlFlowNode for data | semmle.label | ControlFlowNode for data |
|
||||
#select
|
||||
| test.py:15:36:15:39 | ControlFlowNode for data | test.py:13:16:13:27 | ControlFlowNode for Attribute | test.py:15:36:15:39 | ControlFlowNode for data | Call to hmac.new [param 1] with untrusted data from $@. | test.py:13:16:13:27 | ControlFlowNode for Attribute | ControlFlowNode for Attribute |
|
||||
| test.py:15:36:15:39 | ControlFlowNode for data | test.py:13:16:13:22 | ControlFlowNode for request | test.py:15:36:15:39 | ControlFlowNode for data | Call to hmac.new [param 1] with untrusted data from $@. | test.py:13:16:13:22 | ControlFlowNode for request | ControlFlowNode for request |
|
||||
|
||||
@@ -1,25 +1,25 @@
|
||||
edges
|
||||
| path_injection.py:12:16:12:27 | ControlFlowNode for Attribute | path_injection.py:13:14:13:47 | ControlFlowNode for Attribute() |
|
||||
| path_injection.py:19:16:19:27 | ControlFlowNode for Attribute | path_injection.py:20:13:20:64 | ControlFlowNode for Attribute() |
|
||||
| path_injection.py:12:16:12:22 | ControlFlowNode for request | path_injection.py:13:14:13:47 | ControlFlowNode for Attribute() |
|
||||
| path_injection.py:19:16:19:22 | ControlFlowNode for request | path_injection.py:20:13:20:64 | ControlFlowNode for Attribute() |
|
||||
| path_injection.py:20:13:20:64 | ControlFlowNode for Attribute() | path_injection.py:21:14:21:18 | ControlFlowNode for npath |
|
||||
| path_injection.py:27:16:27:27 | ControlFlowNode for Attribute | path_injection.py:28:13:28:64 | ControlFlowNode for Attribute() |
|
||||
| path_injection.py:27:16:27:22 | ControlFlowNode for request | path_injection.py:28:13:28:64 | ControlFlowNode for Attribute() |
|
||||
| path_injection.py:28:13:28:64 | ControlFlowNode for Attribute() | path_injection.py:31:14:31:18 | ControlFlowNode for npath |
|
||||
| path_injection.py:37:16:37:27 | ControlFlowNode for Attribute | path_injection.py:38:13:38:64 | ControlFlowNode for Attribute() |
|
||||
| path_injection.py:46:16:46:27 | ControlFlowNode for Attribute | path_injection.py:47:13:47:64 | ControlFlowNode for Attribute() |
|
||||
| path_injection.py:37:16:37:22 | ControlFlowNode for request | path_injection.py:38:13:38:64 | ControlFlowNode for Attribute() |
|
||||
| path_injection.py:46:16:46:22 | ControlFlowNode for request | path_injection.py:47:13:47:64 | ControlFlowNode for Attribute() |
|
||||
| path_injection.py:47:13:47:64 | ControlFlowNode for Attribute() | path_injection.py:48:14:48:18 | ControlFlowNode for npath |
|
||||
| path_injection.py:54:16:54:27 | ControlFlowNode for Attribute | path_injection.py:55:13:55:64 | ControlFlowNode for Attribute() |
|
||||
| path_injection.py:63:16:63:27 | ControlFlowNode for Attribute | path_injection.py:64:13:64:63 | ControlFlowNode for Attribute() |
|
||||
| path_injection.py:54:16:54:22 | ControlFlowNode for request | path_injection.py:55:13:55:64 | ControlFlowNode for Attribute() |
|
||||
| path_injection.py:63:16:63:22 | ControlFlowNode for request | path_injection.py:64:13:64:63 | ControlFlowNode for Attribute() |
|
||||
| path_injection.py:64:13:64:63 | ControlFlowNode for Attribute() | path_injection.py:65:14:65:18 | ControlFlowNode for npath |
|
||||
| path_injection.py:71:16:71:27 | ControlFlowNode for Attribute | path_injection.py:72:13:72:63 | ControlFlowNode for Attribute() |
|
||||
| path_injection.py:71:16:71:22 | ControlFlowNode for request | path_injection.py:72:13:72:63 | ControlFlowNode for Attribute() |
|
||||
| path_injection.py:78:20:78:25 | ControlFlowNode for foo_id | path_injection.py:81:14:81:17 | ControlFlowNode for path |
|
||||
| path_injection.py:85:20:85:22 | ControlFlowNode for foo | path_injection.py:89:14:89:17 | ControlFlowNode for path |
|
||||
| path_injection.py:94:16:94:27 | ControlFlowNode for Attribute | path_injection.py:100:14:100:17 | ControlFlowNode for path |
|
||||
| path_injection.py:105:16:105:27 | ControlFlowNode for Attribute | path_injection.py:111:14:111:17 | ControlFlowNode for path |
|
||||
| path_injection.py:116:16:116:27 | ControlFlowNode for Attribute | path_injection.py:119:14:119:22 | ControlFlowNode for sanitized |
|
||||
| path_injection.py:125:16:125:27 | ControlFlowNode for Attribute | path_injection.py:127:30:127:51 | ControlFlowNode for Attribute() |
|
||||
| path_injection.py:125:16:125:27 | ControlFlowNode for Attribute | path_injection.py:129:14:129:17 | ControlFlowNode for path |
|
||||
| test.py:9:12:9:23 | ControlFlowNode for Attribute | test.py:9:12:9:39 | ControlFlowNode for Attribute() |
|
||||
| test.py:9:12:9:23 | ControlFlowNode for Attribute | test.py:9:12:9:39 | ControlFlowNode for Attribute() |
|
||||
| path_injection.py:94:16:94:22 | ControlFlowNode for request | path_injection.py:100:14:100:17 | ControlFlowNode for path |
|
||||
| path_injection.py:105:16:105:22 | ControlFlowNode for request | path_injection.py:111:14:111:17 | ControlFlowNode for path |
|
||||
| path_injection.py:116:16:116:22 | ControlFlowNode for request | path_injection.py:119:14:119:22 | ControlFlowNode for sanitized |
|
||||
| path_injection.py:125:16:125:22 | ControlFlowNode for request | path_injection.py:127:30:127:51 | ControlFlowNode for Attribute() |
|
||||
| path_injection.py:125:16:125:22 | ControlFlowNode for request | path_injection.py:129:14:129:17 | ControlFlowNode for path |
|
||||
| test.py:9:12:9:18 | ControlFlowNode for request | test.py:9:12:9:39 | ControlFlowNode for Attribute() |
|
||||
| test.py:9:12:9:18 | ControlFlowNode for request | test.py:9:12:9:39 | ControlFlowNode for Attribute() |
|
||||
| test.py:9:12:9:39 | ControlFlowNode for Attribute() | test.py:18:9:18:16 | ControlFlowNode for source() |
|
||||
| test.py:9:12:9:39 | ControlFlowNode for Attribute() | test.py:24:9:24:16 | ControlFlowNode for source() |
|
||||
| test.py:9:12:9:39 | ControlFlowNode for Attribute() | test.py:31:9:31:16 | ControlFlowNode for source() |
|
||||
@@ -38,7 +38,7 @@ edges
|
||||
| test.py:46:9:46:16 | ControlFlowNode for source() | test.py:48:23:48:23 | ControlFlowNode for x |
|
||||
| test.py:48:13:48:24 | ControlFlowNode for normalize() | test.py:49:14:49:14 | ControlFlowNode for y |
|
||||
| test.py:48:23:48:23 | ControlFlowNode for x | test.py:12:15:12:15 | ControlFlowNode for x |
|
||||
| test_chaining.py:9:12:9:23 | ControlFlowNode for Attribute | test_chaining.py:9:12:9:39 | ControlFlowNode for Attribute() |
|
||||
| test_chaining.py:9:12:9:18 | ControlFlowNode for request | test_chaining.py:9:12:9:39 | ControlFlowNode for Attribute() |
|
||||
| test_chaining.py:9:12:9:39 | ControlFlowNode for Attribute() | test_chaining.py:20:9:20:16 | ControlFlowNode for source() |
|
||||
| test_chaining.py:9:12:9:39 | ControlFlowNode for Attribute() | test_chaining.py:28:9:28:16 | ControlFlowNode for source() |
|
||||
| test_chaining.py:9:12:9:39 | ControlFlowNode for Attribute() | test_chaining.py:41:9:41:16 | ControlFlowNode for source() |
|
||||
@@ -52,42 +52,42 @@ edges
|
||||
| test_chaining.py:41:9:41:16 | ControlFlowNode for source() | test_chaining.py:42:9:42:19 | ControlFlowNode for normpath() |
|
||||
| test_chaining.py:44:13:44:23 | ControlFlowNode for normpath() | test_chaining.py:45:14:45:14 | ControlFlowNode for z |
|
||||
nodes
|
||||
| path_injection.py:12:16:12:27 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| path_injection.py:12:16:12:22 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| path_injection.py:13:14:13:47 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
|
||||
| path_injection.py:19:16:19:27 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| path_injection.py:19:16:19:22 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| path_injection.py:20:13:20:64 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
|
||||
| path_injection.py:21:14:21:18 | ControlFlowNode for npath | semmle.label | ControlFlowNode for npath |
|
||||
| path_injection.py:27:16:27:27 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| path_injection.py:27:16:27:22 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| path_injection.py:28:13:28:64 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
|
||||
| path_injection.py:31:14:31:18 | ControlFlowNode for npath | semmle.label | ControlFlowNode for npath |
|
||||
| path_injection.py:37:16:37:27 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| path_injection.py:37:16:37:22 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| path_injection.py:38:13:38:64 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
|
||||
| path_injection.py:46:16:46:27 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| path_injection.py:46:16:46:22 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| path_injection.py:47:13:47:64 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
|
||||
| path_injection.py:48:14:48:18 | ControlFlowNode for npath | semmle.label | ControlFlowNode for npath |
|
||||
| path_injection.py:54:16:54:27 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| path_injection.py:54:16:54:22 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| path_injection.py:55:13:55:64 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
|
||||
| path_injection.py:63:16:63:27 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| path_injection.py:63:16:63:22 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| path_injection.py:64:13:64:63 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
|
||||
| path_injection.py:65:14:65:18 | ControlFlowNode for npath | semmle.label | ControlFlowNode for npath |
|
||||
| path_injection.py:71:16:71:27 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| path_injection.py:71:16:71:22 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| path_injection.py:72:13:72:63 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
|
||||
| path_injection.py:78:20:78:25 | ControlFlowNode for foo_id | semmle.label | ControlFlowNode for foo_id |
|
||||
| path_injection.py:81:14:81:17 | ControlFlowNode for path | semmle.label | ControlFlowNode for path |
|
||||
| path_injection.py:85:20:85:22 | ControlFlowNode for foo | semmle.label | ControlFlowNode for foo |
|
||||
| path_injection.py:89:14:89:17 | ControlFlowNode for path | semmle.label | ControlFlowNode for path |
|
||||
| path_injection.py:94:16:94:27 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| path_injection.py:94:16:94:22 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| path_injection.py:100:14:100:17 | ControlFlowNode for path | semmle.label | ControlFlowNode for path |
|
||||
| path_injection.py:105:16:105:27 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| path_injection.py:105:16:105:22 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| path_injection.py:111:14:111:17 | ControlFlowNode for path | semmle.label | ControlFlowNode for path |
|
||||
| path_injection.py:116:16:116:27 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| path_injection.py:116:16:116:22 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| path_injection.py:119:14:119:22 | ControlFlowNode for sanitized | semmle.label | ControlFlowNode for sanitized |
|
||||
| path_injection.py:125:16:125:27 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| path_injection.py:125:16:125:27 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| path_injection.py:125:16:125:22 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| path_injection.py:125:16:125:22 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| path_injection.py:127:30:127:51 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
|
||||
| path_injection.py:129:14:129:17 | ControlFlowNode for path | semmle.label | ControlFlowNode for path |
|
||||
| test.py:9:12:9:23 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| test.py:9:12:9:23 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| test.py:9:12:9:18 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| test.py:9:12:9:18 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| test.py:9:12:9:39 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
|
||||
| test.py:9:12:9:39 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
|
||||
| test.py:12:15:12:15 | ControlFlowNode for x | semmle.label | ControlFlowNode for x |
|
||||
@@ -106,7 +106,7 @@ nodes
|
||||
| test.py:48:13:48:24 | ControlFlowNode for normalize() | semmle.label | ControlFlowNode for normalize() |
|
||||
| test.py:48:23:48:23 | ControlFlowNode for x | semmle.label | ControlFlowNode for x |
|
||||
| test.py:49:14:49:14 | ControlFlowNode for y | semmle.label | ControlFlowNode for y |
|
||||
| test_chaining.py:9:12:9:23 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| test_chaining.py:9:12:9:18 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| test_chaining.py:9:12:9:39 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
|
||||
| test_chaining.py:14:15:14:15 | ControlFlowNode for x | semmle.label | ControlFlowNode for x |
|
||||
| test_chaining.py:15:12:15:30 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
|
||||
@@ -121,19 +121,19 @@ nodes
|
||||
| test_chaining.py:44:13:44:23 | ControlFlowNode for normpath() | semmle.label | ControlFlowNode for normpath() |
|
||||
| test_chaining.py:45:14:45:14 | ControlFlowNode for z | semmle.label | ControlFlowNode for z |
|
||||
#select
|
||||
| path_injection.py:13:14:13:47 | ControlFlowNode for Attribute() | path_injection.py:12:16:12:27 | ControlFlowNode for Attribute | path_injection.py:13:14:13:47 | ControlFlowNode for Attribute() | This path depends on $@. | path_injection.py:12:16:12:27 | ControlFlowNode for Attribute | a user-provided value |
|
||||
| path_injection.py:21:14:21:18 | ControlFlowNode for npath | path_injection.py:19:16:19:27 | ControlFlowNode for Attribute | path_injection.py:21:14:21:18 | ControlFlowNode for npath | This path depends on $@. | path_injection.py:19:16:19:27 | ControlFlowNode for Attribute | a user-provided value |
|
||||
| path_injection.py:31:14:31:18 | ControlFlowNode for npath | path_injection.py:27:16:27:27 | ControlFlowNode for Attribute | path_injection.py:31:14:31:18 | ControlFlowNode for npath | This path depends on $@. | path_injection.py:27:16:27:27 | ControlFlowNode for Attribute | a user-provided value |
|
||||
| path_injection.py:48:14:48:18 | ControlFlowNode for npath | path_injection.py:46:16:46:27 | ControlFlowNode for Attribute | path_injection.py:48:14:48:18 | ControlFlowNode for npath | This path depends on $@. | path_injection.py:46:16:46:27 | ControlFlowNode for Attribute | a user-provided value |
|
||||
| path_injection.py:65:14:65:18 | ControlFlowNode for npath | path_injection.py:63:16:63:27 | ControlFlowNode for Attribute | path_injection.py:65:14:65:18 | ControlFlowNode for npath | This path depends on $@. | path_injection.py:63:16:63:27 | ControlFlowNode for Attribute | a user-provided value |
|
||||
| path_injection.py:13:14:13:47 | ControlFlowNode for Attribute() | path_injection.py:12:16:12:22 | ControlFlowNode for request | path_injection.py:13:14:13:47 | ControlFlowNode for Attribute() | This path depends on $@. | path_injection.py:12:16:12:22 | ControlFlowNode for request | a user-provided value |
|
||||
| path_injection.py:21:14:21:18 | ControlFlowNode for npath | path_injection.py:19:16:19:22 | ControlFlowNode for request | path_injection.py:21:14:21:18 | ControlFlowNode for npath | This path depends on $@. | path_injection.py:19:16:19:22 | ControlFlowNode for request | a user-provided value |
|
||||
| path_injection.py:31:14:31:18 | ControlFlowNode for npath | path_injection.py:27:16:27:22 | ControlFlowNode for request | path_injection.py:31:14:31:18 | ControlFlowNode for npath | This path depends on $@. | path_injection.py:27:16:27:22 | ControlFlowNode for request | a user-provided value |
|
||||
| path_injection.py:48:14:48:18 | ControlFlowNode for npath | path_injection.py:46:16:46:22 | ControlFlowNode for request | path_injection.py:48:14:48:18 | ControlFlowNode for npath | This path depends on $@. | path_injection.py:46:16:46:22 | ControlFlowNode for request | a user-provided value |
|
||||
| path_injection.py:65:14:65:18 | ControlFlowNode for npath | path_injection.py:63:16:63:22 | ControlFlowNode for request | path_injection.py:65:14:65:18 | ControlFlowNode for npath | This path depends on $@. | path_injection.py:63:16:63:22 | ControlFlowNode for request | a user-provided value |
|
||||
| path_injection.py:81:14:81:17 | ControlFlowNode for path | path_injection.py:78:20:78:25 | ControlFlowNode for foo_id | path_injection.py:81:14:81:17 | ControlFlowNode for path | This path depends on $@. | path_injection.py:78:20:78:25 | ControlFlowNode for foo_id | a user-provided value |
|
||||
| path_injection.py:89:14:89:17 | ControlFlowNode for path | path_injection.py:85:20:85:22 | ControlFlowNode for foo | path_injection.py:89:14:89:17 | ControlFlowNode for path | This path depends on $@. | path_injection.py:85:20:85:22 | ControlFlowNode for foo | a user-provided value |
|
||||
| path_injection.py:100:14:100:17 | ControlFlowNode for path | path_injection.py:94:16:94:27 | ControlFlowNode for Attribute | path_injection.py:100:14:100:17 | ControlFlowNode for path | This path depends on $@. | path_injection.py:94:16:94:27 | ControlFlowNode for Attribute | a user-provided value |
|
||||
| path_injection.py:111:14:111:17 | ControlFlowNode for path | path_injection.py:105:16:105:27 | ControlFlowNode for Attribute | path_injection.py:111:14:111:17 | ControlFlowNode for path | This path depends on $@. | path_injection.py:105:16:105:27 | ControlFlowNode for Attribute | a user-provided value |
|
||||
| path_injection.py:119:14:119:22 | ControlFlowNode for sanitized | path_injection.py:116:16:116:27 | ControlFlowNode for Attribute | path_injection.py:119:14:119:22 | ControlFlowNode for sanitized | This path depends on $@. | path_injection.py:116:16:116:27 | ControlFlowNode for Attribute | a user-provided value |
|
||||
| path_injection.py:129:14:129:17 | ControlFlowNode for path | path_injection.py:125:16:125:27 | ControlFlowNode for Attribute | path_injection.py:129:14:129:17 | ControlFlowNode for path | This path depends on $@. | path_injection.py:125:16:125:27 | ControlFlowNode for Attribute | a user-provided value |
|
||||
| test.py:19:10:19:10 | ControlFlowNode for x | test.py:9:12:9:23 | ControlFlowNode for Attribute | test.py:19:10:19:10 | ControlFlowNode for x | This path depends on $@. | test.py:9:12:9:23 | ControlFlowNode for Attribute | a user-provided value |
|
||||
| test.py:26:10:26:10 | ControlFlowNode for y | test.py:9:12:9:23 | ControlFlowNode for Attribute | test.py:26:10:26:10 | ControlFlowNode for y | This path depends on $@. | test.py:9:12:9:23 | ControlFlowNode for Attribute | a user-provided value |
|
||||
| test.py:33:14:33:14 | ControlFlowNode for x | test.py:9:12:9:23 | ControlFlowNode for Attribute | test.py:33:14:33:14 | ControlFlowNode for x | This path depends on $@. | test.py:9:12:9:23 | ControlFlowNode for Attribute | a user-provided value |
|
||||
| test.py:49:14:49:14 | ControlFlowNode for y | test.py:9:12:9:23 | ControlFlowNode for Attribute | test.py:49:14:49:14 | ControlFlowNode for y | This path depends on $@. | test.py:9:12:9:23 | ControlFlowNode for Attribute | a user-provided value |
|
||||
| test_chaining.py:32:14:32:14 | ControlFlowNode for z | test_chaining.py:9:12:9:23 | ControlFlowNode for Attribute | test_chaining.py:32:14:32:14 | ControlFlowNode for z | This path depends on $@. | test_chaining.py:9:12:9:23 | ControlFlowNode for Attribute | a user-provided value |
|
||||
| path_injection.py:100:14:100:17 | ControlFlowNode for path | path_injection.py:94:16:94:22 | ControlFlowNode for request | path_injection.py:100:14:100:17 | ControlFlowNode for path | This path depends on $@. | path_injection.py:94:16:94:22 | ControlFlowNode for request | a user-provided value |
|
||||
| path_injection.py:111:14:111:17 | ControlFlowNode for path | path_injection.py:105:16:105:22 | ControlFlowNode for request | path_injection.py:111:14:111:17 | ControlFlowNode for path | This path depends on $@. | path_injection.py:105:16:105:22 | ControlFlowNode for request | a user-provided value |
|
||||
| path_injection.py:119:14:119:22 | ControlFlowNode for sanitized | path_injection.py:116:16:116:22 | ControlFlowNode for request | path_injection.py:119:14:119:22 | ControlFlowNode for sanitized | This path depends on $@. | path_injection.py:116:16:116:22 | ControlFlowNode for request | a user-provided value |
|
||||
| path_injection.py:129:14:129:17 | ControlFlowNode for path | path_injection.py:125:16:125:22 | ControlFlowNode for request | path_injection.py:129:14:129:17 | ControlFlowNode for path | This path depends on $@. | path_injection.py:125:16:125:22 | ControlFlowNode for request | a user-provided value |
|
||||
| test.py:19:10:19:10 | ControlFlowNode for x | test.py:9:12:9:18 | ControlFlowNode for request | test.py:19:10:19:10 | ControlFlowNode for x | This path depends on $@. | test.py:9:12:9:18 | ControlFlowNode for request | a user-provided value |
|
||||
| test.py:26:10:26:10 | ControlFlowNode for y | test.py:9:12:9:18 | ControlFlowNode for request | test.py:26:10:26:10 | ControlFlowNode for y | This path depends on $@. | test.py:9:12:9:18 | ControlFlowNode for request | a user-provided value |
|
||||
| test.py:33:14:33:14 | ControlFlowNode for x | test.py:9:12:9:18 | ControlFlowNode for request | test.py:33:14:33:14 | ControlFlowNode for x | This path depends on $@. | test.py:9:12:9:18 | ControlFlowNode for request | a user-provided value |
|
||||
| test.py:49:14:49:14 | ControlFlowNode for y | test.py:9:12:9:18 | ControlFlowNode for request | test.py:49:14:49:14 | ControlFlowNode for y | This path depends on $@. | test.py:9:12:9:18 | ControlFlowNode for request | a user-provided value |
|
||||
| test_chaining.py:32:14:32:14 | ControlFlowNode for z | test_chaining.py:9:12:9:18 | ControlFlowNode for request | test_chaining.py:32:14:32:14 | ControlFlowNode for z | This path depends on $@. | test_chaining.py:9:12:9:18 | ControlFlowNode for request | a user-provided value |
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
edges
|
||||
| command_injection.py:18:13:18:24 | ControlFlowNode for Attribute | command_injection.py:19:15:19:27 | ControlFlowNode for BinaryExpr |
|
||||
| command_injection.py:18:13:18:24 | ControlFlowNode for Attribute | command_injection.py:20:15:20:27 | ControlFlowNode for BinaryExpr |
|
||||
| command_injection.py:18:13:18:24 | ControlFlowNode for Attribute | command_injection.py:21:15:21:27 | ControlFlowNode for BinaryExpr |
|
||||
| command_injection.py:18:13:18:24 | ControlFlowNode for Attribute | command_injection.py:23:20:23:32 | ControlFlowNode for BinaryExpr |
|
||||
| command_injection.py:18:13:18:24 | ControlFlowNode for Attribute | command_injection.py:25:19:25:31 | ControlFlowNode for BinaryExpr |
|
||||
| command_injection.py:18:13:18:24 | ControlFlowNode for Attribute | command_injection.py:26:19:26:31 | ControlFlowNode for BinaryExpr |
|
||||
| command_injection.py:18:13:18:24 | ControlFlowNode for Attribute | command_injection.py:27:19:27:31 | ControlFlowNode for BinaryExpr |
|
||||
| command_injection.py:18:13:18:24 | ControlFlowNode for Attribute | command_injection.py:28:19:28:31 | ControlFlowNode for BinaryExpr |
|
||||
| command_injection.py:18:13:18:24 | ControlFlowNode for Attribute | command_injection.py:29:19:29:31 | ControlFlowNode for BinaryExpr |
|
||||
| command_injection.py:18:13:18:19 | ControlFlowNode for request | command_injection.py:19:15:19:27 | ControlFlowNode for BinaryExpr |
|
||||
| command_injection.py:18:13:18:19 | ControlFlowNode for request | command_injection.py:20:15:20:27 | ControlFlowNode for BinaryExpr |
|
||||
| command_injection.py:18:13:18:19 | ControlFlowNode for request | command_injection.py:21:15:21:27 | ControlFlowNode for BinaryExpr |
|
||||
| command_injection.py:18:13:18:19 | ControlFlowNode for request | command_injection.py:23:20:23:32 | ControlFlowNode for BinaryExpr |
|
||||
| command_injection.py:18:13:18:19 | ControlFlowNode for request | command_injection.py:25:19:25:31 | ControlFlowNode for BinaryExpr |
|
||||
| command_injection.py:18:13:18:19 | ControlFlowNode for request | command_injection.py:26:19:26:31 | ControlFlowNode for BinaryExpr |
|
||||
| command_injection.py:18:13:18:19 | ControlFlowNode for request | command_injection.py:27:19:27:31 | ControlFlowNode for BinaryExpr |
|
||||
| command_injection.py:18:13:18:19 | ControlFlowNode for request | command_injection.py:28:19:28:31 | ControlFlowNode for BinaryExpr |
|
||||
| command_injection.py:18:13:18:19 | ControlFlowNode for request | command_injection.py:29:19:29:31 | ControlFlowNode for BinaryExpr |
|
||||
nodes
|
||||
| command_injection.py:18:13:18:24 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| command_injection.py:18:13:18:19 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| command_injection.py:19:15:19:27 | ControlFlowNode for BinaryExpr | semmle.label | ControlFlowNode for BinaryExpr |
|
||||
| command_injection.py:20:15:20:27 | ControlFlowNode for BinaryExpr | semmle.label | ControlFlowNode for BinaryExpr |
|
||||
| command_injection.py:21:15:21:27 | ControlFlowNode for BinaryExpr | semmle.label | ControlFlowNode for BinaryExpr |
|
||||
@@ -20,12 +20,12 @@ nodes
|
||||
| command_injection.py:28:19:28:31 | ControlFlowNode for BinaryExpr | semmle.label | ControlFlowNode for BinaryExpr |
|
||||
| command_injection.py:29:19:29:31 | ControlFlowNode for BinaryExpr | semmle.label | ControlFlowNode for BinaryExpr |
|
||||
#select
|
||||
| command_injection.py:19:15:19:27 | ControlFlowNode for BinaryExpr | command_injection.py:18:13:18:24 | ControlFlowNode for Attribute | command_injection.py:19:15:19:27 | ControlFlowNode for BinaryExpr | This command depends on $@. | command_injection.py:18:13:18:24 | ControlFlowNode for Attribute | a user-provided value |
|
||||
| command_injection.py:20:15:20:27 | ControlFlowNode for BinaryExpr | command_injection.py:18:13:18:24 | ControlFlowNode for Attribute | command_injection.py:20:15:20:27 | ControlFlowNode for BinaryExpr | This command depends on $@. | command_injection.py:18:13:18:24 | ControlFlowNode for Attribute | a user-provided value |
|
||||
| command_injection.py:21:15:21:27 | ControlFlowNode for BinaryExpr | command_injection.py:18:13:18:24 | ControlFlowNode for Attribute | command_injection.py:21:15:21:27 | ControlFlowNode for BinaryExpr | This command depends on $@. | command_injection.py:18:13:18:24 | ControlFlowNode for Attribute | a user-provided value |
|
||||
| command_injection.py:23:20:23:32 | ControlFlowNode for BinaryExpr | command_injection.py:18:13:18:24 | ControlFlowNode for Attribute | command_injection.py:23:20:23:32 | ControlFlowNode for BinaryExpr | This command depends on $@. | command_injection.py:18:13:18:24 | ControlFlowNode for Attribute | a user-provided value |
|
||||
| command_injection.py:25:19:25:31 | ControlFlowNode for BinaryExpr | command_injection.py:18:13:18:24 | ControlFlowNode for Attribute | command_injection.py:25:19:25:31 | ControlFlowNode for BinaryExpr | This command depends on $@. | command_injection.py:18:13:18:24 | ControlFlowNode for Attribute | a user-provided value |
|
||||
| command_injection.py:26:19:26:31 | ControlFlowNode for BinaryExpr | command_injection.py:18:13:18:24 | ControlFlowNode for Attribute | command_injection.py:26:19:26:31 | ControlFlowNode for BinaryExpr | This command depends on $@. | command_injection.py:18:13:18:24 | ControlFlowNode for Attribute | a user-provided value |
|
||||
| command_injection.py:27:19:27:31 | ControlFlowNode for BinaryExpr | command_injection.py:18:13:18:24 | ControlFlowNode for Attribute | command_injection.py:27:19:27:31 | ControlFlowNode for BinaryExpr | This command depends on $@. | command_injection.py:18:13:18:24 | ControlFlowNode for Attribute | a user-provided value |
|
||||
| command_injection.py:28:19:28:31 | ControlFlowNode for BinaryExpr | command_injection.py:18:13:18:24 | ControlFlowNode for Attribute | command_injection.py:28:19:28:31 | ControlFlowNode for BinaryExpr | This command depends on $@. | command_injection.py:18:13:18:24 | ControlFlowNode for Attribute | a user-provided value |
|
||||
| command_injection.py:29:19:29:31 | ControlFlowNode for BinaryExpr | command_injection.py:18:13:18:24 | ControlFlowNode for Attribute | command_injection.py:29:19:29:31 | ControlFlowNode for BinaryExpr | This command depends on $@. | command_injection.py:18:13:18:24 | ControlFlowNode for Attribute | a user-provided value |
|
||||
| command_injection.py:19:15:19:27 | ControlFlowNode for BinaryExpr | command_injection.py:18:13:18:19 | ControlFlowNode for request | command_injection.py:19:15:19:27 | ControlFlowNode for BinaryExpr | This command depends on $@. | command_injection.py:18:13:18:19 | ControlFlowNode for request | a user-provided value |
|
||||
| command_injection.py:20:15:20:27 | ControlFlowNode for BinaryExpr | command_injection.py:18:13:18:19 | ControlFlowNode for request | command_injection.py:20:15:20:27 | ControlFlowNode for BinaryExpr | This command depends on $@. | command_injection.py:18:13:18:19 | ControlFlowNode for request | a user-provided value |
|
||||
| command_injection.py:21:15:21:27 | ControlFlowNode for BinaryExpr | command_injection.py:18:13:18:19 | ControlFlowNode for request | command_injection.py:21:15:21:27 | ControlFlowNode for BinaryExpr | This command depends on $@. | command_injection.py:18:13:18:19 | ControlFlowNode for request | a user-provided value |
|
||||
| command_injection.py:23:20:23:32 | ControlFlowNode for BinaryExpr | command_injection.py:18:13:18:19 | ControlFlowNode for request | command_injection.py:23:20:23:32 | ControlFlowNode for BinaryExpr | This command depends on $@. | command_injection.py:18:13:18:19 | ControlFlowNode for request | a user-provided value |
|
||||
| command_injection.py:25:19:25:31 | ControlFlowNode for BinaryExpr | command_injection.py:18:13:18:19 | ControlFlowNode for request | command_injection.py:25:19:25:31 | ControlFlowNode for BinaryExpr | This command depends on $@. | command_injection.py:18:13:18:19 | ControlFlowNode for request | a user-provided value |
|
||||
| command_injection.py:26:19:26:31 | ControlFlowNode for BinaryExpr | command_injection.py:18:13:18:19 | ControlFlowNode for request | command_injection.py:26:19:26:31 | ControlFlowNode for BinaryExpr | This command depends on $@. | command_injection.py:18:13:18:19 | ControlFlowNode for request | a user-provided value |
|
||||
| command_injection.py:27:19:27:31 | ControlFlowNode for BinaryExpr | command_injection.py:18:13:18:19 | ControlFlowNode for request | command_injection.py:27:19:27:31 | ControlFlowNode for BinaryExpr | This command depends on $@. | command_injection.py:18:13:18:19 | ControlFlowNode for request | a user-provided value |
|
||||
| command_injection.py:28:19:28:31 | ControlFlowNode for BinaryExpr | command_injection.py:18:13:18:19 | ControlFlowNode for request | command_injection.py:28:19:28:31 | ControlFlowNode for BinaryExpr | This command depends on $@. | command_injection.py:18:13:18:19 | ControlFlowNode for request | a user-provided value |
|
||||
| command_injection.py:29:19:29:31 | ControlFlowNode for BinaryExpr | command_injection.py:18:13:18:19 | ControlFlowNode for request | command_injection.py:29:19:29:31 | ControlFlowNode for BinaryExpr | This command depends on $@. | command_injection.py:18:13:18:19 | ControlFlowNode for request | a user-provided value |
|
||||
|
||||
@@ -1,50 +1,50 @@
|
||||
edges
|
||||
| command_injection.py:11:13:11:24 | ControlFlowNode for Attribute | command_injection.py:13:15:13:27 | ControlFlowNode for BinaryExpr |
|
||||
| command_injection.py:18:13:18:24 | ControlFlowNode for Attribute | command_injection.py:20:22:20:34 | ControlFlowNode for BinaryExpr |
|
||||
| command_injection.py:25:11:25:22 | ControlFlowNode for Attribute | command_injection.py:26:23:26:25 | ControlFlowNode for cmd |
|
||||
| command_injection.py:31:13:31:24 | ControlFlowNode for Attribute | command_injection.py:33:14:33:26 | ControlFlowNode for BinaryExpr |
|
||||
| command_injection.py:38:15:38:26 | ControlFlowNode for Attribute | command_injection.py:41:15:41:21 | ControlFlowNode for command |
|
||||
| command_injection.py:38:15:38:26 | ControlFlowNode for Attribute | command_injection.py:42:15:42:21 | ControlFlowNode for command |
|
||||
| command_injection.py:54:15:54:26 | ControlFlowNode for Attribute | command_injection.py:55:15:55:21 | ControlFlowNode for command |
|
||||
| command_injection.py:54:15:54:26 | ControlFlowNode for Attribute | command_injection.py:56:14:56:20 | ControlFlowNode for command |
|
||||
| command_injection.py:54:15:54:26 | ControlFlowNode for Attribute | command_injection.py:57:21:57:27 | ControlFlowNode for command |
|
||||
| command_injection.py:54:15:54:26 | ControlFlowNode for Attribute | command_injection.py:58:27:58:33 | ControlFlowNode for command |
|
||||
| command_injection.py:54:15:54:26 | ControlFlowNode for Attribute | command_injection.py:59:20:59:26 | ControlFlowNode for command |
|
||||
| command_injection.py:71:12:71:23 | ControlFlowNode for Attribute | command_injection.py:73:19:73:30 | ControlFlowNode for BinaryExpr |
|
||||
| command_injection.py:78:12:78:23 | ControlFlowNode for Attribute | command_injection.py:80:19:80:30 | ControlFlowNode for BinaryExpr |
|
||||
| command_injection.py:11:13:11:19 | ControlFlowNode for request | command_injection.py:13:15:13:27 | ControlFlowNode for BinaryExpr |
|
||||
| command_injection.py:18:13:18:19 | ControlFlowNode for request | command_injection.py:20:22:20:34 | ControlFlowNode for BinaryExpr |
|
||||
| command_injection.py:25:11:25:17 | ControlFlowNode for request | command_injection.py:26:23:26:25 | ControlFlowNode for cmd |
|
||||
| command_injection.py:31:13:31:19 | ControlFlowNode for request | command_injection.py:33:14:33:26 | ControlFlowNode for BinaryExpr |
|
||||
| command_injection.py:38:15:38:21 | ControlFlowNode for request | command_injection.py:41:15:41:21 | ControlFlowNode for command |
|
||||
| command_injection.py:38:15:38:21 | ControlFlowNode for request | command_injection.py:42:15:42:21 | ControlFlowNode for command |
|
||||
| command_injection.py:54:15:54:21 | ControlFlowNode for request | command_injection.py:55:15:55:21 | ControlFlowNode for command |
|
||||
| command_injection.py:54:15:54:21 | ControlFlowNode for request | command_injection.py:56:14:56:20 | ControlFlowNode for command |
|
||||
| command_injection.py:54:15:54:21 | ControlFlowNode for request | command_injection.py:57:21:57:27 | ControlFlowNode for command |
|
||||
| command_injection.py:54:15:54:21 | ControlFlowNode for request | command_injection.py:58:27:58:33 | ControlFlowNode for command |
|
||||
| command_injection.py:54:15:54:21 | ControlFlowNode for request | command_injection.py:59:20:59:26 | ControlFlowNode for command |
|
||||
| command_injection.py:71:12:71:18 | ControlFlowNode for request | command_injection.py:73:19:73:30 | ControlFlowNode for BinaryExpr |
|
||||
| command_injection.py:78:12:78:18 | ControlFlowNode for request | command_injection.py:80:19:80:30 | ControlFlowNode for BinaryExpr |
|
||||
nodes
|
||||
| command_injection.py:11:13:11:24 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| command_injection.py:11:13:11:19 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| command_injection.py:13:15:13:27 | ControlFlowNode for BinaryExpr | semmle.label | ControlFlowNode for BinaryExpr |
|
||||
| command_injection.py:18:13:18:24 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| command_injection.py:18:13:18:19 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| command_injection.py:20:22:20:34 | ControlFlowNode for BinaryExpr | semmle.label | ControlFlowNode for BinaryExpr |
|
||||
| command_injection.py:25:11:25:22 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| command_injection.py:25:11:25:17 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| command_injection.py:26:23:26:25 | ControlFlowNode for cmd | semmle.label | ControlFlowNode for cmd |
|
||||
| command_injection.py:31:13:31:24 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| command_injection.py:31:13:31:19 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| command_injection.py:33:14:33:26 | ControlFlowNode for BinaryExpr | semmle.label | ControlFlowNode for BinaryExpr |
|
||||
| command_injection.py:38:15:38:26 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| command_injection.py:38:15:38:21 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| command_injection.py:41:15:41:21 | ControlFlowNode for command | semmle.label | ControlFlowNode for command |
|
||||
| command_injection.py:42:15:42:21 | ControlFlowNode for command | semmle.label | ControlFlowNode for command |
|
||||
| command_injection.py:54:15:54:26 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| command_injection.py:54:15:54:21 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| command_injection.py:55:15:55:21 | ControlFlowNode for command | semmle.label | ControlFlowNode for command |
|
||||
| command_injection.py:56:14:56:20 | ControlFlowNode for command | semmle.label | ControlFlowNode for command |
|
||||
| command_injection.py:57:21:57:27 | ControlFlowNode for command | semmle.label | ControlFlowNode for command |
|
||||
| command_injection.py:58:27:58:33 | ControlFlowNode for command | semmle.label | ControlFlowNode for command |
|
||||
| command_injection.py:59:20:59:26 | ControlFlowNode for command | semmle.label | ControlFlowNode for command |
|
||||
| command_injection.py:71:12:71:23 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| command_injection.py:71:12:71:18 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| command_injection.py:73:19:73:30 | ControlFlowNode for BinaryExpr | semmle.label | ControlFlowNode for BinaryExpr |
|
||||
| command_injection.py:78:12:78:23 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| command_injection.py:78:12:78:18 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| command_injection.py:80:19:80:30 | ControlFlowNode for BinaryExpr | semmle.label | ControlFlowNode for BinaryExpr |
|
||||
#select
|
||||
| command_injection.py:13:15:13:27 | ControlFlowNode for BinaryExpr | command_injection.py:11:13:11:24 | ControlFlowNode for Attribute | command_injection.py:13:15:13:27 | ControlFlowNode for BinaryExpr | This command depends on $@. | command_injection.py:11:13:11:24 | ControlFlowNode for Attribute | a user-provided value |
|
||||
| command_injection.py:20:22:20:34 | ControlFlowNode for BinaryExpr | command_injection.py:18:13:18:24 | ControlFlowNode for Attribute | command_injection.py:20:22:20:34 | ControlFlowNode for BinaryExpr | This command depends on $@. | command_injection.py:18:13:18:24 | ControlFlowNode for Attribute | a user-provided value |
|
||||
| command_injection.py:26:23:26:25 | ControlFlowNode for cmd | command_injection.py:25:11:25:22 | ControlFlowNode for Attribute | command_injection.py:26:23:26:25 | ControlFlowNode for cmd | This command depends on $@. | command_injection.py:25:11:25:22 | ControlFlowNode for Attribute | a user-provided value |
|
||||
| command_injection.py:33:14:33:26 | ControlFlowNode for BinaryExpr | command_injection.py:31:13:31:24 | ControlFlowNode for Attribute | command_injection.py:33:14:33:26 | ControlFlowNode for BinaryExpr | This command depends on $@. | command_injection.py:31:13:31:24 | ControlFlowNode for Attribute | a user-provided value |
|
||||
| command_injection.py:41:15:41:21 | ControlFlowNode for command | command_injection.py:38:15:38:26 | ControlFlowNode for Attribute | command_injection.py:41:15:41:21 | ControlFlowNode for command | This command depends on $@. | command_injection.py:38:15:38:26 | ControlFlowNode for Attribute | a user-provided value |
|
||||
| command_injection.py:42:15:42:21 | ControlFlowNode for command | command_injection.py:38:15:38:26 | ControlFlowNode for Attribute | command_injection.py:42:15:42:21 | ControlFlowNode for command | This command depends on $@. | command_injection.py:38:15:38:26 | ControlFlowNode for Attribute | a user-provided value |
|
||||
| command_injection.py:55:15:55:21 | ControlFlowNode for command | command_injection.py:54:15:54:26 | ControlFlowNode for Attribute | command_injection.py:55:15:55:21 | ControlFlowNode for command | This command depends on $@. | command_injection.py:54:15:54:26 | ControlFlowNode for Attribute | a user-provided value |
|
||||
| command_injection.py:56:14:56:20 | ControlFlowNode for command | command_injection.py:54:15:54:26 | ControlFlowNode for Attribute | command_injection.py:56:14:56:20 | ControlFlowNode for command | This command depends on $@. | command_injection.py:54:15:54:26 | ControlFlowNode for Attribute | a user-provided value |
|
||||
| command_injection.py:57:21:57:27 | ControlFlowNode for command | command_injection.py:54:15:54:26 | ControlFlowNode for Attribute | command_injection.py:57:21:57:27 | ControlFlowNode for command | This command depends on $@. | command_injection.py:54:15:54:26 | ControlFlowNode for Attribute | a user-provided value |
|
||||
| command_injection.py:58:27:58:33 | ControlFlowNode for command | command_injection.py:54:15:54:26 | ControlFlowNode for Attribute | command_injection.py:58:27:58:33 | ControlFlowNode for command | This command depends on $@. | command_injection.py:54:15:54:26 | ControlFlowNode for Attribute | a user-provided value |
|
||||
| command_injection.py:59:20:59:26 | ControlFlowNode for command | command_injection.py:54:15:54:26 | ControlFlowNode for Attribute | command_injection.py:59:20:59:26 | ControlFlowNode for command | This command depends on $@. | command_injection.py:54:15:54:26 | ControlFlowNode for Attribute | a user-provided value |
|
||||
| command_injection.py:73:19:73:30 | ControlFlowNode for BinaryExpr | command_injection.py:71:12:71:23 | ControlFlowNode for Attribute | command_injection.py:73:19:73:30 | ControlFlowNode for BinaryExpr | This command depends on $@. | command_injection.py:71:12:71:23 | ControlFlowNode for Attribute | a user-provided value |
|
||||
| command_injection.py:80:19:80:30 | ControlFlowNode for BinaryExpr | command_injection.py:78:12:78:23 | ControlFlowNode for Attribute | command_injection.py:80:19:80:30 | ControlFlowNode for BinaryExpr | This command depends on $@. | command_injection.py:78:12:78:23 | ControlFlowNode for Attribute | a user-provided value |
|
||||
| command_injection.py:13:15:13:27 | ControlFlowNode for BinaryExpr | command_injection.py:11:13:11:19 | ControlFlowNode for request | command_injection.py:13:15:13:27 | ControlFlowNode for BinaryExpr | This command depends on $@. | command_injection.py:11:13:11:19 | ControlFlowNode for request | a user-provided value |
|
||||
| command_injection.py:20:22:20:34 | ControlFlowNode for BinaryExpr | command_injection.py:18:13:18:19 | ControlFlowNode for request | command_injection.py:20:22:20:34 | ControlFlowNode for BinaryExpr | This command depends on $@. | command_injection.py:18:13:18:19 | ControlFlowNode for request | a user-provided value |
|
||||
| command_injection.py:26:23:26:25 | ControlFlowNode for cmd | command_injection.py:25:11:25:17 | ControlFlowNode for request | command_injection.py:26:23:26:25 | ControlFlowNode for cmd | This command depends on $@. | command_injection.py:25:11:25:17 | ControlFlowNode for request | a user-provided value |
|
||||
| command_injection.py:33:14:33:26 | ControlFlowNode for BinaryExpr | command_injection.py:31:13:31:19 | ControlFlowNode for request | command_injection.py:33:14:33:26 | ControlFlowNode for BinaryExpr | This command depends on $@. | command_injection.py:31:13:31:19 | ControlFlowNode for request | a user-provided value |
|
||||
| command_injection.py:41:15:41:21 | ControlFlowNode for command | command_injection.py:38:15:38:21 | ControlFlowNode for request | command_injection.py:41:15:41:21 | ControlFlowNode for command | This command depends on $@. | command_injection.py:38:15:38:21 | ControlFlowNode for request | a user-provided value |
|
||||
| command_injection.py:42:15:42:21 | ControlFlowNode for command | command_injection.py:38:15:38:21 | ControlFlowNode for request | command_injection.py:42:15:42:21 | ControlFlowNode for command | This command depends on $@. | command_injection.py:38:15:38:21 | ControlFlowNode for request | a user-provided value |
|
||||
| command_injection.py:55:15:55:21 | ControlFlowNode for command | command_injection.py:54:15:54:21 | ControlFlowNode for request | command_injection.py:55:15:55:21 | ControlFlowNode for command | This command depends on $@. | command_injection.py:54:15:54:21 | ControlFlowNode for request | a user-provided value |
|
||||
| command_injection.py:56:14:56:20 | ControlFlowNode for command | command_injection.py:54:15:54:21 | ControlFlowNode for request | command_injection.py:56:14:56:20 | ControlFlowNode for command | This command depends on $@. | command_injection.py:54:15:54:21 | ControlFlowNode for request | a user-provided value |
|
||||
| command_injection.py:57:21:57:27 | ControlFlowNode for command | command_injection.py:54:15:54:21 | ControlFlowNode for request | command_injection.py:57:21:57:27 | ControlFlowNode for command | This command depends on $@. | command_injection.py:54:15:54:21 | ControlFlowNode for request | a user-provided value |
|
||||
| command_injection.py:58:27:58:33 | ControlFlowNode for command | command_injection.py:54:15:54:21 | ControlFlowNode for request | command_injection.py:58:27:58:33 | ControlFlowNode for command | This command depends on $@. | command_injection.py:54:15:54:21 | ControlFlowNode for request | a user-provided value |
|
||||
| command_injection.py:59:20:59:26 | ControlFlowNode for command | command_injection.py:54:15:54:21 | ControlFlowNode for request | command_injection.py:59:20:59:26 | ControlFlowNode for command | This command depends on $@. | command_injection.py:54:15:54:21 | ControlFlowNode for request | a user-provided value |
|
||||
| command_injection.py:73:19:73:30 | ControlFlowNode for BinaryExpr | command_injection.py:71:12:71:18 | ControlFlowNode for request | command_injection.py:73:19:73:30 | ControlFlowNode for BinaryExpr | This command depends on $@. | command_injection.py:71:12:71:18 | ControlFlowNode for request | a user-provided value |
|
||||
| command_injection.py:80:19:80:30 | ControlFlowNode for BinaryExpr | command_injection.py:78:12:78:18 | ControlFlowNode for request | command_injection.py:80:19:80:30 | ControlFlowNode for BinaryExpr | This command depends on $@. | command_injection.py:78:12:78:18 | ControlFlowNode for request | a user-provided value |
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
edges
|
||||
| reflected_xss.py:9:18:9:29 | ControlFlowNode for Attribute | reflected_xss.py:10:26:10:53 | ControlFlowNode for BinaryExpr |
|
||||
| reflected_xss.py:21:23:21:34 | ControlFlowNode for Attribute | reflected_xss.py:22:26:22:41 | ControlFlowNode for Attribute() |
|
||||
| reflected_xss.py:27:23:27:34 | ControlFlowNode for Attribute | reflected_xss.py:28:26:28:41 | ControlFlowNode for Attribute() |
|
||||
| reflected_xss.py:9:18:9:24 | ControlFlowNode for request | reflected_xss.py:10:26:10:53 | ControlFlowNode for BinaryExpr |
|
||||
| reflected_xss.py:21:23:21:29 | ControlFlowNode for request | reflected_xss.py:22:26:22:41 | ControlFlowNode for Attribute() |
|
||||
| reflected_xss.py:27:23:27:29 | ControlFlowNode for request | reflected_xss.py:28:26:28:41 | ControlFlowNode for Attribute() |
|
||||
nodes
|
||||
| reflected_xss.py:9:18:9:29 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| reflected_xss.py:9:18:9:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| reflected_xss.py:10:26:10:53 | ControlFlowNode for BinaryExpr | semmle.label | ControlFlowNode for BinaryExpr |
|
||||
| reflected_xss.py:21:23:21:34 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| reflected_xss.py:21:23:21:29 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| reflected_xss.py:22:26:22:41 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
|
||||
| reflected_xss.py:27:23:27:34 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| reflected_xss.py:27:23:27:29 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| reflected_xss.py:28:26:28:41 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
|
||||
#select
|
||||
| reflected_xss.py:10:26:10:53 | ControlFlowNode for BinaryExpr | reflected_xss.py:9:18:9:29 | ControlFlowNode for Attribute | reflected_xss.py:10:26:10:53 | ControlFlowNode for BinaryExpr | Cross-site scripting vulnerability due to $@. | reflected_xss.py:9:18:9:29 | ControlFlowNode for Attribute | a user-provided value |
|
||||
| reflected_xss.py:22:26:22:41 | ControlFlowNode for Attribute() | reflected_xss.py:21:23:21:34 | ControlFlowNode for Attribute | reflected_xss.py:22:26:22:41 | ControlFlowNode for Attribute() | Cross-site scripting vulnerability due to $@. | reflected_xss.py:21:23:21:34 | ControlFlowNode for Attribute | a user-provided value |
|
||||
| reflected_xss.py:28:26:28:41 | ControlFlowNode for Attribute() | reflected_xss.py:27:23:27:34 | ControlFlowNode for Attribute | reflected_xss.py:28:26:28:41 | ControlFlowNode for Attribute() | Cross-site scripting vulnerability due to $@. | reflected_xss.py:27:23:27:34 | ControlFlowNode for Attribute | a user-provided value |
|
||||
| reflected_xss.py:10:26:10:53 | ControlFlowNode for BinaryExpr | reflected_xss.py:9:18:9:24 | ControlFlowNode for request | reflected_xss.py:10:26:10:53 | ControlFlowNode for BinaryExpr | Cross-site scripting vulnerability due to $@. | reflected_xss.py:9:18:9:24 | ControlFlowNode for request | a user-provided value |
|
||||
| reflected_xss.py:22:26:22:41 | ControlFlowNode for Attribute() | reflected_xss.py:21:23:21:29 | ControlFlowNode for request | reflected_xss.py:22:26:22:41 | ControlFlowNode for Attribute() | Cross-site scripting vulnerability due to $@. | reflected_xss.py:21:23:21:29 | ControlFlowNode for request | a user-provided value |
|
||||
| reflected_xss.py:28:26:28:41 | ControlFlowNode for Attribute() | reflected_xss.py:27:23:27:29 | ControlFlowNode for request | reflected_xss.py:28:26:28:41 | ControlFlowNode for Attribute() | Cross-site scripting vulnerability due to $@. | reflected_xss.py:27:23:27:29 | ControlFlowNode for request | a user-provided value |
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
edges
|
||||
| code_injection.py:6:12:6:23 | ControlFlowNode for Attribute | code_injection.py:7:10:7:13 | ControlFlowNode for code |
|
||||
| code_injection.py:6:12:6:23 | ControlFlowNode for Attribute | code_injection.py:8:10:8:13 | ControlFlowNode for code |
|
||||
| code_injection.py:6:12:6:23 | ControlFlowNode for Attribute | code_injection.py:10:10:10:12 | ControlFlowNode for cmd |
|
||||
| code_injection.py:18:16:18:27 | ControlFlowNode for Attribute | code_injection.py:21:20:21:27 | ControlFlowNode for obj_name |
|
||||
| code_injection.py:6:12:6:18 | ControlFlowNode for request | code_injection.py:7:10:7:13 | ControlFlowNode for code |
|
||||
| code_injection.py:6:12:6:18 | ControlFlowNode for request | code_injection.py:8:10:8:13 | ControlFlowNode for code |
|
||||
| code_injection.py:6:12:6:18 | ControlFlowNode for request | code_injection.py:10:10:10:12 | ControlFlowNode for cmd |
|
||||
| code_injection.py:18:16:18:22 | ControlFlowNode for request | code_injection.py:21:20:21:27 | ControlFlowNode for obj_name |
|
||||
nodes
|
||||
| code_injection.py:6:12:6:23 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| code_injection.py:6:12:6:18 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| code_injection.py:7:10:7:13 | ControlFlowNode for code | semmle.label | ControlFlowNode for code |
|
||||
| code_injection.py:8:10:8:13 | ControlFlowNode for code | semmle.label | ControlFlowNode for code |
|
||||
| code_injection.py:10:10:10:12 | ControlFlowNode for cmd | semmle.label | ControlFlowNode for cmd |
|
||||
| code_injection.py:18:16:18:27 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| code_injection.py:18:16:18:22 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| code_injection.py:21:20:21:27 | ControlFlowNode for obj_name | semmle.label | ControlFlowNode for obj_name |
|
||||
#select
|
||||
| code_injection.py:7:10:7:13 | ControlFlowNode for code | code_injection.py:6:12:6:23 | ControlFlowNode for Attribute | code_injection.py:7:10:7:13 | ControlFlowNode for code | $@ flows to here and is interpreted as code. | code_injection.py:6:12:6:23 | ControlFlowNode for Attribute | A user-provided value |
|
||||
| code_injection.py:8:10:8:13 | ControlFlowNode for code | code_injection.py:6:12:6:23 | ControlFlowNode for Attribute | code_injection.py:8:10:8:13 | ControlFlowNode for code | $@ flows to here and is interpreted as code. | code_injection.py:6:12:6:23 | ControlFlowNode for Attribute | A user-provided value |
|
||||
| code_injection.py:10:10:10:12 | ControlFlowNode for cmd | code_injection.py:6:12:6:23 | ControlFlowNode for Attribute | code_injection.py:10:10:10:12 | ControlFlowNode for cmd | $@ flows to here and is interpreted as code. | code_injection.py:6:12:6:23 | ControlFlowNode for Attribute | A user-provided value |
|
||||
| code_injection.py:21:20:21:27 | ControlFlowNode for obj_name | code_injection.py:18:16:18:27 | ControlFlowNode for Attribute | code_injection.py:21:20:21:27 | ControlFlowNode for obj_name | $@ flows to here and is interpreted as code. | code_injection.py:18:16:18:27 | ControlFlowNode for Attribute | A user-provided value |
|
||||
| code_injection.py:7:10:7:13 | ControlFlowNode for code | code_injection.py:6:12:6:18 | ControlFlowNode for request | code_injection.py:7:10:7:13 | ControlFlowNode for code | $@ flows to here and is interpreted as code. | code_injection.py:6:12:6:18 | ControlFlowNode for request | A user-provided value |
|
||||
| code_injection.py:8:10:8:13 | ControlFlowNode for code | code_injection.py:6:12:6:18 | ControlFlowNode for request | code_injection.py:8:10:8:13 | ControlFlowNode for code | $@ flows to here and is interpreted as code. | code_injection.py:6:12:6:18 | ControlFlowNode for request | A user-provided value |
|
||||
| code_injection.py:10:10:10:12 | ControlFlowNode for cmd | code_injection.py:6:12:6:18 | ControlFlowNode for request | code_injection.py:10:10:10:12 | ControlFlowNode for cmd | $@ flows to here and is interpreted as code. | code_injection.py:6:12:6:18 | ControlFlowNode for request | A user-provided value |
|
||||
| code_injection.py:21:20:21:27 | ControlFlowNode for obj_name | code_injection.py:18:16:18:22 | ControlFlowNode for request | code_injection.py:21:20:21:27 | ControlFlowNode for obj_name | $@ flows to here and is interpreted as code. | code_injection.py:18:16:18:22 | ControlFlowNode for request | A user-provided value |
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
edges
|
||||
| unsafe_deserialization.py:14:15:14:26 | ControlFlowNode for Attribute | unsafe_deserialization.py:15:18:15:24 | ControlFlowNode for payload |
|
||||
| unsafe_deserialization.py:14:15:14:26 | ControlFlowNode for Attribute | unsafe_deserialization.py:16:15:16:21 | ControlFlowNode for payload |
|
||||
| unsafe_deserialization.py:14:15:14:26 | ControlFlowNode for Attribute | unsafe_deserialization.py:18:19:18:25 | ControlFlowNode for payload |
|
||||
| unsafe_deserialization.py:14:15:14:26 | ControlFlowNode for Attribute | unsafe_deserialization.py:21:16:21:22 | ControlFlowNode for payload |
|
||||
| unsafe_deserialization.py:14:15:14:21 | ControlFlowNode for request | unsafe_deserialization.py:15:18:15:24 | ControlFlowNode for payload |
|
||||
| unsafe_deserialization.py:14:15:14:21 | ControlFlowNode for request | unsafe_deserialization.py:16:15:16:21 | ControlFlowNode for payload |
|
||||
| unsafe_deserialization.py:14:15:14:21 | ControlFlowNode for request | unsafe_deserialization.py:18:19:18:25 | ControlFlowNode for payload |
|
||||
| unsafe_deserialization.py:14:15:14:21 | ControlFlowNode for request | unsafe_deserialization.py:21:16:21:22 | ControlFlowNode for payload |
|
||||
nodes
|
||||
| unsafe_deserialization.py:14:15:14:26 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| unsafe_deserialization.py:14:15:14:21 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| unsafe_deserialization.py:15:18:15:24 | ControlFlowNode for payload | semmle.label | ControlFlowNode for payload |
|
||||
| unsafe_deserialization.py:16:15:16:21 | ControlFlowNode for payload | semmle.label | ControlFlowNode for payload |
|
||||
| unsafe_deserialization.py:18:19:18:25 | ControlFlowNode for payload | semmle.label | ControlFlowNode for payload |
|
||||
| unsafe_deserialization.py:21:16:21:22 | ControlFlowNode for payload | semmle.label | ControlFlowNode for payload |
|
||||
#select
|
||||
| unsafe_deserialization.py:15:18:15:24 | ControlFlowNode for payload | unsafe_deserialization.py:14:15:14:26 | ControlFlowNode for Attribute | unsafe_deserialization.py:15:18:15:24 | ControlFlowNode for payload | Deserializing of $@. | unsafe_deserialization.py:14:15:14:26 | ControlFlowNode for Attribute | untrusted input |
|
||||
| unsafe_deserialization.py:16:15:16:21 | ControlFlowNode for payload | unsafe_deserialization.py:14:15:14:26 | ControlFlowNode for Attribute | unsafe_deserialization.py:16:15:16:21 | ControlFlowNode for payload | Deserializing of $@. | unsafe_deserialization.py:14:15:14:26 | ControlFlowNode for Attribute | untrusted input |
|
||||
| unsafe_deserialization.py:18:19:18:25 | ControlFlowNode for payload | unsafe_deserialization.py:14:15:14:26 | ControlFlowNode for Attribute | unsafe_deserialization.py:18:19:18:25 | ControlFlowNode for payload | Deserializing of $@. | unsafe_deserialization.py:14:15:14:26 | ControlFlowNode for Attribute | untrusted input |
|
||||
| unsafe_deserialization.py:21:16:21:22 | ControlFlowNode for payload | unsafe_deserialization.py:14:15:14:26 | ControlFlowNode for Attribute | unsafe_deserialization.py:21:16:21:22 | ControlFlowNode for payload | Deserializing of $@. | unsafe_deserialization.py:14:15:14:26 | ControlFlowNode for Attribute | untrusted input |
|
||||
| unsafe_deserialization.py:15:18:15:24 | ControlFlowNode for payload | unsafe_deserialization.py:14:15:14:21 | ControlFlowNode for request | unsafe_deserialization.py:15:18:15:24 | ControlFlowNode for payload | Deserializing of $@. | unsafe_deserialization.py:14:15:14:21 | ControlFlowNode for request | untrusted input |
|
||||
| unsafe_deserialization.py:16:15:16:21 | ControlFlowNode for payload | unsafe_deserialization.py:14:15:14:21 | ControlFlowNode for request | unsafe_deserialization.py:16:15:16:21 | ControlFlowNode for payload | Deserializing of $@. | unsafe_deserialization.py:14:15:14:21 | ControlFlowNode for request | untrusted input |
|
||||
| unsafe_deserialization.py:18:19:18:25 | ControlFlowNode for payload | unsafe_deserialization.py:14:15:14:21 | ControlFlowNode for request | unsafe_deserialization.py:18:19:18:25 | ControlFlowNode for payload | Deserializing of $@. | unsafe_deserialization.py:14:15:14:21 | ControlFlowNode for request | untrusted input |
|
||||
| unsafe_deserialization.py:21:16:21:22 | ControlFlowNode for payload | unsafe_deserialization.py:14:15:14:21 | ControlFlowNode for request | unsafe_deserialization.py:21:16:21:22 | ControlFlowNode for payload | Deserializing of $@. | unsafe_deserialization.py:14:15:14:21 | ControlFlowNode for request | untrusted input |
|
||||
|
||||
@@ -1,35 +1,35 @@
|
||||
edges
|
||||
| test.py:7:14:7:25 | ControlFlowNode for Attribute | test.py:8:21:8:26 | ControlFlowNode for target |
|
||||
| test.py:30:17:30:28 | ControlFlowNode for Attribute | test.py:32:21:32:24 | ControlFlowNode for safe |
|
||||
| test.py:37:17:37:28 | ControlFlowNode for Attribute | test.py:39:21:39:24 | ControlFlowNode for safe |
|
||||
| test.py:44:17:44:28 | ControlFlowNode for Attribute | test.py:46:21:46:24 | ControlFlowNode for safe |
|
||||
| test.py:60:17:60:28 | ControlFlowNode for Attribute | test.py:62:21:62:26 | ControlFlowNode for unsafe |
|
||||
| test.py:67:17:67:28 | ControlFlowNode for Attribute | test.py:69:21:69:26 | ControlFlowNode for unsafe |
|
||||
| test.py:74:17:74:28 | ControlFlowNode for Attribute | test.py:76:21:76:26 | ControlFlowNode for unsafe |
|
||||
| test.py:81:17:81:28 | ControlFlowNode for Attribute | test.py:83:21:83:26 | ControlFlowNode for unsafe |
|
||||
| test.py:7:14:7:20 | ControlFlowNode for request | test.py:8:21:8:26 | ControlFlowNode for target |
|
||||
| test.py:30:17:30:23 | ControlFlowNode for request | test.py:32:21:32:24 | ControlFlowNode for safe |
|
||||
| test.py:37:17:37:23 | ControlFlowNode for request | test.py:39:21:39:24 | ControlFlowNode for safe |
|
||||
| test.py:44:17:44:23 | ControlFlowNode for request | test.py:46:21:46:24 | ControlFlowNode for safe |
|
||||
| test.py:60:17:60:23 | ControlFlowNode for request | test.py:62:21:62:26 | ControlFlowNode for unsafe |
|
||||
| test.py:67:17:67:23 | ControlFlowNode for request | test.py:69:21:69:26 | ControlFlowNode for unsafe |
|
||||
| test.py:74:17:74:23 | ControlFlowNode for request | test.py:76:21:76:26 | ControlFlowNode for unsafe |
|
||||
| test.py:81:17:81:23 | ControlFlowNode for request | test.py:83:21:83:26 | ControlFlowNode for unsafe |
|
||||
nodes
|
||||
| test.py:7:14:7:25 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| test.py:7:14:7:20 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| test.py:8:21:8:26 | ControlFlowNode for target | semmle.label | ControlFlowNode for target |
|
||||
| test.py:30:17:30:28 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| test.py:30:17:30:23 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| test.py:32:21:32:24 | ControlFlowNode for safe | semmle.label | ControlFlowNode for safe |
|
||||
| test.py:37:17:37:28 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| test.py:37:17:37:23 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| test.py:39:21:39:24 | ControlFlowNode for safe | semmle.label | ControlFlowNode for safe |
|
||||
| test.py:44:17:44:28 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| test.py:44:17:44:23 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| test.py:46:21:46:24 | ControlFlowNode for safe | semmle.label | ControlFlowNode for safe |
|
||||
| test.py:60:17:60:28 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| test.py:60:17:60:23 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| test.py:62:21:62:26 | ControlFlowNode for unsafe | semmle.label | ControlFlowNode for unsafe |
|
||||
| test.py:67:17:67:28 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| test.py:67:17:67:23 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| test.py:69:21:69:26 | ControlFlowNode for unsafe | semmle.label | ControlFlowNode for unsafe |
|
||||
| test.py:74:17:74:28 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| test.py:74:17:74:23 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| test.py:76:21:76:26 | ControlFlowNode for unsafe | semmle.label | ControlFlowNode for unsafe |
|
||||
| test.py:81:17:81:28 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| test.py:81:17:81:23 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| test.py:83:21:83:26 | ControlFlowNode for unsafe | semmle.label | ControlFlowNode for unsafe |
|
||||
#select
|
||||
| test.py:8:21:8:26 | ControlFlowNode for target | test.py:7:14:7:25 | ControlFlowNode for Attribute | test.py:8:21:8:26 | ControlFlowNode for target | Untrusted URL redirection due to $@. | test.py:7:14:7:25 | ControlFlowNode for Attribute | A user-provided value |
|
||||
| test.py:32:21:32:24 | ControlFlowNode for safe | test.py:30:17:30:28 | ControlFlowNode for Attribute | test.py:32:21:32:24 | ControlFlowNode for safe | Untrusted URL redirection due to $@. | test.py:30:17:30:28 | ControlFlowNode for Attribute | A user-provided value |
|
||||
| test.py:39:21:39:24 | ControlFlowNode for safe | test.py:37:17:37:28 | ControlFlowNode for Attribute | test.py:39:21:39:24 | ControlFlowNode for safe | Untrusted URL redirection due to $@. | test.py:37:17:37:28 | ControlFlowNode for Attribute | A user-provided value |
|
||||
| test.py:46:21:46:24 | ControlFlowNode for safe | test.py:44:17:44:28 | ControlFlowNode for Attribute | test.py:46:21:46:24 | ControlFlowNode for safe | Untrusted URL redirection due to $@. | test.py:44:17:44:28 | ControlFlowNode for Attribute | A user-provided value |
|
||||
| test.py:62:21:62:26 | ControlFlowNode for unsafe | test.py:60:17:60:28 | ControlFlowNode for Attribute | test.py:62:21:62:26 | ControlFlowNode for unsafe | Untrusted URL redirection due to $@. | test.py:60:17:60:28 | ControlFlowNode for Attribute | A user-provided value |
|
||||
| test.py:69:21:69:26 | ControlFlowNode for unsafe | test.py:67:17:67:28 | ControlFlowNode for Attribute | test.py:69:21:69:26 | ControlFlowNode for unsafe | Untrusted URL redirection due to $@. | test.py:67:17:67:28 | ControlFlowNode for Attribute | A user-provided value |
|
||||
| test.py:76:21:76:26 | ControlFlowNode for unsafe | test.py:74:17:74:28 | ControlFlowNode for Attribute | test.py:76:21:76:26 | ControlFlowNode for unsafe | Untrusted URL redirection due to $@. | test.py:74:17:74:28 | ControlFlowNode for Attribute | A user-provided value |
|
||||
| test.py:83:21:83:26 | ControlFlowNode for unsafe | test.py:81:17:81:28 | ControlFlowNode for Attribute | test.py:83:21:83:26 | ControlFlowNode for unsafe | Untrusted URL redirection due to $@. | test.py:81:17:81:28 | ControlFlowNode for Attribute | A user-provided value |
|
||||
| test.py:8:21:8:26 | ControlFlowNode for target | test.py:7:14:7:20 | ControlFlowNode for request | test.py:8:21:8:26 | ControlFlowNode for target | Untrusted URL redirection due to $@. | test.py:7:14:7:20 | ControlFlowNode for request | A user-provided value |
|
||||
| test.py:32:21:32:24 | ControlFlowNode for safe | test.py:30:17:30:23 | ControlFlowNode for request | test.py:32:21:32:24 | ControlFlowNode for safe | Untrusted URL redirection due to $@. | test.py:30:17:30:23 | ControlFlowNode for request | A user-provided value |
|
||||
| test.py:39:21:39:24 | ControlFlowNode for safe | test.py:37:17:37:23 | ControlFlowNode for request | test.py:39:21:39:24 | ControlFlowNode for safe | Untrusted URL redirection due to $@. | test.py:37:17:37:23 | ControlFlowNode for request | A user-provided value |
|
||||
| test.py:46:21:46:24 | ControlFlowNode for safe | test.py:44:17:44:23 | ControlFlowNode for request | test.py:46:21:46:24 | ControlFlowNode for safe | Untrusted URL redirection due to $@. | test.py:44:17:44:23 | ControlFlowNode for request | A user-provided value |
|
||||
| test.py:62:21:62:26 | ControlFlowNode for unsafe | test.py:60:17:60:23 | ControlFlowNode for request | test.py:62:21:62:26 | ControlFlowNode for unsafe | Untrusted URL redirection due to $@. | test.py:60:17:60:23 | ControlFlowNode for request | A user-provided value |
|
||||
| test.py:69:21:69:26 | ControlFlowNode for unsafe | test.py:67:17:67:23 | ControlFlowNode for request | test.py:69:21:69:26 | ControlFlowNode for unsafe | Untrusted URL redirection due to $@. | test.py:67:17:67:23 | ControlFlowNode for request | A user-provided value |
|
||||
| test.py:76:21:76:26 | ControlFlowNode for unsafe | test.py:74:17:74:23 | ControlFlowNode for request | test.py:76:21:76:26 | ControlFlowNode for unsafe | Untrusted URL redirection due to $@. | test.py:74:17:74:23 | ControlFlowNode for request | A user-provided value |
|
||||
| test.py:83:21:83:26 | ControlFlowNode for unsafe | test.py:81:17:81:23 | ControlFlowNode for request | test.py:83:21:83:26 | ControlFlowNode for unsafe | Untrusted URL redirection due to $@. | test.py:81:17:81:23 | ControlFlowNode for request | A user-provided value |
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
| type_annotation_fp.py:5:5:5:7 | foo | The value assigned to local variable 'foo' is never used. |
|
||||
| variables_test.py:29:5:29:5 | x | The value assigned to local variable 'x' is never used. |
|
||||
| variables_test.py:89:5:89:5 | a | The value assigned to local variable 'a' is never used. |
|
||||
| variables_test.py:89:7:89:7 | b | The value assigned to local variable 'b' is never used. |
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
# FP Type annotation counts as redefinition
|
||||
# See https://github.com/Semmle/ql/issues/2652
|
||||
|
||||
def type_annotation(x):
|
||||
foo = 5
|
||||
if x:
|
||||
foo : int
|
||||
do_stuff_with(foo)
|
||||
else:
|
||||
foo : float
|
||||
do_other_stuff_with(foo)
|
||||
Reference in New Issue
Block a user