diff --git a/python/ql/consistency-queries/CfgConsistency.ql b/python/ql/consistency-queries/CfgConsistency.ql new file mode 100644 index 000000000000..ab13eddf190c --- /dev/null +++ b/python/ql/consistency-queries/CfgConsistency.ql @@ -0,0 +1,2 @@ +import semmle.python.controlflow.internal.AstNodeImpl +import ControlFlow::Consistency diff --git a/python/ql/consistency-queries/DataFlowConsistency.ql b/python/ql/consistency-queries/DataFlowConsistency.ql index e0ed207dc218..8a032ecaba6c 100644 --- a/python/ql/consistency-queries/DataFlowConsistency.ql +++ b/python/ql/consistency-queries/DataFlowConsistency.ql @@ -9,6 +9,7 @@ private import semmle.python.dataflow.new.internal.DataFlowImplSpecific private import semmle.python.dataflow.new.internal.DataFlowDispatch private import semmle.python.dataflow.new.internal.TaintTrackingImplSpecific private import codeql.dataflow.internal.DataFlowImplConsistency +private import semmle.python.controlflow.internal.Cfg as Cfg private module Input implements InputSig { private import Private @@ -74,7 +75,7 @@ private module Input implements InputSig { // resolve to multiple functions), but we only make _one_ ArgumentNode for each // argument in the CallNode, we end up violating this consistency check in those // cases. (see `getCallArg` in DataFlowDispatch.qll) - exists(DataFlowCall other, CallNode cfgCall | other != call | + exists(DataFlowCall other, Cfg::CallNode cfgCall | other != call | call.getNode() = cfgCall and other.getNode() = cfgCall and isArgumentNode(arg, call, _) and @@ -90,16 +91,16 @@ private module Input implements InputSig { // allow it instead. ( call.getScope() = attr.getScope() and - any(CfgNode n | n.asCfgNode() = call.getNode().(CallNode).getFunction()).getALocalSource() = - attr + any(CfgNode n | n.asCfgNode() = call.getNode().(Cfg::CallNode).getFunction()) + .getALocalSource() = attr or not exists(call.getScope().(Function).getDefinition()) and call.getScope().getScope+() = attr.getScope() ) and ( other.getScope() = attr.getScope() and - any(CfgNode n | n.asCfgNode() = other.getNode().(CallNode).getFunction()).getALocalSource() = - attr + any(CfgNode n | n.asCfgNode() = other.getNode().(Cfg::CallNode).getFunction()) + .getALocalSource() = attr or not exists(other.getScope().(Function).getDefinition()) and other.getScope().getScope+() = attr.getScope() diff --git a/python/ql/lib/change-notes/2026-05-19-add-shared-cfg.md b/python/ql/lib/change-notes/2026-05-19-add-shared-cfg.md new file mode 100644 index 000000000000..913f95320d87 --- /dev/null +++ b/python/ql/lib/change-notes/2026-05-19-add-shared-cfg.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* A new Python control flow graph implementation has been added under `semmle.python.controlflow.internal.Cfg` (backed by `AstNodeImpl.qll`), built on the shared `codeql.controlflow.ControlFlowGraph` library. It is not yet used by the dataflow library or any production query; the legacy CFG in `semmle/python/Flow.qll` remains the default. The new library is exposed for tests and for upcoming migrations. diff --git a/python/ql/lib/change-notes/2026-05-19-add-shared-ssa.md b/python/ql/lib/change-notes/2026-05-19-add-shared-ssa.md new file mode 100644 index 000000000000..7e845df3a369 --- /dev/null +++ b/python/ql/lib/change-notes/2026-05-19-add-shared-ssa.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* A new SSA adapter has been added under `semmle.python.dataflow.new.internal.SsaImpl`, built on the shared `codeql.ssa.Ssa` library and the new shared CFG (`semmle.python.controlflow.internal.Cfg`). It is not yet used by the dataflow library or any production query; the legacy ESSA SSA in `semmle/python/essa/*` remains the default. The new SSA adapter is exposed for tests and for the upcoming dataflow migration. diff --git a/python/ql/lib/change-notes/2026-06-02-deprecated-flow-nodes-use-new-cfg.md b/python/ql/lib/change-notes/2026-06-02-deprecated-flow-nodes-use-new-cfg.md new file mode 100644 index 000000000000..89a2fd685ae7 --- /dev/null +++ b/python/ql/lib/change-notes/2026-06-02-deprecated-flow-nodes-use-new-cfg.md @@ -0,0 +1,4 @@ +--- +category: breaking +--- +* The deprecated `AstNode.getAFlowNode()` and `Function.getAReturnValueFlowNode()` predicates now return nodes from the new shared CFG (`Cfg::ControlFlowNode`) rather than from the legacy CFG (`ControlFlowNode`). Callers that still rely on these deprecated APIs and feed the result into legacy-CFG-aware predicates will no longer type-check; migrate to `n.getNode() = e` (or, for return values, the explicit `Return` pattern shown in the deprecation message) to get nodes from the dataflow library's current CFG. diff --git a/python/ql/lib/printCfgNew.ql b/python/ql/lib/printCfgNew.ql new file mode 100644 index 000000000000..ba336de562a7 --- /dev/null +++ b/python/ql/lib/printCfgNew.ql @@ -0,0 +1,45 @@ +/** + * @name Print CFG (New) + * @description Produces a representation of a file's Control Flow Graph + * using the new shared control flow library. + * This query is used by the VS Code extension. + * @id python/print-cfg + * @kind graph + * @tags ide-contextual-queries/print-cfg + */ + +private import python as Py +import semmle.python.controlflow.internal.AstNodeImpl + +external string selectedSourceFile(); + +private predicate selectedSourceFileAlias = selectedSourceFile/0; + +external int selectedSourceLine(); + +private predicate selectedSourceLineAlias = selectedSourceLine/0; + +external int selectedSourceColumn(); + +private predicate selectedSourceColumnAlias = selectedSourceColumn/0; + +module ViewCfgQueryInput implements ControlFlow::ViewCfgQueryInputSig { + predicate selectedSourceFile = selectedSourceFileAlias/0; + + predicate selectedSourceLine = selectedSourceLineAlias/0; + + predicate selectedSourceColumn = selectedSourceColumnAlias/0; + + predicate cfgScopeSpan( + Ast::Callable callable, Py::File file, int startLine, int startColumn, int endLine, + int endColumn + ) { + exists(Py::Scope scope | + scope = callable.asScope() and + file = scope.getLocation().getFile() and + scope.getLocation().hasLocationInfo(_, startLine, startColumn, endLine, endColumn) + ) + } +} + +import ControlFlow::ViewCfgQuery diff --git a/python/ql/lib/semmle/python/ApiGraphs.qll b/python/ql/lib/semmle/python/ApiGraphs.qll index efd8141efc6e..23000a9bd35f 100644 --- a/python/ql/lib/semmle/python/ApiGraphs.qll +++ b/python/ql/lib/semmle/python/ApiGraphs.qll @@ -6,8 +6,9 @@ * directed and labeled; they specify how the components represented by nodes relate to each other. */ -// Importing python under the `py` namespace to avoid importing `CallNode` from `Flow.qll` and thereby having a naming conflict with `API::CallNode`. +// Importing python under the `PY` namespace to avoid pulling in `CallNode` from `Flow.qll` (via `import python`) and thereby having a naming conflict with `API::CallNode`. private import python as PY +private import semmle.python.controlflow.internal.Cfg as Cfg import semmle.python.dataflow.new.DataFlow private import semmle.python.internal.CachedStages @@ -282,7 +283,7 @@ module API { index = this.getIndex() and ( // subscripting - exists(PY::SubscriptNode subscript | + exists(Cfg::SubscriptNode subscript | subscript.getObject() = this.getAValueReachableFromSource().asCfgNode() and subscript.getIndex() = index.asSink().asCfgNode() | @@ -290,7 +291,7 @@ module API { subscript = result.asSource().asCfgNode() or // writing - subscript.(PY::DefinitionNode).getValue() = result.asSink().asCfgNode() + subscript.(Cfg::DefinitionNode).getValue() = result.asSink().asCfgNode() ) or // dictionary literals @@ -684,7 +685,7 @@ module API { * Ignores relative imports, such as `from ..foo.bar import baz`. */ private predicate imports(DataFlow::CfgNode imp, string name) { - exists(PY::ImportExprNode iexpr | + exists(Cfg::ImportExprNode iexpr | imp.getNode() = iexpr and not iexpr.getNode().isRelative() and name = iexpr.getNode().getImportedModuleName() @@ -775,7 +776,7 @@ module API { // list literals, from `x` to `[x]` // TODO: once convenient, this should be done at a higher level than the AST, // at least at the CFG layer, to take splitting into account. - // Also consider `SequenceNode for generality. + // Also consider `Cfg::SequenceNode` for generality. exists(PY::List list | list = pred.(DataFlow::ExprNode).getNode().getNode() | rhs.(DataFlow::ExprNode).getNode().getNode() = list.getAnElt() and lbl = Label::subscript() @@ -805,7 +806,7 @@ module API { subscript = trackUseNode(src).getSubscript(index) | // from `x` to a definition of `x[...]` - rhs.asCfgNode() = subscript.asCfgNode().(PY::DefinitionNode).getValue() and + rhs.asCfgNode() = subscript.asCfgNode().(Cfg::DefinitionNode).getValue() and lbl = Label::subscript() or // from `x` to `"key"` in `x["key"]` diff --git a/python/ql/lib/semmle/python/AstExtended.qll b/python/ql/lib/semmle/python/AstExtended.qll index 2adad68f0b41..dd16f8148f9d 100644 --- a/python/ql/lib/semmle/python/AstExtended.qll +++ b/python/ql/lib/semmle/python/AstExtended.qll @@ -3,6 +3,7 @@ module; import python private import semmle.python.internal.CachedStages +private import semmle.python.controlflow.internal.Cfg as Cfg /** A syntactic node (Class, Function, Module, Expr, Stmt or Comprehension) corresponding to a flow node */ abstract class AstNode extends AstNode_ { @@ -19,17 +20,16 @@ abstract class AstNode extends AstNode_ { /** * DEPRECATED: use `ControlFlowNode.getNode()` from the other direction instead; * that is, replace `e.getAFlowNode() = n` with `n.getNode() = e`. This API is - * being removed to untangle the AST and CFG hierarchies in preparation for - * migrating the dataflow library off the legacy CFG. + * being removed to untangle the AST and CFG hierarchies. * - * Gets a flow node corresponding directly to this node. - * NOTE: For some statements and other purely syntactic elements, - * there may not be a `ControlFlowNode`. + * Gets a flow node corresponding directly to this node, from the new + * (shared) CFG. NOTE: For some statements and other purely syntactic + * elements, there may not be a `ControlFlowNode`. */ cached - deprecated ControlFlowNode getAFlowNode() { + deprecated Cfg::ControlFlowNode getAFlowNode() { Stages::AST::ref() and - py_flow_bb_node(result, this, _, _) + result.getNode() = this } /** Gets the location for this AST node */ diff --git a/python/ql/lib/semmle/python/Concepts.qll b/python/ql/lib/semmle/python/Concepts.qll index 76e9f4bd13f9..6eb74b52121d 100644 --- a/python/ql/lib/semmle/python/Concepts.qll +++ b/python/ql/lib/semmle/python/Concepts.qll @@ -5,6 +5,7 @@ */ private import python +private import semmle.python.controlflow.internal.Cfg as Cfg private import semmle.python.dataflow.new.DataFlow private import semmle.python.dataflow.new.internal.DataFlowImplSpecific private import semmle.python.dataflow.new.RemoteFlowSources @@ -214,7 +215,7 @@ module Path { SafeAccessCheck() { this = DataFlow::BarrierGuard::getABarrierNode() } } - private predicate safeAccessCheck(DataFlow::GuardNode g, ControlFlowNode node, boolean branch) { + private predicate safeAccessCheck(DataFlow::GuardNode g, Cfg::ControlFlowNode node, boolean branch) { g.(SafeAccessCheck::Range).checks(node, branch) } @@ -223,7 +224,7 @@ module Path { /** A data-flow node that checks that a path is safe to access in some way, for example by having a controlled prefix. */ abstract class Range extends DataFlow::GuardNode { /** Holds if this guard validates `node` upon evaluating to `branch`. */ - abstract predicate checks(ControlFlowNode node, boolean branch); + abstract predicate checks(Cfg::ControlFlowNode node, boolean branch); } } } diff --git a/python/ql/lib/semmle/python/Exprs.qll b/python/ql/lib/semmle/python/Exprs.qll index 937c9e5ffd79..31fe304d21e5 100644 --- a/python/ql/lib/semmle/python/Exprs.qll +++ b/python/ql/lib/semmle/python/Exprs.qll @@ -3,6 +3,7 @@ module; private import python private import semmle.python.internal.CachedStages +private import semmle.python.controlflow.internal.Cfg as Cfg /** An expression */ class Expr extends Expr_, AstNode { @@ -70,7 +71,7 @@ class Attribute extends Attribute_ { /* syntax: Expr.name */ override Expr getASubExpression() { result = this.getObject() } - deprecated override AttrNode getAFlowNode() { result = super.getAFlowNode() } + deprecated override Cfg::AttrNode getAFlowNode() { result = super.getAFlowNode() } /** Gets the name of this attribute. That is the `name` in `obj.name` */ string getName() { result = Attribute_.super.getAttr() } @@ -99,7 +100,7 @@ class Subscript extends Subscript_ { Expr getObject() { result = Subscript_.super.getValue() } - deprecated override SubscriptNode getAFlowNode() { result = super.getAFlowNode() } + deprecated override Cfg::SubscriptNode getAFlowNode() { result = super.getAFlowNode() } } /** A call expression, such as `func(...)` */ @@ -115,7 +116,7 @@ class Call extends Call_ { override string toString() { result = this.getFunc().toString() + "()" } - deprecated override CallNode getAFlowNode() { result = super.getAFlowNode() } + deprecated override Cfg::CallNode getAFlowNode() { result = super.getAFlowNode() } /** Gets a tuple (*) argument of this call. */ Expr getStarargs() { result = this.getAPositionalArg().(Starred).getValue() } @@ -203,7 +204,7 @@ class IfExp extends IfExp_ { result = this.getTest() or result = this.getBody() or result = this.getOrelse() } - deprecated override IfExprNode getAFlowNode() { result = super.getAFlowNode() } + deprecated override Cfg::IfExprNode getAFlowNode() { result = super.getAFlowNode() } } /** A starred expression, such as the `*rest` in the assignment `first, *rest = seq` */ @@ -413,7 +414,7 @@ class PlaceHolder extends PlaceHolder_ { override string toString() { result = "$" + this.getId() } - deprecated override NameNode getAFlowNode() { result = super.getAFlowNode() } + deprecated override Cfg::NameNode getAFlowNode() { result = super.getAFlowNode() } } /** A tuple expression such as `( 1, 3, 5, 7, 9 )` */ @@ -480,7 +481,7 @@ class Name extends Name_ { override string toString() { result = this.getId() } - deprecated override NameNode getAFlowNode() { result = super.getAFlowNode() } + deprecated override Cfg::NameNode getAFlowNode() { result = super.getAFlowNode() } override predicate isArtificial() { /* Artificial variable names in comprehensions all start with "." */ @@ -587,7 +588,7 @@ abstract class NameConstant extends Name, ImmutableLiteral { override predicate isConstant() { any() } - deprecated override NameConstantNode getAFlowNode() { result = Name.super.getAFlowNode() } + deprecated override Cfg::NameConstantNode getAFlowNode() { result = Name.super.getAFlowNode() } override predicate isArtificial() { none() } } diff --git a/python/ql/lib/semmle/python/Flow.qll b/python/ql/lib/semmle/python/Flow.qll index bdb01f4c9e2e..76a1f21af157 100644 --- a/python/ql/lib/semmle/python/Flow.qll +++ b/python/ql/lib/semmle/python/Flow.qll @@ -1,7 +1,7 @@ overlay[local] module; -import python +import python as Py private import semmle.python.internal.CachedStages private import codeql.controlflow.BasicBlock as BB @@ -17,7 +17,7 @@ private import codeql.controlflow.BasicBlock as BB */ private predicate augstore(ControlFlowNode load, ControlFlowNode store) { - exists(Expr load_store | exists(AugAssign aa | aa.getTarget() = load_store) | + exists(Py::Expr load_store | exists(Py::AugAssign aa | aa.getTarget() = load_store) | toAst(load) = load_store and toAst(store) = load_store and load.strictlyDominates(store) @@ -25,7 +25,7 @@ private predicate augstore(ControlFlowNode load, ControlFlowNode store) { } /** A non-dispatched getNode() to avoid negative recursion issues */ -private AstNode toAst(ControlFlowNode n) { py_flow_bb_node(n, result, _, _) } +private Py::AstNode toAst(ControlFlowNode n) { py_flow_bb_node(n, result, _, _) } /** * A control flow node. Control flow nodes have a many-to-one relation with syntactic nodes, @@ -35,19 +35,19 @@ private AstNode toAst(ControlFlowNode n) { py_flow_bb_node(n, result, _, _) } class ControlFlowNode extends @py_flow_node { /** Whether this control flow node is a load (including those in augmented assignments) */ predicate isLoad() { - exists(Expr e | e = toAst(this) | py_expr_contexts(_, 3, e) and not augstore(_, this)) + exists(Py::Expr e | e = toAst(this) | py_expr_contexts(_, 3, e) and not augstore(_, this)) } /** Whether this control flow node is a store (including those in augmented assignments) */ predicate isStore() { - exists(Expr e | e = toAst(this) | py_expr_contexts(_, 5, e) or augstore(_, this)) + exists(Py::Expr e | e = toAst(this) | py_expr_contexts(_, 5, e) or augstore(_, this)) } /** Whether this control flow node is a delete */ - predicate isDelete() { exists(Expr e | e = toAst(this) | py_expr_contexts(_, 2, e)) } + predicate isDelete() { exists(Py::Expr e | e = toAst(this) | py_expr_contexts(_, 2, e)) } /** Whether this control flow node is a parameter */ - predicate isParameter() { exists(Expr e | e = toAst(this) | py_expr_contexts(_, 4, e)) } + predicate isParameter() { exists(Py::Expr e | e = toAst(this) | py_expr_contexts(_, 4, e)) } /** Whether this control flow node is a store in an augmented assignment */ predicate isAugStore() { augstore(_, this) } @@ -57,61 +57,61 @@ class ControlFlowNode extends @py_flow_node { /** Whether this flow node corresponds to a literal */ predicate isLiteral() { - toAst(this) instanceof Bytes + toAst(this) instanceof Py::Bytes or - toAst(this) instanceof Dict + toAst(this) instanceof Py::Dict or - toAst(this) instanceof DictComp + toAst(this) instanceof Py::DictComp or - toAst(this) instanceof Set + toAst(this) instanceof Py::Set or - toAst(this) instanceof SetComp + toAst(this) instanceof Py::SetComp or - toAst(this) instanceof Ellipsis + toAst(this) instanceof Py::Ellipsis or - toAst(this) instanceof GeneratorExp + toAst(this) instanceof Py::GeneratorExp or - toAst(this) instanceof Lambda + toAst(this) instanceof Py::Lambda or - toAst(this) instanceof ListComp + toAst(this) instanceof Py::ListComp or - toAst(this) instanceof List + toAst(this) instanceof Py::List or - toAst(this) instanceof Num + toAst(this) instanceof Py::Num or - toAst(this) instanceof Tuple + toAst(this) instanceof Py::Tuple or - toAst(this) instanceof Unicode + toAst(this) instanceof Py::Unicode or - toAst(this) instanceof NameConstant + toAst(this) instanceof Py::NameConstant } /** Whether this flow node corresponds to an attribute expression */ - predicate isAttribute() { toAst(this) instanceof Attribute } + predicate isAttribute() { toAst(this) instanceof Py::Attribute } /** Whether this flow node corresponds to an subscript expression */ - predicate isSubscript() { toAst(this) instanceof Subscript } + predicate isSubscript() { toAst(this) instanceof Py::Subscript } /** Whether this flow node corresponds to an import member */ - predicate isImportMember() { toAst(this) instanceof ImportMember } + predicate isImportMember() { toAst(this) instanceof Py::ImportMember } /** Whether this flow node corresponds to a call */ - predicate isCall() { toAst(this) instanceof Call } + predicate isCall() { toAst(this) instanceof Py::Call } /** Whether this flow node is the first in a module */ - predicate isModuleEntry() { this.isEntryNode() and toAst(this) instanceof Module } + predicate isModuleEntry() { this.isEntryNode() and toAst(this) instanceof Py::Module } /** Whether this flow node corresponds to an import */ - predicate isImport() { toAst(this) instanceof ImportExpr } + predicate isImport() { toAst(this) instanceof Py::ImportExpr } /** Whether this flow node corresponds to a conditional expression */ - predicate isIfExp() { toAst(this) instanceof IfExp } + predicate isIfExp() { toAst(this) instanceof Py::IfExp } /** Whether this flow node corresponds to a function definition expression */ - predicate isFunction() { toAst(this) instanceof FunctionExpr } + predicate isFunction() { toAst(this) instanceof Py::FunctionExpr } /** Whether this flow node corresponds to a class definition expression */ - predicate isClass() { toAst(this) instanceof ClassExpr } + predicate isClass() { toAst(this) instanceof Py::ClassExpr } /** Gets a predecessor of this flow node */ ControlFlowNode getAPredecessor() { this = result.getASuccessor() } @@ -123,25 +123,25 @@ class ControlFlowNode extends @py_flow_node { ControlFlowNode getImmediateDominator() { py_idoms(this, result) } /** Gets the syntactic element corresponding to this flow node */ - AstNode getNode() { py_flow_bb_node(this, result, _, _) } + Py::AstNode getNode() { py_flow_bb_node(this, result, _, _) } /** Gets a textual representation of this element. */ cached string toString() { Stages::AST::ref() and // Since modules can have ambigous names, entry nodes can too, if we do not collate them. - exists(Scope s | s.getEntryNode() = this | + exists(Py::Scope s | s.getEntryNode() = this | result = "Entry node for " + concat( | | s.toString(), ",") ) or - exists(Scope s | s.getANormalExit() = this | result = "Exit node for " + s.toString()) + exists(Py::Scope s | s.getANormalExit() = this | result = "Exit node for " + s.toString()) or - not exists(Scope s | s.getEntryNode() = this or s.getANormalExit() = this) and + not exists(Py::Scope s | s.getEntryNode() = this or s.getANormalExit() = this) and result = "ControlFlowNode for " + this.getNode().toString() } /** Gets the location of this ControlFlowNode */ - Location getLocation() { result = this.getNode().getLocation() } + Py::Location getLocation() { result = this.getNode().getLocation() } /** Whether this flow node is the first in its scope */ predicate isEntryNode() { py_scope_flow(this, _, -1) } @@ -151,9 +151,9 @@ class ControlFlowNode extends @py_flow_node { /** Gets the scope containing this flow node */ cached - Scope getScope() { + Py::Scope getScope() { Stages::AST::ref() and - if this.getNode() instanceof Scope + if this.getNode() instanceof Py::Scope then /* Entry or exit node */ result = this.getNode() @@ -161,7 +161,7 @@ class ControlFlowNode extends @py_flow_node { } /** Gets the enclosing module */ - Module getEnclosingModule() { result = this.getScope().getEnclosingModule() } + Py::Module getEnclosingModule() { result = this.getScope().getEnclosingModule() } /** Gets a successor for this node if the relevant condition is True. */ ControlFlowNode getATrueSuccessor() { @@ -188,7 +188,7 @@ class ControlFlowNode extends @py_flow_node { } /** Whether the scope may be exited as a result of this node raising an exception */ - predicate isExceptionalExit(Scope s) { py_scope_flow(this, s, 1) } + predicate isExceptionalExit(Py::Scope s) { py_scope_flow(this, s, 1) } /** Whether this node is a normal (non-exceptional) exit */ predicate isNormalExit() { py_scope_flow(this, _, 0) or py_scope_flow(this, _, 2) } @@ -236,7 +236,7 @@ class ControlFlowNode extends @py_flow_node { /* join-ordering helper for `getAChild() */ pragma[noinline] private ControlFlowNode getExprChild(BasicBlock dom) { - this.getNode().(Expr).getAChildNode() = result.getNode() and + this.getNode().(Py::Expr).getAChildNode() = result.getNode() and result.getBasicBlock().dominates(dom) and not this instanceof UnaryExprNode } @@ -249,16 +249,16 @@ class ControlFlowNode extends @py_flow_node { */ private class AnyNode extends ControlFlowNode { - override AstNode getNode() { result = super.getNode() } + override Py::AstNode getNode() { result = super.getNode() } } /** A control flow node corresponding to a call expression, such as `func(...)` */ class CallNode extends ControlFlowNode { - CallNode() { toAst(this) instanceof Call } + CallNode() { toAst(this) instanceof Py::Call } /** Gets the flow node corresponding to the function expression for the call corresponding to this flow node */ ControlFlowNode getFunction() { - exists(Call c | + exists(Py::Call c | this.getNode() = c and c.getFunc() = result.getNode() and result.getBasicBlock().dominates(this.getBasicBlock()) @@ -267,7 +267,7 @@ class CallNode extends ControlFlowNode { /** Gets the flow node corresponding to the n'th positional argument of the call corresponding to this flow node */ ControlFlowNode getArg(int n) { - exists(Call c | + exists(Py::Call c | this.getNode() = c and c.getArg(n) = result.getNode() and result.getBasicBlock().dominates(this.getBasicBlock()) @@ -276,7 +276,7 @@ class CallNode extends ControlFlowNode { /** Gets the flow node corresponding to the named argument of the call corresponding to this flow node */ ControlFlowNode getArgByName(string name) { - exists(Call c, Keyword k | + exists(Py::Call c, Py::Keyword k | this.getNode() = c and k = c.getANamedArg() and k.getValue() = result.getNode() and @@ -292,7 +292,7 @@ class CallNode extends ControlFlowNode { result = this.getArgByName(_) } - override Call getNode() { result = super.getNode() } + override Py::Call getNode() { result = super.getNode() } predicate isDecoratorCall() { this.isClassDecoratorCall() @@ -301,11 +301,11 @@ class CallNode extends ControlFlowNode { } predicate isClassDecoratorCall() { - exists(ClassExpr cls | this.getNode() = cls.getADecoratorCall()) + exists(Py::ClassExpr cls | this.getNode() = cls.getADecoratorCall()) } predicate isFunctionDecoratorCall() { - exists(FunctionExpr func | this.getNode() = func.getADecoratorCall()) + exists(Py::FunctionExpr func | this.getNode() = func.getADecoratorCall()) } /** Gets the first tuple (*) argument of this call, if any. */ @@ -323,11 +323,11 @@ class CallNode extends ControlFlowNode { /** A control flow corresponding to an attribute expression, such as `value.attr` */ class AttrNode extends ControlFlowNode { - AttrNode() { toAst(this) instanceof Attribute } + AttrNode() { toAst(this) instanceof Py::Attribute } /** Gets the flow node corresponding to the object of the attribute expression corresponding to this flow node */ ControlFlowNode getObject() { - exists(Attribute a | + exists(Py::Attribute a | this.getNode() = a and a.getObject() = result.getNode() and result.getBasicBlock().dominates(this.getBasicBlock()) @@ -339,7 +339,7 @@ class AttrNode extends ControlFlowNode { * with the matching name */ ControlFlowNode getObject(string name) { - exists(Attribute a | + exists(Py::Attribute a | this.getNode() = a and a.getObject() = result.getNode() and a.getName() = name and @@ -348,57 +348,57 @@ class AttrNode extends ControlFlowNode { } /** Gets the attribute name of the attribute expression corresponding to this flow node */ - string getName() { exists(Attribute a | this.getNode() = a and a.getName() = result) } + string getName() { exists(Py::Attribute a | this.getNode() = a and a.getName() = result) } - override Attribute getNode() { result = super.getNode() } + override Py::Attribute getNode() { result = super.getNode() } } /** A control flow node corresponding to a `from ... import ...` expression */ class ImportMemberNode extends ControlFlowNode { - ImportMemberNode() { toAst(this) instanceof ImportMember } + ImportMemberNode() { toAst(this) instanceof Py::ImportMember } /** * Gets the flow node corresponding to the module in the import-member expression corresponding to this flow node, * with the matching name */ ControlFlowNode getModule(string name) { - exists(ImportMember i | this.getNode() = i and i.getModule() = result.getNode() | + exists(Py::ImportMember i | this.getNode() = i and i.getModule() = result.getNode() | i.getName() = name and result.getBasicBlock().dominates(this.getBasicBlock()) ) } - override ImportMember getNode() { result = super.getNode() } + override Py::ImportMember getNode() { result = super.getNode() } } /** A control flow node corresponding to an artificial expression representing an import */ class ImportExprNode extends ControlFlowNode { - ImportExprNode() { toAst(this) instanceof ImportExpr } + ImportExprNode() { toAst(this) instanceof Py::ImportExpr } - override ImportExpr getNode() { result = super.getNode() } + override Py::ImportExpr getNode() { result = super.getNode() } } /** A control flow node corresponding to a `from ... import *` statement */ class ImportStarNode extends ControlFlowNode { - ImportStarNode() { toAst(this) instanceof ImportStar } + ImportStarNode() { toAst(this) instanceof Py::ImportStar } /** Gets the flow node corresponding to the module in the import-star corresponding to this flow node */ ControlFlowNode getModule() { - exists(ImportStar i | this.getNode() = i and i.getModuleExpr() = result.getNode() | + exists(Py::ImportStar i | this.getNode() = i and i.getModuleExpr() = result.getNode() | result.getBasicBlock().dominates(this.getBasicBlock()) ) } - override ImportStar getNode() { result = super.getNode() } + override Py::ImportStar getNode() { result = super.getNode() } } /** A control flow node corresponding to a subscript expression, such as `value[slice]` */ class SubscriptNode extends ControlFlowNode { - SubscriptNode() { toAst(this) instanceof Subscript } + SubscriptNode() { toAst(this) instanceof Py::Subscript } /** flow node corresponding to the value of the sequence in a subscript operation */ ControlFlowNode getObject() { - exists(Subscript s | + exists(Py::Subscript s | this.getNode() = s and s.getObject() = result.getNode() and result.getBasicBlock().dominates(this.getBasicBlock()) @@ -407,23 +407,23 @@ class SubscriptNode extends ControlFlowNode { /** flow node corresponding to the index in a subscript operation */ ControlFlowNode getIndex() { - exists(Subscript s | + exists(Py::Subscript s | this.getNode() = s and s.getIndex() = result.getNode() and result.getBasicBlock().dominates(this.getBasicBlock()) ) } - override Subscript getNode() { result = super.getNode() } + override Py::Subscript getNode() { result = super.getNode() } } /** A control flow node corresponding to a comparison operation, such as `x DeletionNode -> NameNode('b') -> AttrNode('y') -> DeletionNode`. */ class DeletionNode extends ControlFlowNode { - DeletionNode() { toAst(this) instanceof Delete } + DeletionNode() { toAst(this) instanceof Py::Delete } /** Gets the unique target of this deletion node. */ ControlFlowNode getTarget() { result.getASuccessor() = this } @@ -617,9 +617,9 @@ class DeletionNode extends ControlFlowNode { /** A control flow node corresponding to a sequence (tuple or list) literal */ abstract class SequenceNode extends ControlFlowNode { SequenceNode() { - toAst(this) instanceof Tuple + toAst(this) instanceof Py::Tuple or - toAst(this) instanceof List + toAst(this) instanceof Py::List } /** Gets the control flow node for an element of this sequence */ @@ -632,11 +632,11 @@ abstract class SequenceNode extends ControlFlowNode { /** A control flow node corresponding to a tuple expression such as `( 1, 3, 5, 7, 9 )` */ class TupleNode extends SequenceNode { - TupleNode() { toAst(this) instanceof Tuple } + TupleNode() { toAst(this) instanceof Py::Tuple } override ControlFlowNode getElement(int n) { Stages::AST::ref() and - exists(Tuple t | this.getNode() = t and result.getNode() = t.getElt(n)) and + exists(Py::Tuple t | this.getNode() = t and result.getNode() = t.getElt(n)) and ( result.getBasicBlock().dominates(this.getBasicBlock()) or @@ -647,10 +647,10 @@ class TupleNode extends SequenceNode { /** A control flow node corresponding to a list expression, such as `[ 1, 3, 5, 7, 9 ]` */ class ListNode extends SequenceNode { - ListNode() { toAst(this) instanceof List } + ListNode() { toAst(this) instanceof Py::List } override ControlFlowNode getElement(int n) { - exists(List l | this.getNode() = l and result.getNode() = l.getElt(n)) and + exists(Py::List l | this.getNode() = l and result.getNode() = l.getElt(n)) and ( result.getBasicBlock().dominates(this.getBasicBlock()) or @@ -661,10 +661,10 @@ class ListNode extends SequenceNode { /** A control flow node corresponding to a set expression, such as `{ 1, 3, 5, 7, 9 }` */ class SetNode extends ControlFlowNode { - SetNode() { toAst(this) instanceof Set } + SetNode() { toAst(this) instanceof Py::Set } ControlFlowNode getAnElement() { - exists(Set s | this.getNode() = s and result.getNode() = s.getElt(_)) and + exists(Py::Set s | this.getNode() = s and result.getNode() = s.getElt(_)) and ( result.getBasicBlock().dominates(this.getBasicBlock()) or @@ -675,20 +675,20 @@ class SetNode extends ControlFlowNode { /** A control flow node corresponding to a dictionary literal, such as `{ 'a': 1, 'b': 2 }` */ class DictNode extends ControlFlowNode { - DictNode() { toAst(this) instanceof Dict } + DictNode() { toAst(this) instanceof Py::Dict } /** * Gets a key of this dictionary literal node, for those items that have keys * E.g, in {'a':1, **b} this returns only 'a' */ ControlFlowNode getAKey() { - exists(Dict d | this.getNode() = d and result.getNode() = d.getAKey()) and + exists(Py::Dict d | this.getNode() = d and result.getNode() = d.getAKey()) and result.getBasicBlock().dominates(this.getBasicBlock()) } /** Gets a value of this dictionary literal node */ ControlFlowNode getAValue() { - exists(Dict d | this.getNode() = d and result.getNode() = d.getAValue()) and + exists(Py::Dict d | this.getNode() = d and result.getNode() = d.getAValue()) and result.getBasicBlock().dominates(this.getBasicBlock()) } } @@ -712,21 +712,23 @@ class IterableNode extends ControlFlowNode { } } -private AstNode assigned_value(Expr lhs) { +private Py::AstNode assigned_value(Py::Expr lhs) { /* lhs = result */ - exists(Assign a | a.getATarget() = lhs and result = a.getValue()) + exists(Py::Assign a | a.getATarget() = lhs and result = a.getValue()) or /* lhs := result */ - exists(AssignExpr a | a.getTarget() = lhs and result = a.getValue()) + exists(Py::AssignExpr a | a.getTarget() = lhs and result = a.getValue()) or /* lhs : annotation = result */ - exists(AnnAssign a | a.getTarget() = lhs and result = a.getValue()) + exists(Py::AnnAssign a | a.getTarget() = lhs and result = a.getValue()) or /* import result as lhs */ - exists(Alias a | a.getAsname() = lhs and result = a.getValue()) + exists(Py::Alias a | a.getAsname() = lhs and result = a.getValue()) or /* lhs += x => result = (lhs + x) */ - exists(AugAssign a, BinaryExpr b | b = a.getOperation() and result = b and lhs = b.getLeft()) + exists(Py::AugAssign a, Py::BinaryExpr b | + b = a.getOperation() and result = b and lhs = b.getLeft() + ) or /* * ..., lhs, ... = ..., result, ... @@ -734,31 +736,31 @@ private AstNode assigned_value(Expr lhs) { * ..., (..., lhs, ...), ... = ..., (..., result, ...), ... */ - exists(Assign a | nested_sequence_assign(a.getATarget(), a.getValue(), lhs, result)) + exists(Py::Assign a | nested_sequence_assign(a.getATarget(), a.getValue(), lhs, result)) or /* for lhs in seq: => `result` is the `for` node, representing the `iter(next(seq))` operation. */ - result.(For).getTarget() = lhs + result.(Py::For).getTarget() = lhs or - exists(Parameter param | lhs = param.asName() and result = param.getDefault()) + exists(Py::Parameter param | lhs = param.asName() and result = param.getDefault()) } predicate nested_sequence_assign( - Expr left_parent, Expr right_parent, Expr left_result, Expr right_result + Py::Expr left_parent, Py::Expr right_parent, Py::Expr left_result, Py::Expr right_result ) { - exists(Assign a | + exists(Py::Assign a | a.getATarget().getASubExpression*() = left_parent and a.getValue().getASubExpression*() = right_parent ) and - exists(int i, Expr left_elem, Expr right_elem | + exists(int i, Py::Expr left_elem, Py::Expr right_elem | ( - left_elem = left_parent.(Tuple).getElt(i) + left_elem = left_parent.(Py::Tuple).getElt(i) or - left_elem = left_parent.(List).getElt(i) + left_elem = left_parent.(Py::List).getElt(i) ) and ( - right_elem = right_parent.(Tuple).getElt(i) + right_elem = right_parent.(Py::Tuple).getElt(i) or - right_elem = right_parent.(List).getElt(i) + right_elem = right_parent.(Py::List).getElt(i) ) | left_result = left_elem and right_result = right_elem @@ -769,9 +771,9 @@ predicate nested_sequence_assign( /** A flow node for a `for` statement. */ class ForNode extends ControlFlowNode { - ForNode() { toAst(this) instanceof For } + ForNode() { toAst(this) instanceof Py::For } - override For getNode() { result = super.getNode() } + override Py::For getNode() { result = super.getNode() } /** Holds if this `for` statement causes iteration over `sequence` storing each step of the iteration in `target` */ predicate iterates(ControlFlowNode target, ControlFlowNode sequence) { @@ -782,7 +784,7 @@ class ForNode extends ControlFlowNode { /** Gets the sequence node for this `for` statement. */ ControlFlowNode getSequence() { - exists(For for | + exists(Py::For for | toAst(this) = for and for.getIter() = result.getNode() | @@ -792,7 +794,7 @@ class ForNode extends ControlFlowNode { /** A possible `target` for this `for` statement, not accounting for loop unrolling */ private ControlFlowNode possibleTarget() { - exists(For for | + exists(Py::For for | toAst(this) = for and for.getTarget() = result.getNode() and this.getBasicBlock().dominates(result.getBasicBlock()) @@ -809,11 +811,11 @@ class ForNode extends ControlFlowNode { /** A flow node for a `raise` statement */ class RaiseStmtNode extends ControlFlowNode { - RaiseStmtNode() { toAst(this) instanceof Raise } + RaiseStmtNode() { toAst(this) instanceof Py::Raise } /** Gets the control flow node for the exception raised by this raise statement */ ControlFlowNode getException() { - exists(Raise r | + exists(Py::Raise r | r = toAst(this) and r.getException() = toAst(result) and result.getBasicBlock().dominates(this.getBasicBlock()) @@ -827,36 +829,36 @@ class RaiseStmtNode extends ControlFlowNode { */ class NameNode extends ControlFlowNode { NameNode() { - exists(Name n | py_flow_bb_node(this, n, _, _)) + exists(Py::Name n | py_flow_bb_node(this, n, _, _)) or - exists(PlaceHolder p | py_flow_bb_node(this, p, _, _)) + exists(Py::PlaceHolder p | py_flow_bb_node(this, p, _, _)) } /** Whether this flow node defines the variable `v`. */ - predicate defines(Variable v) { - exists(Name d | this.getNode() = d and d.defines(v)) and + predicate defines(Py::Variable v) { + exists(Py::Name d | this.getNode() = d and d.defines(v)) and not this.isLoad() } /** Whether this flow node deletes the variable `v`. */ - predicate deletes(Variable v) { exists(Name d | this.getNode() = d and d.deletes(v)) } + predicate deletes(Py::Variable v) { exists(Py::Name d | this.getNode() = d and d.deletes(v)) } /** Whether this flow node uses the variable `v`. */ - predicate uses(Variable v) { + predicate uses(Py::Variable v) { this.isLoad() and - exists(Name u | this.getNode() = u and u.uses(v)) + exists(Py::Name u | this.getNode() = u and u.uses(v)) or - exists(PlaceHolder u | - this.getNode() = u and u.getVariable() = v and u.getCtx() instanceof Load + exists(Py::PlaceHolder u | + this.getNode() = u and u.getVariable() = v and u.getCtx() instanceof Py::Load ) or Scopes::use_of_global_variable(this, v.getScope(), v.getId()) } string getId() { - result = this.getNode().(Name).getId() + result = this.getNode().(Py::Name).getId() or - result = this.getNode().(PlaceHolder).getId() + result = this.getNode().(Py::PlaceHolder).getId() } /** Whether this is a use of a local variable. */ @@ -868,37 +870,39 @@ class NameNode extends ControlFlowNode { /** Whether this is a use of a global (including builtin) variable. */ predicate isGlobal() { Scopes::use_of_global_variable(this, _, _) } - predicate isSelf() { exists(SsaVariable selfvar | selfvar.isSelf() and selfvar.getAUse() = this) } + predicate isSelf() { + exists(Py::SsaVariable selfvar | selfvar.isSelf() and selfvar.getAUse() = this) + } } /** A control flow node corresponding to a named constant, one of `None`, `True` or `False`. */ class NameConstantNode extends NameNode { - NameConstantNode() { exists(NameConstant n | py_flow_bb_node(this, n, _, _)) } + NameConstantNode() { exists(Py::NameConstant n | py_flow_bb_node(this, n, _, _)) } /* * We ought to override uses as well, but that has * a serious performance impact. - * deprecated predicate uses(Variable v) { none() } + * deprecated predicate uses(Py::Variable v) { none() } */ } /** A control flow node corresponding to a starred expression, `*a`. */ class StarredNode extends ControlFlowNode { - StarredNode() { toAst(this) instanceof Starred } + StarredNode() { toAst(this) instanceof Py::Starred } - ControlFlowNode getValue() { toAst(result) = toAst(this).(Starred).getValue() } + ControlFlowNode getValue() { toAst(result) = toAst(this).(Py::Starred).getValue() } } /** The ControlFlowNode for an 'except' statement. */ class ExceptFlowNode extends ControlFlowNode { - ExceptFlowNode() { this.getNode() instanceof ExceptStmt } + ExceptFlowNode() { this.getNode() instanceof Py::ExceptStmt } /** * Gets the type handled by this exception handler. - * `ExceptionType` in `except ExceptionType as e:` + * `Py::ExceptionType` in `except Py::ExceptionType as e:` */ ControlFlowNode getType() { - exists(ExceptStmt ex | + exists(Py::ExceptStmt ex | this.getBasicBlock().dominates(result.getBasicBlock()) and ex = this.getNode() and result.getNode() = ex.getType() @@ -907,10 +911,10 @@ class ExceptFlowNode extends ControlFlowNode { /** * Gets the name assigned to the handled exception, if any. - * `e` in `except ExceptionType as e:` + * `e` in `except Py::ExceptionType as e:` */ ControlFlowNode getName() { - exists(ExceptStmt ex | + exists(Py::ExceptStmt ex | this.getBasicBlock().dominates(result.getBasicBlock()) and ex = this.getNode() and result.getNode() = ex.getName() @@ -920,30 +924,30 @@ class ExceptFlowNode extends ControlFlowNode { /** The ControlFlowNode for an 'except*' statement. */ class ExceptGroupFlowNode extends ControlFlowNode { - ExceptGroupFlowNode() { this.getNode() instanceof ExceptGroupStmt } + ExceptGroupFlowNode() { this.getNode() instanceof Py::ExceptGroupStmt } /** * Gets the type handled by this exception handler. - * `ExceptionType` in `except* ExceptionType as e:` + * `Py::ExceptionType` in `except* Py::ExceptionType as e:` */ ControlFlowNode getType() { this.getBasicBlock().dominates(result.getBasicBlock()) and - result.getNode() = this.getNode().(ExceptGroupStmt).getType() + result.getNode() = this.getNode().(Py::ExceptGroupStmt).getType() } /** * Gets the name assigned to the handled exception, if any. - * `e` in `except* ExceptionType as e:` + * `e` in `except* Py::ExceptionType as e:` */ ControlFlowNode getName() { this.getBasicBlock().dominates(result.getBasicBlock()) and - result.getNode() = this.getNode().(ExceptGroupStmt).getName() + result.getNode() = this.getNode().(Py::ExceptGroupStmt).getName() } } private module Scopes { private predicate fast_local(NameNode n) { - exists(FastLocalVariable v | + exists(Py::FastLocalVariable v | n.uses(v) and v.getScope() = n.getScope() ) @@ -952,15 +956,15 @@ private module Scopes { predicate local(NameNode n) { fast_local(n) or - exists(SsaVariable var | + exists(Py::SsaVariable var | var.getAUse() = n and - n.getScope() instanceof Class and + n.getScope() instanceof Py::Class and exists(var.getDefinition()) ) } predicate non_local(NameNode n) { - exists(FastLocalVariable flv | + exists(Py::FastLocalVariable flv | flv.getALoad() = n.getNode() and not flv.getScope() = n.getScope() ) @@ -968,20 +972,20 @@ private module Scopes { // magic is fine, but we get questionable join-ordering of it pragma[nomagic] - predicate use_of_global_variable(NameNode n, Module scope, string name) { + predicate use_of_global_variable(NameNode n, Py::Module scope, string name) { n.isLoad() and not non_local(n) and - not exists(SsaVariable var | var.getAUse() = n | - var.getVariable() instanceof FastLocalVariable + not exists(Py::SsaVariable var | var.getAUse() = n | + var.getVariable() instanceof Py::FastLocalVariable or - n.getScope() instanceof Class and + n.getScope() instanceof Py::Class and not maybe_undefined(var) ) and name = n.getId() and scope = n.getEnclosingModule() } - private predicate maybe_undefined(SsaVariable var) { + private predicate maybe_undefined(Py::SsaVariable var) { not exists(var.getDefinition()) and not py_ssa_phi(var, _) or var.getDefinition().isDelete() @@ -1058,13 +1062,13 @@ class BasicBlock extends @py_flow_node { private predicate oneNodeBlock() { this.firstNode() = this.getLastNode() } private predicate startLocationInfo(string file, int line, int col) { - if this.firstNode().getNode() instanceof Scope + if this.firstNode().getNode() instanceof Py::Scope then this.firstNode().getASuccessor().getLocation().hasLocationInfo(file, line, col, _, _) else this.firstNode().getLocation().hasLocationInfo(file, line, col, _, _) } private predicate endLocationInfo(int endl, int endc) { - if this.getLastNode().getNode() instanceof Scope and not this.oneNodeBlock() + if this.getLastNode().getNode() instanceof Py::Scope and not this.oneNodeBlock() then this.getLastNode().getAPredecessor().getLocation().hasLocationInfo(_, _, _, endl, endc) else this.getLastNode().getLocation().hasLocationInfo(_, _, _, endl, endc) } @@ -1081,7 +1085,7 @@ class BasicBlock extends @py_flow_node { /** Whether flow from this basic block reaches a normal exit from its scope */ predicate reachesExit() { - exists(Scope s | s.getANormalExit().getBasicBlock() = this) + exists(Py::Scope s | s.getANormalExit().getBasicBlock() = this) or this.getASuccessor().reachesExit() } @@ -1122,7 +1126,7 @@ class BasicBlock extends @py_flow_node { /** Gets the scope of this block */ pragma[nomagic] - Scope getScope() { + Py::Scope getScope() { exists(ControlFlowNode n | n.getBasicBlock() = this | /* Take care not to use an entry or exit node as that node's scope will be the outer scope */ not py_scope_flow(n, _, -1) and @@ -1145,17 +1149,17 @@ class BasicBlock extends @py_flow_node { predicate reaches(BasicBlock other) { this = other or this.strictlyReaches(other) } /** - * Gets the `ConditionBlock`, if any, that controls this block and - * does not control any other `ConditionBlock`s that control this block. - * That is the `ConditionBlock` that is closest dominator. + * Gets the `Py::ConditionBlock`, if any, that controls this block and + * does not control any other `Py::ConditionBlock`s that control this block. + * That is the `Py::ConditionBlock` that is closest dominator. */ - ConditionBlock getImmediatelyControllingBlock() { + Py::ConditionBlock getImmediatelyControllingBlock() { result = this.nonControllingImmediateDominator*().getImmediateDominator() } private BasicBlock nonControllingImmediateDominator() { result = this.getImmediateDominator() and - not result.(ConditionBlock).controls(this, _) + not result.(Py::ConditionBlock).controls(this, _) } /** @@ -1175,7 +1179,7 @@ private class ControlFlowNodeAlias = ControlFlowNode; final private class FinalBasicBlock = BasicBlock; -module Cfg implements BB::CfgSig { +module Cfg implements BB::CfgSig { private import codeql.controlflow.SuccessorType class ControlFlowNode = ControlFlowNodeAlias; @@ -1186,7 +1190,7 @@ module Cfg implements BB::CfgSig { // Using the location of the first node is simple // and we just need a way to identify the basic block // during debugging, so this will be serviceable. - Location getLocation() { result = super.getNode(0).getLocation() } + Py::Location getLocation() { result = super.getNode(0).getLocation() } int length() { result = count(int i | exists(this.getNode(i))) } diff --git a/python/ql/lib/semmle/python/Function.qll b/python/ql/lib/semmle/python/Function.qll index 2ef0366aa3b3..a25b17432c7d 100644 --- a/python/ql/lib/semmle/python/Function.qll +++ b/python/ql/lib/semmle/python/Function.qll @@ -2,6 +2,7 @@ overlay[local] module; import python +private import semmle.python.controlflow.internal.Cfg as Cfg /** * A function, independent of defaults and binding. @@ -157,12 +158,12 @@ class Function extends Function_, Scope, AstNode { * DEPRECATED: bind a `Return` node explicitly instead, e.g. * `exists(Return ret | ret.getScope() = this and n.getNode() = ret.getValue())`. * This API is being phased out together with `AstNode.getAFlowNode()` to - * untangle the AST and CFG hierarchies in preparation for migrating the - * dataflow library off the legacy CFG. + * untangle the AST and CFG hierarchies. * - * Gets a control flow node for a return value of this function. + * Gets a control flow node for a return value of this function, from the + * new (shared) CFG. */ - deprecated ControlFlowNode getAReturnValueFlowNode() { + deprecated Cfg::ControlFlowNode getAReturnValueFlowNode() { exists(Return ret | ret.getScope() = this and ret.getValue() = result.getNode() diff --git a/python/ql/lib/semmle/python/Import.qll b/python/ql/lib/semmle/python/Import.qll index 1e153a0de036..57736b6fff83 100644 --- a/python/ql/lib/semmle/python/Import.qll +++ b/python/ql/lib/semmle/python/Import.qll @@ -4,6 +4,7 @@ module; import python private import semmle.python.types.Builtins private import semmle.python.internal.CachedStages +private import semmle.python.controlflow.internal.Cfg as Cfg /** * An alias in an import statement, the `mod as name` part of `import mod as name`. May be artificial; @@ -163,7 +164,7 @@ class ImportMember extends ImportMember_ { result = this.getModule().(ImportExpr).getImportedModuleName() + "." + this.getName() } - deprecated override ImportMemberNode getAFlowNode() { result = super.getAFlowNode() } + deprecated override Cfg::ImportMemberNode getAFlowNode() { result = super.getAFlowNode() } } /** An import statement */ diff --git a/python/ql/lib/semmle/python/controlflow/internal/AstNodeImpl.qll b/python/ql/lib/semmle/python/controlflow/internal/AstNodeImpl.qll new file mode 100644 index 000000000000..50c110f217ef --- /dev/null +++ b/python/ql/lib/semmle/python/controlflow/internal/AstNodeImpl.qll @@ -0,0 +1,1701 @@ +/** + * Provides classes for the shared control-flow library, mediating between + * the Python AST and `AstSig`. + * + * The `Ast` module wraps Python's `Stmt`, `Expr`, `Scope`, and `Pattern`, + * and adds two synthetic kinds of node: + * - `BlockStmt`, identifying a body slot of a parent AST node (e.g. an + * `if`'s then or else branch). `Py::StmtList` itself is not directly + * wrapped. + * - Intermediate nodes for multi-operand boolean expressions. + */ +overlay[local?] +module; + +private import python as Py +private import codeql.controlflow.ControlFlowGraph +private import codeql.controlflow.SuccessorType +private import codeql.util.Void + +/** + * Gets the bound `Name` of a PEP 695 type parameter (`TypeVar`, + * `ParamSpec`, or `TypeVarTuple`). The base `TypeParameter` class does + * not expose `getName()`; this helper dispatches over the subtypes. + */ +private Py::Name typeParameterName(Py::TypeParameter tp) { + result = tp.(Py::TypeVar).getName() + or + result = tp.(Py::ParamSpec).getName() + or + result = tp.(Py::TypeVarTuple).getName() +} + +/** Provides the Python implementation of the shared CFG `AstSig`. */ +module Ast implements AstSig { + private newtype TAstNode = + TPyStmt(Py::Stmt s) or + TPyExpr(Py::Expr e) { not e instanceof Py::BoolExpr } or + TScope(Py::Scope sc) or + TPattern(Py::Pattern p) or + /** + * A synthetic node representing an operand pair of an `and`/`or` + * expression. For `a and b and c` (operands 0, 1, 2) we model the + * operation as a right-nested tree: pair 0 represents the whole + * expression with left=a and right=pair 1; pair 1 represents + * `b and c` with left=b and right=c. Each Python `Py::BoolExpr` + * with `n` operands has `n - 1` such pairs (indices `0 .. n - 2`). + */ + TBoolExprPair(Py::BoolExpr be, int index) { index = [0 .. count(be.getAValue()) - 2] } or + /** + * A synthetic block statement, wrapping a `Py::StmtList`. Each list of + * statements that represents an imperative block (a function/class/module + * body, an `if`/`while`/`for` branch, a `try`/`except`/`finally` body, + * etc.) becomes one `BlockStmt` node in the CFG. `Py::StmtList`s used + * in other roles - `Try.getHandlers()` (iterated via `getCatch`) and + * `MatchStmt.getCases()` (iterated via `getCase`) - are excluded, as + * the shared library's `Try`/`Switch` logic walks their items + * individually. + */ + TBlockStmt(Py::StmtList sl) { + not sl = any(Py::Try t).getHandlers() and + not sl = any(Py::MatchStmt m).getCases() + } + + /** + * The union of `TPyStmt` (wrapping `Py::Stmt`) and `TBlockStmt` (wrapping + * `Py::StmtList`). Both represent the kinds of node that can appear in + * a `Stmt` position in the CFG. + */ + private class TStmt = TPyStmt or TBlockStmt; + + /** + * The union of `TPyExpr` (wrapping non-boolean `Py::Expr`) and + * `TBoolExprPair` (synthetic operand pairs of `and`/`or` expressions). + * Both represent the kinds of node that can appear in an `Expr` + * position in the CFG. + */ + private class TExpr = TPyExpr or TBoolExprPair; + + /** + * An AST node visible to the shared CFG. + * + * This is the abstract implementation class. It enforces that each + * concrete subclass provides `toString`, `getLocation`, and + * `getEnclosingCallable` (one subclass per `TAstNode` newtype branch). + * The public alias `AstNode` is what users (and the `AstSig` signature) + * see; subclasses inside this module extend `AstNodeImpl` directly. + */ + abstract private class AstNodeImpl extends TAstNode { + /** Gets a textual representation of this AST node. */ + abstract string toString(); + + /** Gets the location of this AST node. */ + abstract Py::Location getLocation(); + + /** Gets the enclosing callable that contains this node, if any. */ + abstract Callable getEnclosingCallable(); + + /** Gets the underlying Python `Stmt`, if this node wraps one. */ + Py::Stmt asStmt() { this = TPyStmt(result) } + + /** + * Gets the underlying Python `Expr`, if this node wraps one. Boolean + * expressions are represented by `TBoolExprPair(_, 0)`; this + * predicate also recovers the underlying `Py::BoolExpr` from such a + * representation. + */ + Py::Expr asExpr() { + this = TPyExpr(result) + or + this = TBoolExprPair(result, 0) + } + + /** Gets the underlying Python `Scope`, if this node wraps one. */ + Py::Scope asScope() { this = TScope(result) } + + /** Gets the underlying Python `Pattern`, if this node wraps one. */ + Py::Pattern asPattern() { this = TPattern(result) } + + /** Gets the underlying Python `StmtList`, if this node is a `BlockStmt`. */ + Py::StmtList asStmtList() { this = TBlockStmt(result) } + + /** + * Gets the child of this AST node at the specified (zero-based) + * index, in evaluation order. Subclasses with children override + * this method. + */ + AstNode getChild(int index) { none() } + } + + /** An AST node visible to the shared CFG. */ + final class AstNode = AstNodeImpl; + + /** Gets the immediately enclosing callable that contains `node`. */ + Callable getEnclosingCallable(AstNode node) { result = node.getEnclosingCallable() } + + /** + * A callable: a function, class, or module scope. + * + * In Python, all three are executable scopes with statement bodies. + */ + class Callable extends AstNodeImpl, TScope { + private Py::Scope sc; + + Callable() { this = TScope(sc) } + + override string toString() { result = sc.toString() } + + override Py::Location getLocation() { result = sc.getLocation() } + + override Callable getEnclosingCallable() { result.asScope() = sc.getEnclosingScope() } + } + + /** Gets the body of callable `c`. */ + AstNode callableGetBody(Callable c) { result.asStmtList() = c.asScope().getBody() } + + /** + * A parameter of a callable. + * + * Modelled per the C# template (`csharp/.../ControlFlowGraph.qll:147-156`): + * each Python parameter (the `Py::Parameter` AST node, which is a `Name` + * or — Python 2 only — a `Tuple` in store context) becomes a CFG node + * at a stable position in the enclosing callable's entry sequence. + * + * Default-value expressions for positional and keyword-only parameters + * are wired separately on the `FunctionDefExpr` / `LambdaExpr` wrappers + * (they evaluate at function-definition time, not at call time). + * `Parameter::getDefaultValue()` returns `none()` here, signalling to + * the shared library that the parameter never falls back to a default + * during call binding. This mirrors C# for non-optional parameters. + */ + class Parameter extends Expr { + private Py::Parameter param; + + Parameter() { this = TPyExpr(param) } + + /** Gets the underlying Python parameter. */ + Py::Parameter asParameter() { result = param } + + /** + * Gets the default-value expression of this parameter, if any. + * + * Returns `none()`: defaults evaluate at function-definition time and + * are wired into the CFG via `FunctionDefExpr.getDefault` / + * `LambdaExpr.getDefault`. The shared library calls this predicate + * to model the "missing argument → evaluate default" fallback during + * call binding, which Python does not model at the CFG level. + */ + Expr getDefaultValue() { none() } + + /** + * Gets the pattern for this parameter. In Python, there is no destructuring + * pattern syntax for parameters, so the pattern is the parameter itself. + */ + AstNode getPattern() { result = this } + } + + /** + * Gets the `index`th parameter of callable `c`, ordered as Python binds + * them at call time: positional, then vararg (`*args`), then + * keyword-only, then kwarg (`**kwargs`). + */ + Parameter callableGetParameter(Callable c, int index) { + exists(Py::Function f | f = c.asScope() | + result.asParameter() = + rank[index + 1](Py::Parameter p, int subOrder, int subIndex | + // positional parameters first + p = f.getArg(subIndex) and subOrder = 0 + or + // then *args + p = f.getVararg() and subOrder = 1 and subIndex = 0 + or + // then keyword-only parameters + p = f.getKeywordOnlyArg(subIndex) and subOrder = 2 + or + // finally **kwargs + p = f.getKwarg() and subOrder = 3 and subIndex = 0 + | + p order by subOrder, subIndex + ) + ) + } + + /** A statement. */ + class Stmt extends AstNodeImpl, TStmt { + // For `TPyStmt` instances, delegate to the wrapped Python statement. + // `BlockStmt` (the only `TBlockStmt` subclass) provides its own overrides. + override string toString() { result = this.asStmt().toString() } + + override Py::Location getLocation() { result = this.asStmt().getLocation() } + + override Callable getEnclosingCallable() { result.asScope() = this.asStmt().getScope() } + } + + /** An expression. */ + class Expr extends AstNodeImpl, TExpr { + // For `TPyExpr` instances, delegate to the wrapped Python expression. + // `BinaryExpr` (the only `TBoolExprPair` subclass) provides its own overrides. + override string toString() { result = this.asExpr().toString() } + + override Py::Location getLocation() { result = this.asExpr().getLocation() } + + override Callable getEnclosingCallable() { result.asScope() = this.asExpr().getScope() } + } + + /** A pattern in a `match` statement. */ + additional class Pattern extends AstNodeImpl, TPattern { + private Py::Pattern p; + + Pattern() { this = TPattern(p) } + + override string toString() { result = p.toString() } + + override Py::Location getLocation() { result = p.getLocation() } + + override Callable getEnclosingCallable() { result.asScope() = p.getScope() } + } + + /** + * A `case x` pattern that binds `x` to the matched value. + */ + additional class MatchCapturePattern extends Pattern { + private Py::MatchCapturePattern cap; + + MatchCapturePattern() { this = TPattern(cap) } + + /** Gets the bound Name expression. */ + Expr getVariable() { result.asExpr() = cap.getVariable() } + + override AstNode getChild(int index) { index = 0 and result = this.getVariable() } + } + + /** + * A `case pattern as name` pattern. + */ + additional class MatchAsPattern extends Pattern { + private Py::MatchAsPattern asp; + + MatchAsPattern() { this = TPattern(asp) } + + /** Gets the inner pattern. */ + AstNode getPattern() { result.asPattern() = asp.getPattern() } + + /** Gets the bound Name expression. */ + Expr getAlias() { result.asExpr() = asp.getAlias() } + + override AstNode getChild(int index) { + index = 0 and result = this.getPattern() + or + index = 1 and result = this.getAlias() + } + } + + /** + * A `case [a, b, *rest]` star pattern. Binds `rest` to the remaining + * elements of the sequence. + */ + additional class MatchStarPattern extends Pattern { + private Py::MatchStarPattern starp; + + MatchStarPattern() { this = TPattern(starp) } + + /** Gets the target Pattern (a `MatchCapturePattern` if `*rest`). */ + AstNode getTarget() { result.asPattern() = starp.getTarget() } + + override AstNode getChild(int index) { index = 0 and result = this.getTarget() } + } + + /** + * A `case [a, b, ...]` sequence pattern. Recurses into the sub-patterns. + */ + additional class MatchSequencePattern extends Pattern { + private Py::MatchSequencePattern seqp; + + MatchSequencePattern() { this = TPattern(seqp) } + + /** Gets the `n`th sub-pattern. */ + AstNode getPattern(int n) { result.asPattern() = seqp.getPattern(n) } + + override AstNode getChild(int index) { result = this.getPattern(index) } + } + + /** + * A `case Cls(a, b, x=y)` class pattern. + */ + additional class MatchClassPattern extends Pattern { + private Py::MatchClassPattern clsp; + + MatchClassPattern() { this = TPattern(clsp) } + + /** Gets the class expression of this class pattern. */ + Expr getClass() { result.asExpr() = clsp.getClass() } + + /** Gets the `n`th positional sub-pattern. */ + AstNode getPositional(int n) { result.asPattern() = clsp.getPositional(n) } + + /** Gets the `n`th keyword sub-pattern. */ + AstNode getKeyword(int n) { result.asPattern() = clsp.getKeyword(n) } + + private int numPositional() { result = count(int i | exists(clsp.getPositional(i))) } + + override AstNode getChild(int index) { + index = 0 and result = this.getClass() + or + result = this.getPositional(index - 1) and index >= 1 + or + result = this.getKeyword(index - 1 - this.numPositional()) and + index >= 1 + this.numPositional() + } + } + + /** + * A `case {k: v}` mapping pattern. + */ + additional class MatchMappingPattern extends Pattern { + private Py::MatchMappingPattern mapp; + + MatchMappingPattern() { this = TPattern(mapp) } + + AstNode getMapping(int n) { result.asPattern() = mapp.getMapping(n) } + + override AstNode getChild(int index) { result = this.getMapping(index) } + } + + /** + * A key-value pair inside a `case {k: v}` mapping pattern. + */ + additional class MatchKeyValuePattern extends Pattern { + private Py::MatchKeyValuePattern kvp; + + MatchKeyValuePattern() { this = TPattern(kvp) } + + AstNode getKey() { result.asPattern() = kvp.getKey() } + + AstNode getValue() { result.asPattern() = kvp.getValue() } + + override AstNode getChild(int index) { + index = 0 and result = this.getKey() + or + index = 1 and result = this.getValue() + } + } + + /** + * A `case Cls(name=value)` keyword sub-pattern. + */ + additional class MatchKeywordPattern extends Pattern { + private Py::MatchKeywordPattern kwp; + + MatchKeywordPattern() { this = TPattern(kwp) } + + Expr getAttribute() { result.asExpr() = kwp.getAttribute() } + + AstNode getValue() { result.asPattern() = kwp.getValue() } + + override AstNode getChild(int index) { + index = 0 and result = this.getAttribute() + or + index = 1 and result = this.getValue() + } + } + + /** A `case **rest` double-star mapping sub-pattern. */ + additional class MatchDoubleStarPattern extends Pattern { + private Py::MatchDoubleStarPattern dsp; + + MatchDoubleStarPattern() { this = TPattern(dsp) } + + AstNode getTarget() { result.asPattern() = dsp.getTarget() } + + override AstNode getChild(int index) { index = 0 and result = this.getTarget() } + } + + /** A `case p1 | p2 | …` or-pattern. */ + additional class MatchOrPattern extends Pattern { + private Py::MatchOrPattern orp; + + MatchOrPattern() { this = TPattern(orp) } + + AstNode getPattern(int n) { result.asPattern() = orp.getPattern(n) } + + override AstNode getChild(int index) { result = this.getPattern(index) } + } + + /** A `case 1` literal pattern. */ + additional class MatchLiteralPattern extends Pattern { + private Py::MatchLiteralPattern litp; + + MatchLiteralPattern() { this = TPattern(litp) } + + Expr getLiteral() { result.asExpr() = litp.getLiteral() } + + override AstNode getChild(int index) { index = 0 and result = this.getLiteral() } + } + + /** A `case Cls.NAME` value pattern. */ + additional class MatchValuePattern extends Pattern { + private Py::MatchValuePattern vp; + + MatchValuePattern() { this = TPattern(vp) } + + Expr getValue() { result.asExpr() = vp.getValue() } + + override AstNode getChild(int index) { index = 0 and result = this.getValue() } + } + + /** + * A block statement, modeling the body of a parent AST node as a + * sequence of statements. + */ + class BlockStmt extends Stmt, TBlockStmt { + private Py::StmtList sl; + + BlockStmt() { this = TBlockStmt(sl) } + + /** Gets the `n`th (zero-based) statement in this block. */ + Stmt getStmt(int n) { result.asStmt() = sl.getItem(n) } + + /** Gets the last statement in this block. */ + Stmt getLastStmt() { result.asStmt() = sl.getLastItem() } + + override string toString() { result = sl.toString() } + + // `Py::StmtList` has no native location; approximate with the first + // item's location. + override Py::Location getLocation() { result = sl.getItem(0).getLocation() } + + override Callable getEnclosingCallable() { + result.asScope() = sl.getParent().(Py::Scope) + or + result.asScope() = sl.getParent().(Py::Stmt).getScope() + } + + override AstNode getChild(int index) { result = this.getStmt(index) } + } + + /** An expression statement. */ + class ExprStmt extends Stmt { + private Py::ExprStmt exprStmt; + + ExprStmt() { this = TPyStmt(exprStmt) } + + /** Gets the expression in this expression statement. */ + Expr getExpr() { result.asExpr() = exprStmt.getValue() } + + override AstNode getChild(int index) { index = 0 and result = this.getExpr() } + } + + /** An assignment statement (`x = y = expr`). */ + additional class AssignStmt extends Stmt { + private Py::Assign assign; + + AssignStmt() { this = TPyStmt(assign) } + + Expr getValue() { result.asExpr() = assign.getValue() } + + Expr getTarget(int n) { result.asExpr() = assign.getTarget(n) } + + int getNumberOfTargets() { result = count(assign.getATarget()) } + + override AstNode getChild(int index) { + index = 0 and result = this.getValue() + or + result = this.getTarget(index - 1) and index >= 1 + } + } + + /** An augmented assignment statement (`x += expr`). */ + additional class AugAssignStmt extends Stmt { + private Py::AugAssign augAssign; + + AugAssignStmt() { this = TPyStmt(augAssign) } + + Expr getOperation() { result.asExpr() = augAssign.getOperation() } + + override AstNode getChild(int index) { index = 0 and result = this.getOperation() } + } + + /** + * An annotated assignment statement (`x: T = expr`, or `x: T` without + * value). The evaluation order follows CPython: annotation first, then + * the optional value, then the target binding. + */ + additional class AnnAssignStmt extends Stmt { + private Py::AnnAssign annAssign; + + AnnAssignStmt() { this = TPyStmt(annAssign) } + + Expr getAnnotation() { result.asExpr() = annAssign.getAnnotation() } + + Expr getValue() { result.asExpr() = annAssign.getValue() } + + Expr getTarget() { result.asExpr() = annAssign.getTarget() } + + override AstNode getChild(int index) { + index = 0 and result = this.getAnnotation() + or + index = 1 and result = this.getValue() + or + index = 2 and result = this.getTarget() + } + } + + /** An assignment expression / walrus operator (`x := expr`). */ + additional class NamedExpr extends Expr { + private Py::AssignExpr assignExpr; + + NamedExpr() { this = TPyExpr(assignExpr) } + + Expr getValue() { result.asExpr() = assignExpr.getValue() } + + Expr getTarget() { result.asExpr() = assignExpr.getTarget() } + + override AstNode getChild(int index) { + index = 0 and result = this.getValue() + or + index = 1 and result = this.getTarget() + } + } + + /** + * An `if` statement. + * + * Python's `elif` chains are represented as nested `If` nodes in the + * else branch's `StmtList`. The shared CFG library handles this + * naturally: `getElse()` returns the `BlockStmt` wrapping the else + * branch, and if that block contains a single `If`, the result is + * a chained conditional. + */ + class IfStmt extends Stmt { + private Py::If ifStmt; + + IfStmt() { this = TPyStmt(ifStmt) } + + /** Gets the underlying Python `If` statement. */ + Py::If asIf() { result = ifStmt } + + /** Gets the condition of this `if` statement. */ + Expr getCondition() { result.asExpr() = ifStmt.getTest() } + + /** Gets the `then` (true) branch of this `if` statement. */ + Stmt getThen() { result.asStmtList() = ifStmt.getBody() } + + /** Gets the `else` (false) branch, if any. */ + Stmt getElse() { result.asStmtList() = ifStmt.getOrelse() } + + override AstNode getChild(int index) { + index = 0 and result = this.getCondition() + or + index = 1 and result = this.getThen() + or + index = 2 and result = this.getElse() + } + } + + /** A loop statement. */ + class LoopStmt extends Stmt { + LoopStmt() { + this = TPyStmt(any(Py::While w)) + or + this = TPyStmt(any(Py::For f)) + } + + /** Gets the body of this loop statement. */ + Stmt getBody() { none() } + } + + /** A `while` loop statement. */ + class WhileStmt extends LoopStmt { + private Py::While whileStmt; + + WhileStmt() { this = TPyStmt(whileStmt) } + + /** Gets the boolean condition of this `while` loop. */ + Expr getCondition() { result.asExpr() = whileStmt.getTest() } + + override Stmt getBody() { result.asStmtList() = whileStmt.getBody() } + + /** Gets the `else` branch of this `while` loop, if any. */ + Stmt getElse() { result.asStmtList() = whileStmt.getOrelse() } + + override AstNode getChild(int index) { + index = 0 and result = this.getCondition() + or + index = 1 and result = this.getBody() + or + index = 2 and result = this.getElse() + } + } + + /** + * A `do-while` loop statement. Python has no do-while construct. + */ + class DoStmt extends LoopStmt { + DoStmt() { none() } + + Expr getCondition() { none() } + } + + /** An `until` loop. Python has no `until` loop. */ + class UntilStmt extends LoopStmt { + UntilStmt() { none() } + + Expr getCondition() { none() } + } + + /** A C-style `for` loop. Python has no C-style for loop. */ + class ForStmt extends LoopStmt { + ForStmt() { none() } + + AstNode getInit(int index) { none() } + + Expr getCondition() { none() } + + AstNode getUpdate(int index) { none() } + } + + /** A for-each loop (`for x in iterable:`). */ + class ForeachStmt extends LoopStmt { + private Py::For forStmt; + + ForeachStmt() { this = TPyStmt(forStmt) } + + /** Gets the loop variable. */ + Expr getVariable() { result.asExpr() = forStmt.getTarget() } + + /** Gets the collection being iterated. */ + Expr getCollection() { result.asExpr() = forStmt.getIter() } + + override Stmt getBody() { result.asStmtList() = forStmt.getBody() } + + /** Gets the `else` branch of this `for` loop, if any. */ + Stmt getElse() { result.asStmtList() = forStmt.getOrelse() } + + override AstNode getChild(int index) { + index = 0 and result = this.getCollection() + or + index = 1 and result = this.getVariable() + or + index = 2 and result = this.getBody() + or + index = 3 and result = this.getElse() + } + } + + /** A `break` statement. */ + class BreakStmt extends Stmt { + BreakStmt() { this = TPyStmt(any(Py::Break b)) } + } + + /** A `continue` statement. */ + class ContinueStmt extends Stmt { + ContinueStmt() { this = TPyStmt(any(Py::Continue c)) } + } + + /** A `goto` statement. Python has no goto. */ + class GotoStmt extends Stmt { + GotoStmt() { none() } + } + + /** A `return` statement. */ + class ReturnStmt extends Stmt { + private Py::Return ret; + + ReturnStmt() { this = TPyStmt(ret) } + + /** Gets the expression being returned, if any. */ + Expr getExpr() { result.asExpr() = ret.getValue() } + + override AstNode getChild(int index) { index = 0 and result = this.getExpr() } + } + + /** A `raise` statement (mapped to `Throw`). */ + class Throw extends Stmt { + private Py::Raise raise; + + Throw() { this = TPyStmt(raise) } + + /** Gets the expression being raised. */ + Expr getExpr() { result.asExpr() = raise.getException() } + + /** Gets the cause of this `raise`, if any. */ + Expr getCause() { result.asExpr() = raise.getCause() } + + override AstNode getChild(int index) { + index = 0 and result = this.getExpr() + or + index = 1 and result = this.getCause() + } + } + + /** + * An `import` statement (`import a, b` or `from m import a, b`). + * + * Each alias contributes two children in evaluation order: first the + * value expression (which performs the import side-effect), then the + * bound `asname` Name (the in-scope binding). This makes both reachable + * from the CFG and allows `Name.defines(v)` for `asname` Names to have + * corresponding CFG nodes — which is essential for SSA to see import + * bindings. + */ + additional class ImportStmt extends Stmt { + private Py::Import imp; + + ImportStmt() { this = TPyStmt(imp) } + + /** Gets the value (module/member expression) of the `n`th alias. */ + Expr getValue(int n) { result.asExpr() = imp.getName(n).getValue() } + + /** Gets the bound `asname` of the `n`th alias. */ + Expr getAsname(int n) { result.asExpr() = imp.getName(n).getAsname() } + + /** Gets the number of aliases in this import statement. */ + int getNumberOfAliases() { result = count(int i | exists(imp.getName(i))) } + + override AstNode getChild(int index) { + exists(int i | + index = 2 * i and result = this.getValue(i) + or + index = 2 * i + 1 and result = this.getAsname(i) + ) + } + } + + /** + * A `from m import *` statement. Evaluates the module expression but + * binds no name (the bindings happen by side-effect at runtime, which + * is not modelled at the CFG level). + */ + additional class ImportStarStmt extends Stmt { + private Py::ImportStar imp; + + ImportStarStmt() { this = TPyStmt(imp) } + + Expr getModule() { result.asExpr() = imp.getModule() } + + override AstNode getChild(int index) { index = 0 and result = this.getModule() } + } + + /** A `with` statement. */ + additional class WithStmt extends Stmt { + private Py::With withStmt; + + WithStmt() { this = TPyStmt(withStmt) } + + Expr getContextExpr() { result.asExpr() = withStmt.getContextExpr() } + + Expr getOptionalVars() { result.asExpr() = withStmt.getOptionalVars() } + + Stmt getBody() { result.asStmtList() = withStmt.getBody() } + + override AstNode getChild(int index) { + index = 0 and result = this.getContextExpr() + or + index = 1 and result = this.getOptionalVars() + or + index = 2 and result = this.getBody() + } + } + + /** An `assert` statement. */ + additional class AssertStmt extends Stmt { + private Py::Assert assertStmt; + + AssertStmt() { this = TPyStmt(assertStmt) } + + Expr getTest() { result.asExpr() = assertStmt.getTest() } + + Expr getMsg() { result.asExpr() = assertStmt.getMsg() } + + override AstNode getChild(int index) { + index = 0 and result = this.getTest() + or + index = 1 and result = this.getMsg() + } + } + + /** A `delete` statement. */ + additional class DeleteStmt extends Stmt { + private Py::Delete del; + + DeleteStmt() { this = TPyStmt(del) } + + Expr getTarget(int n) { result.asExpr() = del.getTarget(n) } + + override AstNode getChild(int index) { result = this.getTarget(index) } + } + + /** + * A PEP 695 `type` statement (`type Alias[T1, T2] = value`). + * + * The type parameters bind at statement-evaluation time. The value + * expression is captured for lazy evaluation but the alias `Name` + * itself binds the resulting `TypeAliasType` object — so the CFG must + * visit at minimum the type-parameter names and the alias name. + */ + additional class TypeAliasStmt extends Stmt { + private Py::TypeAlias ta; + + TypeAliasStmt() { this = TPyStmt(ta) } + + /** Gets the alias `Name` bound by this statement. */ + Expr getName() { result.asExpr() = ta.getName() } + + /** + * Gets the `n`th PEP 695 type-parameter name (a `Name` in store + * context), in declaration order. + */ + Expr getTypeParamName(int n) { result.asExpr() = typeParameterName(ta.getTypeParameter(n)) } + + int getNumberOfTypeParams() { result = count(ta.getATypeParameter()) } + + override AstNode getChild(int index) { + result = this.getTypeParamName(index) + or + index = this.getNumberOfTypeParams() and result = this.getName() + } + } + + /** A `try` statement. */ + class TryStmt extends Stmt { + private Py::Try tryStmt; + + TryStmt() { this = TPyStmt(tryStmt) } + + AstNode getBody(int index) { index = 0 and result.asStmtList() = tryStmt.getBody() } + + /** Gets the `else` branch of this `try` statement, if any. */ + Stmt getElse() { result.asStmtList() = tryStmt.getOrelse() } + + Stmt getFinally() { result.asStmtList() = tryStmt.getFinalbody() } + + CatchClause getCatch(int index) { result.asStmt() = tryStmt.getHandler(index) } + + override AstNode getChild(int index) { + index = 0 and result = this.getBody(0) + or + result = this.getCatch(index - 1) and index >= 1 + or + index = -1 and result = this.getFinally() + or + index = -2 and result = this.getElse() + } + } + + /** + * Gets the `else` branch of `try` statement `try`, if any. + */ + AstNode getTryElse(TryStmt try) { result = try.getElse() } + + /** + * Gets the `else` branch of `while` loop `loop`, if any. + */ + AstNode getWhileElse(WhileStmt loop) { result = loop.getElse() } + + /** + * Gets the `else` branch of `for` loop `loop`, if any. + */ + AstNode getForeachElse(ForeachStmt loop) { result = loop.getElse() } + + /** + * Gets the type expression of catch clause `catch`, if any. + */ + Expr getCatchType(CatchClause catch) { result = catch.getType() } + + /** An exception handler (`except` or `except*`). */ + class CatchClause extends Stmt { + private Py::ExceptionHandler handler; + + CatchClause() { this = TPyStmt(handler) } + + /** Gets the type expression of this exception handler. */ + Expr getType() { result.asExpr() = handler.getType() } + + /** Gets the variable name of this exception handler, if any. */ + AstNode getVariable() { result.asExpr() = handler.getName() } + + /** Holds: catch clauses do not have a `Condition` in Python's model. */ + Expr getCondition() { none() } + + /** Gets the body of this exception handler. */ + Stmt getBody() { + result.asStmtList() = handler.(Py::ExceptStmt).getBody() + or + result.asStmtList() = handler.(Py::ExceptGroupStmt).getBody() + } + + override AstNode getChild(int index) { + index = 0 and result = this.getType() + or + index = 1 and result = this.getVariable() + or + index = 2 and result = this.getBody() + } + } + + /** A `match` statement, mapped to the shared CFG's `Switch`. */ + class Switch extends Stmt { + private Py::MatchStmt matchStmt; + + Switch() { this = TPyStmt(matchStmt) } + + Expr getExpr() { result.asExpr() = matchStmt.getSubject() } + + Case getCase(int index) { result.asStmt() = matchStmt.getCase(index) } + + Stmt getStmt(int index) { none() } + + override AstNode getChild(int index) { + index = 0 and result = this.getExpr() + or + result = this.getCase(index - 1) and index >= 1 + } + } + + /** A `case` clause in a match statement. */ + class Case extends Stmt { + private Py::Case caseStmt; + + Case() { this = TPyStmt(caseStmt) } + + AstNode getPattern(int index) { index = 0 and result.asPattern() = caseStmt.getPattern() } + + Expr getGuard() { result.asExpr() = caseStmt.getGuard().(Py::Guard).getTest() } + + AstNode getBody() { result.asStmtList() = caseStmt.getBody() } + + /** Holds if this case is a wildcard pattern (`case _:`). */ + predicate isWildcard() { caseStmt.getPattern() instanceof Py::MatchWildcardPattern } + + override AstNode getChild(int index) { + index = 0 and result = this.getPattern(0) + or + index = 1 and result = this.getGuard() + or + index = 2 and result = this.getBody() + } + } + + /** A wildcard case (`case _:`). */ + class DefaultCase extends Case { + DefaultCase() { this.isWildcard() } + } + + /** A conditional expression (`x if cond else y`). */ + class ConditionalExpr extends Expr { + private Py::IfExp ifExp; + + ConditionalExpr() { this = TPyExpr(ifExp) } + + /** Gets the condition of this expression. */ + Expr getCondition() { result.asExpr() = ifExp.getTest() } + + /** Gets the true branch of this expression. */ + Expr getThen() { result.asExpr() = ifExp.getBody() } + + /** Gets the false branch of this expression. */ + Expr getElse() { result.asExpr() = ifExp.getOrelse() } + + override AstNode getChild(int index) { + index = 0 and result = this.getCondition() + or + index = 1 and result = this.getThen() + or + index = 2 and result = this.getElse() + } + } + + /** + * A binary expression for the shared CFG. In Python, this covers all + * `and`/`or` expression operand pairs. + */ + class BinaryExpr extends Expr, TBoolExprPair { + private Py::BoolExpr be; + private int index; + + BinaryExpr() { this = TBoolExprPair(be, index) } + + /** Gets the underlying Python `BoolExpr`. */ + Py::BoolExpr getBoolExpr() { result = be } + + /** Gets the (zero-based) index of this pair within its `BoolExpr`. */ + int getIndex() { result = index } + + override string toString() { result = be.getOperator() } + + override Py::Location getLocation() { result = be.getValue(index).getLocation() } + + override Callable getEnclosingCallable() { result.asScope() = be.getScope() } + + /** Gets the left operand of this binary expression. */ + Expr getLeftOperand() { result.asExpr() = be.getValue(index) } + + /** Gets the right operand of this binary expression. */ + Expr getRightOperand() { + // Last pair: right operand is the final value. + index = count(be.getAValue()) - 2 and result.asExpr() = be.getValue(index + 1) + or + // Non-last pair: right operand is the next synthetic pair. + index < count(be.getAValue()) - 2 and + exists(BinaryExpr next | + next.getBoolExpr() = be and next.getIndex() = index + 1 and result = next + ) + } + + override AstNode getChild(int childIndex) { + childIndex = 0 and result = this.getLeftOperand() + or + childIndex = 1 and result = this.getRightOperand() + } + } + + /** A short-circuiting logical `and` expression. */ + class LogicalAndExpr extends BinaryExpr { + LogicalAndExpr() { this.getBoolExpr().getOp() instanceof Py::And } + } + + /** A short-circuiting logical `or` expression. */ + class LogicalOrExpr extends BinaryExpr { + LogicalOrExpr() { this.getBoolExpr().getOp() instanceof Py::Or } + } + + /** A null-coalescing expression. Python has no null-coalescing operator. */ + class NullCoalescingExpr extends BinaryExpr { + NullCoalescingExpr() { none() } + } + + /** + * A unary expression. Currently only used for the `not` subclass. + */ + class UnaryExpr extends Expr { + UnaryExpr() { exists(Py::UnaryExpr u | this = TPyExpr(u) and u.getOp() instanceof Py::Not) } + + /** Gets the operand of this unary expression. */ + Expr getOperand() { result.asExpr() = this.asExpr().(Py::UnaryExpr).getOperand() } + + override AstNode getChild(int index) { index = 0 and result = this.getOperand() } + } + + /** A logical `not` expression. */ + class LogicalNotExpr extends UnaryExpr { } + + /** + * An assignment expression. + * + * Empty in Python: `x = y` and `x += y` are statements (`AssignStmt` and + * `AugAssignStmt`), not expressions, and the walrus `x := y` is modeled + * separately as `NamedExpr`. The shared library's `Assignment` extends + * `BinaryExpr`, so it cannot share instances with our `Stmt`-based + * assignment forms. + */ + class Assignment extends BinaryExpr { + Assignment() { none() } + } + + /** A simple assignment expression. Empty in Python (see `Assignment`). */ + class AssignExpr extends Assignment { } + + /** A compound assignment expression. Empty in Python (see `Assignment`). */ + class CompoundAssignment extends Assignment { } + + /** + * A short-circuiting logical AND compound assignment expression (`&&=`). + * Python has no such operator. + */ + class AssignLogicalAndExpr extends CompoundAssignment { } + + /** + * A short-circuiting logical OR compound assignment expression (`||=`). + * Python has no such operator. + */ + class AssignLogicalOrExpr extends CompoundAssignment { } + + /** + * A short-circuiting null-coalescing compound assignment expression + * (`??=`). Python has no such operator. + */ + class AssignNullCoalescingExpr extends CompoundAssignment { } + + /** A boolean literal expression (`True` or `False`). */ + class BooleanLiteral extends Expr { + BooleanLiteral() { this = TPyExpr(any(Py::True t)) or this = TPyExpr(any(Py::False f)) } + + /** Gets the boolean value of this literal. */ + boolean getValue() { + this.asExpr() instanceof Py::True and result = true + or + this.asExpr() instanceof Py::False and result = false + } + } + + /** A pattern match expression. Python has no `instanceof`-style pattern match expression. */ + class PatternMatchExpr extends Expr { + PatternMatchExpr() { none() } + + Expr getExpr() { none() } + + AstNode getPattern() { none() } + } + + // ===== Python-specific expression classes (used by `getChild`) ===== + /** A Python binary expression (arithmetic, bitwise, matmul, etc.). */ + additional class ArithBinaryExpr extends Expr { + private Py::BinaryExpr binExpr; + + ArithBinaryExpr() { this = TPyExpr(binExpr) } + + Expr getLeft() { result.asExpr() = binExpr.getLeft() } + + Expr getRight() { result.asExpr() = binExpr.getRight() } + + override AstNode getChild(int index) { + index = 0 and result = this.getLeft() + or + index = 1 and result = this.getRight() + } + } + + /** A call expression (`func(args...)`). */ + additional class CallExpr extends Expr { + private Py::Call call; + + CallExpr() { this = TPyExpr(call) } + + Expr getFunc() { result.asExpr() = call.getFunc() } + + Expr getPositionalArg(int n) { result.asExpr() = call.getPositionalArg(n) } + + int getNumberOfPositionalArgs() { result = count(call.getAPositionalArg()) } + + Expr getKeywordValue(int n) { + result.asExpr() = call.getNamedArg(n).(Py::Keyword).getValue() + or + result.asExpr() = call.getNamedArg(n).(Py::DictUnpacking).getValue() + } + + int getNumberOfNamedArgs() { result = count(call.getANamedArg()) } + + override AstNode getChild(int index) { + index = 0 and result = this.getFunc() + or + result = this.getPositionalArg(index - 1) and index >= 1 + or + result = this.getKeywordValue(index - 1 - this.getNumberOfPositionalArgs()) and + index >= 1 + this.getNumberOfPositionalArgs() + } + } + + /** A subscript expression (`obj[index]`). */ + additional class SubscriptExpr extends Expr { + private Py::Subscript sub; + + SubscriptExpr() { this = TPyExpr(sub) } + + Expr getObject() { result.asExpr() = sub.getObject() } + + Expr getIndex() { result.asExpr() = sub.getIndex() } + + override AstNode getChild(int index) { + index = 0 and result = this.getObject() + or + index = 1 and result = this.getIndex() + } + } + + /** An attribute access (`obj.name`). */ + additional class AttributeExpr extends Expr { + private Py::Attribute attr; + + AttributeExpr() { this = TPyExpr(attr) } + + Expr getObject() { result.asExpr() = attr.getObject() } + + override AstNode getChild(int index) { index = 0 and result = this.getObject() } + } + + /** + * An `import x.y` module expression. Modelled as a leaf — the dotted + * name is just a string. + */ + additional class ImportExpression extends Expr { + ImportExpression() { this.asExpr() instanceof Py::ImportExpr } + } + + /** + * A `from m import x` member access. The module sub-expression is a + * child so that the CFG visits both the module load and this + * attribute selection. + */ + additional class ImportMemberExpr extends Expr { + private Py::ImportMember im; + + ImportMemberExpr() { this = TPyExpr(im) } + + /** Gets the module expression `m` in `from m import x`. */ + Expr getModule() { result.asExpr() = im.getModule() } + + override AstNode getChild(int index) { index = 0 and result = this.getModule() } + } + + /** A tuple literal. */ + additional class TupleExpr extends Expr { + private Py::Tuple tuple; + + TupleExpr() { this = TPyExpr(tuple) } + + Expr getElt(int n) { result.asExpr() = tuple.getElt(n) } + + override AstNode getChild(int index) { result = this.getElt(index) } + } + + /** A list literal. */ + additional class ListExpr extends Expr { + private Py::List list; + + ListExpr() { this = TPyExpr(list) } + + Expr getElt(int n) { result.asExpr() = list.getElt(n) } + + override AstNode getChild(int index) { result = this.getElt(index) } + } + + /** A set literal. */ + additional class SetExpr extends Expr { + private Py::Set set; + + SetExpr() { this = TPyExpr(set) } + + Expr getElt(int n) { result.asExpr() = set.getElt(n) } + + override AstNode getChild(int index) { result = this.getElt(index) } + } + + /** A dict literal. */ + additional class DictExpr extends Expr { + private Py::Dict dict; + + DictExpr() { this = TPyExpr(dict) } + + /** + * Gets the key of the `n`th item (at child index `2*n`); the value is + * at child index `2*n + 1`. + */ + Expr getKey(int n) { result.asExpr() = dict.getItem(n).(Py::KeyValuePair).getKey() } + + Expr getValue(int n) { result.asExpr() = dict.getItem(n).(Py::KeyValuePair).getValue() } + + int getNumberOfItems() { result = count(dict.getAnItem()) } + + override AstNode getChild(int index) { + exists(int item | + index = 2 * item and result = this.getKey(item) + or + index = 2 * item + 1 and result = this.getValue(item) + ) + } + } + + /** A unary expression other than `not` (e.g., `-x`, `+x`, `~x`). */ + additional class ArithUnaryExpr extends Expr { + private Py::UnaryExpr unaryExpr; + + ArithUnaryExpr() { this = TPyExpr(unaryExpr) and not unaryExpr.getOp() instanceof Py::Not } + + Expr getOperand() { result.asExpr() = unaryExpr.getOperand() } + + override AstNode getChild(int index) { index = 0 and result = this.getOperand() } + } + + /** + * A comprehension or generator expression. The iterable is evaluated in + * the enclosing scope; the body runs in a nested synthetic function + * scope handled by its own CFG. + */ + additional class Comprehension extends Expr { + private Py::Expr iterable; + + Comprehension() { + exists(Py::Expr c | this = TPyExpr(c) | + iterable = c.(Py::ListComp).getIterable() + or + iterable = c.(Py::SetComp).getIterable() + or + iterable = c.(Py::DictComp).getIterable() + or + iterable = c.(Py::GeneratorExp).getIterable() + ) + } + + Expr getIterable() { result.asExpr() = iterable } + + override AstNode getChild(int index) { index = 0 and result = this.getIterable() } + } + + /** A comparison expression (`a < b`, `a < b < c`, etc.). */ + additional class CompareExpr extends Expr { + private Py::Compare cmp; + + CompareExpr() { this = TPyExpr(cmp) } + + Expr getLeft() { result.asExpr() = cmp.getLeft() } + + Expr getComparator(int n) { result.asExpr() = cmp.getComparator(n) } + + override AstNode getChild(int index) { + index = 0 and result = this.getLeft() + or + result = this.getComparator(index - 1) and index >= 1 + } + } + + /** A slice expression (`start:stop:step`). */ + additional class SliceExpr extends Expr { + private Py::Slice slice; + + SliceExpr() { this = TPyExpr(slice) } + + Expr getStart() { result.asExpr() = slice.getStart() } + + Expr getStop() { result.asExpr() = slice.getStop() } + + Expr getStep() { result.asExpr() = slice.getStep() } + + override AstNode getChild(int index) { + index = 0 and result = this.getStart() + or + index = 1 and result = this.getStop() + or + index = 2 and result = this.getStep() + } + } + + /** A starred expression (`*x`). */ + additional class StarredExpr extends Expr { + private Py::Starred starred; + + StarredExpr() { this = TPyExpr(starred) } + + Expr getValue() { result.asExpr() = starred.getValue() } + + override AstNode getChild(int index) { index = 0 and result = this.getValue() } + } + + /** A formatted string literal (`f"...{expr}..."`). */ + additional class FstringExpr extends Expr { + private Py::Fstring fstring; + + FstringExpr() { this = TPyExpr(fstring) } + + Expr getValue(int n) { result.asExpr() = fstring.getValue(n) } + + override AstNode getChild(int index) { result = this.getValue(index) } + } + + /** A formatted value inside an f-string (`{expr}` or `{expr:spec}`). */ + additional class FormattedValueExpr extends Expr { + private Py::FormattedValue fv; + + FormattedValueExpr() { this = TPyExpr(fv) } + + Expr getValue() { result.asExpr() = fv.getValue() } + + Expr getFormatSpec() { result.asExpr() = fv.getFormatSpec() } + + override AstNode getChild(int index) { + index = 0 and result = this.getValue() + or + index = 1 and result = this.getFormatSpec() + } + } + + /** A `yield` expression. */ + additional class YieldExpr extends Expr { + private Py::Yield yield; + + YieldExpr() { this = TPyExpr(yield) } + + Expr getValue() { result.asExpr() = yield.getValue() } + + override AstNode getChild(int index) { index = 0 and result = this.getValue() } + } + + /** A `yield from` expression. */ + additional class YieldFromExpr extends Expr { + private Py::YieldFrom yieldFrom; + + YieldFromExpr() { this = TPyExpr(yieldFrom) } + + Expr getValue() { result.asExpr() = yieldFrom.getValue() } + + override AstNode getChild(int index) { index = 0 and result = this.getValue() } + } + + /** An `await` expression. */ + additional class AwaitExpr extends Expr { + private Py::Await await; + + AwaitExpr() { this = TPyExpr(await) } + + Expr getValue() { result.asExpr() = await.getValue() } + + override AstNode getChild(int index) { index = 0 and result = this.getValue() } + } + + /** + * A class definition expression (visits bases, but NOT PEP 695 type + * parameters — those bind in an annotation scope that nests the class + * body, so they belong to the inner scope's CFG, not the enclosing + * scope's; the legacy CFG also omitted them). + */ + additional class ClassDefExpr extends Expr { + private Py::ClassExpr classExpr; + + ClassDefExpr() { this = TPyExpr(classExpr) } + + Expr getBase(int n) { result.asExpr() = classExpr.getBase(n) } + + override AstNode getChild(int index) { result = this.getBase(index) } + } + + /** + * A function definition expression (visits positional and keyword + * defaults, but NOT PEP 695 type parameters — those bind in an + * annotation scope that nests the function body, so they belong to + * the inner scope's CFG, not the enclosing scope's; the legacy CFG + * also omitted them). + */ + additional class FunctionDefExpr extends Expr { + private Py::FunctionExpr funcExpr; + + FunctionDefExpr() { this = TPyExpr(funcExpr) } + + /** + * Gets the `n`th default for a positional argument, in evaluation + * order. Note that `Args.getDefault(int)` is indexed by argument + * position (with gaps for arguments without defaults), so we must + * renumber here to obtain contiguous indices. + */ + Expr getDefault(int n) { + result.asExpr() = + rank[n + 1](Py::Expr d, int i | d = funcExpr.getArgs().getDefault(i) | d order by i) + } + + /** Gets the `n`th default for a keyword-only argument, in evaluation order. */ + Expr getKwDefault(int n) { + result.asExpr() = + rank[n + 1](Py::Expr d, int i | d = funcExpr.getArgs().getKwDefault(i) | d order by i) + } + + int getNumberOfDefaults() { result = count(funcExpr.getArgs().getADefault()) } + + override AstNode getChild(int index) { + result = this.getDefault(index) + or + result = this.getKwDefault(index - this.getNumberOfDefaults()) + } + } + + /** A lambda expression (has default args evaluated at definition time). */ + additional class LambdaExpr extends Expr { + private Py::Lambda lambda; + + LambdaExpr() { this = TPyExpr(lambda) } + + /** Gets the `n`th default for a positional argument, in evaluation order. */ + Expr getDefault(int n) { + result.asExpr() = + rank[n + 1](Py::Expr d, int i | d = lambda.getArgs().getDefault(i) | d order by i) + } + + /** Gets the `n`th default for a keyword-only argument, in evaluation order. */ + Expr getKwDefault(int n) { + result.asExpr() = + rank[n + 1](Py::Expr d, int i | d = lambda.getArgs().getKwDefault(i) | d order by i) + } + + int getNumberOfDefaults() { result = count(lambda.getArgs().getADefault()) } + + override AstNode getChild(int index) { + result = this.getDefault(index) + or + result = this.getKwDefault(index - this.getNumberOfDefaults()) + } + } + + /** Gets the child of `n` at the specified (zero-based) index. */ + AstNode getChild(AstNode n, int index) { result = n.getChild(index) } +} + +private module Cfg0 = Make0; + +private import Cfg0 + +private module Cfg1 = Make1; + +private import Cfg1 + +private module Cfg2 = Make2; + +private import Cfg2 + +private module Input implements InputSig1, InputSig2 { + predicate cfgCachedStageRef() { CfgCachedStage::ref() } + + private newtype TLabel = TNone() + + class Label extends TLabel { + string toString() { result = "label" } + } + + class CallableContext = Void; + + predicate inConditionalContext(Ast::AstNode n, ConditionKind kind) { + kind.isBoolean() and + n = any(Ast::AssertStmt a).getTest() + } + + private string assertThrowTag() { result = "[assert-throw]" } + + /** + * Holds if the AST node `n` may raise an exception at runtime as part of + * its normal evaluation (not via an explicit `raise`/`assert`, which are + * modelled separately). + * + * The set mirrors what the legacy CFG used to flag implicitly: function + * calls (anything can raise), attribute access (`AttributeError`), + * subscript access (`IndexError`/`KeyError`/`TypeError`), arithmetic and + * comparison operators (`TypeError`/`ZeroDivisionError`), imports + * (`ImportError`/`ModuleNotFoundError`), and generator/coroutine + * suspension points (`await`/`yield`/`yield from`). + * + * Bare `Name` reads are intentionally excluded — modelling every name + * read as `mayThrow` would explode CFG edge count for negligible + * analysis value. `BoolExpr`/`IfExp` containers are also excluded; the + * operands they evaluate contribute their own exception edges. + */ + private predicate exprMayThrow(Py::Expr e) { + e instanceof Py::Call + or + e instanceof Py::Attribute + or + e instanceof Py::Subscript + or + e instanceof Py::BinaryExpr + or + e instanceof Py::UnaryExpr + or + e instanceof Py::Compare + or + e instanceof Py::ImportExpr + or + e instanceof Py::ImportMember + or + e instanceof Py::Await + or + e instanceof Py::Yield + or + e instanceof Py::YieldFrom + } + + /** + * Holds if the statement `s` may raise an exception at runtime as part + * of its normal evaluation. Currently restricted to `from m import *` + * (which performs the import as a statement-level side effect). + */ + private predicate stmtMayThrow(Py::Stmt s) { s instanceof Py::ImportStar } + + /** + * Holds if `n` is syntactically inside the body, handlers, `else`, or + * `finally` of a `try` statement (or the body of a `with` statement, + * which compiles to an implicit try/finally for `__exit__`) in the + * same scope. + * + * This mirrors Java's `ControlFlowGraph::mayThrow`, which only emits + * exception edges when there is local exception handling that would + * observe them. Outside such contexts, exception edges would add CFG + * complexity (weakening BarrierGuard precision and breaking SSA + * continuity around augmented assignments and subscript stores) + * without any analysis benefit, since exceptions just propagate to + * the function exit anyway. + */ + private predicate inExceptionContext(Py::AstNode py) { + exists(Py::Try t | t.containsInScope(py)) + or + exists(Py::With w | w.containsInScope(py)) + } + + /** + * Holds if `n` may raise an exception during normal evaluation. See + * `exprMayThrow` and `stmtMayThrow` for the included AST classes. + * + * Restricted to nodes inside a `try`/`with` statement: matches Java's + * approach of only modelling exception flow where it can be observed + * by local handling. + */ + private predicate mayThrow(Ast::AstNode n) { + exists(Py::AstNode py | py = n.asExpr() or py = n.asStmt() | + (exprMayThrow(py) or stmtMayThrow(py)) and + inExceptionContext(py) + ) + } + + predicate additionalNode(Ast::AstNode n, string tag, NormalSuccessor t) { + n instanceof Ast::AssertStmt and tag = assertThrowTag() and t instanceof DirectSuccessor + } + + predicate beginAbruptCompletion( + Ast::AstNode ast, PreControlFlowNode n, AbruptCompletion c, boolean always + ) { + ast instanceof Ast::AssertStmt and + n.isAdditional(ast, assertThrowTag()) and + c.asSimpleAbruptCompletion() instanceof ExceptionSuccessor and + always = true + or + mayThrow(ast) and + n.isIn(ast) and + c.asSimpleAbruptCompletion() instanceof ExceptionSuccessor and + always = false + } + + predicate endAbruptCompletion(Ast::AstNode ast, PreControlFlowNode n, AbruptCompletion c) { + none() + } + + predicate step(PreControlFlowNode n1, PreControlFlowNode n2) { + exists(Ast::AssertStmt assertStmt | + n1.isBefore(assertStmt) and + n2.isBefore(assertStmt.getTest()) + or + n1.isAfterTrue(assertStmt.getTest()) and + n2.isAfter(assertStmt) + or + n1.isAfterFalse(assertStmt.getTest()) and + ( + n2.isBefore(assertStmt.getMsg()) + or + not exists(assertStmt.getMsg()) and + n2.isAdditional(assertStmt, assertThrowTag()) + ) + or + n1.isAfter(assertStmt.getMsg()) and + n2.isAdditional(assertStmt, assertThrowTag()) + ) + } +} + +import CfgCachedStage +import Public + +/** + * Maps a CFG AST wrapper node to the corresponding Python AST node, if any. + * Entry, exit, and synthetic nodes have no corresponding Python AST node. + */ +Py::AstNode astNodeToPyNode(Ast::AstNode n) { + result = n.asExpr() + or + result = n.asStmt() + or + result = n.asScope() + or + result = n.asPattern() +} diff --git a/python/ql/lib/semmle/python/controlflow/internal/Cfg.qll b/python/ql/lib/semmle/python/controlflow/internal/Cfg.qll new file mode 100644 index 000000000000..e56207d8af94 --- /dev/null +++ b/python/ql/lib/semmle/python/controlflow/internal/Cfg.qll @@ -0,0 +1,1023 @@ +/** + * Provides a Python control flow graph facade backed by the shared + * `codeql.controlflow.ControlFlowGraph` library (via `AstNodeImpl.qll`). + * + * This module re-exposes the same API surface as `semmle/python/Flow.qll` + * (the legacy CFG), but is implemented on the new shared CFG. It is + * intended as a drop-in replacement for use by the Python dataflow library + * and other downstream code. + * + * Layering follows the Java pattern (`java/ql/lib/semmle/code/java/Expr.qll` + * and `SsaImpl.qll`): variable identity and similar AST-level semantics + * live on the Python AST classes (`Name.defines(v)`, `Name.uses(v)`, ...); + * the CFG layer is purely positional, with `toAst` / `getNode` bridging + * back to the AST. The shared SSA library can then be parameterized on + * (`BasicBlock`, `int`) directly, with no CFG-level variable predicates. + */ +overlay[local?] +module; + +private import python as Py +private import semmle.python.controlflow.internal.AstNodeImpl as CfgImpl +private import codeql.controlflow.SuccessorType +private import codeql.controlflow.BasicBlock as BB + +/** + * A nested sub-module that explicitly implements `BB::CfgSig`, so this + * `Cfg` facade can be passed to parameterised shared modules such as + * `codeql.dataflow.VariableCapture::Flow`. The sub-module + * exposes the *raw* shared-CFG types from `AstNodeImpl.qll` (where the + * signature is satisfied natively), not the facade's wrapped types. + */ +module CfgSigImpl implements BB::CfgSig { + class ControlFlowNode = CfgImpl::ControlFlowNode; + + class BasicBlock = CfgImpl::BasicBlock; + + class EntryBasicBlock = CfgImpl::Cfg::EntryBasicBlock; + + predicate dominatingEdge = CfgImpl::Cfg::dominatingEdge/2; +} + +/** + * Gets the Python AST node corresponding to CFG node `n`, if any. + * + * Multiple CFG nodes may map to the same AST node (e.g. `TBeforeNode(Call)` + * and `TAstNode(Call)` both map to `Py::Call`). This is a pure translation; + * uniqueness constraints are enforced at the dataflow layer where needed. + */ +private Py::AstNode toAst(CfgImpl::ControlFlowNode n) { + result = CfgImpl::astNodeToPyNode(n.getAstNode()) +} + +/** + * A control flow node. + * + * This is the full set of CFG nodes from the shared library — it includes + * before-nodes, in-order/post-order nodes, after-value-split nodes, and + * entry/exit nodes. This enables full control-flow-level reasoning and + * compatibility with the shared control-flow reachability library. + * + * AST-level semantics (`getNode()`, `isLoad()`, typed wrappers, etc.) + * are available only on the `injects` (canonical) node for each AST node. + * Non-injects nodes are purely positional CFG nodes with no AST mapping. + */ +class ControlFlowNode extends CfgImpl::ControlFlowNode { + + /** Gets the syntactic element corresponding to this flow node, if any. */ + Py::AstNode getNode() { result = toAst(this) } + + /** Gets a predecessor of this flow node. */ + ControlFlowNode getAPredecessor() { this = result.getASuccessor() } + + /** Gets a successor of this flow node. */ + ControlFlowNode getASuccessor() { result = super.getASuccessor() } + + /** Gets a successor for this node if the relevant condition is True. */ + ControlFlowNode getATrueSuccessor() { + result = super.getASuccessor(any(BooleanSuccessor t | t.getValue() = true)) + } + + /** Gets a successor for this node if the relevant condition is False. */ + ControlFlowNode getAFalseSuccessor() { + result = super.getASuccessor(any(BooleanSuccessor t | t.getValue() = false)) + } + + /** Gets a successor for this node if an exception is raised. */ + ControlFlowNode getAnExceptionalSuccessor() { result = super.getAnExceptionSuccessor() } + + /** Gets a successor for this node if no exception is raised. */ + ControlFlowNode getANormalSuccessor() { result = super.getANormalSuccessor() } + + /** Gets the basic block containing this flow node. */ + BasicBlock getBasicBlock() { result = super.getBasicBlock() } + + /** Gets the scope containing this flow node. */ + Py::Scope getScope() { result = super.getEnclosingCallable().asScope() } + + /** Gets the enclosing module. */ + Py::Module getEnclosingModule() { result = this.getScope().getEnclosingModule() } + + /** Gets the immediate dominator of this flow node. */ + ControlFlowNode getImmediateDominator() { + // Defined positionally via the basic-block dominance tree. + exists(BasicBlock bb, int i | bb.getNode(i) = this | + // Predecessor within the same basic block. + i > 0 and result = bb.getNode(i - 1) + or + // First node of `bb`: dominator is the last node of the immediate dominator block. + i = 0 and result = bb.getImmediateDominator().getLastNode() + ) + } + + /** Holds if this strictly dominates `other`. */ + pragma[inline] + predicate strictlyDominates(ControlFlowNode other) { super.strictlyDominates(other) } + + /** Holds if this dominates `other` (reflexively). */ + pragma[inline] + predicate dominates(ControlFlowNode other) { super.dominates(other) } + + /** Holds if this is the first node in its enclosing scope. */ + predicate isEntryNode() { this instanceof CfgImpl::ControlFlow::EntryNode } + + /** Holds if this is the first node of a module. */ + predicate isModuleEntry() { + this.isEntryNode() and super.getAstNode().asScope() instanceof Py::Module + } + + /** Holds if this node may exit its scope by raising an exception. */ + predicate isExceptionalExit(Py::Scope s) { + this instanceof CfgImpl::ControlFlow::ExceptionalExitNode and + super.getEnclosingCallable().asScope() = s + } + + /** Holds if this node is a normal (non-exceptional) exit. */ + predicate isNormalExit() { this instanceof CfgImpl::ControlFlow::NormalExitNode } + + // ===== AST-shape predicates (bridges to the wrapped Python AST) ===== + /** + * Holds if this flow node is a load (including those in augmented + * assignments). + * + * Note: an augmented-assignment target (`x[i]` in `x[i] += 1`) is + * both a load and a store — `isLoad` and `isStore` both hold on the + * canonical CFG node. This mirrors Java's `VarAccess.isVarRead`, + * which holds on the destination of compound and unary assignments + * even though the destination is also a write. + */ + predicate isLoad() { exists(Py::Expr e | e = toAst(this) | py_expr_contexts(_, 3, e)) } + + /** Holds if this flow node is a store (including those in augmented assignments). */ + predicate isStore() { + exists(Py::Expr e | e = toAst(this) | py_expr_contexts(_, 5, e) or augstore(_, this)) + } + + /** Holds if this flow node is a delete. */ + predicate isDelete() { exists(Py::Expr e | e = toAst(this) | py_expr_contexts(_, 2, e)) } + + /** Holds if this flow node is a parameter. */ + predicate isParameter() { exists(Py::Expr e | e = toAst(this) | py_expr_contexts(_, 4, e)) } + + /** Holds if this flow node is a store in an augmented assignment. */ + predicate isAugStore() { augstore(_, this) } + + /** Holds if this flow node is a load in an augmented assignment. */ + predicate isAugLoad() { augstore(this, _) } + + /** Holds if this flow node corresponds to a literal. */ + predicate isLiteral() { + toAst(this) instanceof Py::Bytes or + toAst(this) instanceof Py::Dict or + toAst(this) instanceof Py::DictComp or + toAst(this) instanceof Py::Set or + toAst(this) instanceof Py::SetComp or + toAst(this) instanceof Py::Ellipsis or + toAst(this) instanceof Py::GeneratorExp or + toAst(this) instanceof Py::Lambda or + toAst(this) instanceof Py::ListComp or + toAst(this) instanceof Py::List or + toAst(this) instanceof Py::Num or + toAst(this) instanceof Py::Tuple or + toAst(this) instanceof Py::Unicode or + toAst(this) instanceof Py::NameConstant + } + + /** Holds if this flow node corresponds to an attribute expression. */ + predicate isAttribute() { toAst(this) instanceof Py::Attribute } + + /** Holds if this flow node corresponds to a subscript expression. */ + predicate isSubscript() { toAst(this) instanceof Py::Subscript } + + /** Holds if this flow node corresponds to an import member. */ + predicate isImportMember() { toAst(this) instanceof Py::ImportMember } + + /** Holds if this flow node corresponds to a call. */ + predicate isCall() { toAst(this) instanceof Py::Call } + + /** Holds if this flow node corresponds to an import. */ + predicate isImport() { toAst(this) instanceof Py::ImportExpr } + + /** Holds if this flow node corresponds to a conditional expression. */ + predicate isIfExp() { toAst(this) instanceof Py::IfExp } + + /** Holds if this flow node corresponds to a function definition expression. */ + predicate isFunction() { toAst(this) instanceof Py::FunctionExpr } + + /** Holds if this flow node corresponds to a class definition expression. */ + predicate isClass() { toAst(this) instanceof Py::ClassExpr } + + /** + * Holds if this flow node is a branch (i.e. has both a true and a + * false successor). + */ + predicate isBranch() { exists(this.getATrueSuccessor()) or exists(this.getAFalseSuccessor()) } + + /** + * Gets a CFG child of this node, defined as a CFG node whose AST node + * is a child of this CFG node's AST node, restricted to nodes that + * dominate this one (so the child has been evaluated by the time we + * reach this node). + * + * Mirrors `Flow.qll`'s `getAChild`. UnaryExprNode is excluded because + * its operand is its CFG predecessor (handled separately). + */ + pragma[nomagic] + ControlFlowNode getAChild() { + toAst(this).(Py::Expr).getAChildNode() = toAst(result) and + result.getBasicBlock().dominates(this.getBasicBlock()) and + not this instanceof UnaryExprNode + } + + /** Holds if this flow node strictly reaches `other`. */ + predicate strictlyReaches(ControlFlowNode other) { this.getASuccessor+() = other } +} + +/** + * Holds if `load` is the load half of an augmented-assignment target, + * and `store` is the corresponding store half. + * + * In the legacy CFG (`Flow.qll`) the same Python `Name` had two + * distinct CFG nodes — a load node (context 3) earlier in the BB, and + * a store node (context 5) later. The legacy `augstore` related the + * pair via dominance. + * + * In the new (shared) CFG, the canonical node for an AST expression is + * unique, so `load` and `store` collapse onto the same CFG node. The + * predicate is therefore reflexive on the augmented-assignment + * target's canonical node. + */ +private predicate augstore(ControlFlowNode load, ControlFlowNode store) { + exists(Py::AugAssign aa | aa.getTarget() = toAst(load)) and + load = store +} + +/** + * A basic block — a maximal-length sequence of control flow nodes such + * that no node except the first has a predecessor outside the sequence, + * and no node except the last has a successor outside the sequence. + */ +class BasicBlock extends CfgImpl::BasicBlock { + /** Gets the `n`th node in this basic block. */ + ControlFlowNode getNode(int n) { result = super.getNode(n) } + + /** Gets a node in this basic block. */ + ControlFlowNode getANode() { result = super.getNode(_) } + + /** Gets the first node in this basic block. */ + ControlFlowNode firstNode() { result = this.getNode(0) } + + /** Gets the last node in this basic block. */ + ControlFlowNode getLastNode() { result = super.getLastNode() } + + /** Holds if this basic block contains `node`. */ + predicate contains(ControlFlowNode node) { node = this.getANode() } + + // Inherited from the shared library's `BasicBlock`: + // getASuccessor(), getASuccessor(SuccessorType), getAPredecessor(), + // strictlyDominates(), dominates(), getImmediateDominator(), + // length(), inLoop(). + // We shadow `getNode(int)` etc. to return `ControlFlowNode` (this + // facade's type) and add Python-style helpers below. + /** Gets a true successor to this basic block. */ + BasicBlock getATrueSuccessor() { + result = super.getASuccessor(any(BooleanSuccessor t | t.getValue() = true)) + } + + /** Gets a false successor to this basic block. */ + BasicBlock getAFalseSuccessor() { + result = super.getASuccessor(any(BooleanSuccessor t | t.getValue() = false)) + } + + /** Gets an unconditional successor to this basic block. */ + BasicBlock getAnUnconditionalSuccessor() { + result = super.getASuccessor() and + not result = this.getATrueSuccessor() and + not result = this.getAFalseSuccessor() + } + + /** Gets an exceptional successor to this basic block. */ + BasicBlock getAnExceptionalSuccessor() { result = super.getASuccessor(any(ExceptionSuccessor t)) } + + /** + * Holds if this basic block is in the dominance frontier of `df`. + * + * Note: implemented locally rather than via the shared lib, which + * doesn't currently expose a `dominanceFrontier` predicate at this + * level. + */ + predicate inDominanceFrontier(BasicBlock df) { + this = df.getAPredecessor() and not this = df.getImmediateDominator() + or + exists(BasicBlock prev | prev.inDominanceFrontier(df) | + this = prev.getImmediateDominator() and + not this = df.getImmediateDominator() + ) + } + + /** Holds if this basic block strictly reaches `other`. */ + predicate strictlyReaches(BasicBlock other) { super.getASuccessor+() = other } + + /** Holds if this basic block reaches `other` (reflexively). */ + predicate reaches(BasicBlock other) { this = other or this.strictlyReaches(other) } + + /** Holds if flow from this basic block reaches a normal exit from its scope. */ + predicate reachesExit() { + this.getANode() instanceof CfgImpl::ControlFlow::NormalExitNode + or + exists(BasicBlock succ | succ = super.getASuccessor() and succ.reachesExit()) + } + + /** Gets the scope of this basic block. */ + Py::Scope getScope() { exists(ControlFlowNode n | n = this.getANode() | result = n.getScope()) } + + /** Holds if flow from this BasicBlock always reaches `succ`. */ + predicate alwaysReaches(BasicBlock succ) { + succ = this + or + strictcount(BasicBlock s | s = super.getASuccessor()) = 1 and + succ = super.getASuccessor() + or + forex(BasicBlock immsucc | immsucc = super.getASuccessor() | immsucc.alwaysReaches(succ)) + } + + /** + * Holds if this basic block ends in a node that branches on a boolean + * outcome, and `other` is dominated by the corresponding successor + * for `branch` while not being reachable from the other branch + * without going through this BB. + * + * In other words: any execution that reaches `other` must have just + * evaluated the last node of this BB and taken the `branch` outcome. + * This mirrors the legacy `ConditionBlock.controls(BB, branch)`. + */ + predicate controls(BasicBlock other, boolean branch) { + exists(BasicBlock succ | + branch = true and succ = this.getATrueSuccessor() + or + branch = false and succ = this.getAFalseSuccessor() + | + succ.dominates(other) and + // The other branch must not also reach `other` — otherwise + // `other` is not actually controlled by `branch`. + not exists(BasicBlock otherSucc | + branch = true and otherSucc = this.getAFalseSuccessor() + or + branch = false and otherSucc = this.getATrueSuccessor() + | + otherSucc.reaches(other) + ) + ) + } +} + +// =========================================================================== +// Re-exports for SSA / dominance consumers +// +// The shared `BB::CfgSig` requires `EntryBasicBlock` and `dominatingEdge` in +// addition to the BasicBlock class we already expose. They are provided by +// the shared CFG library on the `BB::Make` instantiation produced by +// `AstNodeImpl.qll`. +// =========================================================================== +/** An entry basic block, that is, a basic block whose first node is an entry node. */ +class EntryBasicBlock = CfgImpl::Cfg::EntryBasicBlock; + +/** + * Holds if `bb1` has `bb2` as a direct successor and the edge between `bb1` + * and `bb2` is a dominating edge. + */ +predicate dominatingEdge = CfgImpl::Cfg::dominatingEdge/2; + +// =========================================================================== +// AST-shape subclasses of ControlFlowNode +// +// Each class is a thin wrapper around the canonical CFG node for a given +// kind of Python AST node. Methods that take/return CFG nodes look up +// related CFG nodes by AST identity (via `getNode()`), and the dominance +// constraint from the old CFG (`result.getBasicBlock().dominates(this.getBasicBlock())`) +// is preserved. +// =========================================================================== +/** Gets the canonical `ControlFlowNode` for AST expression `e`. */ +ControlFlowNode astExprToCfg(Py::Expr e) { result.getNode() = e } + +/** A control flow node corresponding to a `Name` or `PlaceHolder` expression. */ +class NameNode extends ControlFlowNode { + NameNode() { + toAst(this) instanceof Py::Name + or + toAst(this) instanceof Py::PlaceHolder + } + + /** + * Holds if this flow node defines the variable `v`. + * + * This includes augmented-assignment targets — `n += 1` is both a + * read and a write of `n`, so `defines(n)` and `uses(n)` both hold + * on the same canonical CFG node. Mirrors Java's `VariableUpdate` + * semantics where compound assignments register both a write + * (`VarWrite`) and a read (`VarRead`) on the destination. + */ + predicate defines(Py::Variable v) { exists(Py::Name n | n = toAst(this) and n.defines(v)) } + + /** Holds if this flow node deletes the variable `v`. */ + predicate deletes(Py::Variable v) { exists(Py::Name n | n = toAst(this) and n.deletes(v)) } + + /** Holds if this flow node uses the variable `v`. */ + predicate uses(Py::Variable v) { + this.isLoad() and + exists(Py::Name u | u = toAst(this) and u.uses(v)) + or + exists(Py::PlaceHolder u | + u = toAst(this) and u.getVariable() = v and u.getCtx() instanceof Py::Load + ) + } + + /** Gets the identifier of this name node. */ + string getId() { + result = toAst(this).(Py::Name).getId() + or + result = toAst(this).(Py::PlaceHolder).getId() + } + + /** Holds if this is a use of a local variable. */ + predicate isLocal() { exists(Py::Variable v | this.uses(v) and v instanceof Py::LocalVariable) } + + /** Holds if this is a use of a non-local variable. */ + predicate isNonLocal() { + exists(Py::Variable v | this.uses(v) and v.getScope() != this.getScope()) + } + + /** Holds if this is a use of a global (including builtin) variable. */ + predicate isGlobal() { exists(Py::Variable v | this.uses(v) and v instanceof Py::GlobalVariable) } + + /** + * Holds if this is a use of `self` — the first parameter of an + * enclosing method. + * + * AST-level approximation: matches when the Name uses a `Variable` + * that is the first parameter of an enclosing `Function` defined + * inside a `Class`. + */ + predicate isSelf() { + exists(Py::Variable v, Py::Function f, Py::Class c | + this.uses(v) and + f = c.getAMethod() and + v.getScope() = f and + v = f.getArg(0).(Py::Name).getVariable() + ) + } +} + +/** A control flow node corresponding to a named constant (`None`, `True`, `False`). */ +class NameConstantNode extends NameNode { + NameConstantNode() { toAst(this) instanceof Py::NameConstant } +} + +/** A control flow node corresponding to a call. */ +class CallNode extends ControlFlowNode { + CallNode() { toAst(this) instanceof Py::Call } + + override Py::Call getNode() { result = super.getNode() } + + /** Gets the underlying Python `Call`. */ + Py::Call getCall() { result = toAst(this) } + + /** Gets the flow node for the function component of this call. */ + ControlFlowNode getFunction() { + exists(Py::Call c | + c = toAst(this) and + c.getFunc() = toAst(result) and + result.getBasicBlock().dominates(this.getBasicBlock()) + ) + } + + /** Gets the flow node for the `n`th positional argument. */ + ControlFlowNode getArg(int n) { + exists(Py::Call c | + c = toAst(this) and + c.getArg(n) = toAst(result) and + result.getBasicBlock().dominates(this.getBasicBlock()) + ) + } + + /** Gets the flow node for the named argument with name `name`. */ + ControlFlowNode getArgByName(string name) { + exists(Py::Call c, Py::Keyword k | + c = toAst(this) and + k = c.getANamedArg() and + k.getValue() = toAst(result) and + k.getArg() = name and + result.getBasicBlock().dominates(this.getBasicBlock()) + ) + } + + /** Gets a flow node corresponding to any argument. */ + ControlFlowNode getAnArg() { result = this.getArg(_) or result = this.getArgByName(_) } + + /** Gets the first tuple (`*args`) argument, if any. */ + ControlFlowNode getStarArg() { + exists(Py::Call c | + c = toAst(this) and + c.getStarArg() = toAst(result) and + result.getBasicBlock().dominates(this.getBasicBlock()) + ) + } + + /** Gets a dictionary (`**kwargs`) argument, if any. */ + ControlFlowNode getKwargs() { + exists(Py::Call c | + c = toAst(this) and + c.getKwargs() = toAst(result) and + result.getBasicBlock().dominates(this.getBasicBlock()) + ) + } + + predicate isDecoratorCall() { this.isClassDecoratorCall() or this.isFunctionDecoratorCall() } + + predicate isClassDecoratorCall() { + exists(Py::ClassExpr cls | toAst(this) = cls.getADecoratorCall()) + } + + predicate isFunctionDecoratorCall() { + exists(Py::FunctionExpr func | toAst(this) = func.getADecoratorCall()) + } +} + +/** A control flow node corresponding to an attribute expression. */ +class AttrNode extends ControlFlowNode { + AttrNode() { toAst(this) instanceof Py::Attribute } + + override Py::Attribute getNode() { result = super.getNode() } + + /** Gets the flow node for the object of the attribute expression. */ + ControlFlowNode getObject() { + exists(Py::Attribute a | + a = toAst(this) and + a.getObject() = toAst(result) and + result.getBasicBlock().dominates(this.getBasicBlock()) + ) + } + + /** Gets the flow node for the object of this attribute expression, with the matching name. */ + ControlFlowNode getObject(string name) { + exists(Py::Attribute a | + a = toAst(this) and + a.getObject() = toAst(result) and + a.getName() = name and + result.getBasicBlock().dominates(this.getBasicBlock()) + ) + } + + /** Gets the attribute name. */ + string getName() { exists(Py::Attribute a | a = toAst(this) and a.getName() = result) } +} + +/** A control flow node corresponding to an import statement (`import x`). */ +class ImportExprNode extends ControlFlowNode { + ImportExprNode() { toAst(this) instanceof Py::ImportExpr } + + override Py::ImportExpr getNode() { result = super.getNode() } +} + +/** A control flow node corresponding to a `from ... import name` expression. */ +class ImportMemberNode extends ControlFlowNode { + ImportMemberNode() { toAst(this) instanceof Py::ImportMember } + + override Py::ImportMember getNode() { result = super.getNode() } + + /** Gets the flow node for the module being imported from, with the matching name. */ + ControlFlowNode getModule(string name) { + exists(Py::ImportMember i | + i = toAst(this) and + i.getModule() = toAst(result) and + i.getName() = name and + result.getBasicBlock().dominates(this.getBasicBlock()) + ) + } +} + +/** A control flow node corresponding to a `from ... import *` statement. */ +class ImportStarNode extends ControlFlowNode { + ImportStarNode() { toAst(this) instanceof Py::ImportStar } + + override Py::ImportStar getNode() { result = super.getNode() } + + /** Gets the flow node for the module being imported from. */ + ControlFlowNode getModule() { + exists(Py::ImportStar i | + i = toAst(this) and + i.getModuleExpr() = toAst(result) and + result.getBasicBlock().dominates(this.getBasicBlock()) + ) + } +} + +/** A control flow node corresponding to a subscript expression. */ +class SubscriptNode extends ControlFlowNode { + SubscriptNode() { toAst(this) instanceof Py::Subscript } + + override Py::Subscript getNode() { result = super.getNode() } + + /** Gets the flow node for the value being subscripted. */ + ControlFlowNode getObject() { + exists(Py::Subscript s | + s = toAst(this) and + s.getObject() = toAst(result) and + result.getBasicBlock().dominates(this.getBasicBlock()) + ) + } + + /** Gets the flow node for the index expression. */ + ControlFlowNode getIndex() { + exists(Py::Subscript s | + s = toAst(this) and + s.getIndex() = toAst(result) and + result.getBasicBlock().dominates(this.getBasicBlock()) + ) + } +} + +/** A control flow node corresponding to a comparison operation. */ +class CompareNode extends ControlFlowNode { + CompareNode() { toAst(this) instanceof Py::Compare } + + override Py::Compare getNode() { result = super.getNode() } + + /** Holds if `left` and `right` are a pair of operands for this comparison. */ + predicate operands(ControlFlowNode left, Py::Cmpop op, ControlFlowNode right) { + exists(Py::Compare c, Py::Expr eleft, Py::Expr eright | + c = toAst(this) and eleft = toAst(left) and eright = toAst(right) + | + eleft = c.getLeft() and eright = c.getComparator(0) and op = c.getOp(0) + or + exists(int i | + eleft = c.getComparator(i - 1) and eright = c.getComparator(i) and op = c.getOp(i) + ) + ) and + left.getBasicBlock().dominates(this.getBasicBlock()) and + right.getBasicBlock().dominates(this.getBasicBlock()) + } +} + +/** A control flow node corresponding to a conditional expression (`x if c else y`). */ +class IfExprNode extends ControlFlowNode { + IfExprNode() { toAst(this) instanceof Py::IfExp } + + override Py::IfExp getNode() { result = super.getNode() } + + /** Gets the flow node for one of the value operands (true-branch or false-branch). */ + ControlFlowNode getAnOperand() { + exists(Py::IfExp ie | + ie = toAst(this) and + (toAst(result) = ie.getBody() or toAst(result) = ie.getOrelse()) + ) + } +} + +/** A control flow node corresponding to an assignment expression (walrus `:=`). */ +class AssignmentExprNode extends ControlFlowNode { + AssignmentExprNode() { toAst(this) instanceof Py::AssignExpr } + + override Py::AssignExpr getNode() { result = super.getNode() } + + /** Gets the flow node for the left-hand side. */ + ControlFlowNode getTarget() { + exists(Py::AssignExpr a | + a = toAst(this) and + a.getTarget() = toAst(result) and + result.getBasicBlock().dominates(this.getBasicBlock()) + ) + } + + /** Gets the flow node for the right-hand side. */ + ControlFlowNode getValue() { + exists(Py::AssignExpr a | + a = toAst(this) and + a.getValue() = toAst(result) and + result.getBasicBlock().dominates(this.getBasicBlock()) + ) + } +} + +/** A control flow node corresponding to a binary expression (`a + b` etc.). */ +class BinaryExprNode extends ControlFlowNode { + BinaryExprNode() { toAst(this) instanceof Py::BinaryExpr } + + override Py::BinaryExpr getNode() { result = super.getNode() } + + ControlFlowNode getLeft() { + exists(Py::BinaryExpr be | + be = toAst(this) and + be.getLeft() = toAst(result) and + result.getBasicBlock().dominates(this.getBasicBlock()) + ) + } + + ControlFlowNode getRight() { + exists(Py::BinaryExpr be | + be = toAst(this) and + be.getRight() = toAst(result) and + result.getBasicBlock().dominates(this.getBasicBlock()) + ) + } + + Py::Operator getOp() { result = toAst(this).(Py::BinaryExpr).getOp() } + + /** Holds if `left` and `right` are the operands and `op` is the operator. */ + predicate operands(ControlFlowNode left, Py::Operator op, ControlFlowNode right) { + left = this.getLeft() and right = this.getRight() and op = this.getOp() + } + + /** Gets either operand. */ + ControlFlowNode getAnOperand() { result = this.getLeft() or result = this.getRight() } +} + +/** A control flow node corresponding to a boolean expression (`a and b`, `a or b`). */ +class BoolExprNode extends ControlFlowNode { + BoolExprNode() { toAst(this) instanceof Py::BoolExpr } + + override Py::BoolExpr getNode() { result = super.getNode() } + + Py::Boolop getOp() { result = toAst(this).(Py::BoolExpr).getOp() } + + /** Gets any operand of this boolean expression. */ + ControlFlowNode getAnOperand() { + exists(Py::BoolExpr be | + be = toAst(this) and + be.getAValue() = toAst(result) + ) + } +} + +/** A control flow node corresponding to a unary expression (`-x`, `not x`, etc.). */ +class UnaryExprNode extends ControlFlowNode { + UnaryExprNode() { toAst(this) instanceof Py::UnaryExpr } + + override Py::UnaryExpr getNode() { result = super.getNode() } + + ControlFlowNode getOperand() { + exists(Py::UnaryExpr u | + u = toAst(this) and + u.getOperand() = toAst(result) and + result.getBasicBlock().dominates(this.getBasicBlock()) + ) + } + + Py::Unaryop getOp() { result = toAst(this).(Py::UnaryExpr).getOp() } +} + +/** + * A control flow node that is a definition: it appears in a context that + * binds a variable (assignment target, parameter, etc.). + */ +class DefinitionNode extends ControlFlowNode { + DefinitionNode() { this.isStore() or this.isParameter() } + + /** Gets the value assigned, if any. */ + ControlFlowNode getValue() { + // For-target: the value is the for-loop's iter expression (which + // is also where `Cfg::ForNode` lives — its `getNode()` returns the + // enclosing `Py::For` statement). Treated specially because there + // is no AST node holding the result of `iter(next(seq))`; we use + // the iter expression's CFG node as the stand-in. + exists(Py::For f | + f.getTarget() = toAst(this) and + toAst(result) = f.getIter() + ) + or + exists(Py::AstNode value | value = assignedValue(toAst(this)) | + toAst(result) = value and + ( + result.getBasicBlock().dominates(this.getBasicBlock()) + or + result.isImport() + or + // The default value for a parameter is evaluated in the same basic block as + // the function definition, but the parameter belongs to the basic block of the + // function, so there is no dominance relationship between the two. + exists(Py::Parameter param | toAst(this) = param.asName()) + ) + ) + } +} + +/** + * Gets the AST node that holds the value assigned to `lhs` in a binding + * context. Mirrors `Flow.qll::assigned_value`. + */ +private Py::AstNode assignedValue(Py::Expr lhs) { + // lhs = result + exists(Py::Assign a | a.getATarget() = lhs and result = a.getValue()) + or + // lhs := result + exists(Py::AssignExpr a | a.getTarget() = lhs and result = a.getValue()) + or + // lhs: annotation = result + exists(Py::AnnAssign a | a.getTarget() = lhs and result = a.getValue()) + or + // import result as lhs (also covers plain `import lhs`, where alias.getAsname() = lhs) + exists(Py::Alias a | a.getAsname() = lhs and result = a.getValue()) + or + // lhs += x -> result is the (lhs + x) binary expression + exists(Py::AugAssign a, Py::BinaryExpr b | + b = a.getOperation() and result = b and lhs = b.getLeft() + ) + or + // Nested sequence assign: ..., lhs, ... = ..., result, ... + exists(Py::Assign a | nestedSequenceAssign(a.getATarget(), a.getValue(), lhs, result)) + or + // Parameter default + exists(Py::Parameter param | lhs = param.asName() and result = param.getDefault()) +} + +/** + * Helper for nested sequence assignments such as `(a, b), c = (1, 2), 3`. + */ +private predicate nestedSequenceAssign( + Py::Expr leftParent, Py::Expr rightParent, Py::Expr left, Py::Expr right +) { + exists(int i | + leftParent.(Py::Tuple).getElt(i) = left and rightParent.(Py::Tuple).getElt(i) = right + or + leftParent.(Py::List).getElt(i) = left and rightParent.(Py::List).getElt(i) = right + ) + or + exists(Py::Expr leftMid, Py::Expr rightMid | + nestedSequenceAssign(leftParent, rightParent, leftMid, rightMid) and + nestedSequenceAssign(leftMid, rightMid, left, right) + ) +} + +/** A control flow node corresponding to a deletion (`del x`). */ +class DeletionNode extends ControlFlowNode { + DeletionNode() { this.isDelete() } +} + +/** A control flow node corresponding to a `for` loop target. */ +class ForNode extends ControlFlowNode { + ForNode() { exists(Py::For f | toAst(this) = f.getIter()) } + + /** Gets the iterable expression. */ + ControlFlowNode getIter() { + result = this and result = result // canonical "after" of the iterable + } + + /** Gets the sequence expression (alias for `getIter()`, matches legacy Flow naming). */ + ControlFlowNode getSequence() { result = this.getIter() } + + /** Gets the target (loop variable) of the `for` loop. */ + ControlFlowNode getTarget() { + exists(Py::For f | + f.getIter() = toAst(this) and + f.getTarget() = toAst(result) + ) + } + + /** Holds if `target` is the loop variable and `sequence` is the iterable. */ + predicate iterates(ControlFlowNode target, ControlFlowNode sequence) { + target = this.getTarget() and sequence = this.getSequence() + } +} + +/** A control flow node corresponding to a `raise` statement. */ +class RaiseStmtNode extends ControlFlowNode { + RaiseStmtNode() { toAst(this) instanceof Py::Raise } + + override Py::Raise getNode() { result = super.getNode() } + + /** Gets the exception expression, if any. */ + ControlFlowNode getException() { + exists(Py::Raise r | + r = toAst(this) and + r.getException() = toAst(result) and + result.getBasicBlock().dominates(this.getBasicBlock()) + ) + } +} + +/** A control flow node corresponding to a starred expression (`*x`). */ +class StarredNode extends ControlFlowNode { + StarredNode() { toAst(this) instanceof Py::Starred } + + /** Gets the value being starred. */ + ControlFlowNode getValue() { + exists(Py::Starred s | + s = toAst(this) and + s.getValue() = toAst(result) and + result.getBasicBlock().dominates(this.getBasicBlock()) + ) + } +} + +/** A control flow node corresponding to an `except` clause's name binding. */ +class ExceptFlowNode extends ControlFlowNode { + ExceptFlowNode() { exists(Py::ExceptStmt e | toAst(this) = e.getName()) } + + /** Gets the CFG node for the bound `as`-name itself. */ + ControlFlowNode getName() { result = this } + + /** Gets the type expression of this exception handler. */ + ControlFlowNode getType() { + exists(Py::ExceptStmt e | + e.getName() = toAst(this) and + e.getType() = toAst(result) and + result.getBasicBlock().dominates(this.getBasicBlock()) + ) + } +} + +/** A control flow node corresponding to an `except*` clause's name binding. */ +class ExceptGroupFlowNode extends ControlFlowNode { + ExceptGroupFlowNode() { exists(Py::ExceptGroupStmt e | toAst(this) = e.getName()) } + + /** Gets the CFG node for the bound `as`-name itself. */ + ControlFlowNode getName() { result = this } +} + +/** Abstract base class for sequence nodes (tuple, list). */ +abstract class SequenceNode extends ControlFlowNode { + /** Gets the `n`th element of this sequence. */ + abstract ControlFlowNode getElement(int n); + + /** Gets any element of this sequence. */ + ControlFlowNode getAnElement() { result = this.getElement(_) } +} + +/** A control flow node corresponding to a tuple literal. */ +class TupleNode extends SequenceNode { + TupleNode() { toAst(this) instanceof Py::Tuple } + + override ControlFlowNode getElement(int n) { + exists(Py::Tuple t | + t = toAst(this) and + t.getElt(n) = toAst(result) and + result.getBasicBlock().dominates(this.getBasicBlock()) + ) + } +} + +/** A control flow node corresponding to a list literal. */ +class ListNode extends SequenceNode { + ListNode() { toAst(this) instanceof Py::List } + + override ControlFlowNode getElement(int n) { + exists(Py::List l | + l = toAst(this) and + l.getElt(n) = toAst(result) and + result.getBasicBlock().dominates(this.getBasicBlock()) + ) + } +} + +/** A control flow node corresponding to a set literal. */ +class SetNode extends ControlFlowNode { + SetNode() { toAst(this) instanceof Py::Set } + + /** Gets the flow node for an element of the set. */ + ControlFlowNode getAnElement() { + exists(Py::Set s | + s = toAst(this) and + s.getAnElt() = toAst(result) and + result.getBasicBlock().dominates(this.getBasicBlock()) + ) + } +} + +/** A control flow node corresponding to a dict literal. */ +class DictNode extends ControlFlowNode { + DictNode() { toAst(this) instanceof Py::Dict } + + /** Gets the flow node for a key of the dict. */ + ControlFlowNode getAKey() { + exists(Py::Dict d | + d = toAst(this) and + d.getAKey() = toAst(result) and + result.getBasicBlock().dominates(this.getBasicBlock()) + ) + } + + /** Gets the flow node for a value of the dict. */ + ControlFlowNode getAValue() { + exists(Py::Dict d | + d = toAst(this) and + d.getAValue() = toAst(result) and + result.getBasicBlock().dominates(this.getBasicBlock()) + ) + } +} + +/** A control flow node corresponding to an iterable in a `for` loop. */ +class IterableNode extends ControlFlowNode { + IterableNode() { + this instanceof SequenceNode + or + this instanceof SetNode + } + + /** Gets the control flow node for an element of this iterable. */ + ControlFlowNode getAnElement() { + result = this.(SequenceNode).getAnElement() + or + result = this.(SetNode).getAnElement() + } +} diff --git a/python/ql/lib/semmle/python/dataflow/new/BarrierGuards.qll b/python/ql/lib/semmle/python/dataflow/new/BarrierGuards.qll index 072098991bb4..39e8d40fd172 100644 --- a/python/ql/lib/semmle/python/dataflow/new/BarrierGuards.qll +++ b/python/ql/lib/semmle/python/dataflow/new/BarrierGuards.qll @@ -1,11 +1,12 @@ /** Provides commonly used BarrierGuards. */ private import python +private import semmle.python.controlflow.internal.Cfg as Cfg private import semmle.python.dataflow.new.DataFlow -private predicate constCompare(DataFlow::GuardNode g, ControlFlowNode node, boolean branch) { - exists(CompareNode cn | cn = g | - exists(ImmutableLiteral const, Cmpop op, ControlFlowNode c | +private predicate constCompare(DataFlow::GuardNode g, Cfg::ControlFlowNode node, boolean branch) { + exists(Cfg::CompareNode cn | cn = g | + exists(ImmutableLiteral const, Cmpop op, Cfg::ControlFlowNode c | c.getNode() = const and ( op = any(Eq eq) and branch = true @@ -18,7 +19,7 @@ private predicate constCompare(DataFlow::GuardNode g, ControlFlowNode node, bool cn.operands(node, op, c) ) or - exists(NameConstant const, Cmpop op, ControlFlowNode c | + exists(NameConstant const, Cmpop op, Cfg::ControlFlowNode c | c.getNode() = const and ( op = any(Is is_) and branch = true @@ -31,12 +32,12 @@ private predicate constCompare(DataFlow::GuardNode g, ControlFlowNode node, bool cn.operands(node, op, c) ) or - exists(IterableNode const_iterable, Cmpop op | + exists(Cfg::IterableNode const_iterable, Cmpop op | op = any(In in_) and branch = true or op = any(NotIn ni) and branch = false | - forall(ControlFlowNode elem | elem = const_iterable.getAnElement() | + forall(Cfg::ControlFlowNode elem | elem = const_iterable.getAnElement() | elem.getNode() instanceof ImmutableLiteral ) and cn.operands(node, op, const_iterable) diff --git a/python/ql/lib/semmle/python/dataflow/new/SensitiveDataSources.qll b/python/ql/lib/semmle/python/dataflow/new/SensitiveDataSources.qll index 1a32965d08d7..644f88e311dd 100644 --- a/python/ql/lib/semmle/python/dataflow/new/SensitiveDataSources.qll +++ b/python/ql/lib/semmle/python/dataflow/new/SensitiveDataSources.qll @@ -4,6 +4,7 @@ */ private import python +private import semmle.python.controlflow.internal.Cfg as Cfg private import semmle.python.dataflow.new.DataFlow // Need to import `semmle.python.Frameworks` since frameworks can extend `SensitiveDataSource::Range` private import semmle.python.Frameworks @@ -105,7 +106,7 @@ private module SensitiveDataModeling { or // to cover functions that we don't have the definition for, and where the // reference to the function has not already been marked as being sensitive - this.getFunction().asCfgNode().(NameNode).getId() = sensitiveString(classification) + this.getFunction().asCfgNode().(Cfg::NameNode).getId() = sensitiveString(classification) } override SensitiveDataClassification getClassification() { result = classification } @@ -251,12 +252,12 @@ private module SensitiveDataModeling { SensitiveDataClassification classification; SensitiveVariableAssignment() { - exists(DefinitionNode def | - def.(NameNode).getId() = sensitiveString(classification) and + exists(Cfg::DefinitionNode def | + def.(Cfg::NameNode).getId() = sensitiveString(classification) and ( this.asCfgNode() = def.getValue() or - this.asCfgNode() = def.getValue().(ForNode).getSequence() + this.asCfgNode() = def.getValue().(Cfg::ForNode).getSequence() ) and not this.asExpr() instanceof FunctionExpr and not this.asExpr() instanceof ClassExpr @@ -293,7 +294,7 @@ private module SensitiveDataModeling { SensitiveDataClassification classification; SensitiveSubscript() { - this.asCfgNode().(SubscriptNode).getIndex() = + this.asCfgNode().(Cfg::SubscriptNode).getIndex() = sensitiveLookupStringConst(classification).asCfgNode() } diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/Attributes.qll b/python/ql/lib/semmle/python/dataflow/new/internal/Attributes.qll index 76d2cb11e144..cfdef2a1a905 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/Attributes.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/Attributes.qll @@ -3,6 +3,7 @@ overlay[local] module; private import python +private import semmle.python.controlflow.internal.Cfg as Cfg import DataFlowUtil import DataFlowPublic private import DataFlowPrivate @@ -83,9 +84,9 @@ abstract class AttrWrite extends AttrRef { * ```python * object.attr = value * ``` - * Also gives access to the `value` being written, by extending `DefinitionNode`. + * Also gives access to the `value` being written, by extending `Cfg::DefinitionNode`. */ -private class AttributeAssignmentNode extends DefinitionNode, AttrNode { } +private class AttributeAssignmentNode extends Cfg::DefinitionNode, Cfg::AttrNode { } /** A simple attribute assignment: `object.attr = value`. */ private class AttributeAssignmentAsAttrWrite extends AttrWrite, CfgNode { @@ -131,13 +132,13 @@ private class GlobalAttributeAssignmentAsAttrWrite extends AttrWrite, CfgNode { override string getAttributeName() { result = node.getName() } } -/** Represents `CallNode`s that may refer to calls to built-in functions or classes. */ -private class BuiltInCallNode extends CallNode { +/** Represents `Cfg::CallNode`s that may refer to calls to built-in functions or classes. */ +private class BuiltInCallNode extends Cfg::CallNode { string name; BuiltInCallNode() { // TODO disallow instances where the name of the built-in may refer to an in-scope variable of that name. - exists(NameNode id | + exists(Cfg::NameNode id | name = Builtins::getBuiltinName() and this.getFunction() = id and id.getId() = name and @@ -145,7 +146,7 @@ private class BuiltInCallNode extends CallNode { ) } - /** Gets the name of the built-in function that is called at this `CallNode` */ + /** Gets the name of the built-in function that is called at this `Cfg::CallNode` */ string getBuiltinName() { result = name } } @@ -157,20 +158,20 @@ private class BuiltinAttrCallNode extends BuiltInCallNode { BuiltinAttrCallNode() { name in ["setattr", "getattr", "hasattr", "delattr"] } /** Gets the control flow node for object on which the attribute is accessed. */ - ControlFlowNode getObject() { result in [this.getArg(0), this.getArgByName("object")] } + Cfg::ControlFlowNode getObject() { result in [this.getArg(0), this.getArgByName("object")] } /** * Gets the control flow node for the value that is being written to the attribute. * Only relevant for `setattr` calls. */ - ControlFlowNode getValue() { + Cfg::ControlFlowNode getValue() { // only valid for `setattr` name = "setattr" and result in [this.getArg(2), this.getArgByName("value")] } /** Gets the control flow node that defines the name of the attribute being accessed. */ - ControlFlowNode getName() { result in [this.getArg(1), this.getArgByName("name")] } + Cfg::ControlFlowNode getName() { result in [this.getArg(1), this.getArgByName("name")] } } /** Represents calls to the built-in `setattr`. */ @@ -205,10 +206,10 @@ private class SetAttrCallAsAttrWrite extends AttrWrite, CfgNode { * attr = value * ... * ``` - * Instances of this class correspond to the `NameNode` for `attr`, and also gives access to `value` by - * virtue of being a `DefinitionNode`. + * Instances of this class correspond to the `Cfg::NameNode` for `attr`, and also gives access to `value` by + * virtue of being a `Cfg::DefinitionNode`. */ -private class ClassAttributeAssignmentNode extends DefinitionNode, NameNode { +private class ClassAttributeAssignmentNode extends Cfg::DefinitionNode, Cfg::NameNode { ClassAttributeAssignmentNode() { this.getScope() = any(ClassExpr c).getInnerScope() } } @@ -248,7 +249,7 @@ abstract class AttrRead extends AttrRef, Node, LocalSourceNode { /** A simple attribute read, e.g. `object.attr` */ private class AttributeReadAsAttrRead extends AttrRead, CfgNode { - override AttrNode node; + override Cfg::AttrNode node; AttributeReadAsAttrRead() { node.isLoad() } @@ -285,7 +286,7 @@ private class GetAttrCallAsAttrRead extends AttrRead, CfgNode { * is treated as if it is a read of the attribute `module.attr`, even if `module` is not imported directly. */ private class ModuleAttributeImportAsAttrRead extends AttrRead, CfgNode { - override ImportMemberNode node; + override Cfg::ImportMemberNode node; override Node getObject() { result.asCfgNode() = node.getModule(_) } diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/Builtins.qll b/python/ql/lib/semmle/python/dataflow/new/internal/Builtins.qll index 764af5d9dc57..94c9b486448f 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/Builtins.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/Builtins.qll @@ -3,6 +3,7 @@ overlay[local] module; private import python +private import semmle.python.controlflow.internal.Cfg as Cfg private import semmle.python.dataflow.new.DataFlow private import semmle.python.dataflow.new.internal.ImportStar @@ -67,7 +68,7 @@ module Builtins { DataFlow::CfgNode likelyBuiltin(string name) { exists(Module m | result.getNode() = - any(NameNode n | + any(Cfg::NameNode n | possible_builtin_accessed_in_module(n, name, m) and not possible_builtin_defined_in_module(name, m) ) @@ -87,7 +88,7 @@ module Builtins { * Holds if `n` is an access of a global variable called `name` (which is also the name of a * built-in) inside the module `m`. */ - private predicate possible_builtin_accessed_in_module(NameNode n, string name, Module m) { + private predicate possible_builtin_accessed_in_module(Cfg::NameNode n, string name, Module m) { n.isGlobal() and n.isLoad() and name = n.getId() and diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll index 23b49882445e..e37ac2799773 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll @@ -25,7 +25,7 @@ * what callable this call might end up targeting. * * Specifically this means that we cannot use type-backtrackers from the function of a - * `CallNode`, since there is no `CallNode` to backtrack from for `func` in the example + * `Cfg::CallNode`, since there is no `Cfg::CallNode` to backtrack from for `func` in the example * above. * * Note: This hasn't been 100% realized yet, so we don't currently expose a predicate to @@ -35,6 +35,7 @@ overlay[local?] module; private import python +private import semmle.python.controlflow.internal.Cfg as Cfg private import DataFlowPublic private import DataFlowPrivate private import FlowSummaryImpl as FlowSummaryImpl @@ -162,7 +163,7 @@ newtype TArgumentPosition = */ TLambdaSelfArgumentPosition() or TPositionalArgumentPosition(int index) { - exists(any(CallNode c).getArg(index)) + exists(any(Cfg::CallNode c).getArg(index)) or // since synthetic calls within a summarized callable could use a unique argument // position, we need to ensure we make these available (these are specified as @@ -174,7 +175,7 @@ newtype TArgumentPosition = index = 0 } or TKeywordArgumentPosition(string name) { - exists(any(CallNode c).getArgByName(name)) + exists(any(Cfg::CallNode c).getArgByName(name)) or // see comment for TPositionalArgumentPosition FlowSummaryImpl::ParsePositions::isParsedKeywordParameterPosition(_, name) @@ -297,10 +298,12 @@ predicate hasPropertyDecorator(Function func) { */ overlay[local] predicate hasContextmanagerDecorator(Function func) { - exists(ControlFlowNode contextmanager | - contextmanager.(NameNode).getId() = "contextmanager" and contextmanager.(NameNode).isGlobal() + exists(Cfg::ControlFlowNode contextmanager | + contextmanager.(Cfg::NameNode).getId() = "contextmanager" and + contextmanager.(Cfg::NameNode).isGlobal() or - contextmanager.(AttrNode).getObject("contextmanager").(NameNode).getId() = "contextlib" + contextmanager.(Cfg::AttrNode).getObject("contextmanager").(Cfg::NameNode).getId() = + "contextlib" | func.getADecorator() = contextmanager.getNode() ) @@ -316,10 +319,10 @@ predicate hasContextmanagerDecorator(Function func) { */ overlay[local] private predicate hasOverloadDecorator(Function func) { - exists(ControlFlowNode overload | - overload.(NameNode).getId() = "overload" and overload.(NameNode).isGlobal() + exists(Cfg::ControlFlowNode overload | + overload.(Cfg::NameNode).getId() = "overload" and overload.(Cfg::NameNode).isGlobal() or - overload.(AttrNode).getObject("overload").(NameNode).isGlobal() + overload.(Cfg::AttrNode).getObject("overload").(Cfg::NameNode).isGlobal() | func.getADecorator() = overload.getNode() ) @@ -538,7 +541,7 @@ class LibraryCallableValue extends DataFlowCallable, TLibraryCallable { // ============================================================================= /** Gets a call to `type`. */ private CallCfgNode getTypeCall() { - exists(NameNode id | id.getId() = "type" and id.isGlobal() | + exists(Cfg::NameNode id | id.getId() = "type" and id.isGlobal() | result.getFunction().asCfgNode() = id ) } @@ -550,7 +553,7 @@ private CallCfgNode getSuperCall() { // link below), but otherwise only 2 edgecases. Overall it seems ok to ignore this complexity. // // https://github.com/python/cpython/blob/18b1782192f85bd26db89f5bc850f8bee4247c1a/Lib/unittest/mock.py#L48-L50 - exists(NameNode id | id.getId() = "super" and id.isGlobal() | + exists(Cfg::NameNode id | id.getId() = "super" and id.isGlobal() | result.getFunction().asCfgNode() = id ) } @@ -1036,7 +1039,7 @@ private module MethodCalls { */ pragma[nomagic] private predicate directCall( - CallNode call, Function target, string functionName, Class cls, AttrRead attr, Node self + Cfg::CallNode call, Function target, string functionName, Class cls, AttrRead attr, Node self ) { target = findFunctionAccordingToMroKnownStartingClass(cls, functionName) and directCall_join(call, functionName, cls, attr, self) @@ -1045,7 +1048,7 @@ private module MethodCalls { /** Extracted to give good join order */ pragma[nomagic] private predicate directCall_join( - CallNode call, string functionName, Class cls, AttrRead attr, Node self + Cfg::CallNode call, string functionName, Class cls, AttrRead attr, Node self ) { call.getFunction() = attrReadTracker(attr).asCfgNode() and attr.accesses(self, functionName) and @@ -1062,7 +1065,7 @@ private module MethodCalls { */ pragma[nomagic] private predicate callWithinMethodImplicitSelfOrCls( - CallNode call, Function target, string functionName, Class classWithMethod, AttrRead attr, + Cfg::CallNode call, Function target, string functionName, Class classWithMethod, AttrRead attr, Node self ) { target = findFunctionAccordingToMro(getADirectSubclass*(classWithMethod), functionName) and @@ -1072,7 +1075,7 @@ private module MethodCalls { /** Extracted to give good join order */ pragma[nomagic] private predicate callWithinMethodImplicitSelfOrCls_join( - CallNode call, string functionName, Class classWithMethod, AttrRead attr, Node self + Cfg::CallNode call, string functionName, Class classWithMethod, AttrRead attr, Node self ) { call.getFunction() = attrReadTracker(attr).asCfgNode() and attr.accesses(self, functionName) and @@ -1084,7 +1087,7 @@ private module MethodCalls { * resolve the call to a known target (since the only super class might be the * builtin `object`, so we never have the implementation of `__new__` in the DB). */ - predicate fromSuperNewCall(CallNode call, Class classUsedInSuper, AttrRead attr, Node self) { + predicate fromSuperNewCall(Cfg::CallNode call, Class classUsedInSuper, AttrRead attr, Node self) { fromSuper_join(call, "__new__", classUsedInSuper, attr, self) and self in [classTracker(_), clsArgumentTracker(_)] } @@ -1106,7 +1109,7 @@ private module MethodCalls { */ pragma[nomagic] predicate fromSuper( - CallNode call, Function target, string functionName, Class classUsedInSuper, AttrRead attr, + Cfg::CallNode call, Function target, string functionName, Class classUsedInSuper, AttrRead attr, Node self ) { target = findFunctionAccordingToMro(getNextClassInMro(classUsedInSuper), functionName) and @@ -1116,7 +1119,7 @@ private module MethodCalls { /** Extracted to give good join order */ pragma[nomagic] private predicate fromSuper_join( - CallNode call, string functionName, Class classUsedInSuper, AttrRead attr, Node self + Cfg::CallNode call, string functionName, Class classUsedInSuper, AttrRead attr, Node self ) { call.getFunction() = attrReadTracker(attr).asCfgNode() and ( @@ -1135,7 +1138,7 @@ private module MethodCalls { ) } - predicate resolveMethodCall(CallNode call, Function target, CallType type, Node self) { + predicate resolveMethodCall(Cfg::CallNode call, Function target, CallType type, Node self) { ( directCall(call, target, _, _, _, self) or @@ -1182,7 +1185,7 @@ import MethodCalls * NOTE: We have this predicate mostly to be able to compare with old point-to * call-graph resolution. So it could be removed in the future. */ -predicate resolveClassCall(CallNode call, Class cls) { +predicate resolveClassCall(Cfg::CallNode call, Class cls) { call.getFunction() = classTracker(cls).asCfgNode() or // `cls()` inside a classmethod (which also contains `type(self)()` inside a method) @@ -1212,7 +1215,7 @@ Function invokedFunctionFromClassConstruction(Class cls, string funcName) { * * See https://docs.python.org/3/reference/datamodel.html#object.__call__ */ -predicate resolveClassInstanceCall(CallNode call, Function target, Node self) { +predicate resolveClassInstanceCall(Cfg::CallNode call, Function target, Node self) { exists(Class cls | call.getFunction() = classInstanceTracker(cls).asCfgNode() and target = findFunctionAccordingToMroKnownStartingClass(cls, "__call__") @@ -1231,7 +1234,7 @@ predicate resolveClassInstanceCall(CallNode call, Function target, Node self) { * Holds if `call` is a call to the `target`, with call-type `type`. */ cached -predicate resolveCall(CallNode call, Function target, CallType type) { +predicate resolveCall(Cfg::CallNode call, Function target, CallType type) { Stages::DataFlow::ref() and ( type instanceof CallTypePlainFunction and @@ -1256,11 +1259,11 @@ predicate resolveCall(CallNode call, Function target, CallType type) { // ============================================================================= /** * Holds if the argument of `call` at position `apos` is `arg`. This is just a helper - * predicate that maps ArgumentPositions to the arguments of the underlying `CallNode`. + * predicate that maps ArgumentPositions to the arguments of the underlying `Cfg::CallNode`. */ overlay[local] cached -predicate normalCallArg(CallNode call, Node arg, ArgumentPosition apos) { +predicate normalCallArg(Cfg::CallNode call, Node arg, ArgumentPosition apos) { exists(int index | apos.isPositional(index) and arg.asCfgNode() = call.getArg(index) @@ -1275,7 +1278,7 @@ predicate normalCallArg(CallNode call, Node arg, ArgumentPosition apos) { exists(int index | apos.isStarArgs(index) and arg.asCfgNode() = call.getStarArg() and - // since `CallNode.getArg` doesn't include `*args`, we need to drop to the AST level + // since `Cfg::CallNode.getArg` doesn't include `*args`, we need to drop to the AST level // to get the index. Notice that we only use the AST for getting the index, so we // don't need to check for dominance in regards to splitting. call.getStarArg().getNode() = call.getNode().getPositionalArg(index).(Starred).getValue() @@ -1349,7 +1352,9 @@ predicate normalCallArg(CallNode call, Node arg, ArgumentPosition apos) { * translated into `l.clear()`, and we can still have use-use flow. */ cached -predicate getCallArg(CallNode call, Function target, CallType type, Node arg, ArgumentPosition apos) { +predicate getCallArg( + Cfg::CallNode call, Function target, CallType type, Node arg, ArgumentPosition apos +) { Stages::DataFlow::ref() and resolveCall(call, target, type) and ( @@ -1442,10 +1447,12 @@ private predicate sameEnclosingCallable(Node node1, Node node2) { // DataFlowCall // ============================================================================= newtype TDataFlowCall = - TNormalCall(CallNode call, Function target, CallType type) { resolveCall(call, target, type) } or + TNormalCall(Cfg::CallNode call, Function target, CallType type) { + call.injects(_) and resolveCall(call, target, type) + } or /** A call to the generated function inside a comprehension */ TComprehensionCall(Comp c) or - TPotentialLibraryCall(CallNode call) or + TPotentialLibraryCall(Cfg::CallNode call) { call.injects(_) } or /** A synthesized call inside a summarized callable */ TSummaryCall( FlowSummaryImpl::Public::SummarizedCallable c, FlowSummaryImpl::Private::SummaryNode receiver @@ -1465,7 +1472,7 @@ abstract class DataFlowCall extends TDataFlowCall { abstract ArgumentNode getArgument(ArgumentPosition apos); /** Get the control flow node representing this call, if any. */ - abstract ControlFlowNode getNode(); + abstract Cfg::ControlFlowNode getNode(); /** Gets the enclosing callable of this call. */ DataFlowCallable getEnclosingCallable() { result = getCallableScope(this.getScope()) } @@ -1496,28 +1503,28 @@ abstract class ExtractedDataFlowCall extends DataFlowCall { } /** - * A resolved call in source code with an underlying `CallNode`. + * A resolved call in source code with an underlying `Cfg::CallNode`. * * This is considered normal, compared with special calls such as `obj[0]` calling the * `__getitem__` method on the object. However, this also includes calls that go to the * `__call__` special method. */ class NormalCall extends ExtractedDataFlowCall, TNormalCall { - CallNode call; + Cfg::CallNode call; Function target; CallType type; NormalCall() { this = TNormalCall(call, target, type) } override string toString() { - // note: if we used toString directly on the CallNode we would get - // `ControlFlowNode for func()` - // but the `ControlFlowNode` part is just clutter, so we go directly to the AST node + // note: if we used toString directly on the Cfg::CallNode we would get + // `Cfg::ControlFlowNode for func()` + // but the `Cfg::ControlFlowNode` part is just clutter, so we go directly to the AST node // instead. result = call.getNode().toString() } - override ControlFlowNode getNode() { result = call } + override Cfg::ControlFlowNode getNode() { result = call } override Scope getScope() { result = call.getScope() } @@ -1545,7 +1552,7 @@ class ComprehensionCall extends ExtractedDataFlowCall, TComprehensionCall { override string toString() { result = "comprehension call" } - override ControlFlowNode getNode() { result.getNode() = c } + override Cfg::ControlFlowNode getNode() { result.getNode() = c } override Scope getScope() { result = c.getScope() } @@ -1568,14 +1575,14 @@ class ComprehensionCall extends ExtractedDataFlowCall, TComprehensionCall { * in this class. */ class PotentialLibraryCall extends ExtractedDataFlowCall, TPotentialLibraryCall { - CallNode call; + Cfg::CallNode call; PotentialLibraryCall() { this = TPotentialLibraryCall(call) } override string toString() { - // note: if we used toString directly on the CallNode we would get - // `ControlFlowNode for func()` - // but the `ControlFlowNode` part is just clutter, so we go directly to the AST node + // note: if we used toString directly on the Cfg::CallNode we would get + // `Cfg::ControlFlowNode for func()` + // but the `Cfg::ControlFlowNode` part is just clutter, so we go directly to the AST node // instead. result = call.getNode().toString() } @@ -1592,10 +1599,10 @@ class PotentialLibraryCall extends ExtractedDataFlowCall, TPotentialLibraryCall // potential self argument, from `foo.bar()` -- note that this could also just be a // module reference, but we really don't have a good way of knowing :| apos.isSelf() and - result.asCfgNode() = call.getFunction().(AttrNode).getObject() + result.asCfgNode() = call.getFunction().(Cfg::AttrNode).getObject() } - override ControlFlowNode getNode() { result = call } + override Cfg::ControlFlowNode getNode() { result = call } override Scope getScope() { result = call.getScope() } } @@ -1627,7 +1634,7 @@ class SummaryCall extends DataFlowCall, TSummaryCall { override ArgumentNode getArgument(ArgumentPosition apos) { none() } - override ControlFlowNode getNode() { none() } + override Cfg::ControlFlowNode getNode() { none() } override string toString() { result = "[summary] call to " + receiver + " in " + c } @@ -1769,12 +1776,12 @@ private class SummaryPostUpdateNode extends FlowSummaryNode, PostUpdateNodeImpl * This is used for tracking flow through captured variables. */ class SynthCapturedVariablesArgumentNode extends Node, TSynthCapturedVariablesArgumentNode { - ControlFlowNode callable; + Cfg::ControlFlowNode callable; SynthCapturedVariablesArgumentNode() { this = TSynthCapturedVariablesArgumentNode(callable) } - /** Gets the `CallNode` corresponding to this captured variables argument node. */ - CallNode getCallNode() { result.getFunction() = callable } + /** Gets the `Cfg::CallNode` corresponding to this captured variables argument node. */ + Cfg::CallNode getCallNode() { result.getFunction() = callable } /** Gets the `CfgNode` that corresponds to this synthetic node. */ CfgNode getUnderlyingNode() { result.asCfgNode() = callable } @@ -1792,7 +1799,7 @@ class CapturedVariablesArgumentNodeAsArgumentNode extends ArgumentNode, { overlay[global] override predicate argumentOf(DataFlowCall call, ArgumentPosition pos) { - exists(CallNode callNode | callNode = this.getCallNode() | + exists(Cfg::CallNode callNode | callNode = this.getCallNode() | callNode = call.getNode() and exists(Function target | resolveCall(callNode, target, _) | target = any(VariableCapture::CapturedVariable v).getACapturingScope() @@ -1806,7 +1813,7 @@ class CapturedVariablesArgumentNodeAsArgumentNode extends ArgumentNode, class SynthCapturedVariablesArgumentPostUpdateNode extends PostUpdateNodeImpl, TSynthCapturedVariablesArgumentPostUpdateNode { - ControlFlowNode callable; + Cfg::ControlFlowNode callable; SynthCapturedVariablesArgumentPostUpdateNode() { this = TSynthCapturedVariablesArgumentPostUpdateNode(callable) diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll index 04e8ad0587f6..cc02d140f53f 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll @@ -2,8 +2,9 @@ overlay[local?] module; private import python +private import semmle.python.controlflow.internal.Cfg as Cfg private import DataFlowPublic -private import semmle.python.essa.SsaCompute +private import semmle.python.dataflow.new.internal.SsaImpl as SsaImpl private import semmle.python.dataflow.new.internal.ImportResolution private import FlowSummaryImpl as FlowSummaryImpl private import semmle.python.frameworks.data.ModelsAsData @@ -43,13 +44,28 @@ predicate isArgumentNode(ArgumentNode arg, DataFlowCall c, ArgumentPosition pos) // Nodes //-------- overlay[local] -predicate isExpressionNode(ControlFlowNode node) { node.getNode() instanceof Expr } +predicate isExpressionNode(Cfg::ControlFlowNode node) { + // Restrict to the `injects` representative so the dataflow layer creates + // exactly one `TCfgNode` per AST expression. + node.injects(_) and + ( + node.getNode() instanceof Expr + or + // `Cfg::ForNode` wraps a `For` statement's iter position, but + // overrides `.getNode()` to return the `Py::For` statement (for + // legacy parity). The underlying AST is still an `Expr` (the iter + // expression); we want a dataflow node here so that for-loop + // content reads (`for y in l`) have a source expression node to + // read content from. + node instanceof Cfg::ForNode + ) +} // ============================================================================= // SyntheticPreUpdateNode // ============================================================================= class SyntheticPreUpdateNode extends Node, TSyntheticPreUpdateNode { - CallNode node; + Cfg::CallNode node; SyntheticPreUpdateNode() { this = TSyntheticPreUpdateNode(node) } @@ -151,7 +167,7 @@ predicate synthStarArgsElementParameterNodeStoreStep( * been passed in a `**kwargs` argument. */ class SynthDictSplatArgumentNode extends Node, TSynthDictSplatArgumentNode { - CallNode node; + Cfg::CallNode node; SynthDictSplatArgumentNode() { this = TSynthDictSplatArgumentNode(node) } @@ -165,7 +181,7 @@ class SynthDictSplatArgumentNode extends Node, TSynthDictSplatArgumentNode { private predicate synthDictSplatArgumentNodeStoreStep( ArgumentNode nodeFrom, DictionaryElementContent c, SynthDictSplatArgumentNode nodeTo ) { - exists(string name, CallNode call, ArgumentPosition keywordPos | + exists(string name, Cfg::CallNode call, ArgumentPosition keywordPos | nodeTo = TSynthDictSplatArgumentNode(call) and getCallArg(call, _, _, nodeFrom, keywordPos) and keywordPos.isKeyword(name) and @@ -289,7 +305,7 @@ abstract class PostUpdateNodeImpl extends Node { * Synthetic post-update nodes for synthetic nodes need to be listed one by one. */ class SyntheticPostUpdateNode extends PostUpdateNodeImpl, TSyntheticPostUpdateNode { - ControlFlowNode node; + Cfg::ControlFlowNode node; SyntheticPostUpdateNode() { this = TSyntheticPostUpdateNode(node) } @@ -333,16 +349,42 @@ module LocalFlow { // `x = f(42)` // nodeFrom is `f(42)` // nodeTo is `x` - exists(AssignmentDefinition def | + // + // We use the CFG-level `DefinitionNode.getValue()` directly rather + // than going through SSA, because the new SSA library prunes write + // definitions that have no subsequent read in the same scope (e.g. + // a module-level `def f():` whose `f` is only read inside other + // functions). The CFG-level link is unconditional. + // + // The Name-target restriction mirrors legacy ESSA's + // `SsaDefinitions::assignment_definition`, which required + // `defn.(NameNode).defines(v)`. Subscript and attribute writes + // (`x[i] = 42`, `obj.attr = 42`) are intentionally excluded — their + // value flow is handled by the content-flow / `AttrWrite` machinery, + // not by a local-flow step *into* the Subscript/Attribute expression. + // Excluding them is essential for keeping augmented-assignment + // targets (`x[i] += 42`) classifiable as `LocalSourceNode` on the + // read side: the single canonical CFG node is both a load and a + // store, and any incoming local-flow step would disqualify it from + // being a local source. + exists(Cfg::DefinitionNode def | nodeFrom.(CfgNode).getNode() = def.getValue() and - nodeTo.(CfgNode).getNode() = def.getDefiningNode() + nodeTo.(CfgNode).getNode() = def and + def instanceof Cfg::NameNode and + // Parameter defaults are evaluated in the enclosing scope, while the + // parameter itself lives in the function's scope. The cross-scope + // edge is provided by `runtimeJumpStep` instead. + not exists(Py::Parameter param | def.getNode() = param.asName()) ) or // With definition // `with f(42) as x:` // nodeFrom is `f(42)` // nodeTo is `x` - exists(With with, ControlFlowNode contextManager, WithDefinition withDef, ControlFlowNode var | + exists( + With with, Cfg::ControlFlowNode contextManager, SsaImpl::WithDefinition withDef, + Cfg::ControlFlowNode var + | var = withDef.getDefiningNode() | nodeFrom.(CfgNode).getNode() = contextManager and @@ -361,13 +403,13 @@ module LocalFlow { predicate expressionFlowStep(Node nodeFrom, Node nodeTo) { // If expressions - nodeFrom.asCfgNode() = nodeTo.asCfgNode().(IfExprNode).getAnOperand() + nodeFrom.asCfgNode() = nodeTo.asCfgNode().(Cfg::IfExprNode).getAnOperand() or // Assignment expressions - nodeFrom.asCfgNode() = nodeTo.asCfgNode().(AssignmentExprNode).getValue() + nodeFrom.asCfgNode() = nodeTo.asCfgNode().(Cfg::AssignmentExprNode).getValue() or // boolean inline expressions such as `x or y` or `x and y` - nodeFrom.asCfgNode() = nodeTo.asCfgNode().(BoolExprNode).getAnOperand() + nodeFrom.asCfgNode() = nodeTo.asCfgNode().(Cfg::BoolExprNode).getAnOperand() or // Flow inside an unpacking assignment iterableUnpackingFlowStep(nodeFrom, nodeTo) @@ -376,12 +418,25 @@ module LocalFlow { matchFlowStep(nodeFrom, nodeTo) } - predicate useToNextUse(NameNode nodeFrom, NameNode nodeTo) { - AdjacentUses::adjacentUseUse(nodeFrom, nodeTo) + predicate useToNextUse(Cfg::NameNode nodeFrom, Cfg::NameNode nodeTo) { + // The SSA-level adjacent-use predicate works on specific CFG variants + // (e.g. boolean-outcome `[true]`/`[false]` or emptiness `[empty]`/`[non-empty]` + // splits of the same AST node), but dataflow values are insensitive to + // those splits — there is at most one `CfgNode` per AST. Project both + // ends through `.getNode()` so all variants contribute their use-use + // edges to the canonical pair. + exists(Cfg::NameNode fromVariant, Cfg::NameNode toVariant | + SsaImpl::AdjacentUses::adjacentUseUse(fromVariant, toVariant) and + fromVariant.getNode() = nodeFrom.getNode() and + toVariant.getNode() = nodeTo.getNode() + ) } - predicate defToFirstUse(EssaVariable var, NameNode nodeTo) { - AdjacentUses::firstUse(var.getDefinition(), nodeTo) + predicate defToFirstUse(SsaImpl::EssaVariable var, Cfg::NameNode nodeTo) { + exists(Cfg::NameNode toVariant | + SsaImpl::AdjacentUses::firstUse(var.getDefinition(), toVariant) and + toVariant.getNode() = nodeTo.getNode() + ) } predicate useUseFlowStep(Node nodeFrom, Node nodeTo) { @@ -390,12 +445,13 @@ module LocalFlow { // `x = f(y)` // nodeFrom is `y` on first line // nodeTo is `y` on second line - exists(EssaDefinition def | - nodeFrom.(CfgNode).getNode() = def.(EssaNodeDefinition).getDefiningNode() + exists(SsaImpl::EssaDefinition def, Cfg::NameNode toVariant | + nodeFrom.(CfgNode).getNode() = def.(SsaImpl::EssaNodeDefinition).getDefiningNode() or nodeFrom.(ScopeEntryDefinitionNode).getDefinition() = def | - AdjacentUses::firstUse(def, nodeTo.(CfgNode).getNode()) + SsaImpl::AdjacentUses::firstUse(def, toVariant) and + toVariant.getNode() = nodeTo.(CfgNode).getNode().getNode() ) or // Next use after use @@ -557,9 +613,9 @@ predicate runtimeJumpStep(Node nodeFrom, Node nodeTo) { // a parameter with a default value, since the parameter will be in the scope of the // function, while the default value itself will be in the scope that _defines_ the // function. - exists(ParameterDefinition param | + exists(SsaImpl::ParameterDefinition param | // note: we go to the _control-flow node_ of the parameter, and not the ESSA node of the parameter, since for type-tracking, the ESSA node is not a LocalSourceNode, so we would get in trouble. - nodeFrom.asCfgNode() = param.getDefault() and + nodeFrom.asCfgNode().getNode() = param.getParameter().(Parameter).getDefault() and nodeTo.asCfgNode() = param.getDefiningNode() ) or @@ -663,7 +719,7 @@ predicate neverSkipInPathGraph(Node n) { // ``` // we would end up saying that the path MUST not skip the x in `y = x`, which is just // annoying and doesn't help the path explanation become clearer. - n.asCfgNode() = any(EssaNodeDefinition def).getDefiningNode() + n.asCfgNode() = any(SsaImpl::EssaNodeDefinition def).getDefiningNode() } /** @@ -874,7 +930,7 @@ predicate listStoreStep(CfgNode nodeFrom, ListElementContent c, CfgNode nodeTo) // nodeFrom is `42`, cfg node // nodeTo is the list, `[..., 42, ...]`, cfg node // c denotes element of list - nodeTo.getNode().(ListNode).getAnElement() = nodeFrom.getNode() and + nodeTo.getNode().(Cfg::ListNode).getAnElement() = nodeFrom.getNode() and not nodeTo.getNode() instanceof UnpackingAssignmentSequenceTarget and // Suppress unused variable warning c = c @@ -887,7 +943,7 @@ predicate setStoreStep(CfgNode nodeFrom, SetElementContent c, CfgNode nodeTo) { // nodeFrom is `42`, cfg node // nodeTo is the set, `{..., 42, ...}`, cfg node // c denotes element of list - nodeTo.getNode().(SetNode).getAnElement() = nodeFrom.getNode() and + nodeTo.getNode().(Cfg::SetNode).getAnElement() = nodeFrom.getNode() and // Suppress unused variable warning c = c } @@ -900,7 +956,7 @@ predicate tupleStoreStep(CfgNode nodeFrom, TupleElementContent c, CfgNode nodeTo // nodeTo is the tuple, `(..., 42, ...)`, cfg node // c denotes element of tuple and index of nodeFrom exists(int n | - nodeTo.getNode().(TupleNode).getElement(n) = nodeFrom.getNode() and + nodeTo.getNode().(Cfg::TupleNode).getElement(n) = nodeFrom.getNode() and not nodeTo.getNode() instanceof UnpackingAssignmentSequenceTarget and c.getIndex() = n ) @@ -914,7 +970,7 @@ predicate dictStoreStep(CfgNode nodeFrom, DictionaryElementContent c, Node nodeT // nodeTo is the dict, `{..., "key" = 42, ...}`, cfg node // c denotes element of dictionary and the key `"key"` exists(KeyValuePair item | - item = nodeTo.asCfgNode().(DictNode).getNode().(Dict).getAnItem() and + item = nodeTo.asCfgNode().(Cfg::DictNode).getNode().(Dict).getAnItem() and nodeFrom.getNode().getNode() = item.getValue() and c.getKey() = item.getKey().(StringLiteral).getS() ) @@ -929,9 +985,9 @@ predicate dictStoreStep(CfgNode nodeFrom, DictionaryElementContent c, Node nodeT private predicate moreDictStoreSteps(CfgNode nodeFrom, DictionaryElementContent c, Node nodeTo) { // NOTE: It's important to add logic to the newtype definition of // DictionaryElementContent if you add new cases here. - exists(SubscriptNode subscript | + exists(Cfg::SubscriptNode subscript | nodeTo.(PostUpdateNode).getPreUpdateNode().asCfgNode() = subscript.getObject() and - nodeFrom.asCfgNode() = subscript.(DefinitionNode).getValue() and + nodeFrom.asCfgNode() = subscript.(Cfg::DefinitionNode).getValue() and c.getKey() = subscript.getIndex().getNode().(StringLiteral).getText() ) or @@ -944,8 +1000,8 @@ private predicate moreDictStoreSteps(CfgNode nodeFrom, DictionaryElementContent } predicate dictClearStep(Node node, DictionaryElementContent c) { - exists(SubscriptNode subscript | - subscript instanceof DefinitionNode and + exists(Cfg::SubscriptNode subscript | + subscript instanceof Cfg::DefinitionNode and node.asCfgNode() = subscript.getObject() and c.getKey() = subscript.getIndex().getNode().(StringLiteral).getText() ) @@ -1024,7 +1080,7 @@ predicate subscriptReadStep(CfgNode nodeFrom, Content c, CfgNode nodeTo) { // nodeFrom is `l`, cfg node // nodeTo is `l[3]`, cfg node // c is compatible with 3 - nodeFrom.getNode() = nodeTo.getNode().(SubscriptNode).getObject() and + nodeFrom.getNode() = nodeTo.getNode().(Cfg::SubscriptNode).getObject() and ( c instanceof ListElementContent or @@ -1033,10 +1089,10 @@ predicate subscriptReadStep(CfgNode nodeFrom, Content c, CfgNode nodeTo) { c instanceof DictionaryElementAnyContent or c.(TupleElementContent).getIndex() = - nodeTo.getNode().(SubscriptNode).getIndex().getNode().(IntegerLiteral).getValue() + nodeTo.getNode().(Cfg::SubscriptNode).getIndex().getNode().(IntegerLiteral).getValue() or c.(DictionaryElementContent).getKey() = - nodeTo.getNode().(SubscriptNode).getIndex().getNode().(StringLiteral).getS() + nodeTo.getNode().(Cfg::SubscriptNode).getIndex().getNode().(StringLiteral).getS() ) } @@ -1091,7 +1147,7 @@ module Conversions { predicate formatReadStep(Node nodeFrom, ContentSet c, Node nodeTo) { // % formatting - exists(BinaryExprNode fmt | fmt = nodeTo.asCfgNode() | + exists(Cfg::BinaryExprNode fmt | fmt = nodeTo.asCfgNode() | fmt.getOp() instanceof Mod and fmt.getRight() = nodeFrom.asCfgNode() ) and diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPublic.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPublic.qll index 8ee269cab34e..1fc1e14ec5f4 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPublic.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPublic.qll @@ -5,11 +5,14 @@ overlay[local] module; private import python +private import semmle.python.controlflow.internal.Cfg as Cfg +private import semmle.python.controlflow.internal.AstNodeImpl as CfgImpl +private import codeql.controlflow.SuccessorType private import DataFlowPrivate import semmle.python.dataflow.new.TypeTracking import Attributes import LocalSources -private import semmle.python.essa.SsaCompute +private import semmle.python.dataflow.new.internal.SsaImpl as SsaImpl private import semmle.python.dataflow.new.internal.ImportStar private import semmle.python.frameworks.data.ModelsAsData private import FlowSummaryImpl as FlowSummaryImpl @@ -27,16 +30,18 @@ private import semmle.python.frameworks.data.ModelsAsData overlay[local] newtype TNode = /** A node corresponding to a control flow node. */ - TCfgNode(ControlFlowNode node) { + TCfgNode(Cfg::ControlFlowNode node) { isExpressionNode(node) or - node.getNode() instanceof Pattern + node.injects(_) and node.getNode() instanceof Pattern } or /** * A node corresponding to a scope entry definition. That is, the value of a variable * as it enters a scope. */ - TScopeEntryDefinitionNode(ScopeEntryDefinition def) { not def.getScope() instanceof Module } or + TScopeEntryDefinitionNode(SsaImpl::ScopeEntryDefinition def) { + not def.getScope() instanceof Module + } or /** * A synthetic node representing the value of an object before a state change. * @@ -47,13 +52,15 @@ newtype TNode = // NOTE: since we can't rely on the call graph, but we want to have synthetic // pre-update nodes for class calls, we end up getting synthetic pre-update nodes for // ALL calls :| - TSyntheticPreUpdateNode(CallNode call) or + TSyntheticPreUpdateNode(Cfg::CallNode call) { call.injects(_) } or /** * A synthetic node representing the value of an object after a state change. * See QLDoc for `PostUpdateNode`. */ - TSyntheticPostUpdateNode(ControlFlowNode node) { - exists(CallNode call | + TSyntheticPostUpdateNode(Cfg::ControlFlowNode node) { + node.injects(_) and + ( + exists(Cfg::CallNode call | node = call.getArg(_) or node = call.getArgByName(_) @@ -62,12 +69,12 @@ newtype TNode = node = call.getFunction() ) or - node = any(AttrNode a).getObject() + node = any(Cfg::AttrNode a).getObject() or - node = any(SubscriptNode s).getObject() + node = any(Cfg::SubscriptNode s).getObject() or // self parameter when used implicitly in `super()` - exists(Class cls, Function func, ParameterDefinition def | + exists(Class cls, Function func, SsaImpl::ParameterDefinition def | func = cls.getAMethod() and not isStaticmethod(func) and // this matches what we do in ExtractedParameterNode @@ -77,6 +84,7 @@ newtype TNode = or // the iterable argument to the implicit comprehension function node.getNode() = any(Comp c).getIterable() + ) } or /** A node representing a global (module-level) variable in a specific module. */ TModuleVariableNode(Module m, GlobalVariable v) { v.getScope() = m } or @@ -112,7 +120,9 @@ newtype TNode = exists(ParameterPosition ppos | ppos.isStarArgs(_) | exists(callable.getParameter(ppos))) } or /** A synthetic node to capture keyword arguments that are passed to a `**kwargs` parameter. */ - TSynthDictSplatArgumentNode(CallNode call) { exists(call.getArgByName(_)) } or + TSynthDictSplatArgumentNode(Cfg::CallNode call) { + call.injects(_) and exists(call.getArgByName(_)) + } or /** A synthetic node to allow flow to keyword parameters from a `**kwargs` argument. */ TSynthDictSplatParameterNode(DataFlowCallable callable) { exists(ParameterPosition ppos | ppos.isKeyword(_) | exists(callable.getParameter(ppos))) @@ -128,15 +138,15 @@ newtype TNode = * A synthetic node representing the values of the variables captured * by the callable being called. */ - TSynthCapturedVariablesArgumentNode(ControlFlowNode callable) { - callable = any(CallNode c).getFunction() + TSynthCapturedVariablesArgumentNode(Cfg::ControlFlowNode callable) { + callable.injects(_) and callable = any(Cfg::CallNode c).getFunction() } or /** * A synthetic node representing the values of the variables captured * by the callable being called, after the output has been computed. */ - TSynthCapturedVariablesArgumentPostUpdateNode(ControlFlowNode callable) { - callable = any(CallNode c).getFunction() + TSynthCapturedVariablesArgumentPostUpdateNode(Cfg::ControlFlowNode callable) { + callable.injects(_) and callable = any(Cfg::CallNode c).getFunction() } or /** A synthetic node representing the values of variables captured by a comprehension. */ TSynthCompCapturedVariablesArgumentNode(Comp comp) { @@ -194,7 +204,7 @@ class Node extends TNode { } /** Gets the control-flow node corresponding to this node, if any. */ - ControlFlowNode asCfgNode() { none() } + Cfg::ControlFlowNode asCfgNode() { none() } /** Gets the expression corresponding to this node, if any. */ Expr asExpr() { none() } @@ -207,14 +217,14 @@ class Node extends TNode { /** A data-flow node corresponding to a control-flow node. */ class CfgNode extends Node, TCfgNode { - ControlFlowNode node; + Cfg::ControlFlowNode node; CfgNode() { this = TCfgNode(node) } - /** Gets the `ControlFlowNode` represented by this data-flow node. */ - ControlFlowNode getNode() { result = node } + /** Gets the `Cfg::ControlFlowNode` represented by this data-flow node. */ + Cfg::ControlFlowNode getNode() { result = node } - override ControlFlowNode asCfgNode() { result = node } + override Cfg::ControlFlowNode asCfgNode() { result = node } /** Gets a textual representation of this element. */ override string toString() { result = node.toString() } @@ -224,9 +234,9 @@ class CfgNode extends Node, TCfgNode { override Location getLocation() { result = node.getLocation() } } -/** A data-flow node corresponding to a `CallNode` in the control-flow graph. */ +/** A data-flow node corresponding to a `Cfg::CallNode` in the control-flow graph. */ class CallCfgNode extends CfgNode, LocalSourceNode { - override CallNode node; + override Cfg::CallNode node; /** * Gets the data-flow node for the function component of the call corresponding to this data-flow @@ -307,15 +317,15 @@ ExprNode exprNode(DataFlowExpr e) { result.getNode().getNode() = e } * as it enters a scope. */ class ScopeEntryDefinitionNode extends Node, TScopeEntryDefinitionNode { - ScopeEntryDefinition def; + SsaImpl::ScopeEntryDefinition def; ScopeEntryDefinitionNode() { this = TScopeEntryDefinitionNode(def) } - /** Gets the `ScopeEntryDefinition` associated with this node. */ - ScopeEntryDefinition getDefinition() { result = def } + /** Gets the `SsaImpl::ScopeEntryDefinition` associated with this node. */ + SsaImpl::ScopeEntryDefinition getDefinition() { result = def } /** Gets the source variable represented by this node. */ - SsaSourceVariable getVariable() { result = def.getSourceVariable() } + SsaImpl::SsaSourceVariable getVariable() { result = def.getSourceVariable() } override Location getLocation() { result = def.getLocation() } @@ -337,7 +347,7 @@ class ParameterNode extends Node instanceof ParameterNodeImpl { /** A parameter node found in the source code (not in a summary). */ class ExtractedParameterNode extends ParameterNodeImpl, CfgNode { //, LocalSourceNode { - ParameterDefinition def; + SsaImpl::ParameterDefinition def; ExtractedParameterNode() { node = def.getDefiningNode() } @@ -368,10 +378,10 @@ Node getCallArgApproximation() { exists(Class c | result.asExpr() = c.getAMethod().getArg(0)) or // the object part of an attribute expression (which might be a bound method) - result.asCfgNode() = any(AttrNode a).getObject() + result.asCfgNode() = any(Cfg::AttrNode a).getObject() or // the function part of any call - result.asCfgNode() = any(CallNode c).getFunction() + result.asCfgNode() = any(Cfg::CallNode c).getFunction() } /** Gets the extracted argument nodes that do not rely on `getCallArg`. */ @@ -380,7 +390,7 @@ private Node implicitArgumentNode() { normalCallArg(_, result, _) or // and self arguments - result.asCfgNode() = any(CallNode c).getFunction().(AttrNode).getObject() + result.asCfgNode() = any(Cfg::CallNode c).getFunction().(Cfg::AttrNode).getObject() or // for comprehensions, we allow the synthetic `iterable` argument result.asExpr() = any(Comp c).getIterable() @@ -489,17 +499,20 @@ class ModuleVariableNode extends Node, TModuleVariableNode { not result.getScope() = mod } - /** Gets an `EssaNode` that corresponds to an assignment of this global variable. */ + /** Gets a CFG node that corresponds to an assignment of this global variable. */ Node getAWrite() { - any(EssaNodeDefinition def).definedBy(var, result.asCfgNode().(DefinitionNode)) + exists(Cfg::NameNode n | + n.defines(var) and + result.asCfgNode() = n + ) } /** Gets the possible values of the variable at the end of import time */ CfgNode getADefiningWrite() { - exists(SsaVariable def | - def = any(SsaVariable ssa_var).getAnUltimateDefinition() and - def.getDefinition() = result.asCfgNode() and - def.getVariable() = var + exists(SsaImpl::EssaVariable def | + def = any(SsaImpl::EssaVariable ssa_var).getAnUltimateDefinition() and + def.getDefinition().(SsaImpl::EssaNodeDefinition).getDefiningNode() = result.asCfgNode() and + def.getSourceVariable().getVariable() = var ) } @@ -516,7 +529,7 @@ private ModuleVariableNode import_star_read(Node n) { overlay[global] pragma[nomagic] private predicate resolved_import_star_module(Module m, string name, Node n) { - exists(NameNode nn | nn = n.asCfgNode() | + exists(Cfg::NameNode nn | nn = n.asCfgNode() | ImportStar::importStarResolvesTo(pragma[only_bind_into](nn), m) and nn.getId() = name ) @@ -574,88 +587,88 @@ class StarPatternElementNode extends Node, TStarPatternElementNode { } /** - * Gets a node that controls whether other nodes are evaluated. + * A node that participates in a conditional split: a CFG node whose + * evaluation outcome (true/false) is used to choose between two + * successor basic blocks. In the shared CFG, branching is detected + * via typed successor edges (boolean successor types) on the unique + * `injects` node for each AST expression. * - * In the base case, this is the last node of `conditionBlock`, and `flipped` is `false`. - * This definition accounts for (short circuting) `and`- and `or`-expressions, as the structure - * of basic blocks will reflect their semantics. - * - * However, in the program - * ```python - * if not is_safe(path): - * return - * ``` - * the last node in the `ConditionBlock` is `not is_safe(path)`. + * Users typically obtain a `GuardNode` by casting from a more specific + * Cfg type: `g.(Cfg::CallNode)` for a call-based check, etc. + */ +class GuardNode extends Cfg::ControlFlowNode { + GuardNode() { + // This node has boolean successor edges (directly or via wrapping). + outcomeOfGuard(this, _, _) + } + + /** Holds if this guard controls block `b` upon evaluating to `branch`. */ + predicate controlsBlock(Cfg::BasicBlock b, boolean branch) { + exists(CfgImpl::BasicBlock outcomeBB | + outcomeOfGuard(this, outcomeBB, branch) and + outcomeBB.dominates(b) + ) + } +} + +/** + * Holds if `outcomeBB` is the basic block entered when `guard` evaluates + * to `branch`. * - * We would like to consider also `is_safe(path)` a guard node, albeit with `flipped` being `true`. - * Thus we recurse through `not`-expressions. + * For a direct guard `if g:`, the outcome BB starts at the after-value + * node for the matching branch. For wrapped guards like `not g` or + * `g == True`, we follow those wrappers up the AST to find the + * outermost expression that actually branches, with an appropriate + * polarity transform. */ -ControlFlowNode guardNode(ConditionBlock conditionBlock, boolean flipped) { - // Base case: the last node truly does determine which successor is chosen - result = conditionBlock.getLastNode() and - flipped = false +private predicate outcomeOfGuard( + Cfg::ControlFlowNode guard, CfgImpl::BasicBlock outcomeBB, boolean branch +) { + // Base case: the guard has boolean successor edges. + // Only the canonical representative (injects) can act as a guard base. + guard.injects(_) and + exists(BooleanSuccessor t | + t.getValue() = branch and + outcomeBB = guard.(CfgImpl::ControlFlowNode).getASuccessor(t).getBasicBlock() + ) or - // Recursive cases: - // if a guard node is a `not`-expression, - // the operand is also a guard node, but with inverted polarity. - exists(UnaryExprNode notNode | - result = notNode.getOperand() and - notNode.getNode().getOp() instanceof Not - | - notNode = guardNode(conditionBlock, flipped.booleanNot()) + // Recursive: `not guard` — same outcome split as `guard`, flipped. + exists(Cfg::UnaryExprNode notNode, boolean notBranch | + notNode.injects(_) and + notNode.getOperand().getNode() = guard.getNode() and + notNode.getNode().getOp() instanceof Not and + outcomeOfGuard(notNode, outcomeBB, notBranch) and + branch = notBranch.booleanNot() ) or - // if a guard node is compared to a boolean literal, - // the other operand is also a guard node, - // but with polarity depending on the literal (and on the comparison). - exists(CompareNode cmpNode, Cmpop op, ControlFlowNode b, boolean should_flip | + // Recursive: comparisons against a boolean literal. + exists( + Cfg::CompareNode cmpNode, Cmpop op, Cfg::ControlFlowNode otherOperand, + Cfg::ControlFlowNode guardOperand, boolean polarity, boolean cmpBranch + | + cmpNode.injects(_) and + guardOperand.getNode() = guard.getNode() and ( - cmpNode.operands(result, op, b) or - cmpNode.operands(b, op, result) + cmpNode.operands(guardOperand, op, otherOperand) or + cmpNode.operands(otherOperand, op, guardOperand) ) and - not result.getNode() instanceof BooleanLiteral and + not guard.getNode() instanceof BooleanLiteral and ( - // comparing to the boolean (op instanceof Eq or op instanceof Is) and - // we should flip if the value compared against, here the value of `b`, is false - should_flip = b.getNode().(BooleanLiteral).booleanValue().booleanNot() + polarity = otherOperand.getNode().(BooleanLiteral).booleanValue() or - // comparing to the negation of the boolean (op instanceof NotEq or op instanceof IsNot) and - // again, we should flip if the value compared against, here the value of `not b`, is false. - // That is, if the value of `b` is true. - should_flip = b.getNode().(BooleanLiteral).booleanValue() - ) - | - // we flip `flipped` according to `should_flip` via the formula `flipped xor should_flip`. - flipped in [true, false] and - cmpNode = guardNode(conditionBlock, flipped.booleanXor(should_flip)) + polarity = otherOperand.getNode().(BooleanLiteral).booleanValue().booleanNot() + ) and + outcomeOfGuard(cmpNode, outcomeBB, cmpBranch) and + branch = cmpBranch.booleanXor(polarity.booleanNot()) ) } -/** - * A node that controls whether other nodes are evaluated. - * - * The field `flipped` allows us to match `GuardNode`s underneath - * `not`-expressions and still choose the appropriate branch. - */ -class GuardNode extends ControlFlowNode { - ConditionBlock conditionBlock; - boolean flipped; - - GuardNode() { this = guardNode(conditionBlock, flipped) } - - /** Holds if this guard controls block `b` upon evaluating to `branch`. */ - predicate controlsBlock(BasicBlock b, boolean branch) { - branch in [true, false] and - conditionBlock.controls(b, branch.booleanXor(flipped)) - } -} - /** * Holds if the guard `g` validates `node` upon evaluating to `branch`. */ -signature predicate guardChecksSig(GuardNode g, ControlFlowNode node, boolean branch); +signature predicate guardChecksSig(GuardNode g, Cfg::ControlFlowNode node, boolean branch); /** * Provides a set of barrier nodes for a guard that validates a node. @@ -670,7 +683,9 @@ module BarrierGuard { result = ParameterizedBarrierGuard::getABarrierNode(_) } - private predicate extendedGuardChecks(GuardNode g, ControlFlowNode node, boolean branch, Unit u) { + private predicate extendedGuardChecks( + GuardNode g, Cfg::ControlFlowNode node, boolean branch, Unit u + ) { guardChecks(g, node, branch) and u = u } @@ -680,7 +695,7 @@ bindingset[this] private signature class ParamSig; private module WithParam { - signature predicate guardChecksSig(GuardNode g, ControlFlowNode node, boolean branch, P param); + signature predicate guardChecksSig(GuardNode g, Cfg::ControlFlowNode node, boolean branch, P param); } /** @@ -693,10 +708,16 @@ module ParameterizedBarrierGuard::guardChecksSig/4 guar /** Gets a node that is safely guarded by the given guard check with parameter `param`. */ overlay[global] ExprNode getABarrierNode(P param) { - exists(GuardNode g, EssaDefinition def, ControlFlowNode node, boolean branch | - AdjacentUses::useOfDef(def, node) and + exists(GuardNode g, SsaImpl::EssaDefinition def, Cfg::ControlFlowNode node, boolean branch | + SsaImpl::AdjacentUses::useOfDef(def, node) and guardChecks(g, node, branch, param) and - AdjacentUses::useOfDef(def, result.asCfgNode()) and + SsaImpl::AdjacentUses::useOfDef(def, result.asCfgNode()) and + // The protected use must be a different SSA position than the test + // position itself: `controlsBlock` is reflexive on dominance, and + // the test expression is an SSA-use position on the def-use chain. + // Without this guard, the test position would be returned as a + // barrier and block flow before it can reach genuine branch uses. + node != result.asCfgNode() and g.controlsBlock(result.asCfgNode().getBasicBlock(), branch) ) } @@ -712,7 +733,7 @@ module ExternalBarrierGuard { private import semmle.python.ApiGraphs overlay[global] - private predicate guardCheck(GuardNode g, ControlFlowNode node, boolean branch, string kind) { + private predicate guardCheck(GuardNode g, Cfg::ControlFlowNode node, boolean branch, string kind) { exists(API::CallNode call, API::Node parameter | parameter = call.getAParameter() and parameter = ModelOutput::getABarrierGuardNode(kind, branch) @@ -748,10 +769,10 @@ newtype TContent = TSetElementContent() or /** An element of a tuple at a specific index. */ TTupleElementContent(int index) { - exists(any(TupleNode tn).getElement(index)) + exists(any(Cfg::TupleNode tn).getElement(index)) or // Arguments can overflow and end up in the starred parameter tuple. - exists(any(CallNode cn).getArg(index)) + exists(any(Cfg::CallNode cn).getArg(index)) or // since flow summaries might use tuples, we ensure that we at least have valid // TTupleElementContent for the 0..7 (7 was picked to match `small_tuple` in @@ -768,10 +789,14 @@ newtype TContent = or // d["key"] = ... key = - any(SubscriptNode sub | sub.isStore() | sub.getIndex().getNode().(StringLiteral).getText()) + any(Cfg::SubscriptNode sub | + sub.isStore() + | + sub.getIndex().getNode().(StringLiteral).getText() + ) or // d.setdefault("key", ...) - exists(CallNode call | call.getFunction().(AttrNode).getName() = "setdefault" | + exists(Cfg::CallNode call | call.getFunction().(Cfg::AttrNode).getName() = "setdefault" | key = call.getArg(0).getNode().(StringLiteral).getText() ) } or diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/ImportResolution.qll b/python/ql/lib/semmle/python/dataflow/new/internal/ImportResolution.qll index f62c4efcac8a..38ec4d146a46 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/ImportResolution.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/ImportResolution.qll @@ -5,17 +5,18 @@ */ private import python +private import semmle.python.controlflow.internal.Cfg as Cfg +private import semmle.python.dataflow.new.internal.SsaImpl as SsaImpl private import semmle.python.dataflow.new.DataFlow private import semmle.python.dataflow.new.internal.ImportStar private import semmle.python.dataflow.new.TypeTracking private import semmle.python.dataflow.new.internal.DataFlowPrivate /** - * Holds if `init` is a package's `__init__.py` and `var` is a global variable in - * `init` whose name matches a submodule of the package. - * - * Inlined from `SsaSource::init_module_submodule_defn` to avoid pulling - * `semmle.python.essa.SsaDefinitions` into the new dataflow stack. + * Holds if the name of `var` refers to a submodule of a package and `init` is + * the `__init__` module of that package. Locally inlined replacement for the + * legacy `SsaSource::init_module_submodule_defn` so that this module has no + * direct dependency on `semmle.python.essa.SsaDefinitions`. */ private predicate initModuleSubmoduleDefn(GlobalVariable var, Module init) { init.isPackageInit() and @@ -81,13 +82,19 @@ module ImportResolution { * Holds if there is an ESSA step from `defFrom` to `defTo`, which should be allowed * for import resolution. */ - private predicate allowedEssaImportStep(EssaDefinition defFrom, EssaDefinition defTo) { + private predicate allowedEssaImportStep( + SsaImpl::EssaDefinition defFrom, SsaImpl::EssaDefinition defTo + ) { // to handle definitions guarded by if-then-else - defFrom = defTo.(PhiFunction).getAnInput() + defFrom = defTo.(SsaImpl::PhiFunction).getAnInput() or - // refined variable - // example: https://github.com/nvbn/thefuck/blob/ceeaeab94b5df5a4fe9d94d61e4f6b0bbea96378/thefuck/utils.py#L25-L45 - defFrom = defTo.(EssaNodeRefinement).getInput().getDefinition() + // to handle uncertain writes such as `from X import *`, which create an + // uncertain SSA definition for every name in the importing scope. The + // immediately preceding definition is still potentially the value of the + // module export. + SsaImpl::Ssa::uncertainWriteDefinitionInput(defTo, defFrom) + // Note: legacy ESSA refinement-step (e.g. for `foo.bar = X`) is + // not modelled in the new SSA beyond the cases handled above. } /** @@ -104,30 +111,32 @@ module ImportResolution { // Definitions made inside `m` itself // // for code such as `foo = ...; foo.bar = ...` there will be TWO - // EssaDefinition/EssaVariable. One for `foo = ...` (AssignmentDefinition) and one + // SsaImpl::EssaDefinition/SsaImpl::EssaVariable. One for `foo = ...` (SsaImpl::AssignmentDefinition) and one // for `foo.bar = ...`. The one for `foo.bar = ...` (EssaNodeRefinement). The // EssaNodeRefinement is the one that will reach the end of the module (normal // exit). // // However, we cannot just use the EssaNodeRefinement as the `val`, because the // normal data-flow depends on use-use flow, and use-use flow targets CFG nodes not - // EssaNodes. So we need to go back from the EssaDefinition/EssaVariable that + // EssaNodes. So we need to go back from the SsaImpl::EssaDefinition/SsaImpl::EssaVariable that // reaches the end of the module, to the first definition of the variable, and then // track forwards using use-use flow to find a suitable CFG node that has flow into // it from use-use flow. - exists(EssaVariable lastUseVar, EssaVariable firstDef | + exists(SsaImpl::EssaVariable lastUseVar, SsaImpl::EssaVariable firstDef | lastUseVar.getName() = name and // we ignore special variable $ introduced by our analysis (not used for anything) // we ignore special variable * introduced by `from import *` -- TODO: understand why we even have this? not name in ["$", "*"] and - lastUseVar.getAUse() = m.getANormalExit() and + exists(Cfg::ControlFlowNode exit | + exit.isNormalExit() and exit.getScope() = m and lastUseVar.getAUse() = exit + ) and allowedEssaImportStep*(firstDef, lastUseVar) and not allowedEssaImportStep(_, firstDef) | not LocalFlow::defToFirstUse(firstDef, _) and - val.asCfgNode() = firstDef.getDefinition().(EssaNodeDefinition).getDefiningNode() + val.asCfgNode() = firstDef.getDefinition().(SsaImpl::EssaNodeDefinition).getDefiningNode() or - exists(ControlFlowNode mid, ControlFlowNode end | + exists(Cfg::ControlFlowNode mid, Cfg::ControlFlowNode end | LocalFlow::defToFirstUse(firstDef, mid) and LocalFlow::useToNextUse*(mid, end) and not LocalFlow::useToNextUse(end, _) and @@ -155,9 +164,9 @@ module ImportResolution { * handles simple cases where we can statically tell that this is the case. */ private predicate all_mentions_name(Module m, string name) { - exists(DefinitionNode def, SequenceNode n | + exists(Cfg::DefinitionNode def, Cfg::SequenceNode n | def.getValue() = n and - def.(NameNode).getId() = "__all__" and + def.(Cfg::NameNode).getId() = "__all__" and def.getScope() = m and any(StringLiteral s | s.getText() = name) = n.getAnElement().getNode() ) @@ -170,18 +179,20 @@ module ImportResolution { */ private predicate no_or_complicated_all(Module m) { // No mention of `__all__` in the module - not exists(DefinitionNode def | def.getScope() = m and def.(NameNode).getId() = "__all__") + not exists(Cfg::DefinitionNode def | + def.getScope() = m and def.(Cfg::NameNode).getId() = "__all__" + ) or // `__all__` is set to a non-sequence value - exists(DefinitionNode def | - def.(NameNode).getId() = "__all__" and + exists(Cfg::DefinitionNode def | + def.(Cfg::NameNode).getId() = "__all__" and def.getScope() = m and - not def.getValue() instanceof SequenceNode + not def.getValue() instanceof Cfg::SequenceNode ) or // `__all__` is used in some way that doesn't involve storing a value in it. This usually means // it is being mutated through `append` or `extend`, which we don't handle. - exists(NameNode n | n.getId() = "__all__" and n.getScope() = m and n.isLoad()) + exists(Cfg::NameNode n | n.getId() = "__all__" and n.getScope() = m and n.isLoad()) } private predicate potential_module_export(Module m, string name) { @@ -189,7 +200,7 @@ module ImportResolution { or no_or_complicated_all(m) and ( - exists(NameNode n | n.getId() = name and n.getScope() = m and name.charAt(0) != "_") + exists(Cfg::NameNode n | n.getId() = name and n.getScope() = m and name.charAt(0) != "_") or exists(Alias a | a.getAsname().(Name).getId() = name and a.getValue().getScope() = m) ) @@ -219,12 +230,12 @@ module ImportResolution { /** Gets a module that may have been added to `sys.modules`. */ private Module sys_modules_module_with_name(string name) { - exists(ControlFlowNode n, DataFlow::Node mod | - exists(SubscriptNode sub | + exists(Cfg::ControlFlowNode n, DataFlow::Node mod | + exists(Cfg::SubscriptNode sub | sub.getObject() = sys_modules_reference().asCfgNode() and sub.getIndex() = n and n.getNode().(StringLiteral).getText() = name and - sub.(DefinitionNode).getValue() = mod.asCfgNode() and + sub.(Cfg::DefinitionNode).getValue() = mod.asCfgNode() and mod = getModuleReference(result) ) ) @@ -336,11 +347,11 @@ module ImportResolution { // name as a submodule, we always consider that this attribute _could_ be a // reference to the submodule, even if we don't know that the submodule has been // imported yet. - exists(string submodule, Module package, EssaVariable var | + exists(string submodule, Module package, SsaImpl::EssaVariable var | submodule = var.getName() and - initModuleSubmoduleDefn(var.getSourceVariable(), package) and + initModuleSubmoduleDefn(var.getSourceVariable().getVariable(), package) and m = getModuleFromName(package.getPackageName() + "." + submodule) and - result.asCfgNode() = var.getDefinition().(EssaNodeDefinition).getDefiningNode() + result.asCfgNode() = var.getDefinition().(SsaImpl::EssaNodeDefinition).getDefiningNode() ) } diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/ImportStar.qll b/python/ql/lib/semmle/python/dataflow/new/internal/ImportStar.qll index 83f8ee862c39..8c906696be7a 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/ImportStar.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/ImportStar.qll @@ -3,6 +3,7 @@ overlay[local] module; private import python +private import semmle.python.controlflow.internal.Cfg as Cfg private import semmle.python.dataflow.new.internal.Builtins private import semmle.python.dataflow.new.internal.ImportResolution private import semmle.python.dataflow.new.DataFlow @@ -15,7 +16,7 @@ module ImportStar { */ overlay[local] cached - predicate namePossiblyDefinedInImportStar(NameNode n, string name, Scope s) { + predicate namePossiblyDefinedInImportStar(Cfg::NameNode n, string name, Scope s) { n.isLoad() and name = n.getId() and s = n.getScope().getEnclosingScope*() and @@ -52,7 +53,7 @@ module ImportStar { /** Holds if a global variable called `name` is assigned a value in the module `m`. */ cached predicate globalNameDefinedInModule(string name, Module m) { - exists(NameNode n | + exists(Cfg::NameNode n | not exists(LocalVariable v | n.defines(v)) and n.isStore() and name = n.getId() and @@ -66,7 +67,7 @@ module ImportStar { */ overlay[global] cached - predicate importStarResolvesTo(NameNode n, Module m) { + predicate importStarResolvesTo(Cfg::NameNode n, Module m) { m = getStarImported+(n.getEnclosingModule()) and globalNameDefinedInModule(n.getId(), m) and not isDefinedLocally(n.getNode()) @@ -99,7 +100,7 @@ module ImportStar { */ overlay[local] cached - ControlFlowNode potentialImportStarBase(Scope s) { - result = any(ImportStarNode n | n.getScope() = s).getModule() + Cfg::ControlFlowNode potentialImportStarBase(Scope s) { + result = any(Cfg::ImportStarNode n | n.getScope() = s).getModule() } } diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/IterableUnpacking.qll b/python/ql/lib/semmle/python/dataflow/new/internal/IterableUnpacking.qll index 5def15fa3c8a..ac7200115ce2 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/IterableUnpacking.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/IterableUnpacking.qll @@ -170,6 +170,8 @@ overlay[local] module; private import python +private import semmle.python.controlflow.internal.Cfg as Cfg +private import semmle.python.dataflow.new.internal.SsaImpl as SsaImpl private import DataFlowPublic /** @@ -178,7 +180,7 @@ private import DataFlowPublic * This class abstracts away the differing representations of comprehensions and * for statements. */ -class ForTarget extends ControlFlowNode { +class ForTarget extends Cfg::ControlFlowNode { Expr source; ForTarget() { @@ -198,7 +200,7 @@ class ForTarget extends ControlFlowNode { } /** The LHS of an assignment, it also records the assigned value. */ -class AssignmentTarget extends ControlFlowNode { +class AssignmentTarget extends Cfg::ControlFlowNode { Expr value; AssignmentTarget() { @@ -209,7 +211,7 @@ class AssignmentTarget extends ControlFlowNode { } /** A direct (or top-level) target of an unpacking assignment. */ -class UnpackingAssignmentDirectTarget extends ControlFlowNode instanceof SequenceNode { +class UnpackingAssignmentDirectTarget extends Cfg::ControlFlowNode instanceof Cfg::SequenceNode { Expr value; UnpackingAssignmentDirectTarget() { @@ -222,7 +224,7 @@ class UnpackingAssignmentDirectTarget extends ControlFlowNode instanceof Sequenc } /** A (possibly recursive) target of an unpacking assignment. */ -class UnpackingAssignmentTarget extends ControlFlowNode { +class UnpackingAssignmentTarget extends Cfg::ControlFlowNode { UnpackingAssignmentTarget() { this instanceof UnpackingAssignmentDirectTarget or @@ -231,10 +233,11 @@ class UnpackingAssignmentTarget extends ControlFlowNode { } /** A (possibly recursive) target of an unpacking assignment which is also a sequence. */ -class UnpackingAssignmentSequenceTarget extends UnpackingAssignmentTarget instanceof SequenceNode { - ControlFlowNode getElement(int i) { result = super.getElement(i) } +class UnpackingAssignmentSequenceTarget extends UnpackingAssignmentTarget instanceof Cfg::SequenceNode +{ + Cfg::ControlFlowNode getElement(int i) { result = super.getElement(i) } - ControlFlowNode getAnElement() { result = this.getElement(_) } + Cfg::ControlFlowNode getAnElement() { result = this.getElement(_) } } /** @@ -255,7 +258,7 @@ predicate iterableUnpackingAssignmentFlowStep(Node nodeFrom, Node nodeTo) { predicate iterableUnpackingForReadStep(CfgNode nodeFrom, Content c, Node nodeTo) { exists(ForTarget target | nodeFrom.getNode().getNode() = target.getSource() and - target instanceof SequenceNode and + target instanceof Cfg::SequenceNode and nodeTo = TIterableSequenceNode(target) ) and ( @@ -323,11 +326,11 @@ predicate iterableUnpackingConvertingStoreStep(Node nodeFrom, Content c, Node no */ predicate iterableUnpackingElementReadStep(Node nodeFrom, Content c, Node nodeTo) { exists( - UnpackingAssignmentSequenceTarget target, int index, ControlFlowNode element, int starIndex + UnpackingAssignmentSequenceTarget target, int index, Cfg::ControlFlowNode element, int starIndex | - target.getElement(starIndex) instanceof StarredNode + target.getElement(starIndex) instanceof Cfg::StarredNode or - not exists(target.getAnElement().(StarredNode)) and + not exists(target.getAnElement().(Cfg::StarredNode)) and starIndex = -1 | nodeFrom.(CfgNode).getNode() = target and @@ -342,18 +345,18 @@ predicate iterableUnpackingElementReadStep(Node nodeFrom, Content c, Node nodeTo else c.(TupleElementContent).getIndex() >= index - 1 ) and ( - if element instanceof SequenceNode + if element instanceof Cfg::SequenceNode then // Step 5b nodeTo = TIterableSequenceNode(element) else - if element instanceof StarredNode + if element instanceof Cfg::StarredNode then // Step 5c nodeTo = TIterableElementNode(element) else // Step 5a - exists(MultiAssignmentDefinition mad | element = mad.getDefiningNode() | + exists(SsaImpl::MultiAssignmentDefinition mad | element = mad.getDefiningNode() | nodeTo.(CfgNode).getNode() = element ) ) @@ -366,7 +369,7 @@ predicate iterableUnpackingElementReadStep(Node nodeFrom, Content c, Node nodeTo * content type `ListElementContent`. */ predicate iterableUnpackingStarredElementStoreStep(Node nodeFrom, Content c, Node nodeTo) { - exists(ControlFlowNode starred, MultiAssignmentDefinition mad | + exists(Cfg::ControlFlowNode starred, SsaImpl::MultiAssignmentDefinition mad | starred.getNode() instanceof Starred and starred = mad.getDefiningNode() | diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/LocalSources.qll b/python/ql/lib/semmle/python/dataflow/new/internal/LocalSources.qll index 5cbe7b44ab30..9f63e2160ed8 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/LocalSources.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/LocalSources.qll @@ -9,6 +9,7 @@ overlay[local] module; private import python +private import semmle.python.controlflow.internal.Cfg as Cfg import DataFlowPublic private import DataFlowPrivate private import semmle.python.internal.CachedStages @@ -314,7 +315,7 @@ private module Cached { */ cached predicate subscript(LocalSourceNode node, CfgNode subscript, CfgNode index) { - exists(CfgNode seq, SubscriptNode subscriptNode | subscriptNode = subscript.getNode() | + exists(CfgNode seq, Cfg::SubscriptNode subscriptNode | subscriptNode = subscript.getNode() | node.flowsTo(seq) and seq.getNode() = subscriptNode.getObject() and index.getNode() = subscriptNode.getIndex() diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/MatchUnpacking.qll b/python/ql/lib/semmle/python/dataflow/new/internal/MatchUnpacking.qll index e72e378da528..f6c97e489e5b 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/MatchUnpacking.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/MatchUnpacking.qll @@ -91,9 +91,7 @@ predicate matchAsFlowStep(Node nodeFrom, Node nodeTo) { or // the interior pattern flows to the alias nodeFrom.(CfgNode).getNode().getNode() = subject.getPattern() and - exists(PatternAliasDefinition pad | pad.getDefiningNode().getNode() = alias | - nodeTo.(CfgNode).getNode() = pad.getDefiningNode() - ) + nodeTo.(CfgNode).getNode().getNode() = alias ) } @@ -124,11 +122,9 @@ predicate matchLiteralFlowStep(Node nodeFrom, Node nodeTo) { * syntax (toplevel): `case var:` */ predicate matchCaptureFlowStep(Node nodeFrom, Node nodeTo) { - exists(MatchCapturePattern capture, Name var | capture.getVariable() = var | + exists(MatchCapturePattern capture | nodeFrom.(CfgNode).getNode().getNode() = capture and - exists(PatternCaptureDefinition pcd | pcd.getDefiningNode().getNode() = var | - nodeTo.(CfgNode).getNode() = pcd.getDefiningNode() - ) + nodeTo.(CfgNode).getNode().getNode() = capture.getVariable() ) } diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/SsaImpl.qll b/python/ql/lib/semmle/python/dataflow/new/internal/SsaImpl.qll new file mode 100644 index 000000000000..0b084c1bea6b --- /dev/null +++ b/python/ql/lib/semmle/python/dataflow/new/internal/SsaImpl.qll @@ -0,0 +1,548 @@ +/** + * Provides the Python SSA implementation built on the new (shared) CFG. + * + * Mirrors the Java SSA adapter at + * `java/ql/lib/semmle/code/java/dataflow/internal/SsaImpl.qll`: + * an `InputSig` is defined in terms of positional `(BasicBlock, int)` + * variable references, and the shared + * `codeql.ssa.Ssa::Make` module is then + * instantiated. + * + * `SourceVariable` is the AST-level `Py::Variable`. Variable references + * are looked up via the CFG facade's `NameNode.defines`/`uses`/`deletes` + * predicates, which themselves are one-line bridges to AST-level + * `Name.defines`/`uses`/`deletes`. + * + * Implicit-entry definitions are inserted for: + * - non-local / global / builtin variables that are read in the scope + * but never assigned (no enclosing CFG node defines them), + * - captured variables (variables defined in an enclosing scope that + * are read inside the scope), and + * - parameters, but only if the corresponding parameter name is *not* + * itself a CFG node. With the C#-style parameter wiring already + * installed in `AstNodeImpl.qll`, parameter names *are* CFG nodes, + * so the regular `variableWrite` path handles them — no `i = -1` + * entry is needed for ordinary parameters. + */ +overlay[local?] +module; + +private import python as Py +private import semmle.python.controlflow.internal.AstNodeImpl as CfgImpl +private import semmle.python.controlflow.internal.Cfg as Cfg +private import codeql.ssa.Ssa as SsaImplCommon +private import codeql.controlflow.BasicBlock as BB + +/** + * Adapts the Python `Cfg` facade to the shared SSA library's `CfgSig`. + * All members are inherited from `Cfg::ControlFlowNode` and + * `Cfg::BasicBlock`. + */ +private module CfgForSsa implements BB::CfgSig { + class ControlFlowNode = CfgImpl::ControlFlowNode; + + class BasicBlock = CfgImpl::BasicBlock; + + class EntryBasicBlock = CfgImpl::Cfg::EntryBasicBlock; + + predicate dominatingEdge = CfgImpl::Cfg::dominatingEdge/2; +} + +/** + * A source variable for SSA, wrapping a Python AST `Variable`. + * + * We only track variables that are read at least once in their scope — + * tracking write-only variables would be unnecessary work — *except* + * for module-scope globals, where the "read" can be external (e.g. + * `import mymodule; mymodule.x`). Such globals are tracked + * unconditionally so that import-resolution can find their defining + * write. + */ +private newtype TSsaSourceVariable = + TPyVar(Py::Variable v) { + // Has a use somewhere — read-relevant for SSA. + exists(Cfg::NameNode n | n.uses(v)) + or + // Or has a deletion (treated as a write that destroys the value). + exists(Cfg::NameNode n | n.deletes(v)) + or + // Or is a module-scope global written in this module — must be + // tracked even if never read locally, because importers may read + // it as an attribute on the module object. + v.getScope() instanceof Py::Module and + exists(Cfg::NameNode n | n.defines(v)) + or + // Or is a parameter — parameters must always have a + // `ParameterDefinition` for dataflow argument-routing to work, + // even if the parameter is never read in its scope. Mirrors + // legacy ESSA's `ParameterDefinition` (which fired for every + // parameter binding regardless of liveness). + exists(Py::Parameter p | p.asName() = v.getAStore()) + } + +/** + * A source variable for SSA, wrapping a Python AST `Variable`. + */ +class SsaSourceVariable extends TSsaSourceVariable { + /** Gets the underlying Python AST variable. */ + Py::Variable getVariable() { this = TPyVar(result) } + + /** Gets the (textual) name of this variable. */ + string getName() { result = this.getVariable().getId() } + + /** Gets a textual representation of this source variable. */ + string toString() { result = this.getVariable().toString() } + + /** Gets the location of this source variable. */ + Py::Location getLocation() { result = this.getVariable().getScope().getLocation() } + + /** Gets the scope in which this variable lives. */ + Py::Scope getScope() { result = this.getVariable().getScope() } + + /** + * Gets a use of this variable as it appears in the source — a `NameNode` + * that loads or deletes the variable. Mirrors legacy + * `SsaSourceVariable.getASourceUse()`. + */ + Cfg::ControlFlowNode getASourceUse() { + exists(Cfg::NameNode n | result = n | + n.uses(this.getVariable()) or n.deletes(this.getVariable()) + ) + } + + /** + * Gets an implicit use of this variable. The new SSA does not have + * implicit-use refinements, but we keep this for API parity — every + * normal-exit of the variable's scope counts as a sink, ensuring + * variables stay live to scope exit for taint-tracking. + */ + Cfg::ControlFlowNode getAnImplicitUse() { + result.isNormalExit() and result.getScope() = this.getScope() + } + + /** + * Gets a use of this variable — either an explicit source use or an + * implicit use at scope exit. Mirrors legacy `SsaSourceVariable.getAUse()`. + */ + Cfg::ControlFlowNode getAUse() { + result = this.getASourceUse() or result = this.getAnImplicitUse() + } +} + +/** + * Holds if `v` is a non-local read in scope `s`, in the sense that `s` + * uses `v` but does not write it within `s`. This includes globals, + * builtins, and variables captured from an enclosing function scope. + * + * The `Py::Variable` `v` lives in some defining scope (the module for + * globals, an outer function for closures, etc.); the reading scope + * `s` is the scope where the use of `v` occurs. + */ +private predicate nonLocalReadIn(Py::Variable v, Py::Scope s) { + exists(Cfg::NameNode n | + n.uses(v) and + n.getScope() = s and + not exists(Cfg::NameNode def | def.defines(v) and def.getScope() = s) + ) and + // Match legacy ESSA: only create entry defs for variables that have + // at least one defining store somewhere — otherwise the entry def + // represents "nothing reaches here", which is the default anyway and + // introduces no useful flow. (Legacy's `ModuleVariable` required a + // store; this is the closure-aware generalisation.) + exists(Cfg::NameNode store | store.defines(v)) +} + +/** + * Holds if `bb` is the entry basic block of a scope where `v` should + * have an implicit entry definition. This covers: + * - non-local / global / builtin variables read in `s`, and + * - captured variables (defined in an enclosing scope but read in `s`). + * + * Each reading scope gets its own entry def, so a closure variable can + * have multiple entry defs across all functions/methods that read it. + * + * Parameters are *not* included: their bound `Name` is itself a CFG + * node (per the C#-style parameter wiring), so `variableWrite` fires at + * the parameter's natural CFG index. + */ +private predicate hasEntryDefIn(SsaSourceVariable v, CfgImpl::BasicBlock bb) { + exists(Py::Scope s | + nonLocalReadIn(v.getVariable(), s) and + bb = entryBlock(s) + ) +} + +/** + * Gets the entry basic block of scope `s`, where implicit entry + * definitions are placed (at synthetic index `-1`). + */ +private CfgImpl::BasicBlock entryBlock(Py::Scope s) { + exists(CfgImpl::ControlFlowNode entry | + entry instanceof CfgImpl::ControlFlow::EntryNode and + entry.getEnclosingCallable().asScope() = s and + result = entry.getBasicBlock() + ) +} + +/** + * The SSA `InputSig` for Python. References are positional + * `(BasicBlock, int)` pairs into the new CFG. + */ +private module SsaImplInput implements SsaImplCommon::InputSig { + class SourceVariable = SsaSourceVariable; + + predicate variableWrite(CfgImpl::BasicBlock bb, int i, SourceVariable v, boolean certain) { + // Explicit binding at a CFG node — includes assignments, + // parameter Names (wired in via the C# pattern), exception-handler + // `as`-bindings, import aliases, and match-pattern captures. + exists(Cfg::NameNode n | + bb.getNode(i) = n and + n.defines(v.getVariable()) and + certain = true + ) + or + // `del x` — removes the binding. Modelled as a certain write that + // makes any subsequent read invalid. + exists(Cfg::NameNode n | + bb.getNode(i) = n and + n.deletes(v.getVariable()) and + certain = true + ) + or + // Implicit entry definition for non-local / captured / global / + // builtin variables read in some scope. Each reading scope's entry + // block gets one such write, allowing closures: e.g. when `x` is a + // parameter of an outer function and read inside a nested + // function, both scopes get entry defs for `x`. + hasEntryDefIn(v, bb) and + i = -1 and + certain = true + or + // `from X import *` — possibly rebinds every name in the importing + // scope. Modelled as an uncertain write at the import-star's CFG + // position for every variable that lives in (or is referenced + // from) the same scope as the import-star. Mirrors legacy ESSA's + // `ImportStarRefinement` (see `essa/SsaDefinitions.qll`'s + // `import_star_refinement` predicate). The write is uncertain so + // that prior definitions of the variable remain available — the + // shared-SSA `SsaUncertainWrite` merges the new value with the + // immediately preceding definition. + exists(Cfg::ImportStarNode imp | + imp.injects(_) and + bb.getNode(i) = imp and + certain = false and + ( + v.getVariable().getScope() = imp.getScope() + or + // Variable is defined in some other scope but referenced in + // the same scope as the import-star (matches legacy clause 2: + // `other.uses(v) and def.getScope() = other.getScope()`). + exists(Cfg::NameNode other | + other.uses(v.getVariable()) and + imp.getScope() = other.getScope() + ) + ) + ) + } + + predicate variableRead(CfgImpl::BasicBlock bb, int i, SourceVariable v, boolean certain) { + // Explicit source use — a `Name` load or a `del x` of the variable. + exists(Cfg::NameNode n | + bb.getNode(i) = n and + n.uses(v.getVariable()) and + certain = true + ) + or + // Synthetic use at the normal exit of the variable's defining scope. + // This keeps every variable live to scope exit so that callers (e.g. + // `module_export` in ImportResolution.qll, or taint-tracking pass-through + // through unread locals) can ask "which definition reaches end of + // scope?". Mirrors legacy ESSA's `SsaSourceVariable.getAUse()` which + // included `getScope().getANormalExit()`. + exists(Cfg::ControlFlowNode exit | + exit.isNormalExit() and + exit.getScope() = v.getVariable().getScope() and + bb.getNode(i) = exit and + certain = true + ) + } +} + +/** + * The shared SSA instantiation for Python. + * + * Members: + * - `Definition` — the union of explicit, uncertain, and phi definitions + * - `WriteDefinition`, `UncertainWriteDefinition`, `PhiNode` + * - the standard SSA predicates (`getAUse`, `getAnUltimateDefinition`, ...). + */ +module Ssa = SsaImplCommon::Make; + +final class Definition = Ssa::Definition; + +final class WriteDefinition = Ssa::WriteDefinition; + +final class UncertainWriteDefinition = Ssa::UncertainWriteDefinition; + +final class PhiNode = Ssa::PhiNode; + +// =========================================================================== +// ESSA-shaped adapter layer +// +// The dataflow library (`python/ql/lib/semmle/python/dataflow/new/`) and +// related modules (`ApiGraphs.qll`, etc.) consume the legacy ESSA API +// (`EssaVariable`, `EssaDefinition`, `AssignmentDefinition`, +// `ScopeEntryDefinition`, `ParameterDefinition`, `WithDefinition`, +// `PhiFunction`, plus the `AdjacentUses` module). To migrate them off +// the legacy CFG, we expose the same API surface on top of the +// shared SSA built above. +// +// This adapter is intentionally narrow: it covers only the predicates +// that new dataflow consumes. The richer legacy ESSA — refinement +// nodes, attribute refinements, edge refinements — stays available +// via `semmle.python.essa.Essa` for points-to / legacy code. +// =========================================================================== +/** + * Gets the CFG node at which a write definition's binding takes place. + * + * For ordinary writes (assignment, deletion, parameter) this is the + * canonical CFG node of the bound Name. For implicit entry definitions + * (synthesised at position `-1` of a scope's entry BB) this is the + * scope's entry node. + */ +private Cfg::ControlFlowNode writeDefNode(Ssa::WriteDefinition def) { + exists(CfgImpl::BasicBlock bb, int i | def.definesAt(_, bb, i) | + i >= 0 and result = bb.getNode(i) + or + i = -1 and result = bb.getNode(0) + ) +} + +/** + * A write definition whose binding has a corresponding CFG node — i.e. + * everything that's not a phi node. Mirrors legacy ESSA's + * `EssaNodeDefinition`. + */ +class EssaNodeDefinition extends Ssa::WriteDefinition { + /** Gets the CFG node where this definition's binding takes place. */ + Cfg::ControlFlowNode getDefiningNode() { result = writeDefNode(this) } + + /** Gets the variable defined here (legacy name). */ + SsaSourceVariable getVariable() { result = this.getSourceVariable() } + + /** Gets the enclosing scope. */ + Py::Scope getScope() { + exists(Cfg::ControlFlowNode n | n = this.getDefiningNode() | result = n.getScope()) + } + + /** + * Holds if this definition defines source variable `v` at CFG node + * `defNode`. Flatter form of `getSourceVariable()` + + * `getDefiningNode()`, matching legacy ESSA's `definedBy`. + */ + predicate definedBy(SsaSourceVariable v, Cfg::ControlFlowNode defNode) { + v = this.getSourceVariable() and defNode = this.getDefiningNode() + } +} + +/** + * An assignment definition: any binding where the value being assigned + * is statically known via `Cfg::DefinitionNode.getValue()`. Includes + * plain assignments, walrus, annotated assignments, augmented + * assignments, import aliases (`import x` / `from m import x [as y]`), + * `with ... as x`, and for-target bindings (where `getValue()` returns + * the iter expression's CFG node). Excludes parameter bindings — + * those are modelled by `ParameterDefinition`. + */ +class AssignmentDefinition extends EssaNodeDefinition { + AssignmentDefinition() { + exists(Cfg::NameNode n | n = this.getDefiningNode() | + exists(n.(Cfg::DefinitionNode).getValue()) and + not n.(Cfg::ControlFlowNode).isParameter() + ) + } + + /** Gets the CFG node for the value being assigned, if statically known. */ + Cfg::ControlFlowNode getValue() { + result = this.getDefiningNode().(Cfg::DefinitionNode).getValue() + } +} + +/** + * A parameter definition — the binding of a parameter name in a + * function's scope. + */ +class ParameterDefinition extends EssaNodeDefinition { + ParameterDefinition() { this.getDefiningNode().isParameter() } + + /** Gets the AST `Parameter` (a `Py::Name` in param context). */ + Py::Name getParameter() { result = this.getDefiningNode().getNode() } +} + +/** + * A definition introduced by a `with ... as x:` clause. + */ +class WithDefinition extends EssaNodeDefinition { + WithDefinition() { + exists(Cfg::NameNode n, Py::With w | + n = this.getDefiningNode() and + w.getOptionalVars() = n.getNode() + ) + } +} + +/** + * An assignment where the LHS is a tuple/list and the RHS is unpacked: + * `a, b = (1, 2)` or `a, *rest = xs`. The SSA def lives at the inner + * `Name` CFG node, but for IterableUnpacking integration we expose + * the enclosing `StarredNode` as the `getDefiningNode()` for `*rest` + * patterns — mirroring legacy ESSA's `multi_assignment_definition`, + * which placed the def at the StarredNode CFG node. + */ +class MultiAssignmentDefinition extends EssaNodeDefinition { + MultiAssignmentDefinition() { + exists(Cfg::NameNode n | n = super.getDefiningNode() | + exists(Py::Assign a, Py::Expr lhs | + a.getATarget() = lhs and + (lhs instanceof Py::Tuple or lhs instanceof Py::List) and + lhs.getASubExpression+() = n.getNode() + ) + or + // For-loop with tuple/list target: `for a, b in xs:` — + // tuple-unpacking semantics applies to the for-target. + exists(Py::For f, Py::Expr lhs | + f.getTarget() = lhs and + (lhs instanceof Py::Tuple or lhs instanceof Py::List) and + lhs.getASubExpression+() = n.getNode() + ) + ) + } + + override Cfg::ControlFlowNode getDefiningNode() { + // Default: the underlying `Name` CFG node (where the SSA def lives). + not exists(Cfg::StarredNode s | + s.getNode().(Py::Starred).getValue() = super.getDefiningNode().getNode() + ) and + result = super.getDefiningNode() + or + // Exception: for `*rest`, expose the enclosing `Starred` CFG node + // so that `IterableUnpacking::iterableUnpackingStarredElementStoreStep` + // can attach the rest-list to it. + exists(Cfg::StarredNode s | + s.getNode().(Py::Starred).getValue() = super.getDefiningNode().getNode() + | + result = s + ) + } +} + +/** + * An implicit entry definition for a non-local / captured / global / + * builtin variable read in a scope but not defined there. + * + * Inherits from `EssaNodeDefinition` and exposes the scope's entry node + * as its defining node (matching legacy ESSA semantics). + */ +class ScopeEntryDefinition extends EssaNodeDefinition { + ScopeEntryDefinition() { + exists(CfgImpl::BasicBlock bb | + this.definesAt(_, bb, -1) and + bb instanceof CfgImpl::Cfg::EntryBasicBlock + ) + } + + /** Gets the enclosing scope (the scope whose entry block this def is in). */ + override Py::Scope getScope() { + exists(CfgImpl::BasicBlock bb | + this.definesAt(_, bb, -1) and + result = bb.getNode(0).(Cfg::ControlFlowNode).getScope() + ) + } +} + +/** A phi node (alias matching legacy naming). */ +class PhiFunction extends PhiNode { + /** + * Gets an input to this phi function (a definition that flows into + * the phi from one of its predecessor blocks). Mirrors legacy + * ESSA's `PhiFunction.getAnInput()`. + */ + Ssa::Definition getAnInput() { Ssa::phiHasInputFromBlock(this, result, _) } +} + +/** Base class for all ESSA definitions (legacy-shaped). */ +class EssaDefinition = Ssa::Definition; + +/** + * An adapter representing a single SSA-defined "variable" — wrapping + * one `Ssa::Definition`. Mirrors legacy `EssaVariable` API. + */ +class EssaVariable extends Ssa::Definition { + /** Gets the underlying SSA definition (legacy name). */ + Ssa::Definition getDefinition() { result = this } + + /** + * Gets a CFG node where this definition is used. Includes regular + * `Name` reads as well as the synthetic scope-exit "use" registered + * via `SsaImplInput::variableRead` — mirrors legacy ESSA's + * `EssaVariable.getAUse()` which inherited the synthetic exit-use + * from `SsaSourceVariable`. + */ + Cfg::ControlFlowNode getAUse() { + exists(CfgImpl::BasicBlock bb, int i | + Ssa::ssaDefReachesRead(this.getSourceVariable(), this, bb, i) and + bb.getNode(i) = result + ) + } + + /** Gets the (textual) name of the underlying variable. */ + string getName() { result = this.getSourceVariable().getVariable().getId() } + + /** Gets the scope in which this variable lives. */ + Py::Scope getScope() { result = this.getSourceVariable().getVariable().getScope() } + + /** Gets an ultimate non-phi ancestor of this definition. */ + EssaVariable getAnUltimateDefinition() { + if this instanceof PhiNode + then + exists(Ssa::Definition input | + Ssa::phiHasInputFromBlock(this, input, _) and + result = input.(EssaVariable).getAnUltimateDefinition() + ) + else result = this + } +} + +/** + * Adjacent use-use and def-use relations exposed by the shared SSA + * library. Provides the same interface as legacy + * `semmle.python.essa.SsaCompute::AdjacentUses`. + */ +module AdjacentUses { + /** Holds if `nodeFrom` and `nodeTo` are adjacent uses of the same SSA variable. */ + predicate adjacentUseUse(Cfg::NameNode nodeFrom, Cfg::NameNode nodeTo) { + exists(SsaSourceVariable v, CfgImpl::BasicBlock bb1, int i1, CfgImpl::BasicBlock bb2, int i2 | + Ssa::adjacentUseUse(bb1, i1, bb2, i2, v, _) and + nodeFrom = bb1.getNode(i1) and + nodeTo = bb2.getNode(i2) + ) + } + + /** Holds if `use` is a first use of definition `def`. */ + predicate firstUse(Ssa::Definition def, Cfg::NameNode use) { + exists(CfgImpl::BasicBlock bb, int i | + Ssa::firstUse(def, bb, i, _) and + use = bb.getNode(i) + ) + } + + /** + * Holds if `use` is any reachable use of definition `def`. Combines + * `firstUse` with transitive use-use adjacency. + */ + predicate useOfDef(Ssa::Definition def, Cfg::NameNode use) { + firstUse(def, use) + or + exists(Cfg::NameNode mid | useOfDef(def, mid) and adjacentUseUse(mid, use)) + } +} diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/TaintTrackingPrivate.qll b/python/ql/lib/semmle/python/dataflow/new/internal/TaintTrackingPrivate.qll index 2213ff35b1b9..28a559263477 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/TaintTrackingPrivate.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/TaintTrackingPrivate.qll @@ -1,4 +1,6 @@ private import python +private import semmle.python.controlflow.internal.Cfg as Cfg +private import semmle.python.dataflow.new.internal.SsaImpl as SsaImpl private import semmle.python.dataflow.new.DataFlow private import semmle.python.dataflow.new.internal.DataFlowPrivate as DataFlowPrivate private import FlowSummaryImpl as FlowSummaryImpl @@ -97,7 +99,7 @@ import Cached * and isn't a big problem in practice. */ predicate concatStep(DataFlow::CfgNode nodeFrom, DataFlow::CfgNode nodeTo) { - exists(BinaryExprNode add | add = nodeTo.getNode() | + exists(Cfg::BinaryExprNode add | add = nodeTo.getNode() | add.getOp() instanceof Add and add.getAnOperand() = nodeFrom.getNode() ) } @@ -106,7 +108,7 @@ predicate concatStep(DataFlow::CfgNode nodeFrom, DataFlow::CfgNode nodeTo) { * Holds if taint can flow from `nodeFrom` to `nodeTo` with a step related to subscripting. */ predicate subscriptStep(DataFlow::CfgNode nodeFrom, DataFlow::CfgNode nodeTo) { - nodeTo.getNode().(SubscriptNode).getObject() = nodeFrom.getNode() + nodeTo.getNode().(Cfg::SubscriptNode).getObject() = nodeFrom.getNode() } /** @@ -122,15 +124,15 @@ predicate stringManipulation(DataFlow::CfgNode nodeFrom, DataFlow::CfgNode nodeT ( call = API::builtin(["str", "bytes", "unicode"]).getACall() or - call.getFunction().asCfgNode().(NameNode).getId() in ["str", "bytes", "unicode"] + call.getFunction().asCfgNode().(Cfg::NameNode).getId() in ["str", "bytes", "unicode"] ) and nodeFrom in [call.getArg(0), call.getArgByName("object")] ) or // String methods. Note that this doesn't recognize `meth = "foo".upper; meth()` - exists(CallNode call, string method_name, ControlFlowNode object | + exists(Cfg::CallNode call, string method_name, Cfg::ControlFlowNode object | call = nodeTo.getNode() and - object = call.getFunction().(AttrNode).getObject(method_name) + object = call.getFunction().(Cfg::AttrNode).getObject(method_name) | nodeFrom.getNode() = object and method_name in [ @@ -156,7 +158,7 @@ predicate stringManipulation(DataFlow::CfgNode nodeFrom, DataFlow::CfgNode nodeT ) or // % formatting - exists(BinaryExprNode fmt | fmt = nodeTo.getNode() | + exists(Cfg::BinaryExprNode fmt | fmt = nodeTo.getNode() | fmt.getOp() instanceof Mod and ( fmt.getLeft() = nodeFrom.getNode() @@ -166,7 +168,7 @@ predicate stringManipulation(DataFlow::CfgNode nodeFrom, DataFlow::CfgNode nodeT ) or // string multiplication -- `"foo" * 10` - exists(BinaryExprNode mult | mult = nodeTo.getNode() | + exists(Cfg::BinaryExprNode mult | mult = nodeTo.getNode() | mult.getOp() instanceof Mult and mult.getLeft() = nodeFrom.getNode() ) @@ -213,8 +215,8 @@ predicate awaitStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { * the variable `f` is tainted if the result of `open("foo")` is tainted. */ predicate asyncWithStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { - exists(With with, ControlFlowNode contextManager, ControlFlowNode var | - var = any(WithDefinition wd).getDefiningNode() + exists(With with, Cfg::ControlFlowNode contextManager, Cfg::ControlFlowNode var | + var = any(SsaImpl::WithDefinition wd).getDefiningNode() | nodeFrom.(DataFlow::CfgNode).getNode() = contextManager and nodeTo.(DataFlow::CfgNode).getNode() = var and diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackingImpl.qll b/python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackingImpl.qll index 13afd6a4276d..b8cb8a756879 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackingImpl.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackingImpl.qll @@ -2,6 +2,8 @@ import codeql.util.Unit import codeql.typetracking.TypeTracking as Shared import codeql.typetracking.internal.TypeTrackingImpl as SharedImpl private import python +private import semmle.python.controlflow.internal.Cfg as Cfg +private import semmle.python.dataflow.new.internal.SsaImpl as SsaImpl private import semmle.python.internal.CachedStages private import semmle.python.dataflow.new.internal.DataFlowPublic as DataFlowPublic private import semmle.python.dataflow.new.internal.DataFlowPrivate as DataFlowPrivate @@ -162,7 +164,7 @@ module TypeTrackingInput implements Shared::TypeTrackingInput { // ignore the flow steps from the synthetic sequence node to the real sequence node, // since we only support one level of content in type-trackers, and the nested // structure requires two levels at least to be useful. - not exists(SequenceNode outer | + not exists(Cfg::SequenceNode outer | outer.getAnElement() = nodeTo.asCfgNode() and IterableUnpacking::iterableUnpackingTupleFlowStep(nodeFrom, nodeTo) ) @@ -267,7 +269,7 @@ module TypeTrackingInput implements Shared::TypeTrackingInput { // Since we only support one level of content in type-trackers we don't actually // support `(aa, ab), (ba, bb) = ...`. Therefore we exclude the read-step from `(aa, // ab)` to `aa` (since it is not needed). - not exists(SequenceNode outer | + not exists(Cfg::SequenceNode outer | outer.getAnElement() = nodeFrom.asCfgNode() and IterableUnpacking::iterableUnpackingTupleFlowStep(_, nodeFrom) ) and @@ -277,7 +279,7 @@ module TypeTrackingInput implements Shared::TypeTrackingInput { IterableUnpacking::iterableUnpackingForReadStep(_, _, seq) and IterableUnpacking::iterableUnpackingConvertingReadStep(seq, _, elem) and IterableUnpacking::iterableUnpackingConvertingStoreStep(elem, _, nodeFrom) and - nodeFrom.asCfgNode() instanceof SequenceNode + nodeFrom.asCfgNode() instanceof Cfg::SequenceNode ) or TypeTrackerSummaryFlow::basicLoadStep(nodeFrom, nodeTo, DataFlowPublic::singleton(content)) @@ -315,13 +317,15 @@ module TypeTrackingInput implements Shared::TypeTrackingInput { // // nodeFrom is `expr` // nodeTo is entry node for `f` - exists(ScopeEntryDefinition e, SsaSourceVariable var, DefinitionNode def | + exists( + SsaImpl::ScopeEntryDefinition e, SsaImpl::SsaSourceVariable var, Cfg::DefinitionNode def + | e.getSourceVariable() = var and - var.hasDefiningNode(def) + def.getNode() = var.getVariable().getAStore() | nodeTo.(DataFlowPublic::ScopeEntryDefinitionNode).getDefinition() = e and nodeFrom.asCfgNode() = def and - var.getScope().getScope*() = nodeFrom.getScope() + var.getVariable().getScope().getScope*() = nodeFrom.getScope() ) } diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/VariableCapture.qll b/python/ql/lib/semmle/python/dataflow/new/internal/VariableCapture.qll index b170f7d95d79..2cd2fedb1d7a 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/VariableCapture.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/VariableCapture.qll @@ -3,6 +3,9 @@ overlay[local] module; private import python +private import semmle.python.controlflow.internal.Cfg as Cfg +private import semmle.python.controlflow.internal.AstNodeImpl as CfgImpl +private import semmle.python.dataflow.new.internal.SsaImpl as SsaImpl private import DataFlowPublic private import semmle.python.dataflow.new.internal.DataFlowPrivate private import codeql.dataflow.VariableCapture as Shared @@ -14,10 +17,10 @@ private import codeql.dataflow.VariableCapture as Shared // The first is the main implementation, the second is a performance motivated restriction. // The restriction is to clear any `CapturedVariableContent` before writing a new one // to avoid long access paths (see the link for a nice explanation). -private module CaptureInput implements Shared::InputSig { +private module CaptureInput implements Shared::InputSig { private import python as PY - additional class ExprCfgNode extends ControlFlowNode { + additional class ExprCfgNode extends Cfg::ControlFlowNode { ExprCfgNode() { isExpressionNode(this) } } @@ -25,7 +28,9 @@ private module CaptureInput implements Shared::InputSig; +module Flow = Shared::Flow; private Flow::ClosureNode asClosureNode(Node n) { result = n.(SynthCaptureNode).getSynthesizedCaptureNode() diff --git a/python/ql/lib/semmle/python/frameworks/Bottle.qll b/python/ql/lib/semmle/python/frameworks/Bottle.qll index d4fc54f95687..9a07cf91381c 100644 --- a/python/ql/lib/semmle/python/frameworks/Bottle.qll +++ b/python/ql/lib/semmle/python/frameworks/Bottle.qll @@ -4,6 +4,7 @@ */ private import python +private import semmle.python.controlflow.internal.Cfg as Cfg private import semmle.python.Concepts private import semmle.python.ApiGraphs private import semmle.python.dataflow.new.RemoteFlowSources @@ -157,9 +158,9 @@ module Bottle { DataFlow::Node value; HeaderWriteSubscript() { - exists(SubscriptNode subscript | + exists(Cfg::SubscriptNode subscript | this.asCfgNode() = subscript and - value.asCfgNode() = subscript.(DefinitionNode).getValue() and + value.asCfgNode() = subscript.(Cfg::DefinitionNode).getValue() and name.asCfgNode() = subscript.getIndex() and subscript.getObject() = headers().asSource().asCfgNode() ) diff --git a/python/ql/lib/semmle/python/frameworks/Django.qll b/python/ql/lib/semmle/python/frameworks/Django.qll index 4f3fdbff01ae..38f3cdf3623c 100644 --- a/python/ql/lib/semmle/python/frameworks/Django.qll +++ b/python/ql/lib/semmle/python/frameworks/Django.qll @@ -4,6 +4,7 @@ */ private import python +private import semmle.python.controlflow.internal.Cfg as Cfg private import semmle.python.dataflow.new.DataFlow private import semmle.python.dataflow.new.RemoteFlowSources private import semmle.python.dataflow.new.TaintTracking @@ -1305,7 +1306,7 @@ module PrivateDjango { dict.(DataFlow::MethodCallNode).calls(files, "dict") ) | - this.asCfgNode().(SubscriptNode).getObject() = dict.asCfgNode() + this.asCfgNode().(Cfg::SubscriptNode).getObject() = dict.asCfgNode() or this.(DataFlow::MethodCallNode).calls(dict, "get") ) @@ -1314,7 +1315,7 @@ module PrivateDjango { exists(DataFlow::AttrRead files, DataFlow::MethodCallNode getlistCall | files.accesses(instance(), "FILES") and getlistCall.calls(files, "getlist") and - this.asCfgNode().(SubscriptNode).getObject() = getlistCall.asCfgNode() + this.asCfgNode().(Cfg::SubscriptNode).getObject() = getlistCall.asCfgNode() ) } } @@ -2216,7 +2217,7 @@ module PrivateDjango { DataFlow::Node value; DjangoResponseCookieSubscriptWrite() { - exists(SubscriptNode subscript, DataFlow::AttrRead cookieLookup | + exists(Cfg::SubscriptNode subscript, DataFlow::AttrRead cookieLookup | // To give `this` a value, we need to choose between either LHS or RHS, // and just go with the LHS this.asCfgNode() = subscript @@ -2228,7 +2229,7 @@ module PrivateDjango { | cookieLookup.flowsTo(subscriptObj) ) and - value.asCfgNode() = subscript.(DefinitionNode).getValue() and + value.asCfgNode() = subscript.(Cfg::DefinitionNode).getValue() and index.asCfgNode() = subscript.getIndex() ) } @@ -2249,7 +2250,7 @@ module PrivateDjango { DataFlow::Node value; DjangoResponseHeaderSubscriptWrite() { - exists(SubscriptNode subscript, DataFlow::AttrRead headerLookup | + exists(Cfg::SubscriptNode subscript, DataFlow::AttrRead headerLookup | // To give `this` a value, we need to choose between either LHS or RHS, // and just go with the LHS this.asCfgNode() = subscript @@ -2261,7 +2262,7 @@ module PrivateDjango { | headerLookup.flowsTo(subscriptObj) ) and - value.asCfgNode() = subscript.(DefinitionNode).getValue() and + value.asCfgNode() = subscript.(Cfg::DefinitionNode).getValue() and index.asCfgNode() = subscript.getIndex() ) } @@ -2284,14 +2285,14 @@ module PrivateDjango { DataFlow::Node value; DjangoResponseSubscriptWrite() { - exists(SubscriptNode subscript | + exists(Cfg::SubscriptNode subscript | // To give `this` a value, we need to choose between either LHS or RHS, // and just go with the LHS this.asCfgNode() = subscript | subscript.getObject() = DjangoImpl::DjangoHttp::Response::HttpResponse::instance().asCfgNode() and - value.asCfgNode() = subscript.(DefinitionNode).getValue() and + value.asCfgNode() = subscript.(Cfg::DefinitionNode).getValue() and index.asCfgNode() = subscript.getIndex() ) } @@ -2426,7 +2427,7 @@ module PrivateDjango { /** Gets a reference to the result of calling the `as_view` classmethod of this class. */ private DataFlow::TypeTrackingNode asViewResult(DataFlow::TypeTracker t) { t.start() and - result.asCfgNode().(CallNode).getFunction() = this.asViewRef().asCfgNode() + result.asCfgNode().(Cfg::CallNode).getFunction() = this.asViewRef().asCfgNode() or exists(DataFlow::TypeTracker t2 | result = this.asViewResult(t2).track(t2, t)) } diff --git a/python/ql/lib/semmle/python/frameworks/FastApi.qll b/python/ql/lib/semmle/python/frameworks/FastApi.qll index db8cd8e78961..39d10044ee1a 100644 --- a/python/ql/lib/semmle/python/frameworks/FastApi.qll +++ b/python/ql/lib/semmle/python/frameworks/FastApi.qll @@ -4,6 +4,7 @@ */ private import python +private import semmle.python.controlflow.internal.Cfg as Cfg private import semmle.python.dataflow.new.DataFlow private import semmle.python.dataflow.new.RemoteFlowSources private import semmle.python.dataflow.new.TaintTracking @@ -441,7 +442,7 @@ module FastApi { DataFlow::Node value; HeaderSubscriptWrite() { - exists(SubscriptNode subscript, DataFlow::AttrRead headerLookup | + exists(Cfg::SubscriptNode subscript, DataFlow::AttrRead headerLookup | // To give `this` a value, we need to choose between either LHS or RHS, // and just go with the LHS this.asCfgNode() = subscript @@ -450,7 +451,7 @@ module FastApi { exists(DataFlow::Node subscriptObj | subscriptObj.asCfgNode() = subscript.getObject() | headerLookup.flowsTo(subscriptObj) ) and - value.asCfgNode() = subscript.(DefinitionNode).getValue() and + value.asCfgNode() = subscript.(Cfg::DefinitionNode).getValue() and index.asCfgNode() = subscript.getIndex() ) } diff --git a/python/ql/lib/semmle/python/frameworks/Gradio.qll b/python/ql/lib/semmle/python/frameworks/Gradio.qll index 11109e150bfd..92aec4bd7732 100644 --- a/python/ql/lib/semmle/python/frameworks/Gradio.qll +++ b/python/ql/lib/semmle/python/frameworks/Gradio.qll @@ -4,6 +4,7 @@ */ import python +private import semmle.python.controlflow.internal.Cfg as Cfg import semmle.python.dataflow.new.RemoteFlowSources import semmle.python.dataflow.new.TaintTracking import semmle.python.ApiGraphs @@ -51,9 +52,9 @@ module Gradio { // limit only to lists of parameters given to `inputs`. ( ( - call.getKeywordParameter("inputs").asSink().asCfgNode() instanceof ListNode + call.getKeywordParameter("inputs").asSink().asCfgNode() instanceof Cfg::ListNode or - call.getParameter(1).asSink().asCfgNode() instanceof ListNode + call.getParameter(1).asSink().asCfgNode() instanceof Cfg::ListNode ) and ( this = call.getKeywordParameter("inputs").getASubscript().getAValueReachingSink() @@ -75,8 +76,8 @@ module Gradio { exists(GradioInput call | this = call.getParameter(0, "fn").getParameter(_).asSource() and // exclude lists of parameters given to `inputs` - not call.getKeywordParameter("inputs").asSink().asCfgNode() instanceof ListNode and - not call.getParameter(1).asSink().asCfgNode() instanceof ListNode + not call.getKeywordParameter("inputs").asSink().asCfgNode() instanceof Cfg::ListNode and + not call.getParameter(1).asSink().asCfgNode() instanceof Cfg::ListNode ) } @@ -105,16 +106,16 @@ module Gradio { // handle cases where there are multiple arguments passed as a list to `inputs` ( ( - node.getKeywordParameter("inputs").asSink().asCfgNode() instanceof ListNode + node.getKeywordParameter("inputs").asSink().asCfgNode() instanceof Cfg::ListNode or - node.getParameter(1).asSink().asCfgNode() instanceof ListNode + node.getParameter(1).asSink().asCfgNode() instanceof Cfg::ListNode ) and exists(int i | nodeTo = node.getParameter(0, "fn").getParameter(i).asSource() | nodeFrom.asCfgNode() = - node.getKeywordParameter("inputs").asSink().asCfgNode().(ListNode).getElement(i) + node.getKeywordParameter("inputs").asSink().asCfgNode().(Cfg::ListNode).getElement(i) or nodeFrom.asCfgNode() = - node.getParameter(1).asSink().asCfgNode().(ListNode).getElement(i) + node.getParameter(1).asSink().asCfgNode().(Cfg::ListNode).getElement(i) ) ) ) diff --git a/python/ql/lib/semmle/python/frameworks/MarkupSafe.qll b/python/ql/lib/semmle/python/frameworks/MarkupSafe.qll index 6e3b630ffa57..a4832b27ba40 100644 --- a/python/ql/lib/semmle/python/frameworks/MarkupSafe.qll +++ b/python/ql/lib/semmle/python/frameworks/MarkupSafe.qll @@ -4,6 +4,7 @@ */ private import python +private import semmle.python.controlflow.internal.Cfg as Cfg private import semmle.python.dataflow.new.DataFlow private import semmle.python.dataflow.new.TaintTracking private import semmle.python.Concepts @@ -46,7 +47,7 @@ module MarkupSafeModel { /** A direct instantiation of `markupsafe.Markup`. */ private class ClassInstantiation extends InstanceSource, DataFlow::CallCfgNode { - override CallNode node; + override Cfg::CallNode node; ClassInstantiation() { this = classRef().getACall() } } @@ -64,7 +65,7 @@ module MarkupSafeModel { /** A string concatenation with a `markupsafe.Markup` involved. */ class StringConcat extends Markup::InstanceSource, DataFlow::CfgNode { - override BinaryExprNode node; + override Cfg::BinaryExprNode node; StringConcat() { node.getOp() instanceof Add and @@ -79,7 +80,7 @@ module MarkupSafeModel { /** A %-style string format with `markupsafe.Markup` as the format string. */ class PercentStringFormat extends Markup::InstanceSource, DataFlow::CfgNode { - override BinaryExprNode node; + override Cfg::BinaryExprNode node; PercentStringFormat() { node.getOp() instanceof Mod and diff --git a/python/ql/lib/semmle/python/frameworks/Pycurl.qll b/python/ql/lib/semmle/python/frameworks/Pycurl.qll index 7280eec5f61c..030e6c66f8de 100644 --- a/python/ql/lib/semmle/python/frameworks/Pycurl.qll +++ b/python/ql/lib/semmle/python/frameworks/Pycurl.qll @@ -7,6 +7,7 @@ */ private import python +private import semmle.python.controlflow.internal.Cfg as Cfg private import semmle.python.Concepts private import semmle.python.ApiGraphs private import semmle.python.frameworks.data.ModelsAsData @@ -56,7 +57,7 @@ module Pycurl { { OutgoingRequestCall() { this = setopt().getACall() and - this.getArg(0).asCfgNode().(AttrNode).getName() = "URL" + this.getArg(0).asCfgNode().(Cfg::AttrNode).getName() = "URL" } override DataFlow::Node getAUrlPart() { @@ -81,7 +82,7 @@ module Pycurl { private class CurlSslCall extends Http::Client::Request::Range instanceof DataFlow::CallCfgNode { CurlSslCall() { this = setopt().getACall() and - this.getArg(0).asCfgNode().(AttrNode).getName() = ["SSL_VERIFYPEER", "SSL_VERIFYHOST"] + this.getArg(0).asCfgNode().(Cfg::AttrNode).getName() = ["SSL_VERIFYPEER", "SSL_VERIFYHOST"] } override DataFlow::Node getAUrlPart() { none() } diff --git a/python/ql/lib/semmle/python/frameworks/Pydantic.qll b/python/ql/lib/semmle/python/frameworks/Pydantic.qll index c3d76835b429..1aa5c9142e6d 100644 --- a/python/ql/lib/semmle/python/frameworks/Pydantic.qll +++ b/python/ql/lib/semmle/python/frameworks/Pydantic.qll @@ -7,6 +7,7 @@ */ private import python +private import semmle.python.controlflow.internal.Cfg as Cfg private import semmle.python.dataflow.new.DataFlow private import semmle.python.dataflow.new.TaintTracking private import semmle.python.Concepts @@ -93,7 +94,7 @@ module Pydantic { // be a Pydantic model. So `model[0]` will be an overapproximation, but should not // really cause problems (since we don't expect real code to contain such accesses) nodeFrom = instance() and - nodeTo.asCfgNode().(SubscriptNode).getObject() = nodeFrom.asCfgNode() + nodeTo.asCfgNode().(Cfg::SubscriptNode).getObject() = nodeFrom.asCfgNode() } /** diff --git a/python/ql/lib/semmle/python/frameworks/Stdlib.qll b/python/ql/lib/semmle/python/frameworks/Stdlib.qll index a9fd72530f51..31ae5f909920 100644 --- a/python/ql/lib/semmle/python/frameworks/Stdlib.qll +++ b/python/ql/lib/semmle/python/frameworks/Stdlib.qll @@ -6,6 +6,7 @@ overlay[local?] module; private import python +private import semmle.python.controlflow.internal.Cfg as Cfg private import semmle.python.dataflow.new.DataFlow private import semmle.python.dataflow.new.TaintTracking private import semmle.python.dataflow.new.RemoteFlowSources @@ -1246,7 +1247,7 @@ module StdlibPrivate { /** An additional taint step for calls to `os.path.join` */ private class OsPathJoinCallAdditionalTaintStep extends TaintTracking::AdditionalTaintStep { override predicate step(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { - exists(CallNode call | + exists(Cfg::CallNode call | nodeTo.asCfgNode() = call and call = OS::OsPath::join().getACall().asCfgNode() and call.getAnArg() = nodeFrom.asCfgNode() @@ -1317,13 +1318,13 @@ module StdlibPrivate { // run, so if we're able to, we only mark the first element as the command // (and not the arguments to the command). // - result.asCfgNode() = arg_args.asCfgNode().(SequenceNode).getElement(0) + result.asCfgNode() = arg_args.asCfgNode().(Cfg::SequenceNode).getElement(0) or // Either the "args" argument is not a sequence (which is valid) or we where // just not able to figure it out. Simply mark the "args" argument as the // command. // - not arg_args.asCfgNode() instanceof SequenceNode and + not arg_args.asCfgNode() instanceof Cfg::SequenceNode and result = arg_args ) ) @@ -1542,7 +1543,7 @@ module StdlibPrivate { * See https://docs.python.org/3/library/functions.html#eval */ private class BuiltinsEvalCall extends CodeExecution::Range, DataFlow::CallCfgNode { - override CallNode node; + override Cfg::CallNode node; BuiltinsEvalCall() { this = API::builtin("eval").getACall() } @@ -1923,7 +1924,7 @@ module StdlibPrivate { nodeFrom = instance().getAValueReachableFromSource() and nodeTo = [getvalueRef(), getfirstRef(), getlistRef()].getAValueReachableFromSource() or - nodeFrom.asCfgNode() = nodeTo.asCfgNode().(CallNode).getFunction() and + nodeFrom.asCfgNode() = nodeTo.asCfgNode().(Cfg::CallNode).getFunction() and ( nodeFrom = getvalueRef().getAValueReachableFromSource() and nodeTo = getvalueResult().asSource() @@ -1939,7 +1940,7 @@ module StdlibPrivate { nodeFrom in [ instance().getAValueReachableFromSource(), fieldList().getAValueReachableFromSource() ] and - nodeTo.asCfgNode().(SubscriptNode).getObject() = nodeFrom.asCfgNode() + nodeTo.asCfgNode().(Cfg::SubscriptNode).getObject() = nodeFrom.asCfgNode() or // Attributes on Field nodeFrom = field().getAValueReachableFromSource() and @@ -2254,8 +2255,8 @@ module StdlibPrivate { DataFlow::CfgNode { WsgirefSimpleServerApplicationReturn() { - exists(WsgirefSimpleServerApplication requestHandler, Return ret | - ret.getScope() = requestHandler and + exists(Return ret | + ret.getScope() = any(WsgirefSimpleServerApplication requestHandler) and node.getNode() = ret.getValue() ) } @@ -2338,9 +2339,9 @@ module StdlibPrivate { DataFlow::Node value; HeaderWriteSubscript() { - exists(SubscriptNode subscript | + exists(Cfg::SubscriptNode subscript | this.asCfgNode() = subscript and - value.asCfgNode() = subscript.(DefinitionNode).getValue() and + value.asCfgNode() = subscript.(Cfg::DefinitionNode).getValue() and name.asCfgNode() = subscript.getIndex() and subscript.getObject() = instance().asCfgNode() ) @@ -2682,7 +2683,7 @@ module StdlibPrivate { or // Data injection // Special handling of the `/` operator - exists(BinaryExprNode slash, DataFlow::Node pathOperand, DataFlow::TypeTracker t2 | + exists(Cfg::BinaryExprNode slash, DataFlow::Node pathOperand, DataFlow::TypeTracker t2 | slash.getOp() instanceof Div and pathOperand.asCfgNode() = slash.getAnOperand() and pathlibPath(t2).flowsTo(pathOperand) and @@ -2807,7 +2808,7 @@ module StdlibPrivate { pathlibPath().flowsTo(nodeTo) and ( // Special handling of the `/` operator - exists(BinaryExprNode slash, DataFlow::Node pathOperand | + exists(Cfg::BinaryExprNode slash, DataFlow::Node pathOperand | slash.getOp() instanceof Div and pathOperand.asCfgNode() = slash.getAnOperand() and pathlibPath().flowsTo(pathOperand) @@ -4605,9 +4606,9 @@ module StdlibPrivate { } override predicate propagatesFlow(string input, string output, boolean preservesValue) { - exists(CallNode c, string name, ControlFlowNode n, DataFlow::AttributeContent ac | - c.getFunction().(NameNode).getId() = "replace" or - c.getFunction().(AttrNode).getName() = "replace" + exists(Cfg::CallNode c, string name, Cfg::ControlFlowNode n, DataFlow::AttributeContent ac | + c.getFunction().(Cfg::NameNode).getId() = "replace" or + c.getFunction().(Cfg::AttrNode).getName() = "replace" | n = c.getArgByName(name) and ac.getAttribute() = name and @@ -5171,10 +5172,10 @@ module StdlibPrivate { * See https://docs.python.org/3.9/library/stdtypes.html#str.startswith */ private class StartswithCall extends Path::SafeAccessCheck::Range { - StartswithCall() { this.(CallNode).getFunction().(AttrNode).getName() = "startswith" } + StartswithCall() { this.(Cfg::CallNode).getFunction().(Cfg::AttrNode).getName() = "startswith" } - override predicate checks(ControlFlowNode node, boolean branch) { - node = this.(CallNode).getFunction().(AttrNode).getObject() and + override predicate checks(Cfg::ControlFlowNode node, boolean branch) { + node = this.(Cfg::CallNode).getFunction().(Cfg::AttrNode).getObject() and branch = true } } diff --git a/python/ql/lib/semmle/python/frameworks/Stdlib/Urllib.qll b/python/ql/lib/semmle/python/frameworks/Stdlib/Urllib.qll index 6b5764e55925..af670c009b6c 100644 --- a/python/ql/lib/semmle/python/frameworks/Stdlib/Urllib.qll +++ b/python/ql/lib/semmle/python/frameworks/Stdlib/Urllib.qll @@ -8,6 +8,7 @@ */ private import python +private import semmle.python.controlflow.internal.Cfg as Cfg private import semmle.python.Concepts private import semmle.python.ApiGraphs private import semmle.python.security.dataflow.UrlRedirectCustomizations @@ -91,7 +92,7 @@ private module Urllib { * A read of the `netloc` attribute of a parsed URL as returned by `urllib.parse.urlparse`, * which is being checked in a way that is relevant for URL redirection vulnerabilities. */ - private predicate netlocCheck(DataFlow::GuardNode g, ControlFlowNode node, boolean branch) { + private predicate netlocCheck(DataFlow::GuardNode g, Cfg::ControlFlowNode node, boolean branch) { exists(DataFlow::CallCfgNode urlParseCall, DataFlow::AttrRead netlocRead | urlParseCall = getUrlParseCall() and netlocRead = urlParseCall.getAnAttributeRead("netloc") and diff --git a/python/ql/lib/semmle/python/frameworks/Tornado.qll b/python/ql/lib/semmle/python/frameworks/Tornado.qll index 61cf7df316e7..3e57cdd3108a 100644 --- a/python/ql/lib/semmle/python/frameworks/Tornado.qll +++ b/python/ql/lib/semmle/python/frameworks/Tornado.qll @@ -4,6 +4,7 @@ */ private import python +private import semmle.python.controlflow.internal.Cfg as Cfg private import semmle.python.dataflow.new.DataFlow private import semmle.python.dataflow.new.RemoteFlowSources private import semmle.python.dataflow.new.TaintTracking @@ -72,9 +73,9 @@ module Tornado { DataFlow::Node value; TornadoHeaderSubscriptWrite() { - exists(SubscriptNode subscript | + exists(Cfg::SubscriptNode subscript | subscript.getObject() = instance().asCfgNode() and - value.asCfgNode() = subscript.(DefinitionNode).getValue() and + value.asCfgNode() = subscript.(Cfg::DefinitionNode).getValue() and index.asCfgNode() = subscript.getIndex() and this.asCfgNode() = subscript ) @@ -422,7 +423,7 @@ module Tornado { // be able to do something more structured for providing modeling of the members // of a container-object. exists(DataFlow::AttrRead files | files.accesses(instance(), "cookies") | - this.asCfgNode().(SubscriptNode).getObject() = files.asCfgNode() + this.asCfgNode().(Cfg::SubscriptNode).getObject() = files.asCfgNode() or this.(DataFlow::MethodCallNode).calls(files, "get") ) @@ -479,20 +480,20 @@ module Tornado { // routing // --------------------------------------------------------------------------- /** Gets a sequence that defines a number of route rules */ - SequenceNode routeSetupRuleList() { - exists(CallNode call | + Cfg::SequenceNode routeSetupRuleList() { + exists(Cfg::CallNode call | call = any(TornadoModule::Web::Application::ClassInstantiation c).asCfgNode() | result in [call.getArg(0), call.getArgByName("handlers")] ) or - exists(CallNode call | + exists(Cfg::CallNode call | call.getFunction() = TornadoModule::Web::Application::add_handlers().asCfgNode() | result in [call.getArg(1), call.getArgByName("host_handlers")] ) or - result = routeSetupRuleList().getElement(_).(TupleNode).getElement(1) + result = routeSetupRuleList().getElement(_).(Cfg::TupleNode).getElement(1) } /** A tornado route setup. */ @@ -515,12 +516,12 @@ module Tornado { /** A route setup using a tuple. */ private class TornadoTupleRouteSetup extends TornadoRouteSetup, DataFlow::CfgNode { - override TupleNode node; + override Cfg::TupleNode node; TornadoTupleRouteSetup() { node = routeSetupRuleList().getElement(_) and count(node.getElement(_)) = 2 and - not node.getElement(1) instanceof SequenceNode + not node.getElement(1) instanceof Cfg::SequenceNode } override DataFlow::Node getUrlPatternArg() { result.asCfgNode() = node.getElement(0) } diff --git a/python/ql/lib/semmle/python/frameworks/Werkzeug.qll b/python/ql/lib/semmle/python/frameworks/Werkzeug.qll index d9150c8cfecd..d88171275da2 100644 --- a/python/ql/lib/semmle/python/frameworks/Werkzeug.qll +++ b/python/ql/lib/semmle/python/frameworks/Werkzeug.qll @@ -6,6 +6,7 @@ */ private import python +private import semmle.python.controlflow.internal.Cfg as Cfg private import semmle.python.dataflow.new.DataFlow private import semmle.python.dataflow.new.TaintTracking private import semmle.python.ApiGraphs @@ -221,9 +222,9 @@ module Werkzeug { DataFlow::Node value; HeaderWriteSubscript() { - exists(SubscriptNode subscript | + exists(Cfg::SubscriptNode subscript | this.asCfgNode() = subscript and - value.asCfgNode() = subscript.(DefinitionNode).getValue() and + value.asCfgNode() = subscript.(Cfg::DefinitionNode).getValue() and name.asCfgNode() = subscript.getIndex() and subscript.getObject() = instance().asCfgNode() ) diff --git a/python/ql/lib/semmle/python/frameworks/Yaml.qll b/python/ql/lib/semmle/python/frameworks/Yaml.qll index 670fad75e6e3..8c5601f5a71d 100644 --- a/python/ql/lib/semmle/python/frameworks/Yaml.qll +++ b/python/ql/lib/semmle/python/frameworks/Yaml.qll @@ -8,6 +8,7 @@ */ private import python +private import semmle.python.controlflow.internal.Cfg as Cfg private import semmle.python.dataflow.new.DataFlow private import semmle.python.Concepts private import semmle.python.ApiGraphs @@ -28,7 +29,7 @@ private module Yaml { * See https://pyyaml.org/wiki/PyYAMLDocumentation (you will have to scroll down). */ private class YamlLoadCall extends Decoding::Range, DataFlow::CallCfgNode { - override CallNode node; + override Cfg::CallNode node; string func_name; YamlLoadCall() { diff --git a/python/ql/lib/semmle/python/frameworks/Yarl.qll b/python/ql/lib/semmle/python/frameworks/Yarl.qll index a1c602e6016b..670075764332 100644 --- a/python/ql/lib/semmle/python/frameworks/Yarl.qll +++ b/python/ql/lib/semmle/python/frameworks/Yarl.qll @@ -4,6 +4,7 @@ */ private import python +private import semmle.python.controlflow.internal.Cfg as Cfg private import semmle.python.dataflow.new.DataFlow private import semmle.python.dataflow.new.TaintTracking private import semmle.python.Concepts @@ -111,7 +112,7 @@ module Yarl { } private predicate yarlUrlIsAbsoluteCall( - DataFlow::GuardNode g, ControlFlowNode node, boolean branch + DataFlow::GuardNode g, Cfg::ControlFlowNode node, boolean branch ) { exists(ClassInstantiation instance, DataFlow::MethodCallNode call | call.calls(instance, "is_absolute") and diff --git a/python/ql/lib/semmle/python/frameworks/internal/SubclassFinder.qll b/python/ql/lib/semmle/python/frameworks/internal/SubclassFinder.qll index 7916a54afcb5..831535e3b19d 100644 --- a/python/ql/lib/semmle/python/frameworks/internal/SubclassFinder.qll +++ b/python/ql/lib/semmle/python/frameworks/internal/SubclassFinder.qll @@ -11,6 +11,7 @@ private import semmle.python.dataflow.new.internal.ImportResolution private import semmle.python.ApiGraphs private import semmle.python.filters.Tests private import semmle.python.Module +private import semmle.python.controlflow.internal.Cfg as Cfg // very much inspired by the draft at https://github.com/github/codeql/pull/5632 module NotExposed { @@ -206,7 +207,7 @@ module NotExposed { string relevantName, Location loc ) { loc = mod.getLocation() and - exists(API::Node relevantClass, ControlFlowNode value | + exists(API::Node relevantClass, Cfg::ControlFlowNode value | relevantClass = newOrExistingModeling(spec).getASubclass*() and ImportResolution::module_export(mod, relevantName, def) and value = relevantClass.getAValueReachableFromSource().asCfgNode() and diff --git a/python/ql/lib/semmle/python/regexp/internal/ParseRegExp.qll b/python/ql/lib/semmle/python/regexp/internal/ParseRegExp.qll index d91c4bbd78c0..23031c30772c 100644 --- a/python/ql/lib/semmle/python/regexp/internal/ParseRegExp.qll +++ b/python/ql/lib/semmle/python/regexp/internal/ParseRegExp.qll @@ -3,6 +3,7 @@ */ import python +private import semmle.python.controlflow.internal.Cfg as Cfg private import semmle.python.dataflow.new.DataFlow private import semmle.python.Concepts as Concepts private import semmle.python.regex @@ -78,7 +79,7 @@ private module FindRegexMode { t.start() and exists(API::Node flag | flag_name = canonical_name(flag) and result = flag.asSource()) or - exists(BinaryExprNode binop, DataFlow::Node operand | + exists(Cfg::BinaryExprNode binop, DataFlow::Node operand | operand.getALocalSource() = re_flag_tracker(flag_name, t.continue()) and operand.asCfgNode() = binop.getAnOperand() and (binop.getOp() instanceof BitOr or binop.getOp() instanceof Add) and diff --git a/python/ql/lib/semmle/python/security/dataflow/ExceptionInfo.qll b/python/ql/lib/semmle/python/security/dataflow/ExceptionInfo.qll index e389dd3dd4d1..f7d87f17402e 100644 --- a/python/ql/lib/semmle/python/security/dataflow/ExceptionInfo.qll +++ b/python/ql/lib/semmle/python/security/dataflow/ExceptionInfo.qll @@ -3,6 +3,7 @@ import python import semmle.python.dataflow.new.DataFlow private import semmle.python.ApiGraphs +private import semmle.python.controlflow.internal.Cfg as Cfg /** * INTERNAL: Do not use. @@ -29,7 +30,7 @@ private class TracebackFunctionCall extends ExceptionInfo, DataFlow::CallCfgNode private class CaughtException extends ExceptionInfo { CaughtException() { this.asExpr() = any(ExceptStmt s).getName() and - this.asCfgNode() = any(EssaNodeDefinition def).getDefiningNode() + this.asCfgNode().(Cfg::NameNode).defines(_) } } diff --git a/python/ql/lib/semmle/python/security/dataflow/ServerSideRequestForgeryCustomizations.qll b/python/ql/lib/semmle/python/security/dataflow/ServerSideRequestForgeryCustomizations.qll index e3f18170f630..bca40652403a 100644 --- a/python/ql/lib/semmle/python/security/dataflow/ServerSideRequestForgeryCustomizations.qll +++ b/python/ql/lib/semmle/python/security/dataflow/ServerSideRequestForgeryCustomizations.qll @@ -11,6 +11,7 @@ private import semmle.python.dataflow.new.RemoteFlowSources private import semmle.python.dataflow.new.BarrierGuards private import semmle.python.ApiGraphs private import semmle.python.frameworks.data.internal.ApiGraphModels +private import semmle.python.controlflow.internal.Cfg as Cfg /** * Provides default sources, sinks and sanitizers for detecting @@ -95,7 +96,7 @@ module ServerSideRequestForgery { class StringConstructionAsFullUrlControlSanitizer extends FullUrlControlSanitizer { StringConstructionAsFullUrlControlSanitizer() { // string concat - exists(BinaryExprNode add | + exists(Cfg::BinaryExprNode add | add.getOp() instanceof Add and add.getRight() = this.asCfgNode() and not add.getLeft().getNode().(StringLiteral).getText().toLowerCase() in [ @@ -104,7 +105,7 @@ module ServerSideRequestForgery { ) or // % formatting - exists(BinaryExprNode fmt | + exists(Cfg::BinaryExprNode fmt | fmt.getOp() instanceof Mod and fmt.getRight() = this.asCfgNode() and // detecting %-formatting is not super easy, so we simplify it to only handle @@ -155,7 +156,9 @@ module ServerSideRequestForgery { } } - private predicate stringRestriction(DataFlow::GuardNode g, ControlFlowNode node, boolean branch) { + private predicate stringRestriction( + DataFlow::GuardNode g, Cfg::ControlFlowNode node, boolean branch + ) { exists(DataFlow::MethodCallNode call, DataFlow::Node strNode | call.asCfgNode() = g and strNode.asCfgNode() = node | diff --git a/python/ql/lib/semmle/python/security/dataflow/TarSlipCustomizations.qll b/python/ql/lib/semmle/python/security/dataflow/TarSlipCustomizations.qll index 2dbe2c542aee..7dcf74d94c4e 100644 --- a/python/ql/lib/semmle/python/security/dataflow/TarSlipCustomizations.qll +++ b/python/ql/lib/semmle/python/security/dataflow/TarSlipCustomizations.qll @@ -9,6 +9,7 @@ private import semmle.python.dataflow.new.DataFlow private import semmle.python.Concepts private import semmle.python.dataflow.new.BarrierGuards private import semmle.python.ApiGraphs +private import semmle.python.controlflow.internal.Cfg as Cfg /** * Provides default sources, sinks and sanitizers for detecting @@ -139,8 +140,8 @@ module TarSlip { * where `` is any function matching `"%path"`. * `info` is assumed to be a `TarInfo` instance. */ - predicate tarFileInfoSanitizer(DataFlow::GuardNode g, ControlFlowNode tarInfo, boolean branch) { - exists(CallNode call, AttrNode attr | + predicate tarFileInfoSanitizer(DataFlow::GuardNode g, Cfg::ControlFlowNode tarInfo, boolean branch) { + exists(Cfg::CallNode call, Cfg::AttrNode attr | g = call and // We must test the name of the tar info object. attr = call.getAnArg() and @@ -148,9 +149,9 @@ module TarSlip { attr.getObject() = tarInfo | // The assumption that any test that matches %path is a sanitizer might be too broad. - call.getAChild*().(AttrNode).getName().matches("%path") + call.getAChild*().(Cfg::AttrNode).getName().matches("%path") or - call.getAChild*().(NameNode).getId().matches("%path") + call.getAChild*().(Cfg::NameNode).getId().matches("%path") ) and branch = false } diff --git a/python/ql/lib/semmle/python/security/dataflow/UrlRedirectCustomizations.qll b/python/ql/lib/semmle/python/security/dataflow/UrlRedirectCustomizations.qll index 75a638fc3a42..38b05ecf05d1 100644 --- a/python/ql/lib/semmle/python/security/dataflow/UrlRedirectCustomizations.qll +++ b/python/ql/lib/semmle/python/security/dataflow/UrlRedirectCustomizations.qll @@ -5,6 +5,7 @@ */ private import python +private import semmle.python.controlflow.internal.Cfg as Cfg private import semmle.python.dataflow.new.DataFlow private import semmle.python.Concepts private import semmle.python.ApiGraphs @@ -111,7 +112,7 @@ module UrlRedirect { // Url redirection is a problem only if the user controls the prefix of the URL. // TODO: This is a copy of the taint-sanitizer from the old points-to query, which doesn't // cover formatting. - exists(BinaryExprNode string_concat | string_concat.getOp() instanceof Add | + exists(Cfg::BinaryExprNode string_concat | string_concat.getOp() instanceof Add | string_concat.getRight() = this.asCfgNode() ) } diff --git a/python/ql/lib/utils/test/dataflow/MaximalFlowTest.qll b/python/ql/lib/utils/test/dataflow/MaximalFlowTest.qll index cbd3b4c6aa51..f9b1b1c676d2 100644 --- a/python/ql/lib/utils/test/dataflow/MaximalFlowTest.qll +++ b/python/ql/lib/utils/test/dataflow/MaximalFlowTest.qll @@ -1,4 +1,5 @@ import python +private import semmle.python.controlflow.internal.Cfg as Cfg import semmle.python.dataflow.new.DataFlow private import semmle.python.dataflow.new.internal.DataFlowPrivate import FlowTest @@ -23,7 +24,7 @@ import MakeTest> module MaximalFlowsConfig implements DataFlow::ConfigSig { predicate isSource(DataFlow::Node node) { exists(node.getLocation().getFile().getRelativePath()) and - not node.asCfgNode() instanceof CallNode and + not node.asCfgNode() instanceof Cfg::CallNode and not node.asCfgNode().getNode() instanceof Return and not node instanceof DataFlow::ParameterNode and not node instanceof DataFlow::PostUpdateNode and @@ -34,9 +35,9 @@ module MaximalFlowsConfig implements DataFlow::ConfigSig { predicate isSink(DataFlow::Node node) { exists(node.getLocation().getFile().getRelativePath()) and - not any(CallNode c).getArg(_) = node.asCfgNode() and + not any(Cfg::CallNode c).getArg(_) = node.asCfgNode() and not isArgumentNode(node, _, _) and - not node.asCfgNode().(NameNode).getId().matches("SINK%") and + not node.asCfgNode().(Cfg::NameNode).getId().matches("SINK%") and not DataFlow::localFlowStep(node, _) } } diff --git a/python/ql/lib/utils/test/dataflow/NormalDataflowTest.qll b/python/ql/lib/utils/test/dataflow/NormalDataflowTest.qll index 696b43d5f038..6c27cdc25239 100644 --- a/python/ql/lib/utils/test/dataflow/NormalDataflowTest.qll +++ b/python/ql/lib/utils/test/dataflow/NormalDataflowTest.qll @@ -1,4 +1,5 @@ import python +private import semmle.python.controlflow.internal.Cfg as Cfg import utils.test.dataflow.FlowTest import utils.test.dataflow.testConfig private import semmle.python.dataflow.new.internal.PrintNode @@ -19,7 +20,7 @@ query predicate missingAnnotationOnSink(Location location, string error, string TestConfig::isSink(sink) and // note: we only care about `SINK` and not `SINK_F`, so we have to reconstruct manually. exists(DataFlow::CallCfgNode call | - call.getFunction().asCfgNode().(NameNode).getId() = "SINK" and + call.getFunction().asCfgNode().(Cfg::NameNode).getId() = "SINK" and (sink = call.getArg(_) or sink = call.getArgByName(_)) ) and location = sink.getLocation() and diff --git a/python/ql/lib/utils/test/dataflow/NormalTaintTrackingTest.qll b/python/ql/lib/utils/test/dataflow/NormalTaintTrackingTest.qll index 753f8f61e137..df2f35c48fe0 100644 --- a/python/ql/lib/utils/test/dataflow/NormalTaintTrackingTest.qll +++ b/python/ql/lib/utils/test/dataflow/NormalTaintTrackingTest.qll @@ -1,4 +1,5 @@ import python +private import semmle.python.controlflow.internal.Cfg as Cfg import utils.test.dataflow.FlowTest import utils.test.dataflow.testTaintConfig private import semmle.python.dataflow.new.internal.PrintNode @@ -18,7 +19,7 @@ query predicate missingAnnotationOnSink(Location location, string error, string exists(DataFlow::Node sink | exists(DataFlow::CallCfgNode call | // note: we only care about `SINK` and not `SINK_F`, so we have to reconstruct manually. - call.getFunction().asCfgNode().(NameNode).getId() = "SINK" and + call.getFunction().asCfgNode().(Cfg::NameNode).getId() = "SINK" and (sink = call.getArg(_) or sink = call.getArgByName(_)) ) and location = sink.getLocation() and diff --git a/python/ql/lib/utils/test/dataflow/RoutingTest.qll b/python/ql/lib/utils/test/dataflow/RoutingTest.qll index e7ac4e872470..ffa52dbd550f 100644 --- a/python/ql/lib/utils/test/dataflow/RoutingTest.qll +++ b/python/ql/lib/utils/test/dataflow/RoutingTest.qll @@ -1,4 +1,5 @@ import python +private import semmle.python.controlflow.internal.Cfg as Cfg import semmle.python.dataflow.new.DataFlow import utils.test.InlineExpectationsTest private import semmle.python.dataflow.new.internal.PrintNode @@ -49,7 +50,7 @@ private string fromValue(DataFlow::Node fromNode) { pragma[inline] private string fromFunc(DataFlow::ArgumentNode fromNode) { - result = fromNode.getCall().getNode().(CallNode).getFunction().getNode().(Name).getId() + result = fromNode.getCall().getNode().(Cfg::CallNode).getFunction().getNode().(Name).getId() } pragma[inline] diff --git a/python/ql/lib/utils/test/dataflow/UnresolvedCalls.qll b/python/ql/lib/utils/test/dataflow/UnresolvedCalls.qll index a4dfb07ee90f..f38a28a7db05 100644 --- a/python/ql/lib/utils/test/dataflow/UnresolvedCalls.qll +++ b/python/ql/lib/utils/test/dataflow/UnresolvedCalls.qll @@ -1,15 +1,16 @@ import python +private import semmle.python.controlflow.internal.Cfg as Cfg private import semmle.python.dataflow.new.internal.PrintNode private import semmle.python.dataflow.new.internal.DataFlowPrivate as DataFlowPrivate private import semmle.python.ApiGraphs import utils.test.InlineExpectationsTest signature module UnresolvedCallExpectationsSig { - predicate unresolvedCall(CallNode call); + predicate unresolvedCall(Cfg::CallNode call); } module DefaultUnresolvedCallExpectations implements UnresolvedCallExpectationsSig { - predicate unresolvedCall(CallNode call) { + predicate unresolvedCall(Cfg::CallNode call) { not exists(DataFlowPrivate::DataFlowCall dfc | exists(dfc.getCallable()) and dfc.getNode() = call ) and @@ -24,7 +25,7 @@ module MakeUnresolvedCallExpectations { predicate hasActualResult(Location location, string element, string tag, string value) { exists(location.getFile().getRelativePath()) and - exists(CallNode call | Impl::unresolvedCall(call) | + exists(Cfg::CallNode call | Impl::unresolvedCall(call) and call.injects(_) | location = call.getLocation() and tag = "unresolved_call" and value = prettyExpr(call.getNode()) and diff --git a/python/ql/lib/utils/test/dataflow/testConfig.qll b/python/ql/lib/utils/test/dataflow/testConfig.qll index 552180eeaaf3..cfdf1e1a7c92 100644 --- a/python/ql/lib/utils/test/dataflow/testConfig.qll +++ b/python/ql/lib/utils/test/dataflow/testConfig.qll @@ -21,11 +21,12 @@ */ private import python +private import semmle.python.controlflow.internal.Cfg as Cfg import semmle.python.dataflow.new.DataFlow module TestConfig implements DataFlow::ConfigSig { predicate isSource(DataFlow::Node node) { - node.(DataFlow::CfgNode).getNode().(NameNode).getId() = "SOURCE" + node.(DataFlow::CfgNode).getNode().(Cfg::NameNode).getId() = "SOURCE" or node.(DataFlow::CfgNode).getNode().getNode().(StringLiteral).getS() = "source" or @@ -37,7 +38,7 @@ module TestConfig implements DataFlow::ConfigSig { predicate isSink(DataFlow::Node node) { exists(DataFlow::CallCfgNode call | - call.getFunction().asCfgNode().(NameNode).getId() in ["SINK", "SINK_F"] and + call.getFunction().asCfgNode().(Cfg::NameNode).getId() in ["SINK", "SINK_F"] and (node = call.getArg(_) or node = call.getArgByName(_)) and not node = call.getArgByName("not_present_at_runtime") ) diff --git a/python/ql/lib/utils/test/dataflow/testTaintConfig.qll b/python/ql/lib/utils/test/dataflow/testTaintConfig.qll index c9770600eeb4..b784042901e0 100644 --- a/python/ql/lib/utils/test/dataflow/testTaintConfig.qll +++ b/python/ql/lib/utils/test/dataflow/testTaintConfig.qll @@ -21,12 +21,13 @@ */ private import python +private import semmle.python.controlflow.internal.Cfg as Cfg import semmle.python.dataflow.new.DataFlow import semmle.python.dataflow.new.TaintTracking module TestConfig implements DataFlow::ConfigSig { predicate isSource(DataFlow::Node node) { - node.(DataFlow::CfgNode).getNode().(NameNode).getId() = "SOURCE" + node.(DataFlow::CfgNode).getNode().(Cfg::NameNode).getId() = "SOURCE" or node.(DataFlow::CfgNode).getNode().getNode().(StringLiteral).getS() = "source" or @@ -37,8 +38,8 @@ module TestConfig implements DataFlow::ConfigSig { } predicate isSink(DataFlow::Node node) { - exists(CallNode call | - call.getFunction().(NameNode).getId() in ["SINK", "SINK_F"] and + exists(Cfg::CallNode call | + call.getFunction().(Cfg::NameNode).getId() in ["SINK", "SINK_F"] and node.(DataFlow::CfgNode).getNode() = call.getAnArg() ) } diff --git a/python/ql/src/Exceptions/UnguardedNextInGenerator.ql b/python/ql/src/Exceptions/UnguardedNextInGenerator.ql index a6969218fddc..437a3f208df7 100644 --- a/python/ql/src/Exceptions/UnguardedNextInGenerator.ql +++ b/python/ql/src/Exceptions/UnguardedNextInGenerator.ql @@ -12,6 +12,8 @@ import python private import semmle.python.ApiGraphs +private import semmle.python.controlflow.internal.Cfg as Cfg +private import semmle.python.Flow as Flow API::Node iter() { result = API::builtin("iter") } @@ -19,17 +21,17 @@ API::Node next() { result = API::builtin("next") } API::Node stopIteration() { result = API::builtin("StopIteration") } -predicate call_to_iter(CallNode call, EssaVariable sequence) { - call = iter().getACall().asCfgNode() and +predicate call_to_iter(Flow::CallNode call, EssaVariable sequence) { + call.getNode() = iter().getACall().asCfgNode().(Cfg::CallNode).getNode() and call.getArg(0) = sequence.getAUse() } -predicate call_to_next(CallNode call, ControlFlowNode iter) { - call = next().getACall().asCfgNode() and +predicate call_to_next(Flow::CallNode call, Flow::ControlFlowNode iter) { + call.getNode() = next().getACall().asCfgNode().(Cfg::CallNode).getNode() and call.getArg(0) = iter } -predicate call_to_next_has_default(CallNode call) { +predicate call_to_next_has_default(Flow::CallNode call) { exists(call.getArg(1)) or exists(call.getArgByName("default")) } @@ -49,14 +51,14 @@ predicate iter_not_exhausted(EssaVariable iterator) { ) } -predicate stop_iteration_handled(CallNode call) { +predicate stop_iteration_handled(Flow::CallNode call) { exists(Try t | t.containsInScope(call.getNode()) and t.getAHandler().getType() = stopIteration().getAValueReachableFromSource().asExpr() ) } -from CallNode call +from Flow::CallNode call where call_to_next(call, _) and not call_to_next_has_default(call) and diff --git a/python/ql/src/Expressions/UseofApply.ql b/python/ql/src/Expressions/UseofApply.ql index f1068eca837c..6fa5c9817224 100644 --- a/python/ql/src/Expressions/UseofApply.ql +++ b/python/ql/src/Expressions/UseofApply.ql @@ -11,8 +11,9 @@ import python private import semmle.python.ApiGraphs +private import semmle.python.controlflow.internal.Cfg as Cfg -from CallNode call +from Cfg::CallNode call where major_version() = 2 and call = API::builtin("apply").getACall().asCfgNode() diff --git a/python/ql/src/Functions/SignatureOverriddenMethod.ql b/python/ql/src/Functions/SignatureOverriddenMethod.ql index 15b3fa706401..7ecced29c60f 100644 --- a/python/ql/src/Functions/SignatureOverriddenMethod.ql +++ b/python/ql/src/Functions/SignatureOverriddenMethod.ql @@ -15,6 +15,7 @@ import python import semmle.python.dataflow.new.DataFlow import semmle.python.dataflow.new.internal.DataFlowDispatch +private import semmle.python.controlflow.internal.Cfg as Cfg import codeql.util.Option /** Holds if `base` is overridden by `sub` */ @@ -143,7 +144,7 @@ predicate ignore(Function f) { /** Gets a function that `call` may resolve to. */ Function resolveCall(Call call) { - exists(DataFlowCall dfc | call = dfc.getNode().(CallNode).getNode() | + exists(DataFlowCall dfc | call = dfc.getNode().(Cfg::CallNode).getNode() | result = viableCallable(dfc).(DataFlowFunction).getScope() ) } diff --git a/python/ql/src/Resources/FileNotAlwaysClosedQuery.qll b/python/ql/src/Resources/FileNotAlwaysClosedQuery.qll index 2dfda7044d92..4b8a3631806e 100644 --- a/python/ql/src/Resources/FileNotAlwaysClosedQuery.qll +++ b/python/ql/src/Resources/FileNotAlwaysClosedQuery.qll @@ -4,6 +4,7 @@ import python import semmle.python.dataflow.new.internal.DataFlowDispatch import semmle.python.ApiGraphs private import semmle.python.dataflow.new.internal.ReExposedInstance +private import semmle.python.controlflow.internal.Cfg as Cfg /** A CFG node where a file is opened. */ abstract class FileOpenSource extends DataFlow::CfgNode { } @@ -81,12 +82,14 @@ abstract class FileClose extends DataFlow::CfgNode { } } -private predicate bbSuccessor(BasicBlock src, BasicBlock sink) { sink = src.getASuccessor() } +private predicate bbSuccessor(Cfg::BasicBlock src, Cfg::BasicBlock sink) { + sink = src.getASuccessor() +} -private predicate bbReachableStrict(BasicBlock src, BasicBlock sink) = +private predicate bbReachableStrict(Cfg::BasicBlock src, Cfg::BasicBlock sink) = fastTC(bbSuccessor/2)(src, sink) -private predicate bbReachableRefl(BasicBlock src, BasicBlock sink) { +private predicate bbReachableRefl(Cfg::BasicBlock src, Cfg::BasicBlock sink) { bbReachableStrict(src, sink) or src = sink } diff --git a/python/ql/src/Security/CWE-020-ExternalAPIs/ExternalAPIs.qll b/python/ql/src/Security/CWE-020-ExternalAPIs/ExternalAPIs.qll index 9c12845a0cad..1aa1e74cf132 100644 --- a/python/ql/src/Security/CWE-020-ExternalAPIs/ExternalAPIs.qll +++ b/python/ql/src/Security/CWE-020-ExternalAPIs/ExternalAPIs.qll @@ -10,6 +10,7 @@ private import semmle.python.dataflow.new.RemoteFlowSources private import semmle.python.ApiGraphs private import semmle.python.dataflow.new.internal.DataFlowPrivate as DataFlowPrivate private import semmle.python.dataflow.new.internal.TaintTrackingPrivate as TaintTrackingPrivate +private import semmle.python.controlflow.internal.Cfg as Cfg /** * An external API that is considered "safe" from a security perspective. @@ -71,7 +72,7 @@ string apiNodeToStringRepr(API::Node node) { ) } -predicate resolvedCall(CallNode call) { +predicate resolvedCall(Cfg::CallNode call) { DataFlowPrivate::resolveCall(call, _, _) or DataFlowPrivate::resolveClassCall(call, _) } diff --git a/python/ql/src/Security/CWE-079/Jinja2WithoutEscaping.ql b/python/ql/src/Security/CWE-079/Jinja2WithoutEscaping.ql index fd03ba433a10..fb5ef283e65a 100644 --- a/python/ql/src/Security/CWE-079/Jinja2WithoutEscaping.ql +++ b/python/ql/src/Security/CWE-079/Jinja2WithoutEscaping.ql @@ -14,6 +14,7 @@ import python import semmle.python.dataflow.new.DataFlow import semmle.python.ApiGraphs +private import semmle.python.controlflow.internal.Cfg as Cfg /* * Jinja 2 Docs: @@ -36,8 +37,8 @@ private API::Node jinja2EnvironmentOrTemplate() { from API::CallNode call where call = jinja2EnvironmentOrTemplate().getACall() and - not exists(call.asCfgNode().(CallNode).getNode().getStarargs()) and - not exists(call.asCfgNode().(CallNode).getNode().getKwargs()) and + not exists(call.asCfgNode().(Cfg::CallNode).getNode().getStarargs()) and + not exists(call.asCfgNode().(Cfg::CallNode).getNode().getKwargs()) and ( not exists(call.getArgByName("autoescape")) or diff --git a/python/ql/src/Security/CWE-327/PyOpenSSL.qll b/python/ql/src/Security/CWE-327/PyOpenSSL.qll index e2571195bfa0..7ce3276598c8 100644 --- a/python/ql/src/Security/CWE-327/PyOpenSSL.qll +++ b/python/ql/src/Security/CWE-327/PyOpenSSL.qll @@ -5,6 +5,7 @@ private import python private import semmle.python.ApiGraphs +private import semmle.python.controlflow.internal.Cfg as Cfg import TlsLibraryModel class PyOpenSslContextCreation extends ContextCreation, DataFlow::CallCfgNode { @@ -37,10 +38,10 @@ class ConnectionCall extends ConnectionCreation, DataFlow::CallCfgNode { // This cannot be used to unrestrict, // see https://www.pyopenssl.org/en/stable/api/ssl.html#OpenSSL.SSL.Context.set_options class SetOptionsCall extends ProtocolRestriction, DataFlow::CallCfgNode { - SetOptionsCall() { node.getFunction().(AttrNode).getName() = "set_options" } + SetOptionsCall() { node.getFunction().(Cfg::AttrNode).getName() = "set_options" } override DataFlow::CfgNode getContext() { - result.getNode() = node.getFunction().(AttrNode).getObject() + result.getNode() = node.getFunction().(Cfg::AttrNode).getObject() } override ProtocolVersion getRestriction() { diff --git a/python/ql/src/Security/CWE-327/Ssl.qll b/python/ql/src/Security/CWE-327/Ssl.qll index c3fd0366436d..5f35590bacf5 100644 --- a/python/ql/src/Security/CWE-327/Ssl.qll +++ b/python/ql/src/Security/CWE-327/Ssl.qll @@ -5,6 +5,7 @@ private import python private import semmle.python.ApiGraphs +private import semmle.python.controlflow.internal.Cfg as Cfg import TlsLibraryModel class SslContextCreation extends ContextCreation, DataFlow::CallCfgNode { @@ -53,7 +54,7 @@ class OptionsAugOr extends ProtocolRestriction, DataFlow::CfgNode { ProtocolVersion restriction; OptionsAugOr() { - exists(AugAssign aa, AttrNode attr, Expr flag | + exists(AugAssign aa, Cfg::AttrNode attr, Expr flag | aa.getOperation().getOp() instanceof BitOr and aa.getTarget() = attr.getNode() and attr.getName() = "options" and @@ -80,7 +81,7 @@ class OptionsAugAndNot extends ProtocolUnrestriction, DataFlow::CfgNode { ProtocolVersion restriction; OptionsAugAndNot() { - exists(AugAssign aa, AttrNode attr, Expr flag, UnaryExpr notFlag | + exists(AugAssign aa, Cfg::AttrNode attr, Expr flag, UnaryExpr notFlag | aa.getOperation().getOp() instanceof BitAnd and aa.getTarget() = attr.getNode() and attr.getName() = "options" and diff --git a/python/ql/src/Security/CWE-798/HardcodedCredentials.ql b/python/ql/src/Security/CWE-798/HardcodedCredentials.ql index baeaf26514c4..28b0e5da8c54 100644 --- a/python/ql/src/Security/CWE-798/HardcodedCredentials.ql +++ b/python/ql/src/Security/CWE-798/HardcodedCredentials.ql @@ -19,6 +19,7 @@ import semmle.python.filters.Tests private import semmle.python.dataflow.new.internal.DataFlowDispatch as DataFlowDispatch private import semmle.python.dataflow.new.internal.Builtins::Builtins as Builtins private import semmle.python.frameworks.data.ModelsAsData +private import semmle.python.controlflow.internal.Cfg as Cfg bindingset[char, fraction] predicate fewer_characters_than(StringLiteral str, string char, float fraction) { @@ -48,7 +49,7 @@ predicate capitalized_word(StringLiteral str) { str.getText().regexpMatch("[A-Z] predicate format_string(StringLiteral str) { str.getText().matches("%{%}%") } -predicate maybeCredential(ControlFlowNode f) { +predicate maybeCredential(Cfg::ControlFlowNode f) { /* A string that is not too short and unlikely to be text or an identifier. */ exists(StringLiteral str | str = f.getNode() | /* At least 10 characters */ @@ -96,7 +97,7 @@ class CredentialSink extends DataFlow::Node { or exists(Keyword k | k.getArg() = name and this.asCfgNode().getNode() = k.getValue()) or - exists(CompareNode cmp, NameNode n | n.getId() = name | + exists(Cfg::CompareNode cmp, Cfg::NameNode n | n.getId() = name | cmp.operands(this.asCfgNode(), any(Eq eq), n) or cmp.operands(n, any(Eq eq), this.asCfgNode()) diff --git a/python/ql/src/Statements/ModificationOfLocals.ql b/python/ql/src/Statements/ModificationOfLocals.ql index 886a49c763e9..4774c8d34313 100644 --- a/python/ql/src/Statements/ModificationOfLocals.ql +++ b/python/ql/src/Statements/ModificationOfLocals.ql @@ -14,8 +14,9 @@ import python private import semmle.python.ApiGraphs private import semmle.python.dataflow.new.DataFlow +private import semmle.python.controlflow.internal.Cfg as Cfg -predicate originIsLocals(ControlFlowNode n) { +predicate originIsLocals(Cfg::ControlFlowNode n) { // Only consider the `locals()` dictionary within the scope that called `locals()`. // Once the dictionary is passed to another scope (e.g. as an argument or via an // instance attribute) it is just an ordinary mapping, and modifying it is both @@ -28,19 +29,19 @@ predicate originIsLocals(ControlFlowNode n) { ) } -predicate modification_of_locals(ControlFlowNode f) { - originIsLocals(f.(SubscriptNode).getObject()) and +predicate modification_of_locals(Cfg::ControlFlowNode f) { + originIsLocals(f.(Cfg::SubscriptNode).getObject()) and (f.isStore() or f.isDelete()) or - exists(string mname, AttrNode attr | - attr = f.(CallNode).getFunction() and + exists(string mname, Cfg::AttrNode attr | + attr = f.(Cfg::CallNode).getFunction() and originIsLocals(attr.getObject(mname)) | mname in ["pop", "popitem", "update", "clear"] ) } -from AstNode a, ControlFlowNode f +from AstNode a, Cfg::ControlFlowNode f where modification_of_locals(f) and a = f.getNode() and diff --git a/python/ql/src/Statements/SideEffectInAssert.ql b/python/ql/src/Statements/SideEffectInAssert.ql index 55c34144dced..c58d3947424e 100644 --- a/python/ql/src/Statements/SideEffectInAssert.ql +++ b/python/ql/src/Statements/SideEffectInAssert.ql @@ -14,6 +14,7 @@ import python private import semmle.python.ApiGraphs +private import semmle.python.controlflow.internal.Cfg as Cfg predicate func_with_side_effects(Expr e) { exists(string name | name = e.(Attribute).getName() or name = e.(Name).getId() | @@ -24,7 +25,7 @@ predicate func_with_side_effects(Expr e) { } predicate call_with_side_effect(Call e) { - exists(ControlFlowNode eCfg | eCfg.getNode() = e | + exists(Cfg::ControlFlowNode eCfg | eCfg.getNode() = e | eCfg = API::moduleImport("subprocess") .getMember(["call", "check_call", "check_output"]) diff --git a/python/ql/src/Statements/UseOfExit.ql b/python/ql/src/Statements/UseOfExit.ql index 2310a839f67b..88a4f1ff7774 100644 --- a/python/ql/src/Statements/UseOfExit.ql +++ b/python/ql/src/Statements/UseOfExit.ql @@ -13,8 +13,9 @@ import python private import semmle.python.ApiGraphs +private import semmle.python.controlflow.internal.Cfg as Cfg -from CallNode call, string name +from Cfg::CallNode call, string name where name = ["exit", "quit"] and call = API::builtin(name).getACall().asCfgNode() diff --git a/python/ql/src/experimental/Security/CWE-022bis/TarSlipImprov.ql b/python/ql/src/experimental/Security/CWE-022bis/TarSlipImprov.ql index 42c0bc170fd9..5f49cb218805 100755 --- a/python/ql/src/experimental/Security/CWE-022bis/TarSlipImprov.ql +++ b/python/ql/src/experimental/Security/CWE-022bis/TarSlipImprov.ql @@ -21,6 +21,7 @@ import semmle.python.ApiGraphs import semmle.python.dataflow.new.internal.Attributes import semmle.python.dataflow.new.BarrierGuards import semmle.python.dataflow.new.RemoteFlowSources +private import semmle.python.controlflow.internal.Cfg as Cfg /** * Handle those three cases of Tarfile opens: @@ -75,8 +76,8 @@ private module TarSlipImprovConfig implements DataFlow::ConfigSig { call = atfo.getReturn().getMember("extractall").getACall() and arg = call.getArgByName("members") and if - arg.asCfgNode() instanceof NameConstantNode or - arg.asCfgNode() instanceof ListNode + arg.asCfgNode() instanceof Cfg::NameConstantNode or + arg.asCfgNode() instanceof Cfg::ListNode then sink = call.getObject() else if arg.(MethodCallNode).getMethodName() = "getmembers" diff --git a/python/ql/src/experimental/Security/CWE-340/TokenBuiltFromUUID.ql b/python/ql/src/experimental/Security/CWE-340/TokenBuiltFromUUID.ql index ab5a4243a746..f43b718289de 100644 --- a/python/ql/src/experimental/Security/CWE-340/TokenBuiltFromUUID.ql +++ b/python/ql/src/experimental/Security/CWE-340/TokenBuiltFromUUID.ql @@ -16,6 +16,7 @@ import python import semmle.python.dataflow.new.DataFlow import semmle.python.ApiGraphs import semmle.python.dataflow.new.TaintTracking +private import semmle.python.controlflow.internal.Cfg as Cfg class PredictableResultSource extends DataFlow::Node { PredictableResultSource() { @@ -32,7 +33,9 @@ class PredictableResultSource extends DataFlow::Node { class TokenAssignmentValueSink extends DataFlow::Node { TokenAssignmentValueSink() { exists(string name | name.toLowerCase().matches(["%token", "%code"]) | - exists(DefinitionNode n | n.getValue() = this.asCfgNode() | name = n.(NameNode).getId()) + exists(Cfg::DefinitionNode n | n.getValue() = this.asCfgNode() | + name = n.(Cfg::NameNode).getId() + ) or exists(DataFlow::AttrWrite aw | aw.getValue() = this | name = aw.getAttributeName()) ) diff --git a/python/ql/src/experimental/Security/CWE-346/CorsBypass.ql b/python/ql/src/experimental/Security/CWE-346/CorsBypass.ql index 01e661cb0bbf..5ce58869a890 100644 --- a/python/ql/src/experimental/Security/CWE-346/CorsBypass.ql +++ b/python/ql/src/experimental/Security/CWE-346/CorsBypass.ql @@ -11,25 +11,25 @@ import python import semmle.python.ApiGraphs import semmle.python.dataflow.new.TaintTracking -import semmle.python.Flow import semmle.python.dataflow.new.RemoteFlowSources +private import semmle.python.controlflow.internal.Cfg as Cfg /** * Returns true if the control flow node may be useful in the current context. * * Ideally for more completeness, we should alert on every `startswith` call and every remote flow source which gets partailly checked. But, as this can lead to lots of FPs, we apply heuristics to filter some calls. This predicate provides logic for this filteration. */ -private predicate maybeInteresting(ControlFlowNode c) { +private predicate maybeInteresting(Cfg::ControlFlowNode c) { // Check if the name of the variable which calls the function matches the heuristic. // This would typically occur at the sink. // This should deal with cases like // `origin.startswith("bla")` - heuristics(c.(CallNode).getFunction().(AttrNode).getObject().(NameNode).getId()) + heuristics(c.(Cfg::CallNode).getFunction().(Cfg::AttrNode).getObject().(Cfg::NameNode).getId()) or // Check if the name of the variable passed as an argument to the functions matches the heuristic. This would typically occur at the sink. // This should deal with cases like // `bla.startswith(origin)` - heuristics(c.(CallNode).getArg(0).(NameNode).getId()) + heuristics(c.(Cfg::CallNode).getArg(0).(Cfg::NameNode).getId()) or // Check if the value gets written to any interesting variable. This would typically occur at the source. // This should deal with cases like @@ -37,8 +37,10 @@ private predicate maybeInteresting(ControlFlowNode c) { exists(Variable v | heuristics(v.getId()) | c.getASuccessor*().getNode() = v.getAStore()) } -private class StringStartswithCall extends ControlFlowNode { - StringStartswithCall() { this.(CallNode).getFunction().(AttrNode).getName() = "startswith" } +private class StringStartswithCall extends Cfg::ControlFlowNode { + StringStartswithCall() { + this.(Cfg::CallNode).getFunction().(Cfg::AttrNode).getName() = "startswith" + } } bindingset[s] @@ -66,8 +68,8 @@ module CorsBypassConfig implements DataFlow::ConfigSig { predicate isSink(DataFlow::Node node) { exists(StringStartswithCall s | - node.asCfgNode() = s.(CallNode).getArg(0) or - node.asCfgNode() = s.(CallNode).getFunction().(AttrNode).getObject() + node.asCfgNode() = s.(Cfg::CallNode).getArg(0) or + node.asCfgNode() = s.(Cfg::CallNode).getFunction().(Cfg::AttrNode).getObject() ) } diff --git a/python/ql/src/experimental/Security/CWE-770/UnicodeDoS.ql b/python/ql/src/experimental/Security/CWE-770/UnicodeDoS.ql index 61cdd34920de..84627456310b 100644 --- a/python/ql/src/experimental/Security/CWE-770/UnicodeDoS.ql +++ b/python/ql/src/experimental/Security/CWE-770/UnicodeDoS.ql @@ -16,6 +16,7 @@ import semmle.python.Concepts import semmle.python.dataflow.new.TaintTracking import semmle.python.dataflow.new.internal.DataFlowPublic import semmle.python.dataflow.new.RemoteFlowSources +private import semmle.python.controlflow.internal.Cfg as Cfg // The Unicode compatibility normalization calls from unicodedata, unidecode, pyunormalize // and textnorm modules. The use of argIdx is to constraint the argument being normalized. @@ -52,8 +53,8 @@ class UnicodeCompatibilityNormalize extends API::CallNode { DataFlow::Node getPathArg() { result = this.getArg(argIdx) } } -predicate underAValue(DataFlow::GuardNode g, ControlFlowNode node, boolean branch) { - exists(CompareNode cn | cn = g | +predicate underAValue(DataFlow::GuardNode g, Cfg::ControlFlowNode node, boolean branch) { + exists(Cfg::CompareNode cn | cn = g | exists(API::CallNode lenCall, Cmpop op, Node n | lenCall = n.getALocalSource() and ( diff --git a/python/ql/src/experimental/Security/UnsafeUnpackQuery.qll b/python/ql/src/experimental/Security/UnsafeUnpackQuery.qll index 64da6b8d799a..ecc029ca8a78 100644 --- a/python/ql/src/experimental/Security/UnsafeUnpackQuery.qll +++ b/python/ql/src/experimental/Security/UnsafeUnpackQuery.qll @@ -9,6 +9,7 @@ import semmle.python.ApiGraphs import semmle.python.dataflow.new.TaintTracking import semmle.python.frameworks.Stdlib import semmle.python.dataflow.new.RemoteFlowSources +private import semmle.python.controlflow.internal.Cfg as Cfg /** * Handle those three cases of Tarfile opens: @@ -111,8 +112,8 @@ module UnsafeUnpackConfig implements DataFlow::ConfigSig { call = atfo.getReturn().getMember("extractall").getACall() and arg = call.getArgByName("members") and if - arg.asCfgNode() instanceof NameConstantNode or - arg.asCfgNode() instanceof ListNode + arg.asCfgNode() instanceof Cfg::NameConstantNode or + arg.asCfgNode() instanceof Cfg::ListNode then sink = call.getObject() else if arg.(MethodCallNode).getMethodName() = "getmembers" diff --git a/python/ql/src/experimental/semmle/python/security/injection/CsvInjection.qll b/python/ql/src/experimental/semmle/python/security/injection/CsvInjection.qll index 859f6d1e5e80..d789007b8d50 100644 --- a/python/ql/src/experimental/semmle/python/security/injection/CsvInjection.qll +++ b/python/ql/src/experimental/semmle/python/security/injection/CsvInjection.qll @@ -4,6 +4,7 @@ import semmle.python.dataflow.new.DataFlow import semmle.python.dataflow.new.TaintTracking import semmle.python.dataflow.new.BarrierGuards import semmle.python.dataflow.new.RemoteFlowSources +private import semmle.python.controlflow.internal.Cfg as Cfg /** * A taint-tracking configuration for tracking untrusted user input used in file read. @@ -21,7 +22,7 @@ private module CsvInjectionConfig implements DataFlow::ConfigSig { predicate observeDiffInformedIncrementalMode() { any() } } -private predicate startsWithCheck(DataFlow::GuardNode g, ControlFlowNode node, boolean branch) { +private predicate startsWithCheck(DataFlow::GuardNode g, Cfg::ControlFlowNode node, boolean branch) { exists(DataFlow::MethodCallNode mc | g = mc.asCfgNode() and mc.calls(_, "startswith") and diff --git a/python/ql/src/meta/analysis-quality/CallGraphQuality.qll b/python/ql/src/meta/analysis-quality/CallGraphQuality.qll index 679b39ddc8d4..1ac0896064b5 100644 --- a/python/ql/src/meta/analysis-quality/CallGraphQuality.qll +++ b/python/ql/src/meta/analysis-quality/CallGraphQuality.qll @@ -6,6 +6,7 @@ import python import meta.MetaMetrics private import LegacyPointsTo +private import semmle.python.controlflow.internal.Cfg as Cfg newtype TTarget = TFunction(Function func) or @@ -50,7 +51,7 @@ class TargetClass extends Target, TClass { * A call that is (possibly) relevant for analysis quality. * See `IgnoredFile` for details on what is excluded. */ -class RelevantCall extends CallNode { +class RelevantCall extends Cfg::CallNode { RelevantCall() { not this.getLocation().getFile() instanceof IgnoredFile } } @@ -60,7 +61,7 @@ module PointsToBasedCallGraph { class ResolvableCall extends RelevantCall { Value targetValue; - ResolvableCall() { targetValue.getACall() = this } + ResolvableCall() { targetValue.getACall().getNode() = this.getNode() } /** Gets a resolved target of this call. */ Target getTarget() { diff --git a/python/ql/src/meta/analysis-quality/TTCallGraph.ql b/python/ql/src/meta/analysis-quality/TTCallGraph.ql index bdd634951919..4487095a6fb6 100644 --- a/python/ql/src/meta/analysis-quality/TTCallGraph.ql +++ b/python/ql/src/meta/analysis-quality/TTCallGraph.ql @@ -8,8 +8,9 @@ import python import CallGraphQuality +private import semmle.python.controlflow.internal.Cfg as Cfg -from CallNode call, Target target +from Cfg::CallNode call, Target target where target.isRelevant() and call.(TypeTrackingBasedCallGraph::ResolvableCall).getTarget() = target diff --git a/python/ql/src/meta/analysis-quality/TTCallGraphMissing.ql b/python/ql/src/meta/analysis-quality/TTCallGraphMissing.ql index bb28c5bf804f..188f483689f5 100644 --- a/python/ql/src/meta/analysis-quality/TTCallGraphMissing.ql +++ b/python/ql/src/meta/analysis-quality/TTCallGraphMissing.ql @@ -8,8 +8,9 @@ import python import CallGraphQuality +private import semmle.python.controlflow.internal.Cfg as Cfg -from CallNode call, Target target +from Cfg::CallNode call, Target target where target.isRelevant() and call.(PointsToBasedCallGraph::ResolvableCall).getTarget() = target and diff --git a/python/ql/src/meta/analysis-quality/TTCallGraphNew.ql b/python/ql/src/meta/analysis-quality/TTCallGraphNew.ql index b9f1df54b3b2..198007d07759 100644 --- a/python/ql/src/meta/analysis-quality/TTCallGraphNew.ql +++ b/python/ql/src/meta/analysis-quality/TTCallGraphNew.ql @@ -8,8 +8,9 @@ import python import CallGraphQuality +private import semmle.python.controlflow.internal.Cfg as Cfg -from CallNode call, Target target +from Cfg::CallNode call, Target target where target.isRelevant() and not call.(PointsToBasedCallGraph::ResolvableCall).getTarget() = target and diff --git a/python/ql/src/meta/analysis-quality/TTCallGraphNewAmbiguous.ql b/python/ql/src/meta/analysis-quality/TTCallGraphNewAmbiguous.ql index 702541ca16d4..b14644f6585a 100644 --- a/python/ql/src/meta/analysis-quality/TTCallGraphNewAmbiguous.ql +++ b/python/ql/src/meta/analysis-quality/TTCallGraphNewAmbiguous.ql @@ -8,8 +8,9 @@ import python import CallGraphQuality +private import semmle.python.controlflow.internal.Cfg as Cfg -from CallNode call, Target target +from Cfg::CallNode call, Target target where target.isRelevant() and not call.(PointsToBasedCallGraph::ResolvableCall).getTarget() = target and diff --git a/python/ql/src/meta/analysis-quality/TTCallGraphOverview.ql b/python/ql/src/meta/analysis-quality/TTCallGraphOverview.ql index 5a789d1be90b..19660f92ec55 100644 --- a/python/ql/src/meta/analysis-quality/TTCallGraphOverview.ql +++ b/python/ql/src/meta/analysis-quality/TTCallGraphOverview.ql @@ -6,12 +6,13 @@ import python import CallGraphQuality +private import semmle.python.controlflow.internal.Cfg as Cfg from string tag, int c where tag = "SHARED" and c = - count(CallNode call, Target target | + count(Cfg::CallNode call, Target target | target.isRelevant() and call.(PointsToBasedCallGraph::ResolvableCall).getTarget() = target and call.(TypeTrackingBasedCallGraph::ResolvableCall).getTarget() = target @@ -19,7 +20,7 @@ where or tag = "NEW" and c = - count(CallNode call, Target target | + count(Cfg::CallNode call, Target target | target.isRelevant() and not call.(PointsToBasedCallGraph::ResolvableCall).getTarget() = target and call.(TypeTrackingBasedCallGraph::ResolvableCall).getTarget() = target @@ -27,7 +28,7 @@ where or tag = "MISSING" and c = - count(CallNode call, Target target | + count(Cfg::CallNode call, Target target | target.isRelevant() and call.(PointsToBasedCallGraph::ResolvableCall).getTarget() = target and not call.(TypeTrackingBasedCallGraph::ResolvableCall).getTarget() = target diff --git a/python/ql/src/meta/analysis-quality/TTCallGraphShared.ql b/python/ql/src/meta/analysis-quality/TTCallGraphShared.ql index d44d1ac497ff..f8275b5a965b 100644 --- a/python/ql/src/meta/analysis-quality/TTCallGraphShared.ql +++ b/python/ql/src/meta/analysis-quality/TTCallGraphShared.ql @@ -8,8 +8,9 @@ import python import CallGraphQuality +private import semmle.python.controlflow.internal.Cfg as Cfg -from CallNode call, Target target +from Cfg::CallNode call, Target target where target.isRelevant() and call.(PointsToBasedCallGraph::ResolvableCall).getTarget() = target and diff --git a/python/ql/src/semmle/python/functions/ModificationOfParameterWithDefaultCustomizations.qll b/python/ql/src/semmle/python/functions/ModificationOfParameterWithDefaultCustomizations.qll index 83ba4df4e298..1d6a05780672 100644 --- a/python/ql/src/semmle/python/functions/ModificationOfParameterWithDefaultCustomizations.qll +++ b/python/ql/src/semmle/python/functions/ModificationOfParameterWithDefaultCustomizations.qll @@ -6,6 +6,7 @@ private import python private import semmle.python.dataflow.new.DataFlow private import semmle.python.dataflow.new.BarrierGuards +private import semmle.python.controlflow.internal.Cfg as Cfg /** * Provides default sources, sinks and sanitizers for detecting @@ -76,7 +77,7 @@ module ModificationOfParameterWithDefault { boolean nonEmpty; MutableDefaultValue() { - nonEmpty = mutableDefaultValue(this.asCfgNode().(NameNode).getNode()) and + nonEmpty = mutableDefaultValue(this.asCfgNode().(Cfg::NameNode).getNode()) and // Ignore sources inside the standard library. These are unlikely to be true positives. exists(this.getLocation().getFile().getRelativePath()) } @@ -125,10 +126,10 @@ module ModificationOfParameterWithDefault { class Mutation extends Sink { Mutation() { // assignment to a subscript (includes slices) - exists(DefinitionNode d | d.(SubscriptNode).getObject() = this.asCfgNode()) + exists(Cfg::DefinitionNode d | d.(Cfg::SubscriptNode).getObject() = this.asCfgNode()) or // deletion of a subscript - exists(DeletionNode d | d.getTarget().(SubscriptNode).getObject() = this.asCfgNode()) + exists(Cfg::DeletionNode d | d.(Cfg::SubscriptNode).getObject() = this.asCfgNode()) or // augmented assignment to the value exists(AugAssign a | this.asCfgNode().getNode() = a.getTarget()) @@ -141,54 +142,26 @@ module ModificationOfParameterWithDefault { } } - // This to reimplement some of the functionality of the DataFlow::BarrierGuard - private import semmle.python.essa.SsaCompute - /** - * A data-flow node that is known to be either truthy or falsey. - * - * It handles the cases `if x` and `if not x`. - * - * For example, in the following code, `this` will be the `x` that is printed, - * which we will know is truthy: - * - * ```py - * if x: - * print(x) - * ``` + * Holds if `g` is a direct truthiness check that proves its (single + * operand-and-result) value truthy on the `true` branch — i.e. `if g:`. */ - private class MustBe extends DataFlow::Node { - boolean truthy; - - MustBe() { - exists(DataFlow::GuardNode guard, NameNode guarded, boolean branch | - // case: if x - guard = guarded and - branch = truthy - or - // case: if not x - guard.(UnaryExprNode).getNode().getOp() instanceof Not and - guarded = guard.(UnaryExprNode).getOperand() and - branch = truthy.booleanNot() - | - // guard controls this - guard.controlsBlock(this.asCfgNode().getBasicBlock(), branch) and - // there is a definition tying the guarded value to this - exists(EssaDefinition def | - AdjacentUses::useOfDef(def, this.asCfgNode()) and - AdjacentUses::useOfDef(def, guarded) - ) - ) - } + private predicate truthyGuard(DataFlow::GuardNode g, Cfg::ControlFlowNode node, boolean branch) { + node = g and branch = true + } + + /** Holds if `g` is a direct falsiness check — i.e. `if g:` taken to the false branch. */ + private predicate falseyGuard(DataFlow::GuardNode g, Cfg::ControlFlowNode node, boolean branch) { + node = g and branch = false } /** Simple guard detecting truthy values. */ - private class MustBeTruthy extends MustBe, MustBeNonEmpty { - MustBeTruthy() { truthy = true } + private class MustBeTruthy extends MustBeNonEmpty { + MustBeTruthy() { this = DataFlow::BarrierGuard::getABarrierNode() } } /** Simple guard detecting falsey values. */ - private class MustBeFalsey extends MustBe, MustBeEmpty { - MustBeFalsey() { truthy = false } + private class MustBeFalsey extends MustBeEmpty { + MustBeFalsey() { this = DataFlow::BarrierGuard::getABarrierNode() } } } diff --git a/python/ql/test/2/query-tests/Exceptions/generators/UnguardedNextInGenerator.expected b/python/ql/test/2/query-tests/Exceptions/generators/UnguardedNextInGenerator.expected index 7cd772d46623..69b06e3ecd97 100644 --- a/python/ql/test/2/query-tests/Exceptions/generators/UnguardedNextInGenerator.expected +++ b/python/ql/test/2/query-tests/Exceptions/generators/UnguardedNextInGenerator.expected @@ -1,2 +1,5 @@ | test.py:5:15:5:22 | ControlFlowNode for next() | Call to 'next()' in a generator. | | test.py:10:20:10:27 | ControlFlowNode for next() | Call to 'next()' in a generator. | +| test.py:34:15:34:24 | ControlFlowNode for next() | Call to 'next()' in a generator. | +| test.py:41:19:41:28 | ControlFlowNode for next() | Call to 'next()' in a generator. | +| test.py:62:19:62:28 | ControlFlowNode for next() | Call to 'next()' in a generator. | diff --git a/python/ql/test/2/query-tests/Exceptions/raising/RaisingTuple.expected b/python/ql/test/2/query-tests/Exceptions/raising/RaisingTuple.expected index ecfd7587d535..5f914d6c49ea 100644 --- a/python/ql/test/2/query-tests/Exceptions/raising/RaisingTuple.expected +++ b/python/ql/test/2/query-tests/Exceptions/raising/RaisingTuple.expected @@ -1,3 +1,3 @@ -| test.py:8:5:8:12 | Raise | Raising a $@ will result in the first element (recursively) being raised and all other elements being discarded. | test.py:7:10:7:29 | ControlFlowNode for Tuple | tuple | -| test.py:11:5:11:32 | Raise | Raising a $@ will result in the first element (recursively) being raised and all other elements being discarded. | test.py:11:12:11:31 | ControlFlowNode for Tuple | tuple | -| test.py:15:5:15:23 | Raise | Raising a $@ will result in the first element (recursively) being raised and all other elements being discarded. | test.py:14:10:14:19 | ControlFlowNode for Tuple | tuple | +| test.py:8:5:8:12 | Raise | Raising a $@ will result in the first element (recursively) being raised and all other elements being discarded. | test.py:7:10:7:29 | After Tuple | tuple | +| test.py:11:5:11:32 | Raise | Raising a $@ will result in the first element (recursively) being raised and all other elements being discarded. | test.py:11:12:11:31 | After Tuple | tuple | +| test.py:15:5:15:23 | Raise | Raising a $@ will result in the first element (recursively) being raised and all other elements being discarded. | test.py:14:10:14:19 | After Tuple | tuple | diff --git a/python/ql/test/2/query-tests/Expressions/UseofApply.expected b/python/ql/test/2/query-tests/Expressions/UseofApply.expected index 0c5e28c94940..78ec06d8b071 100644 --- a/python/ql/test/2/query-tests/Expressions/UseofApply.expected +++ b/python/ql/test/2/query-tests/Expressions/UseofApply.expected @@ -1,2 +1,2 @@ -| UseofApply.py:19:3:19:17 | ControlFlowNode for apply() | Call to the obsolete builtin function 'apply'. | -| expressions_test.py:2:5:2:21 | ControlFlowNode for apply() | Call to the obsolete builtin function 'apply'. | +| UseofApply.py:19:3:19:17 | After apply() | Call to the obsolete builtin function 'apply'. | +| expressions_test.py:2:5:2:21 | After apply() | Call to the obsolete builtin function 'apply'. | diff --git a/python/ql/test/2/query-tests/Expressions/UseofInput.expected b/python/ql/test/2/query-tests/Expressions/UseofInput.expected index 470c24df21f8..e1ded3ef9616 100644 --- a/python/ql/test/2/query-tests/Expressions/UseofInput.expected +++ b/python/ql/test/2/query-tests/Expressions/UseofInput.expected @@ -1 +1 @@ -| expressions_test.py:6:12:6:18 | ControlFlowNode for input() | The unsafe built-in function 'input' is used in Python 2. | +| expressions_test.py:6:12:6:18 | After input() | The unsafe built-in function 'input' is used in Python 2. | diff --git a/python/ql/test/experimental/attrs/AttrReads.expected b/python/ql/test/experimental/attrs/AttrReads.expected index 28fda7c75d4d..a313b5abec22 100644 --- a/python/ql/test/experimental/attrs/AttrReads.expected +++ b/python/ql/test/experimental/attrs/AttrReads.expected @@ -1,2 +1,2 @@ -| test.py:10:1:10:9 | ControlFlowNode for Attribute | test.py:10:1:10:5 | ControlFlowNode for myobj | foo | -| test.py:13:1:13:21 | ControlFlowNode for getattr() | test.py:13:9:13:13 | ControlFlowNode for myobj | foo | +| test.py:10:1:10:9 | After Attribute | test.py:10:1:10:5 | myobj | foo | +| test.py:13:1:13:21 | After getattr() | test.py:13:9:13:13 | myobj | foo | diff --git a/python/ql/test/experimental/attrs/AttrWrites.expected b/python/ql/test/experimental/attrs/AttrWrites.expected index d1fc30b34515..8ecdda65808d 100644 --- a/python/ql/test/experimental/attrs/AttrWrites.expected +++ b/python/ql/test/experimental/attrs/AttrWrites.expected @@ -1,5 +1,5 @@ -| test.py:5:9:5:16 | ControlFlowNode for __init__ | test.py:4:1:4:20 | ControlFlowNode for ClassExpr | __init__ | test.py:5:5:5:28 | ControlFlowNode for FunctionExpr | -| test.py:6:9:6:16 | ControlFlowNode for Attribute | test.py:6:9:6:12 | ControlFlowNode for self | foo | test.py:6:20:6:22 | ControlFlowNode for foo | -| test.py:9:1:9:9 | ControlFlowNode for Attribute | test.py:0:0:0:0 | ModuleVariableNode in Module test for myobj | foo | test.py:9:13:9:17 | ControlFlowNode for StringLiteral | -| test.py:9:1:9:9 | ControlFlowNode for Attribute | test.py:9:1:9:5 | ControlFlowNode for myobj | foo | test.py:9:13:9:17 | ControlFlowNode for StringLiteral | -| test.py:12:1:12:25 | ControlFlowNode for setattr() | test.py:12:9:12:13 | ControlFlowNode for myobj | foo | test.py:12:23:12:24 | ControlFlowNode for IntegerLiteral | +| test.py:5:9:5:16 | __init__ | test.py:4:1:4:20 | After ClassExpr | __init__ | test.py:5:5:5:28 | FunctionExpr | +| test.py:6:9:6:16 | After Attribute | test.py:6:9:6:12 | self | foo | test.py:6:20:6:22 | foo | +| test.py:9:1:9:9 | After Attribute | test.py:0:0:0:0 | ModuleVariableNode in Module test for myobj | foo | test.py:9:13:9:17 | StringLiteral | +| test.py:9:1:9:9 | After Attribute | test.py:9:1:9:5 | myobj | foo | test.py:9:13:9:17 | StringLiteral | +| test.py:12:1:12:25 | After setattr() | test.py:12:9:12:13 | myobj | foo | test.py:12:23:12:24 | IntegerLiteral | diff --git a/python/ql/test/experimental/import-resolution-namespace-relative/test.ql b/python/ql/test/experimental/import-resolution-namespace-relative/test.ql index 4f5f09a527dd..7de2a81968b9 100644 --- a/python/ql/test/experimental/import-resolution-namespace-relative/test.ql +++ b/python/ql/test/experimental/import-resolution-namespace-relative/test.ql @@ -2,15 +2,16 @@ import python import semmle.python.dataflow.new.DataFlow import semmle.python.dataflow.new.TaintTracking import utils.test.InlineExpectationsTest +private import semmle.python.controlflow.internal.Cfg as Cfg private module TestConfig implements DataFlow::ConfigSig { predicate isSource(DataFlow::Node node) { - node.(DataFlow::CallCfgNode).getFunction().asCfgNode().(NameNode).getId() = "source" + node.(DataFlow::CallCfgNode).getFunction().asCfgNode().(Cfg::NameNode).getId() = "source" } predicate isSink(DataFlow::Node node) { exists(DataFlow::CallCfgNode call | - call.getFunction().asCfgNode().(NameNode).getId() = "sink" and + call.getFunction().asCfgNode().(Cfg::NameNode).getId() = "sink" and node = call.getArg(0) ) } diff --git a/python/ql/test/experimental/import-resolution/ModuleExport.expected b/python/ql/test/experimental/import-resolution/ModuleExport.expected index f67ae004011a..80605a523c0d 100644 --- a/python/ql/test/experimental/import-resolution/ModuleExport.expected +++ b/python/ql/test/experimental/import-resolution/ModuleExport.expected @@ -1,120 +1,120 @@ -| attr_clash.__init__ | __file__ | attr_clash/__init__.py:6:6:6:13 | ControlFlowNode for __file__ | -| attr_clash.__init__ | clashing_attr | attr_clash/__init__.py:4:1:4:13 | ControlFlowNode for clashing_attr | -| attr_clash.__init__ | enter | attr_clash/__init__.py:2:1:2:5 | ControlFlowNode for enter | -| attr_clash.__init__ | exit | attr_clash/__init__.py:6:1:6:4 | ControlFlowNode for exit | -| attr_clash.clashing_attr | __file__ | attr_clash/clashing_attr.py:4:6:4:13 | ControlFlowNode for __file__ | -| attr_clash.clashing_attr | enter | attr_clash/clashing_attr.py:2:1:2:5 | ControlFlowNode for enter | -| attr_clash.clashing_attr | exit | attr_clash/clashing_attr.py:4:1:4:4 | ControlFlowNode for exit | -| attr_clash.non_clashing_submodule | __file__ | attr_clash/non_clashing_submodule.py:4:6:4:13 | ControlFlowNode for __file__ | -| attr_clash.non_clashing_submodule | enter | attr_clash/non_clashing_submodule.py:2:1:2:5 | ControlFlowNode for enter | -| attr_clash.non_clashing_submodule | exit | attr_clash/non_clashing_submodule.py:4:1:4:4 | ControlFlowNode for exit | -| bar | __file__ | bar.py:6:6:6:13 | ControlFlowNode for __file__ | -| bar | bar_attr | bar.py:4:1:4:8 | ControlFlowNode for bar_attr | -| bar | enter | bar.py:2:1:2:5 | ControlFlowNode for enter | -| bar | exit | bar.py:6:1:6:4 | ControlFlowNode for exit | -| baz | __file__ | baz.py:6:6:6:13 | ControlFlowNode for __file__ | -| baz | baz_attr | baz.py:4:1:4:8 | ControlFlowNode for baz_attr | -| baz | enter | baz.py:2:1:2:5 | ControlFlowNode for enter | -| baz | exit | baz.py:6:1:6:4 | ControlFlowNode for exit | -| block_flow_check | SOURCE | block_flow_check.py:12:25:12:30 | ControlFlowNode for SOURCE | -| block_flow_check | __file__ | block_flow_check.py:14:6:14:13 | ControlFlowNode for __file__ | -| block_flow_check | check | block_flow_check.py:12:1:12:5 | ControlFlowNode for check | -| block_flow_check | enter | block_flow_check.py:2:1:2:5 | ControlFlowNode for enter | -| block_flow_check | exit | block_flow_check.py:14:1:14:4 | ControlFlowNode for exit | -| block_flow_check | globals | block_flow_check.py:12:33:12:39 | ControlFlowNode for globals | -| block_flow_check | object | block_flow_check.py:4:14:4:19 | ControlFlowNode for object | -| foo | __file__ | foo.py:14:6:14:13 | ControlFlowNode for __file__ | -| foo | __private_foo_attr | foo.py:8:1:8:18 | ControlFlowNode for __private_foo_attr | -| foo | bar_reexported | foo.py:11:8:11:10 | ControlFlowNode for ImportExpr | -| foo | bar_reexported | foo.py:12:34:12:47 | ControlFlowNode for bar_reexported | -| foo | check | foo.py:12:1:12:5 | ControlFlowNode for check | -| foo | enter | foo.py:2:1:2:5 | ControlFlowNode for enter | -| foo | exit | foo.py:14:1:14:4 | ControlFlowNode for exit | -| foo | foo_attr | foo.py:5:1:5:8 | ControlFlowNode for foo_attr | -| foo | globals | foo.py:12:71:12:77 | ControlFlowNode for globals | -| generous_export | Exception | generous_export.py:16:11:16:19 | ControlFlowNode for Exception | -| generous_export | SOURCE | generous_export.py:15:11:15:16 | ControlFlowNode for SOURCE | -| generous_export | SOURCE | generous_export.py:20:25:20:30 | ControlFlowNode for SOURCE | -| generous_export | __file__ | generous_export.py:22:6:22:13 | ControlFlowNode for __file__ | -| generous_export | check | generous_export.py:20:1:20:5 | ControlFlowNode for check | -| generous_export | enter | generous_export.py:2:1:2:5 | ControlFlowNode for enter | -| generous_export | eval | generous_export.py:10:4:10:7 | ControlFlowNode for eval | -| generous_export | exit | generous_export.py:22:1:22:4 | ControlFlowNode for exit | -| generous_export | globals | generous_export.py:20:33:20:39 | ControlFlowNode for globals | -| generous_export | object | generous_export.py:4:14:4:19 | ControlFlowNode for object | -| generous_export | print | generous_export.py:15:5:15:9 | ControlFlowNode for print | -| has_defined_all | __all__ | has_defined_all.py:7:1:7:7 | ControlFlowNode for __all__ | -| has_defined_all | __file__ | has_defined_all.py:9:6:9:13 | ControlFlowNode for __file__ | -| has_defined_all | all_defined_bar | has_defined_all.py:5:1:5:15 | ControlFlowNode for all_defined_bar | -| has_defined_all | all_defined_foo | has_defined_all.py:4:1:4:15 | ControlFlowNode for all_defined_foo | -| has_defined_all | enter | has_defined_all.py:2:1:2:5 | ControlFlowNode for enter | -| has_defined_all | exit | has_defined_all.py:9:1:9:4 | ControlFlowNode for exit | -| has_defined_all_copy | __all__ | has_defined_all_copy.py:9:1:9:7 | ControlFlowNode for __all__ | -| has_defined_all_copy | __file__ | has_defined_all_copy.py:11:6:11:13 | ControlFlowNode for __file__ | -| has_defined_all_copy | all_defined_bar_copy | has_defined_all_copy.py:7:1:7:20 | ControlFlowNode for all_defined_bar_copy | -| has_defined_all_copy | all_defined_foo_copy | has_defined_all_copy.py:6:1:6:20 | ControlFlowNode for all_defined_foo_copy | -| has_defined_all_copy | enter | has_defined_all_copy.py:4:1:4:5 | ControlFlowNode for enter | -| has_defined_all_copy | exit | has_defined_all_copy.py:11:1:11:4 | ControlFlowNode for exit | -| has_defined_all_indirection | __file__ | has_defined_all_indirection.py:6:6:6:13 | ControlFlowNode for __file__ | -| has_defined_all_indirection | all_defined_foo_copy | has_defined_all_copy.py:6:1:6:20 | ControlFlowNode for all_defined_foo_copy | -| has_defined_all_indirection | enter | has_defined_all_indirection.py:2:1:2:5 | ControlFlowNode for enter | -| has_defined_all_indirection | exit | has_defined_all_indirection.py:6:1:6:4 | ControlFlowNode for exit | -| if_then_else | __file__ | if_then_else.py:16:6:16:13 | ControlFlowNode for __file__ | -| if_then_else | enter | if_then_else.py:2:1:2:5 | ControlFlowNode for enter | -| if_then_else | eval | if_then_else.py:11:8:11:11 | ControlFlowNode for eval | -| if_then_else | exit | if_then_else.py:16:1:16:4 | ControlFlowNode for exit | -| if_then_else | if_then_else_defined | if_then_else.py:7:5:7:24 | ControlFlowNode for if_then_else_defined | -| if_then_else | if_then_else_defined | if_then_else.py:12:9:12:28 | ControlFlowNode for if_then_else_defined | -| if_then_else | if_then_else_defined | if_then_else.py:14:9:14:28 | ControlFlowNode for if_then_else_defined | -| if_then_else_refined | SOURCE | if_then_else_refined.py:11:11:11:16 | ControlFlowNode for SOURCE | -| if_then_else_refined | SOURCE | if_then_else_refined.py:13:11:13:16 | ControlFlowNode for SOURCE | -| if_then_else_refined | __file__ | if_then_else_refined.py:19:6:19:13 | ControlFlowNode for __file__ | -| if_then_else_refined | check | if_then_else_refined.py:17:1:17:5 | ControlFlowNode for check | -| if_then_else_refined | enter | if_then_else_refined.py:4:1:4:5 | ControlFlowNode for enter | -| if_then_else_refined | eval | if_then_else_refined.py:10:4:10:7 | ControlFlowNode for eval | -| if_then_else_refined | exit | if_then_else_refined.py:19:1:19:4 | ControlFlowNode for exit | -| if_then_else_refined | globals | if_then_else_refined.py:17:24:17:30 | ControlFlowNode for globals | -| if_then_else_refined | src | if_then_else_refined.py:17:19:17:21 | ControlFlowNode for src | -| package.__init__ | __file__ | package/__init__.py:7:6:7:13 | ControlFlowNode for __file__ | -| package.__init__ | attr_used_in_subpackage | package/__init__.py:4:1:4:23 | ControlFlowNode for attr_used_in_subpackage | -| package.__init__ | enter | package/__init__.py:2:1:2:5 | ControlFlowNode for enter | -| package.__init__ | exit | package/__init__.py:7:1:7:4 | ControlFlowNode for exit | -| package.__init__ | package_attr | package/__init__.py:5:1:5:12 | ControlFlowNode for package_attr | -| package.subpackage2.__init__ | __file__ | package/subpackage2/__init__.py:6:6:6:13 | ControlFlowNode for __file__ | -| package.subpackage2.__init__ | enter | package/subpackage2/__init__.py:2:1:2:5 | ControlFlowNode for enter | -| package.subpackage2.__init__ | exit | package/subpackage2/__init__.py:6:1:6:4 | ControlFlowNode for exit | -| package.subpackage2.__init__ | subpackage2_attr | package/subpackage2/__init__.py:4:1:4:16 | ControlFlowNode for subpackage2_attr | -| package.subpackage.__init__ | __file__ | package/subpackage/__init__.py:14:6:14:13 | ControlFlowNode for __file__ | -| package.subpackage.__init__ | check | package/subpackage/__init__.py:12:1:12:5 | ControlFlowNode for check | -| package.subpackage.__init__ | enter | package/subpackage/__init__.py:2:1:2:5 | ControlFlowNode for enter | -| package.subpackage.__init__ | exit | package/subpackage/__init__.py:14:1:14:4 | ControlFlowNode for exit | -| package.subpackage.__init__ | globals | package/subpackage/__init__.py:12:79:12:85 | ControlFlowNode for globals | -| package.subpackage.__init__ | imported_attr | package/subpackage/__init__.py:7:16:7:55 | ControlFlowNode for ImportMember | -| package.subpackage.__init__ | imported_attr | package/subpackage/__init__.py:8:24:8:36 | ControlFlowNode for imported_attr | -| package.subpackage.__init__ | irrelevant_attr | package/subpackage/__init__.py:11:24:11:38 | ControlFlowNode for ImportMember | -| package.subpackage.__init__ | irrelevant_attr | package/subpackage/__init__.py:11:24:11:38 | ControlFlowNode for irrelevant_attr | -| package.subpackage.__init__ | submodule | package/subpackage/__init__.py:12:35:12:43 | ControlFlowNode for submodule | -| package.subpackage.__init__ | subpackage_attr | package/subpackage/__init__.py:4:1:4:15 | ControlFlowNode for subpackage_attr | -| package.subpackage.submodule | __file__ | package/subpackage/submodule.py:7:6:7:13 | ControlFlowNode for __file__ | -| package.subpackage.submodule | enter | package/subpackage/submodule.py:2:1:2:5 | ControlFlowNode for enter | -| package.subpackage.submodule | exit | package/subpackage/submodule.py:7:1:7:4 | ControlFlowNode for exit | -| package.subpackage.submodule | irrelevant_attr | package/subpackage/submodule.py:5:1:5:15 | ControlFlowNode for irrelevant_attr | -| package.subpackage.submodule | submodule_attr | package/subpackage/submodule.py:4:1:4:14 | ControlFlowNode for submodule_attr | -| refined | SOURCE | refined.py:12:25:12:30 | ControlFlowNode for SOURCE | -| refined | __file__ | refined.py:14:6:14:13 | ControlFlowNode for __file__ | -| refined | check | refined.py:12:1:12:5 | ControlFlowNode for check | -| refined | enter | refined.py:2:1:2:5 | ControlFlowNode for enter | -| refined | exit | refined.py:14:1:14:4 | ControlFlowNode for exit | -| refined | globals | refined.py:12:33:12:39 | ControlFlowNode for globals | -| refined | object | refined.py:4:14:4:19 | ControlFlowNode for object | -| simplistic_reexport | __file__ | simplistic_reexport.py:19:6:19:13 | ControlFlowNode for __file__ | -| simplistic_reexport | bar_attr | simplistic_reexport.py:6:17:6:24 | ControlFlowNode for ImportMember | -| simplistic_reexport | bar_attr | simplistic_reexport.py:10:19:10:26 | ControlFlowNode for bar_attr | -| simplistic_reexport | baz_attr | baz.py:4:1:4:8 | ControlFlowNode for baz_attr | -| simplistic_reexport | baz_attr | simplistic_reexport.py:17:19:17:26 | ControlFlowNode for baz_attr | -| simplistic_reexport | check | simplistic_reexport.py:17:1:17:5 | ControlFlowNode for check | -| simplistic_reexport | enter | baz.py:2:1:2:5 | ControlFlowNode for enter | -| simplistic_reexport | enter | simplistic_reexport.py:4:1:4:5 | ControlFlowNode for enter | -| simplistic_reexport | exit | baz.py:6:1:6:4 | ControlFlowNode for exit | -| simplistic_reexport | exit | simplistic_reexport.py:19:1:19:4 | ControlFlowNode for exit | -| simplistic_reexport | globals | simplistic_reexport.py:17:44:17:50 | ControlFlowNode for globals | +| attr_clash.__init__ | __file__ | attr_clash/__init__.py:6:6:6:13 | __file__ | +| attr_clash.__init__ | clashing_attr | attr_clash/__init__.py:4:1:4:13 | clashing_attr | +| attr_clash.__init__ | enter | attr_clash/__init__.py:2:1:2:5 | enter | +| attr_clash.__init__ | exit | attr_clash/__init__.py:6:1:6:4 | exit | +| attr_clash.clashing_attr | __file__ | attr_clash/clashing_attr.py:4:6:4:13 | __file__ | +| attr_clash.clashing_attr | enter | attr_clash/clashing_attr.py:2:1:2:5 | enter | +| attr_clash.clashing_attr | exit | attr_clash/clashing_attr.py:4:1:4:4 | exit | +| attr_clash.non_clashing_submodule | __file__ | attr_clash/non_clashing_submodule.py:4:6:4:13 | __file__ | +| attr_clash.non_clashing_submodule | enter | attr_clash/non_clashing_submodule.py:2:1:2:5 | enter | +| attr_clash.non_clashing_submodule | exit | attr_clash/non_clashing_submodule.py:4:1:4:4 | exit | +| bar | __file__ | bar.py:6:6:6:13 | __file__ | +| bar | bar_attr | bar.py:4:1:4:8 | bar_attr | +| bar | enter | bar.py:2:1:2:5 | enter | +| bar | exit | bar.py:6:1:6:4 | exit | +| baz | __file__ | baz.py:6:6:6:13 | __file__ | +| baz | baz_attr | baz.py:4:1:4:8 | baz_attr | +| baz | enter | baz.py:2:1:2:5 | enter | +| baz | exit | baz.py:6:1:6:4 | exit | +| block_flow_check | SOURCE | block_flow_check.py:12:25:12:30 | SOURCE | +| block_flow_check | __file__ | block_flow_check.py:14:6:14:13 | __file__ | +| block_flow_check | check | block_flow_check.py:12:1:12:5 | check | +| block_flow_check | enter | block_flow_check.py:2:1:2:5 | enter | +| block_flow_check | exit | block_flow_check.py:14:1:14:4 | exit | +| block_flow_check | globals | block_flow_check.py:12:33:12:39 | globals | +| block_flow_check | object | block_flow_check.py:4:14:4:19 | object | +| foo | __file__ | foo.py:14:6:14:13 | __file__ | +| foo | __private_foo_attr | foo.py:8:1:8:18 | __private_foo_attr | +| foo | bar_reexported | foo.py:11:8:11:10 | ImportExpr | +| foo | bar_reexported | foo.py:12:34:12:47 | bar_reexported | +| foo | check | foo.py:12:1:12:5 | check | +| foo | enter | foo.py:2:1:2:5 | enter | +| foo | exit | foo.py:14:1:14:4 | exit | +| foo | foo_attr | foo.py:5:1:5:8 | foo_attr | +| foo | globals | foo.py:12:71:12:77 | globals | +| generous_export | Exception | generous_export.py:16:11:16:19 | Exception | +| generous_export | SOURCE | generous_export.py:15:11:15:16 | SOURCE | +| generous_export | SOURCE | generous_export.py:20:25:20:30 | SOURCE | +| generous_export | __file__ | generous_export.py:22:6:22:13 | __file__ | +| generous_export | check | generous_export.py:20:1:20:5 | check | +| generous_export | enter | generous_export.py:2:1:2:5 | enter | +| generous_export | eval | generous_export.py:10:4:10:7 | eval | +| generous_export | exit | generous_export.py:22:1:22:4 | exit | +| generous_export | globals | generous_export.py:20:33:20:39 | globals | +| generous_export | object | generous_export.py:4:14:4:19 | object | +| generous_export | print | generous_export.py:15:5:15:9 | print | +| has_defined_all | __all__ | has_defined_all.py:7:1:7:7 | __all__ | +| has_defined_all | __file__ | has_defined_all.py:9:6:9:13 | __file__ | +| has_defined_all | all_defined_bar | has_defined_all.py:5:1:5:15 | all_defined_bar | +| has_defined_all | all_defined_foo | has_defined_all.py:4:1:4:15 | all_defined_foo | +| has_defined_all | enter | has_defined_all.py:2:1:2:5 | enter | +| has_defined_all | exit | has_defined_all.py:9:1:9:4 | exit | +| has_defined_all_copy | __all__ | has_defined_all_copy.py:9:1:9:7 | __all__ | +| has_defined_all_copy | __file__ | has_defined_all_copy.py:11:6:11:13 | __file__ | +| has_defined_all_copy | all_defined_bar_copy | has_defined_all_copy.py:7:1:7:20 | all_defined_bar_copy | +| has_defined_all_copy | all_defined_foo_copy | has_defined_all_copy.py:6:1:6:20 | all_defined_foo_copy | +| has_defined_all_copy | enter | has_defined_all_copy.py:4:1:4:5 | enter | +| has_defined_all_copy | exit | has_defined_all_copy.py:11:1:11:4 | exit | +| has_defined_all_indirection | __file__ | has_defined_all_indirection.py:6:6:6:13 | __file__ | +| has_defined_all_indirection | all_defined_foo_copy | has_defined_all_copy.py:6:1:6:20 | all_defined_foo_copy | +| has_defined_all_indirection | enter | has_defined_all_indirection.py:2:1:2:5 | enter | +| has_defined_all_indirection | exit | has_defined_all_indirection.py:6:1:6:4 | exit | +| if_then_else | __file__ | if_then_else.py:16:6:16:13 | __file__ | +| if_then_else | enter | if_then_else.py:2:1:2:5 | enter | +| if_then_else | eval | if_then_else.py:11:8:11:11 | eval | +| if_then_else | exit | if_then_else.py:16:1:16:4 | exit | +| if_then_else | if_then_else_defined | if_then_else.py:7:5:7:24 | if_then_else_defined | +| if_then_else | if_then_else_defined | if_then_else.py:12:9:12:28 | if_then_else_defined | +| if_then_else | if_then_else_defined | if_then_else.py:14:9:14:28 | if_then_else_defined | +| if_then_else_refined | SOURCE | if_then_else_refined.py:11:11:11:16 | SOURCE | +| if_then_else_refined | SOURCE | if_then_else_refined.py:13:11:13:16 | SOURCE | +| if_then_else_refined | __file__ | if_then_else_refined.py:19:6:19:13 | __file__ | +| if_then_else_refined | check | if_then_else_refined.py:17:1:17:5 | check | +| if_then_else_refined | enter | if_then_else_refined.py:4:1:4:5 | enter | +| if_then_else_refined | eval | if_then_else_refined.py:10:4:10:7 | eval | +| if_then_else_refined | exit | if_then_else_refined.py:19:1:19:4 | exit | +| if_then_else_refined | globals | if_then_else_refined.py:17:24:17:30 | globals | +| if_then_else_refined | src | if_then_else_refined.py:17:19:17:21 | src | +| package.__init__ | __file__ | package/__init__.py:7:6:7:13 | __file__ | +| package.__init__ | attr_used_in_subpackage | package/__init__.py:4:1:4:23 | attr_used_in_subpackage | +| package.__init__ | enter | package/__init__.py:2:1:2:5 | enter | +| package.__init__ | exit | package/__init__.py:7:1:7:4 | exit | +| package.__init__ | package_attr | package/__init__.py:5:1:5:12 | package_attr | +| package.subpackage2.__init__ | __file__ | package/subpackage2/__init__.py:6:6:6:13 | __file__ | +| package.subpackage2.__init__ | enter | package/subpackage2/__init__.py:2:1:2:5 | enter | +| package.subpackage2.__init__ | exit | package/subpackage2/__init__.py:6:1:6:4 | exit | +| package.subpackage2.__init__ | subpackage2_attr | package/subpackage2/__init__.py:4:1:4:16 | subpackage2_attr | +| package.subpackage.__init__ | __file__ | package/subpackage/__init__.py:14:6:14:13 | __file__ | +| package.subpackage.__init__ | check | package/subpackage/__init__.py:12:1:12:5 | check | +| package.subpackage.__init__ | enter | package/subpackage/__init__.py:2:1:2:5 | enter | +| package.subpackage.__init__ | exit | package/subpackage/__init__.py:14:1:14:4 | exit | +| package.subpackage.__init__ | globals | package/subpackage/__init__.py:12:79:12:85 | globals | +| package.subpackage.__init__ | imported_attr | package/subpackage/__init__.py:7:16:7:55 | After ImportMember | +| package.subpackage.__init__ | imported_attr | package/subpackage/__init__.py:8:24:8:36 | imported_attr | +| package.subpackage.__init__ | irrelevant_attr | package/subpackage/__init__.py:11:24:11:38 | After ImportMember | +| package.subpackage.__init__ | irrelevant_attr | package/subpackage/__init__.py:11:24:11:38 | irrelevant_attr | +| package.subpackage.__init__ | submodule | package/subpackage/__init__.py:12:35:12:43 | submodule | +| package.subpackage.__init__ | subpackage_attr | package/subpackage/__init__.py:4:1:4:15 | subpackage_attr | +| package.subpackage.submodule | __file__ | package/subpackage/submodule.py:7:6:7:13 | __file__ | +| package.subpackage.submodule | enter | package/subpackage/submodule.py:2:1:2:5 | enter | +| package.subpackage.submodule | exit | package/subpackage/submodule.py:7:1:7:4 | exit | +| package.subpackage.submodule | irrelevant_attr | package/subpackage/submodule.py:5:1:5:15 | irrelevant_attr | +| package.subpackage.submodule | submodule_attr | package/subpackage/submodule.py:4:1:4:14 | submodule_attr | +| refined | SOURCE | refined.py:12:25:12:30 | SOURCE | +| refined | __file__ | refined.py:14:6:14:13 | __file__ | +| refined | check | refined.py:12:1:12:5 | check | +| refined | enter | refined.py:2:1:2:5 | enter | +| refined | exit | refined.py:14:1:14:4 | exit | +| refined | globals | refined.py:12:33:12:39 | globals | +| refined | object | refined.py:4:14:4:19 | object | +| simplistic_reexport | __file__ | simplistic_reexport.py:19:6:19:13 | __file__ | +| simplistic_reexport | bar_attr | simplistic_reexport.py:6:17:6:24 | After ImportMember | +| simplistic_reexport | bar_attr | simplistic_reexport.py:10:19:10:26 | bar_attr | +| simplistic_reexport | baz_attr | baz.py:4:1:4:8 | baz_attr | +| simplistic_reexport | baz_attr | simplistic_reexport.py:17:19:17:26 | baz_attr | +| simplistic_reexport | check | simplistic_reexport.py:17:1:17:5 | check | +| simplistic_reexport | enter | baz.py:2:1:2:5 | enter | +| simplistic_reexport | enter | simplistic_reexport.py:4:1:4:5 | enter | +| simplistic_reexport | exit | baz.py:6:1:6:4 | exit | +| simplistic_reexport | exit | simplistic_reexport.py:19:1:19:4 | exit | +| simplistic_reexport | globals | simplistic_reexport.py:17:44:17:50 | globals | diff --git a/python/ql/test/experimental/import-resolution/importflow.ql b/python/ql/test/experimental/import-resolution/importflow.ql index 15a4498aa113..4fbc782abf5f 100644 --- a/python/ql/test/experimental/import-resolution/importflow.ql +++ b/python/ql/test/experimental/import-resolution/importflow.ql @@ -3,6 +3,7 @@ import semmle.python.dataflow.new.DataFlow import semmle.python.ApiGraphs import utils.test.InlineExpectationsTest import semmle.python.dataflow.new.internal.ImportResolution +private import semmle.python.controlflow.internal.Cfg as Cfg /** A string that appears on the right hand side of an assignment. */ private class SourceString extends DataFlow::Node { @@ -45,7 +46,7 @@ private class VersionGuardedNode extends DataFlow::Node { VersionGuardedNode() { version in [2, 3] and - exists(If parent, CompareNode c, ControlFlowNode litCfg | + exists(If parent, Cfg::CompareNode c, Cfg::ControlFlowNode litCfg | parent.getBody().contains(this.asExpr()) and litCfg.getNode() = any(IntegerLiteral lit | lit.getValue() = version) | diff --git a/python/ql/test/experimental/library-tests/CallGraph-type-annotations/InlineCallGraphTest.expected b/python/ql/test/experimental/library-tests/CallGraph-type-annotations/InlineCallGraphTest.expected index a08ad78be2e1..064abf1b1c49 100644 --- a/python/ql/test/experimental/library-tests/CallGraph-type-annotations/InlineCallGraphTest.expected +++ b/python/ql/test/experimental/library-tests/CallGraph-type-annotations/InlineCallGraphTest.expected @@ -1,6 +1,7 @@ testFailures +| type_annotations.py:6:16:6:32 | Comment # $ tt=Foo.method | Missing result: tt=Foo.method | +| type_annotations.py:16:16:16:32 | Comment # $ tt=Foo.method | Missing result: tt=Foo.method | debug_callableNotUnique pointsTo_found_typeTracker_notFound typeTracker_found_pointsTo_notFound -| type_annotations.py:6:5:6:14 | ControlFlowNode for Attribute() | Foo.method | -| type_annotations.py:16:5:16:14 | ControlFlowNode for Attribute() | Foo.method | +| type_annotations.py:29:5:29:14 | Attribute() | Foo.method | diff --git a/python/ql/test/experimental/library-tests/CallGraph-type-annotations/type_annotations.py b/python/ql/test/experimental/library-tests/CallGraph-type-annotations/type_annotations.py index a71d3103456a..7191c1edd5b7 100644 --- a/python/ql/test/experimental/library-tests/CallGraph-type-annotations/type_annotations.py +++ b/python/ql/test/experimental/library-tests/CallGraph-type-annotations/type_annotations.py @@ -26,7 +26,7 @@ def test_variable_annotation(): x = eval("Foo()") x : Foo # Currently fails because there is no flow from the class definition to the type annotation. - x.method() # $ MISSING: tt=Foo.method + x.method() # $ tt=Foo.method def test_no_variable_annotation(): x = eval("Foo()") diff --git a/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.expected b/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.expected index 1cd62c6de347..cc5800030fae 100644 --- a/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.expected +++ b/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.expected @@ -1,51 +1,52 @@ testFailures debug_callableNotUnique pointsTo_found_typeTracker_notFound -| code/class_super.py:50:1:50:6 | ControlFlowNode for Attribute() | outside_def | -| code/conditional_in_argument.py:18:5:18:11 | ControlFlowNode for Attribute() | X.bar | -| code/func_defined_outside_class.py:21:1:21:11 | ControlFlowNode for Attribute() | A.foo | -| code/func_defined_outside_class.py:22:1:22:15 | ControlFlowNode for Attribute() | outside | -| code/func_defined_outside_class.py:24:1:24:14 | ControlFlowNode for Attribute() | outside_sm | -| code/func_defined_outside_class.py:25:1:25:14 | ControlFlowNode for Attribute() | outside_cm | -| code/func_defined_outside_class.py:38:11:38:21 | ControlFlowNode for _gen() | B._gen | -| code/func_defined_outside_class.py:39:11:39:21 | ControlFlowNode for _gen() | B._gen | -| code/func_defined_outside_class.py:42:1:42:7 | ControlFlowNode for Attribute() | B._gen.func | -| code/func_defined_outside_class.py:43:1:43:7 | ControlFlowNode for Attribute() | B._gen.func | -| code/funky_regression.py:15:9:15:17 | ControlFlowNode for Attribute() | Wat.f2 | -| code/type_tracking_limitation.py:8:1:8:3 | ControlFlowNode for x() | my_func | +| code/class_attr_assign.py:10:9:10:27 | Attribute() | my_func | +| code/class_attr_assign.py:11:9:11:25 | Attribute() | my_func | +| code/class_attr_assign.py:26:9:26:25 | Attribute() | DummyObject.method | +| code/class_super.py:50:1:50:6 | Attribute() | outside_def | +| code/func_defined_outside_class.py:21:1:21:11 | Attribute() | A.foo | +| code/func_defined_outside_class.py:22:1:22:15 | Attribute() | outside | +| code/func_defined_outside_class.py:24:1:24:14 | Attribute() | outside_sm | +| code/func_defined_outside_class.py:25:1:25:14 | Attribute() | outside_cm | +| code/func_defined_outside_class.py:38:11:38:21 | _gen() | B._gen | +| code/func_defined_outside_class.py:39:11:39:21 | _gen() | B._gen | +| code/func_defined_outside_class.py:42:1:42:7 | Attribute() | B._gen.func | +| code/func_defined_outside_class.py:43:1:43:7 | Attribute() | B._gen.func | +| code/type_tracking_limitation.py:8:1:8:3 | x() | my_func | typeTracker_found_pointsTo_notFound -| code/callable_as_argument.py:29:5:29:12 | ControlFlowNode for Attribute() | test_class.InsideTestFunc.sm | -| code/class_construction.py:44:9:44:26 | ControlFlowNode for Attribute() | WithNew.some_method | -| code/class_construction.py:61:9:61:26 | ControlFlowNode for Attribute() | WithNew.some_method | -| code/class_construction.py:75:9:75:27 | ControlFlowNode for Attribute() | ExtraCallToInit.__init__ | -| code/class_special_methods.py:22:9:22:16 | ControlFlowNode for self() | Base.__call__ | -| code/class_special_methods.py:22:9:22:16 | ControlFlowNode for self() | Sub.__call__ | -| code/class_special_methods.py:33:1:33:5 | ControlFlowNode for b() | Base.__call__ | -| code/class_special_methods.py:59:1:59:7 | ControlFlowNode for sub() | Sub.__call__ | -| code/class_super.py:43:9:43:21 | ControlFlowNode for Attribute() | A.bar | -| code/class_super.py:44:9:44:27 | ControlFlowNode for Attribute() | A.bar | -| code/class_super.py:63:1:63:18 | ControlFlowNode for Attribute() | A.foo | -| code/class_super.py:78:9:78:28 | ControlFlowNode for Attribute() | A.foo | -| code/class_super.py:81:1:81:12 | ControlFlowNode for Attribute() | C.foo_on_A | -| code/class_super.py:92:9:92:21 | ControlFlowNode for Attribute() | X.foo | -| code/class_super.py:97:9:97:21 | ControlFlowNode for Attribute() | X.foo | -| code/class_super.py:97:9:97:21 | ControlFlowNode for Attribute() | Y.foo | -| code/class_super.py:101:1:101:7 | ControlFlowNode for Attribute() | Z.foo | -| code/class_super.py:108:1:108:8 | ControlFlowNode for Attribute() | Z.foo | -| code/def_in_function.py:22:5:22:11 | ControlFlowNode for Attribute() | test.A.foo | -| code/func_ref_in_content.py:32:1:32:4 | ControlFlowNode for f4() | func | -| code/func_ref_in_content.py:46:1:46:4 | ControlFlowNode for f5() | func | -| code/func_ref_in_content.py:48:1:48:15 | ControlFlowNode for Subscript() | func2 | -| code/func_ref_in_content.py:50:1:50:19 | ControlFlowNode for Subscript() | func2 | -| code/isinstance.py:9:13:9:22 | ControlFlowNode for Attribute() | A.foo | -| code/isinstance.py:9:13:9:22 | ControlFlowNode for Attribute() | ASub.foo | -| code/isinstance.py:14:13:14:22 | ControlFlowNode for Attribute() | A.foo | -| code/isinstance.py:14:13:14:22 | ControlFlowNode for Attribute() | ASub.foo | -| code/isinstance.py:14:13:14:22 | ControlFlowNode for Attribute() | B.foo | -| code/isinstance.py:17:13:17:22 | ControlFlowNode for Attribute() | A.foo | -| code/nested_class.py:83:9:83:16 | ControlFlowNode for Attribute() | X.class_def_in_func.Y.meth | -| code/self_passing.py:16:9:16:18 | ControlFlowNode for Attribute() | A.foo | -| code/self_passing.py:16:9:16:18 | ControlFlowNode for Attribute() | B.foo | -| code/self_passing.py:67:9:67:16 | ControlFlowNode for Attribute() | Y.cm | -| code/self_passing.py:69:9:69:17 | ControlFlowNode for Attribute() | X.foo | -| code/underscore_prefix_func_name.py:14:5:14:19 | ControlFlowNode for some_function() | some_function | +| code/callable_as_argument.py:29:5:29:12 | Attribute() | test_class.InsideTestFunc.sm | +| code/class_construction.py:44:9:44:26 | Attribute() | WithNew.some_method | +| code/class_construction.py:61:9:61:26 | Attribute() | WithNew.some_method | +| code/class_construction.py:75:9:75:27 | Attribute() | ExtraCallToInit.__init__ | +| code/class_special_methods.py:22:9:22:16 | self() | Base.__call__ | +| code/class_special_methods.py:22:9:22:16 | self() | Sub.__call__ | +| code/class_special_methods.py:33:1:33:5 | b() | Base.__call__ | +| code/class_special_methods.py:59:1:59:7 | sub() | Sub.__call__ | +| code/class_super.py:43:9:43:21 | Attribute() | A.bar | +| code/class_super.py:44:9:44:27 | Attribute() | A.bar | +| code/class_super.py:63:1:63:18 | Attribute() | A.foo | +| code/class_super.py:78:9:78:28 | Attribute() | A.foo | +| code/class_super.py:81:1:81:12 | Attribute() | C.foo_on_A | +| code/class_super.py:92:9:92:21 | Attribute() | X.foo | +| code/class_super.py:97:9:97:21 | Attribute() | X.foo | +| code/class_super.py:97:9:97:21 | Attribute() | Y.foo | +| code/class_super.py:101:1:101:7 | Attribute() | Z.foo | +| code/class_super.py:108:1:108:8 | Attribute() | Z.foo | +| code/def_in_function.py:22:5:22:11 | Attribute() | test.A.foo | +| code/func_ref_in_content.py:32:1:32:4 | f4() | func | +| code/func_ref_in_content.py:46:1:46:4 | f5() | func | +| code/func_ref_in_content.py:48:1:48:15 | Subscript() | func2 | +| code/func_ref_in_content.py:50:1:50:19 | Subscript() | func2 | +| code/isinstance.py:9:13:9:22 | Attribute() | A.foo | +| code/isinstance.py:9:13:9:22 | Attribute() | ASub.foo | +| code/isinstance.py:14:13:14:22 | Attribute() | A.foo | +| code/isinstance.py:14:13:14:22 | Attribute() | ASub.foo | +| code/isinstance.py:14:13:14:22 | Attribute() | B.foo | +| code/isinstance.py:17:13:17:22 | Attribute() | A.foo | +| code/nested_class.py:83:9:83:16 | Attribute() | X.class_def_in_func.Y.meth | +| code/self_passing.py:16:9:16:18 | Attribute() | A.foo | +| code/self_passing.py:16:9:16:18 | Attribute() | B.foo | +| code/self_passing.py:67:9:67:16 | Attribute() | Y.cm | +| code/self_passing.py:69:9:69:17 | Attribute() | X.foo | +| code/underscore_prefix_func_name.py:14:5:14:19 | some_function() | some_function | diff --git a/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.ql b/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.ql index 5cdbd9e6a4e5..7217c8436085 100644 --- a/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.ql +++ b/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.ql @@ -1,38 +1,43 @@ import python import utils.test.InlineExpectationsTest private import semmle.python.dataflow.new.internal.DataFlowDispatch as TT +private import semmle.python.controlflow.internal.Cfg as Cfg private import LegacyPointsTo /** Holds when `call` is resolved to `callable` using points-to based call-graph. */ -predicate pointsToCallEdge(CallNode call, Function callable) { +predicate pointsToCallEdge(Call call, Function callable) { exists(call.getLocation().getFile().getRelativePath()) and exists(callable.getLocation().getFile().getRelativePath()) and // I did try using viableCallable from `DataFlowDispatchPointsTo` (from temporary copy // of `dataflow.new.internal` that still uses points-to) instead of direct // `getACall()` on a Value, but it only added results for `__init__` methods, not for // anything else. - exists(PythonFunctionValue funcValue | + exists(PythonFunctionValue funcValue, CallNode legacyCall | funcValue.getScope() = callable and - call = funcValue.getACall() + legacyCall = funcValue.getACall() and + legacyCall.getNode() = call ) } /** Holds when `call` is resolved to `callable` using type-tracking based call-graph. */ -predicate typeTrackerCallEdge(CallNode call, Function callable) { +predicate typeTrackerCallEdge(Call call, Function callable) { exists(call.getLocation().getFile().getRelativePath()) and exists(callable.getLocation().getFile().getRelativePath()) and exists(TT::DataFlowCallable dfCallable, TT::DataFlowCall dfCall | dfCallable.getScope() = callable and - dfCall.getNode() = call and + dfCall.getNode().getNode() = call and dfCallable = TT::viableCallable(dfCall) ) } /** Holds if the call edge is from a class call. */ -predicate typeTrackerClassCall(CallNode call, Function callable) { +predicate typeTrackerClassCall(Call call, Function callable) { exists(call.getLocation().getFile().getRelativePath()) and exists(callable.getLocation().getFile().getRelativePath()) and - TT::resolveCall(call, callable, any(TT::TCallType t | t instanceof TT::CallTypeClass)) + exists(Cfg::CallNode cfgCall | + cfgCall.getNode() = call and + TT::resolveCall(cfgCall, callable, any(TT::TCallType t | t instanceof TT::CallTypeClass)) + ) } module CallGraphTest implements TestSig { @@ -40,7 +45,7 @@ module CallGraphTest implements TestSig { predicate hasActualResult(Location location, string element, string tag, string value) { exists(location.getFile().getRelativePath()) and - exists(CallNode call, Function target | + exists(Call call, Function target | tag = "tt" and typeTrackerCallEdge(call, target) or @@ -57,7 +62,7 @@ module CallGraphTest implements TestSig { import MakeTest bindingset[call, target] -string getCallEdgeValue(CallNode call, Function target) { +string getCallEdgeValue(Call call, Function target) { if call.getLocation().getFile() = target.getLocation().getFile() then result = betterQualName(target) else @@ -100,7 +105,7 @@ query predicate debug_callableNotUnique(Function callable, string message) { "' is not unique within its file. Please fix." } -query predicate pointsTo_found_typeTracker_notFound(CallNode call, string qualname) { +query predicate pointsTo_found_typeTracker_notFound(Call call, string qualname) { exists(Function target | pointsToCallEdge(call, target) and not typeTrackerCallEdge(call, target) and @@ -115,7 +120,7 @@ query predicate pointsTo_found_typeTracker_notFound(CallNode call, string qualna ) } -query predicate typeTracker_found_pointsTo_notFound(CallNode call, string qualname) { +query predicate typeTracker_found_pointsTo_notFound(Call call, string qualname) { exists(Function target | not pointsToCallEdge(call, target) and typeTrackerCallEdge(call, target) and diff --git a/python/ql/test/experimental/library-tests/CallGraph/code/conditional_in_argument.py b/python/ql/test/experimental/library-tests/CallGraph/code/conditional_in_argument.py index 885393fae902..cc147fe71d49 100644 --- a/python/ql/test/experimental/library-tests/CallGraph/code/conditional_in_argument.py +++ b/python/ql/test/experimental/library-tests/CallGraph/code/conditional_in_argument.py @@ -15,7 +15,7 @@ def func(cond=True): # the conditional in the argument makes us stop tracking the class instance :| x.foo(1 if cond else 0) # $ pt,tt=X.foo - x.bar() # $ pt=X.bar MISSING: tt=X.bar + x.bar() # $ pt=X.bar tt=X.bar func() # $ pt,tt=func diff --git a/python/ql/test/experimental/library-tests/CallGraph/code/funky_regression.py b/python/ql/test/experimental/library-tests/CallGraph/code/funky_regression.py index bb87bfb47e9c..ceff7fd0d85d 100644 --- a/python/ql/test/experimental/library-tests/CallGraph/code/funky_regression.py +++ b/python/ql/test/experimental/library-tests/CallGraph/code/funky_regression.py @@ -12,7 +12,7 @@ def func(self, foo): except Exception as e: raise e - self.f2() # $ pt=Wat.f2 MISSING: tt=Wat.f2 + self.f2() # $ pt=Wat.f2 tt=Wat.f2 # ============================================================================== diff --git a/python/ql/test/experimental/meta/InlineTaintTest.qll b/python/ql/test/experimental/meta/InlineTaintTest.qll index 525775d5106c..5c20a9913beb 100644 --- a/python/ql/test/experimental/meta/InlineTaintTest.qll +++ b/python/ql/test/experimental/meta/InlineTaintTest.qll @@ -10,6 +10,7 @@ */ import python +private import semmle.python.controlflow.internal.Cfg as Cfg import semmle.python.dataflow.new.DataFlow import semmle.python.dataflow.new.TaintTracking import semmle.python.dataflow.new.RemoteFlowSources @@ -19,14 +20,14 @@ private import semmle.python.Concepts DataFlow::Node shouldBeTainted() { exists(DataFlow::CallCfgNode call | - call.getFunction().asCfgNode().(NameNode).getId() = "ensure_tainted" and + call.getFunction().asCfgNode().(Cfg::NameNode).getId() = "ensure_tainted" and result in [call.getArg(_), call.getArgByName(_)] ) } DataFlow::Node shouldNotBeTainted() { exists(DataFlow::CallCfgNode call | - call.getFunction().asCfgNode().(NameNode).getId() = "ensure_not_tainted" and + call.getFunction().asCfgNode().(Cfg::NameNode).getId() = "ensure_not_tainted" and result in [call.getArg(_), call.getArgByName(_)] ) } @@ -36,13 +37,13 @@ DataFlow::Node shouldNotBeTainted() { module Conf { module TestTaintTrackingConfig implements DataFlow::ConfigSig { predicate isSource(DataFlow::Node source) { - source.asCfgNode().(NameNode).getId() in [ + source.asCfgNode().(Cfg::NameNode).getId() in [ "TAINTED_STRING", "TAINTED_BYTES", "TAINTED_LIST", "TAINTED_DICT" ] or // User defined sources - exists(CallNode call | - call.getFunction().(NameNode).getId() = "taint" and + exists(Cfg::CallNode call | + call.getFunction().(Cfg::NameNode).getId() = "taint" and source.(DataFlow::CfgNode).getNode() = call.getAnArg() ) or diff --git a/python/ql/test/experimental/query-tests/Security/CWE-022-TarSlip/TarSlip.expected b/python/ql/test/experimental/query-tests/Security/CWE-022-TarSlip/TarSlip.expected index 6de2b27bfa76..84c0ec31cbb5 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-022-TarSlip/TarSlip.expected +++ b/python/ql/test/experimental/query-tests/Security/CWE-022-TarSlip/TarSlip.expected @@ -1,255 +1,235 @@ edges -| TarSlipImprov.py:15:1:15:3 | ControlFlowNode for tar | TarSlipImprov.py:17:5:17:10 | ControlFlowNode for member | provenance | | -| TarSlipImprov.py:15:7:15:39 | ControlFlowNode for Attribute() | TarSlipImprov.py:15:1:15:3 | ControlFlowNode for tar | provenance | | -| TarSlipImprov.py:17:5:17:10 | ControlFlowNode for member | TarSlipImprov.py:20:19:20:24 | ControlFlowNode for member | provenance | | -| TarSlipImprov.py:20:5:20:10 | [post] ControlFlowNode for result | TarSlipImprov.py:22:35:22:40 | ControlFlowNode for result | provenance | | -| TarSlipImprov.py:20:5:20:10 | [post] ControlFlowNode for result [List element] | TarSlipImprov.py:22:35:22:40 | ControlFlowNode for result | provenance | | -| TarSlipImprov.py:20:19:20:24 | ControlFlowNode for member | TarSlipImprov.py:20:5:20:10 | [post] ControlFlowNode for result | provenance | list.append | -| TarSlipImprov.py:20:19:20:24 | ControlFlowNode for member | TarSlipImprov.py:20:5:20:10 | [post] ControlFlowNode for result [List element] | provenance | list.append | -| TarSlipImprov.py:26:21:26:27 | ControlFlowNode for tarfile | TarSlipImprov.py:28:9:28:14 | ControlFlowNode for member | provenance | | -| TarSlipImprov.py:28:9:28:14 | ControlFlowNode for member | TarSlipImprov.py:35:23:35:28 | ControlFlowNode for member | provenance | | -| TarSlipImprov.py:35:9:35:14 | [post] ControlFlowNode for result | TarSlipImprov.py:36:12:36:17 | ControlFlowNode for result | provenance | | -| TarSlipImprov.py:35:9:35:14 | [post] ControlFlowNode for result [List element] | TarSlipImprov.py:36:12:36:17 | ControlFlowNode for result [List element] | provenance | | -| TarSlipImprov.py:35:23:35:28 | ControlFlowNode for member | TarSlipImprov.py:35:9:35:14 | [post] ControlFlowNode for result | provenance | list.append | -| TarSlipImprov.py:35:23:35:28 | ControlFlowNode for member | TarSlipImprov.py:35:9:35:14 | [post] ControlFlowNode for result [List element] | provenance | list.append | -| TarSlipImprov.py:38:1:38:3 | ControlFlowNode for tar | TarSlipImprov.py:39:65:39:67 | ControlFlowNode for tar | provenance | | -| TarSlipImprov.py:38:7:38:39 | ControlFlowNode for Attribute() | TarSlipImprov.py:38:1:38:3 | ControlFlowNode for tar | provenance | | -| TarSlipImprov.py:39:65:39:67 | ControlFlowNode for tar | TarSlipImprov.py:26:21:26:27 | ControlFlowNode for tarfile | provenance | | -| TarSlipImprov.py:39:65:39:67 | ControlFlowNode for tar | TarSlipImprov.py:39:49:39:68 | ControlFlowNode for members_filter1() | provenance | list.append | -| TarSlipImprov.py:43:6:43:38 | ControlFlowNode for Attribute() | TarSlipImprov.py:43:43:43:45 | ControlFlowNode for tar | provenance | | -| TarSlipImprov.py:43:43:43:45 | ControlFlowNode for tar | TarSlipImprov.py:44:9:44:13 | ControlFlowNode for entry | provenance | | -| TarSlipImprov.py:44:9:44:13 | ControlFlowNode for entry | TarSlipImprov.py:47:21:47:25 | ControlFlowNode for entry | provenance | | -| TarSlipImprov.py:54:6:54:38 | ControlFlowNode for Attribute() | TarSlipImprov.py:54:43:54:45 | ControlFlowNode for tar | provenance | | -| TarSlipImprov.py:54:43:54:45 | ControlFlowNode for tar | TarSlipImprov.py:56:9:56:13 | ControlFlowNode for entry | provenance | | -| TarSlipImprov.py:56:9:56:13 | ControlFlowNode for entry | TarSlipImprov.py:58:21:58:25 | ControlFlowNode for entry | provenance | | -| TarSlipImprov.py:88:6:88:43 | ControlFlowNode for Attribute() | TarSlipImprov.py:88:48:88:50 | ControlFlowNode for tar | provenance | | -| TarSlipImprov.py:88:48:88:50 | ControlFlowNode for tar | TarSlipImprov.py:91:5:91:7 | ControlFlowNode for tar | provenance | | -| TarSlipImprov.py:111:1:111:3 | ControlFlowNode for tar | TarSlipImprov.py:115:9:115:11 | ControlFlowNode for tar | provenance | | -| TarSlipImprov.py:111:7:111:39 | ControlFlowNode for Attribute() | TarSlipImprov.py:111:1:111:3 | ControlFlowNode for tar | provenance | | -| TarSlipImprov.py:123:6:123:29 | ControlFlowNode for Attribute() | TarSlipImprov.py:123:34:123:36 | ControlFlowNode for tar | provenance | | -| TarSlipImprov.py:123:34:123:36 | ControlFlowNode for tar | TarSlipImprov.py:124:9:124:13 | ControlFlowNode for entry | provenance | | -| TarSlipImprov.py:124:9:124:13 | ControlFlowNode for entry | TarSlipImprov.py:125:36:125:40 | ControlFlowNode for entry | provenance | | -| TarSlipImprov.py:129:6:129:26 | ControlFlowNode for Attribute() | TarSlipImprov.py:129:31:129:33 | ControlFlowNode for tar | provenance | | -| TarSlipImprov.py:129:31:129:33 | ControlFlowNode for tar | TarSlipImprov.py:130:5:130:7 | ControlFlowNode for tar | provenance | | -| TarSlipImprov.py:133:1:133:3 | ControlFlowNode for tar | TarSlipImprov.py:134:1:134:3 | ControlFlowNode for tar | provenance | | -| TarSlipImprov.py:133:7:133:39 | ControlFlowNode for Attribute() | TarSlipImprov.py:133:1:133:3 | ControlFlowNode for tar | provenance | | -| TarSlipImprov.py:141:6:141:29 | ControlFlowNode for Attribute() | TarSlipImprov.py:141:34:141:36 | ControlFlowNode for tar | provenance | | -| TarSlipImprov.py:141:34:141:36 | ControlFlowNode for tar | TarSlipImprov.py:142:9:142:13 | ControlFlowNode for entry | provenance | | -| TarSlipImprov.py:142:9:142:13 | ControlFlowNode for entry | TarSlipImprov.py:143:36:143:40 | ControlFlowNode for entry | provenance | | -| TarSlipImprov.py:151:14:151:50 | ControlFlowNode for closing() | TarSlipImprov.py:151:55:151:56 | ControlFlowNode for tf | provenance | | -| TarSlipImprov.py:151:22:151:49 | ControlFlowNode for Attribute() | TarSlipImprov.py:151:14:151:50 | ControlFlowNode for closing() | provenance | Config | -| TarSlipImprov.py:151:55:151:56 | ControlFlowNode for tf | TarSlipImprov.py:152:19:152:20 | ControlFlowNode for tf | provenance | | -| TarSlipImprov.py:152:13:152:20 | ControlFlowNode for Yield [List element] | TarSlipImprov.py:157:18:157:40 | ControlFlowNode for py2_tarxz() [List element] | provenance | | -| TarSlipImprov.py:152:19:152:20 | ControlFlowNode for tf | TarSlipImprov.py:152:13:152:20 | ControlFlowNode for Yield [List element] | provenance | | -| TarSlipImprov.py:152:19:152:20 | ControlFlowNode for tf | TarSlipImprov.py:157:18:157:40 | ControlFlowNode for py2_tarxz() | provenance | | -| TarSlipImprov.py:157:9:157:14 | ControlFlowNode for tar_cm | TarSlipImprov.py:162:20:162:23 | ControlFlowNode for tarc | provenance | | -| TarSlipImprov.py:157:9:157:14 | ControlFlowNode for tar_cm [List element] | TarSlipImprov.py:162:20:162:23 | ControlFlowNode for tarc [List element] | provenance | | -| TarSlipImprov.py:157:18:157:40 | ControlFlowNode for py2_tarxz() | TarSlipImprov.py:157:9:157:14 | ControlFlowNode for tar_cm | provenance | | -| TarSlipImprov.py:157:18:157:40 | ControlFlowNode for py2_tarxz() [List element] | TarSlipImprov.py:157:9:157:14 | ControlFlowNode for tar_cm [List element] | provenance | | -| TarSlipImprov.py:159:9:159:14 | ControlFlowNode for tar_cm | TarSlipImprov.py:162:20:162:23 | ControlFlowNode for tarc | provenance | | -| TarSlipImprov.py:159:18:159:52 | ControlFlowNode for closing() | TarSlipImprov.py:159:9:159:14 | ControlFlowNode for tar_cm | provenance | | -| TarSlipImprov.py:159:26:159:51 | ControlFlowNode for Attribute() | TarSlipImprov.py:159:18:159:52 | ControlFlowNode for closing() | provenance | Config | -| TarSlipImprov.py:162:20:162:23 | ControlFlowNode for tarc | TarSlipImprov.py:169:9:169:12 | ControlFlowNode for tarc | provenance | | -| TarSlipImprov.py:162:20:162:23 | ControlFlowNode for tarc [List element] | TarSlipImprov.py:169:9:169:12 | ControlFlowNode for tarc | provenance | | -| TarSlipImprov.py:176:6:176:31 | ControlFlowNode for Attribute() | TarSlipImprov.py:176:36:176:38 | ControlFlowNode for tar | provenance | | -| TarSlipImprov.py:176:36:176:38 | ControlFlowNode for tar | TarSlipImprov.py:177:9:177:13 | ControlFlowNode for entry | provenance | | -| TarSlipImprov.py:177:9:177:13 | ControlFlowNode for entry | TarSlipImprov.py:178:36:178:40 | ControlFlowNode for entry | provenance | | -| TarSlipImprov.py:182:6:182:31 | ControlFlowNode for Attribute() | TarSlipImprov.py:182:36:182:38 | ControlFlowNode for tar | provenance | | -| TarSlipImprov.py:182:36:182:38 | ControlFlowNode for tar | TarSlipImprov.py:183:9:183:13 | ControlFlowNode for entry | provenance | | -| TarSlipImprov.py:183:9:183:13 | ControlFlowNode for entry | TarSlipImprov.py:184:21:184:25 | ControlFlowNode for entry | provenance | | -| TarSlipImprov.py:188:1:188:3 | ControlFlowNode for tar | TarSlipImprov.py:189:1:189:3 | ControlFlowNode for tar | provenance | | -| TarSlipImprov.py:188:7:188:27 | ControlFlowNode for Attribute() | TarSlipImprov.py:188:1:188:3 | ControlFlowNode for tar | provenance | | -| TarSlipImprov.py:193:6:193:31 | ControlFlowNode for Attribute() | TarSlipImprov.py:193:36:193:38 | ControlFlowNode for tar | provenance | | -| TarSlipImprov.py:193:36:193:38 | ControlFlowNode for tar | TarSlipImprov.py:194:49:194:51 | ControlFlowNode for tar | provenance | | -| TarSlipImprov.py:210:6:210:43 | ControlFlowNode for Attribute() | TarSlipImprov.py:210:48:210:50 | ControlFlowNode for tar | provenance | | -| TarSlipImprov.py:210:48:210:50 | ControlFlowNode for tar | TarSlipImprov.py:211:5:211:7 | ControlFlowNode for tar | provenance | | -| TarSlipImprov.py:231:6:231:38 | ControlFlowNode for Attribute() | TarSlipImprov.py:231:43:231:52 | ControlFlowNode for corpus_tar | provenance | | -| TarSlipImprov.py:231:43:231:52 | ControlFlowNode for corpus_tar | TarSlipImprov.py:233:9:233:9 | ControlFlowNode for f | provenance | | -| TarSlipImprov.py:233:9:233:9 | ControlFlowNode for f | TarSlipImprov.py:235:28:235:28 | ControlFlowNode for f | provenance | | -| TarSlipImprov.py:235:13:235:19 | [post] ControlFlowNode for members | TarSlipImprov.py:236:44:236:50 | ControlFlowNode for members | provenance | | -| TarSlipImprov.py:235:13:235:19 | [post] ControlFlowNode for members [List element] | TarSlipImprov.py:236:44:236:50 | ControlFlowNode for members | provenance | | -| TarSlipImprov.py:235:28:235:28 | ControlFlowNode for f | TarSlipImprov.py:235:13:235:19 | [post] ControlFlowNode for members | provenance | list.append | -| TarSlipImprov.py:235:28:235:28 | ControlFlowNode for f | TarSlipImprov.py:235:13:235:19 | [post] ControlFlowNode for members [List element] | provenance | list.append | -| TarSlipImprov.py:258:6:258:26 | ControlFlowNode for Attribute() | TarSlipImprov.py:258:31:258:33 | ControlFlowNode for tar | provenance | | -| TarSlipImprov.py:258:31:258:33 | ControlFlowNode for tar | TarSlipImprov.py:259:9:259:13 | ControlFlowNode for entry | provenance | | -| TarSlipImprov.py:259:9:259:13 | ControlFlowNode for entry | TarSlipImprov.py:261:25:261:29 | ControlFlowNode for entry | provenance | | -| TarSlipImprov.py:264:6:264:38 | ControlFlowNode for Attribute() | TarSlipImprov.py:264:43:264:45 | ControlFlowNode for tar | provenance | | -| TarSlipImprov.py:264:43:264:45 | ControlFlowNode for tar | TarSlipImprov.py:265:9:265:13 | ControlFlowNode for entry | provenance | | -| TarSlipImprov.py:265:9:265:13 | ControlFlowNode for entry | TarSlipImprov.py:268:21:268:25 | ControlFlowNode for entry | provenance | | -| TarSlipImprov.py:271:6:271:39 | ControlFlowNode for Attribute() | TarSlipImprov.py:271:44:271:46 | ControlFlowNode for tar | provenance | | -| TarSlipImprov.py:271:44:271:46 | ControlFlowNode for tar | TarSlipImprov.py:272:9:272:13 | ControlFlowNode for entry | provenance | | -| TarSlipImprov.py:272:9:272:13 | ControlFlowNode for entry | TarSlipImprov.py:274:25:274:29 | ControlFlowNode for entry | provenance | | -| TarSlipImprov.py:276:6:276:38 | ControlFlowNode for Attribute() | TarSlipImprov.py:276:43:276:45 | ControlFlowNode for tar | provenance | | -| TarSlipImprov.py:276:43:276:45 | ControlFlowNode for tar | TarSlipImprov.py:277:9:277:13 | ControlFlowNode for entry | provenance | | -| TarSlipImprov.py:277:9:277:13 | ControlFlowNode for entry | TarSlipImprov.py:280:21:280:25 | ControlFlowNode for entry | provenance | | -| TarSlipImprov.py:283:6:283:51 | ControlFlowNode for Attribute() | TarSlipImprov.py:283:56:283:58 | ControlFlowNode for tar | provenance | | -| TarSlipImprov.py:283:56:283:58 | ControlFlowNode for tar | TarSlipImprov.py:284:5:284:7 | ControlFlowNode for tar | provenance | | -| TarSlipImprov.py:287:1:287:3 | ControlFlowNode for tar | TarSlipImprov.py:288:49:288:51 | ControlFlowNode for tar | provenance | | -| TarSlipImprov.py:287:7:287:28 | ControlFlowNode for Attribute() | TarSlipImprov.py:287:1:287:3 | ControlFlowNode for tar | provenance | | -| TarSlipImprov.py:292:1:292:3 | ControlFlowNode for tar | TarSlipImprov.py:293:1:293:3 | ControlFlowNode for tar | provenance | | -| TarSlipImprov.py:292:7:292:39 | ControlFlowNode for Attribute() | TarSlipImprov.py:292:1:292:3 | ControlFlowNode for tar | provenance | | -| TarSlipImprov.py:300:6:300:51 | ControlFlowNode for Attribute() | TarSlipImprov.py:300:56:300:58 | ControlFlowNode for tar | provenance | | -| TarSlipImprov.py:300:56:300:58 | ControlFlowNode for tar | TarSlipImprov.py:301:49:301:51 | ControlFlowNode for tar | provenance | | -| TarSlipImprov.py:304:1:304:3 | ControlFlowNode for tar | TarSlipImprov.py:306:5:306:10 | ControlFlowNode for member | provenance | | -| TarSlipImprov.py:304:7:304:39 | ControlFlowNode for Attribute() | TarSlipImprov.py:304:1:304:3 | ControlFlowNode for tar | provenance | | -| TarSlipImprov.py:306:5:306:10 | ControlFlowNode for member | TarSlipImprov.py:309:19:309:24 | ControlFlowNode for member | provenance | | -| TarSlipImprov.py:309:5:309:10 | [post] ControlFlowNode for result | TarSlipImprov.py:310:49:310:54 | ControlFlowNode for result | provenance | | -| TarSlipImprov.py:309:5:309:10 | [post] ControlFlowNode for result [List element] | TarSlipImprov.py:310:49:310:54 | ControlFlowNode for result | provenance | | -| TarSlipImprov.py:309:19:309:24 | ControlFlowNode for member | TarSlipImprov.py:309:5:309:10 | [post] ControlFlowNode for result | provenance | list.append | -| TarSlipImprov.py:309:19:309:24 | ControlFlowNode for member | TarSlipImprov.py:309:5:309:10 | [post] ControlFlowNode for result [List element] | provenance | list.append | +| TarSlipImprov.py:15:1:15:3 | tar | TarSlipImprov.py:17:5:17:10 | member | provenance | | +| TarSlipImprov.py:15:7:15:39 | After Attribute() | TarSlipImprov.py:15:1:15:3 | tar | provenance | | +| TarSlipImprov.py:17:5:17:10 | member | TarSlipImprov.py:20:19:20:24 | member | provenance | | +| TarSlipImprov.py:20:5:20:10 | [post] result | TarSlipImprov.py:22:35:22:40 | result | provenance | | +| TarSlipImprov.py:20:19:20:24 | member | TarSlipImprov.py:20:5:20:10 | [post] result | provenance | list.append | +| TarSlipImprov.py:26:21:26:27 | tarfile | TarSlipImprov.py:28:9:28:14 | member | provenance | | +| TarSlipImprov.py:28:9:28:14 | member | TarSlipImprov.py:35:23:35:28 | member | provenance | | +| TarSlipImprov.py:35:9:35:14 | [post] result | TarSlipImprov.py:36:12:36:17 | result | provenance | | +| TarSlipImprov.py:35:23:35:28 | member | TarSlipImprov.py:35:9:35:14 | [post] result | provenance | list.append | +| TarSlipImprov.py:38:1:38:3 | tar | TarSlipImprov.py:39:65:39:67 | tar | provenance | | +| TarSlipImprov.py:38:7:38:39 | After Attribute() | TarSlipImprov.py:38:1:38:3 | tar | provenance | | +| TarSlipImprov.py:39:65:39:67 | tar | TarSlipImprov.py:26:21:26:27 | tarfile | provenance | | +| TarSlipImprov.py:39:65:39:67 | tar | TarSlipImprov.py:39:49:39:68 | After members_filter1() | provenance | list.append | +| TarSlipImprov.py:43:6:43:38 | After Attribute() | TarSlipImprov.py:43:43:43:45 | tar | provenance | | +| TarSlipImprov.py:43:43:43:45 | tar | TarSlipImprov.py:44:9:44:13 | entry | provenance | | +| TarSlipImprov.py:44:9:44:13 | entry | TarSlipImprov.py:47:21:47:25 | entry | provenance | | +| TarSlipImprov.py:54:6:54:38 | After Attribute() | TarSlipImprov.py:54:43:54:45 | tar | provenance | | +| TarSlipImprov.py:54:43:54:45 | tar | TarSlipImprov.py:56:9:56:13 | entry | provenance | | +| TarSlipImprov.py:56:9:56:13 | entry | TarSlipImprov.py:58:21:58:25 | entry | provenance | | +| TarSlipImprov.py:88:6:88:43 | After Attribute() | TarSlipImprov.py:88:48:88:50 | tar | provenance | | +| TarSlipImprov.py:88:48:88:50 | tar | TarSlipImprov.py:91:5:91:7 | tar | provenance | | +| TarSlipImprov.py:111:1:111:3 | tar | TarSlipImprov.py:115:9:115:11 | tar | provenance | | +| TarSlipImprov.py:111:7:111:39 | After Attribute() | TarSlipImprov.py:111:1:111:3 | tar | provenance | | +| TarSlipImprov.py:123:6:123:29 | After Attribute() | TarSlipImprov.py:123:34:123:36 | tar | provenance | | +| TarSlipImprov.py:123:34:123:36 | tar | TarSlipImprov.py:124:9:124:13 | entry | provenance | | +| TarSlipImprov.py:124:9:124:13 | entry | TarSlipImprov.py:125:36:125:40 | entry | provenance | | +| TarSlipImprov.py:129:6:129:26 | After Attribute() | TarSlipImprov.py:129:31:129:33 | tar | provenance | | +| TarSlipImprov.py:129:31:129:33 | tar | TarSlipImprov.py:130:5:130:7 | tar | provenance | | +| TarSlipImprov.py:133:1:133:3 | tar | TarSlipImprov.py:134:1:134:3 | tar | provenance | | +| TarSlipImprov.py:133:7:133:39 | After Attribute() | TarSlipImprov.py:133:1:133:3 | tar | provenance | | +| TarSlipImprov.py:141:6:141:29 | After Attribute() | TarSlipImprov.py:141:34:141:36 | tar | provenance | | +| TarSlipImprov.py:141:34:141:36 | tar | TarSlipImprov.py:142:9:142:13 | entry | provenance | | +| TarSlipImprov.py:142:9:142:13 | entry | TarSlipImprov.py:143:36:143:40 | entry | provenance | | +| TarSlipImprov.py:151:14:151:50 | After closing() | TarSlipImprov.py:151:55:151:56 | tf | provenance | | +| TarSlipImprov.py:151:22:151:49 | After Attribute() | TarSlipImprov.py:151:14:151:50 | After closing() | provenance | Config | +| TarSlipImprov.py:151:55:151:56 | tf | TarSlipImprov.py:152:13:152:20 | After Yield | provenance | | +| TarSlipImprov.py:151:55:151:56 | tf | TarSlipImprov.py:152:19:152:20 | tf | provenance | | +| TarSlipImprov.py:152:13:152:20 | After Yield | TarSlipImprov.py:157:18:157:40 | After py2_tarxz() | provenance | | +| TarSlipImprov.py:152:19:152:20 | tf | TarSlipImprov.py:157:18:157:40 | After py2_tarxz() | provenance | | +| TarSlipImprov.py:157:9:157:14 | tar_cm | TarSlipImprov.py:162:20:162:23 | tarc | provenance | | +| TarSlipImprov.py:157:18:157:40 | After py2_tarxz() | TarSlipImprov.py:157:9:157:14 | tar_cm | provenance | | +| TarSlipImprov.py:159:9:159:14 | tar_cm | TarSlipImprov.py:162:20:162:23 | tarc | provenance | | +| TarSlipImprov.py:159:18:159:52 | After closing() | TarSlipImprov.py:159:9:159:14 | tar_cm | provenance | | +| TarSlipImprov.py:159:26:159:51 | After Attribute() | TarSlipImprov.py:159:18:159:52 | After closing() | provenance | Config | +| TarSlipImprov.py:162:20:162:23 | tarc | TarSlipImprov.py:169:9:169:12 | tarc | provenance | | +| TarSlipImprov.py:176:6:176:31 | After Attribute() | TarSlipImprov.py:176:36:176:38 | tar | provenance | | +| TarSlipImprov.py:176:36:176:38 | tar | TarSlipImprov.py:177:9:177:13 | entry | provenance | | +| TarSlipImprov.py:177:9:177:13 | entry | TarSlipImprov.py:178:36:178:40 | entry | provenance | | +| TarSlipImprov.py:182:6:182:31 | After Attribute() | TarSlipImprov.py:182:36:182:38 | tar | provenance | | +| TarSlipImprov.py:182:36:182:38 | tar | TarSlipImprov.py:183:9:183:13 | entry | provenance | | +| TarSlipImprov.py:183:9:183:13 | entry | TarSlipImprov.py:184:21:184:25 | entry | provenance | | +| TarSlipImprov.py:188:1:188:3 | tar | TarSlipImprov.py:189:1:189:3 | tar | provenance | | +| TarSlipImprov.py:188:7:188:27 | After Attribute() | TarSlipImprov.py:188:1:188:3 | tar | provenance | | +| TarSlipImprov.py:193:6:193:31 | After Attribute() | TarSlipImprov.py:193:36:193:38 | tar | provenance | | +| TarSlipImprov.py:193:36:193:38 | tar | TarSlipImprov.py:194:49:194:51 | tar | provenance | | +| TarSlipImprov.py:210:6:210:43 | After Attribute() | TarSlipImprov.py:210:48:210:50 | tar | provenance | | +| TarSlipImprov.py:210:48:210:50 | tar | TarSlipImprov.py:211:5:211:7 | tar | provenance | | +| TarSlipImprov.py:231:6:231:38 | After Attribute() | TarSlipImprov.py:231:43:231:52 | corpus_tar | provenance | | +| TarSlipImprov.py:231:43:231:52 | corpus_tar | TarSlipImprov.py:233:9:233:9 | f | provenance | | +| TarSlipImprov.py:233:9:233:9 | f | TarSlipImprov.py:235:28:235:28 | f | provenance | | +| TarSlipImprov.py:235:13:235:19 | [post] members | TarSlipImprov.py:236:44:236:50 | members | provenance | | +| TarSlipImprov.py:235:28:235:28 | f | TarSlipImprov.py:235:13:235:19 | [post] members | provenance | list.append | +| TarSlipImprov.py:258:6:258:26 | After Attribute() | TarSlipImprov.py:258:31:258:33 | tar | provenance | | +| TarSlipImprov.py:258:31:258:33 | tar | TarSlipImprov.py:259:9:259:13 | entry | provenance | | +| TarSlipImprov.py:259:9:259:13 | entry | TarSlipImprov.py:261:25:261:29 | entry | provenance | | +| TarSlipImprov.py:264:6:264:38 | After Attribute() | TarSlipImprov.py:264:43:264:45 | tar | provenance | | +| TarSlipImprov.py:264:43:264:45 | tar | TarSlipImprov.py:265:9:265:13 | entry | provenance | | +| TarSlipImprov.py:265:9:265:13 | entry | TarSlipImprov.py:268:21:268:25 | entry | provenance | | +| TarSlipImprov.py:271:6:271:39 | After Attribute() | TarSlipImprov.py:271:44:271:46 | tar | provenance | | +| TarSlipImprov.py:271:44:271:46 | tar | TarSlipImprov.py:272:9:272:13 | entry | provenance | | +| TarSlipImprov.py:272:9:272:13 | entry | TarSlipImprov.py:274:25:274:29 | entry | provenance | | +| TarSlipImprov.py:276:6:276:38 | After Attribute() | TarSlipImprov.py:276:43:276:45 | tar | provenance | | +| TarSlipImprov.py:276:43:276:45 | tar | TarSlipImprov.py:277:9:277:13 | entry | provenance | | +| TarSlipImprov.py:277:9:277:13 | entry | TarSlipImprov.py:280:21:280:25 | entry | provenance | | +| TarSlipImprov.py:283:6:283:51 | After Attribute() | TarSlipImprov.py:283:56:283:58 | tar | provenance | | +| TarSlipImprov.py:283:56:283:58 | tar | TarSlipImprov.py:284:5:284:7 | tar | provenance | | +| TarSlipImprov.py:287:1:287:3 | tar | TarSlipImprov.py:288:49:288:51 | tar | provenance | | +| TarSlipImprov.py:287:7:287:28 | After Attribute() | TarSlipImprov.py:287:1:287:3 | tar | provenance | | +| TarSlipImprov.py:292:1:292:3 | tar | TarSlipImprov.py:293:1:293:3 | tar | provenance | | +| TarSlipImprov.py:292:7:292:39 | After Attribute() | TarSlipImprov.py:292:1:292:3 | tar | provenance | | +| TarSlipImprov.py:300:6:300:51 | After Attribute() | TarSlipImprov.py:300:56:300:58 | tar | provenance | | +| TarSlipImprov.py:300:56:300:58 | tar | TarSlipImprov.py:301:49:301:51 | tar | provenance | | +| TarSlipImprov.py:304:1:304:3 | tar | TarSlipImprov.py:306:5:306:10 | member | provenance | | +| TarSlipImprov.py:304:7:304:39 | After Attribute() | TarSlipImprov.py:304:1:304:3 | tar | provenance | | +| TarSlipImprov.py:306:5:306:10 | member | TarSlipImprov.py:309:19:309:24 | member | provenance | | +| TarSlipImprov.py:309:5:309:10 | [post] result | TarSlipImprov.py:310:49:310:54 | result | provenance | | +| TarSlipImprov.py:309:19:309:24 | member | TarSlipImprov.py:309:5:309:10 | [post] result | provenance | list.append | nodes -| TarSlipImprov.py:15:1:15:3 | ControlFlowNode for tar | semmle.label | ControlFlowNode for tar | -| TarSlipImprov.py:15:7:15:39 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| TarSlipImprov.py:17:5:17:10 | ControlFlowNode for member | semmle.label | ControlFlowNode for member | -| TarSlipImprov.py:20:5:20:10 | [post] ControlFlowNode for result | semmle.label | [post] ControlFlowNode for result | -| TarSlipImprov.py:20:5:20:10 | [post] ControlFlowNode for result [List element] | semmle.label | [post] ControlFlowNode for result [List element] | -| TarSlipImprov.py:20:19:20:24 | ControlFlowNode for member | semmle.label | ControlFlowNode for member | -| TarSlipImprov.py:22:35:22:40 | ControlFlowNode for result | semmle.label | ControlFlowNode for result | -| TarSlipImprov.py:26:21:26:27 | ControlFlowNode for tarfile | semmle.label | ControlFlowNode for tarfile | -| TarSlipImprov.py:28:9:28:14 | ControlFlowNode for member | semmle.label | ControlFlowNode for member | -| TarSlipImprov.py:35:9:35:14 | [post] ControlFlowNode for result | semmle.label | [post] ControlFlowNode for result | -| TarSlipImprov.py:35:9:35:14 | [post] ControlFlowNode for result [List element] | semmle.label | [post] ControlFlowNode for result [List element] | -| TarSlipImprov.py:35:23:35:28 | ControlFlowNode for member | semmle.label | ControlFlowNode for member | -| TarSlipImprov.py:36:12:36:17 | ControlFlowNode for result | semmle.label | ControlFlowNode for result | -| TarSlipImprov.py:36:12:36:17 | ControlFlowNode for result [List element] | semmle.label | ControlFlowNode for result [List element] | -| TarSlipImprov.py:38:1:38:3 | ControlFlowNode for tar | semmle.label | ControlFlowNode for tar | -| TarSlipImprov.py:38:7:38:39 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| TarSlipImprov.py:39:49:39:68 | ControlFlowNode for members_filter1() | semmle.label | ControlFlowNode for members_filter1() | -| TarSlipImprov.py:39:65:39:67 | ControlFlowNode for tar | semmle.label | ControlFlowNode for tar | -| TarSlipImprov.py:43:6:43:38 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| TarSlipImprov.py:43:43:43:45 | ControlFlowNode for tar | semmle.label | ControlFlowNode for tar | -| TarSlipImprov.py:44:9:44:13 | ControlFlowNode for entry | semmle.label | ControlFlowNode for entry | -| TarSlipImprov.py:47:21:47:25 | ControlFlowNode for entry | semmle.label | ControlFlowNode for entry | -| TarSlipImprov.py:54:6:54:38 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| TarSlipImprov.py:54:43:54:45 | ControlFlowNode for tar | semmle.label | ControlFlowNode for tar | -| TarSlipImprov.py:56:9:56:13 | ControlFlowNode for entry | semmle.label | ControlFlowNode for entry | -| TarSlipImprov.py:58:21:58:25 | ControlFlowNode for entry | semmle.label | ControlFlowNode for entry | -| TarSlipImprov.py:88:6:88:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| TarSlipImprov.py:88:48:88:50 | ControlFlowNode for tar | semmle.label | ControlFlowNode for tar | -| TarSlipImprov.py:91:5:91:7 | ControlFlowNode for tar | semmle.label | ControlFlowNode for tar | -| TarSlipImprov.py:111:1:111:3 | ControlFlowNode for tar | semmle.label | ControlFlowNode for tar | -| TarSlipImprov.py:111:7:111:39 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| TarSlipImprov.py:115:9:115:11 | ControlFlowNode for tar | semmle.label | ControlFlowNode for tar | -| TarSlipImprov.py:123:6:123:29 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| TarSlipImprov.py:123:34:123:36 | ControlFlowNode for tar | semmle.label | ControlFlowNode for tar | -| TarSlipImprov.py:124:9:124:13 | ControlFlowNode for entry | semmle.label | ControlFlowNode for entry | -| TarSlipImprov.py:125:36:125:40 | ControlFlowNode for entry | semmle.label | ControlFlowNode for entry | -| TarSlipImprov.py:129:6:129:26 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| TarSlipImprov.py:129:31:129:33 | ControlFlowNode for tar | semmle.label | ControlFlowNode for tar | -| TarSlipImprov.py:130:5:130:7 | ControlFlowNode for tar | semmle.label | ControlFlowNode for tar | -| TarSlipImprov.py:133:1:133:3 | ControlFlowNode for tar | semmle.label | ControlFlowNode for tar | -| TarSlipImprov.py:133:7:133:39 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| TarSlipImprov.py:134:1:134:3 | ControlFlowNode for tar | semmle.label | ControlFlowNode for tar | -| TarSlipImprov.py:141:6:141:29 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| TarSlipImprov.py:141:34:141:36 | ControlFlowNode for tar | semmle.label | ControlFlowNode for tar | -| TarSlipImprov.py:142:9:142:13 | ControlFlowNode for entry | semmle.label | ControlFlowNode for entry | -| TarSlipImprov.py:143:36:143:40 | ControlFlowNode for entry | semmle.label | ControlFlowNode for entry | -| TarSlipImprov.py:151:14:151:50 | ControlFlowNode for closing() | semmle.label | ControlFlowNode for closing() | -| TarSlipImprov.py:151:22:151:49 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| TarSlipImprov.py:151:55:151:56 | ControlFlowNode for tf | semmle.label | ControlFlowNode for tf | -| TarSlipImprov.py:152:13:152:20 | ControlFlowNode for Yield [List element] | semmle.label | ControlFlowNode for Yield [List element] | -| TarSlipImprov.py:152:19:152:20 | ControlFlowNode for tf | semmle.label | ControlFlowNode for tf | -| TarSlipImprov.py:157:9:157:14 | ControlFlowNode for tar_cm | semmle.label | ControlFlowNode for tar_cm | -| TarSlipImprov.py:157:9:157:14 | ControlFlowNode for tar_cm [List element] | semmle.label | ControlFlowNode for tar_cm [List element] | -| TarSlipImprov.py:157:18:157:40 | ControlFlowNode for py2_tarxz() | semmle.label | ControlFlowNode for py2_tarxz() | -| TarSlipImprov.py:157:18:157:40 | ControlFlowNode for py2_tarxz() [List element] | semmle.label | ControlFlowNode for py2_tarxz() [List element] | -| TarSlipImprov.py:159:9:159:14 | ControlFlowNode for tar_cm | semmle.label | ControlFlowNode for tar_cm | -| TarSlipImprov.py:159:18:159:52 | ControlFlowNode for closing() | semmle.label | ControlFlowNode for closing() | -| TarSlipImprov.py:159:26:159:51 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| TarSlipImprov.py:162:20:162:23 | ControlFlowNode for tarc | semmle.label | ControlFlowNode for tarc | -| TarSlipImprov.py:162:20:162:23 | ControlFlowNode for tarc [List element] | semmle.label | ControlFlowNode for tarc [List element] | -| TarSlipImprov.py:169:9:169:12 | ControlFlowNode for tarc | semmle.label | ControlFlowNode for tarc | -| TarSlipImprov.py:176:6:176:31 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| TarSlipImprov.py:176:36:176:38 | ControlFlowNode for tar | semmle.label | ControlFlowNode for tar | -| TarSlipImprov.py:177:9:177:13 | ControlFlowNode for entry | semmle.label | ControlFlowNode for entry | -| TarSlipImprov.py:178:36:178:40 | ControlFlowNode for entry | semmle.label | ControlFlowNode for entry | -| TarSlipImprov.py:182:6:182:31 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| TarSlipImprov.py:182:36:182:38 | ControlFlowNode for tar | semmle.label | ControlFlowNode for tar | -| TarSlipImprov.py:183:9:183:13 | ControlFlowNode for entry | semmle.label | ControlFlowNode for entry | -| TarSlipImprov.py:184:21:184:25 | ControlFlowNode for entry | semmle.label | ControlFlowNode for entry | -| TarSlipImprov.py:188:1:188:3 | ControlFlowNode for tar | semmle.label | ControlFlowNode for tar | -| TarSlipImprov.py:188:7:188:27 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| TarSlipImprov.py:189:1:189:3 | ControlFlowNode for tar | semmle.label | ControlFlowNode for tar | -| TarSlipImprov.py:193:6:193:31 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| TarSlipImprov.py:193:36:193:38 | ControlFlowNode for tar | semmle.label | ControlFlowNode for tar | -| TarSlipImprov.py:194:49:194:51 | ControlFlowNode for tar | semmle.label | ControlFlowNode for tar | -| TarSlipImprov.py:210:6:210:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| TarSlipImprov.py:210:48:210:50 | ControlFlowNode for tar | semmle.label | ControlFlowNode for tar | -| TarSlipImprov.py:211:5:211:7 | ControlFlowNode for tar | semmle.label | ControlFlowNode for tar | -| TarSlipImprov.py:231:6:231:38 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| TarSlipImprov.py:231:43:231:52 | ControlFlowNode for corpus_tar | semmle.label | ControlFlowNode for corpus_tar | -| TarSlipImprov.py:233:9:233:9 | ControlFlowNode for f | semmle.label | ControlFlowNode for f | -| TarSlipImprov.py:235:13:235:19 | [post] ControlFlowNode for members | semmle.label | [post] ControlFlowNode for members | -| TarSlipImprov.py:235:13:235:19 | [post] ControlFlowNode for members [List element] | semmle.label | [post] ControlFlowNode for members [List element] | -| TarSlipImprov.py:235:28:235:28 | ControlFlowNode for f | semmle.label | ControlFlowNode for f | -| TarSlipImprov.py:236:44:236:50 | ControlFlowNode for members | semmle.label | ControlFlowNode for members | -| TarSlipImprov.py:254:1:254:31 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| TarSlipImprov.py:258:6:258:26 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| TarSlipImprov.py:258:31:258:33 | ControlFlowNode for tar | semmle.label | ControlFlowNode for tar | -| TarSlipImprov.py:259:9:259:13 | ControlFlowNode for entry | semmle.label | ControlFlowNode for entry | -| TarSlipImprov.py:261:25:261:29 | ControlFlowNode for entry | semmle.label | ControlFlowNode for entry | -| TarSlipImprov.py:264:6:264:38 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| TarSlipImprov.py:264:43:264:45 | ControlFlowNode for tar | semmle.label | ControlFlowNode for tar | -| TarSlipImprov.py:265:9:265:13 | ControlFlowNode for entry | semmle.label | ControlFlowNode for entry | -| TarSlipImprov.py:268:21:268:25 | ControlFlowNode for entry | semmle.label | ControlFlowNode for entry | -| TarSlipImprov.py:271:6:271:39 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| TarSlipImprov.py:271:44:271:46 | ControlFlowNode for tar | semmle.label | ControlFlowNode for tar | -| TarSlipImprov.py:272:9:272:13 | ControlFlowNode for entry | semmle.label | ControlFlowNode for entry | -| TarSlipImprov.py:274:25:274:29 | ControlFlowNode for entry | semmle.label | ControlFlowNode for entry | -| TarSlipImprov.py:276:6:276:38 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| TarSlipImprov.py:276:43:276:45 | ControlFlowNode for tar | semmle.label | ControlFlowNode for tar | -| TarSlipImprov.py:277:9:277:13 | ControlFlowNode for entry | semmle.label | ControlFlowNode for entry | -| TarSlipImprov.py:280:21:280:25 | ControlFlowNode for entry | semmle.label | ControlFlowNode for entry | -| TarSlipImprov.py:283:6:283:51 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| TarSlipImprov.py:283:56:283:58 | ControlFlowNode for tar | semmle.label | ControlFlowNode for tar | -| TarSlipImprov.py:284:5:284:7 | ControlFlowNode for tar | semmle.label | ControlFlowNode for tar | -| TarSlipImprov.py:287:1:287:3 | ControlFlowNode for tar | semmle.label | ControlFlowNode for tar | -| TarSlipImprov.py:287:7:287:28 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| TarSlipImprov.py:288:49:288:51 | ControlFlowNode for tar | semmle.label | ControlFlowNode for tar | -| TarSlipImprov.py:292:1:292:3 | ControlFlowNode for tar | semmle.label | ControlFlowNode for tar | -| TarSlipImprov.py:292:7:292:39 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| TarSlipImprov.py:293:1:293:3 | ControlFlowNode for tar | semmle.label | ControlFlowNode for tar | -| TarSlipImprov.py:300:6:300:51 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| TarSlipImprov.py:300:56:300:58 | ControlFlowNode for tar | semmle.label | ControlFlowNode for tar | -| TarSlipImprov.py:301:49:301:51 | ControlFlowNode for tar | semmle.label | ControlFlowNode for tar | -| TarSlipImprov.py:304:1:304:3 | ControlFlowNode for tar | semmle.label | ControlFlowNode for tar | -| TarSlipImprov.py:304:7:304:39 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| TarSlipImprov.py:306:5:306:10 | ControlFlowNode for member | semmle.label | ControlFlowNode for member | -| TarSlipImprov.py:309:5:309:10 | [post] ControlFlowNode for result | semmle.label | [post] ControlFlowNode for result | -| TarSlipImprov.py:309:5:309:10 | [post] ControlFlowNode for result [List element] | semmle.label | [post] ControlFlowNode for result [List element] | -| TarSlipImprov.py:309:19:309:24 | ControlFlowNode for member | semmle.label | ControlFlowNode for member | -| TarSlipImprov.py:310:49:310:54 | ControlFlowNode for result | semmle.label | ControlFlowNode for result | -| TarSlipImprov.py:316:1:316:46 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | +| TarSlipImprov.py:15:1:15:3 | tar | semmle.label | tar | +| TarSlipImprov.py:15:7:15:39 | After Attribute() | semmle.label | After Attribute() | +| TarSlipImprov.py:17:5:17:10 | member | semmle.label | member | +| TarSlipImprov.py:20:5:20:10 | [post] result | semmle.label | [post] result | +| TarSlipImprov.py:20:19:20:24 | member | semmle.label | member | +| TarSlipImprov.py:22:35:22:40 | result | semmle.label | result | +| TarSlipImprov.py:26:21:26:27 | tarfile | semmle.label | tarfile | +| TarSlipImprov.py:28:9:28:14 | member | semmle.label | member | +| TarSlipImprov.py:35:9:35:14 | [post] result | semmle.label | [post] result | +| TarSlipImprov.py:35:23:35:28 | member | semmle.label | member | +| TarSlipImprov.py:36:12:36:17 | result | semmle.label | result | +| TarSlipImprov.py:38:1:38:3 | tar | semmle.label | tar | +| TarSlipImprov.py:38:7:38:39 | After Attribute() | semmle.label | After Attribute() | +| TarSlipImprov.py:39:49:39:68 | After members_filter1() | semmle.label | After members_filter1() | +| TarSlipImprov.py:39:65:39:67 | tar | semmle.label | tar | +| TarSlipImprov.py:43:6:43:38 | After Attribute() | semmle.label | After Attribute() | +| TarSlipImprov.py:43:43:43:45 | tar | semmle.label | tar | +| TarSlipImprov.py:44:9:44:13 | entry | semmle.label | entry | +| TarSlipImprov.py:47:21:47:25 | entry | semmle.label | entry | +| TarSlipImprov.py:54:6:54:38 | After Attribute() | semmle.label | After Attribute() | +| TarSlipImprov.py:54:43:54:45 | tar | semmle.label | tar | +| TarSlipImprov.py:56:9:56:13 | entry | semmle.label | entry | +| TarSlipImprov.py:58:21:58:25 | entry | semmle.label | entry | +| TarSlipImprov.py:88:6:88:43 | After Attribute() | semmle.label | After Attribute() | +| TarSlipImprov.py:88:48:88:50 | tar | semmle.label | tar | +| TarSlipImprov.py:91:5:91:7 | tar | semmle.label | tar | +| TarSlipImprov.py:111:1:111:3 | tar | semmle.label | tar | +| TarSlipImprov.py:111:7:111:39 | After Attribute() | semmle.label | After Attribute() | +| TarSlipImprov.py:115:9:115:11 | tar | semmle.label | tar | +| TarSlipImprov.py:123:6:123:29 | After Attribute() | semmle.label | After Attribute() | +| TarSlipImprov.py:123:34:123:36 | tar | semmle.label | tar | +| TarSlipImprov.py:124:9:124:13 | entry | semmle.label | entry | +| TarSlipImprov.py:125:36:125:40 | entry | semmle.label | entry | +| TarSlipImprov.py:129:6:129:26 | After Attribute() | semmle.label | After Attribute() | +| TarSlipImprov.py:129:31:129:33 | tar | semmle.label | tar | +| TarSlipImprov.py:130:5:130:7 | tar | semmle.label | tar | +| TarSlipImprov.py:133:1:133:3 | tar | semmle.label | tar | +| TarSlipImprov.py:133:7:133:39 | After Attribute() | semmle.label | After Attribute() | +| TarSlipImprov.py:134:1:134:3 | tar | semmle.label | tar | +| TarSlipImprov.py:141:6:141:29 | After Attribute() | semmle.label | After Attribute() | +| TarSlipImprov.py:141:34:141:36 | tar | semmle.label | tar | +| TarSlipImprov.py:142:9:142:13 | entry | semmle.label | entry | +| TarSlipImprov.py:143:36:143:40 | entry | semmle.label | entry | +| TarSlipImprov.py:151:14:151:50 | After closing() | semmle.label | After closing() | +| TarSlipImprov.py:151:22:151:49 | After Attribute() | semmle.label | After Attribute() | +| TarSlipImprov.py:151:55:151:56 | tf | semmle.label | tf | +| TarSlipImprov.py:152:13:152:20 | After Yield | semmle.label | After Yield | +| TarSlipImprov.py:152:19:152:20 | tf | semmle.label | tf | +| TarSlipImprov.py:157:9:157:14 | tar_cm | semmle.label | tar_cm | +| TarSlipImprov.py:157:18:157:40 | After py2_tarxz() | semmle.label | After py2_tarxz() | +| TarSlipImprov.py:159:9:159:14 | tar_cm | semmle.label | tar_cm | +| TarSlipImprov.py:159:18:159:52 | After closing() | semmle.label | After closing() | +| TarSlipImprov.py:159:26:159:51 | After Attribute() | semmle.label | After Attribute() | +| TarSlipImprov.py:162:20:162:23 | tarc | semmle.label | tarc | +| TarSlipImprov.py:169:9:169:12 | tarc | semmle.label | tarc | +| TarSlipImprov.py:176:6:176:31 | After Attribute() | semmle.label | After Attribute() | +| TarSlipImprov.py:176:36:176:38 | tar | semmle.label | tar | +| TarSlipImprov.py:177:9:177:13 | entry | semmle.label | entry | +| TarSlipImprov.py:178:36:178:40 | entry | semmle.label | entry | +| TarSlipImprov.py:182:6:182:31 | After Attribute() | semmle.label | After Attribute() | +| TarSlipImprov.py:182:36:182:38 | tar | semmle.label | tar | +| TarSlipImprov.py:183:9:183:13 | entry | semmle.label | entry | +| TarSlipImprov.py:184:21:184:25 | entry | semmle.label | entry | +| TarSlipImprov.py:188:1:188:3 | tar | semmle.label | tar | +| TarSlipImprov.py:188:7:188:27 | After Attribute() | semmle.label | After Attribute() | +| TarSlipImprov.py:189:1:189:3 | tar | semmle.label | tar | +| TarSlipImprov.py:193:6:193:31 | After Attribute() | semmle.label | After Attribute() | +| TarSlipImprov.py:193:36:193:38 | tar | semmle.label | tar | +| TarSlipImprov.py:194:49:194:51 | tar | semmle.label | tar | +| TarSlipImprov.py:210:6:210:43 | After Attribute() | semmle.label | After Attribute() | +| TarSlipImprov.py:210:48:210:50 | tar | semmle.label | tar | +| TarSlipImprov.py:211:5:211:7 | tar | semmle.label | tar | +| TarSlipImprov.py:231:6:231:38 | After Attribute() | semmle.label | After Attribute() | +| TarSlipImprov.py:231:43:231:52 | corpus_tar | semmle.label | corpus_tar | +| TarSlipImprov.py:233:9:233:9 | f | semmle.label | f | +| TarSlipImprov.py:235:13:235:19 | [post] members | semmle.label | [post] members | +| TarSlipImprov.py:235:28:235:28 | f | semmle.label | f | +| TarSlipImprov.py:236:44:236:50 | members | semmle.label | members | +| TarSlipImprov.py:254:1:254:31 | After Attribute() | semmle.label | After Attribute() | +| TarSlipImprov.py:258:6:258:26 | After Attribute() | semmle.label | After Attribute() | +| TarSlipImprov.py:258:31:258:33 | tar | semmle.label | tar | +| TarSlipImprov.py:259:9:259:13 | entry | semmle.label | entry | +| TarSlipImprov.py:261:25:261:29 | entry | semmle.label | entry | +| TarSlipImprov.py:264:6:264:38 | After Attribute() | semmle.label | After Attribute() | +| TarSlipImprov.py:264:43:264:45 | tar | semmle.label | tar | +| TarSlipImprov.py:265:9:265:13 | entry | semmle.label | entry | +| TarSlipImprov.py:268:21:268:25 | entry | semmle.label | entry | +| TarSlipImprov.py:271:6:271:39 | After Attribute() | semmle.label | After Attribute() | +| TarSlipImprov.py:271:44:271:46 | tar | semmle.label | tar | +| TarSlipImprov.py:272:9:272:13 | entry | semmle.label | entry | +| TarSlipImprov.py:274:25:274:29 | entry | semmle.label | entry | +| TarSlipImprov.py:276:6:276:38 | After Attribute() | semmle.label | After Attribute() | +| TarSlipImprov.py:276:43:276:45 | tar | semmle.label | tar | +| TarSlipImprov.py:277:9:277:13 | entry | semmle.label | entry | +| TarSlipImprov.py:280:21:280:25 | entry | semmle.label | entry | +| TarSlipImprov.py:283:6:283:51 | After Attribute() | semmle.label | After Attribute() | +| TarSlipImprov.py:283:56:283:58 | tar | semmle.label | tar | +| TarSlipImprov.py:284:5:284:7 | tar | semmle.label | tar | +| TarSlipImprov.py:287:1:287:3 | tar | semmle.label | tar | +| TarSlipImprov.py:287:7:287:28 | After Attribute() | semmle.label | After Attribute() | +| TarSlipImprov.py:288:49:288:51 | tar | semmle.label | tar | +| TarSlipImprov.py:292:1:292:3 | tar | semmle.label | tar | +| TarSlipImprov.py:292:7:292:39 | After Attribute() | semmle.label | After Attribute() | +| TarSlipImprov.py:293:1:293:3 | tar | semmle.label | tar | +| TarSlipImprov.py:300:6:300:51 | After Attribute() | semmle.label | After Attribute() | +| TarSlipImprov.py:300:56:300:58 | tar | semmle.label | tar | +| TarSlipImprov.py:301:49:301:51 | tar | semmle.label | tar | +| TarSlipImprov.py:304:1:304:3 | tar | semmle.label | tar | +| TarSlipImprov.py:304:7:304:39 | After Attribute() | semmle.label | After Attribute() | +| TarSlipImprov.py:306:5:306:10 | member | semmle.label | member | +| TarSlipImprov.py:309:5:309:10 | [post] result | semmle.label | [post] result | +| TarSlipImprov.py:309:19:309:24 | member | semmle.label | member | +| TarSlipImprov.py:310:49:310:54 | result | semmle.label | result | +| TarSlipImprov.py:316:1:316:46 | After Attribute() | semmle.label | After Attribute() | subpaths -| TarSlipImprov.py:39:65:39:67 | ControlFlowNode for tar | TarSlipImprov.py:26:21:26:27 | ControlFlowNode for tarfile | TarSlipImprov.py:36:12:36:17 | ControlFlowNode for result | TarSlipImprov.py:39:49:39:68 | ControlFlowNode for members_filter1() | -| TarSlipImprov.py:39:65:39:67 | ControlFlowNode for tar | TarSlipImprov.py:26:21:26:27 | ControlFlowNode for tarfile | TarSlipImprov.py:36:12:36:17 | ControlFlowNode for result [List element] | TarSlipImprov.py:39:49:39:68 | ControlFlowNode for members_filter1() | +| TarSlipImprov.py:39:65:39:67 | tar | TarSlipImprov.py:26:21:26:27 | tarfile | TarSlipImprov.py:36:12:36:17 | result | TarSlipImprov.py:39:49:39:68 | After members_filter1() | #select -| TarSlipImprov.py:22:35:22:40 | ControlFlowNode for result | TarSlipImprov.py:15:7:15:39 | ControlFlowNode for Attribute() | TarSlipImprov.py:22:35:22:40 | ControlFlowNode for result | Extraction of tarfile from $@ to a potentially untrusted source $@. | TarSlipImprov.py:15:7:15:39 | ControlFlowNode for Attribute() | ControlFlowNode for Attribute() | TarSlipImprov.py:22:35:22:40 | ControlFlowNode for result | ControlFlowNode for result | -| TarSlipImprov.py:39:49:39:68 | ControlFlowNode for members_filter1() | TarSlipImprov.py:38:7:38:39 | ControlFlowNode for Attribute() | TarSlipImprov.py:39:49:39:68 | ControlFlowNode for members_filter1() | Extraction of tarfile from $@ to a potentially untrusted source $@. | TarSlipImprov.py:38:7:38:39 | ControlFlowNode for Attribute() | ControlFlowNode for Attribute() | TarSlipImprov.py:39:49:39:68 | ControlFlowNode for members_filter1() | ControlFlowNode for members_filter1() | -| TarSlipImprov.py:47:21:47:25 | ControlFlowNode for entry | TarSlipImprov.py:43:6:43:38 | ControlFlowNode for Attribute() | TarSlipImprov.py:47:21:47:25 | ControlFlowNode for entry | Extraction of tarfile from $@ to a potentially untrusted source $@. | TarSlipImprov.py:43:6:43:38 | ControlFlowNode for Attribute() | ControlFlowNode for Attribute() | TarSlipImprov.py:47:21:47:25 | ControlFlowNode for entry | ControlFlowNode for entry | -| TarSlipImprov.py:58:21:58:25 | ControlFlowNode for entry | TarSlipImprov.py:54:6:54:38 | ControlFlowNode for Attribute() | TarSlipImprov.py:58:21:58:25 | ControlFlowNode for entry | Extraction of tarfile from $@ to a potentially untrusted source $@. | TarSlipImprov.py:54:6:54:38 | ControlFlowNode for Attribute() | ControlFlowNode for Attribute() | TarSlipImprov.py:58:21:58:25 | ControlFlowNode for entry | ControlFlowNode for entry | -| TarSlipImprov.py:91:5:91:7 | ControlFlowNode for tar | TarSlipImprov.py:88:6:88:43 | ControlFlowNode for Attribute() | TarSlipImprov.py:91:5:91:7 | ControlFlowNode for tar | Extraction of tarfile from $@ to a potentially untrusted source $@. | TarSlipImprov.py:88:6:88:43 | ControlFlowNode for Attribute() | ControlFlowNode for Attribute() | TarSlipImprov.py:91:5:91:7 | ControlFlowNode for tar | ControlFlowNode for tar | -| TarSlipImprov.py:115:9:115:11 | ControlFlowNode for tar | TarSlipImprov.py:111:7:111:39 | ControlFlowNode for Attribute() | TarSlipImprov.py:115:9:115:11 | ControlFlowNode for tar | Extraction of tarfile from $@ to a potentially untrusted source $@. | TarSlipImprov.py:111:7:111:39 | ControlFlowNode for Attribute() | ControlFlowNode for Attribute() | TarSlipImprov.py:115:9:115:11 | ControlFlowNode for tar | ControlFlowNode for tar | -| TarSlipImprov.py:125:36:125:40 | ControlFlowNode for entry | TarSlipImprov.py:123:6:123:29 | ControlFlowNode for Attribute() | TarSlipImprov.py:125:36:125:40 | ControlFlowNode for entry | Extraction of tarfile from $@ to a potentially untrusted source $@. | TarSlipImprov.py:123:6:123:29 | ControlFlowNode for Attribute() | ControlFlowNode for Attribute() | TarSlipImprov.py:125:36:125:40 | ControlFlowNode for entry | ControlFlowNode for entry | -| TarSlipImprov.py:130:5:130:7 | ControlFlowNode for tar | TarSlipImprov.py:129:6:129:26 | ControlFlowNode for Attribute() | TarSlipImprov.py:130:5:130:7 | ControlFlowNode for tar | Extraction of tarfile from $@ to a potentially untrusted source $@. | TarSlipImprov.py:129:6:129:26 | ControlFlowNode for Attribute() | ControlFlowNode for Attribute() | TarSlipImprov.py:130:5:130:7 | ControlFlowNode for tar | ControlFlowNode for tar | -| TarSlipImprov.py:134:1:134:3 | ControlFlowNode for tar | TarSlipImprov.py:133:7:133:39 | ControlFlowNode for Attribute() | TarSlipImprov.py:134:1:134:3 | ControlFlowNode for tar | Extraction of tarfile from $@ to a potentially untrusted source $@. | TarSlipImprov.py:133:7:133:39 | ControlFlowNode for Attribute() | ControlFlowNode for Attribute() | TarSlipImprov.py:134:1:134:3 | ControlFlowNode for tar | ControlFlowNode for tar | -| TarSlipImprov.py:143:36:143:40 | ControlFlowNode for entry | TarSlipImprov.py:141:6:141:29 | ControlFlowNode for Attribute() | TarSlipImprov.py:143:36:143:40 | ControlFlowNode for entry | Extraction of tarfile from $@ to a potentially untrusted source $@. | TarSlipImprov.py:141:6:141:29 | ControlFlowNode for Attribute() | ControlFlowNode for Attribute() | TarSlipImprov.py:143:36:143:40 | ControlFlowNode for entry | ControlFlowNode for entry | -| TarSlipImprov.py:169:9:169:12 | ControlFlowNode for tarc | TarSlipImprov.py:151:22:151:49 | ControlFlowNode for Attribute() | TarSlipImprov.py:169:9:169:12 | ControlFlowNode for tarc | Extraction of tarfile from $@ to a potentially untrusted source $@. | TarSlipImprov.py:151:22:151:49 | ControlFlowNode for Attribute() | ControlFlowNode for Attribute() | TarSlipImprov.py:169:9:169:12 | ControlFlowNode for tarc | ControlFlowNode for tarc | -| TarSlipImprov.py:169:9:169:12 | ControlFlowNode for tarc | TarSlipImprov.py:159:26:159:51 | ControlFlowNode for Attribute() | TarSlipImprov.py:169:9:169:12 | ControlFlowNode for tarc | Extraction of tarfile from $@ to a potentially untrusted source $@. | TarSlipImprov.py:159:26:159:51 | ControlFlowNode for Attribute() | ControlFlowNode for Attribute() | TarSlipImprov.py:169:9:169:12 | ControlFlowNode for tarc | ControlFlowNode for tarc | -| TarSlipImprov.py:178:36:178:40 | ControlFlowNode for entry | TarSlipImprov.py:176:6:176:31 | ControlFlowNode for Attribute() | TarSlipImprov.py:178:36:178:40 | ControlFlowNode for entry | Extraction of tarfile from $@ to a potentially untrusted source $@. | TarSlipImprov.py:176:6:176:31 | ControlFlowNode for Attribute() | ControlFlowNode for Attribute() | TarSlipImprov.py:178:36:178:40 | ControlFlowNode for entry | ControlFlowNode for entry | -| TarSlipImprov.py:184:21:184:25 | ControlFlowNode for entry | TarSlipImprov.py:182:6:182:31 | ControlFlowNode for Attribute() | TarSlipImprov.py:184:21:184:25 | ControlFlowNode for entry | Extraction of tarfile from $@ to a potentially untrusted source $@. | TarSlipImprov.py:182:6:182:31 | ControlFlowNode for Attribute() | ControlFlowNode for Attribute() | TarSlipImprov.py:184:21:184:25 | ControlFlowNode for entry | ControlFlowNode for entry | -| TarSlipImprov.py:189:1:189:3 | ControlFlowNode for tar | TarSlipImprov.py:188:7:188:27 | ControlFlowNode for Attribute() | TarSlipImprov.py:189:1:189:3 | ControlFlowNode for tar | Extraction of tarfile from $@ to a potentially untrusted source $@. | TarSlipImprov.py:188:7:188:27 | ControlFlowNode for Attribute() | ControlFlowNode for Attribute() | TarSlipImprov.py:189:1:189:3 | ControlFlowNode for tar | ControlFlowNode for tar | -| TarSlipImprov.py:194:49:194:51 | ControlFlowNode for tar | TarSlipImprov.py:193:6:193:31 | ControlFlowNode for Attribute() | TarSlipImprov.py:194:49:194:51 | ControlFlowNode for tar | Extraction of tarfile from $@ to a potentially untrusted source $@. | TarSlipImprov.py:193:6:193:31 | ControlFlowNode for Attribute() | ControlFlowNode for Attribute() | TarSlipImprov.py:194:49:194:51 | ControlFlowNode for tar | ControlFlowNode for tar | -| TarSlipImprov.py:211:5:211:7 | ControlFlowNode for tar | TarSlipImprov.py:210:6:210:43 | ControlFlowNode for Attribute() | TarSlipImprov.py:211:5:211:7 | ControlFlowNode for tar | Extraction of tarfile from $@ to a potentially untrusted source $@. | TarSlipImprov.py:210:6:210:43 | ControlFlowNode for Attribute() | ControlFlowNode for Attribute() | TarSlipImprov.py:211:5:211:7 | ControlFlowNode for tar | ControlFlowNode for tar | -| TarSlipImprov.py:236:44:236:50 | ControlFlowNode for members | TarSlipImprov.py:231:6:231:38 | ControlFlowNode for Attribute() | TarSlipImprov.py:236:44:236:50 | ControlFlowNode for members | Extraction of tarfile from $@ to a potentially untrusted source $@. | TarSlipImprov.py:231:6:231:38 | ControlFlowNode for Attribute() | ControlFlowNode for Attribute() | TarSlipImprov.py:236:44:236:50 | ControlFlowNode for members | ControlFlowNode for members | -| TarSlipImprov.py:254:1:254:31 | ControlFlowNode for Attribute() | TarSlipImprov.py:254:1:254:31 | ControlFlowNode for Attribute() | TarSlipImprov.py:254:1:254:31 | ControlFlowNode for Attribute() | Extraction of tarfile from $@ to a potentially untrusted source $@. | TarSlipImprov.py:254:1:254:31 | ControlFlowNode for Attribute() | ControlFlowNode for Attribute() | TarSlipImprov.py:254:1:254:31 | ControlFlowNode for Attribute() | ControlFlowNode for Attribute() | -| TarSlipImprov.py:261:25:261:29 | ControlFlowNode for entry | TarSlipImprov.py:258:6:258:26 | ControlFlowNode for Attribute() | TarSlipImprov.py:261:25:261:29 | ControlFlowNode for entry | Extraction of tarfile from $@ to a potentially untrusted source $@. | TarSlipImprov.py:258:6:258:26 | ControlFlowNode for Attribute() | ControlFlowNode for Attribute() | TarSlipImprov.py:261:25:261:29 | ControlFlowNode for entry | ControlFlowNode for entry | -| TarSlipImprov.py:268:21:268:25 | ControlFlowNode for entry | TarSlipImprov.py:264:6:264:38 | ControlFlowNode for Attribute() | TarSlipImprov.py:268:21:268:25 | ControlFlowNode for entry | Extraction of tarfile from $@ to a potentially untrusted source $@. | TarSlipImprov.py:264:6:264:38 | ControlFlowNode for Attribute() | ControlFlowNode for Attribute() | TarSlipImprov.py:268:21:268:25 | ControlFlowNode for entry | ControlFlowNode for entry | -| TarSlipImprov.py:274:25:274:29 | ControlFlowNode for entry | TarSlipImprov.py:271:6:271:39 | ControlFlowNode for Attribute() | TarSlipImprov.py:274:25:274:29 | ControlFlowNode for entry | Extraction of tarfile from $@ to a potentially untrusted source $@. | TarSlipImprov.py:271:6:271:39 | ControlFlowNode for Attribute() | ControlFlowNode for Attribute() | TarSlipImprov.py:274:25:274:29 | ControlFlowNode for entry | ControlFlowNode for entry | -| TarSlipImprov.py:280:21:280:25 | ControlFlowNode for entry | TarSlipImprov.py:276:6:276:38 | ControlFlowNode for Attribute() | TarSlipImprov.py:280:21:280:25 | ControlFlowNode for entry | Extraction of tarfile from $@ to a potentially untrusted source $@. | TarSlipImprov.py:276:6:276:38 | ControlFlowNode for Attribute() | ControlFlowNode for Attribute() | TarSlipImprov.py:280:21:280:25 | ControlFlowNode for entry | ControlFlowNode for entry | -| TarSlipImprov.py:284:5:284:7 | ControlFlowNode for tar | TarSlipImprov.py:283:6:283:51 | ControlFlowNode for Attribute() | TarSlipImprov.py:284:5:284:7 | ControlFlowNode for tar | Extraction of tarfile from $@ to a potentially untrusted source $@. | TarSlipImprov.py:283:6:283:51 | ControlFlowNode for Attribute() | ControlFlowNode for Attribute() | TarSlipImprov.py:284:5:284:7 | ControlFlowNode for tar | ControlFlowNode for tar | -| TarSlipImprov.py:288:49:288:51 | ControlFlowNode for tar | TarSlipImprov.py:287:7:287:28 | ControlFlowNode for Attribute() | TarSlipImprov.py:288:49:288:51 | ControlFlowNode for tar | Extraction of tarfile from $@ to a potentially untrusted source $@. | TarSlipImprov.py:287:7:287:28 | ControlFlowNode for Attribute() | ControlFlowNode for Attribute() | TarSlipImprov.py:288:49:288:51 | ControlFlowNode for tar | ControlFlowNode for tar | -| TarSlipImprov.py:293:1:293:3 | ControlFlowNode for tar | TarSlipImprov.py:292:7:292:39 | ControlFlowNode for Attribute() | TarSlipImprov.py:293:1:293:3 | ControlFlowNode for tar | Extraction of tarfile from $@ to a potentially untrusted source $@. | TarSlipImprov.py:292:7:292:39 | ControlFlowNode for Attribute() | ControlFlowNode for Attribute() | TarSlipImprov.py:293:1:293:3 | ControlFlowNode for tar | ControlFlowNode for tar | -| TarSlipImprov.py:301:49:301:51 | ControlFlowNode for tar | TarSlipImprov.py:300:6:300:51 | ControlFlowNode for Attribute() | TarSlipImprov.py:301:49:301:51 | ControlFlowNode for tar | Extraction of tarfile from $@ to a potentially untrusted source $@. | TarSlipImprov.py:300:6:300:51 | ControlFlowNode for Attribute() | ControlFlowNode for Attribute() | TarSlipImprov.py:301:49:301:51 | ControlFlowNode for tar | ControlFlowNode for tar | -| TarSlipImprov.py:310:49:310:54 | ControlFlowNode for result | TarSlipImprov.py:304:7:304:39 | ControlFlowNode for Attribute() | TarSlipImprov.py:310:49:310:54 | ControlFlowNode for result | Extraction of tarfile from $@ to a potentially untrusted source $@. | TarSlipImprov.py:304:7:304:39 | ControlFlowNode for Attribute() | ControlFlowNode for Attribute() | TarSlipImprov.py:310:49:310:54 | ControlFlowNode for result | ControlFlowNode for result | -| TarSlipImprov.py:316:1:316:46 | ControlFlowNode for Attribute() | TarSlipImprov.py:316:1:316:46 | ControlFlowNode for Attribute() | TarSlipImprov.py:316:1:316:46 | ControlFlowNode for Attribute() | Extraction of tarfile from $@ to a potentially untrusted source $@. | TarSlipImprov.py:316:1:316:46 | ControlFlowNode for Attribute() | ControlFlowNode for Attribute() | TarSlipImprov.py:316:1:316:46 | ControlFlowNode for Attribute() | ControlFlowNode for Attribute() | +| TarSlipImprov.py:22:35:22:40 | result | TarSlipImprov.py:15:7:15:39 | After Attribute() | TarSlipImprov.py:22:35:22:40 | result | Extraction of tarfile from $@ to a potentially untrusted source $@. | TarSlipImprov.py:15:7:15:39 | After Attribute() | After Attribute() | TarSlipImprov.py:22:35:22:40 | result | result | +| TarSlipImprov.py:39:49:39:68 | After members_filter1() | TarSlipImprov.py:38:7:38:39 | After Attribute() | TarSlipImprov.py:39:49:39:68 | After members_filter1() | Extraction of tarfile from $@ to a potentially untrusted source $@. | TarSlipImprov.py:38:7:38:39 | After Attribute() | After Attribute() | TarSlipImprov.py:39:49:39:68 | After members_filter1() | After members_filter1() | +| TarSlipImprov.py:47:21:47:25 | entry | TarSlipImprov.py:43:6:43:38 | After Attribute() | TarSlipImprov.py:47:21:47:25 | entry | Extraction of tarfile from $@ to a potentially untrusted source $@. | TarSlipImprov.py:43:6:43:38 | After Attribute() | After Attribute() | TarSlipImprov.py:47:21:47:25 | entry | entry | +| TarSlipImprov.py:58:21:58:25 | entry | TarSlipImprov.py:54:6:54:38 | After Attribute() | TarSlipImprov.py:58:21:58:25 | entry | Extraction of tarfile from $@ to a potentially untrusted source $@. | TarSlipImprov.py:54:6:54:38 | After Attribute() | After Attribute() | TarSlipImprov.py:58:21:58:25 | entry | entry | +| TarSlipImprov.py:91:5:91:7 | tar | TarSlipImprov.py:88:6:88:43 | After Attribute() | TarSlipImprov.py:91:5:91:7 | tar | Extraction of tarfile from $@ to a potentially untrusted source $@. | TarSlipImprov.py:88:6:88:43 | After Attribute() | After Attribute() | TarSlipImprov.py:91:5:91:7 | tar | tar | +| TarSlipImprov.py:115:9:115:11 | tar | TarSlipImprov.py:111:7:111:39 | After Attribute() | TarSlipImprov.py:115:9:115:11 | tar | Extraction of tarfile from $@ to a potentially untrusted source $@. | TarSlipImprov.py:111:7:111:39 | After Attribute() | After Attribute() | TarSlipImprov.py:115:9:115:11 | tar | tar | +| TarSlipImprov.py:125:36:125:40 | entry | TarSlipImprov.py:123:6:123:29 | After Attribute() | TarSlipImprov.py:125:36:125:40 | entry | Extraction of tarfile from $@ to a potentially untrusted source $@. | TarSlipImprov.py:123:6:123:29 | After Attribute() | After Attribute() | TarSlipImprov.py:125:36:125:40 | entry | entry | +| TarSlipImprov.py:130:5:130:7 | tar | TarSlipImprov.py:129:6:129:26 | After Attribute() | TarSlipImprov.py:130:5:130:7 | tar | Extraction of tarfile from $@ to a potentially untrusted source $@. | TarSlipImprov.py:129:6:129:26 | After Attribute() | After Attribute() | TarSlipImprov.py:130:5:130:7 | tar | tar | +| TarSlipImprov.py:134:1:134:3 | tar | TarSlipImprov.py:133:7:133:39 | After Attribute() | TarSlipImprov.py:134:1:134:3 | tar | Extraction of tarfile from $@ to a potentially untrusted source $@. | TarSlipImprov.py:133:7:133:39 | After Attribute() | After Attribute() | TarSlipImprov.py:134:1:134:3 | tar | tar | +| TarSlipImprov.py:143:36:143:40 | entry | TarSlipImprov.py:141:6:141:29 | After Attribute() | TarSlipImprov.py:143:36:143:40 | entry | Extraction of tarfile from $@ to a potentially untrusted source $@. | TarSlipImprov.py:141:6:141:29 | After Attribute() | After Attribute() | TarSlipImprov.py:143:36:143:40 | entry | entry | +| TarSlipImprov.py:169:9:169:12 | tarc | TarSlipImprov.py:151:22:151:49 | After Attribute() | TarSlipImprov.py:169:9:169:12 | tarc | Extraction of tarfile from $@ to a potentially untrusted source $@. | TarSlipImprov.py:151:22:151:49 | After Attribute() | After Attribute() | TarSlipImprov.py:169:9:169:12 | tarc | tarc | +| TarSlipImprov.py:169:9:169:12 | tarc | TarSlipImprov.py:159:26:159:51 | After Attribute() | TarSlipImprov.py:169:9:169:12 | tarc | Extraction of tarfile from $@ to a potentially untrusted source $@. | TarSlipImprov.py:159:26:159:51 | After Attribute() | After Attribute() | TarSlipImprov.py:169:9:169:12 | tarc | tarc | +| TarSlipImprov.py:178:36:178:40 | entry | TarSlipImprov.py:176:6:176:31 | After Attribute() | TarSlipImprov.py:178:36:178:40 | entry | Extraction of tarfile from $@ to a potentially untrusted source $@. | TarSlipImprov.py:176:6:176:31 | After Attribute() | After Attribute() | TarSlipImprov.py:178:36:178:40 | entry | entry | +| TarSlipImprov.py:184:21:184:25 | entry | TarSlipImprov.py:182:6:182:31 | After Attribute() | TarSlipImprov.py:184:21:184:25 | entry | Extraction of tarfile from $@ to a potentially untrusted source $@. | TarSlipImprov.py:182:6:182:31 | After Attribute() | After Attribute() | TarSlipImprov.py:184:21:184:25 | entry | entry | +| TarSlipImprov.py:189:1:189:3 | tar | TarSlipImprov.py:188:7:188:27 | After Attribute() | TarSlipImprov.py:189:1:189:3 | tar | Extraction of tarfile from $@ to a potentially untrusted source $@. | TarSlipImprov.py:188:7:188:27 | After Attribute() | After Attribute() | TarSlipImprov.py:189:1:189:3 | tar | tar | +| TarSlipImprov.py:194:49:194:51 | tar | TarSlipImprov.py:193:6:193:31 | After Attribute() | TarSlipImprov.py:194:49:194:51 | tar | Extraction of tarfile from $@ to a potentially untrusted source $@. | TarSlipImprov.py:193:6:193:31 | After Attribute() | After Attribute() | TarSlipImprov.py:194:49:194:51 | tar | tar | +| TarSlipImprov.py:211:5:211:7 | tar | TarSlipImprov.py:210:6:210:43 | After Attribute() | TarSlipImprov.py:211:5:211:7 | tar | Extraction of tarfile from $@ to a potentially untrusted source $@. | TarSlipImprov.py:210:6:210:43 | After Attribute() | After Attribute() | TarSlipImprov.py:211:5:211:7 | tar | tar | +| TarSlipImprov.py:236:44:236:50 | members | TarSlipImprov.py:231:6:231:38 | After Attribute() | TarSlipImprov.py:236:44:236:50 | members | Extraction of tarfile from $@ to a potentially untrusted source $@. | TarSlipImprov.py:231:6:231:38 | After Attribute() | After Attribute() | TarSlipImprov.py:236:44:236:50 | members | members | +| TarSlipImprov.py:254:1:254:31 | After Attribute() | TarSlipImprov.py:254:1:254:31 | After Attribute() | TarSlipImprov.py:254:1:254:31 | After Attribute() | Extraction of tarfile from $@ to a potentially untrusted source $@. | TarSlipImprov.py:254:1:254:31 | After Attribute() | After Attribute() | TarSlipImprov.py:254:1:254:31 | After Attribute() | After Attribute() | +| TarSlipImprov.py:261:25:261:29 | entry | TarSlipImprov.py:258:6:258:26 | After Attribute() | TarSlipImprov.py:261:25:261:29 | entry | Extraction of tarfile from $@ to a potentially untrusted source $@. | TarSlipImprov.py:258:6:258:26 | After Attribute() | After Attribute() | TarSlipImprov.py:261:25:261:29 | entry | entry | +| TarSlipImprov.py:268:21:268:25 | entry | TarSlipImprov.py:264:6:264:38 | After Attribute() | TarSlipImprov.py:268:21:268:25 | entry | Extraction of tarfile from $@ to a potentially untrusted source $@. | TarSlipImprov.py:264:6:264:38 | After Attribute() | After Attribute() | TarSlipImprov.py:268:21:268:25 | entry | entry | +| TarSlipImprov.py:274:25:274:29 | entry | TarSlipImprov.py:271:6:271:39 | After Attribute() | TarSlipImprov.py:274:25:274:29 | entry | Extraction of tarfile from $@ to a potentially untrusted source $@. | TarSlipImprov.py:271:6:271:39 | After Attribute() | After Attribute() | TarSlipImprov.py:274:25:274:29 | entry | entry | +| TarSlipImprov.py:280:21:280:25 | entry | TarSlipImprov.py:276:6:276:38 | After Attribute() | TarSlipImprov.py:280:21:280:25 | entry | Extraction of tarfile from $@ to a potentially untrusted source $@. | TarSlipImprov.py:276:6:276:38 | After Attribute() | After Attribute() | TarSlipImprov.py:280:21:280:25 | entry | entry | +| TarSlipImprov.py:284:5:284:7 | tar | TarSlipImprov.py:283:6:283:51 | After Attribute() | TarSlipImprov.py:284:5:284:7 | tar | Extraction of tarfile from $@ to a potentially untrusted source $@. | TarSlipImprov.py:283:6:283:51 | After Attribute() | After Attribute() | TarSlipImprov.py:284:5:284:7 | tar | tar | +| TarSlipImprov.py:288:49:288:51 | tar | TarSlipImprov.py:287:7:287:28 | After Attribute() | TarSlipImprov.py:288:49:288:51 | tar | Extraction of tarfile from $@ to a potentially untrusted source $@. | TarSlipImprov.py:287:7:287:28 | After Attribute() | After Attribute() | TarSlipImprov.py:288:49:288:51 | tar | tar | +| TarSlipImprov.py:293:1:293:3 | tar | TarSlipImprov.py:292:7:292:39 | After Attribute() | TarSlipImprov.py:293:1:293:3 | tar | Extraction of tarfile from $@ to a potentially untrusted source $@. | TarSlipImprov.py:292:7:292:39 | After Attribute() | After Attribute() | TarSlipImprov.py:293:1:293:3 | tar | tar | +| TarSlipImprov.py:301:49:301:51 | tar | TarSlipImprov.py:300:6:300:51 | After Attribute() | TarSlipImprov.py:301:49:301:51 | tar | Extraction of tarfile from $@ to a potentially untrusted source $@. | TarSlipImprov.py:300:6:300:51 | After Attribute() | After Attribute() | TarSlipImprov.py:301:49:301:51 | tar | tar | +| TarSlipImprov.py:310:49:310:54 | result | TarSlipImprov.py:304:7:304:39 | After Attribute() | TarSlipImprov.py:310:49:310:54 | result | Extraction of tarfile from $@ to a potentially untrusted source $@. | TarSlipImprov.py:304:7:304:39 | After Attribute() | After Attribute() | TarSlipImprov.py:310:49:310:54 | result | result | +| TarSlipImprov.py:316:1:316:46 | After Attribute() | TarSlipImprov.py:316:1:316:46 | After Attribute() | TarSlipImprov.py:316:1:316:46 | After Attribute() | Extraction of tarfile from $@ to a potentially untrusted source $@. | TarSlipImprov.py:316:1:316:46 | After Attribute() | After Attribute() | TarSlipImprov.py:316:1:316:46 | After Attribute() | After Attribute() | diff --git a/python/ql/test/experimental/query-tests/Security/CWE-022-TarSlip/ZipSlip.expected b/python/ql/test/experimental/query-tests/Security/CWE-022-TarSlip/ZipSlip.expected index 6b618335d810..4a0dd8c5b9f7 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-022-TarSlip/ZipSlip.expected +++ b/python/ql/test/experimental/query-tests/Security/CWE-022-TarSlip/ZipSlip.expected @@ -1,44 +1,44 @@ edges -| zipslip_bad.py:8:10:8:31 | ControlFlowNode for Attribute() | zipslip_bad.py:8:36:8:39 | ControlFlowNode for zipf | provenance | | -| zipslip_bad.py:8:36:8:39 | ControlFlowNode for zipf | zipslip_bad.py:10:13:10:17 | ControlFlowNode for entry | provenance | | -| zipslip_bad.py:10:13:10:17 | ControlFlowNode for entry | zipslip_bad.py:11:25:11:29 | ControlFlowNode for entry | provenance | | -| zipslip_bad.py:14:10:14:28 | ControlFlowNode for Attribute() | zipslip_bad.py:14:33:14:36 | ControlFlowNode for zipf | provenance | | -| zipslip_bad.py:14:33:14:36 | ControlFlowNode for zipf | zipslip_bad.py:16:13:16:17 | ControlFlowNode for entry | provenance | | -| zipslip_bad.py:16:13:16:17 | ControlFlowNode for entry | zipslip_bad.py:17:26:17:30 | ControlFlowNode for entry | provenance | | -| zipslip_bad.py:20:10:20:27 | ControlFlowNode for Attribute() | zipslip_bad.py:20:32:20:35 | ControlFlowNode for zipf | provenance | | -| zipslip_bad.py:20:32:20:35 | ControlFlowNode for zipf | zipslip_bad.py:22:13:22:17 | ControlFlowNode for entry | provenance | | -| zipslip_bad.py:22:13:22:17 | ControlFlowNode for entry | zipslip_bad.py:23:29:23:33 | ControlFlowNode for entry | provenance | | -| zipslip_bad.py:27:10:27:22 | ControlFlowNode for Attribute() | zipslip_bad.py:27:27:27:34 | ControlFlowNode for filelist | provenance | | -| zipslip_bad.py:27:27:27:34 | ControlFlowNode for filelist | zipslip_bad.py:29:13:29:13 | ControlFlowNode for x | provenance | | -| zipslip_bad.py:29:13:29:13 | ControlFlowNode for x | zipslip_bad.py:30:25:30:25 | ControlFlowNode for x | provenance | | -| zipslip_bad.py:34:5:34:12 | ControlFlowNode for filelist | zipslip_bad.py:35:9:35:9 | ControlFlowNode for x | provenance | | -| zipslip_bad.py:34:16:34:28 | ControlFlowNode for Attribute() | zipslip_bad.py:34:5:34:12 | ControlFlowNode for filelist | provenance | | -| zipslip_bad.py:35:9:35:9 | ControlFlowNode for x | zipslip_bad.py:37:32:37:32 | ControlFlowNode for x | provenance | | +| zipslip_bad.py:8:10:8:31 | After Attribute() | zipslip_bad.py:8:36:8:39 | zipf | provenance | | +| zipslip_bad.py:8:36:8:39 | zipf | zipslip_bad.py:10:13:10:17 | entry | provenance | | +| zipslip_bad.py:10:13:10:17 | entry | zipslip_bad.py:11:25:11:29 | entry | provenance | | +| zipslip_bad.py:14:10:14:28 | After Attribute() | zipslip_bad.py:14:33:14:36 | zipf | provenance | | +| zipslip_bad.py:14:33:14:36 | zipf | zipslip_bad.py:16:13:16:17 | entry | provenance | | +| zipslip_bad.py:16:13:16:17 | entry | zipslip_bad.py:17:26:17:30 | entry | provenance | | +| zipslip_bad.py:20:10:20:27 | After Attribute() | zipslip_bad.py:20:32:20:35 | zipf | provenance | | +| zipslip_bad.py:20:32:20:35 | zipf | zipslip_bad.py:22:13:22:17 | entry | provenance | | +| zipslip_bad.py:22:13:22:17 | entry | zipslip_bad.py:23:29:23:33 | entry | provenance | | +| zipslip_bad.py:27:10:27:22 | After Attribute() | zipslip_bad.py:27:27:27:34 | filelist | provenance | | +| zipslip_bad.py:27:27:27:34 | filelist | zipslip_bad.py:29:13:29:13 | x | provenance | | +| zipslip_bad.py:29:13:29:13 | x | zipslip_bad.py:30:25:30:25 | x | provenance | | +| zipslip_bad.py:34:5:34:12 | filelist | zipslip_bad.py:35:9:35:9 | x | provenance | | +| zipslip_bad.py:34:16:34:28 | After Attribute() | zipslip_bad.py:34:5:34:12 | filelist | provenance | | +| zipslip_bad.py:35:9:35:9 | x | zipslip_bad.py:37:32:37:32 | x | provenance | | nodes -| zipslip_bad.py:8:10:8:31 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| zipslip_bad.py:8:36:8:39 | ControlFlowNode for zipf | semmle.label | ControlFlowNode for zipf | -| zipslip_bad.py:10:13:10:17 | ControlFlowNode for entry | semmle.label | ControlFlowNode for entry | -| zipslip_bad.py:11:25:11:29 | ControlFlowNode for entry | semmle.label | ControlFlowNode for entry | -| zipslip_bad.py:14:10:14:28 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| zipslip_bad.py:14:33:14:36 | ControlFlowNode for zipf | semmle.label | ControlFlowNode for zipf | -| zipslip_bad.py:16:13:16:17 | ControlFlowNode for entry | semmle.label | ControlFlowNode for entry | -| zipslip_bad.py:17:26:17:30 | ControlFlowNode for entry | semmle.label | ControlFlowNode for entry | -| zipslip_bad.py:20:10:20:27 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| zipslip_bad.py:20:32:20:35 | ControlFlowNode for zipf | semmle.label | ControlFlowNode for zipf | -| zipslip_bad.py:22:13:22:17 | ControlFlowNode for entry | semmle.label | ControlFlowNode for entry | -| zipslip_bad.py:23:29:23:33 | ControlFlowNode for entry | semmle.label | ControlFlowNode for entry | -| zipslip_bad.py:27:10:27:22 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| zipslip_bad.py:27:27:27:34 | ControlFlowNode for filelist | semmle.label | ControlFlowNode for filelist | -| zipslip_bad.py:29:13:29:13 | ControlFlowNode for x | semmle.label | ControlFlowNode for x | -| zipslip_bad.py:30:25:30:25 | ControlFlowNode for x | semmle.label | ControlFlowNode for x | -| zipslip_bad.py:34:5:34:12 | ControlFlowNode for filelist | semmle.label | ControlFlowNode for filelist | -| zipslip_bad.py:34:16:34:28 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| zipslip_bad.py:35:9:35:9 | ControlFlowNode for x | semmle.label | ControlFlowNode for x | -| zipslip_bad.py:37:32:37:32 | ControlFlowNode for x | semmle.label | ControlFlowNode for x | +| zipslip_bad.py:8:10:8:31 | After Attribute() | semmle.label | After Attribute() | +| zipslip_bad.py:8:36:8:39 | zipf | semmle.label | zipf | +| zipslip_bad.py:10:13:10:17 | entry | semmle.label | entry | +| zipslip_bad.py:11:25:11:29 | entry | semmle.label | entry | +| zipslip_bad.py:14:10:14:28 | After Attribute() | semmle.label | After Attribute() | +| zipslip_bad.py:14:33:14:36 | zipf | semmle.label | zipf | +| zipslip_bad.py:16:13:16:17 | entry | semmle.label | entry | +| zipslip_bad.py:17:26:17:30 | entry | semmle.label | entry | +| zipslip_bad.py:20:10:20:27 | After Attribute() | semmle.label | After Attribute() | +| zipslip_bad.py:20:32:20:35 | zipf | semmle.label | zipf | +| zipslip_bad.py:22:13:22:17 | entry | semmle.label | entry | +| zipslip_bad.py:23:29:23:33 | entry | semmle.label | entry | +| zipslip_bad.py:27:10:27:22 | After Attribute() | semmle.label | After Attribute() | +| zipslip_bad.py:27:27:27:34 | filelist | semmle.label | filelist | +| zipslip_bad.py:29:13:29:13 | x | semmle.label | x | +| zipslip_bad.py:30:25:30:25 | x | semmle.label | x | +| zipslip_bad.py:34:5:34:12 | filelist | semmle.label | filelist | +| zipslip_bad.py:34:16:34:28 | After Attribute() | semmle.label | After Attribute() | +| zipslip_bad.py:35:9:35:9 | x | semmle.label | x | +| zipslip_bad.py:37:32:37:32 | x | semmle.label | x | subpaths #select -| zipslip_bad.py:8:10:8:31 | ControlFlowNode for Attribute() | zipslip_bad.py:8:10:8:31 | ControlFlowNode for Attribute() | zipslip_bad.py:11:25:11:29 | ControlFlowNode for entry | This unsanitized archive entry, which may contain '..', is used in a $@. | zipslip_bad.py:11:25:11:29 | ControlFlowNode for entry | file system operation | -| zipslip_bad.py:14:10:14:28 | ControlFlowNode for Attribute() | zipslip_bad.py:14:10:14:28 | ControlFlowNode for Attribute() | zipslip_bad.py:17:26:17:30 | ControlFlowNode for entry | This unsanitized archive entry, which may contain '..', is used in a $@. | zipslip_bad.py:17:26:17:30 | ControlFlowNode for entry | file system operation | -| zipslip_bad.py:20:10:20:27 | ControlFlowNode for Attribute() | zipslip_bad.py:20:10:20:27 | ControlFlowNode for Attribute() | zipslip_bad.py:23:29:23:33 | ControlFlowNode for entry | This unsanitized archive entry, which may contain '..', is used in a $@. | zipslip_bad.py:23:29:23:33 | ControlFlowNode for entry | file system operation | -| zipslip_bad.py:27:10:27:22 | ControlFlowNode for Attribute() | zipslip_bad.py:27:10:27:22 | ControlFlowNode for Attribute() | zipslip_bad.py:30:25:30:25 | ControlFlowNode for x | This unsanitized archive entry, which may contain '..', is used in a $@. | zipslip_bad.py:30:25:30:25 | ControlFlowNode for x | file system operation | -| zipslip_bad.py:34:16:34:28 | ControlFlowNode for Attribute() | zipslip_bad.py:34:16:34:28 | ControlFlowNode for Attribute() | zipslip_bad.py:37:32:37:32 | ControlFlowNode for x | This unsanitized archive entry, which may contain '..', is used in a $@. | zipslip_bad.py:37:32:37:32 | ControlFlowNode for x | file system operation | +| zipslip_bad.py:8:10:8:31 | After Attribute() | zipslip_bad.py:8:10:8:31 | After Attribute() | zipslip_bad.py:11:25:11:29 | entry | This unsanitized archive entry, which may contain '..', is used in a $@. | zipslip_bad.py:11:25:11:29 | entry | file system operation | +| zipslip_bad.py:14:10:14:28 | After Attribute() | zipslip_bad.py:14:10:14:28 | After Attribute() | zipslip_bad.py:17:26:17:30 | entry | This unsanitized archive entry, which may contain '..', is used in a $@. | zipslip_bad.py:17:26:17:30 | entry | file system operation | +| zipslip_bad.py:20:10:20:27 | After Attribute() | zipslip_bad.py:20:10:20:27 | After Attribute() | zipslip_bad.py:23:29:23:33 | entry | This unsanitized archive entry, which may contain '..', is used in a $@. | zipslip_bad.py:23:29:23:33 | entry | file system operation | +| zipslip_bad.py:27:10:27:22 | After Attribute() | zipslip_bad.py:27:10:27:22 | After Attribute() | zipslip_bad.py:30:25:30:25 | x | This unsanitized archive entry, which may contain '..', is used in a $@. | zipslip_bad.py:30:25:30:25 | x | file system operation | +| zipslip_bad.py:34:16:34:28 | After Attribute() | zipslip_bad.py:34:16:34:28 | After Attribute() | zipslip_bad.py:37:32:37:32 | x | This unsanitized archive entry, which may contain '..', is used in a $@. | zipslip_bad.py:37:32:37:32 | x | file system operation | diff --git a/python/ql/test/experimental/query-tests/Security/CWE-022-UnsafeUnpacking/UnsafeUnpack.expected b/python/ql/test/experimental/query-tests/Security/CWE-022-UnsafeUnpacking/UnsafeUnpack.expected index ccc2daba50bf..2041a991dca2 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-022-UnsafeUnpacking/UnsafeUnpack.expected +++ b/python/ql/test/experimental/query-tests/Security/CWE-022-UnsafeUnpacking/UnsafeUnpack.expected @@ -1,209 +1,208 @@ #select -| UnsafeUnpack.py:19:35:19:41 | ControlFlowNode for tarpath | UnsafeUnpack.py:5:26:5:32 | ControlFlowNode for ImportMember | UnsafeUnpack.py:19:35:19:41 | ControlFlowNode for tarpath | Unsafe extraction from a malicious tarball retrieved from a remote location. | -| UnsafeUnpack.py:34:23:34:38 | ControlFlowNode for local_ziped_path | UnsafeUnpack.py:33:50:33:65 | ControlFlowNode for local_ziped_path | UnsafeUnpack.py:34:23:34:38 | ControlFlowNode for local_ziped_path | Unsafe extraction from a malicious tarball retrieved from a remote location. | -| UnsafeUnpack.py:48:23:48:37 | ControlFlowNode for compressed_file | UnsafeUnpack.py:47:20:47:34 | ControlFlowNode for compressed_file | UnsafeUnpack.py:48:23:48:37 | ControlFlowNode for compressed_file | Unsafe extraction from a malicious tarball retrieved from a remote location. | -| UnsafeUnpack.py:52:23:52:37 | ControlFlowNode for compressed_file | UnsafeUnpack.py:51:19:51:36 | ControlFlowNode for Attribute() | UnsafeUnpack.py:52:23:52:37 | ControlFlowNode for compressed_file | Unsafe extraction from a malicious tarball retrieved from a remote location. | -| UnsafeUnpack.py:66:23:66:37 | ControlFlowNode for compressed_file | UnsafeUnpack.py:65:19:65:31 | ControlFlowNode for Attribute | UnsafeUnpack.py:66:23:66:37 | ControlFlowNode for compressed_file | Unsafe extraction from a malicious tarball retrieved from a remote location. | -| UnsafeUnpack.py:87:23:87:29 | ControlFlowNode for tarpath | UnsafeUnpack.py:79:16:79:28 | ControlFlowNode for Attribute | UnsafeUnpack.py:87:23:87:29 | ControlFlowNode for tarpath | Unsafe extraction from a malicious tarball retrieved from a remote location. | -| UnsafeUnpack.py:105:35:105:42 | ControlFlowNode for savepath | UnsafeUnpack.py:103:32:103:44 | ControlFlowNode for Attribute | UnsafeUnpack.py:105:35:105:42 | ControlFlowNode for savepath | Unsafe extraction from a malicious tarball retrieved from a remote location. | -| UnsafeUnpack.py:112:35:112:43 | ControlFlowNode for file_path | UnsafeUnpack.py:108:22:108:34 | ControlFlowNode for Attribute | UnsafeUnpack.py:112:35:112:43 | ControlFlowNode for file_path | Unsafe extraction from a malicious tarball retrieved from a remote location. | -| UnsafeUnpack.py:120:41:120:58 | ControlFlowNode for uploaded_file_path | UnsafeUnpack.py:116:27:116:39 | ControlFlowNode for Attribute | UnsafeUnpack.py:120:41:120:58 | ControlFlowNode for uploaded_file_path | Unsafe extraction from a malicious tarball retrieved from a remote location. | -| UnsafeUnpack.py:142:49:142:51 | ControlFlowNode for tar | UnsafeUnpack.py:140:23:140:35 | ControlFlowNode for Attribute | UnsafeUnpack.py:142:49:142:51 | ControlFlowNode for tar | Unsafe extraction from a malicious tarball retrieved from a remote location. | -| UnsafeUnpack.py:167:67:167:72 | ControlFlowNode for result | UnsafeUnpack.py:158:32:158:44 | ControlFlowNode for Attribute | UnsafeUnpack.py:167:67:167:72 | ControlFlowNode for result | Unsafe extraction from a malicious tarball retrieved from a remote location. | -| UnsafeUnpack.py:176:1:176:34 | ControlFlowNode for Attribute() | UnsafeUnpack.py:79:16:79:28 | ControlFlowNode for Attribute | UnsafeUnpack.py:176:1:176:34 | ControlFlowNode for Attribute() | Unsafe extraction from a malicious tarball retrieved from a remote location. | -| UnsafeUnpack.py:201:29:201:36 | ControlFlowNode for Attribute | UnsafeUnpack.py:194:53:194:55 | ControlFlowNode for tmp | UnsafeUnpack.py:201:29:201:36 | ControlFlowNode for Attribute | Unsafe extraction from a malicious tarball retrieved from a remote location. | +| UnsafeUnpack.py:19:35:19:41 | tarpath | UnsafeUnpack.py:5:26:5:32 | After ImportMember | UnsafeUnpack.py:19:35:19:41 | tarpath | Unsafe extraction from a malicious tarball retrieved from a remote location. | +| UnsafeUnpack.py:34:23:34:38 | local_ziped_path | UnsafeUnpack.py:33:50:33:65 | local_ziped_path | UnsafeUnpack.py:34:23:34:38 | local_ziped_path | Unsafe extraction from a malicious tarball retrieved from a remote location. | +| UnsafeUnpack.py:48:23:48:37 | compressed_file | UnsafeUnpack.py:47:20:47:34 | compressed_file | UnsafeUnpack.py:48:23:48:37 | compressed_file | Unsafe extraction from a malicious tarball retrieved from a remote location. | +| UnsafeUnpack.py:52:23:52:37 | compressed_file | UnsafeUnpack.py:51:19:51:36 | After Attribute() | UnsafeUnpack.py:52:23:52:37 | compressed_file | Unsafe extraction from a malicious tarball retrieved from a remote location. | +| UnsafeUnpack.py:66:23:66:37 | compressed_file | UnsafeUnpack.py:65:19:65:31 | After Attribute | UnsafeUnpack.py:66:23:66:37 | compressed_file | Unsafe extraction from a malicious tarball retrieved from a remote location. | +| UnsafeUnpack.py:87:23:87:29 | tarpath | UnsafeUnpack.py:79:16:79:28 | After Attribute | UnsafeUnpack.py:87:23:87:29 | tarpath | Unsafe extraction from a malicious tarball retrieved from a remote location. | +| UnsafeUnpack.py:105:35:105:42 | savepath | UnsafeUnpack.py:103:32:103:44 | After Attribute | UnsafeUnpack.py:105:35:105:42 | savepath | Unsafe extraction from a malicious tarball retrieved from a remote location. | +| UnsafeUnpack.py:112:35:112:43 | file_path | UnsafeUnpack.py:108:22:108:34 | After Attribute | UnsafeUnpack.py:112:35:112:43 | file_path | Unsafe extraction from a malicious tarball retrieved from a remote location. | +| UnsafeUnpack.py:120:41:120:58 | uploaded_file_path | UnsafeUnpack.py:116:27:116:39 | After Attribute | UnsafeUnpack.py:120:41:120:58 | uploaded_file_path | Unsafe extraction from a malicious tarball retrieved from a remote location. | +| UnsafeUnpack.py:142:49:142:51 | tar | UnsafeUnpack.py:140:23:140:35 | After Attribute | UnsafeUnpack.py:142:49:142:51 | tar | Unsafe extraction from a malicious tarball retrieved from a remote location. | +| UnsafeUnpack.py:167:67:167:72 | result | UnsafeUnpack.py:158:32:158:44 | After Attribute | UnsafeUnpack.py:167:67:167:72 | result | Unsafe extraction from a malicious tarball retrieved from a remote location. | +| UnsafeUnpack.py:176:1:176:34 | After Attribute() | UnsafeUnpack.py:79:16:79:28 | After Attribute | UnsafeUnpack.py:176:1:176:34 | After Attribute() | Unsafe extraction from a malicious tarball retrieved from a remote location. | +| UnsafeUnpack.py:201:29:201:36 | After Attribute | UnsafeUnpack.py:194:53:194:55 | tmp | UnsafeUnpack.py:201:29:201:36 | After Attribute | Unsafe extraction from a malicious tarball retrieved from a remote location. | edges -| UnsafeUnpack.py:5:26:5:32 | ControlFlowNode for ImportMember | UnsafeUnpack.py:5:26:5:32 | ControlFlowNode for request | provenance | | -| UnsafeUnpack.py:5:26:5:32 | ControlFlowNode for request | UnsafeUnpack.py:11:18:11:24 | ControlFlowNode for request | provenance | | -| UnsafeUnpack.py:11:7:11:14 | ControlFlowNode for filename | UnsafeUnpack.py:13:24:13:58 | ControlFlowNode for Attribute() | provenance | AdditionalTaintStep | -| UnsafeUnpack.py:11:18:11:24 | ControlFlowNode for request | UnsafeUnpack.py:11:18:11:29 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | -| UnsafeUnpack.py:11:18:11:29 | ControlFlowNode for Attribute | UnsafeUnpack.py:11:18:11:49 | ControlFlowNode for Attribute() | provenance | Config | -| UnsafeUnpack.py:11:18:11:29 | ControlFlowNode for Attribute | UnsafeUnpack.py:11:18:11:49 | ControlFlowNode for Attribute() | provenance | dict.get | -| UnsafeUnpack.py:11:18:11:49 | ControlFlowNode for Attribute() | UnsafeUnpack.py:11:7:11:14 | ControlFlowNode for filename | provenance | | -| UnsafeUnpack.py:13:13:13:20 | ControlFlowNode for response | UnsafeUnpack.py:17:27:17:34 | ControlFlowNode for response | provenance | | -| UnsafeUnpack.py:13:24:13:58 | ControlFlowNode for Attribute() | UnsafeUnpack.py:13:13:13:20 | ControlFlowNode for response | provenance | | -| UnsafeUnpack.py:16:23:16:29 | ControlFlowNode for tarpath | UnsafeUnpack.py:19:35:19:41 | ControlFlowNode for tarpath | provenance | | -| UnsafeUnpack.py:17:19:17:19 | ControlFlowNode for f | UnsafeUnpack.py:16:23:16:29 | ControlFlowNode for tarpath | provenance | Config | -| UnsafeUnpack.py:17:27:17:34 | ControlFlowNode for response | UnsafeUnpack.py:17:27:17:38 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | -| UnsafeUnpack.py:17:27:17:34 | ControlFlowNode for response | UnsafeUnpack.py:17:27:17:38 | ControlFlowNode for Attribute | provenance | Config | -| UnsafeUnpack.py:17:27:17:38 | ControlFlowNode for Attribute | UnsafeUnpack.py:17:27:17:45 | ControlFlowNode for Attribute() | provenance | AdditionalTaintStep | -| UnsafeUnpack.py:17:27:17:38 | ControlFlowNode for Attribute | UnsafeUnpack.py:17:27:17:45 | ControlFlowNode for Attribute() | provenance | Config | -| UnsafeUnpack.py:17:27:17:45 | ControlFlowNode for Attribute() | UnsafeUnpack.py:17:19:17:19 | ControlFlowNode for f | provenance | Config | -| UnsafeUnpack.py:33:50:33:65 | ControlFlowNode for local_ziped_path | UnsafeUnpack.py:34:23:34:38 | ControlFlowNode for local_ziped_path | provenance | | -| UnsafeUnpack.py:47:20:47:34 | ControlFlowNode for compressed_file | UnsafeUnpack.py:48:23:48:37 | ControlFlowNode for compressed_file | provenance | | -| UnsafeUnpack.py:51:1:51:15 | ControlFlowNode for compressed_file | UnsafeUnpack.py:52:23:52:37 | ControlFlowNode for compressed_file | provenance | | -| UnsafeUnpack.py:51:19:51:36 | ControlFlowNode for Attribute() | UnsafeUnpack.py:51:1:51:15 | ControlFlowNode for compressed_file | provenance | | -| UnsafeUnpack.py:65:1:65:15 | ControlFlowNode for compressed_file | UnsafeUnpack.py:66:23:66:37 | ControlFlowNode for compressed_file | provenance | | -| UnsafeUnpack.py:65:19:65:31 | ControlFlowNode for Attribute | UnsafeUnpack.py:65:1:65:15 | ControlFlowNode for compressed_file | provenance | | -| UnsafeUnpack.py:79:1:79:12 | ControlFlowNode for url_filename | UnsafeUnpack.py:81:12:81:50 | ControlFlowNode for Attribute() | provenance | AdditionalTaintStep | -| UnsafeUnpack.py:79:1:79:12 | ControlFlowNode for url_filename | UnsafeUnpack.py:171:12:171:50 | ControlFlowNode for Attribute() | provenance | AdditionalTaintStep | -| UnsafeUnpack.py:79:16:79:28 | ControlFlowNode for Attribute | UnsafeUnpack.py:79:1:79:12 | ControlFlowNode for url_filename | provenance | | -| UnsafeUnpack.py:81:1:81:8 | ControlFlowNode for response | UnsafeUnpack.py:85:15:85:22 | ControlFlowNode for response | provenance | | -| UnsafeUnpack.py:81:12:81:50 | ControlFlowNode for Attribute() | UnsafeUnpack.py:81:1:81:8 | ControlFlowNode for response | provenance | | -| UnsafeUnpack.py:84:11:84:17 | ControlFlowNode for tarpath | UnsafeUnpack.py:87:23:87:29 | ControlFlowNode for tarpath | provenance | | -| UnsafeUnpack.py:85:7:85:7 | ControlFlowNode for f | UnsafeUnpack.py:84:11:84:17 | ControlFlowNode for tarpath | provenance | Config | -| UnsafeUnpack.py:85:15:85:22 | ControlFlowNode for response | UnsafeUnpack.py:85:15:85:26 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | -| UnsafeUnpack.py:85:15:85:22 | ControlFlowNode for response | UnsafeUnpack.py:85:15:85:26 | ControlFlowNode for Attribute | provenance | Config | -| UnsafeUnpack.py:85:15:85:26 | ControlFlowNode for Attribute | UnsafeUnpack.py:85:15:85:33 | ControlFlowNode for Attribute() | provenance | AdditionalTaintStep | -| UnsafeUnpack.py:85:15:85:26 | ControlFlowNode for Attribute | UnsafeUnpack.py:85:15:85:33 | ControlFlowNode for Attribute() | provenance | Config | -| UnsafeUnpack.py:85:15:85:33 | ControlFlowNode for Attribute() | UnsafeUnpack.py:85:7:85:7 | ControlFlowNode for f | provenance | Config | -| UnsafeUnpack.py:102:23:102:30 | ControlFlowNode for savepath | UnsafeUnpack.py:105:35:105:42 | ControlFlowNode for savepath | provenance | | -| UnsafeUnpack.py:103:23:103:27 | ControlFlowNode for chunk | UnsafeUnpack.py:104:37:104:41 | ControlFlowNode for chunk | provenance | | -| UnsafeUnpack.py:103:32:103:44 | ControlFlowNode for Attribute | UnsafeUnpack.py:103:32:103:54 | ControlFlowNode for Subscript | provenance | | -| UnsafeUnpack.py:103:32:103:54 | ControlFlowNode for Subscript | UnsafeUnpack.py:103:32:103:63 | ControlFlowNode for Attribute() | provenance | Config | -| UnsafeUnpack.py:103:32:103:63 | ControlFlowNode for Attribute() | UnsafeUnpack.py:103:23:103:27 | ControlFlowNode for chunk | provenance | | -| UnsafeUnpack.py:104:25:104:29 | ControlFlowNode for wfile | UnsafeUnpack.py:102:23:102:30 | ControlFlowNode for savepath | provenance | Config | -| UnsafeUnpack.py:104:37:104:41 | ControlFlowNode for chunk | UnsafeUnpack.py:104:25:104:29 | ControlFlowNode for wfile | provenance | AdditionalTaintStep | -| UnsafeUnpack.py:104:37:104:41 | ControlFlowNode for chunk | UnsafeUnpack.py:104:25:104:29 | ControlFlowNode for wfile | provenance | Config | -| UnsafeUnpack.py:108:13:108:18 | ControlFlowNode for myfile | UnsafeUnpack.py:111:27:111:32 | ControlFlowNode for myfile | provenance | | -| UnsafeUnpack.py:108:22:108:34 | ControlFlowNode for Attribute | UnsafeUnpack.py:108:22:108:48 | ControlFlowNode for Attribute() | provenance | Config | -| UnsafeUnpack.py:108:22:108:34 | ControlFlowNode for Attribute | UnsafeUnpack.py:108:22:108:48 | ControlFlowNode for Attribute() | provenance | dict.get | -| UnsafeUnpack.py:108:22:108:48 | ControlFlowNode for Attribute() | UnsafeUnpack.py:108:13:108:18 | ControlFlowNode for myfile | provenance | | -| UnsafeUnpack.py:110:18:110:26 | ControlFlowNode for file_path | UnsafeUnpack.py:112:35:112:43 | ControlFlowNode for file_path | provenance | | -| UnsafeUnpack.py:111:19:111:19 | ControlFlowNode for f | UnsafeUnpack.py:110:18:110:26 | ControlFlowNode for file_path | provenance | Config | -| UnsafeUnpack.py:111:27:111:32 | ControlFlowNode for myfile | UnsafeUnpack.py:111:27:111:39 | ControlFlowNode for Attribute() | provenance | Config | -| UnsafeUnpack.py:111:27:111:39 | ControlFlowNode for Attribute() | UnsafeUnpack.py:111:19:111:19 | ControlFlowNode for f | provenance | Config | -| UnsafeUnpack.py:116:17:116:21 | ControlFlowNode for ufile | UnsafeUnpack.py:118:38:118:42 | ControlFlowNode for ufile | provenance | | -| UnsafeUnpack.py:116:27:116:39 | ControlFlowNode for Attribute | UnsafeUnpack.py:116:27:116:49 | ControlFlowNode for Attribute() | provenance | Config | -| UnsafeUnpack.py:116:27:116:49 | ControlFlowNode for Attribute() | UnsafeUnpack.py:116:17:116:21 | ControlFlowNode for ufile | provenance | | -| UnsafeUnpack.py:118:19:118:26 | ControlFlowNode for filename | UnsafeUnpack.py:119:48:119:55 | ControlFlowNode for filename | provenance | | -| UnsafeUnpack.py:118:30:118:55 | ControlFlowNode for Attribute() | UnsafeUnpack.py:118:19:118:26 | ControlFlowNode for filename | provenance | | -| UnsafeUnpack.py:118:38:118:42 | ControlFlowNode for ufile | UnsafeUnpack.py:118:38:118:47 | ControlFlowNode for Attribute | provenance | Config | -| UnsafeUnpack.py:118:38:118:47 | ControlFlowNode for Attribute | UnsafeUnpack.py:118:30:118:55 | ControlFlowNode for Attribute() | provenance | Config | -| UnsafeUnpack.py:119:19:119:36 | ControlFlowNode for uploaded_file_path | UnsafeUnpack.py:120:41:120:58 | ControlFlowNode for uploaded_file_path | provenance | | -| UnsafeUnpack.py:119:40:119:56 | ControlFlowNode for Attribute() | UnsafeUnpack.py:119:19:119:36 | ControlFlowNode for uploaded_file_path | provenance | | -| UnsafeUnpack.py:119:48:119:55 | ControlFlowNode for filename | UnsafeUnpack.py:119:40:119:56 | ControlFlowNode for Attribute() | provenance | Config | -| UnsafeUnpack.py:140:1:140:19 | ControlFlowNode for unsafe_filename_tar | UnsafeUnpack.py:141:22:141:40 | ControlFlowNode for unsafe_filename_tar | provenance | | -| UnsafeUnpack.py:140:23:140:35 | ControlFlowNode for Attribute | UnsafeUnpack.py:140:1:140:19 | ControlFlowNode for unsafe_filename_tar | provenance | | -| UnsafeUnpack.py:141:6:141:51 | ControlFlowNode for Attribute() | UnsafeUnpack.py:141:56:141:58 | ControlFlowNode for tar | provenance | | -| UnsafeUnpack.py:141:22:141:40 | ControlFlowNode for unsafe_filename_tar | UnsafeUnpack.py:141:6:141:51 | ControlFlowNode for Attribute() | provenance | Config | -| UnsafeUnpack.py:141:56:141:58 | ControlFlowNode for tar | UnsafeUnpack.py:142:49:142:51 | ControlFlowNode for tar | provenance | | -| UnsafeUnpack.py:157:23:157:30 | ControlFlowNode for savepath | UnsafeUnpack.py:161:38:161:45 | ControlFlowNode for savepath | provenance | | -| UnsafeUnpack.py:158:23:158:27 | ControlFlowNode for chunk | UnsafeUnpack.py:159:37:159:41 | ControlFlowNode for chunk | provenance | | -| UnsafeUnpack.py:158:32:158:44 | ControlFlowNode for Attribute | UnsafeUnpack.py:158:32:158:54 | ControlFlowNode for Subscript | provenance | | -| UnsafeUnpack.py:158:32:158:54 | ControlFlowNode for Subscript | UnsafeUnpack.py:158:32:158:63 | ControlFlowNode for Attribute() | provenance | Config | -| UnsafeUnpack.py:158:32:158:63 | ControlFlowNode for Attribute() | UnsafeUnpack.py:158:23:158:27 | ControlFlowNode for chunk | provenance | | -| UnsafeUnpack.py:159:25:159:29 | ControlFlowNode for wfile | UnsafeUnpack.py:157:23:157:30 | ControlFlowNode for savepath | provenance | Config | -| UnsafeUnpack.py:159:37:159:41 | ControlFlowNode for chunk | UnsafeUnpack.py:159:25:159:29 | ControlFlowNode for wfile | provenance | AdditionalTaintStep | -| UnsafeUnpack.py:159:37:159:41 | ControlFlowNode for chunk | UnsafeUnpack.py:159:25:159:29 | ControlFlowNode for wfile | provenance | Config | -| UnsafeUnpack.py:161:19:161:21 | ControlFlowNode for tar | UnsafeUnpack.py:163:33:163:35 | ControlFlowNode for tar | provenance | | -| UnsafeUnpack.py:161:25:161:46 | ControlFlowNode for Attribute() | UnsafeUnpack.py:161:19:161:21 | ControlFlowNode for tar | provenance | | -| UnsafeUnpack.py:161:38:161:45 | ControlFlowNode for savepath | UnsafeUnpack.py:161:25:161:46 | ControlFlowNode for Attribute() | provenance | Config | -| UnsafeUnpack.py:161:38:161:45 | ControlFlowNode for savepath | UnsafeUnpack.py:161:25:161:46 | ControlFlowNode for Attribute() | provenance | MaD:1 | -| UnsafeUnpack.py:163:23:163:28 | ControlFlowNode for member | UnsafeUnpack.py:166:37:166:42 | ControlFlowNode for member | provenance | | -| UnsafeUnpack.py:163:33:163:35 | ControlFlowNode for tar | UnsafeUnpack.py:163:23:163:28 | ControlFlowNode for member | provenance | | -| UnsafeUnpack.py:166:23:166:28 | [post] ControlFlowNode for result | UnsafeUnpack.py:167:67:167:72 | ControlFlowNode for result | provenance | | -| UnsafeUnpack.py:166:23:166:28 | [post] ControlFlowNode for result [List element] | UnsafeUnpack.py:167:67:167:72 | ControlFlowNode for result | provenance | | -| UnsafeUnpack.py:166:37:166:42 | ControlFlowNode for member | UnsafeUnpack.py:166:23:166:28 | [post] ControlFlowNode for result | provenance | list.append | -| UnsafeUnpack.py:166:37:166:42 | ControlFlowNode for member | UnsafeUnpack.py:166:23:166:28 | [post] ControlFlowNode for result [List element] | provenance | list.append | -| UnsafeUnpack.py:171:1:171:8 | ControlFlowNode for response | UnsafeUnpack.py:174:15:174:22 | ControlFlowNode for response | provenance | | -| UnsafeUnpack.py:171:12:171:50 | ControlFlowNode for Attribute() | UnsafeUnpack.py:171:1:171:8 | ControlFlowNode for response | provenance | | -| UnsafeUnpack.py:173:11:173:17 | ControlFlowNode for tarpath | UnsafeUnpack.py:176:17:176:23 | ControlFlowNode for tarpath | provenance | | -| UnsafeUnpack.py:174:7:174:7 | ControlFlowNode for f | UnsafeUnpack.py:173:11:173:17 | ControlFlowNode for tarpath | provenance | Config | -| UnsafeUnpack.py:174:15:174:22 | ControlFlowNode for response | UnsafeUnpack.py:174:15:174:26 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | -| UnsafeUnpack.py:174:15:174:22 | ControlFlowNode for response | UnsafeUnpack.py:174:15:174:26 | ControlFlowNode for Attribute | provenance | Config | -| UnsafeUnpack.py:174:15:174:26 | ControlFlowNode for Attribute | UnsafeUnpack.py:174:15:174:33 | ControlFlowNode for Attribute() | provenance | AdditionalTaintStep | -| UnsafeUnpack.py:174:15:174:26 | ControlFlowNode for Attribute | UnsafeUnpack.py:174:15:174:33 | ControlFlowNode for Attribute() | provenance | Config | -| UnsafeUnpack.py:174:15:174:33 | ControlFlowNode for Attribute() | UnsafeUnpack.py:174:7:174:7 | ControlFlowNode for f | provenance | Config | -| UnsafeUnpack.py:176:17:176:23 | ControlFlowNode for tarpath | UnsafeUnpack.py:176:1:176:34 | ControlFlowNode for Attribute() | provenance | Config | -| UnsafeUnpack.py:194:53:194:55 | ControlFlowNode for tmp | UnsafeUnpack.py:201:29:201:31 | ControlFlowNode for tmp | provenance | | -| UnsafeUnpack.py:201:29:201:31 | ControlFlowNode for tmp | UnsafeUnpack.py:201:29:201:36 | ControlFlowNode for Attribute | provenance | Config | +| UnsafeUnpack.py:5:26:5:32 | After ImportMember | UnsafeUnpack.py:5:26:5:32 | request | provenance | | +| UnsafeUnpack.py:5:26:5:32 | request | UnsafeUnpack.py:11:18:11:24 | request | provenance | | +| UnsafeUnpack.py:11:7:11:14 | filename | UnsafeUnpack.py:13:24:13:58 | After Attribute() | provenance | AdditionalTaintStep | +| UnsafeUnpack.py:11:18:11:24 | request | UnsafeUnpack.py:11:18:11:29 | After Attribute | provenance | AdditionalTaintStep | +| UnsafeUnpack.py:11:18:11:29 | After Attribute | UnsafeUnpack.py:11:18:11:49 | After Attribute() | provenance | Config | +| UnsafeUnpack.py:11:18:11:29 | After Attribute | UnsafeUnpack.py:11:18:11:49 | After Attribute() | provenance | dict.get | +| UnsafeUnpack.py:11:18:11:49 | After Attribute() | UnsafeUnpack.py:11:7:11:14 | filename | provenance | | +| UnsafeUnpack.py:13:13:13:20 | response | UnsafeUnpack.py:17:27:17:34 | response | provenance | | +| UnsafeUnpack.py:13:24:13:58 | After Attribute() | UnsafeUnpack.py:13:13:13:20 | response | provenance | | +| UnsafeUnpack.py:16:23:16:29 | tarpath | UnsafeUnpack.py:19:35:19:41 | tarpath | provenance | | +| UnsafeUnpack.py:17:19:17:19 | f | UnsafeUnpack.py:16:23:16:29 | tarpath | provenance | Config | +| UnsafeUnpack.py:17:27:17:34 | response | UnsafeUnpack.py:17:27:17:38 | After Attribute | provenance | AdditionalTaintStep | +| UnsafeUnpack.py:17:27:17:34 | response | UnsafeUnpack.py:17:27:17:38 | After Attribute | provenance | Config | +| UnsafeUnpack.py:17:27:17:38 | After Attribute | UnsafeUnpack.py:17:27:17:45 | After Attribute() | provenance | AdditionalTaintStep | +| UnsafeUnpack.py:17:27:17:38 | After Attribute | UnsafeUnpack.py:17:27:17:45 | After Attribute() | provenance | Config | +| UnsafeUnpack.py:17:27:17:45 | After Attribute() | UnsafeUnpack.py:17:19:17:19 | f | provenance | Config | +| UnsafeUnpack.py:33:50:33:65 | local_ziped_path | UnsafeUnpack.py:34:23:34:38 | local_ziped_path | provenance | | +| UnsafeUnpack.py:47:20:47:34 | compressed_file | UnsafeUnpack.py:48:23:48:37 | compressed_file | provenance | | +| UnsafeUnpack.py:51:1:51:15 | compressed_file | UnsafeUnpack.py:52:23:52:37 | compressed_file | provenance | | +| UnsafeUnpack.py:51:19:51:36 | After Attribute() | UnsafeUnpack.py:51:1:51:15 | compressed_file | provenance | | +| UnsafeUnpack.py:65:1:65:15 | compressed_file | UnsafeUnpack.py:66:23:66:37 | compressed_file | provenance | | +| UnsafeUnpack.py:65:19:65:31 | After Attribute | UnsafeUnpack.py:65:1:65:15 | compressed_file | provenance | | +| UnsafeUnpack.py:79:1:79:12 | url_filename | UnsafeUnpack.py:81:12:81:50 | After Attribute() | provenance | AdditionalTaintStep | +| UnsafeUnpack.py:79:1:79:12 | url_filename | UnsafeUnpack.py:171:12:171:50 | After Attribute() | provenance | AdditionalTaintStep | +| UnsafeUnpack.py:79:16:79:28 | After Attribute | UnsafeUnpack.py:79:1:79:12 | url_filename | provenance | | +| UnsafeUnpack.py:81:1:81:8 | response | UnsafeUnpack.py:85:15:85:22 | response | provenance | | +| UnsafeUnpack.py:81:12:81:50 | After Attribute() | UnsafeUnpack.py:81:1:81:8 | response | provenance | | +| UnsafeUnpack.py:84:11:84:17 | tarpath | UnsafeUnpack.py:87:23:87:29 | tarpath | provenance | | +| UnsafeUnpack.py:85:7:85:7 | f | UnsafeUnpack.py:84:11:84:17 | tarpath | provenance | Config | +| UnsafeUnpack.py:85:15:85:22 | response | UnsafeUnpack.py:85:15:85:26 | After Attribute | provenance | AdditionalTaintStep | +| UnsafeUnpack.py:85:15:85:22 | response | UnsafeUnpack.py:85:15:85:26 | After Attribute | provenance | Config | +| UnsafeUnpack.py:85:15:85:26 | After Attribute | UnsafeUnpack.py:85:15:85:33 | After Attribute() | provenance | AdditionalTaintStep | +| UnsafeUnpack.py:85:15:85:26 | After Attribute | UnsafeUnpack.py:85:15:85:33 | After Attribute() | provenance | Config | +| UnsafeUnpack.py:85:15:85:33 | After Attribute() | UnsafeUnpack.py:85:7:85:7 | f | provenance | Config | +| UnsafeUnpack.py:102:23:102:30 | savepath | UnsafeUnpack.py:105:35:105:42 | savepath | provenance | | +| UnsafeUnpack.py:103:23:103:27 | chunk | UnsafeUnpack.py:104:37:104:41 | chunk | provenance | | +| UnsafeUnpack.py:103:32:103:44 | After Attribute | UnsafeUnpack.py:103:32:103:54 | After Subscript | provenance | | +| UnsafeUnpack.py:103:32:103:54 | After Subscript | UnsafeUnpack.py:103:32:103:63 | After Attribute() [empty] | provenance | Config | +| UnsafeUnpack.py:103:32:103:63 | After Attribute() [empty] | UnsafeUnpack.py:103:23:103:27 | chunk | provenance | | +| UnsafeUnpack.py:104:25:104:29 | wfile | UnsafeUnpack.py:102:23:102:30 | savepath | provenance | Config | +| UnsafeUnpack.py:104:37:104:41 | chunk | UnsafeUnpack.py:104:25:104:29 | wfile | provenance | AdditionalTaintStep | +| UnsafeUnpack.py:104:37:104:41 | chunk | UnsafeUnpack.py:104:25:104:29 | wfile | provenance | Config | +| UnsafeUnpack.py:108:13:108:18 | myfile | UnsafeUnpack.py:111:27:111:32 | myfile | provenance | | +| UnsafeUnpack.py:108:22:108:34 | After Attribute | UnsafeUnpack.py:108:22:108:48 | After Attribute() | provenance | Config | +| UnsafeUnpack.py:108:22:108:34 | After Attribute | UnsafeUnpack.py:108:22:108:48 | After Attribute() | provenance | dict.get | +| UnsafeUnpack.py:108:22:108:48 | After Attribute() | UnsafeUnpack.py:108:13:108:18 | myfile | provenance | | +| UnsafeUnpack.py:110:18:110:26 | file_path | UnsafeUnpack.py:112:35:112:43 | file_path | provenance | | +| UnsafeUnpack.py:111:19:111:19 | f | UnsafeUnpack.py:110:18:110:26 | file_path | provenance | Config | +| UnsafeUnpack.py:111:27:111:32 | myfile | UnsafeUnpack.py:111:27:111:39 | After Attribute() | provenance | Config | +| UnsafeUnpack.py:111:27:111:39 | After Attribute() | UnsafeUnpack.py:111:19:111:19 | f | provenance | Config | +| UnsafeUnpack.py:116:17:116:21 | ufile | UnsafeUnpack.py:118:38:118:42 | ufile | provenance | | +| UnsafeUnpack.py:116:27:116:39 | After Attribute | UnsafeUnpack.py:116:27:116:49 | After Attribute() [empty] | provenance | Config | +| UnsafeUnpack.py:116:27:116:49 | After Attribute() [empty] | UnsafeUnpack.py:116:17:116:21 | ufile | provenance | | +| UnsafeUnpack.py:118:19:118:26 | filename | UnsafeUnpack.py:119:48:119:55 | filename | provenance | | +| UnsafeUnpack.py:118:30:118:55 | After Attribute() | UnsafeUnpack.py:118:19:118:26 | filename | provenance | | +| UnsafeUnpack.py:118:38:118:42 | ufile | UnsafeUnpack.py:118:38:118:47 | After Attribute | provenance | Config | +| UnsafeUnpack.py:118:38:118:47 | After Attribute | UnsafeUnpack.py:118:30:118:55 | After Attribute() | provenance | Config | +| UnsafeUnpack.py:119:19:119:36 | uploaded_file_path | UnsafeUnpack.py:120:41:120:58 | uploaded_file_path | provenance | | +| UnsafeUnpack.py:119:40:119:56 | After Attribute() | UnsafeUnpack.py:119:19:119:36 | uploaded_file_path | provenance | | +| UnsafeUnpack.py:119:48:119:55 | filename | UnsafeUnpack.py:119:40:119:56 | After Attribute() | provenance | Config | +| UnsafeUnpack.py:140:1:140:19 | unsafe_filename_tar | UnsafeUnpack.py:141:22:141:40 | unsafe_filename_tar | provenance | | +| UnsafeUnpack.py:140:23:140:35 | After Attribute | UnsafeUnpack.py:140:1:140:19 | unsafe_filename_tar | provenance | | +| UnsafeUnpack.py:141:6:141:51 | After Attribute() | UnsafeUnpack.py:141:56:141:58 | tar | provenance | | +| UnsafeUnpack.py:141:22:141:40 | unsafe_filename_tar | UnsafeUnpack.py:141:6:141:51 | After Attribute() | provenance | Config | +| UnsafeUnpack.py:141:56:141:58 | tar | UnsafeUnpack.py:142:49:142:51 | tar | provenance | | +| UnsafeUnpack.py:157:23:157:30 | savepath | UnsafeUnpack.py:161:38:161:45 | savepath | provenance | | +| UnsafeUnpack.py:158:23:158:27 | chunk | UnsafeUnpack.py:159:37:159:41 | chunk | provenance | | +| UnsafeUnpack.py:158:32:158:44 | After Attribute | UnsafeUnpack.py:158:32:158:54 | After Subscript | provenance | | +| UnsafeUnpack.py:158:32:158:54 | After Subscript | UnsafeUnpack.py:158:32:158:63 | After Attribute() [empty] | provenance | Config | +| UnsafeUnpack.py:158:32:158:63 | After Attribute() [empty] | UnsafeUnpack.py:158:23:158:27 | chunk | provenance | | +| UnsafeUnpack.py:159:25:159:29 | wfile | UnsafeUnpack.py:157:23:157:30 | savepath | provenance | Config | +| UnsafeUnpack.py:159:37:159:41 | chunk | UnsafeUnpack.py:159:25:159:29 | wfile | provenance | AdditionalTaintStep | +| UnsafeUnpack.py:159:37:159:41 | chunk | UnsafeUnpack.py:159:25:159:29 | wfile | provenance | Config | +| UnsafeUnpack.py:161:19:161:21 | tar | UnsafeUnpack.py:163:33:163:35 | After tar [empty] | provenance | | +| UnsafeUnpack.py:161:25:161:46 | After Attribute() | UnsafeUnpack.py:161:19:161:21 | tar | provenance | | +| UnsafeUnpack.py:161:38:161:45 | savepath | UnsafeUnpack.py:161:25:161:46 | After Attribute() | provenance | Config | +| UnsafeUnpack.py:161:38:161:45 | savepath | UnsafeUnpack.py:161:25:161:46 | After Attribute() | provenance | MaD:1 | +| UnsafeUnpack.py:163:23:163:28 | member | UnsafeUnpack.py:164:26:164:31 | member | provenance | | +| UnsafeUnpack.py:163:33:163:35 | After tar [empty] | UnsafeUnpack.py:163:23:163:28 | member | provenance | | +| UnsafeUnpack.py:164:26:164:31 | member | UnsafeUnpack.py:166:37:166:42 | member | provenance | | +| UnsafeUnpack.py:166:23:166:28 | [post] result | UnsafeUnpack.py:167:67:167:72 | result | provenance | | +| UnsafeUnpack.py:166:37:166:42 | member | UnsafeUnpack.py:166:23:166:28 | [post] result | provenance | list.append | +| UnsafeUnpack.py:171:1:171:8 | response | UnsafeUnpack.py:174:15:174:22 | response | provenance | | +| UnsafeUnpack.py:171:12:171:50 | After Attribute() | UnsafeUnpack.py:171:1:171:8 | response | provenance | | +| UnsafeUnpack.py:173:11:173:17 | tarpath | UnsafeUnpack.py:176:17:176:23 | tarpath | provenance | | +| UnsafeUnpack.py:174:7:174:7 | f | UnsafeUnpack.py:173:11:173:17 | tarpath | provenance | Config | +| UnsafeUnpack.py:174:15:174:22 | response | UnsafeUnpack.py:174:15:174:26 | After Attribute | provenance | AdditionalTaintStep | +| UnsafeUnpack.py:174:15:174:22 | response | UnsafeUnpack.py:174:15:174:26 | After Attribute | provenance | Config | +| UnsafeUnpack.py:174:15:174:26 | After Attribute | UnsafeUnpack.py:174:15:174:33 | After Attribute() | provenance | AdditionalTaintStep | +| UnsafeUnpack.py:174:15:174:26 | After Attribute | UnsafeUnpack.py:174:15:174:33 | After Attribute() | provenance | Config | +| UnsafeUnpack.py:174:15:174:33 | After Attribute() | UnsafeUnpack.py:174:7:174:7 | f | provenance | Config | +| UnsafeUnpack.py:176:17:176:23 | tarpath | UnsafeUnpack.py:176:1:176:34 | After Attribute() | provenance | Config | +| UnsafeUnpack.py:194:53:194:55 | tmp | UnsafeUnpack.py:201:29:201:31 | tmp | provenance | | +| UnsafeUnpack.py:201:29:201:31 | tmp | UnsafeUnpack.py:201:29:201:36 | After Attribute | provenance | Config | models | 1 | Summary: tarfile; Member[open]; Argument[0,name:,2,fileobj:]; ReturnValue; taint | nodes -| UnsafeUnpack.py:5:26:5:32 | ControlFlowNode for ImportMember | semmle.label | ControlFlowNode for ImportMember | -| UnsafeUnpack.py:5:26:5:32 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| UnsafeUnpack.py:11:7:11:14 | ControlFlowNode for filename | semmle.label | ControlFlowNode for filename | -| UnsafeUnpack.py:11:18:11:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| UnsafeUnpack.py:11:18:11:29 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| UnsafeUnpack.py:11:18:11:49 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| UnsafeUnpack.py:13:13:13:20 | ControlFlowNode for response | semmle.label | ControlFlowNode for response | -| UnsafeUnpack.py:13:24:13:58 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| UnsafeUnpack.py:16:23:16:29 | ControlFlowNode for tarpath | semmle.label | ControlFlowNode for tarpath | -| UnsafeUnpack.py:17:19:17:19 | ControlFlowNode for f | semmle.label | ControlFlowNode for f | -| UnsafeUnpack.py:17:27:17:34 | ControlFlowNode for response | semmle.label | ControlFlowNode for response | -| UnsafeUnpack.py:17:27:17:38 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| UnsafeUnpack.py:17:27:17:45 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| UnsafeUnpack.py:19:35:19:41 | ControlFlowNode for tarpath | semmle.label | ControlFlowNode for tarpath | -| UnsafeUnpack.py:33:50:33:65 | ControlFlowNode for local_ziped_path | semmle.label | ControlFlowNode for local_ziped_path | -| UnsafeUnpack.py:34:23:34:38 | ControlFlowNode for local_ziped_path | semmle.label | ControlFlowNode for local_ziped_path | -| UnsafeUnpack.py:47:20:47:34 | ControlFlowNode for compressed_file | semmle.label | ControlFlowNode for compressed_file | -| UnsafeUnpack.py:48:23:48:37 | ControlFlowNode for compressed_file | semmle.label | ControlFlowNode for compressed_file | -| UnsafeUnpack.py:51:1:51:15 | ControlFlowNode for compressed_file | semmle.label | ControlFlowNode for compressed_file | -| UnsafeUnpack.py:51:19:51:36 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| UnsafeUnpack.py:52:23:52:37 | ControlFlowNode for compressed_file | semmle.label | ControlFlowNode for compressed_file | -| UnsafeUnpack.py:65:1:65:15 | ControlFlowNode for compressed_file | semmle.label | ControlFlowNode for compressed_file | -| UnsafeUnpack.py:65:19:65:31 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| UnsafeUnpack.py:66:23:66:37 | ControlFlowNode for compressed_file | semmle.label | ControlFlowNode for compressed_file | -| UnsafeUnpack.py:79:1:79:12 | ControlFlowNode for url_filename | semmle.label | ControlFlowNode for url_filename | -| UnsafeUnpack.py:79:16:79:28 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| UnsafeUnpack.py:81:1:81:8 | ControlFlowNode for response | semmle.label | ControlFlowNode for response | -| UnsafeUnpack.py:81:12:81:50 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| UnsafeUnpack.py:84:11:84:17 | ControlFlowNode for tarpath | semmle.label | ControlFlowNode for tarpath | -| UnsafeUnpack.py:85:7:85:7 | ControlFlowNode for f | semmle.label | ControlFlowNode for f | -| UnsafeUnpack.py:85:15:85:22 | ControlFlowNode for response | semmle.label | ControlFlowNode for response | -| UnsafeUnpack.py:85:15:85:26 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| UnsafeUnpack.py:85:15:85:33 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| UnsafeUnpack.py:87:23:87:29 | ControlFlowNode for tarpath | semmle.label | ControlFlowNode for tarpath | -| UnsafeUnpack.py:102:23:102:30 | ControlFlowNode for savepath | semmle.label | ControlFlowNode for savepath | -| UnsafeUnpack.py:103:23:103:27 | ControlFlowNode for chunk | semmle.label | ControlFlowNode for chunk | -| UnsafeUnpack.py:103:32:103:44 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| UnsafeUnpack.py:103:32:103:54 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript | -| UnsafeUnpack.py:103:32:103:63 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| UnsafeUnpack.py:104:25:104:29 | ControlFlowNode for wfile | semmle.label | ControlFlowNode for wfile | -| UnsafeUnpack.py:104:37:104:41 | ControlFlowNode for chunk | semmle.label | ControlFlowNode for chunk | -| UnsafeUnpack.py:105:35:105:42 | ControlFlowNode for savepath | semmle.label | ControlFlowNode for savepath | -| UnsafeUnpack.py:108:13:108:18 | ControlFlowNode for myfile | semmle.label | ControlFlowNode for myfile | -| UnsafeUnpack.py:108:22:108:34 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| UnsafeUnpack.py:108:22:108:48 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| UnsafeUnpack.py:110:18:110:26 | ControlFlowNode for file_path | semmle.label | ControlFlowNode for file_path | -| UnsafeUnpack.py:111:19:111:19 | ControlFlowNode for f | semmle.label | ControlFlowNode for f | -| UnsafeUnpack.py:111:27:111:32 | ControlFlowNode for myfile | semmle.label | ControlFlowNode for myfile | -| UnsafeUnpack.py:111:27:111:39 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| UnsafeUnpack.py:112:35:112:43 | ControlFlowNode for file_path | semmle.label | ControlFlowNode for file_path | -| UnsafeUnpack.py:116:17:116:21 | ControlFlowNode for ufile | semmle.label | ControlFlowNode for ufile | -| UnsafeUnpack.py:116:27:116:39 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| UnsafeUnpack.py:116:27:116:49 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| UnsafeUnpack.py:118:19:118:26 | ControlFlowNode for filename | semmle.label | ControlFlowNode for filename | -| UnsafeUnpack.py:118:30:118:55 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| UnsafeUnpack.py:118:38:118:42 | ControlFlowNode for ufile | semmle.label | ControlFlowNode for ufile | -| UnsafeUnpack.py:118:38:118:47 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| UnsafeUnpack.py:119:19:119:36 | ControlFlowNode for uploaded_file_path | semmle.label | ControlFlowNode for uploaded_file_path | -| UnsafeUnpack.py:119:40:119:56 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| UnsafeUnpack.py:119:48:119:55 | ControlFlowNode for filename | semmle.label | ControlFlowNode for filename | -| UnsafeUnpack.py:120:41:120:58 | ControlFlowNode for uploaded_file_path | semmle.label | ControlFlowNode for uploaded_file_path | -| UnsafeUnpack.py:140:1:140:19 | ControlFlowNode for unsafe_filename_tar | semmle.label | ControlFlowNode for unsafe_filename_tar | -| UnsafeUnpack.py:140:23:140:35 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| UnsafeUnpack.py:141:6:141:51 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| UnsafeUnpack.py:141:22:141:40 | ControlFlowNode for unsafe_filename_tar | semmle.label | ControlFlowNode for unsafe_filename_tar | -| UnsafeUnpack.py:141:56:141:58 | ControlFlowNode for tar | semmle.label | ControlFlowNode for tar | -| UnsafeUnpack.py:142:49:142:51 | ControlFlowNode for tar | semmle.label | ControlFlowNode for tar | -| UnsafeUnpack.py:157:23:157:30 | ControlFlowNode for savepath | semmle.label | ControlFlowNode for savepath | -| UnsafeUnpack.py:158:23:158:27 | ControlFlowNode for chunk | semmle.label | ControlFlowNode for chunk | -| UnsafeUnpack.py:158:32:158:44 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| UnsafeUnpack.py:158:32:158:54 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript | -| UnsafeUnpack.py:158:32:158:63 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| UnsafeUnpack.py:159:25:159:29 | ControlFlowNode for wfile | semmle.label | ControlFlowNode for wfile | -| UnsafeUnpack.py:159:37:159:41 | ControlFlowNode for chunk | semmle.label | ControlFlowNode for chunk | -| UnsafeUnpack.py:161:19:161:21 | ControlFlowNode for tar | semmle.label | ControlFlowNode for tar | -| UnsafeUnpack.py:161:25:161:46 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| UnsafeUnpack.py:161:38:161:45 | ControlFlowNode for savepath | semmle.label | ControlFlowNode for savepath | -| UnsafeUnpack.py:163:23:163:28 | ControlFlowNode for member | semmle.label | ControlFlowNode for member | -| UnsafeUnpack.py:163:33:163:35 | ControlFlowNode for tar | semmle.label | ControlFlowNode for tar | -| UnsafeUnpack.py:166:23:166:28 | [post] ControlFlowNode for result | semmle.label | [post] ControlFlowNode for result | -| UnsafeUnpack.py:166:23:166:28 | [post] ControlFlowNode for result [List element] | semmle.label | [post] ControlFlowNode for result [List element] | -| UnsafeUnpack.py:166:37:166:42 | ControlFlowNode for member | semmle.label | ControlFlowNode for member | -| UnsafeUnpack.py:167:67:167:72 | ControlFlowNode for result | semmle.label | ControlFlowNode for result | -| UnsafeUnpack.py:171:1:171:8 | ControlFlowNode for response | semmle.label | ControlFlowNode for response | -| UnsafeUnpack.py:171:12:171:50 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| UnsafeUnpack.py:173:11:173:17 | ControlFlowNode for tarpath | semmle.label | ControlFlowNode for tarpath | -| UnsafeUnpack.py:174:7:174:7 | ControlFlowNode for f | semmle.label | ControlFlowNode for f | -| UnsafeUnpack.py:174:15:174:22 | ControlFlowNode for response | semmle.label | ControlFlowNode for response | -| UnsafeUnpack.py:174:15:174:26 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| UnsafeUnpack.py:174:15:174:33 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| UnsafeUnpack.py:176:1:176:34 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| UnsafeUnpack.py:176:17:176:23 | ControlFlowNode for tarpath | semmle.label | ControlFlowNode for tarpath | -| UnsafeUnpack.py:194:53:194:55 | ControlFlowNode for tmp | semmle.label | ControlFlowNode for tmp | -| UnsafeUnpack.py:201:29:201:31 | ControlFlowNode for tmp | semmle.label | ControlFlowNode for tmp | -| UnsafeUnpack.py:201:29:201:36 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | +| UnsafeUnpack.py:5:26:5:32 | After ImportMember | semmle.label | After ImportMember | +| UnsafeUnpack.py:5:26:5:32 | request | semmle.label | request | +| UnsafeUnpack.py:11:7:11:14 | filename | semmle.label | filename | +| UnsafeUnpack.py:11:18:11:24 | request | semmle.label | request | +| UnsafeUnpack.py:11:18:11:29 | After Attribute | semmle.label | After Attribute | +| UnsafeUnpack.py:11:18:11:49 | After Attribute() | semmle.label | After Attribute() | +| UnsafeUnpack.py:13:13:13:20 | response | semmle.label | response | +| UnsafeUnpack.py:13:24:13:58 | After Attribute() | semmle.label | After Attribute() | +| UnsafeUnpack.py:16:23:16:29 | tarpath | semmle.label | tarpath | +| UnsafeUnpack.py:17:19:17:19 | f | semmle.label | f | +| UnsafeUnpack.py:17:27:17:34 | response | semmle.label | response | +| UnsafeUnpack.py:17:27:17:38 | After Attribute | semmle.label | After Attribute | +| UnsafeUnpack.py:17:27:17:45 | After Attribute() | semmle.label | After Attribute() | +| UnsafeUnpack.py:19:35:19:41 | tarpath | semmle.label | tarpath | +| UnsafeUnpack.py:33:50:33:65 | local_ziped_path | semmle.label | local_ziped_path | +| UnsafeUnpack.py:34:23:34:38 | local_ziped_path | semmle.label | local_ziped_path | +| UnsafeUnpack.py:47:20:47:34 | compressed_file | semmle.label | compressed_file | +| UnsafeUnpack.py:48:23:48:37 | compressed_file | semmle.label | compressed_file | +| UnsafeUnpack.py:51:1:51:15 | compressed_file | semmle.label | compressed_file | +| UnsafeUnpack.py:51:19:51:36 | After Attribute() | semmle.label | After Attribute() | +| UnsafeUnpack.py:52:23:52:37 | compressed_file | semmle.label | compressed_file | +| UnsafeUnpack.py:65:1:65:15 | compressed_file | semmle.label | compressed_file | +| UnsafeUnpack.py:65:19:65:31 | After Attribute | semmle.label | After Attribute | +| UnsafeUnpack.py:66:23:66:37 | compressed_file | semmle.label | compressed_file | +| UnsafeUnpack.py:79:1:79:12 | url_filename | semmle.label | url_filename | +| UnsafeUnpack.py:79:16:79:28 | After Attribute | semmle.label | After Attribute | +| UnsafeUnpack.py:81:1:81:8 | response | semmle.label | response | +| UnsafeUnpack.py:81:12:81:50 | After Attribute() | semmle.label | After Attribute() | +| UnsafeUnpack.py:84:11:84:17 | tarpath | semmle.label | tarpath | +| UnsafeUnpack.py:85:7:85:7 | f | semmle.label | f | +| UnsafeUnpack.py:85:15:85:22 | response | semmle.label | response | +| UnsafeUnpack.py:85:15:85:26 | After Attribute | semmle.label | After Attribute | +| UnsafeUnpack.py:85:15:85:33 | After Attribute() | semmle.label | After Attribute() | +| UnsafeUnpack.py:87:23:87:29 | tarpath | semmle.label | tarpath | +| UnsafeUnpack.py:102:23:102:30 | savepath | semmle.label | savepath | +| UnsafeUnpack.py:103:23:103:27 | chunk | semmle.label | chunk | +| UnsafeUnpack.py:103:32:103:44 | After Attribute | semmle.label | After Attribute | +| UnsafeUnpack.py:103:32:103:54 | After Subscript | semmle.label | After Subscript | +| UnsafeUnpack.py:103:32:103:63 | After Attribute() [empty] | semmle.label | After Attribute() [empty] | +| UnsafeUnpack.py:104:25:104:29 | wfile | semmle.label | wfile | +| UnsafeUnpack.py:104:37:104:41 | chunk | semmle.label | chunk | +| UnsafeUnpack.py:105:35:105:42 | savepath | semmle.label | savepath | +| UnsafeUnpack.py:108:13:108:18 | myfile | semmle.label | myfile | +| UnsafeUnpack.py:108:22:108:34 | After Attribute | semmle.label | After Attribute | +| UnsafeUnpack.py:108:22:108:48 | After Attribute() | semmle.label | After Attribute() | +| UnsafeUnpack.py:110:18:110:26 | file_path | semmle.label | file_path | +| UnsafeUnpack.py:111:19:111:19 | f | semmle.label | f | +| UnsafeUnpack.py:111:27:111:32 | myfile | semmle.label | myfile | +| UnsafeUnpack.py:111:27:111:39 | After Attribute() | semmle.label | After Attribute() | +| UnsafeUnpack.py:112:35:112:43 | file_path | semmle.label | file_path | +| UnsafeUnpack.py:116:17:116:21 | ufile | semmle.label | ufile | +| UnsafeUnpack.py:116:27:116:39 | After Attribute | semmle.label | After Attribute | +| UnsafeUnpack.py:116:27:116:49 | After Attribute() [empty] | semmle.label | After Attribute() [empty] | +| UnsafeUnpack.py:118:19:118:26 | filename | semmle.label | filename | +| UnsafeUnpack.py:118:30:118:55 | After Attribute() | semmle.label | After Attribute() | +| UnsafeUnpack.py:118:38:118:42 | ufile | semmle.label | ufile | +| UnsafeUnpack.py:118:38:118:47 | After Attribute | semmle.label | After Attribute | +| UnsafeUnpack.py:119:19:119:36 | uploaded_file_path | semmle.label | uploaded_file_path | +| UnsafeUnpack.py:119:40:119:56 | After Attribute() | semmle.label | After Attribute() | +| UnsafeUnpack.py:119:48:119:55 | filename | semmle.label | filename | +| UnsafeUnpack.py:120:41:120:58 | uploaded_file_path | semmle.label | uploaded_file_path | +| UnsafeUnpack.py:140:1:140:19 | unsafe_filename_tar | semmle.label | unsafe_filename_tar | +| UnsafeUnpack.py:140:23:140:35 | After Attribute | semmle.label | After Attribute | +| UnsafeUnpack.py:141:6:141:51 | After Attribute() | semmle.label | After Attribute() | +| UnsafeUnpack.py:141:22:141:40 | unsafe_filename_tar | semmle.label | unsafe_filename_tar | +| UnsafeUnpack.py:141:56:141:58 | tar | semmle.label | tar | +| UnsafeUnpack.py:142:49:142:51 | tar | semmle.label | tar | +| UnsafeUnpack.py:157:23:157:30 | savepath | semmle.label | savepath | +| UnsafeUnpack.py:158:23:158:27 | chunk | semmle.label | chunk | +| UnsafeUnpack.py:158:32:158:44 | After Attribute | semmle.label | After Attribute | +| UnsafeUnpack.py:158:32:158:54 | After Subscript | semmle.label | After Subscript | +| UnsafeUnpack.py:158:32:158:63 | After Attribute() [empty] | semmle.label | After Attribute() [empty] | +| UnsafeUnpack.py:159:25:159:29 | wfile | semmle.label | wfile | +| UnsafeUnpack.py:159:37:159:41 | chunk | semmle.label | chunk | +| UnsafeUnpack.py:161:19:161:21 | tar | semmle.label | tar | +| UnsafeUnpack.py:161:25:161:46 | After Attribute() | semmle.label | After Attribute() | +| UnsafeUnpack.py:161:38:161:45 | savepath | semmle.label | savepath | +| UnsafeUnpack.py:163:23:163:28 | member | semmle.label | member | +| UnsafeUnpack.py:163:33:163:35 | After tar [empty] | semmle.label | After tar [empty] | +| UnsafeUnpack.py:164:26:164:31 | member | semmle.label | member | +| UnsafeUnpack.py:166:23:166:28 | [post] result | semmle.label | [post] result | +| UnsafeUnpack.py:166:37:166:42 | member | semmle.label | member | +| UnsafeUnpack.py:167:67:167:72 | result | semmle.label | result | +| UnsafeUnpack.py:171:1:171:8 | response | semmle.label | response | +| UnsafeUnpack.py:171:12:171:50 | After Attribute() | semmle.label | After Attribute() | +| UnsafeUnpack.py:173:11:173:17 | tarpath | semmle.label | tarpath | +| UnsafeUnpack.py:174:7:174:7 | f | semmle.label | f | +| UnsafeUnpack.py:174:15:174:22 | response | semmle.label | response | +| UnsafeUnpack.py:174:15:174:26 | After Attribute | semmle.label | After Attribute | +| UnsafeUnpack.py:174:15:174:33 | After Attribute() | semmle.label | After Attribute() | +| UnsafeUnpack.py:176:1:176:34 | After Attribute() | semmle.label | After Attribute() | +| UnsafeUnpack.py:176:17:176:23 | tarpath | semmle.label | tarpath | +| UnsafeUnpack.py:194:53:194:55 | tmp | semmle.label | tmp | +| UnsafeUnpack.py:201:29:201:31 | tmp | semmle.label | tmp | +| UnsafeUnpack.py:201:29:201:36 | After Attribute | semmle.label | After Attribute | subpaths diff --git a/python/ql/test/experimental/query-tests/Security/CWE-074-RemoteCommandExecution/RemoteCommandExecution.expected b/python/ql/test/experimental/query-tests/Security/CWE-074-RemoteCommandExecution/RemoteCommandExecution.expected index 9ae14db94676..1eb9694fedd4 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-074-RemoteCommandExecution/RemoteCommandExecution.expected +++ b/python/ql/test/experimental/query-tests/Security/CWE-074-RemoteCommandExecution/RemoteCommandExecution.expected @@ -1,92 +1,88 @@ edges -| AsyncSsh.py:15:16:15:18 | ControlFlowNode for cmd | AsyncSsh.py:17:33:17:35 | ControlFlowNode for cmd | provenance | | -| Netmiko.py:18:16:18:18 | ControlFlowNode for cmd | Netmiko.py:20:45:20:47 | ControlFlowNode for cmd | provenance | | -| Netmiko.py:18:16:18:18 | ControlFlowNode for cmd | Netmiko.py:21:52:21:54 | ControlFlowNode for cmd | provenance | | -| Netmiko.py:18:16:18:18 | ControlFlowNode for cmd | Netmiko.py:22:52:22:54 | ControlFlowNode for cmd | provenance | | -| Netmiko.py:18:16:18:18 | ControlFlowNode for cmd | Netmiko.py:23:43:23:45 | ControlFlowNode for cmd | provenance | | -| Netmiko.py:18:16:18:18 | ControlFlowNode for cmd | Netmiko.py:24:48:24:50 | ControlFlowNode for cmd | provenance | | -| Netmiko.py:23:42:23:56 | ControlFlowNode for List [List element] | Netmiko.py:23:41:23:57 | ControlFlowNode for List | provenance | | -| Netmiko.py:23:43:23:45 | ControlFlowNode for cmd | Netmiko.py:23:42:23:56 | ControlFlowNode for List [List element] | provenance | | -| Pexpect.py:15:16:15:18 | ControlFlowNode for cmd | Pexpect.py:16:14:16:16 | ControlFlowNode for cmd | provenance | | -| Pexpect.py:15:16:15:18 | ControlFlowNode for cmd | Pexpect.py:18:18:18:20 | ControlFlowNode for cmd | provenance | | -| Scrapli.py:13:16:13:18 | ControlFlowNode for cmd | Scrapli.py:24:42:24:44 | ControlFlowNode for cmd | provenance | | -| Scrapli.py:13:16:13:18 | ControlFlowNode for cmd | Scrapli.py:27:42:27:44 | ControlFlowNode for cmd | provenance | | -| Scrapli.py:13:16:13:18 | ControlFlowNode for cmd | Scrapli.py:30:42:30:44 | ControlFlowNode for cmd | provenance | | -| Scrapli.py:13:16:13:18 | ControlFlowNode for cmd | Scrapli.py:33:42:33:44 | ControlFlowNode for cmd | provenance | | -| Scrapli.py:13:16:13:18 | ControlFlowNode for cmd | Scrapli.py:36:42:36:44 | ControlFlowNode for cmd | provenance | | -| Scrapli.py:40:10:40:12 | ControlFlowNode for cmd | Scrapli.py:51:36:51:38 | ControlFlowNode for cmd | provenance | | -| Scrapli.py:40:10:40:12 | ControlFlowNode for cmd | Scrapli.py:54:36:54:38 | ControlFlowNode for cmd | provenance | | -| Scrapli.py:40:10:40:12 | ControlFlowNode for cmd | Scrapli.py:57:36:57:38 | ControlFlowNode for cmd | provenance | | -| Scrapli.py:40:10:40:12 | ControlFlowNode for cmd | Scrapli.py:60:36:60:38 | ControlFlowNode for cmd | provenance | | -| Scrapli.py:40:10:40:12 | ControlFlowNode for cmd | Scrapli.py:63:36:63:38 | ControlFlowNode for cmd | provenance | | -| Scrapli.py:40:10:40:12 | ControlFlowNode for cmd | Scrapli.py:74:36:74:38 | ControlFlowNode for cmd | provenance | | -| Scrapli.py:40:10:40:12 | ControlFlowNode for cmd | Scrapli.py:84:36:84:38 | ControlFlowNode for cmd | provenance | | -| Twisted.py:13:16:13:18 | ControlFlowNode for cmd | Twisted.py:16:5:16:7 | ControlFlowNode for cmd | provenance | | -| Twisted.py:13:16:13:18 | ControlFlowNode for cmd | Twisted.py:24:9:24:11 | ControlFlowNode for cmd | provenance | | -| paramiko.py:15:16:15:18 | ControlFlowNode for cmd | paramiko.py:16:62:16:64 | ControlFlowNode for cmd | provenance | | -| paramiko.py:20:16:20:18 | ControlFlowNode for cmd | paramiko.py:21:70:21:72 | ControlFlowNode for cmd | provenance | | -| ssh2.py:15:16:15:18 | ControlFlowNode for cmd | ssh2.py:17:21:17:23 | ControlFlowNode for cmd | provenance | | +| AsyncSsh.py:15:16:15:18 | cmd | AsyncSsh.py:17:33:17:35 | cmd | provenance | | +| Netmiko.py:18:16:18:18 | cmd | Netmiko.py:20:45:20:47 | cmd | provenance | | +| Netmiko.py:18:16:18:18 | cmd | Netmiko.py:21:52:21:54 | cmd | provenance | | +| Netmiko.py:18:16:18:18 | cmd | Netmiko.py:22:52:22:54 | cmd | provenance | | +| Netmiko.py:18:16:18:18 | cmd | Netmiko.py:23:41:23:57 | After List | provenance | | +| Netmiko.py:18:16:18:18 | cmd | Netmiko.py:24:48:24:50 | cmd | provenance | | +| Pexpect.py:15:16:15:18 | cmd | Pexpect.py:16:14:16:16 | cmd | provenance | | +| Pexpect.py:15:16:15:18 | cmd | Pexpect.py:18:18:18:20 | cmd | provenance | | +| Scrapli.py:13:16:13:18 | cmd | Scrapli.py:24:42:24:44 | cmd | provenance | | +| Scrapli.py:13:16:13:18 | cmd | Scrapli.py:27:42:27:44 | cmd | provenance | | +| Scrapli.py:13:16:13:18 | cmd | Scrapli.py:30:42:30:44 | cmd | provenance | | +| Scrapli.py:13:16:13:18 | cmd | Scrapli.py:33:42:33:44 | cmd | provenance | | +| Scrapli.py:13:16:13:18 | cmd | Scrapli.py:36:42:36:44 | cmd | provenance | | +| Scrapli.py:40:10:40:12 | cmd | Scrapli.py:51:36:51:38 | cmd | provenance | | +| Scrapli.py:40:10:40:12 | cmd | Scrapli.py:54:36:54:38 | cmd | provenance | | +| Scrapli.py:40:10:40:12 | cmd | Scrapli.py:57:36:57:38 | cmd | provenance | | +| Scrapli.py:40:10:40:12 | cmd | Scrapli.py:60:36:60:38 | cmd | provenance | | +| Scrapli.py:40:10:40:12 | cmd | Scrapli.py:63:36:63:38 | cmd | provenance | | +| Scrapli.py:40:10:40:12 | cmd | Scrapli.py:74:36:74:38 | cmd | provenance | | +| Scrapli.py:40:10:40:12 | cmd | Scrapli.py:84:36:84:38 | cmd | provenance | | +| Twisted.py:13:16:13:18 | cmd | Twisted.py:16:5:16:7 | cmd | provenance | | +| Twisted.py:13:16:13:18 | cmd | Twisted.py:24:9:24:11 | cmd | provenance | | +| paramiko.py:15:16:15:18 | cmd | paramiko.py:16:62:16:64 | cmd | provenance | | +| paramiko.py:20:16:20:18 | cmd | paramiko.py:21:70:21:72 | cmd | provenance | | +| ssh2.py:15:16:15:18 | cmd | ssh2.py:17:21:17:23 | cmd | provenance | | nodes -| AsyncSsh.py:15:16:15:18 | ControlFlowNode for cmd | semmle.label | ControlFlowNode for cmd | -| AsyncSsh.py:17:33:17:35 | ControlFlowNode for cmd | semmle.label | ControlFlowNode for cmd | -| Netmiko.py:18:16:18:18 | ControlFlowNode for cmd | semmle.label | ControlFlowNode for cmd | -| Netmiko.py:20:45:20:47 | ControlFlowNode for cmd | semmle.label | ControlFlowNode for cmd | -| Netmiko.py:21:52:21:54 | ControlFlowNode for cmd | semmle.label | ControlFlowNode for cmd | -| Netmiko.py:22:52:22:54 | ControlFlowNode for cmd | semmle.label | ControlFlowNode for cmd | -| Netmiko.py:23:41:23:57 | ControlFlowNode for List | semmle.label | ControlFlowNode for List | -| Netmiko.py:23:42:23:56 | ControlFlowNode for List [List element] | semmle.label | ControlFlowNode for List [List element] | -| Netmiko.py:23:43:23:45 | ControlFlowNode for cmd | semmle.label | ControlFlowNode for cmd | -| Netmiko.py:24:48:24:50 | ControlFlowNode for cmd | semmle.label | ControlFlowNode for cmd | -| Pexpect.py:15:16:15:18 | ControlFlowNode for cmd | semmle.label | ControlFlowNode for cmd | -| Pexpect.py:16:14:16:16 | ControlFlowNode for cmd | semmle.label | ControlFlowNode for cmd | -| Pexpect.py:18:18:18:20 | ControlFlowNode for cmd | semmle.label | ControlFlowNode for cmd | -| Scrapli.py:13:16:13:18 | ControlFlowNode for cmd | semmle.label | ControlFlowNode for cmd | -| Scrapli.py:24:42:24:44 | ControlFlowNode for cmd | semmle.label | ControlFlowNode for cmd | -| Scrapli.py:27:42:27:44 | ControlFlowNode for cmd | semmle.label | ControlFlowNode for cmd | -| Scrapli.py:30:42:30:44 | ControlFlowNode for cmd | semmle.label | ControlFlowNode for cmd | -| Scrapli.py:33:42:33:44 | ControlFlowNode for cmd | semmle.label | ControlFlowNode for cmd | -| Scrapli.py:36:42:36:44 | ControlFlowNode for cmd | semmle.label | ControlFlowNode for cmd | -| Scrapli.py:40:10:40:12 | ControlFlowNode for cmd | semmle.label | ControlFlowNode for cmd | -| Scrapli.py:51:36:51:38 | ControlFlowNode for cmd | semmle.label | ControlFlowNode for cmd | -| Scrapli.py:54:36:54:38 | ControlFlowNode for cmd | semmle.label | ControlFlowNode for cmd | -| Scrapli.py:57:36:57:38 | ControlFlowNode for cmd | semmle.label | ControlFlowNode for cmd | -| Scrapli.py:60:36:60:38 | ControlFlowNode for cmd | semmle.label | ControlFlowNode for cmd | -| Scrapli.py:63:36:63:38 | ControlFlowNode for cmd | semmle.label | ControlFlowNode for cmd | -| Scrapli.py:74:36:74:38 | ControlFlowNode for cmd | semmle.label | ControlFlowNode for cmd | -| Scrapli.py:84:36:84:38 | ControlFlowNode for cmd | semmle.label | ControlFlowNode for cmd | -| Twisted.py:13:16:13:18 | ControlFlowNode for cmd | semmle.label | ControlFlowNode for cmd | -| Twisted.py:16:5:16:7 | ControlFlowNode for cmd | semmle.label | ControlFlowNode for cmd | -| Twisted.py:24:9:24:11 | ControlFlowNode for cmd | semmle.label | ControlFlowNode for cmd | -| paramiko.py:15:16:15:18 | ControlFlowNode for cmd | semmle.label | ControlFlowNode for cmd | -| paramiko.py:16:62:16:64 | ControlFlowNode for cmd | semmle.label | ControlFlowNode for cmd | -| paramiko.py:20:16:20:18 | ControlFlowNode for cmd | semmle.label | ControlFlowNode for cmd | -| paramiko.py:21:70:21:72 | ControlFlowNode for cmd | semmle.label | ControlFlowNode for cmd | -| ssh2.py:15:16:15:18 | ControlFlowNode for cmd | semmle.label | ControlFlowNode for cmd | -| ssh2.py:17:21:17:23 | ControlFlowNode for cmd | semmle.label | ControlFlowNode for cmd | +| AsyncSsh.py:15:16:15:18 | cmd | semmle.label | cmd | +| AsyncSsh.py:17:33:17:35 | cmd | semmle.label | cmd | +| Netmiko.py:18:16:18:18 | cmd | semmle.label | cmd | +| Netmiko.py:20:45:20:47 | cmd | semmle.label | cmd | +| Netmiko.py:21:52:21:54 | cmd | semmle.label | cmd | +| Netmiko.py:22:52:22:54 | cmd | semmle.label | cmd | +| Netmiko.py:23:41:23:57 | After List | semmle.label | After List | +| Netmiko.py:24:48:24:50 | cmd | semmle.label | cmd | +| Pexpect.py:15:16:15:18 | cmd | semmle.label | cmd | +| Pexpect.py:16:14:16:16 | cmd | semmle.label | cmd | +| Pexpect.py:18:18:18:20 | cmd | semmle.label | cmd | +| Scrapli.py:13:16:13:18 | cmd | semmle.label | cmd | +| Scrapli.py:24:42:24:44 | cmd | semmle.label | cmd | +| Scrapli.py:27:42:27:44 | cmd | semmle.label | cmd | +| Scrapli.py:30:42:30:44 | cmd | semmle.label | cmd | +| Scrapli.py:33:42:33:44 | cmd | semmle.label | cmd | +| Scrapli.py:36:42:36:44 | cmd | semmle.label | cmd | +| Scrapli.py:40:10:40:12 | cmd | semmle.label | cmd | +| Scrapli.py:51:36:51:38 | cmd | semmle.label | cmd | +| Scrapli.py:54:36:54:38 | cmd | semmle.label | cmd | +| Scrapli.py:57:36:57:38 | cmd | semmle.label | cmd | +| Scrapli.py:60:36:60:38 | cmd | semmle.label | cmd | +| Scrapli.py:63:36:63:38 | cmd | semmle.label | cmd | +| Scrapli.py:74:36:74:38 | cmd | semmle.label | cmd | +| Scrapli.py:84:36:84:38 | cmd | semmle.label | cmd | +| Twisted.py:13:16:13:18 | cmd | semmle.label | cmd | +| Twisted.py:16:5:16:7 | cmd | semmle.label | cmd | +| Twisted.py:24:9:24:11 | cmd | semmle.label | cmd | +| paramiko.py:15:16:15:18 | cmd | semmle.label | cmd | +| paramiko.py:16:62:16:64 | cmd | semmle.label | cmd | +| paramiko.py:20:16:20:18 | cmd | semmle.label | cmd | +| paramiko.py:21:70:21:72 | cmd | semmle.label | cmd | +| ssh2.py:15:16:15:18 | cmd | semmle.label | cmd | +| ssh2.py:17:21:17:23 | cmd | semmle.label | cmd | subpaths #select -| AsyncSsh.py:17:33:17:35 | ControlFlowNode for cmd | AsyncSsh.py:15:16:15:18 | ControlFlowNode for cmd | AsyncSsh.py:17:33:17:35 | ControlFlowNode for cmd | This code execution depends on a $@. | AsyncSsh.py:15:16:15:18 | ControlFlowNode for cmd | a user-provided value | -| Netmiko.py:20:45:20:47 | ControlFlowNode for cmd | Netmiko.py:18:16:18:18 | ControlFlowNode for cmd | Netmiko.py:20:45:20:47 | ControlFlowNode for cmd | This code execution depends on a $@. | Netmiko.py:18:16:18:18 | ControlFlowNode for cmd | a user-provided value | -| Netmiko.py:21:52:21:54 | ControlFlowNode for cmd | Netmiko.py:18:16:18:18 | ControlFlowNode for cmd | Netmiko.py:21:52:21:54 | ControlFlowNode for cmd | This code execution depends on a $@. | Netmiko.py:18:16:18:18 | ControlFlowNode for cmd | a user-provided value | -| Netmiko.py:22:52:22:54 | ControlFlowNode for cmd | Netmiko.py:18:16:18:18 | ControlFlowNode for cmd | Netmiko.py:22:52:22:54 | ControlFlowNode for cmd | This code execution depends on a $@. | Netmiko.py:18:16:18:18 | ControlFlowNode for cmd | a user-provided value | -| Netmiko.py:23:41:23:57 | ControlFlowNode for List | Netmiko.py:18:16:18:18 | ControlFlowNode for cmd | Netmiko.py:23:41:23:57 | ControlFlowNode for List | This code execution depends on a $@. | Netmiko.py:18:16:18:18 | ControlFlowNode for cmd | a user-provided value | -| Netmiko.py:24:48:24:50 | ControlFlowNode for cmd | Netmiko.py:18:16:18:18 | ControlFlowNode for cmd | Netmiko.py:24:48:24:50 | ControlFlowNode for cmd | This code execution depends on a $@. | Netmiko.py:18:16:18:18 | ControlFlowNode for cmd | a user-provided value | -| Pexpect.py:16:14:16:16 | ControlFlowNode for cmd | Pexpect.py:15:16:15:18 | ControlFlowNode for cmd | Pexpect.py:16:14:16:16 | ControlFlowNode for cmd | This code execution depends on a $@. | Pexpect.py:15:16:15:18 | ControlFlowNode for cmd | a user-provided value | -| Pexpect.py:18:18:18:20 | ControlFlowNode for cmd | Pexpect.py:15:16:15:18 | ControlFlowNode for cmd | Pexpect.py:18:18:18:20 | ControlFlowNode for cmd | This code execution depends on a $@. | Pexpect.py:15:16:15:18 | ControlFlowNode for cmd | a user-provided value | -| Scrapli.py:24:42:24:44 | ControlFlowNode for cmd | Scrapli.py:13:16:13:18 | ControlFlowNode for cmd | Scrapli.py:24:42:24:44 | ControlFlowNode for cmd | This code execution depends on a $@. | Scrapli.py:13:16:13:18 | ControlFlowNode for cmd | a user-provided value | -| Scrapli.py:27:42:27:44 | ControlFlowNode for cmd | Scrapli.py:13:16:13:18 | ControlFlowNode for cmd | Scrapli.py:27:42:27:44 | ControlFlowNode for cmd | This code execution depends on a $@. | Scrapli.py:13:16:13:18 | ControlFlowNode for cmd | a user-provided value | -| Scrapli.py:30:42:30:44 | ControlFlowNode for cmd | Scrapli.py:13:16:13:18 | ControlFlowNode for cmd | Scrapli.py:30:42:30:44 | ControlFlowNode for cmd | This code execution depends on a $@. | Scrapli.py:13:16:13:18 | ControlFlowNode for cmd | a user-provided value | -| Scrapli.py:33:42:33:44 | ControlFlowNode for cmd | Scrapli.py:13:16:13:18 | ControlFlowNode for cmd | Scrapli.py:33:42:33:44 | ControlFlowNode for cmd | This code execution depends on a $@. | Scrapli.py:13:16:13:18 | ControlFlowNode for cmd | a user-provided value | -| Scrapli.py:36:42:36:44 | ControlFlowNode for cmd | Scrapli.py:13:16:13:18 | ControlFlowNode for cmd | Scrapli.py:36:42:36:44 | ControlFlowNode for cmd | This code execution depends on a $@. | Scrapli.py:13:16:13:18 | ControlFlowNode for cmd | a user-provided value | -| Scrapli.py:51:36:51:38 | ControlFlowNode for cmd | Scrapli.py:40:10:40:12 | ControlFlowNode for cmd | Scrapli.py:51:36:51:38 | ControlFlowNode for cmd | This code execution depends on a $@. | Scrapli.py:40:10:40:12 | ControlFlowNode for cmd | a user-provided value | -| Scrapli.py:54:36:54:38 | ControlFlowNode for cmd | Scrapli.py:40:10:40:12 | ControlFlowNode for cmd | Scrapli.py:54:36:54:38 | ControlFlowNode for cmd | This code execution depends on a $@. | Scrapli.py:40:10:40:12 | ControlFlowNode for cmd | a user-provided value | -| Scrapli.py:57:36:57:38 | ControlFlowNode for cmd | Scrapli.py:40:10:40:12 | ControlFlowNode for cmd | Scrapli.py:57:36:57:38 | ControlFlowNode for cmd | This code execution depends on a $@. | Scrapli.py:40:10:40:12 | ControlFlowNode for cmd | a user-provided value | -| Scrapli.py:60:36:60:38 | ControlFlowNode for cmd | Scrapli.py:40:10:40:12 | ControlFlowNode for cmd | Scrapli.py:60:36:60:38 | ControlFlowNode for cmd | This code execution depends on a $@. | Scrapli.py:40:10:40:12 | ControlFlowNode for cmd | a user-provided value | -| Scrapli.py:63:36:63:38 | ControlFlowNode for cmd | Scrapli.py:40:10:40:12 | ControlFlowNode for cmd | Scrapli.py:63:36:63:38 | ControlFlowNode for cmd | This code execution depends on a $@. | Scrapli.py:40:10:40:12 | ControlFlowNode for cmd | a user-provided value | -| Scrapli.py:74:36:74:38 | ControlFlowNode for cmd | Scrapli.py:40:10:40:12 | ControlFlowNode for cmd | Scrapli.py:74:36:74:38 | ControlFlowNode for cmd | This code execution depends on a $@. | Scrapli.py:40:10:40:12 | ControlFlowNode for cmd | a user-provided value | -| Scrapli.py:84:36:84:38 | ControlFlowNode for cmd | Scrapli.py:40:10:40:12 | ControlFlowNode for cmd | Scrapli.py:84:36:84:38 | ControlFlowNode for cmd | This code execution depends on a $@. | Scrapli.py:40:10:40:12 | ControlFlowNode for cmd | a user-provided value | -| Twisted.py:16:5:16:7 | ControlFlowNode for cmd | Twisted.py:13:16:13:18 | ControlFlowNode for cmd | Twisted.py:16:5:16:7 | ControlFlowNode for cmd | This code execution depends on a $@. | Twisted.py:13:16:13:18 | ControlFlowNode for cmd | a user-provided value | -| Twisted.py:24:9:24:11 | ControlFlowNode for cmd | Twisted.py:13:16:13:18 | ControlFlowNode for cmd | Twisted.py:24:9:24:11 | ControlFlowNode for cmd | This code execution depends on a $@. | Twisted.py:13:16:13:18 | ControlFlowNode for cmd | a user-provided value | -| paramiko.py:16:62:16:64 | ControlFlowNode for cmd | paramiko.py:15:16:15:18 | ControlFlowNode for cmd | paramiko.py:16:62:16:64 | ControlFlowNode for cmd | This code execution depends on a $@. | paramiko.py:15:16:15:18 | ControlFlowNode for cmd | a user-provided value | -| paramiko.py:21:70:21:72 | ControlFlowNode for cmd | paramiko.py:20:16:20:18 | ControlFlowNode for cmd | paramiko.py:21:70:21:72 | ControlFlowNode for cmd | This code execution depends on a $@. | paramiko.py:20:16:20:18 | ControlFlowNode for cmd | a user-provided value | -| ssh2.py:17:21:17:23 | ControlFlowNode for cmd | ssh2.py:15:16:15:18 | ControlFlowNode for cmd | ssh2.py:17:21:17:23 | ControlFlowNode for cmd | This code execution depends on a $@. | ssh2.py:15:16:15:18 | ControlFlowNode for cmd | a user-provided value | +| AsyncSsh.py:17:33:17:35 | cmd | AsyncSsh.py:15:16:15:18 | cmd | AsyncSsh.py:17:33:17:35 | cmd | This code execution depends on a $@. | AsyncSsh.py:15:16:15:18 | cmd | a user-provided value | +| Netmiko.py:20:45:20:47 | cmd | Netmiko.py:18:16:18:18 | cmd | Netmiko.py:20:45:20:47 | cmd | This code execution depends on a $@. | Netmiko.py:18:16:18:18 | cmd | a user-provided value | +| Netmiko.py:21:52:21:54 | cmd | Netmiko.py:18:16:18:18 | cmd | Netmiko.py:21:52:21:54 | cmd | This code execution depends on a $@. | Netmiko.py:18:16:18:18 | cmd | a user-provided value | +| Netmiko.py:22:52:22:54 | cmd | Netmiko.py:18:16:18:18 | cmd | Netmiko.py:22:52:22:54 | cmd | This code execution depends on a $@. | Netmiko.py:18:16:18:18 | cmd | a user-provided value | +| Netmiko.py:23:41:23:57 | After List | Netmiko.py:18:16:18:18 | cmd | Netmiko.py:23:41:23:57 | After List | This code execution depends on a $@. | Netmiko.py:18:16:18:18 | cmd | a user-provided value | +| Netmiko.py:24:48:24:50 | cmd | Netmiko.py:18:16:18:18 | cmd | Netmiko.py:24:48:24:50 | cmd | This code execution depends on a $@. | Netmiko.py:18:16:18:18 | cmd | a user-provided value | +| Pexpect.py:16:14:16:16 | cmd | Pexpect.py:15:16:15:18 | cmd | Pexpect.py:16:14:16:16 | cmd | This code execution depends on a $@. | Pexpect.py:15:16:15:18 | cmd | a user-provided value | +| Pexpect.py:18:18:18:20 | cmd | Pexpect.py:15:16:15:18 | cmd | Pexpect.py:18:18:18:20 | cmd | This code execution depends on a $@. | Pexpect.py:15:16:15:18 | cmd | a user-provided value | +| Scrapli.py:24:42:24:44 | cmd | Scrapli.py:13:16:13:18 | cmd | Scrapli.py:24:42:24:44 | cmd | This code execution depends on a $@. | Scrapli.py:13:16:13:18 | cmd | a user-provided value | +| Scrapli.py:27:42:27:44 | cmd | Scrapli.py:13:16:13:18 | cmd | Scrapli.py:27:42:27:44 | cmd | This code execution depends on a $@. | Scrapli.py:13:16:13:18 | cmd | a user-provided value | +| Scrapli.py:30:42:30:44 | cmd | Scrapli.py:13:16:13:18 | cmd | Scrapli.py:30:42:30:44 | cmd | This code execution depends on a $@. | Scrapli.py:13:16:13:18 | cmd | a user-provided value | +| Scrapli.py:33:42:33:44 | cmd | Scrapli.py:13:16:13:18 | cmd | Scrapli.py:33:42:33:44 | cmd | This code execution depends on a $@. | Scrapli.py:13:16:13:18 | cmd | a user-provided value | +| Scrapli.py:36:42:36:44 | cmd | Scrapli.py:13:16:13:18 | cmd | Scrapli.py:36:42:36:44 | cmd | This code execution depends on a $@. | Scrapli.py:13:16:13:18 | cmd | a user-provided value | +| Scrapli.py:51:36:51:38 | cmd | Scrapli.py:40:10:40:12 | cmd | Scrapli.py:51:36:51:38 | cmd | This code execution depends on a $@. | Scrapli.py:40:10:40:12 | cmd | a user-provided value | +| Scrapli.py:54:36:54:38 | cmd | Scrapli.py:40:10:40:12 | cmd | Scrapli.py:54:36:54:38 | cmd | This code execution depends on a $@. | Scrapli.py:40:10:40:12 | cmd | a user-provided value | +| Scrapli.py:57:36:57:38 | cmd | Scrapli.py:40:10:40:12 | cmd | Scrapli.py:57:36:57:38 | cmd | This code execution depends on a $@. | Scrapli.py:40:10:40:12 | cmd | a user-provided value | +| Scrapli.py:60:36:60:38 | cmd | Scrapli.py:40:10:40:12 | cmd | Scrapli.py:60:36:60:38 | cmd | This code execution depends on a $@. | Scrapli.py:40:10:40:12 | cmd | a user-provided value | +| Scrapli.py:63:36:63:38 | cmd | Scrapli.py:40:10:40:12 | cmd | Scrapli.py:63:36:63:38 | cmd | This code execution depends on a $@. | Scrapli.py:40:10:40:12 | cmd | a user-provided value | +| Scrapli.py:74:36:74:38 | cmd | Scrapli.py:40:10:40:12 | cmd | Scrapli.py:74:36:74:38 | cmd | This code execution depends on a $@. | Scrapli.py:40:10:40:12 | cmd | a user-provided value | +| Scrapli.py:84:36:84:38 | cmd | Scrapli.py:40:10:40:12 | cmd | Scrapli.py:84:36:84:38 | cmd | This code execution depends on a $@. | Scrapli.py:40:10:40:12 | cmd | a user-provided value | +| Twisted.py:16:5:16:7 | cmd | Twisted.py:13:16:13:18 | cmd | Twisted.py:16:5:16:7 | cmd | This code execution depends on a $@. | Twisted.py:13:16:13:18 | cmd | a user-provided value | +| Twisted.py:24:9:24:11 | cmd | Twisted.py:13:16:13:18 | cmd | Twisted.py:24:9:24:11 | cmd | This code execution depends on a $@. | Twisted.py:13:16:13:18 | cmd | a user-provided value | +| paramiko.py:16:62:16:64 | cmd | paramiko.py:15:16:15:18 | cmd | paramiko.py:16:62:16:64 | cmd | This code execution depends on a $@. | paramiko.py:15:16:15:18 | cmd | a user-provided value | +| paramiko.py:21:70:21:72 | cmd | paramiko.py:20:16:20:18 | cmd | paramiko.py:21:70:21:72 | cmd | This code execution depends on a $@. | paramiko.py:20:16:20:18 | cmd | a user-provided value | +| ssh2.py:17:21:17:23 | cmd | ssh2.py:15:16:15:18 | cmd | ssh2.py:17:21:17:23 | cmd | This code execution depends on a $@. | ssh2.py:15:16:15:18 | cmd | a user-provided value | diff --git a/python/ql/test/experimental/query-tests/Security/CWE-079/EmailXss.expected b/python/ql/test/experimental/query-tests/Security/CWE-079/EmailXss.expected index 8f0493b79278..eac526d96453 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-079/EmailXss.expected +++ b/python/ql/test/experimental/query-tests/Security/CWE-079/EmailXss.expected @@ -1,94 +1,94 @@ edges -| flask_mail.py:1:19:1:25 | ControlFlowNode for ImportMember | flask_mail.py:1:19:1:25 | ControlFlowNode for request | provenance | | -| flask_mail.py:1:19:1:25 | ControlFlowNode for request | flask_mail.py:13:22:13:28 | ControlFlowNode for request | provenance | | -| flask_mail.py:1:19:1:25 | ControlFlowNode for request | flask_mail.py:18:14:18:20 | ControlFlowNode for request | provenance | | -| flask_mail.py:1:19:1:25 | ControlFlowNode for request | flask_mail.py:31:24:31:30 | ControlFlowNode for request | provenance | | -| flask_mail.py:13:22:13:28 | ControlFlowNode for request | flask_mail.py:13:22:13:41 | ControlFlowNode for Subscript | provenance | AdditionalTaintStep | -| flask_mail.py:13:22:13:28 | ControlFlowNode for request | flask_mail.py:18:14:18:33 | ControlFlowNode for Subscript | provenance | AdditionalTaintStep | -| flask_mail.py:18:14:18:20 | ControlFlowNode for request | flask_mail.py:18:14:18:33 | ControlFlowNode for Subscript | provenance | AdditionalTaintStep | -| flask_mail.py:31:24:31:30 | ControlFlowNode for request | flask_mail.py:31:24:31:43 | ControlFlowNode for Subscript | provenance | AdditionalTaintStep | -| sendgrid_mail.py:1:19:1:25 | ControlFlowNode for ImportMember | sendgrid_mail.py:1:19:1:25 | ControlFlowNode for request | provenance | | -| sendgrid_mail.py:1:19:1:25 | ControlFlowNode for request | sendgrid_mail.py:14:22:14:28 | ControlFlowNode for request | provenance | | -| sendgrid_mail.py:1:19:1:25 | ControlFlowNode for request | sendgrid_mail.py:26:34:26:40 | ControlFlowNode for request | provenance | | -| sendgrid_mail.py:1:19:1:25 | ControlFlowNode for request | sendgrid_mail.py:37:41:37:47 | ControlFlowNode for request | provenance | | -| sendgrid_mail.py:14:22:14:28 | ControlFlowNode for request | sendgrid_mail.py:14:22:14:49 | ControlFlowNode for Subscript | provenance | AdditionalTaintStep | -| sendgrid_mail.py:26:34:26:40 | ControlFlowNode for request | sendgrid_mail.py:26:34:26:61 | ControlFlowNode for Subscript | provenance | AdditionalTaintStep | -| sendgrid_mail.py:26:34:26:61 | ControlFlowNode for Subscript | sendgrid_mail.py:26:22:26:62 | ControlFlowNode for HtmlContent() | provenance | Config | -| sendgrid_mail.py:37:41:37:47 | ControlFlowNode for request | sendgrid_mail.py:37:41:37:68 | ControlFlowNode for Subscript | provenance | AdditionalTaintStep | -| sendgrid_via_mail_send_post_request_body_bad.py:3:19:3:25 | ControlFlowNode for ImportMember | sendgrid_via_mail_send_post_request_body_bad.py:3:19:3:25 | ControlFlowNode for request | provenance | | -| sendgrid_via_mail_send_post_request_body_bad.py:3:19:3:25 | ControlFlowNode for request | sendgrid_via_mail_send_post_request_body_bad.py:16:51:16:57 | ControlFlowNode for request | provenance | | -| sendgrid_via_mail_send_post_request_body_bad.py:3:19:3:25 | ControlFlowNode for request | sendgrid_via_mail_send_post_request_body_bad.py:27:50:27:56 | ControlFlowNode for request | provenance | | -| sendgrid_via_mail_send_post_request_body_bad.py:3:19:3:25 | ControlFlowNode for request | sendgrid_via_mail_send_post_request_body_bad.py:41:50:41:56 | ControlFlowNode for request | provenance | | -| sendgrid_via_mail_send_post_request_body_bad.py:16:51:16:57 | ControlFlowNode for request | sendgrid_via_mail_send_post_request_body_bad.py:16:26:16:79 | ControlFlowNode for Attribute() | provenance | AdditionalTaintStep | -| sendgrid_via_mail_send_post_request_body_bad.py:16:51:16:57 | ControlFlowNode for request | sendgrid_via_mail_send_post_request_body_bad.py:27:25:27:77 | ControlFlowNode for Attribute() | provenance | AdditionalTaintStep | -| sendgrid_via_mail_send_post_request_body_bad.py:16:51:16:57 | ControlFlowNode for request | sendgrid_via_mail_send_post_request_body_bad.py:41:25:41:79 | ControlFlowNode for Attribute() | provenance | AdditionalTaintStep | -| sendgrid_via_mail_send_post_request_body_bad.py:27:50:27:56 | ControlFlowNode for request | sendgrid_via_mail_send_post_request_body_bad.py:27:25:27:77 | ControlFlowNode for Attribute() | provenance | AdditionalTaintStep | -| sendgrid_via_mail_send_post_request_body_bad.py:27:50:27:56 | ControlFlowNode for request | sendgrid_via_mail_send_post_request_body_bad.py:41:25:41:79 | ControlFlowNode for Attribute() | provenance | AdditionalTaintStep | -| sendgrid_via_mail_send_post_request_body_bad.py:41:50:41:56 | ControlFlowNode for request | sendgrid_via_mail_send_post_request_body_bad.py:41:25:41:79 | ControlFlowNode for Attribute() | provenance | AdditionalTaintStep | -| smtplib_bad_subparts.py:2:26:2:32 | ControlFlowNode for ImportMember | smtplib_bad_subparts.py:2:26:2:32 | ControlFlowNode for request | provenance | | -| smtplib_bad_subparts.py:2:26:2:32 | ControlFlowNode for request | smtplib_bad_subparts.py:17:12:17:18 | ControlFlowNode for request | provenance | | -| smtplib_bad_subparts.py:17:5:17:8 | ControlFlowNode for name | smtplib_bad_subparts.py:20:5:20:8 | ControlFlowNode for html | provenance | | -| smtplib_bad_subparts.py:17:12:17:18 | ControlFlowNode for request | smtplib_bad_subparts.py:17:5:17:8 | ControlFlowNode for name | provenance | AdditionalTaintStep | -| smtplib_bad_subparts.py:20:5:20:8 | ControlFlowNode for html | smtplib_bad_subparts.py:24:22:24:25 | ControlFlowNode for html | provenance | | -| smtplib_bad_via_attach.py:2:26:2:32 | ControlFlowNode for ImportMember | smtplib_bad_via_attach.py:2:26:2:32 | ControlFlowNode for request | provenance | | -| smtplib_bad_via_attach.py:2:26:2:32 | ControlFlowNode for request | smtplib_bad_via_attach.py:20:12:20:18 | ControlFlowNode for request | provenance | | -| smtplib_bad_via_attach.py:20:5:20:8 | ControlFlowNode for name | smtplib_bad_via_attach.py:23:5:23:8 | ControlFlowNode for html | provenance | | -| smtplib_bad_via_attach.py:20:12:20:18 | ControlFlowNode for request | smtplib_bad_via_attach.py:20:5:20:8 | ControlFlowNode for name | provenance | AdditionalTaintStep | -| smtplib_bad_via_attach.py:23:5:23:8 | ControlFlowNode for html | smtplib_bad_via_attach.py:27:22:27:25 | ControlFlowNode for html | provenance | | +| flask_mail.py:1:19:1:25 | After ImportMember | flask_mail.py:1:19:1:25 | request | provenance | | +| flask_mail.py:1:19:1:25 | request | flask_mail.py:13:22:13:28 | request | provenance | | +| flask_mail.py:1:19:1:25 | request | flask_mail.py:18:14:18:20 | request | provenance | | +| flask_mail.py:1:19:1:25 | request | flask_mail.py:31:24:31:30 | request | provenance | | +| flask_mail.py:13:22:13:28 | request | flask_mail.py:13:22:13:41 | After Subscript | provenance | AdditionalTaintStep | +| flask_mail.py:13:22:13:28 | request | flask_mail.py:18:14:18:33 | After Subscript | provenance | AdditionalTaintStep | +| flask_mail.py:18:14:18:20 | request | flask_mail.py:18:14:18:33 | After Subscript | provenance | AdditionalTaintStep | +| flask_mail.py:31:24:31:30 | request | flask_mail.py:31:24:31:43 | After Subscript | provenance | AdditionalTaintStep | +| sendgrid_mail.py:1:19:1:25 | After ImportMember | sendgrid_mail.py:1:19:1:25 | request | provenance | | +| sendgrid_mail.py:1:19:1:25 | request | sendgrid_mail.py:14:22:14:28 | request | provenance | | +| sendgrid_mail.py:1:19:1:25 | request | sendgrid_mail.py:26:34:26:40 | request | provenance | | +| sendgrid_mail.py:1:19:1:25 | request | sendgrid_mail.py:37:41:37:47 | request | provenance | | +| sendgrid_mail.py:14:22:14:28 | request | sendgrid_mail.py:14:22:14:49 | After Subscript | provenance | AdditionalTaintStep | +| sendgrid_mail.py:26:34:26:40 | request | sendgrid_mail.py:26:34:26:61 | After Subscript | provenance | AdditionalTaintStep | +| sendgrid_mail.py:26:34:26:61 | After Subscript | sendgrid_mail.py:26:22:26:62 | After HtmlContent() | provenance | Config | +| sendgrid_mail.py:37:41:37:47 | request | sendgrid_mail.py:37:41:37:68 | After Subscript | provenance | AdditionalTaintStep | +| sendgrid_via_mail_send_post_request_body_bad.py:3:19:3:25 | After ImportMember | sendgrid_via_mail_send_post_request_body_bad.py:3:19:3:25 | request | provenance | | +| sendgrid_via_mail_send_post_request_body_bad.py:3:19:3:25 | request | sendgrid_via_mail_send_post_request_body_bad.py:16:51:16:57 | request | provenance | | +| sendgrid_via_mail_send_post_request_body_bad.py:3:19:3:25 | request | sendgrid_via_mail_send_post_request_body_bad.py:27:50:27:56 | request | provenance | | +| sendgrid_via_mail_send_post_request_body_bad.py:3:19:3:25 | request | sendgrid_via_mail_send_post_request_body_bad.py:41:50:41:56 | request | provenance | | +| sendgrid_via_mail_send_post_request_body_bad.py:16:51:16:57 | request | sendgrid_via_mail_send_post_request_body_bad.py:16:26:16:79 | After Attribute() | provenance | AdditionalTaintStep | +| sendgrid_via_mail_send_post_request_body_bad.py:16:51:16:57 | request | sendgrid_via_mail_send_post_request_body_bad.py:27:25:27:77 | After Attribute() | provenance | AdditionalTaintStep | +| sendgrid_via_mail_send_post_request_body_bad.py:16:51:16:57 | request | sendgrid_via_mail_send_post_request_body_bad.py:41:25:41:79 | After Attribute() | provenance | AdditionalTaintStep | +| sendgrid_via_mail_send_post_request_body_bad.py:27:50:27:56 | request | sendgrid_via_mail_send_post_request_body_bad.py:27:25:27:77 | After Attribute() | provenance | AdditionalTaintStep | +| sendgrid_via_mail_send_post_request_body_bad.py:27:50:27:56 | request | sendgrid_via_mail_send_post_request_body_bad.py:41:25:41:79 | After Attribute() | provenance | AdditionalTaintStep | +| sendgrid_via_mail_send_post_request_body_bad.py:41:50:41:56 | request | sendgrid_via_mail_send_post_request_body_bad.py:41:25:41:79 | After Attribute() | provenance | AdditionalTaintStep | +| smtplib_bad_subparts.py:2:26:2:32 | After ImportMember | smtplib_bad_subparts.py:2:26:2:32 | request | provenance | | +| smtplib_bad_subparts.py:2:26:2:32 | request | smtplib_bad_subparts.py:17:12:17:18 | request | provenance | | +| smtplib_bad_subparts.py:17:5:17:8 | name | smtplib_bad_subparts.py:20:5:20:8 | html | provenance | | +| smtplib_bad_subparts.py:17:12:17:18 | request | smtplib_bad_subparts.py:17:5:17:8 | name | provenance | AdditionalTaintStep | +| smtplib_bad_subparts.py:20:5:20:8 | html | smtplib_bad_subparts.py:24:22:24:25 | html | provenance | | +| smtplib_bad_via_attach.py:2:26:2:32 | After ImportMember | smtplib_bad_via_attach.py:2:26:2:32 | request | provenance | | +| smtplib_bad_via_attach.py:2:26:2:32 | request | smtplib_bad_via_attach.py:20:12:20:18 | request | provenance | | +| smtplib_bad_via_attach.py:20:5:20:8 | name | smtplib_bad_via_attach.py:23:5:23:8 | html | provenance | | +| smtplib_bad_via_attach.py:20:12:20:18 | request | smtplib_bad_via_attach.py:20:5:20:8 | name | provenance | AdditionalTaintStep | +| smtplib_bad_via_attach.py:23:5:23:8 | html | smtplib_bad_via_attach.py:27:22:27:25 | html | provenance | | nodes -| django_mail.py:14:48:14:82 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| django_mail.py:23:30:23:64 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| django_mail.py:25:32:25:66 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| flask_mail.py:1:19:1:25 | ControlFlowNode for ImportMember | semmle.label | ControlFlowNode for ImportMember | -| flask_mail.py:1:19:1:25 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| flask_mail.py:13:22:13:28 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| flask_mail.py:13:22:13:41 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript | -| flask_mail.py:18:14:18:20 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| flask_mail.py:18:14:18:33 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript | -| flask_mail.py:31:24:31:30 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| flask_mail.py:31:24:31:43 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript | -| sendgrid_mail.py:1:19:1:25 | ControlFlowNode for ImportMember | semmle.label | ControlFlowNode for ImportMember | -| sendgrid_mail.py:1:19:1:25 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| sendgrid_mail.py:14:22:14:28 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| sendgrid_mail.py:14:22:14:49 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript | -| sendgrid_mail.py:26:22:26:62 | ControlFlowNode for HtmlContent() | semmle.label | ControlFlowNode for HtmlContent() | -| sendgrid_mail.py:26:34:26:40 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| sendgrid_mail.py:26:34:26:61 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript | -| sendgrid_mail.py:37:41:37:47 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| sendgrid_mail.py:37:41:37:68 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript | -| sendgrid_via_mail_send_post_request_body_bad.py:3:19:3:25 | ControlFlowNode for ImportMember | semmle.label | ControlFlowNode for ImportMember | -| sendgrid_via_mail_send_post_request_body_bad.py:3:19:3:25 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| sendgrid_via_mail_send_post_request_body_bad.py:16:26:16:79 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| sendgrid_via_mail_send_post_request_body_bad.py:16:51:16:57 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| sendgrid_via_mail_send_post_request_body_bad.py:27:25:27:77 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| sendgrid_via_mail_send_post_request_body_bad.py:27:50:27:56 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| sendgrid_via_mail_send_post_request_body_bad.py:41:25:41:79 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| sendgrid_via_mail_send_post_request_body_bad.py:41:50:41:56 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| smtplib_bad_subparts.py:2:26:2:32 | ControlFlowNode for ImportMember | semmle.label | ControlFlowNode for ImportMember | -| smtplib_bad_subparts.py:2:26:2:32 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| smtplib_bad_subparts.py:17:5:17:8 | ControlFlowNode for name | semmle.label | ControlFlowNode for name | -| smtplib_bad_subparts.py:17:12:17:18 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| smtplib_bad_subparts.py:20:5:20:8 | ControlFlowNode for html | semmle.label | ControlFlowNode for html | -| smtplib_bad_subparts.py:24:22:24:25 | ControlFlowNode for html | semmle.label | ControlFlowNode for html | -| smtplib_bad_via_attach.py:2:26:2:32 | ControlFlowNode for ImportMember | semmle.label | ControlFlowNode for ImportMember | -| smtplib_bad_via_attach.py:2:26:2:32 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| smtplib_bad_via_attach.py:20:5:20:8 | ControlFlowNode for name | semmle.label | ControlFlowNode for name | -| smtplib_bad_via_attach.py:20:12:20:18 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| smtplib_bad_via_attach.py:23:5:23:8 | ControlFlowNode for html | semmle.label | ControlFlowNode for html | -| smtplib_bad_via_attach.py:27:22:27:25 | ControlFlowNode for html | semmle.label | ControlFlowNode for html | +| django_mail.py:14:48:14:82 | After Attribute() | semmle.label | After Attribute() | +| django_mail.py:23:30:23:64 | After Attribute() | semmle.label | After Attribute() | +| django_mail.py:25:32:25:66 | After Attribute() | semmle.label | After Attribute() | +| flask_mail.py:1:19:1:25 | After ImportMember | semmle.label | After ImportMember | +| flask_mail.py:1:19:1:25 | request | semmle.label | request | +| flask_mail.py:13:22:13:28 | request | semmle.label | request | +| flask_mail.py:13:22:13:41 | After Subscript | semmle.label | After Subscript | +| flask_mail.py:18:14:18:20 | request | semmle.label | request | +| flask_mail.py:18:14:18:33 | After Subscript | semmle.label | After Subscript | +| flask_mail.py:31:24:31:30 | request | semmle.label | request | +| flask_mail.py:31:24:31:43 | After Subscript | semmle.label | After Subscript | +| sendgrid_mail.py:1:19:1:25 | After ImportMember | semmle.label | After ImportMember | +| sendgrid_mail.py:1:19:1:25 | request | semmle.label | request | +| sendgrid_mail.py:14:22:14:28 | request | semmle.label | request | +| sendgrid_mail.py:14:22:14:49 | After Subscript | semmle.label | After Subscript | +| sendgrid_mail.py:26:22:26:62 | After HtmlContent() | semmle.label | After HtmlContent() | +| sendgrid_mail.py:26:34:26:40 | request | semmle.label | request | +| sendgrid_mail.py:26:34:26:61 | After Subscript | semmle.label | After Subscript | +| sendgrid_mail.py:37:41:37:47 | request | semmle.label | request | +| sendgrid_mail.py:37:41:37:68 | After Subscript | semmle.label | After Subscript | +| sendgrid_via_mail_send_post_request_body_bad.py:3:19:3:25 | After ImportMember | semmle.label | After ImportMember | +| sendgrid_via_mail_send_post_request_body_bad.py:3:19:3:25 | request | semmle.label | request | +| sendgrid_via_mail_send_post_request_body_bad.py:16:26:16:79 | After Attribute() | semmle.label | After Attribute() | +| sendgrid_via_mail_send_post_request_body_bad.py:16:51:16:57 | request | semmle.label | request | +| sendgrid_via_mail_send_post_request_body_bad.py:27:25:27:77 | After Attribute() | semmle.label | After Attribute() | +| sendgrid_via_mail_send_post_request_body_bad.py:27:50:27:56 | request | semmle.label | request | +| sendgrid_via_mail_send_post_request_body_bad.py:41:25:41:79 | After Attribute() | semmle.label | After Attribute() | +| sendgrid_via_mail_send_post_request_body_bad.py:41:50:41:56 | request | semmle.label | request | +| smtplib_bad_subparts.py:2:26:2:32 | After ImportMember | semmle.label | After ImportMember | +| smtplib_bad_subparts.py:2:26:2:32 | request | semmle.label | request | +| smtplib_bad_subparts.py:17:5:17:8 | name | semmle.label | name | +| smtplib_bad_subparts.py:17:12:17:18 | request | semmle.label | request | +| smtplib_bad_subparts.py:20:5:20:8 | html | semmle.label | html | +| smtplib_bad_subparts.py:24:22:24:25 | html | semmle.label | html | +| smtplib_bad_via_attach.py:2:26:2:32 | After ImportMember | semmle.label | After ImportMember | +| smtplib_bad_via_attach.py:2:26:2:32 | request | semmle.label | request | +| smtplib_bad_via_attach.py:20:5:20:8 | name | semmle.label | name | +| smtplib_bad_via_attach.py:20:12:20:18 | request | semmle.label | request | +| smtplib_bad_via_attach.py:23:5:23:8 | html | semmle.label | html | +| smtplib_bad_via_attach.py:27:22:27:25 | html | semmle.label | html | subpaths #select -| django_mail.py:14:48:14:82 | ControlFlowNode for Attribute() | django_mail.py:14:48:14:82 | ControlFlowNode for Attribute() | django_mail.py:14:48:14:82 | ControlFlowNode for Attribute() | Cross-site scripting vulnerability due to $@. | django_mail.py:14:48:14:82 | ControlFlowNode for Attribute() | a user-provided value | -| django_mail.py:23:30:23:64 | ControlFlowNode for Attribute() | django_mail.py:23:30:23:64 | ControlFlowNode for Attribute() | django_mail.py:23:30:23:64 | ControlFlowNode for Attribute() | Cross-site scripting vulnerability due to $@. | django_mail.py:23:30:23:64 | ControlFlowNode for Attribute() | a user-provided value | -| django_mail.py:25:32:25:66 | ControlFlowNode for Attribute() | django_mail.py:25:32:25:66 | ControlFlowNode for Attribute() | django_mail.py:25:32:25:66 | ControlFlowNode for Attribute() | Cross-site scripting vulnerability due to $@. | django_mail.py:25:32:25:66 | ControlFlowNode for Attribute() | a user-provided value | -| flask_mail.py:13:22:13:41 | ControlFlowNode for Subscript | flask_mail.py:1:19:1:25 | ControlFlowNode for ImportMember | flask_mail.py:13:22:13:41 | ControlFlowNode for Subscript | Cross-site scripting vulnerability due to $@. | flask_mail.py:1:19:1:25 | ControlFlowNode for ImportMember | a user-provided value | -| flask_mail.py:18:14:18:33 | ControlFlowNode for Subscript | flask_mail.py:1:19:1:25 | ControlFlowNode for ImportMember | flask_mail.py:18:14:18:33 | ControlFlowNode for Subscript | Cross-site scripting vulnerability due to $@. | flask_mail.py:1:19:1:25 | ControlFlowNode for ImportMember | a user-provided value | -| flask_mail.py:31:24:31:43 | ControlFlowNode for Subscript | flask_mail.py:1:19:1:25 | ControlFlowNode for ImportMember | flask_mail.py:31:24:31:43 | ControlFlowNode for Subscript | Cross-site scripting vulnerability due to $@. | flask_mail.py:1:19:1:25 | ControlFlowNode for ImportMember | a user-provided value | -| sendgrid_mail.py:14:22:14:49 | ControlFlowNode for Subscript | sendgrid_mail.py:1:19:1:25 | ControlFlowNode for ImportMember | sendgrid_mail.py:14:22:14:49 | ControlFlowNode for Subscript | Cross-site scripting vulnerability due to $@. | sendgrid_mail.py:1:19:1:25 | ControlFlowNode for ImportMember | a user-provided value | -| sendgrid_mail.py:26:22:26:62 | ControlFlowNode for HtmlContent() | sendgrid_mail.py:1:19:1:25 | ControlFlowNode for ImportMember | sendgrid_mail.py:26:22:26:62 | ControlFlowNode for HtmlContent() | Cross-site scripting vulnerability due to $@. | sendgrid_mail.py:1:19:1:25 | ControlFlowNode for ImportMember | a user-provided value | -| sendgrid_mail.py:37:41:37:68 | ControlFlowNode for Subscript | sendgrid_mail.py:1:19:1:25 | ControlFlowNode for ImportMember | sendgrid_mail.py:37:41:37:68 | ControlFlowNode for Subscript | Cross-site scripting vulnerability due to $@. | sendgrid_mail.py:1:19:1:25 | ControlFlowNode for ImportMember | a user-provided value | -| sendgrid_via_mail_send_post_request_body_bad.py:16:26:16:79 | ControlFlowNode for Attribute() | sendgrid_via_mail_send_post_request_body_bad.py:3:19:3:25 | ControlFlowNode for ImportMember | sendgrid_via_mail_send_post_request_body_bad.py:16:26:16:79 | ControlFlowNode for Attribute() | Cross-site scripting vulnerability due to $@. | sendgrid_via_mail_send_post_request_body_bad.py:3:19:3:25 | ControlFlowNode for ImportMember | a user-provided value | -| sendgrid_via_mail_send_post_request_body_bad.py:27:25:27:77 | ControlFlowNode for Attribute() | sendgrid_via_mail_send_post_request_body_bad.py:3:19:3:25 | ControlFlowNode for ImportMember | sendgrid_via_mail_send_post_request_body_bad.py:27:25:27:77 | ControlFlowNode for Attribute() | Cross-site scripting vulnerability due to $@. | sendgrid_via_mail_send_post_request_body_bad.py:3:19:3:25 | ControlFlowNode for ImportMember | a user-provided value | -| sendgrid_via_mail_send_post_request_body_bad.py:41:25:41:79 | ControlFlowNode for Attribute() | sendgrid_via_mail_send_post_request_body_bad.py:3:19:3:25 | ControlFlowNode for ImportMember | sendgrid_via_mail_send_post_request_body_bad.py:41:25:41:79 | ControlFlowNode for Attribute() | Cross-site scripting vulnerability due to $@. | sendgrid_via_mail_send_post_request_body_bad.py:3:19:3:25 | ControlFlowNode for ImportMember | a user-provided value | -| smtplib_bad_subparts.py:24:22:24:25 | ControlFlowNode for html | smtplib_bad_subparts.py:2:26:2:32 | ControlFlowNode for ImportMember | smtplib_bad_subparts.py:24:22:24:25 | ControlFlowNode for html | Cross-site scripting vulnerability due to $@. | smtplib_bad_subparts.py:2:26:2:32 | ControlFlowNode for ImportMember | a user-provided value | -| smtplib_bad_via_attach.py:27:22:27:25 | ControlFlowNode for html | smtplib_bad_via_attach.py:2:26:2:32 | ControlFlowNode for ImportMember | smtplib_bad_via_attach.py:27:22:27:25 | ControlFlowNode for html | Cross-site scripting vulnerability due to $@. | smtplib_bad_via_attach.py:2:26:2:32 | ControlFlowNode for ImportMember | a user-provided value | +| django_mail.py:14:48:14:82 | After Attribute() | django_mail.py:14:48:14:82 | After Attribute() | django_mail.py:14:48:14:82 | After Attribute() | Cross-site scripting vulnerability due to $@. | django_mail.py:14:48:14:82 | After Attribute() | a user-provided value | +| django_mail.py:23:30:23:64 | After Attribute() | django_mail.py:23:30:23:64 | After Attribute() | django_mail.py:23:30:23:64 | After Attribute() | Cross-site scripting vulnerability due to $@. | django_mail.py:23:30:23:64 | After Attribute() | a user-provided value | +| django_mail.py:25:32:25:66 | After Attribute() | django_mail.py:25:32:25:66 | After Attribute() | django_mail.py:25:32:25:66 | After Attribute() | Cross-site scripting vulnerability due to $@. | django_mail.py:25:32:25:66 | After Attribute() | a user-provided value | +| flask_mail.py:13:22:13:41 | After Subscript | flask_mail.py:1:19:1:25 | After ImportMember | flask_mail.py:13:22:13:41 | After Subscript | Cross-site scripting vulnerability due to $@. | flask_mail.py:1:19:1:25 | After ImportMember | a user-provided value | +| flask_mail.py:18:14:18:33 | After Subscript | flask_mail.py:1:19:1:25 | After ImportMember | flask_mail.py:18:14:18:33 | After Subscript | Cross-site scripting vulnerability due to $@. | flask_mail.py:1:19:1:25 | After ImportMember | a user-provided value | +| flask_mail.py:31:24:31:43 | After Subscript | flask_mail.py:1:19:1:25 | After ImportMember | flask_mail.py:31:24:31:43 | After Subscript | Cross-site scripting vulnerability due to $@. | flask_mail.py:1:19:1:25 | After ImportMember | a user-provided value | +| sendgrid_mail.py:14:22:14:49 | After Subscript | sendgrid_mail.py:1:19:1:25 | After ImportMember | sendgrid_mail.py:14:22:14:49 | After Subscript | Cross-site scripting vulnerability due to $@. | sendgrid_mail.py:1:19:1:25 | After ImportMember | a user-provided value | +| sendgrid_mail.py:26:22:26:62 | After HtmlContent() | sendgrid_mail.py:1:19:1:25 | After ImportMember | sendgrid_mail.py:26:22:26:62 | After HtmlContent() | Cross-site scripting vulnerability due to $@. | sendgrid_mail.py:1:19:1:25 | After ImportMember | a user-provided value | +| sendgrid_mail.py:37:41:37:68 | After Subscript | sendgrid_mail.py:1:19:1:25 | After ImportMember | sendgrid_mail.py:37:41:37:68 | After Subscript | Cross-site scripting vulnerability due to $@. | sendgrid_mail.py:1:19:1:25 | After ImportMember | a user-provided value | +| sendgrid_via_mail_send_post_request_body_bad.py:16:26:16:79 | After Attribute() | sendgrid_via_mail_send_post_request_body_bad.py:3:19:3:25 | After ImportMember | sendgrid_via_mail_send_post_request_body_bad.py:16:26:16:79 | After Attribute() | Cross-site scripting vulnerability due to $@. | sendgrid_via_mail_send_post_request_body_bad.py:3:19:3:25 | After ImportMember | a user-provided value | +| sendgrid_via_mail_send_post_request_body_bad.py:27:25:27:77 | After Attribute() | sendgrid_via_mail_send_post_request_body_bad.py:3:19:3:25 | After ImportMember | sendgrid_via_mail_send_post_request_body_bad.py:27:25:27:77 | After Attribute() | Cross-site scripting vulnerability due to $@. | sendgrid_via_mail_send_post_request_body_bad.py:3:19:3:25 | After ImportMember | a user-provided value | +| sendgrid_via_mail_send_post_request_body_bad.py:41:25:41:79 | After Attribute() | sendgrid_via_mail_send_post_request_body_bad.py:3:19:3:25 | After ImportMember | sendgrid_via_mail_send_post_request_body_bad.py:41:25:41:79 | After Attribute() | Cross-site scripting vulnerability due to $@. | sendgrid_via_mail_send_post_request_body_bad.py:3:19:3:25 | After ImportMember | a user-provided value | +| smtplib_bad_subparts.py:24:22:24:25 | html | smtplib_bad_subparts.py:2:26:2:32 | After ImportMember | smtplib_bad_subparts.py:24:22:24:25 | html | Cross-site scripting vulnerability due to $@. | smtplib_bad_subparts.py:2:26:2:32 | After ImportMember | a user-provided value | +| smtplib_bad_via_attach.py:27:22:27:25 | html | smtplib_bad_via_attach.py:2:26:2:32 | After ImportMember | smtplib_bad_via_attach.py:27:22:27:25 | html | Cross-site scripting vulnerability due to $@. | smtplib_bad_via_attach.py:2:26:2:32 | After ImportMember | a user-provided value | diff --git a/python/ql/test/experimental/query-tests/Security/CWE-091-XsltInjection/XsltInjection.expected b/python/ql/test/experimental/query-tests/Security/CWE-091-XsltInjection/XsltInjection.expected index 28c85388a97f..5b997f1d0881 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-091-XsltInjection/XsltInjection.expected +++ b/python/ql/test/experimental/query-tests/Security/CWE-091-XsltInjection/XsltInjection.expected @@ -1,131 +1,120 @@ -#select -| xslt.py:14:29:14:37 | ControlFlowNode for xslt_root | xslt.py:3:26:3:32 | ControlFlowNode for ImportMember | xslt.py:14:29:14:37 | ControlFlowNode for xslt_root | This XSLT query depends on $@. | xslt.py:3:26:3:32 | ControlFlowNode for ImportMember | user-provided value | -| xsltInjection.py:12:28:12:36 | ControlFlowNode for xslt_root | xsltInjection.py:3:26:3:32 | ControlFlowNode for ImportMember | xsltInjection.py:12:28:12:36 | ControlFlowNode for xslt_root | This XSLT query depends on $@. | xsltInjection.py:3:26:3:32 | ControlFlowNode for ImportMember | user-provided value | -| xsltInjection.py:21:29:21:37 | ControlFlowNode for xslt_root | xsltInjection.py:3:26:3:32 | ControlFlowNode for ImportMember | xsltInjection.py:21:29:21:37 | ControlFlowNode for xslt_root | This XSLT query depends on $@. | xsltInjection.py:3:26:3:32 | ControlFlowNode for ImportMember | user-provided value | -| xsltInjection.py:31:24:31:32 | ControlFlowNode for xslt_root | xsltInjection.py:3:26:3:32 | ControlFlowNode for ImportMember | xsltInjection.py:31:24:31:32 | ControlFlowNode for xslt_root | This XSLT query depends on $@. | xsltInjection.py:3:26:3:32 | ControlFlowNode for ImportMember | user-provided value | -| xsltInjection.py:40:24:40:32 | ControlFlowNode for xslt_root | xsltInjection.py:3:26:3:32 | ControlFlowNode for ImportMember | xsltInjection.py:40:24:40:32 | ControlFlowNode for xslt_root | This XSLT query depends on $@. | xsltInjection.py:3:26:3:32 | ControlFlowNode for ImportMember | user-provided value | -| xsltInjection.py:50:24:50:32 | ControlFlowNode for xslt_root | xsltInjection.py:3:26:3:32 | ControlFlowNode for ImportMember | xsltInjection.py:50:24:50:32 | ControlFlowNode for xslt_root | This XSLT query depends on $@. | xsltInjection.py:3:26:3:32 | ControlFlowNode for ImportMember | user-provided value | edges -| xslt.py:3:26:3:32 | ControlFlowNode for ImportMember | xslt.py:3:26:3:32 | ControlFlowNode for request | provenance | | -| xslt.py:3:26:3:32 | ControlFlowNode for request | xslt.py:10:17:10:23 | ControlFlowNode for request | provenance | | -| xslt.py:10:5:10:13 | ControlFlowNode for xsltQuery | xslt.py:11:27:11:35 | ControlFlowNode for xsltQuery | provenance | | -| xslt.py:10:17:10:23 | ControlFlowNode for request | xslt.py:10:17:10:28 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | -| xslt.py:10:17:10:28 | ControlFlowNode for Attribute | xslt.py:10:17:10:43 | ControlFlowNode for Attribute() | provenance | dict.get | -| xslt.py:10:17:10:43 | ControlFlowNode for Attribute() | xslt.py:10:5:10:13 | ControlFlowNode for xsltQuery | provenance | | -| xslt.py:11:5:11:13 | ControlFlowNode for xslt_root | xslt.py:14:29:14:37 | ControlFlowNode for xslt_root | provenance | | -| xslt.py:11:17:11:36 | ControlFlowNode for Attribute() | xslt.py:11:5:11:13 | ControlFlowNode for xslt_root | provenance | | -| xslt.py:11:27:11:35 | ControlFlowNode for xsltQuery | xslt.py:11:17:11:36 | ControlFlowNode for Attribute() | provenance | | -| xslt.py:11:27:11:35 | ControlFlowNode for xsltQuery | xslt.py:11:17:11:36 | ControlFlowNode for Attribute() | provenance | Config | -| xslt.py:11:27:11:35 | ControlFlowNode for xsltQuery | xslt.py:11:17:11:36 | ControlFlowNode for Attribute() | provenance | Decoding-XML | -| xsltInjection.py:3:26:3:32 | ControlFlowNode for ImportMember | xsltInjection.py:3:26:3:32 | ControlFlowNode for request | provenance | | -| xsltInjection.py:3:26:3:32 | ControlFlowNode for request | xsltInjection.py:10:17:10:23 | ControlFlowNode for request | provenance | | -| xsltInjection.py:3:26:3:32 | ControlFlowNode for request | xsltInjection.py:17:17:17:23 | ControlFlowNode for request | provenance | | -| xsltInjection.py:3:26:3:32 | ControlFlowNode for request | xsltInjection.py:26:17:26:23 | ControlFlowNode for request | provenance | | -| xsltInjection.py:3:26:3:32 | ControlFlowNode for request | xsltInjection.py:35:17:35:23 | ControlFlowNode for request | provenance | | -| xsltInjection.py:3:26:3:32 | ControlFlowNode for request | xsltInjection.py:44:17:44:23 | ControlFlowNode for request | provenance | | -| xsltInjection.py:10:5:10:13 | ControlFlowNode for xsltQuery | xsltInjection.py:11:27:11:35 | ControlFlowNode for xsltQuery | provenance | | -| xsltInjection.py:10:17:10:23 | ControlFlowNode for request | xsltInjection.py:10:17:10:28 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | -| xsltInjection.py:10:17:10:28 | ControlFlowNode for Attribute | xsltInjection.py:10:17:10:43 | ControlFlowNode for Attribute() | provenance | dict.get | -| xsltInjection.py:10:17:10:43 | ControlFlowNode for Attribute() | xsltInjection.py:10:5:10:13 | ControlFlowNode for xsltQuery | provenance | | -| xsltInjection.py:11:5:11:13 | ControlFlowNode for xslt_root | xsltInjection.py:12:28:12:36 | ControlFlowNode for xslt_root | provenance | | -| xsltInjection.py:11:17:11:36 | ControlFlowNode for Attribute() | xsltInjection.py:11:5:11:13 | ControlFlowNode for xslt_root | provenance | | -| xsltInjection.py:11:27:11:35 | ControlFlowNode for xsltQuery | xsltInjection.py:11:17:11:36 | ControlFlowNode for Attribute() | provenance | | -| xsltInjection.py:11:27:11:35 | ControlFlowNode for xsltQuery | xsltInjection.py:11:17:11:36 | ControlFlowNode for Attribute() | provenance | Config | -| xsltInjection.py:11:27:11:35 | ControlFlowNode for xsltQuery | xsltInjection.py:11:17:11:36 | ControlFlowNode for Attribute() | provenance | Decoding-XML | -| xsltInjection.py:17:5:17:13 | ControlFlowNode for xsltQuery | xsltInjection.py:18:27:18:35 | ControlFlowNode for xsltQuery | provenance | | -| xsltInjection.py:17:17:17:23 | ControlFlowNode for request | xsltInjection.py:17:17:17:28 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | -| xsltInjection.py:17:17:17:28 | ControlFlowNode for Attribute | xsltInjection.py:17:17:17:43 | ControlFlowNode for Attribute() | provenance | dict.get | -| xsltInjection.py:17:17:17:43 | ControlFlowNode for Attribute() | xsltInjection.py:17:5:17:13 | ControlFlowNode for xsltQuery | provenance | | -| xsltInjection.py:18:5:18:13 | ControlFlowNode for xslt_root | xsltInjection.py:21:29:21:37 | ControlFlowNode for xslt_root | provenance | | -| xsltInjection.py:18:17:18:36 | ControlFlowNode for Attribute() | xsltInjection.py:18:5:18:13 | ControlFlowNode for xslt_root | provenance | | -| xsltInjection.py:18:27:18:35 | ControlFlowNode for xsltQuery | xsltInjection.py:18:17:18:36 | ControlFlowNode for Attribute() | provenance | | -| xsltInjection.py:18:27:18:35 | ControlFlowNode for xsltQuery | xsltInjection.py:18:17:18:36 | ControlFlowNode for Attribute() | provenance | Config | -| xsltInjection.py:18:27:18:35 | ControlFlowNode for xsltQuery | xsltInjection.py:18:17:18:36 | ControlFlowNode for Attribute() | provenance | Decoding-XML | -| xsltInjection.py:26:5:26:13 | ControlFlowNode for xsltQuery | xsltInjection.py:27:27:27:35 | ControlFlowNode for xsltQuery | provenance | | -| xsltInjection.py:26:17:26:23 | ControlFlowNode for request | xsltInjection.py:26:17:26:28 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | -| xsltInjection.py:26:17:26:28 | ControlFlowNode for Attribute | xsltInjection.py:26:17:26:43 | ControlFlowNode for Attribute() | provenance | dict.get | -| xsltInjection.py:26:17:26:43 | ControlFlowNode for Attribute() | xsltInjection.py:26:5:26:13 | ControlFlowNode for xsltQuery | provenance | | -| xsltInjection.py:27:5:27:13 | ControlFlowNode for xslt_root | xsltInjection.py:31:24:31:32 | ControlFlowNode for xslt_root | provenance | | -| xsltInjection.py:27:17:27:36 | ControlFlowNode for Attribute() | xsltInjection.py:27:5:27:13 | ControlFlowNode for xslt_root | provenance | | -| xsltInjection.py:27:27:27:35 | ControlFlowNode for xsltQuery | xsltInjection.py:27:17:27:36 | ControlFlowNode for Attribute() | provenance | | -| xsltInjection.py:27:27:27:35 | ControlFlowNode for xsltQuery | xsltInjection.py:27:17:27:36 | ControlFlowNode for Attribute() | provenance | Config | -| xsltInjection.py:27:27:27:35 | ControlFlowNode for xsltQuery | xsltInjection.py:27:17:27:36 | ControlFlowNode for Attribute() | provenance | Decoding-XML | -| xsltInjection.py:35:5:35:13 | ControlFlowNode for xsltQuery | xsltInjection.py:36:34:36:42 | ControlFlowNode for xsltQuery | provenance | | -| xsltInjection.py:35:17:35:23 | ControlFlowNode for request | xsltInjection.py:35:17:35:28 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | -| xsltInjection.py:35:17:35:28 | ControlFlowNode for Attribute | xsltInjection.py:35:17:35:43 | ControlFlowNode for Attribute() | provenance | dict.get | -| xsltInjection.py:35:17:35:43 | ControlFlowNode for Attribute() | xsltInjection.py:35:5:35:13 | ControlFlowNode for xsltQuery | provenance | | -| xsltInjection.py:36:5:36:13 | ControlFlowNode for xslt_root | xsltInjection.py:40:24:40:32 | ControlFlowNode for xslt_root | provenance | | -| xsltInjection.py:36:17:36:43 | ControlFlowNode for Attribute() | xsltInjection.py:36:5:36:13 | ControlFlowNode for xslt_root | provenance | | -| xsltInjection.py:36:34:36:42 | ControlFlowNode for xsltQuery | xsltInjection.py:36:17:36:43 | ControlFlowNode for Attribute() | provenance | | -| xsltInjection.py:36:34:36:42 | ControlFlowNode for xsltQuery | xsltInjection.py:36:17:36:43 | ControlFlowNode for Attribute() | provenance | Config | -| xsltInjection.py:36:34:36:42 | ControlFlowNode for xsltQuery | xsltInjection.py:36:17:36:43 | ControlFlowNode for Attribute() | provenance | Decoding-XML | -| xsltInjection.py:44:5:44:13 | ControlFlowNode for xsltQuery | xsltInjection.py:45:20:45:28 | ControlFlowNode for xsltQuery | provenance | | -| xsltInjection.py:44:17:44:23 | ControlFlowNode for request | xsltInjection.py:44:17:44:28 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | -| xsltInjection.py:44:17:44:28 | ControlFlowNode for Attribute | xsltInjection.py:44:17:44:43 | ControlFlowNode for Attribute() | provenance | dict.get | -| xsltInjection.py:44:17:44:43 | ControlFlowNode for Attribute() | xsltInjection.py:44:5:44:13 | ControlFlowNode for xsltQuery | provenance | | -| xsltInjection.py:45:5:45:15 | ControlFlowNode for xsltStrings [List element] | xsltInjection.py:46:38:46:48 | ControlFlowNode for xsltStrings [List element] | provenance | | -| xsltInjection.py:45:19:45:44 | ControlFlowNode for List [List element] | xsltInjection.py:45:5:45:15 | ControlFlowNode for xsltStrings [List element] | provenance | | -| xsltInjection.py:45:20:45:28 | ControlFlowNode for xsltQuery | xsltInjection.py:45:19:45:44 | ControlFlowNode for List [List element] | provenance | | -| xsltInjection.py:46:5:46:13 | ControlFlowNode for xslt_root | xsltInjection.py:50:24:50:32 | ControlFlowNode for xslt_root | provenance | | -| xsltInjection.py:46:17:46:49 | ControlFlowNode for Attribute() | xsltInjection.py:46:5:46:13 | ControlFlowNode for xslt_root | provenance | | -| xsltInjection.py:46:38:46:48 | ControlFlowNode for xsltStrings [List element] | xsltInjection.py:46:17:46:49 | ControlFlowNode for Attribute() | provenance | | -| xsltInjection.py:46:38:46:48 | ControlFlowNode for xsltStrings [List element] | xsltInjection.py:46:17:46:49 | ControlFlowNode for Attribute() | provenance | Config | -| xsltInjection.py:46:38:46:48 | ControlFlowNode for xsltStrings [List element] | xsltInjection.py:46:17:46:49 | ControlFlowNode for Attribute() | provenance | Decoding-XML | -| xsltInjection.py:46:38:46:48 | ControlFlowNode for xsltStrings [List element] | xsltInjection.py:46:17:46:49 | ControlFlowNode for Attribute() | provenance | MaD:58660 | +| xslt.py:3:26:3:32 | After ImportMember | xslt.py:3:26:3:32 | request | provenance | | +| xslt.py:3:26:3:32 | request | xslt.py:10:17:10:23 | request | provenance | | +| xslt.py:10:5:10:13 | xsltQuery | xslt.py:11:27:11:35 | xsltQuery | provenance | | +| xslt.py:10:17:10:23 | request | xslt.py:10:17:10:28 | After Attribute | provenance | AdditionalTaintStep | +| xslt.py:10:17:10:28 | After Attribute | xslt.py:10:17:10:43 | After Attribute() | provenance | dict.get | +| xslt.py:10:17:10:43 | After Attribute() | xslt.py:10:5:10:13 | xsltQuery | provenance | | +| xslt.py:11:5:11:13 | xslt_root | xslt.py:14:29:14:37 | xslt_root | provenance | | +| xslt.py:11:17:11:36 | After Attribute() | xslt.py:11:5:11:13 | xslt_root | provenance | | +| xslt.py:11:27:11:35 | xsltQuery | xslt.py:11:17:11:36 | After Attribute() | provenance | Config | +| xslt.py:11:27:11:35 | xsltQuery | xslt.py:11:17:11:36 | After Attribute() | provenance | Decoding-XML | +| xsltInjection.py:3:26:3:32 | After ImportMember | xsltInjection.py:3:26:3:32 | request | provenance | | +| xsltInjection.py:3:26:3:32 | request | xsltInjection.py:10:17:10:23 | request | provenance | | +| xsltInjection.py:3:26:3:32 | request | xsltInjection.py:17:17:17:23 | request | provenance | | +| xsltInjection.py:3:26:3:32 | request | xsltInjection.py:26:17:26:23 | request | provenance | | +| xsltInjection.py:3:26:3:32 | request | xsltInjection.py:35:17:35:23 | request | provenance | | +| xsltInjection.py:3:26:3:32 | request | xsltInjection.py:44:17:44:23 | request | provenance | | +| xsltInjection.py:10:5:10:13 | xsltQuery | xsltInjection.py:11:27:11:35 | xsltQuery | provenance | | +| xsltInjection.py:10:17:10:23 | request | xsltInjection.py:10:17:10:28 | After Attribute | provenance | AdditionalTaintStep | +| xsltInjection.py:10:17:10:28 | After Attribute | xsltInjection.py:10:17:10:43 | After Attribute() | provenance | dict.get | +| xsltInjection.py:10:17:10:43 | After Attribute() | xsltInjection.py:10:5:10:13 | xsltQuery | provenance | | +| xsltInjection.py:11:5:11:13 | xslt_root | xsltInjection.py:12:28:12:36 | xslt_root | provenance | | +| xsltInjection.py:11:17:11:36 | After Attribute() | xsltInjection.py:11:5:11:13 | xslt_root | provenance | | +| xsltInjection.py:11:27:11:35 | xsltQuery | xsltInjection.py:11:17:11:36 | After Attribute() | provenance | Config | +| xsltInjection.py:11:27:11:35 | xsltQuery | xsltInjection.py:11:17:11:36 | After Attribute() | provenance | Decoding-XML | +| xsltInjection.py:17:5:17:13 | xsltQuery | xsltInjection.py:18:27:18:35 | xsltQuery | provenance | | +| xsltInjection.py:17:17:17:23 | request | xsltInjection.py:17:17:17:28 | After Attribute | provenance | AdditionalTaintStep | +| xsltInjection.py:17:17:17:28 | After Attribute | xsltInjection.py:17:17:17:43 | After Attribute() | provenance | dict.get | +| xsltInjection.py:17:17:17:43 | After Attribute() | xsltInjection.py:17:5:17:13 | xsltQuery | provenance | | +| xsltInjection.py:18:5:18:13 | xslt_root | xsltInjection.py:21:29:21:37 | xslt_root | provenance | | +| xsltInjection.py:18:17:18:36 | After Attribute() | xsltInjection.py:18:5:18:13 | xslt_root | provenance | | +| xsltInjection.py:18:27:18:35 | xsltQuery | xsltInjection.py:18:17:18:36 | After Attribute() | provenance | Config | +| xsltInjection.py:18:27:18:35 | xsltQuery | xsltInjection.py:18:17:18:36 | After Attribute() | provenance | Decoding-XML | +| xsltInjection.py:26:5:26:13 | xsltQuery | xsltInjection.py:27:27:27:35 | xsltQuery | provenance | | +| xsltInjection.py:26:17:26:23 | request | xsltInjection.py:26:17:26:28 | After Attribute | provenance | AdditionalTaintStep | +| xsltInjection.py:26:17:26:28 | After Attribute | xsltInjection.py:26:17:26:43 | After Attribute() | provenance | dict.get | +| xsltInjection.py:26:17:26:43 | After Attribute() | xsltInjection.py:26:5:26:13 | xsltQuery | provenance | | +| xsltInjection.py:27:5:27:13 | xslt_root | xsltInjection.py:31:24:31:32 | xslt_root | provenance | | +| xsltInjection.py:27:17:27:36 | After Attribute() | xsltInjection.py:27:5:27:13 | xslt_root | provenance | | +| xsltInjection.py:27:27:27:35 | xsltQuery | xsltInjection.py:27:17:27:36 | After Attribute() | provenance | Config | +| xsltInjection.py:27:27:27:35 | xsltQuery | xsltInjection.py:27:17:27:36 | After Attribute() | provenance | Decoding-XML | +| xsltInjection.py:35:5:35:13 | xsltQuery | xsltInjection.py:36:34:36:42 | xsltQuery | provenance | | +| xsltInjection.py:35:17:35:23 | request | xsltInjection.py:35:17:35:28 | After Attribute | provenance | AdditionalTaintStep | +| xsltInjection.py:35:17:35:28 | After Attribute | xsltInjection.py:35:17:35:43 | After Attribute() | provenance | dict.get | +| xsltInjection.py:35:17:35:43 | After Attribute() | xsltInjection.py:35:5:35:13 | xsltQuery | provenance | | +| xsltInjection.py:36:5:36:13 | xslt_root | xsltInjection.py:40:24:40:32 | xslt_root | provenance | | +| xsltInjection.py:36:17:36:43 | After Attribute() | xsltInjection.py:36:5:36:13 | xslt_root | provenance | | +| xsltInjection.py:36:34:36:42 | xsltQuery | xsltInjection.py:36:17:36:43 | After Attribute() | provenance | Config | +| xsltInjection.py:36:34:36:42 | xsltQuery | xsltInjection.py:36:17:36:43 | After Attribute() | provenance | Decoding-XML | +| xsltInjection.py:44:5:44:13 | xsltQuery | xsltInjection.py:45:5:45:15 | xsltStrings | provenance | | +| xsltInjection.py:44:17:44:23 | request | xsltInjection.py:44:17:44:28 | After Attribute | provenance | AdditionalTaintStep | +| xsltInjection.py:44:17:44:28 | After Attribute | xsltInjection.py:44:17:44:43 | After Attribute() | provenance | dict.get | +| xsltInjection.py:44:17:44:43 | After Attribute() | xsltInjection.py:44:5:44:13 | xsltQuery | provenance | | +| xsltInjection.py:45:5:45:15 | xsltStrings | xsltInjection.py:46:38:46:48 | xsltStrings | provenance | | +| xsltInjection.py:46:5:46:13 | xslt_root | xsltInjection.py:50:24:50:32 | xslt_root | provenance | | +| xsltInjection.py:46:17:46:49 | After Attribute() | xsltInjection.py:46:5:46:13 | xslt_root | provenance | | +| xsltInjection.py:46:38:46:48 | xsltStrings | xsltInjection.py:46:17:46:49 | After Attribute() | provenance | Config | +| xsltInjection.py:46:38:46:48 | xsltStrings | xsltInjection.py:46:17:46:49 | After Attribute() | provenance | Decoding-XML | nodes -| xslt.py:3:26:3:32 | ControlFlowNode for ImportMember | semmle.label | ControlFlowNode for ImportMember | -| xslt.py:3:26:3:32 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| xslt.py:10:5:10:13 | ControlFlowNode for xsltQuery | semmle.label | ControlFlowNode for xsltQuery | -| xslt.py:10:17:10:23 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| xslt.py:10:17:10:28 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| xslt.py:10:17:10:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| xslt.py:11:5:11:13 | ControlFlowNode for xslt_root | semmle.label | ControlFlowNode for xslt_root | -| xslt.py:11:17:11:36 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| xslt.py:11:27:11:35 | ControlFlowNode for xsltQuery | semmle.label | ControlFlowNode for xsltQuery | -| xslt.py:14:29:14:37 | ControlFlowNode for xslt_root | semmle.label | ControlFlowNode for xslt_root | -| xsltInjection.py:3:26:3:32 | ControlFlowNode for ImportMember | semmle.label | ControlFlowNode for ImportMember | -| xsltInjection.py:3:26:3:32 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| xsltInjection.py:10:5:10:13 | ControlFlowNode for xsltQuery | semmle.label | ControlFlowNode for xsltQuery | -| xsltInjection.py:10:17:10:23 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| xsltInjection.py:10:17:10:28 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| xsltInjection.py:10:17:10:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| xsltInjection.py:11:5:11:13 | ControlFlowNode for xslt_root | semmle.label | ControlFlowNode for xslt_root | -| xsltInjection.py:11:17:11:36 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| xsltInjection.py:11:27:11:35 | ControlFlowNode for xsltQuery | semmle.label | ControlFlowNode for xsltQuery | -| xsltInjection.py:12:28:12:36 | ControlFlowNode for xslt_root | semmle.label | ControlFlowNode for xslt_root | -| xsltInjection.py:17:5:17:13 | ControlFlowNode for xsltQuery | semmle.label | ControlFlowNode for xsltQuery | -| xsltInjection.py:17:17:17:23 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| xsltInjection.py:17:17:17:28 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| xsltInjection.py:17:17:17:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| xsltInjection.py:18:5:18:13 | ControlFlowNode for xslt_root | semmle.label | ControlFlowNode for xslt_root | -| xsltInjection.py:18:17:18:36 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| xsltInjection.py:18:27:18:35 | ControlFlowNode for xsltQuery | semmle.label | ControlFlowNode for xsltQuery | -| xsltInjection.py:21:29:21:37 | ControlFlowNode for xslt_root | semmle.label | ControlFlowNode for xslt_root | -| xsltInjection.py:26:5:26:13 | ControlFlowNode for xsltQuery | semmle.label | ControlFlowNode for xsltQuery | -| xsltInjection.py:26:17:26:23 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| xsltInjection.py:26:17:26:28 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| xsltInjection.py:26:17:26:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| xsltInjection.py:27:5:27:13 | ControlFlowNode for xslt_root | semmle.label | ControlFlowNode for xslt_root | -| xsltInjection.py:27:17:27:36 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| xsltInjection.py:27:27:27:35 | ControlFlowNode for xsltQuery | semmle.label | ControlFlowNode for xsltQuery | -| xsltInjection.py:31:24:31:32 | ControlFlowNode for xslt_root | semmle.label | ControlFlowNode for xslt_root | -| xsltInjection.py:35:5:35:13 | ControlFlowNode for xsltQuery | semmle.label | ControlFlowNode for xsltQuery | -| xsltInjection.py:35:17:35:23 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| xsltInjection.py:35:17:35:28 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| xsltInjection.py:35:17:35:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| xsltInjection.py:36:5:36:13 | ControlFlowNode for xslt_root | semmle.label | ControlFlowNode for xslt_root | -| xsltInjection.py:36:17:36:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| xsltInjection.py:36:34:36:42 | ControlFlowNode for xsltQuery | semmle.label | ControlFlowNode for xsltQuery | -| xsltInjection.py:40:24:40:32 | ControlFlowNode for xslt_root | semmle.label | ControlFlowNode for xslt_root | -| xsltInjection.py:44:5:44:13 | ControlFlowNode for xsltQuery | semmle.label | ControlFlowNode for xsltQuery | -| xsltInjection.py:44:17:44:23 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| xsltInjection.py:44:17:44:28 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| xsltInjection.py:44:17:44:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| xsltInjection.py:45:5:45:15 | ControlFlowNode for xsltStrings [List element] | semmle.label | ControlFlowNode for xsltStrings [List element] | -| xsltInjection.py:45:19:45:44 | ControlFlowNode for List [List element] | semmle.label | ControlFlowNode for List [List element] | -| xsltInjection.py:45:20:45:28 | ControlFlowNode for xsltQuery | semmle.label | ControlFlowNode for xsltQuery | -| xsltInjection.py:46:5:46:13 | ControlFlowNode for xslt_root | semmle.label | ControlFlowNode for xslt_root | -| xsltInjection.py:46:17:46:49 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| xsltInjection.py:46:38:46:48 | ControlFlowNode for xsltStrings [List element] | semmle.label | ControlFlowNode for xsltStrings [List element] | -| xsltInjection.py:50:24:50:32 | ControlFlowNode for xslt_root | semmle.label | ControlFlowNode for xslt_root | +| xslt.py:3:26:3:32 | After ImportMember | semmle.label | After ImportMember | +| xslt.py:3:26:3:32 | request | semmle.label | request | +| xslt.py:10:5:10:13 | xsltQuery | semmle.label | xsltQuery | +| xslt.py:10:17:10:23 | request | semmle.label | request | +| xslt.py:10:17:10:28 | After Attribute | semmle.label | After Attribute | +| xslt.py:10:17:10:43 | After Attribute() | semmle.label | After Attribute() | +| xslt.py:11:5:11:13 | xslt_root | semmle.label | xslt_root | +| xslt.py:11:17:11:36 | After Attribute() | semmle.label | After Attribute() | +| xslt.py:11:27:11:35 | xsltQuery | semmle.label | xsltQuery | +| xslt.py:14:29:14:37 | xslt_root | semmle.label | xslt_root | +| xsltInjection.py:3:26:3:32 | After ImportMember | semmle.label | After ImportMember | +| xsltInjection.py:3:26:3:32 | request | semmle.label | request | +| xsltInjection.py:10:5:10:13 | xsltQuery | semmle.label | xsltQuery | +| xsltInjection.py:10:17:10:23 | request | semmle.label | request | +| xsltInjection.py:10:17:10:28 | After Attribute | semmle.label | After Attribute | +| xsltInjection.py:10:17:10:43 | After Attribute() | semmle.label | After Attribute() | +| xsltInjection.py:11:5:11:13 | xslt_root | semmle.label | xslt_root | +| xsltInjection.py:11:17:11:36 | After Attribute() | semmle.label | After Attribute() | +| xsltInjection.py:11:27:11:35 | xsltQuery | semmle.label | xsltQuery | +| xsltInjection.py:12:28:12:36 | xslt_root | semmle.label | xslt_root | +| xsltInjection.py:17:5:17:13 | xsltQuery | semmle.label | xsltQuery | +| xsltInjection.py:17:17:17:23 | request | semmle.label | request | +| xsltInjection.py:17:17:17:28 | After Attribute | semmle.label | After Attribute | +| xsltInjection.py:17:17:17:43 | After Attribute() | semmle.label | After Attribute() | +| xsltInjection.py:18:5:18:13 | xslt_root | semmle.label | xslt_root | +| xsltInjection.py:18:17:18:36 | After Attribute() | semmle.label | After Attribute() | +| xsltInjection.py:18:27:18:35 | xsltQuery | semmle.label | xsltQuery | +| xsltInjection.py:21:29:21:37 | xslt_root | semmle.label | xslt_root | +| xsltInjection.py:26:5:26:13 | xsltQuery | semmle.label | xsltQuery | +| xsltInjection.py:26:17:26:23 | request | semmle.label | request | +| xsltInjection.py:26:17:26:28 | After Attribute | semmle.label | After Attribute | +| xsltInjection.py:26:17:26:43 | After Attribute() | semmle.label | After Attribute() | +| xsltInjection.py:27:5:27:13 | xslt_root | semmle.label | xslt_root | +| xsltInjection.py:27:17:27:36 | After Attribute() | semmle.label | After Attribute() | +| xsltInjection.py:27:27:27:35 | xsltQuery | semmle.label | xsltQuery | +| xsltInjection.py:31:24:31:32 | xslt_root | semmle.label | xslt_root | +| xsltInjection.py:35:5:35:13 | xsltQuery | semmle.label | xsltQuery | +| xsltInjection.py:35:17:35:23 | request | semmle.label | request | +| xsltInjection.py:35:17:35:28 | After Attribute | semmle.label | After Attribute | +| xsltInjection.py:35:17:35:43 | After Attribute() | semmle.label | After Attribute() | +| xsltInjection.py:36:5:36:13 | xslt_root | semmle.label | xslt_root | +| xsltInjection.py:36:17:36:43 | After Attribute() | semmle.label | After Attribute() | +| xsltInjection.py:36:34:36:42 | xsltQuery | semmle.label | xsltQuery | +| xsltInjection.py:40:24:40:32 | xslt_root | semmle.label | xslt_root | +| xsltInjection.py:44:5:44:13 | xsltQuery | semmle.label | xsltQuery | +| xsltInjection.py:44:17:44:23 | request | semmle.label | request | +| xsltInjection.py:44:17:44:28 | After Attribute | semmle.label | After Attribute | +| xsltInjection.py:44:17:44:43 | After Attribute() | semmle.label | After Attribute() | +| xsltInjection.py:45:5:45:15 | xsltStrings | semmle.label | xsltStrings | +| xsltInjection.py:46:5:46:13 | xslt_root | semmle.label | xslt_root | +| xsltInjection.py:46:17:46:49 | After Attribute() | semmle.label | After Attribute() | +| xsltInjection.py:46:38:46:48 | xsltStrings | semmle.label | xsltStrings | +| xsltInjection.py:50:24:50:32 | xslt_root | semmle.label | xslt_root | subpaths +#select +| xslt.py:14:29:14:37 | xslt_root | xslt.py:3:26:3:32 | After ImportMember | xslt.py:14:29:14:37 | xslt_root | This XSLT query depends on $@. | xslt.py:3:26:3:32 | After ImportMember | user-provided value | +| xsltInjection.py:12:28:12:36 | xslt_root | xsltInjection.py:3:26:3:32 | After ImportMember | xsltInjection.py:12:28:12:36 | xslt_root | This XSLT query depends on $@. | xsltInjection.py:3:26:3:32 | After ImportMember | user-provided value | +| xsltInjection.py:21:29:21:37 | xslt_root | xsltInjection.py:3:26:3:32 | After ImportMember | xsltInjection.py:21:29:21:37 | xslt_root | This XSLT query depends on $@. | xsltInjection.py:3:26:3:32 | After ImportMember | user-provided value | +| xsltInjection.py:31:24:31:32 | xslt_root | xsltInjection.py:3:26:3:32 | After ImportMember | xsltInjection.py:31:24:31:32 | xslt_root | This XSLT query depends on $@. | xsltInjection.py:3:26:3:32 | After ImportMember | user-provided value | +| xsltInjection.py:40:24:40:32 | xslt_root | xsltInjection.py:3:26:3:32 | After ImportMember | xsltInjection.py:40:24:40:32 | xslt_root | This XSLT query depends on $@. | xsltInjection.py:3:26:3:32 | After ImportMember | user-provided value | +| xsltInjection.py:50:24:50:32 | xslt_root | xsltInjection.py:3:26:3:32 | After ImportMember | xsltInjection.py:50:24:50:32 | xslt_root | This XSLT query depends on $@. | xsltInjection.py:3:26:3:32 | After ImportMember | user-provided value | diff --git a/python/ql/test/experimental/query-tests/Security/CWE-094/Js2Py.expected b/python/ql/test/experimental/query-tests/Security/CWE-094/Js2Py.expected index 7798cdda143c..70e3a597134e 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-094/Js2Py.expected +++ b/python/ql/test/experimental/query-tests/Security/CWE-094/Js2Py.expected @@ -1,10 +1,10 @@ edges -| Js2PyTest.py:9:5:9:6 | ControlFlowNode for jk | Js2PyTest.py:10:18:10:28 | ControlFlowNode for Fstring | provenance | | -| Js2PyTest.py:9:10:9:22 | ControlFlowNode for Attribute | Js2PyTest.py:9:5:9:6 | ControlFlowNode for jk | provenance | AdditionalTaintStep | +| Js2PyTest.py:9:5:9:6 | jk | Js2PyTest.py:10:18:10:28 | After Fstring | provenance | | +| Js2PyTest.py:9:10:9:22 | After Attribute | Js2PyTest.py:9:5:9:6 | jk | provenance | AdditionalTaintStep | nodes -| Js2PyTest.py:9:5:9:6 | ControlFlowNode for jk | semmle.label | ControlFlowNode for jk | -| Js2PyTest.py:9:10:9:22 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| Js2PyTest.py:10:18:10:28 | ControlFlowNode for Fstring | semmle.label | ControlFlowNode for Fstring | +| Js2PyTest.py:9:5:9:6 | jk | semmle.label | jk | +| Js2PyTest.py:9:10:9:22 | After Attribute | semmle.label | After Attribute | +| Js2PyTest.py:10:18:10:28 | After Fstring | semmle.label | After Fstring | subpaths #select -| Js2PyTest.py:10:18:10:28 | ControlFlowNode for Fstring | Js2PyTest.py:9:10:9:22 | ControlFlowNode for Attribute | Js2PyTest.py:10:18:10:28 | ControlFlowNode for Fstring | This input to Js2Py depends on a $@. | Js2PyTest.py:9:10:9:22 | ControlFlowNode for Attribute | user-provided value | +| Js2PyTest.py:10:18:10:28 | After Fstring | Js2PyTest.py:9:10:9:22 | After Attribute | Js2PyTest.py:10:18:10:28 | After Fstring | This input to Js2Py depends on a $@. | Js2PyTest.py:9:10:9:22 | After Attribute | user-provided value | diff --git a/python/ql/test/experimental/query-tests/Security/CWE-1236/CsvInjection.expected b/python/ql/test/experimental/query-tests/Security/CWE-1236/CsvInjection.expected index aa90dfaeea0d..313bad416f33 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-1236/CsvInjection.expected +++ b/python/ql/test/experimental/query-tests/Security/CWE-1236/CsvInjection.expected @@ -1,32 +1,32 @@ -#select -| csv_bad.py:18:24:18:31 | ControlFlowNode for csv_data | csv_bad.py:9:19:9:25 | ControlFlowNode for ImportMember | csv_bad.py:18:24:18:31 | ControlFlowNode for csv_data | Csv injection might include code from $@. | csv_bad.py:9:19:9:25 | ControlFlowNode for ImportMember | this user input | -| csv_bad.py:19:25:19:32 | ControlFlowNode for csv_data | csv_bad.py:9:19:9:25 | ControlFlowNode for ImportMember | csv_bad.py:19:25:19:32 | ControlFlowNode for csv_data | Csv injection might include code from $@. | csv_bad.py:9:19:9:25 | ControlFlowNode for ImportMember | this user input | -| csv_bad.py:25:46:25:53 | ControlFlowNode for csv_data | csv_bad.py:9:19:9:25 | ControlFlowNode for ImportMember | csv_bad.py:25:46:25:53 | ControlFlowNode for csv_data | Csv injection might include code from $@. | csv_bad.py:9:19:9:25 | ControlFlowNode for ImportMember | this user input | edges -| csv_bad.py:9:19:9:25 | ControlFlowNode for ImportMember | csv_bad.py:9:19:9:25 | ControlFlowNode for request | provenance | | -| csv_bad.py:9:19:9:25 | ControlFlowNode for request | csv_bad.py:16:16:16:22 | ControlFlowNode for request | provenance | | -| csv_bad.py:9:19:9:25 | ControlFlowNode for request | csv_bad.py:24:16:24:22 | ControlFlowNode for request | provenance | | -| csv_bad.py:16:5:16:12 | ControlFlowNode for csv_data | csv_bad.py:18:24:18:31 | ControlFlowNode for csv_data | provenance | | -| csv_bad.py:16:5:16:12 | ControlFlowNode for csv_data | csv_bad.py:19:25:19:32 | ControlFlowNode for csv_data | provenance | | -| csv_bad.py:16:16:16:22 | ControlFlowNode for request | csv_bad.py:16:16:16:27 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | -| csv_bad.py:16:16:16:27 | ControlFlowNode for Attribute | csv_bad.py:16:16:16:38 | ControlFlowNode for Attribute() | provenance | dict.get | -| csv_bad.py:16:16:16:38 | ControlFlowNode for Attribute() | csv_bad.py:16:5:16:12 | ControlFlowNode for csv_data | provenance | | -| csv_bad.py:24:5:24:12 | ControlFlowNode for csv_data | csv_bad.py:25:46:25:53 | ControlFlowNode for csv_data | provenance | | -| csv_bad.py:24:16:24:22 | ControlFlowNode for request | csv_bad.py:24:16:24:27 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | -| csv_bad.py:24:16:24:27 | ControlFlowNode for Attribute | csv_bad.py:24:16:24:38 | ControlFlowNode for Attribute() | provenance | dict.get | -| csv_bad.py:24:16:24:38 | ControlFlowNode for Attribute() | csv_bad.py:24:5:24:12 | ControlFlowNode for csv_data | provenance | | +| csv_bad.py:9:19:9:25 | After ImportMember | csv_bad.py:9:19:9:25 | request | provenance | | +| csv_bad.py:9:19:9:25 | request | csv_bad.py:16:16:16:22 | request | provenance | | +| csv_bad.py:9:19:9:25 | request | csv_bad.py:24:16:24:22 | request | provenance | | +| csv_bad.py:16:5:16:12 | csv_data | csv_bad.py:18:24:18:31 | csv_data | provenance | | +| csv_bad.py:16:5:16:12 | csv_data | csv_bad.py:19:25:19:32 | csv_data | provenance | | +| csv_bad.py:16:16:16:22 | request | csv_bad.py:16:16:16:27 | After Attribute | provenance | AdditionalTaintStep | +| csv_bad.py:16:16:16:27 | After Attribute | csv_bad.py:16:16:16:38 | After Attribute() | provenance | dict.get | +| csv_bad.py:16:16:16:38 | After Attribute() | csv_bad.py:16:5:16:12 | csv_data | provenance | | +| csv_bad.py:24:5:24:12 | csv_data | csv_bad.py:25:46:25:53 | csv_data | provenance | | +| csv_bad.py:24:16:24:22 | request | csv_bad.py:24:16:24:27 | After Attribute | provenance | AdditionalTaintStep | +| csv_bad.py:24:16:24:27 | After Attribute | csv_bad.py:24:16:24:38 | After Attribute() | provenance | dict.get | +| csv_bad.py:24:16:24:38 | After Attribute() | csv_bad.py:24:5:24:12 | csv_data | provenance | | nodes -| csv_bad.py:9:19:9:25 | ControlFlowNode for ImportMember | semmle.label | ControlFlowNode for ImportMember | -| csv_bad.py:9:19:9:25 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| csv_bad.py:16:5:16:12 | ControlFlowNode for csv_data | semmle.label | ControlFlowNode for csv_data | -| csv_bad.py:16:16:16:22 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| csv_bad.py:16:16:16:27 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| csv_bad.py:16:16:16:38 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| csv_bad.py:18:24:18:31 | ControlFlowNode for csv_data | semmle.label | ControlFlowNode for csv_data | -| csv_bad.py:19:25:19:32 | ControlFlowNode for csv_data | semmle.label | ControlFlowNode for csv_data | -| csv_bad.py:24:5:24:12 | ControlFlowNode for csv_data | semmle.label | ControlFlowNode for csv_data | -| csv_bad.py:24:16:24:22 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| csv_bad.py:24:16:24:27 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| csv_bad.py:24:16:24:38 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| csv_bad.py:25:46:25:53 | ControlFlowNode for csv_data | semmle.label | ControlFlowNode for csv_data | +| csv_bad.py:9:19:9:25 | After ImportMember | semmle.label | After ImportMember | +| csv_bad.py:9:19:9:25 | request | semmle.label | request | +| csv_bad.py:16:5:16:12 | csv_data | semmle.label | csv_data | +| csv_bad.py:16:16:16:22 | request | semmle.label | request | +| csv_bad.py:16:16:16:27 | After Attribute | semmle.label | After Attribute | +| csv_bad.py:16:16:16:38 | After Attribute() | semmle.label | After Attribute() | +| csv_bad.py:18:24:18:31 | csv_data | semmle.label | csv_data | +| csv_bad.py:19:25:19:32 | csv_data | semmle.label | csv_data | +| csv_bad.py:24:5:24:12 | csv_data | semmle.label | csv_data | +| csv_bad.py:24:16:24:22 | request | semmle.label | request | +| csv_bad.py:24:16:24:27 | After Attribute | semmle.label | After Attribute | +| csv_bad.py:24:16:24:38 | After Attribute() | semmle.label | After Attribute() | +| csv_bad.py:25:46:25:53 | csv_data | semmle.label | csv_data | subpaths +#select +| csv_bad.py:18:24:18:31 | csv_data | csv_bad.py:9:19:9:25 | After ImportMember | csv_bad.py:18:24:18:31 | csv_data | Csv injection might include code from $@. | csv_bad.py:9:19:9:25 | After ImportMember | this user input | +| csv_bad.py:19:25:19:32 | csv_data | csv_bad.py:9:19:9:25 | After ImportMember | csv_bad.py:19:25:19:32 | csv_data | Csv injection might include code from $@. | csv_bad.py:9:19:9:25 | After ImportMember | this user input | +| csv_bad.py:25:46:25:53 | csv_data | csv_bad.py:9:19:9:25 | After ImportMember | csv_bad.py:25:46:25:53 | csv_data | Csv injection might include code from $@. | csv_bad.py:9:19:9:25 | After ImportMember | this user input | diff --git a/python/ql/test/experimental/query-tests/Security/CWE-1427-PromptInjection/PromptInjection.expected b/python/ql/test/experimental/query-tests/Security/CWE-1427-PromptInjection/PromptInjection.expected index 6e814aac4964..cf4fe1ec784d 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-1427-PromptInjection/PromptInjection.expected +++ b/python/ql/test/experimental/query-tests/Security/CWE-1427-PromptInjection/PromptInjection.expected @@ -1,97 +1,87 @@ #select -| agent_instructions.py:9:50:9:89 | ControlFlowNode for BinaryExpr | agent_instructions.py:2:26:2:32 | ControlFlowNode for ImportMember | agent_instructions.py:9:50:9:89 | ControlFlowNode for BinaryExpr | This prompt construction depends on a $@. | agent_instructions.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value | -| agent_instructions.py:25:28:25:32 | ControlFlowNode for input | agent_instructions.py:2:26:2:32 | ControlFlowNode for ImportMember | agent_instructions.py:25:28:25:32 | ControlFlowNode for input | This prompt construction depends on a $@. | agent_instructions.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value | -| agent_instructions.py:35:28:35:32 | ControlFlowNode for input | agent_instructions.py:2:26:2:32 | ControlFlowNode for ImportMember | agent_instructions.py:35:28:35:32 | ControlFlowNode for input | This prompt construction depends on a $@. | agent_instructions.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value | -| anthropic_test.py:17:16:17:37 | ControlFlowNode for BinaryExpr | anthropic_test.py:2:26:2:32 | ControlFlowNode for ImportMember | anthropic_test.py:17:16:17:37 | ControlFlowNode for BinaryExpr | This prompt construction depends on a $@. | anthropic_test.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value | -| anthropic_test.py:21:28:21:32 | ControlFlowNode for query | anthropic_test.py:2:26:2:32 | ControlFlowNode for ImportMember | anthropic_test.py:21:28:21:32 | ControlFlowNode for query | This prompt construction depends on a $@. | anthropic_test.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value | -| anthropic_test.py:29:16:29:37 | ControlFlowNode for BinaryExpr | anthropic_test.py:2:26:2:32 | ControlFlowNode for ImportMember | anthropic_test.py:29:16:29:37 | ControlFlowNode for BinaryExpr | This prompt construction depends on a $@. | anthropic_test.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value | -| anthropic_test.py:33:28:33:32 | ControlFlowNode for query | anthropic_test.py:2:26:2:32 | ControlFlowNode for ImportMember | anthropic_test.py:33:28:33:32 | ControlFlowNode for query | This prompt construction depends on a $@. | anthropic_test.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value | -| anthropic_test.py:41:16:41:37 | ControlFlowNode for BinaryExpr | anthropic_test.py:2:26:2:32 | ControlFlowNode for ImportMember | anthropic_test.py:41:16:41:37 | ControlFlowNode for BinaryExpr | This prompt construction depends on a $@. | anthropic_test.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value | -| anthropic_test.py:45:28:45:32 | ControlFlowNode for query | anthropic_test.py:2:26:2:32 | ControlFlowNode for ImportMember | anthropic_test.py:45:28:45:32 | ControlFlowNode for query | This prompt construction depends on a $@. | anthropic_test.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value | -| anthropic_test.py:53:16:53:37 | ControlFlowNode for BinaryExpr | anthropic_test.py:2:26:2:32 | ControlFlowNode for ImportMember | anthropic_test.py:53:16:53:37 | ControlFlowNode for BinaryExpr | This prompt construction depends on a $@. | anthropic_test.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value | -| anthropic_test.py:57:28:57:32 | ControlFlowNode for query | anthropic_test.py:2:26:2:32 | ControlFlowNode for ImportMember | anthropic_test.py:57:28:57:32 | ControlFlowNode for query | This prompt construction depends on a $@. | anthropic_test.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value | -| openai_test.py:17:22:17:46 | ControlFlowNode for BinaryExpr | openai_test.py:2:26:2:32 | ControlFlowNode for ImportMember | openai_test.py:17:22:17:46 | ControlFlowNode for BinaryExpr | This prompt construction depends on a $@. | openai_test.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value | -| openai_test.py:18:15:18:19 | ControlFlowNode for query | openai_test.py:2:26:2:32 | ControlFlowNode for ImportMember | openai_test.py:18:15:18:19 | ControlFlowNode for query | This prompt construction depends on a $@. | openai_test.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value | -| openai_test.py:22:22:22:46 | ControlFlowNode for BinaryExpr | openai_test.py:2:26:2:32 | ControlFlowNode for ImportMember | openai_test.py:22:22:22:46 | ControlFlowNode for BinaryExpr | This prompt construction depends on a $@. | openai_test.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value | -| openai_test.py:23:15:37:9 | ControlFlowNode for List | openai_test.py:2:26:2:32 | ControlFlowNode for ImportMember | openai_test.py:23:15:37:9 | ControlFlowNode for List | This prompt construction depends on a $@. | openai_test.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value | -| openai_test.py:26:28:26:51 | ControlFlowNode for BinaryExpr | openai_test.py:2:26:2:32 | ControlFlowNode for ImportMember | openai_test.py:26:28:26:51 | ControlFlowNode for BinaryExpr | This prompt construction depends on a $@. | openai_test.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value | -| openai_test.py:33:33:33:37 | ControlFlowNode for query | openai_test.py:2:26:2:32 | ControlFlowNode for ImportMember | openai_test.py:33:33:33:37 | ControlFlowNode for query | This prompt construction depends on a $@. | openai_test.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value | -| openai_test.py:41:22:41:46 | ControlFlowNode for BinaryExpr | openai_test.py:2:26:2:32 | ControlFlowNode for ImportMember | openai_test.py:41:22:41:46 | ControlFlowNode for BinaryExpr | This prompt construction depends on a $@. | openai_test.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value | -| openai_test.py:42:15:42:19 | ControlFlowNode for query | openai_test.py:2:26:2:32 | ControlFlowNode for ImportMember | openai_test.py:42:15:42:19 | ControlFlowNode for query | This prompt construction depends on a $@. | openai_test.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value | -| openai_test.py:53:33:53:37 | ControlFlowNode for query | openai_test.py:2:26:2:32 | ControlFlowNode for ImportMember | openai_test.py:53:33:53:37 | ControlFlowNode for query | This prompt construction depends on a $@. | openai_test.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value | -| openai_test.py:63:28:63:51 | ControlFlowNode for BinaryExpr | openai_test.py:2:26:2:32 | ControlFlowNode for ImportMember | openai_test.py:63:28:63:51 | ControlFlowNode for BinaryExpr | This prompt construction depends on a $@. | openai_test.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value | -| openai_test.py:67:28:67:32 | ControlFlowNode for query | openai_test.py:2:26:2:32 | ControlFlowNode for ImportMember | openai_test.py:67:28:67:32 | ControlFlowNode for query | This prompt construction depends on a $@. | openai_test.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value | -| openai_test.py:71:28:71:32 | ControlFlowNode for query | openai_test.py:2:26:2:32 | ControlFlowNode for ImportMember | openai_test.py:71:28:71:32 | ControlFlowNode for query | This prompt construction depends on a $@. | openai_test.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value | -| openai_test.py:80:28:80:51 | ControlFlowNode for BinaryExpr | openai_test.py:2:26:2:32 | ControlFlowNode for ImportMember | openai_test.py:80:28:80:51 | ControlFlowNode for BinaryExpr | This prompt construction depends on a $@. | openai_test.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value | -| openai_test.py:84:28:84:32 | ControlFlowNode for query | openai_test.py:2:26:2:32 | ControlFlowNode for ImportMember | openai_test.py:84:28:84:32 | ControlFlowNode for query | This prompt construction depends on a $@. | openai_test.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value | -| openai_test.py:92:22:92:46 | ControlFlowNode for BinaryExpr | openai_test.py:2:26:2:32 | ControlFlowNode for ImportMember | openai_test.py:92:22:92:46 | ControlFlowNode for BinaryExpr | This prompt construction depends on a $@. | openai_test.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value | +| agent_instructions.py:9:50:9:89 | After BinaryExpr | agent_instructions.py:2:26:2:32 | After ImportMember | agent_instructions.py:9:50:9:89 | After BinaryExpr | This prompt construction depends on a $@. | agent_instructions.py:2:26:2:32 | After ImportMember | user-provided value | +| agent_instructions.py:25:28:25:32 | input | agent_instructions.py:2:26:2:32 | After ImportMember | agent_instructions.py:25:28:25:32 | input | This prompt construction depends on a $@. | agent_instructions.py:2:26:2:32 | After ImportMember | user-provided value | +| agent_instructions.py:35:28:35:32 | input | agent_instructions.py:2:26:2:32 | After ImportMember | agent_instructions.py:35:28:35:32 | input | This prompt construction depends on a $@. | agent_instructions.py:2:26:2:32 | After ImportMember | user-provided value | +| anthropic_test.py:17:16:17:37 | After BinaryExpr | anthropic_test.py:2:26:2:32 | After ImportMember | anthropic_test.py:17:16:17:37 | After BinaryExpr | This prompt construction depends on a $@. | anthropic_test.py:2:26:2:32 | After ImportMember | user-provided value | +| anthropic_test.py:21:28:21:32 | query | anthropic_test.py:2:26:2:32 | After ImportMember | anthropic_test.py:21:28:21:32 | query | This prompt construction depends on a $@. | anthropic_test.py:2:26:2:32 | After ImportMember | user-provided value | +| anthropic_test.py:29:16:29:37 | After BinaryExpr | anthropic_test.py:2:26:2:32 | After ImportMember | anthropic_test.py:29:16:29:37 | After BinaryExpr | This prompt construction depends on a $@. | anthropic_test.py:2:26:2:32 | After ImportMember | user-provided value | +| anthropic_test.py:33:28:33:32 | query | anthropic_test.py:2:26:2:32 | After ImportMember | anthropic_test.py:33:28:33:32 | query | This prompt construction depends on a $@. | anthropic_test.py:2:26:2:32 | After ImportMember | user-provided value | +| anthropic_test.py:41:16:41:37 | After BinaryExpr | anthropic_test.py:2:26:2:32 | After ImportMember | anthropic_test.py:41:16:41:37 | After BinaryExpr | This prompt construction depends on a $@. | anthropic_test.py:2:26:2:32 | After ImportMember | user-provided value | +| anthropic_test.py:45:28:45:32 | query | anthropic_test.py:2:26:2:32 | After ImportMember | anthropic_test.py:45:28:45:32 | query | This prompt construction depends on a $@. | anthropic_test.py:2:26:2:32 | After ImportMember | user-provided value | +| anthropic_test.py:53:16:53:37 | After BinaryExpr | anthropic_test.py:2:26:2:32 | After ImportMember | anthropic_test.py:53:16:53:37 | After BinaryExpr | This prompt construction depends on a $@. | anthropic_test.py:2:26:2:32 | After ImportMember | user-provided value | +| anthropic_test.py:57:28:57:32 | query | anthropic_test.py:2:26:2:32 | After ImportMember | anthropic_test.py:57:28:57:32 | query | This prompt construction depends on a $@. | anthropic_test.py:2:26:2:32 | After ImportMember | user-provided value | +| openai_test.py:17:22:17:46 | After BinaryExpr | openai_test.py:2:26:2:32 | After ImportMember | openai_test.py:17:22:17:46 | After BinaryExpr | This prompt construction depends on a $@. | openai_test.py:2:26:2:32 | After ImportMember | user-provided value | +| openai_test.py:18:15:18:19 | query | openai_test.py:2:26:2:32 | After ImportMember | openai_test.py:18:15:18:19 | query | This prompt construction depends on a $@. | openai_test.py:2:26:2:32 | After ImportMember | user-provided value | +| openai_test.py:22:22:22:46 | After BinaryExpr | openai_test.py:2:26:2:32 | After ImportMember | openai_test.py:22:22:22:46 | After BinaryExpr | This prompt construction depends on a $@. | openai_test.py:2:26:2:32 | After ImportMember | user-provided value | +| openai_test.py:23:15:37:9 | After List | openai_test.py:2:26:2:32 | After ImportMember | openai_test.py:23:15:37:9 | After List | This prompt construction depends on a $@. | openai_test.py:2:26:2:32 | After ImportMember | user-provided value | +| openai_test.py:26:28:26:51 | After BinaryExpr | openai_test.py:2:26:2:32 | After ImportMember | openai_test.py:26:28:26:51 | After BinaryExpr | This prompt construction depends on a $@. | openai_test.py:2:26:2:32 | After ImportMember | user-provided value | +| openai_test.py:33:33:33:37 | query | openai_test.py:2:26:2:32 | After ImportMember | openai_test.py:33:33:33:37 | query | This prompt construction depends on a $@. | openai_test.py:2:26:2:32 | After ImportMember | user-provided value | +| openai_test.py:41:22:41:46 | After BinaryExpr | openai_test.py:2:26:2:32 | After ImportMember | openai_test.py:41:22:41:46 | After BinaryExpr | This prompt construction depends on a $@. | openai_test.py:2:26:2:32 | After ImportMember | user-provided value | +| openai_test.py:42:15:42:19 | query | openai_test.py:2:26:2:32 | After ImportMember | openai_test.py:42:15:42:19 | query | This prompt construction depends on a $@. | openai_test.py:2:26:2:32 | After ImportMember | user-provided value | +| openai_test.py:53:33:53:37 | query | openai_test.py:2:26:2:32 | After ImportMember | openai_test.py:53:33:53:37 | query | This prompt construction depends on a $@. | openai_test.py:2:26:2:32 | After ImportMember | user-provided value | +| openai_test.py:63:28:63:51 | After BinaryExpr | openai_test.py:2:26:2:32 | After ImportMember | openai_test.py:63:28:63:51 | After BinaryExpr | This prompt construction depends on a $@. | openai_test.py:2:26:2:32 | After ImportMember | user-provided value | +| openai_test.py:67:28:67:32 | query | openai_test.py:2:26:2:32 | After ImportMember | openai_test.py:67:28:67:32 | query | This prompt construction depends on a $@. | openai_test.py:2:26:2:32 | After ImportMember | user-provided value | +| openai_test.py:71:28:71:32 | query | openai_test.py:2:26:2:32 | After ImportMember | openai_test.py:71:28:71:32 | query | This prompt construction depends on a $@. | openai_test.py:2:26:2:32 | After ImportMember | user-provided value | +| openai_test.py:80:28:80:51 | After BinaryExpr | openai_test.py:2:26:2:32 | After ImportMember | openai_test.py:80:28:80:51 | After BinaryExpr | This prompt construction depends on a $@. | openai_test.py:2:26:2:32 | After ImportMember | user-provided value | +| openai_test.py:84:28:84:32 | query | openai_test.py:2:26:2:32 | After ImportMember | openai_test.py:84:28:84:32 | query | This prompt construction depends on a $@. | openai_test.py:2:26:2:32 | After ImportMember | user-provided value | +| openai_test.py:92:22:92:46 | After BinaryExpr | openai_test.py:2:26:2:32 | After ImportMember | openai_test.py:92:22:92:46 | After BinaryExpr | This prompt construction depends on a $@. | openai_test.py:2:26:2:32 | After ImportMember | user-provided value | edges -| agent_instructions.py:2:26:2:32 | ControlFlowNode for ImportMember | agent_instructions.py:2:26:2:32 | ControlFlowNode for request | provenance | | -| agent_instructions.py:2:26:2:32 | ControlFlowNode for request | agent_instructions.py:7:13:7:19 | ControlFlowNode for request | provenance | | -| agent_instructions.py:2:26:2:32 | ControlFlowNode for request | agent_instructions.py:17:13:17:19 | ControlFlowNode for request | provenance | | -| agent_instructions.py:7:5:7:9 | ControlFlowNode for input | agent_instructions.py:9:50:9:89 | ControlFlowNode for BinaryExpr | provenance | Sink:MaD:11 | -| agent_instructions.py:7:13:7:19 | ControlFlowNode for request | agent_instructions.py:7:13:7:24 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | -| agent_instructions.py:7:13:7:24 | ControlFlowNode for Attribute | agent_instructions.py:7:13:7:37 | ControlFlowNode for Attribute() | provenance | dict.get | -| agent_instructions.py:7:13:7:24 | ControlFlowNode for Attribute | agent_instructions.py:7:13:7:37 | ControlFlowNode for Attribute() | provenance | dict.get(input) | -| agent_instructions.py:7:13:7:37 | ControlFlowNode for Attribute() | agent_instructions.py:7:5:7:9 | ControlFlowNode for input | provenance | | -| agent_instructions.py:17:5:17:9 | ControlFlowNode for input | agent_instructions.py:25:28:25:32 | ControlFlowNode for input | provenance | | -| agent_instructions.py:17:5:17:9 | ControlFlowNode for input | agent_instructions.py:35:28:35:32 | ControlFlowNode for input | provenance | | -| agent_instructions.py:17:13:17:19 | ControlFlowNode for request | agent_instructions.py:17:13:17:24 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | -| agent_instructions.py:17:13:17:24 | ControlFlowNode for Attribute | agent_instructions.py:17:13:17:37 | ControlFlowNode for Attribute() | provenance | dict.get | -| agent_instructions.py:17:13:17:24 | ControlFlowNode for Attribute | agent_instructions.py:17:13:17:37 | ControlFlowNode for Attribute() | provenance | dict.get(input) | -| agent_instructions.py:17:13:17:37 | ControlFlowNode for Attribute() | agent_instructions.py:17:5:17:9 | ControlFlowNode for input | provenance | | -| anthropic_test.py:2:26:2:32 | ControlFlowNode for ImportMember | anthropic_test.py:2:26:2:32 | ControlFlowNode for request | provenance | | -| anthropic_test.py:2:26:2:32 | ControlFlowNode for request | anthropic_test.py:11:15:11:21 | ControlFlowNode for request | provenance | | -| anthropic_test.py:2:26:2:32 | ControlFlowNode for request | anthropic_test.py:12:13:12:19 | ControlFlowNode for request | provenance | | -| anthropic_test.py:11:5:11:11 | ControlFlowNode for persona | anthropic_test.py:17:16:17:37 | ControlFlowNode for BinaryExpr | provenance | Sink:MaD:4 | -| anthropic_test.py:11:5:11:11 | ControlFlowNode for persona | anthropic_test.py:29:16:29:37 | ControlFlowNode for BinaryExpr | provenance | Sink:MaD:6 | -| anthropic_test.py:11:5:11:11 | ControlFlowNode for persona | anthropic_test.py:41:16:41:37 | ControlFlowNode for BinaryExpr | provenance | Sink:MaD:4 | -| anthropic_test.py:11:5:11:11 | ControlFlowNode for persona | anthropic_test.py:53:16:53:37 | ControlFlowNode for BinaryExpr | provenance | Sink:MaD:2 | -| anthropic_test.py:11:15:11:21 | ControlFlowNode for request | anthropic_test.py:11:15:11:26 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | -| anthropic_test.py:11:15:11:21 | ControlFlowNode for request | anthropic_test.py:12:13:12:24 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | -| anthropic_test.py:11:15:11:26 | ControlFlowNode for Attribute | anthropic_test.py:11:15:11:41 | ControlFlowNode for Attribute() | provenance | dict.get | -| anthropic_test.py:11:15:11:41 | ControlFlowNode for Attribute() | anthropic_test.py:11:5:11:11 | ControlFlowNode for persona | provenance | | -| anthropic_test.py:12:5:12:9 | ControlFlowNode for query | anthropic_test.py:21:28:21:32 | ControlFlowNode for query | provenance | Sink:MaD:3 | -| anthropic_test.py:12:5:12:9 | ControlFlowNode for query | anthropic_test.py:33:28:33:32 | ControlFlowNode for query | provenance | Sink:MaD:5 | -| anthropic_test.py:12:5:12:9 | ControlFlowNode for query | anthropic_test.py:45:28:45:32 | ControlFlowNode for query | provenance | Sink:MaD:3 | -| anthropic_test.py:12:5:12:9 | ControlFlowNode for query | anthropic_test.py:57:28:57:32 | ControlFlowNode for query | provenance | Sink:MaD:1 | -| anthropic_test.py:12:13:12:19 | ControlFlowNode for request | anthropic_test.py:12:13:12:24 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | -| anthropic_test.py:12:13:12:24 | ControlFlowNode for Attribute | anthropic_test.py:12:13:12:37 | ControlFlowNode for Attribute() | provenance | dict.get | -| anthropic_test.py:12:13:12:37 | ControlFlowNode for Attribute() | anthropic_test.py:12:5:12:9 | ControlFlowNode for query | provenance | | -| openai_test.py:2:26:2:32 | ControlFlowNode for ImportMember | openai_test.py:2:26:2:32 | ControlFlowNode for request | provenance | | -| openai_test.py:2:26:2:32 | ControlFlowNode for request | openai_test.py:12:15:12:21 | ControlFlowNode for request | provenance | | -| openai_test.py:2:26:2:32 | ControlFlowNode for request | openai_test.py:13:13:13:19 | ControlFlowNode for request | provenance | | -| openai_test.py:12:5:12:11 | ControlFlowNode for persona | openai_test.py:17:22:17:46 | ControlFlowNode for BinaryExpr | provenance | Sink:MaD:10 | -| openai_test.py:12:5:12:11 | ControlFlowNode for persona | openai_test.py:22:22:22:46 | ControlFlowNode for BinaryExpr | provenance | Sink:MaD:10 | -| openai_test.py:12:5:12:11 | ControlFlowNode for persona | openai_test.py:26:28:26:51 | ControlFlowNode for BinaryExpr | provenance | | -| openai_test.py:12:5:12:11 | ControlFlowNode for persona | openai_test.py:26:28:26:51 | ControlFlowNode for BinaryExpr | provenance | | -| openai_test.py:12:5:12:11 | ControlFlowNode for persona | openai_test.py:41:22:41:46 | ControlFlowNode for BinaryExpr | provenance | Sink:MaD:10 | -| openai_test.py:12:5:12:11 | ControlFlowNode for persona | openai_test.py:63:28:63:51 | ControlFlowNode for BinaryExpr | provenance | Sink:MaD:8 | -| openai_test.py:12:5:12:11 | ControlFlowNode for persona | openai_test.py:80:28:80:51 | ControlFlowNode for BinaryExpr | provenance | Sink:MaD:8 | -| openai_test.py:12:5:12:11 | ControlFlowNode for persona | openai_test.py:92:22:92:46 | ControlFlowNode for BinaryExpr | provenance | Sink:MaD:7 | -| openai_test.py:12:15:12:21 | ControlFlowNode for request | openai_test.py:12:15:12:26 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | -| openai_test.py:12:15:12:21 | ControlFlowNode for request | openai_test.py:13:13:13:24 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | -| openai_test.py:12:15:12:26 | ControlFlowNode for Attribute | openai_test.py:12:15:12:41 | ControlFlowNode for Attribute() | provenance | dict.get | -| openai_test.py:12:15:12:41 | ControlFlowNode for Attribute() | openai_test.py:12:5:12:11 | ControlFlowNode for persona | provenance | | -| openai_test.py:13:5:13:9 | ControlFlowNode for query | openai_test.py:18:15:18:19 | ControlFlowNode for query | provenance | Sink:MaD:9 | -| openai_test.py:13:5:13:9 | ControlFlowNode for query | openai_test.py:33:33:33:37 | ControlFlowNode for query | provenance | | -| openai_test.py:13:5:13:9 | ControlFlowNode for query | openai_test.py:33:33:33:37 | ControlFlowNode for query | provenance | | -| openai_test.py:13:5:13:9 | ControlFlowNode for query | openai_test.py:42:15:42:19 | ControlFlowNode for query | provenance | Sink:MaD:9 | -| openai_test.py:13:5:13:9 | ControlFlowNode for query | openai_test.py:53:33:53:37 | ControlFlowNode for query | provenance | | -| openai_test.py:13:5:13:9 | ControlFlowNode for query | openai_test.py:67:28:67:32 | ControlFlowNode for query | provenance | Sink:MaD:8 | -| openai_test.py:13:5:13:9 | ControlFlowNode for query | openai_test.py:71:28:71:32 | ControlFlowNode for query | provenance | Sink:MaD:8 | -| openai_test.py:13:5:13:9 | ControlFlowNode for query | openai_test.py:84:28:84:32 | ControlFlowNode for query | provenance | Sink:MaD:8 | -| openai_test.py:13:13:13:19 | ControlFlowNode for request | openai_test.py:13:13:13:24 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | -| openai_test.py:13:13:13:24 | ControlFlowNode for Attribute | openai_test.py:13:13:13:37 | ControlFlowNode for Attribute() | provenance | dict.get | -| openai_test.py:13:13:13:37 | ControlFlowNode for Attribute() | openai_test.py:13:5:13:9 | ControlFlowNode for query | provenance | | -| openai_test.py:24:13:27:13 | ControlFlowNode for Dict [Dictionary element at key content] | openai_test.py:23:15:37:9 | ControlFlowNode for List | provenance | Sink:MaD:9 Sink:MaD:9 | -| openai_test.py:26:28:26:51 | ControlFlowNode for BinaryExpr | openai_test.py:24:13:27:13 | ControlFlowNode for Dict [Dictionary element at key content] | provenance | | -| openai_test.py:28:13:36:13 | ControlFlowNode for Dict [Dictionary element at key content, List element, Dictionary element at key text] | openai_test.py:23:15:37:9 | ControlFlowNode for List | provenance | Sink:MaD:9 Sink:MaD:9 | -| openai_test.py:28:13:36:13 | ControlFlowNode for Dict [Dictionary element at key content, List element, Dictionary element at key text] | openai_test.py:23:15:37:9 | ControlFlowNode for List | provenance | Sink:MaD:9 Sink:MaD:9 Sink:MaD:9 | -| openai_test.py:28:13:36:13 | ControlFlowNode for Dict [Dictionary element at key content, List element, Dictionary element at key text] | openai_test.py:23:15:37:9 | ControlFlowNode for List | provenance | Sink:MaD:9 Sink:MaD:9 Sink:MaD:9 Sink:MaD:9 | -| openai_test.py:30:28:35:17 | ControlFlowNode for List [List element, Dictionary element at key text] | openai_test.py:28:13:36:13 | ControlFlowNode for Dict [Dictionary element at key content, List element, Dictionary element at key text] | provenance | | -| openai_test.py:31:21:34:21 | ControlFlowNode for Dict [Dictionary element at key text] | openai_test.py:30:28:35:17 | ControlFlowNode for List [List element, Dictionary element at key text] | provenance | | -| openai_test.py:33:33:33:37 | ControlFlowNode for query | openai_test.py:31:21:34:21 | ControlFlowNode for Dict [Dictionary element at key text] | provenance | | +| agent_instructions.py:2:26:2:32 | After ImportMember | agent_instructions.py:2:26:2:32 | request | provenance | | +| agent_instructions.py:2:26:2:32 | request | agent_instructions.py:7:13:7:19 | request | provenance | | +| agent_instructions.py:2:26:2:32 | request | agent_instructions.py:17:13:17:19 | request | provenance | | +| agent_instructions.py:7:5:7:9 | input | agent_instructions.py:9:50:9:89 | After BinaryExpr | provenance | Sink:MaD:11 | +| agent_instructions.py:7:13:7:19 | request | agent_instructions.py:7:13:7:24 | After Attribute | provenance | AdditionalTaintStep | +| agent_instructions.py:7:13:7:24 | After Attribute | agent_instructions.py:7:13:7:37 | After Attribute() | provenance | dict.get | +| agent_instructions.py:7:13:7:37 | After Attribute() | agent_instructions.py:7:5:7:9 | input | provenance | | +| agent_instructions.py:17:5:17:9 | input | agent_instructions.py:25:28:25:32 | input | provenance | | +| agent_instructions.py:17:5:17:9 | input | agent_instructions.py:35:28:35:32 | input | provenance | | +| agent_instructions.py:17:13:17:19 | request | agent_instructions.py:17:13:17:24 | After Attribute | provenance | AdditionalTaintStep | +| agent_instructions.py:17:13:17:24 | After Attribute | agent_instructions.py:17:13:17:37 | After Attribute() | provenance | dict.get | +| agent_instructions.py:17:13:17:37 | After Attribute() | agent_instructions.py:17:5:17:9 | input | provenance | | +| anthropic_test.py:2:26:2:32 | After ImportMember | anthropic_test.py:2:26:2:32 | request | provenance | | +| anthropic_test.py:2:26:2:32 | request | anthropic_test.py:11:15:11:21 | request | provenance | | +| anthropic_test.py:2:26:2:32 | request | anthropic_test.py:12:13:12:19 | request | provenance | | +| anthropic_test.py:11:5:11:11 | persona | anthropic_test.py:17:16:17:37 | After BinaryExpr | provenance | Sink:MaD:4 | +| anthropic_test.py:11:5:11:11 | persona | anthropic_test.py:29:16:29:37 | After BinaryExpr | provenance | Sink:MaD:6 | +| anthropic_test.py:11:5:11:11 | persona | anthropic_test.py:41:16:41:37 | After BinaryExpr | provenance | Sink:MaD:4 | +| anthropic_test.py:11:5:11:11 | persona | anthropic_test.py:53:16:53:37 | After BinaryExpr | provenance | Sink:MaD:2 | +| anthropic_test.py:11:15:11:21 | request | anthropic_test.py:11:15:11:26 | After Attribute | provenance | AdditionalTaintStep | +| anthropic_test.py:11:15:11:21 | request | anthropic_test.py:12:13:12:24 | After Attribute | provenance | AdditionalTaintStep | +| anthropic_test.py:11:15:11:26 | After Attribute | anthropic_test.py:11:15:11:41 | After Attribute() | provenance | dict.get | +| anthropic_test.py:11:15:11:41 | After Attribute() | anthropic_test.py:11:5:11:11 | persona | provenance | | +| anthropic_test.py:12:5:12:9 | query | anthropic_test.py:21:28:21:32 | query | provenance | Sink:MaD:3 | +| anthropic_test.py:12:5:12:9 | query | anthropic_test.py:33:28:33:32 | query | provenance | Sink:MaD:5 | +| anthropic_test.py:12:5:12:9 | query | anthropic_test.py:45:28:45:32 | query | provenance | Sink:MaD:3 | +| anthropic_test.py:12:5:12:9 | query | anthropic_test.py:57:28:57:32 | query | provenance | Sink:MaD:1 | +| anthropic_test.py:12:13:12:19 | request | anthropic_test.py:12:13:12:24 | After Attribute | provenance | AdditionalTaintStep | +| anthropic_test.py:12:13:12:24 | After Attribute | anthropic_test.py:12:13:12:37 | After Attribute() | provenance | dict.get | +| anthropic_test.py:12:13:12:37 | After Attribute() | anthropic_test.py:12:5:12:9 | query | provenance | | +| openai_test.py:2:26:2:32 | After ImportMember | openai_test.py:2:26:2:32 | request | provenance | | +| openai_test.py:2:26:2:32 | request | openai_test.py:12:15:12:21 | request | provenance | | +| openai_test.py:2:26:2:32 | request | openai_test.py:13:13:13:19 | request | provenance | | +| openai_test.py:12:5:12:11 | persona | openai_test.py:17:22:17:46 | After BinaryExpr | provenance | Sink:MaD:10 | +| openai_test.py:12:5:12:11 | persona | openai_test.py:22:22:22:46 | After BinaryExpr | provenance | Sink:MaD:10 | +| openai_test.py:12:5:12:11 | persona | openai_test.py:23:15:37:9 | After List | provenance | Sink:MaD:9 | +| openai_test.py:12:5:12:11 | persona | openai_test.py:26:28:26:51 | After BinaryExpr | provenance | | +| openai_test.py:12:5:12:11 | persona | openai_test.py:41:22:41:46 | After BinaryExpr | provenance | Sink:MaD:10 | +| openai_test.py:12:5:12:11 | persona | openai_test.py:63:28:63:51 | After BinaryExpr | provenance | Sink:MaD:8 | +| openai_test.py:12:5:12:11 | persona | openai_test.py:80:28:80:51 | After BinaryExpr | provenance | Sink:MaD:8 | +| openai_test.py:12:5:12:11 | persona | openai_test.py:92:22:92:46 | After BinaryExpr | provenance | Sink:MaD:7 | +| openai_test.py:12:15:12:21 | request | openai_test.py:12:15:12:26 | After Attribute | provenance | AdditionalTaintStep | +| openai_test.py:12:15:12:21 | request | openai_test.py:13:13:13:24 | After Attribute | provenance | AdditionalTaintStep | +| openai_test.py:12:15:12:26 | After Attribute | openai_test.py:12:15:12:41 | After Attribute() | provenance | dict.get | +| openai_test.py:12:15:12:41 | After Attribute() | openai_test.py:12:5:12:11 | persona | provenance | | +| openai_test.py:13:5:13:9 | query | openai_test.py:18:15:18:19 | query | provenance | Sink:MaD:9 | +| openai_test.py:13:5:13:9 | query | openai_test.py:23:15:37:9 | After List | provenance | Sink:MaD:9 | +| openai_test.py:13:5:13:9 | query | openai_test.py:33:33:33:37 | query | provenance | | +| openai_test.py:13:5:13:9 | query | openai_test.py:42:15:42:19 | query | provenance | Sink:MaD:9 | +| openai_test.py:13:5:13:9 | query | openai_test.py:53:33:53:37 | query | provenance | | +| openai_test.py:13:5:13:9 | query | openai_test.py:67:28:67:32 | query | provenance | Sink:MaD:8 | +| openai_test.py:13:5:13:9 | query | openai_test.py:71:28:71:32 | query | provenance | Sink:MaD:8 | +| openai_test.py:13:5:13:9 | query | openai_test.py:84:28:84:32 | query | provenance | Sink:MaD:8 | +| openai_test.py:13:13:13:19 | request | openai_test.py:13:13:13:24 | After Attribute | provenance | AdditionalTaintStep | +| openai_test.py:13:13:13:24 | After Attribute | openai_test.py:13:13:13:37 | After Attribute() | provenance | dict.get | +| openai_test.py:13:13:13:37 | After Attribute() | openai_test.py:13:5:13:9 | query | provenance | | models | 1 | Sink: Anthropic; Member[beta].Member[messages].Member[create].Argument[messages:].ListElement.DictionaryElement[content]; prompt-injection | | 2 | Sink: Anthropic; Member[beta].Member[messages].Member[create].Argument[system:]; prompt-injection | @@ -105,66 +95,60 @@ models | 10 | Sink: OpenAI; Member[responses].Member[create].Argument[instructions:]; prompt-injection | | 11 | Sink: agents; Member[Agent].Argument[instructions:]; prompt-injection | nodes -| agent_instructions.py:2:26:2:32 | ControlFlowNode for ImportMember | semmle.label | ControlFlowNode for ImportMember | -| agent_instructions.py:2:26:2:32 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| agent_instructions.py:7:5:7:9 | ControlFlowNode for input | semmle.label | ControlFlowNode for input | -| agent_instructions.py:7:13:7:19 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| agent_instructions.py:7:13:7:24 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| agent_instructions.py:7:13:7:37 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| agent_instructions.py:9:50:9:89 | ControlFlowNode for BinaryExpr | semmle.label | ControlFlowNode for BinaryExpr | -| agent_instructions.py:17:5:17:9 | ControlFlowNode for input | semmle.label | ControlFlowNode for input | -| agent_instructions.py:17:13:17:19 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| agent_instructions.py:17:13:17:24 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| agent_instructions.py:17:13:17:37 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| agent_instructions.py:25:28:25:32 | ControlFlowNode for input | semmle.label | ControlFlowNode for input | -| agent_instructions.py:35:28:35:32 | ControlFlowNode for input | semmle.label | ControlFlowNode for input | -| anthropic_test.py:2:26:2:32 | ControlFlowNode for ImportMember | semmle.label | ControlFlowNode for ImportMember | -| anthropic_test.py:2:26:2:32 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| anthropic_test.py:11:5:11:11 | ControlFlowNode for persona | semmle.label | ControlFlowNode for persona | -| anthropic_test.py:11:15:11:21 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| anthropic_test.py:11:15:11:26 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| anthropic_test.py:11:15:11:41 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| anthropic_test.py:12:5:12:9 | ControlFlowNode for query | semmle.label | ControlFlowNode for query | -| anthropic_test.py:12:13:12:19 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| anthropic_test.py:12:13:12:24 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| anthropic_test.py:12:13:12:37 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| anthropic_test.py:17:16:17:37 | ControlFlowNode for BinaryExpr | semmle.label | ControlFlowNode for BinaryExpr | -| anthropic_test.py:21:28:21:32 | ControlFlowNode for query | semmle.label | ControlFlowNode for query | -| anthropic_test.py:29:16:29:37 | ControlFlowNode for BinaryExpr | semmle.label | ControlFlowNode for BinaryExpr | -| anthropic_test.py:33:28:33:32 | ControlFlowNode for query | semmle.label | ControlFlowNode for query | -| anthropic_test.py:41:16:41:37 | ControlFlowNode for BinaryExpr | semmle.label | ControlFlowNode for BinaryExpr | -| anthropic_test.py:45:28:45:32 | ControlFlowNode for query | semmle.label | ControlFlowNode for query | -| anthropic_test.py:53:16:53:37 | ControlFlowNode for BinaryExpr | semmle.label | ControlFlowNode for BinaryExpr | -| anthropic_test.py:57:28:57:32 | ControlFlowNode for query | semmle.label | ControlFlowNode for query | -| openai_test.py:2:26:2:32 | ControlFlowNode for ImportMember | semmle.label | ControlFlowNode for ImportMember | -| openai_test.py:2:26:2:32 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| openai_test.py:12:5:12:11 | ControlFlowNode for persona | semmle.label | ControlFlowNode for persona | -| openai_test.py:12:15:12:21 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| openai_test.py:12:15:12:26 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| openai_test.py:12:15:12:41 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| openai_test.py:13:5:13:9 | ControlFlowNode for query | semmle.label | ControlFlowNode for query | -| openai_test.py:13:13:13:19 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| openai_test.py:13:13:13:24 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| openai_test.py:13:13:13:37 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| openai_test.py:17:22:17:46 | ControlFlowNode for BinaryExpr | semmle.label | ControlFlowNode for BinaryExpr | -| openai_test.py:18:15:18:19 | ControlFlowNode for query | semmle.label | ControlFlowNode for query | -| openai_test.py:22:22:22:46 | ControlFlowNode for BinaryExpr | semmle.label | ControlFlowNode for BinaryExpr | -| openai_test.py:23:15:37:9 | ControlFlowNode for List | semmle.label | ControlFlowNode for List | -| openai_test.py:24:13:27:13 | ControlFlowNode for Dict [Dictionary element at key content] | semmle.label | ControlFlowNode for Dict [Dictionary element at key content] | -| openai_test.py:26:28:26:51 | ControlFlowNode for BinaryExpr | semmle.label | ControlFlowNode for BinaryExpr | -| openai_test.py:26:28:26:51 | ControlFlowNode for BinaryExpr | semmle.label | ControlFlowNode for BinaryExpr | -| openai_test.py:28:13:36:13 | ControlFlowNode for Dict [Dictionary element at key content, List element, Dictionary element at key text] | semmle.label | ControlFlowNode for Dict [Dictionary element at key content, List element, Dictionary element at key text] | -| openai_test.py:30:28:35:17 | ControlFlowNode for List [List element, Dictionary element at key text] | semmle.label | ControlFlowNode for List [List element, Dictionary element at key text] | -| openai_test.py:31:21:34:21 | ControlFlowNode for Dict [Dictionary element at key text] | semmle.label | ControlFlowNode for Dict [Dictionary element at key text] | -| openai_test.py:33:33:33:37 | ControlFlowNode for query | semmle.label | ControlFlowNode for query | -| openai_test.py:33:33:33:37 | ControlFlowNode for query | semmle.label | ControlFlowNode for query | -| openai_test.py:41:22:41:46 | ControlFlowNode for BinaryExpr | semmle.label | ControlFlowNode for BinaryExpr | -| openai_test.py:42:15:42:19 | ControlFlowNode for query | semmle.label | ControlFlowNode for query | -| openai_test.py:53:33:53:37 | ControlFlowNode for query | semmle.label | ControlFlowNode for query | -| openai_test.py:63:28:63:51 | ControlFlowNode for BinaryExpr | semmle.label | ControlFlowNode for BinaryExpr | -| openai_test.py:67:28:67:32 | ControlFlowNode for query | semmle.label | ControlFlowNode for query | -| openai_test.py:71:28:71:32 | ControlFlowNode for query | semmle.label | ControlFlowNode for query | -| openai_test.py:80:28:80:51 | ControlFlowNode for BinaryExpr | semmle.label | ControlFlowNode for BinaryExpr | -| openai_test.py:84:28:84:32 | ControlFlowNode for query | semmle.label | ControlFlowNode for query | -| openai_test.py:92:22:92:46 | ControlFlowNode for BinaryExpr | semmle.label | ControlFlowNode for BinaryExpr | +| agent_instructions.py:2:26:2:32 | After ImportMember | semmle.label | After ImportMember | +| agent_instructions.py:2:26:2:32 | request | semmle.label | request | +| agent_instructions.py:7:5:7:9 | input | semmle.label | input | +| agent_instructions.py:7:13:7:19 | request | semmle.label | request | +| agent_instructions.py:7:13:7:24 | After Attribute | semmle.label | After Attribute | +| agent_instructions.py:7:13:7:37 | After Attribute() | semmle.label | After Attribute() | +| agent_instructions.py:9:50:9:89 | After BinaryExpr | semmle.label | After BinaryExpr | +| agent_instructions.py:17:5:17:9 | input | semmle.label | input | +| agent_instructions.py:17:13:17:19 | request | semmle.label | request | +| agent_instructions.py:17:13:17:24 | After Attribute | semmle.label | After Attribute | +| agent_instructions.py:17:13:17:37 | After Attribute() | semmle.label | After Attribute() | +| agent_instructions.py:25:28:25:32 | input | semmle.label | input | +| agent_instructions.py:35:28:35:32 | input | semmle.label | input | +| anthropic_test.py:2:26:2:32 | After ImportMember | semmle.label | After ImportMember | +| anthropic_test.py:2:26:2:32 | request | semmle.label | request | +| anthropic_test.py:11:5:11:11 | persona | semmle.label | persona | +| anthropic_test.py:11:15:11:21 | request | semmle.label | request | +| anthropic_test.py:11:15:11:26 | After Attribute | semmle.label | After Attribute | +| anthropic_test.py:11:15:11:41 | After Attribute() | semmle.label | After Attribute() | +| anthropic_test.py:12:5:12:9 | query | semmle.label | query | +| anthropic_test.py:12:13:12:19 | request | semmle.label | request | +| anthropic_test.py:12:13:12:24 | After Attribute | semmle.label | After Attribute | +| anthropic_test.py:12:13:12:37 | After Attribute() | semmle.label | After Attribute() | +| anthropic_test.py:17:16:17:37 | After BinaryExpr | semmle.label | After BinaryExpr | +| anthropic_test.py:21:28:21:32 | query | semmle.label | query | +| anthropic_test.py:29:16:29:37 | After BinaryExpr | semmle.label | After BinaryExpr | +| anthropic_test.py:33:28:33:32 | query | semmle.label | query | +| anthropic_test.py:41:16:41:37 | After BinaryExpr | semmle.label | After BinaryExpr | +| anthropic_test.py:45:28:45:32 | query | semmle.label | query | +| anthropic_test.py:53:16:53:37 | After BinaryExpr | semmle.label | After BinaryExpr | +| anthropic_test.py:57:28:57:32 | query | semmle.label | query | +| openai_test.py:2:26:2:32 | After ImportMember | semmle.label | After ImportMember | +| openai_test.py:2:26:2:32 | request | semmle.label | request | +| openai_test.py:12:5:12:11 | persona | semmle.label | persona | +| openai_test.py:12:15:12:21 | request | semmle.label | request | +| openai_test.py:12:15:12:26 | After Attribute | semmle.label | After Attribute | +| openai_test.py:12:15:12:41 | After Attribute() | semmle.label | After Attribute() | +| openai_test.py:13:5:13:9 | query | semmle.label | query | +| openai_test.py:13:13:13:19 | request | semmle.label | request | +| openai_test.py:13:13:13:24 | After Attribute | semmle.label | After Attribute | +| openai_test.py:13:13:13:37 | After Attribute() | semmle.label | After Attribute() | +| openai_test.py:17:22:17:46 | After BinaryExpr | semmle.label | After BinaryExpr | +| openai_test.py:18:15:18:19 | query | semmle.label | query | +| openai_test.py:22:22:22:46 | After BinaryExpr | semmle.label | After BinaryExpr | +| openai_test.py:23:15:37:9 | After List | semmle.label | After List | +| openai_test.py:26:28:26:51 | After BinaryExpr | semmle.label | After BinaryExpr | +| openai_test.py:33:33:33:37 | query | semmle.label | query | +| openai_test.py:41:22:41:46 | After BinaryExpr | semmle.label | After BinaryExpr | +| openai_test.py:42:15:42:19 | query | semmle.label | query | +| openai_test.py:53:33:53:37 | query | semmle.label | query | +| openai_test.py:63:28:63:51 | After BinaryExpr | semmle.label | After BinaryExpr | +| openai_test.py:67:28:67:32 | query | semmle.label | query | +| openai_test.py:71:28:71:32 | query | semmle.label | query | +| openai_test.py:80:28:80:51 | After BinaryExpr | semmle.label | After BinaryExpr | +| openai_test.py:84:28:84:32 | query | semmle.label | query | +| openai_test.py:92:22:92:46 | After BinaryExpr | semmle.label | After BinaryExpr | subpaths diff --git a/python/ql/test/experimental/query-tests/Security/CWE-176/UnicodeBypassValidation.expected b/python/ql/test/experimental/query-tests/Security/CWE-176/UnicodeBypassValidation.expected index b667a4bd04d4..0f6c72bc3f11 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-176/UnicodeBypassValidation.expected +++ b/python/ql/test/experimental/query-tests/Security/CWE-176/UnicodeBypassValidation.expected @@ -1,33 +1,33 @@ edges -| samples.py:2:26:2:32 | ControlFlowNode for ImportMember | samples.py:2:26:2:32 | ControlFlowNode for request | provenance | | -| samples.py:2:26:2:32 | ControlFlowNode for request | samples.py:9:25:9:31 | ControlFlowNode for request | provenance | | -| samples.py:2:26:2:32 | ControlFlowNode for request | samples.py:16:25:16:31 | ControlFlowNode for request | provenance | | -| samples.py:9:5:9:14 | ControlFlowNode for user_input | samples.py:10:59:10:68 | ControlFlowNode for user_input | provenance | | -| samples.py:9:18:9:47 | ControlFlowNode for escape() | samples.py:9:5:9:14 | ControlFlowNode for user_input | provenance | | -| samples.py:9:25:9:31 | ControlFlowNode for request | samples.py:9:25:9:36 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | -| samples.py:9:25:9:36 | ControlFlowNode for Attribute | samples.py:9:25:9:46 | ControlFlowNode for Attribute() | provenance | dict.get | -| samples.py:9:25:9:46 | ControlFlowNode for Attribute() | samples.py:9:18:9:47 | ControlFlowNode for escape() | provenance | Config | -| samples.py:16:5:16:14 | ControlFlowNode for user_input | samples.py:20:62:20:71 | ControlFlowNode for user_input | provenance | | -| samples.py:16:18:16:47 | ControlFlowNode for escape() | samples.py:16:5:16:14 | ControlFlowNode for user_input | provenance | | -| samples.py:16:25:16:31 | ControlFlowNode for request | samples.py:16:25:16:36 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | -| samples.py:16:25:16:36 | ControlFlowNode for Attribute | samples.py:16:25:16:46 | ControlFlowNode for Attribute() | provenance | dict.get | -| samples.py:16:25:16:46 | ControlFlowNode for Attribute() | samples.py:16:18:16:47 | ControlFlowNode for escape() | provenance | Config | +| samples.py:2:26:2:32 | After ImportMember | samples.py:2:26:2:32 | request | provenance | | +| samples.py:2:26:2:32 | request | samples.py:9:25:9:31 | request | provenance | | +| samples.py:2:26:2:32 | request | samples.py:16:25:16:31 | request | provenance | | +| samples.py:9:5:9:14 | user_input | samples.py:10:59:10:68 | user_input | provenance | | +| samples.py:9:18:9:47 | After escape() | samples.py:9:5:9:14 | user_input | provenance | | +| samples.py:9:25:9:31 | request | samples.py:9:25:9:36 | After Attribute | provenance | AdditionalTaintStep | +| samples.py:9:25:9:36 | After Attribute | samples.py:9:25:9:46 | After Attribute() | provenance | dict.get | +| samples.py:9:25:9:46 | After Attribute() | samples.py:9:18:9:47 | After escape() | provenance | Config | +| samples.py:16:5:16:14 | user_input | samples.py:20:62:20:71 | user_input | provenance | | +| samples.py:16:18:16:47 | After escape() | samples.py:16:5:16:14 | user_input | provenance | | +| samples.py:16:25:16:31 | request | samples.py:16:25:16:36 | After Attribute | provenance | AdditionalTaintStep | +| samples.py:16:25:16:36 | After Attribute | samples.py:16:25:16:46 | After Attribute() | provenance | dict.get | +| samples.py:16:25:16:46 | After Attribute() | samples.py:16:18:16:47 | After escape() | provenance | Config | nodes -| samples.py:2:26:2:32 | ControlFlowNode for ImportMember | semmle.label | ControlFlowNode for ImportMember | -| samples.py:2:26:2:32 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| samples.py:9:5:9:14 | ControlFlowNode for user_input | semmle.label | ControlFlowNode for user_input | -| samples.py:9:18:9:47 | ControlFlowNode for escape() | semmle.label | ControlFlowNode for escape() | -| samples.py:9:25:9:31 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| samples.py:9:25:9:36 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| samples.py:9:25:9:46 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| samples.py:10:59:10:68 | ControlFlowNode for user_input | semmle.label | ControlFlowNode for user_input | -| samples.py:16:5:16:14 | ControlFlowNode for user_input | semmle.label | ControlFlowNode for user_input | -| samples.py:16:18:16:47 | ControlFlowNode for escape() | semmle.label | ControlFlowNode for escape() | -| samples.py:16:25:16:31 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| samples.py:16:25:16:36 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| samples.py:16:25:16:46 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| samples.py:20:62:20:71 | ControlFlowNode for user_input | semmle.label | ControlFlowNode for user_input | +| samples.py:2:26:2:32 | After ImportMember | semmle.label | After ImportMember | +| samples.py:2:26:2:32 | request | semmle.label | request | +| samples.py:9:5:9:14 | user_input | semmle.label | user_input | +| samples.py:9:18:9:47 | After escape() | semmle.label | After escape() | +| samples.py:9:25:9:31 | request | semmle.label | request | +| samples.py:9:25:9:36 | After Attribute | semmle.label | After Attribute | +| samples.py:9:25:9:46 | After Attribute() | semmle.label | After Attribute() | +| samples.py:10:59:10:68 | user_input | semmle.label | user_input | +| samples.py:16:5:16:14 | user_input | semmle.label | user_input | +| samples.py:16:18:16:47 | After escape() | semmle.label | After escape() | +| samples.py:16:25:16:31 | request | semmle.label | request | +| samples.py:16:25:16:36 | After Attribute | semmle.label | After Attribute | +| samples.py:16:25:16:46 | After Attribute() | semmle.label | After Attribute() | +| samples.py:20:62:20:71 | user_input | semmle.label | user_input | subpaths #select -| samples.py:10:59:10:68 | ControlFlowNode for user_input | samples.py:2:26:2:32 | ControlFlowNode for ImportMember | samples.py:10:59:10:68 | ControlFlowNode for user_input | This $@ processes unsafely $@ and any logical validation in-between could be bypassed using special Unicode characters. | samples.py:10:59:10:68 | ControlFlowNode for user_input | Unicode transformation (Unicode normalization) | samples.py:2:26:2:32 | ControlFlowNode for ImportMember | remote user-controlled data | -| samples.py:20:62:20:71 | ControlFlowNode for user_input | samples.py:2:26:2:32 | ControlFlowNode for ImportMember | samples.py:20:62:20:71 | ControlFlowNode for user_input | This $@ processes unsafely $@ and any logical validation in-between could be bypassed using special Unicode characters. | samples.py:20:62:20:71 | ControlFlowNode for user_input | Unicode transformation (Unicode normalization) | samples.py:2:26:2:32 | ControlFlowNode for ImportMember | remote user-controlled data | +| samples.py:10:59:10:68 | user_input | samples.py:2:26:2:32 | After ImportMember | samples.py:10:59:10:68 | user_input | This $@ processes unsafely $@ and any logical validation in-between could be bypassed using special Unicode characters. | samples.py:10:59:10:68 | user_input | Unicode transformation (Unicode normalization) | samples.py:2:26:2:32 | After ImportMember | remote user-controlled data | +| samples.py:20:62:20:71 | user_input | samples.py:2:26:2:32 | After ImportMember | samples.py:20:62:20:71 | user_input | This $@ processes unsafely $@ and any logical validation in-between could be bypassed using special Unicode characters. | samples.py:20:62:20:71 | user_input | Unicode transformation (Unicode normalization) | samples.py:2:26:2:32 | After ImportMember | remote user-controlled data | diff --git a/python/ql/test/experimental/query-tests/Security/CWE-208/TimingAttackAgainstHash/PossibleTimingAttackAgainstHash.expected b/python/ql/test/experimental/query-tests/Security/CWE-208/TimingAttackAgainstHash/PossibleTimingAttackAgainstHash.expected index bd32259294e0..232ee1f587c1 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-208/TimingAttackAgainstHash/PossibleTimingAttackAgainstHash.expected +++ b/python/ql/test/experimental/query-tests/Security/CWE-208/TimingAttackAgainstHash/PossibleTimingAttackAgainstHash.expected @@ -1,14 +1,14 @@ -#select -| TimingAttackAgainstHash.py:27:24:27:32 | ControlFlowNode for signature | TimingAttackAgainstHash.py:26:17:26:41 | ControlFlowNode for Attribute() | TimingAttackAgainstHash.py:27:24:27:32 | ControlFlowNode for signature | Possible Timing attack against $@ validation. | TimingAttackAgainstHash.py:26:17:26:41 | ControlFlowNode for Attribute() | signature message | -| TimingAttackAgainstHash.py:37:19:37:48 | ControlFlowNode for sign() | TimingAttackAgainstHash.py:30:12:30:47 | ControlFlowNode for Attribute() | TimingAttackAgainstHash.py:37:19:37:48 | ControlFlowNode for sign() | Possible Timing attack against $@ validation. | TimingAttackAgainstHash.py:30:12:30:47 | ControlFlowNode for Attribute() | MAC message | edges -| TimingAttackAgainstHash.py:26:5:26:13 | ControlFlowNode for signature | TimingAttackAgainstHash.py:27:24:27:32 | ControlFlowNode for signature | provenance | | -| TimingAttackAgainstHash.py:26:17:26:41 | ControlFlowNode for Attribute() | TimingAttackAgainstHash.py:26:5:26:13 | ControlFlowNode for signature | provenance | | -| TimingAttackAgainstHash.py:30:12:30:47 | ControlFlowNode for Attribute() | TimingAttackAgainstHash.py:37:19:37:48 | ControlFlowNode for sign() | provenance | | +| TimingAttackAgainstHash.py:26:5:26:13 | signature | TimingAttackAgainstHash.py:27:24:27:32 | signature | provenance | | +| TimingAttackAgainstHash.py:26:17:26:41 | After Attribute() | TimingAttackAgainstHash.py:26:5:26:13 | signature | provenance | | +| TimingAttackAgainstHash.py:30:12:30:47 | After Attribute() | TimingAttackAgainstHash.py:37:19:37:48 | After sign() | provenance | | nodes -| TimingAttackAgainstHash.py:26:5:26:13 | ControlFlowNode for signature | semmle.label | ControlFlowNode for signature | -| TimingAttackAgainstHash.py:26:17:26:41 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| TimingAttackAgainstHash.py:27:24:27:32 | ControlFlowNode for signature | semmle.label | ControlFlowNode for signature | -| TimingAttackAgainstHash.py:30:12:30:47 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| TimingAttackAgainstHash.py:37:19:37:48 | ControlFlowNode for sign() | semmle.label | ControlFlowNode for sign() | +| TimingAttackAgainstHash.py:26:5:26:13 | signature | semmle.label | signature | +| TimingAttackAgainstHash.py:26:17:26:41 | After Attribute() | semmle.label | After Attribute() | +| TimingAttackAgainstHash.py:27:24:27:32 | signature | semmle.label | signature | +| TimingAttackAgainstHash.py:30:12:30:47 | After Attribute() | semmle.label | After Attribute() | +| TimingAttackAgainstHash.py:37:19:37:48 | After sign() | semmle.label | After sign() | subpaths +#select +| TimingAttackAgainstHash.py:27:24:27:32 | signature | TimingAttackAgainstHash.py:26:17:26:41 | After Attribute() | TimingAttackAgainstHash.py:27:24:27:32 | signature | Possible Timing attack against $@ validation. | TimingAttackAgainstHash.py:26:17:26:41 | After Attribute() | signature message | +| TimingAttackAgainstHash.py:37:19:37:48 | After sign() | TimingAttackAgainstHash.py:30:12:30:47 | After Attribute() | TimingAttackAgainstHash.py:37:19:37:48 | After sign() | Possible Timing attack against $@ validation. | TimingAttackAgainstHash.py:30:12:30:47 | After Attribute() | MAC message | diff --git a/python/ql/test/experimental/query-tests/Security/CWE-208/TimingAttackAgainstHash/TimingAttackAgainstHash.expected b/python/ql/test/experimental/query-tests/Security/CWE-208/TimingAttackAgainstHash/TimingAttackAgainstHash.expected index 0b7b2de8ddb9..ea0d313f636d 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-208/TimingAttackAgainstHash/TimingAttackAgainstHash.expected +++ b/python/ql/test/experimental/query-tests/Security/CWE-208/TimingAttackAgainstHash/TimingAttackAgainstHash.expected @@ -1,12 +1,12 @@ edges -| TimingAttackAgainstHash.py:26:5:26:13 | ControlFlowNode for signature | TimingAttackAgainstHash.py:27:24:27:32 | ControlFlowNode for signature | provenance | | -| TimingAttackAgainstHash.py:26:17:26:41 | ControlFlowNode for Attribute() | TimingAttackAgainstHash.py:26:5:26:13 | ControlFlowNode for signature | provenance | | -| TimingAttackAgainstHash.py:30:12:30:47 | ControlFlowNode for Attribute() | TimingAttackAgainstHash.py:37:19:37:48 | ControlFlowNode for sign() | provenance | | +| TimingAttackAgainstHash.py:26:5:26:13 | signature | TimingAttackAgainstHash.py:27:24:27:32 | signature | provenance | | +| TimingAttackAgainstHash.py:26:17:26:41 | After Attribute() | TimingAttackAgainstHash.py:26:5:26:13 | signature | provenance | | +| TimingAttackAgainstHash.py:30:12:30:47 | After Attribute() | TimingAttackAgainstHash.py:37:19:37:48 | After sign() | provenance | | nodes -| TimingAttackAgainstHash.py:26:5:26:13 | ControlFlowNode for signature | semmle.label | ControlFlowNode for signature | -| TimingAttackAgainstHash.py:26:17:26:41 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| TimingAttackAgainstHash.py:27:24:27:32 | ControlFlowNode for signature | semmle.label | ControlFlowNode for signature | -| TimingAttackAgainstHash.py:30:12:30:47 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| TimingAttackAgainstHash.py:37:19:37:48 | ControlFlowNode for sign() | semmle.label | ControlFlowNode for sign() | +| TimingAttackAgainstHash.py:26:5:26:13 | signature | semmle.label | signature | +| TimingAttackAgainstHash.py:26:17:26:41 | After Attribute() | semmle.label | After Attribute() | +| TimingAttackAgainstHash.py:27:24:27:32 | signature | semmle.label | signature | +| TimingAttackAgainstHash.py:30:12:30:47 | After Attribute() | semmle.label | After Attribute() | +| TimingAttackAgainstHash.py:37:19:37:48 | After sign() | semmle.label | After sign() | subpaths #select diff --git a/python/ql/test/experimental/query-tests/Security/CWE-208/TimingAttackAgainstHeaderValue/TimingAttackAgainstHeaderValue.expected b/python/ql/test/experimental/query-tests/Security/CWE-208/TimingAttackAgainstHeaderValue/TimingAttackAgainstHeaderValue.expected index 14c8b8bf1eb1..9649a60033ae 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-208/TimingAttackAgainstHeaderValue/TimingAttackAgainstHeaderValue.expected +++ b/python/ql/test/experimental/query-tests/Security/CWE-208/TimingAttackAgainstHeaderValue/TimingAttackAgainstHeaderValue.expected @@ -1,6 +1,6 @@ edges nodes -| TimingAttackAgainstHeader.py:14:12:14:46 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | +| TimingAttackAgainstHeader.py:14:12:14:46 | After Attribute() | semmle.label | After Attribute() | subpaths #select -| TimingAttackAgainstHeader.py:14:12:14:46 | ControlFlowNode for Attribute() | TimingAttackAgainstHeader.py:14:12:14:46 | ControlFlowNode for Attribute() | TimingAttackAgainstHeader.py:14:12:14:46 | ControlFlowNode for Attribute() | Timing attack against $@ validation. | TimingAttackAgainstHeader.py:14:12:14:46 | ControlFlowNode for Attribute() | client-supplied token | +| TimingAttackAgainstHeader.py:14:12:14:46 | After Attribute() | TimingAttackAgainstHeader.py:14:12:14:46 | After Attribute() | TimingAttackAgainstHeader.py:14:12:14:46 | After Attribute() | Timing attack against $@ validation. | TimingAttackAgainstHeader.py:14:12:14:46 | After Attribute() | client-supplied token | diff --git a/python/ql/test/experimental/query-tests/Security/CWE-208/TimingAttackAgainstSensitiveInfo/PossibleTimingAttackAgainstSensitiveInfo.expected b/python/ql/test/experimental/query-tests/Security/CWE-208/TimingAttackAgainstSensitiveInfo/PossibleTimingAttackAgainstSensitiveInfo.expected index 80b074348966..9eb436d0e38b 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-208/TimingAttackAgainstSensitiveInfo/PossibleTimingAttackAgainstSensitiveInfo.expected +++ b/python/ql/test/experimental/query-tests/Security/CWE-208/TimingAttackAgainstSensitiveInfo/PossibleTimingAttackAgainstSensitiveInfo.expected @@ -1,9 +1,9 @@ edges -| TimingAttackAgainstSensitiveInfo.py:15:9:15:16 | ControlFlowNode for password | TimingAttackAgainstSensitiveInfo.py:16:16:16:23 | ControlFlowNode for password | provenance | | +| TimingAttackAgainstSensitiveInfo.py:15:9:15:16 | password | TimingAttackAgainstSensitiveInfo.py:16:16:16:23 | password | provenance | | nodes -| TimingAttackAgainstSensitiveInfo.py:15:9:15:16 | ControlFlowNode for password | semmle.label | ControlFlowNode for password | -| TimingAttackAgainstSensitiveInfo.py:16:16:16:23 | ControlFlowNode for password | semmle.label | ControlFlowNode for password | +| TimingAttackAgainstSensitiveInfo.py:15:9:15:16 | password | semmle.label | password | +| TimingAttackAgainstSensitiveInfo.py:16:16:16:23 | password | semmle.label | password | subpaths #select -| TimingAttackAgainstSensitiveInfo.py:16:16:16:23 | ControlFlowNode for password | TimingAttackAgainstSensitiveInfo.py:15:9:15:16 | ControlFlowNode for password | TimingAttackAgainstSensitiveInfo.py:16:16:16:23 | ControlFlowNode for password | Timing attack against $@ validation. | TimingAttackAgainstSensitiveInfo.py:15:9:15:16 | ControlFlowNode for password | client-supplied token | -| TimingAttackAgainstSensitiveInfo.py:16:16:16:23 | ControlFlowNode for password | TimingAttackAgainstSensitiveInfo.py:16:16:16:23 | ControlFlowNode for password | TimingAttackAgainstSensitiveInfo.py:16:16:16:23 | ControlFlowNode for password | Timing attack against $@ validation. | TimingAttackAgainstSensitiveInfo.py:16:16:16:23 | ControlFlowNode for password | client-supplied token | +| TimingAttackAgainstSensitiveInfo.py:16:16:16:23 | password | TimingAttackAgainstSensitiveInfo.py:15:9:15:16 | password | TimingAttackAgainstSensitiveInfo.py:16:16:16:23 | password | Timing attack against $@ validation. | TimingAttackAgainstSensitiveInfo.py:15:9:15:16 | password | client-supplied token | +| TimingAttackAgainstSensitiveInfo.py:16:16:16:23 | password | TimingAttackAgainstSensitiveInfo.py:16:16:16:23 | password | TimingAttackAgainstSensitiveInfo.py:16:16:16:23 | password | Timing attack against $@ validation. | TimingAttackAgainstSensitiveInfo.py:16:16:16:23 | password | client-supplied token | diff --git a/python/ql/test/experimental/query-tests/Security/CWE-287-ConstantSecretKey/ConstantSecretKey.expected b/python/ql/test/experimental/query-tests/Security/CWE-287-ConstantSecretKey/ConstantSecretKey.expected index 00c32be4267c..7bdbc80c2d2f 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-287-ConstantSecretKey/ConstantSecretKey.expected +++ b/python/ql/test/experimental/query-tests/Security/CWE-287-ConstantSecretKey/ConstantSecretKey.expected @@ -1,44 +1,44 @@ edges -| app_unsafe.py:4:1:4:9 | ControlFlowNode for aConstant | app_unsafe.py:5:28:5:36 | ControlFlowNode for aConstant | provenance | | -| app_unsafe.py:4:1:4:9 | ControlFlowNode for aConstant | app_unsafe.py:6:18:6:26 | ControlFlowNode for aConstant | provenance | | -| app_unsafe.py:4:1:4:9 | ControlFlowNode for aConstant | app_unsafe.py:7:30:7:38 | ControlFlowNode for aConstant | provenance | | -| app_unsafe.py:4:1:4:9 | ControlFlowNode for aConstant | app_unsafe.py:8:36:8:44 | ControlFlowNode for aConstant | provenance | | -| app_unsafe.py:4:13:4:23 | ControlFlowNode for StringLiteral | app_unsafe.py:4:1:4:9 | ControlFlowNode for aConstant | provenance | | -| config.py:7:1:7:9 | ControlFlowNode for aConstant | config.py:12:18:12:26 | ControlFlowNode for aConstant | provenance | | -| config.py:7:1:7:9 | ControlFlowNode for aConstant | config.py:12:18:12:26 | ControlFlowNode for aConstant | provenance | | -| config.py:7:1:7:9 | ControlFlowNode for aConstant | config.py:17:38:17:46 | ControlFlowNode for aConstant | provenance | | -| config.py:7:1:7:9 | ControlFlowNode for aConstant | config.py:18:43:18:51 | ControlFlowNode for aConstant | provenance | | -| config.py:7:13:7:23 | ControlFlowNode for StringLiteral | config.py:7:1:7:9 | ControlFlowNode for aConstant | provenance | | -| config.py:12:18:12:26 | ControlFlowNode for aConstant | config.py:17:38:17:46 | ControlFlowNode for aConstant | provenance | | -| config.py:12:18:12:26 | ControlFlowNode for aConstant | config.py:18:43:18:51 | ControlFlowNode for aConstant | provenance | | -| config.py:17:38:17:46 | ControlFlowNode for aConstant | config.py:17:18:17:47 | ControlFlowNode for Attribute() | provenance | os.getenv | -| config.py:17:38:17:46 | ControlFlowNode for aConstant | config.py:18:43:18:51 | ControlFlowNode for aConstant | provenance | | -| config.py:18:43:18:51 | ControlFlowNode for aConstant | config.py:18:18:18:52 | ControlFlowNode for Attribute() | provenance | dict.get | +| app_unsafe.py:4:1:4:9 | aConstant | app_unsafe.py:5:28:5:36 | aConstant | provenance | | +| app_unsafe.py:4:1:4:9 | aConstant | app_unsafe.py:6:18:6:26 | aConstant | provenance | | +| app_unsafe.py:4:1:4:9 | aConstant | app_unsafe.py:7:30:7:38 | aConstant | provenance | | +| app_unsafe.py:4:1:4:9 | aConstant | app_unsafe.py:8:36:8:44 | aConstant | provenance | | +| app_unsafe.py:4:13:4:23 | StringLiteral | app_unsafe.py:4:1:4:9 | aConstant | provenance | | +| config.py:7:1:7:9 | aConstant | config.py:12:18:12:26 | aConstant | provenance | | +| config.py:7:1:7:9 | aConstant | config.py:12:18:12:26 | aConstant | provenance | | +| config.py:7:1:7:9 | aConstant | config.py:17:38:17:46 | aConstant | provenance | | +| config.py:7:1:7:9 | aConstant | config.py:18:43:18:51 | aConstant | provenance | | +| config.py:7:13:7:23 | StringLiteral | config.py:7:1:7:9 | aConstant | provenance | | +| config.py:12:18:12:26 | aConstant | config.py:17:38:17:46 | aConstant | provenance | | +| config.py:12:18:12:26 | aConstant | config.py:18:43:18:51 | aConstant | provenance | | +| config.py:17:38:17:46 | aConstant | config.py:17:18:17:47 | After Attribute() | provenance | os.getenv | +| config.py:17:38:17:46 | aConstant | config.py:18:43:18:51 | aConstant | provenance | | +| config.py:18:43:18:51 | aConstant | config.py:18:18:18:52 | After Attribute() | provenance | dict.get | nodes -| app_safe.py:5:28:5:37 | ControlFlowNode for StringLiteral | semmle.label | ControlFlowNode for StringLiteral | -| app_unsafe.py:4:1:4:9 | ControlFlowNode for aConstant | semmle.label | ControlFlowNode for aConstant | -| app_unsafe.py:4:13:4:23 | ControlFlowNode for StringLiteral | semmle.label | ControlFlowNode for StringLiteral | -| app_unsafe.py:5:28:5:36 | ControlFlowNode for aConstant | semmle.label | ControlFlowNode for aConstant | -| app_unsafe.py:6:18:6:26 | ControlFlowNode for aConstant | semmle.label | ControlFlowNode for aConstant | -| app_unsafe.py:7:30:7:38 | ControlFlowNode for aConstant | semmle.label | ControlFlowNode for aConstant | -| app_unsafe.py:8:36:8:44 | ControlFlowNode for aConstant | semmle.label | ControlFlowNode for aConstant | -| config2.py:5:14:5:24 | ControlFlowNode for StringLiteral | semmle.label | ControlFlowNode for StringLiteral | -| config.py:7:1:7:9 | ControlFlowNode for aConstant | semmle.label | ControlFlowNode for aConstant | -| config.py:7:13:7:23 | ControlFlowNode for StringLiteral | semmle.label | ControlFlowNode for StringLiteral | -| config.py:12:18:12:26 | ControlFlowNode for aConstant | semmle.label | ControlFlowNode for aConstant | -| config.py:12:18:12:26 | ControlFlowNode for aConstant | semmle.label | ControlFlowNode for aConstant | -| config.py:17:18:17:47 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| config.py:17:38:17:46 | ControlFlowNode for aConstant | semmle.label | ControlFlowNode for aConstant | -| config.py:18:18:18:52 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| config.py:18:43:18:51 | ControlFlowNode for aConstant | semmle.label | ControlFlowNode for aConstant | +| app_safe.py:5:28:5:37 | StringLiteral | semmle.label | StringLiteral | +| app_unsafe.py:4:1:4:9 | aConstant | semmle.label | aConstant | +| app_unsafe.py:4:13:4:23 | StringLiteral | semmle.label | StringLiteral | +| app_unsafe.py:5:28:5:36 | aConstant | semmle.label | aConstant | +| app_unsafe.py:6:18:6:26 | aConstant | semmle.label | aConstant | +| app_unsafe.py:7:30:7:38 | aConstant | semmle.label | aConstant | +| app_unsafe.py:8:36:8:44 | aConstant | semmle.label | aConstant | +| config2.py:5:14:5:24 | StringLiteral | semmle.label | StringLiteral | +| config.py:7:1:7:9 | aConstant | semmle.label | aConstant | +| config.py:7:13:7:23 | StringLiteral | semmle.label | StringLiteral | +| config.py:12:18:12:26 | aConstant | semmle.label | aConstant | +| config.py:12:18:12:26 | aConstant | semmle.label | aConstant | +| config.py:17:18:17:47 | After Attribute() | semmle.label | After Attribute() | +| config.py:17:38:17:46 | aConstant | semmle.label | aConstant | +| config.py:18:18:18:52 | After Attribute() | semmle.label | After Attribute() | +| config.py:18:43:18:51 | aConstant | semmle.label | aConstant | subpaths #select -| app_safe.py:5:28:5:37 | ControlFlowNode for StringLiteral | app_safe.py:5:28:5:37 | ControlFlowNode for StringLiteral | app_safe.py:5:28:5:37 | ControlFlowNode for StringLiteral | The SECRET_KEY config variable is assigned by $@. | app_safe.py:5:28:5:37 | ControlFlowNode for StringLiteral | this constant String | -| app_unsafe.py:5:28:5:36 | ControlFlowNode for aConstant | app_unsafe.py:4:13:4:23 | ControlFlowNode for StringLiteral | app_unsafe.py:5:28:5:36 | ControlFlowNode for aConstant | The SECRET_KEY config variable is assigned by $@. | app_unsafe.py:4:13:4:23 | ControlFlowNode for StringLiteral | this constant String | -| app_unsafe.py:6:18:6:26 | ControlFlowNode for aConstant | app_unsafe.py:4:13:4:23 | ControlFlowNode for StringLiteral | app_unsafe.py:6:18:6:26 | ControlFlowNode for aConstant | The SECRET_KEY config variable is assigned by $@. | app_unsafe.py:4:13:4:23 | ControlFlowNode for StringLiteral | this constant String | -| app_unsafe.py:7:30:7:38 | ControlFlowNode for aConstant | app_unsafe.py:4:13:4:23 | ControlFlowNode for StringLiteral | app_unsafe.py:7:30:7:38 | ControlFlowNode for aConstant | The SECRET_KEY config variable is assigned by $@. | app_unsafe.py:4:13:4:23 | ControlFlowNode for StringLiteral | this constant String | -| app_unsafe.py:8:36:8:44 | ControlFlowNode for aConstant | app_unsafe.py:4:13:4:23 | ControlFlowNode for StringLiteral | app_unsafe.py:8:36:8:44 | ControlFlowNode for aConstant | The SECRET_KEY config variable is assigned by $@. | app_unsafe.py:4:13:4:23 | ControlFlowNode for StringLiteral | this constant String | -| config2.py:5:14:5:24 | ControlFlowNode for StringLiteral | config2.py:5:14:5:24 | ControlFlowNode for StringLiteral | config2.py:5:14:5:24 | ControlFlowNode for StringLiteral | The SECRET_KEY config variable is assigned by $@. | config2.py:5:14:5:24 | ControlFlowNode for StringLiteral | this constant String | -| config.py:12:18:12:26 | ControlFlowNode for aConstant | config.py:7:13:7:23 | ControlFlowNode for StringLiteral | config.py:12:18:12:26 | ControlFlowNode for aConstant | The SECRET_KEY config variable is assigned by $@. | config.py:7:13:7:23 | ControlFlowNode for StringLiteral | this constant String | -| config.py:17:18:17:47 | ControlFlowNode for Attribute() | config.py:7:13:7:23 | ControlFlowNode for StringLiteral | config.py:17:18:17:47 | ControlFlowNode for Attribute() | The SECRET_KEY config variable is assigned by $@. | config.py:7:13:7:23 | ControlFlowNode for StringLiteral | this constant String | -| config.py:18:18:18:52 | ControlFlowNode for Attribute() | config.py:7:13:7:23 | ControlFlowNode for StringLiteral | config.py:18:18:18:52 | ControlFlowNode for Attribute() | The SECRET_KEY config variable is assigned by $@. | config.py:7:13:7:23 | ControlFlowNode for StringLiteral | this constant String | +| app_safe.py:5:28:5:37 | StringLiteral | app_safe.py:5:28:5:37 | StringLiteral | app_safe.py:5:28:5:37 | StringLiteral | The SECRET_KEY config variable is assigned by $@. | app_safe.py:5:28:5:37 | StringLiteral | this constant String | +| app_unsafe.py:5:28:5:36 | aConstant | app_unsafe.py:4:13:4:23 | StringLiteral | app_unsafe.py:5:28:5:36 | aConstant | The SECRET_KEY config variable is assigned by $@. | app_unsafe.py:4:13:4:23 | StringLiteral | this constant String | +| app_unsafe.py:6:18:6:26 | aConstant | app_unsafe.py:4:13:4:23 | StringLiteral | app_unsafe.py:6:18:6:26 | aConstant | The SECRET_KEY config variable is assigned by $@. | app_unsafe.py:4:13:4:23 | StringLiteral | this constant String | +| app_unsafe.py:7:30:7:38 | aConstant | app_unsafe.py:4:13:4:23 | StringLiteral | app_unsafe.py:7:30:7:38 | aConstant | The SECRET_KEY config variable is assigned by $@. | app_unsafe.py:4:13:4:23 | StringLiteral | this constant String | +| app_unsafe.py:8:36:8:44 | aConstant | app_unsafe.py:4:13:4:23 | StringLiteral | app_unsafe.py:8:36:8:44 | aConstant | The SECRET_KEY config variable is assigned by $@. | app_unsafe.py:4:13:4:23 | StringLiteral | this constant String | +| config2.py:5:14:5:24 | StringLiteral | config2.py:5:14:5:24 | StringLiteral | config2.py:5:14:5:24 | StringLiteral | The SECRET_KEY config variable is assigned by $@. | config2.py:5:14:5:24 | StringLiteral | this constant String | +| config.py:12:18:12:26 | aConstant | config.py:7:13:7:23 | StringLiteral | config.py:12:18:12:26 | aConstant | The SECRET_KEY config variable is assigned by $@. | config.py:7:13:7:23 | StringLiteral | this constant String | +| config.py:17:18:17:47 | After Attribute() | config.py:7:13:7:23 | StringLiteral | config.py:17:18:17:47 | After Attribute() | The SECRET_KEY config variable is assigned by $@. | config.py:7:13:7:23 | StringLiteral | this constant String | +| config.py:18:18:18:52 | After Attribute() | config.py:7:13:7:23 | StringLiteral | config.py:18:18:18:52 | After Attribute() | The SECRET_KEY config variable is assigned by $@. | config.py:7:13:7:23 | StringLiteral | this constant String | diff --git a/python/ql/test/experimental/query-tests/Security/CWE-287/ImproperLdapAuth.expected b/python/ql/test/experimental/query-tests/Security/CWE-287/ImproperLdapAuth.expected index 224c1a33902b..4198c71a8971 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-287/ImproperLdapAuth.expected +++ b/python/ql/test/experimental/query-tests/Security/CWE-287/ImproperLdapAuth.expected @@ -1,10 +1,10 @@ -| auth_bad_2.py:19:5:19:42 | ControlFlowNode for Attribute() | The following LDAP bind operation is executed without authentication. | -| auth_bad_2.py:33:5:33:44 | ControlFlowNode for Attribute() | The following LDAP bind operation is executed without authentication. | -| auth_bad_2.py:47:5:47:43 | ControlFlowNode for Attribute() | The following LDAP bind operation is executed without authentication. | -| auth_bad_2.py:60:5:60:52 | ControlFlowNode for Attribute() | The following LDAP bind operation is executed without authentication. | -| auth_bad_2.py:73:5:73:39 | ControlFlowNode for Attribute() | The following LDAP bind operation is executed without authentication. | -| auth_bad_2.py:87:5:87:48 | ControlFlowNode for Attribute() | The following LDAP bind operation is executed without authentication. | -| auth_bad_3.py:19:12:19:43 | ControlFlowNode for Connection() | The following LDAP bind operation is executed without authentication. | -| auth_bad_3.py:33:12:33:57 | ControlFlowNode for Connection() | The following LDAP bind operation is executed without authentication. | -| auth_bad_3.py:46:12:46:55 | ControlFlowNode for Connection() | The following LDAP bind operation is executed without authentication. | -| auth_bad_3.py:60:12:60:42 | ControlFlowNode for Connection() | The following LDAP bind operation is executed without authentication. | +| auth_bad_2.py:19:5:19:42 | After Attribute() | The following LDAP bind operation is executed without authentication. | +| auth_bad_2.py:33:5:33:44 | After Attribute() | The following LDAP bind operation is executed without authentication. | +| auth_bad_2.py:47:5:47:43 | After Attribute() | The following LDAP bind operation is executed without authentication. | +| auth_bad_2.py:60:5:60:52 | After Attribute() | The following LDAP bind operation is executed without authentication. | +| auth_bad_2.py:73:5:73:39 | After Attribute() | The following LDAP bind operation is executed without authentication. | +| auth_bad_2.py:87:5:87:48 | After Attribute() | The following LDAP bind operation is executed without authentication. | +| auth_bad_3.py:19:12:19:43 | After Connection() | The following LDAP bind operation is executed without authentication. | +| auth_bad_3.py:33:12:33:57 | After Connection() | The following LDAP bind operation is executed without authentication. | +| auth_bad_3.py:46:12:46:55 | After Connection() | The following LDAP bind operation is executed without authentication. | +| auth_bad_3.py:60:12:60:42 | After Connection() | The following LDAP bind operation is executed without authentication. | diff --git a/python/ql/test/experimental/query-tests/Security/CWE-327-UnsafeUsageOfClientSideEncryptionVersion/UnsafeUsageOfClientSideEncryptionVersion.expected b/python/ql/test/experimental/query-tests/Security/CWE-327-UnsafeUsageOfClientSideEncryptionVersion/UnsafeUsageOfClientSideEncryptionVersion.expected index 8ffc7ac31d9b..ffea96e36fab 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-327-UnsafeUsageOfClientSideEncryptionVersion/UnsafeUsageOfClientSideEncryptionVersion.expected +++ b/python/ql/test/experimental/query-tests/Security/CWE-327-UnsafeUsageOfClientSideEncryptionVersion/UnsafeUsageOfClientSideEncryptionVersion.expected @@ -1,94 +1,94 @@ -#select -| test.py:11:9:11:19 | ControlFlowNode for blob_client | test.py:3:7:3:51 | ControlFlowNode for Attribute() | test.py:11:9:11:19 | ControlFlowNode for blob_client | Unsafe usage of v1 version of Azure Storage client-side encryption | -| test.py:21:9:21:19 | ControlFlowNode for blob_client | test.py:15:27:15:71 | ControlFlowNode for Attribute() | test.py:21:9:21:19 | ControlFlowNode for blob_client | Unsafe usage of v1 version of Azure Storage client-side encryption | -| test.py:31:9:31:19 | ControlFlowNode for blob_client | test.py:25:24:25:66 | ControlFlowNode for Attribute() | test.py:31:9:31:19 | ControlFlowNode for blob_client | Unsafe usage of v1 version of Azure Storage client-side encryption | -| test.py:43:9:43:19 | ControlFlowNode for blob_client | test.py:3:7:3:51 | ControlFlowNode for Attribute() | test.py:43:9:43:19 | ControlFlowNode for blob_client | Unsafe usage of v1 version of Azure Storage client-side encryption | -| test.py:75:9:75:10 | ControlFlowNode for bc | test.py:3:7:3:51 | ControlFlowNode for Attribute() | test.py:75:9:75:10 | ControlFlowNode for bc | Unsafe usage of v1 version of Azure Storage client-side encryption | edges -| test.py:3:1:3:3 | ControlFlowNode for BSC | test.py:7:19:7:21 | ControlFlowNode for BSC | provenance | | -| test.py:3:1:3:3 | ControlFlowNode for BSC | test.py:35:19:35:21 | ControlFlowNode for BSC | provenance | | -| test.py:3:1:3:3 | ControlFlowNode for BSC | test.py:66:19:66:21 | ControlFlowNode for BSC | provenance | | -| test.py:3:7:3:51 | ControlFlowNode for Attribute() | test.py:3:1:3:3 | ControlFlowNode for BSC | provenance | | -| test.py:7:5:7:15 | ControlFlowNode for blob_client | test.py:8:5:8:15 | ControlFlowNode for blob_client | provenance | | -| test.py:7:19:7:21 | ControlFlowNode for BSC | test.py:7:19:7:42 | ControlFlowNode for Attribute() | provenance | Config | -| test.py:7:19:7:42 | ControlFlowNode for Attribute() | test.py:7:5:7:15 | ControlFlowNode for blob_client | provenance | | -| test.py:8:5:8:15 | ControlFlowNode for blob_client | test.py:9:5:9:15 | ControlFlowNode for blob_client | provenance | | -| test.py:9:5:9:15 | ControlFlowNode for blob_client | test.py:9:5:9:15 | [post] ControlFlowNode for blob_client | provenance | Config | -| test.py:9:5:9:15 | [post] ControlFlowNode for blob_client | test.py:11:9:11:19 | ControlFlowNode for blob_client | provenance | | -| test.py:15:5:15:23 | ControlFlowNode for blob_service_client | test.py:16:5:16:23 | ControlFlowNode for blob_service_client | provenance | | -| test.py:15:27:15:71 | ControlFlowNode for Attribute() | test.py:15:5:15:23 | ControlFlowNode for blob_service_client | provenance | | -| test.py:16:5:16:23 | ControlFlowNode for blob_service_client | test.py:17:5:17:23 | ControlFlowNode for blob_service_client | provenance | | -| test.py:17:5:17:23 | ControlFlowNode for blob_service_client | test.py:17:5:17:23 | [post] ControlFlowNode for blob_service_client | provenance | Config | -| test.py:17:5:17:23 | [post] ControlFlowNode for blob_service_client | test.py:19:19:19:37 | ControlFlowNode for blob_service_client | provenance | | -| test.py:19:5:19:15 | ControlFlowNode for blob_client | test.py:21:9:21:19 | ControlFlowNode for blob_client | provenance | | -| test.py:19:19:19:37 | ControlFlowNode for blob_service_client | test.py:19:19:19:58 | ControlFlowNode for Attribute() | provenance | Config | -| test.py:19:19:19:58 | ControlFlowNode for Attribute() | test.py:19:5:19:15 | ControlFlowNode for blob_client | provenance | | -| test.py:25:5:25:20 | ControlFlowNode for container_client | test.py:26:5:26:20 | ControlFlowNode for container_client | provenance | | -| test.py:25:24:25:66 | ControlFlowNode for Attribute() | test.py:25:5:25:20 | ControlFlowNode for container_client | provenance | | -| test.py:26:5:26:20 | ControlFlowNode for container_client | test.py:27:5:27:20 | ControlFlowNode for container_client | provenance | | -| test.py:27:5:27:20 | ControlFlowNode for container_client | test.py:27:5:27:20 | [post] ControlFlowNode for container_client | provenance | Config | -| test.py:27:5:27:20 | [post] ControlFlowNode for container_client | test.py:29:19:29:34 | ControlFlowNode for container_client | provenance | | -| test.py:29:5:29:15 | ControlFlowNode for blob_client | test.py:31:9:31:19 | ControlFlowNode for blob_client | provenance | | -| test.py:29:19:29:34 | ControlFlowNode for container_client | test.py:29:19:29:55 | ControlFlowNode for Attribute() | provenance | Config | -| test.py:29:19:29:55 | ControlFlowNode for Attribute() | test.py:29:5:29:15 | ControlFlowNode for blob_client | provenance | | -| test.py:35:5:35:15 | ControlFlowNode for blob_client | test.py:36:5:36:15 | ControlFlowNode for blob_client | provenance | | -| test.py:35:19:35:21 | ControlFlowNode for BSC | test.py:35:19:35:42 | ControlFlowNode for Attribute() | provenance | Config | -| test.py:35:19:35:42 | ControlFlowNode for Attribute() | test.py:35:5:35:15 | ControlFlowNode for blob_client | provenance | | -| test.py:36:5:36:15 | ControlFlowNode for blob_client | test.py:37:5:37:15 | ControlFlowNode for blob_client | provenance | | -| test.py:37:5:37:15 | ControlFlowNode for blob_client | test.py:37:5:37:15 | [post] ControlFlowNode for blob_client | provenance | Config | -| test.py:37:5:37:15 | [post] ControlFlowNode for blob_client | test.py:43:9:43:19 | ControlFlowNode for blob_client | provenance | | -| test.py:66:5:66:15 | ControlFlowNode for blob_client | test.py:67:5:67:15 | ControlFlowNode for blob_client | provenance | | -| test.py:66:19:66:21 | ControlFlowNode for BSC | test.py:66:19:66:42 | ControlFlowNode for Attribute() | provenance | Config | -| test.py:66:19:66:42 | ControlFlowNode for Attribute() | test.py:66:5:66:15 | ControlFlowNode for blob_client | provenance | | -| test.py:67:5:67:15 | ControlFlowNode for blob_client | test.py:68:5:68:15 | ControlFlowNode for blob_client | provenance | | -| test.py:68:5:68:15 | ControlFlowNode for blob_client | test.py:68:5:68:15 | [post] ControlFlowNode for blob_client | provenance | Config | -| test.py:68:5:68:15 | [post] ControlFlowNode for blob_client | test.py:69:12:69:22 | ControlFlowNode for blob_client | provenance | | -| test.py:69:12:69:22 | ControlFlowNode for blob_client | test.py:73:10:73:33 | ControlFlowNode for get_unsafe_blob_client() | provenance | | -| test.py:73:5:73:6 | ControlFlowNode for bc | test.py:75:9:75:10 | ControlFlowNode for bc | provenance | | -| test.py:73:10:73:33 | ControlFlowNode for get_unsafe_blob_client() | test.py:73:5:73:6 | ControlFlowNode for bc | provenance | | +| test.py:3:1:3:3 | BSC | test.py:7:19:7:21 | BSC | provenance | | +| test.py:3:1:3:3 | BSC | test.py:35:19:35:21 | BSC | provenance | | +| test.py:3:1:3:3 | BSC | test.py:66:19:66:21 | BSC | provenance | | +| test.py:3:7:3:51 | After Attribute() | test.py:3:1:3:3 | BSC | provenance | | +| test.py:7:5:7:15 | blob_client | test.py:8:5:8:15 | blob_client | provenance | | +| test.py:7:19:7:21 | BSC | test.py:7:19:7:42 | After Attribute() | provenance | Config | +| test.py:7:19:7:42 | After Attribute() | test.py:7:5:7:15 | blob_client | provenance | | +| test.py:8:5:8:15 | blob_client | test.py:9:5:9:15 | blob_client | provenance | | +| test.py:9:5:9:15 | [post] blob_client | test.py:11:9:11:19 | blob_client | provenance | | +| test.py:9:5:9:15 | blob_client | test.py:9:5:9:15 | [post] blob_client | provenance | Config | +| test.py:15:5:15:23 | blob_service_client | test.py:16:5:16:23 | blob_service_client | provenance | | +| test.py:15:27:15:71 | After Attribute() | test.py:15:5:15:23 | blob_service_client | provenance | | +| test.py:16:5:16:23 | blob_service_client | test.py:17:5:17:23 | blob_service_client | provenance | | +| test.py:17:5:17:23 | [post] blob_service_client | test.py:19:19:19:37 | blob_service_client | provenance | | +| test.py:17:5:17:23 | blob_service_client | test.py:17:5:17:23 | [post] blob_service_client | provenance | Config | +| test.py:19:5:19:15 | blob_client | test.py:21:9:21:19 | blob_client | provenance | | +| test.py:19:19:19:37 | blob_service_client | test.py:19:19:19:58 | After Attribute() | provenance | Config | +| test.py:19:19:19:58 | After Attribute() | test.py:19:5:19:15 | blob_client | provenance | | +| test.py:25:5:25:20 | container_client | test.py:26:5:26:20 | container_client | provenance | | +| test.py:25:24:25:66 | After Attribute() | test.py:25:5:25:20 | container_client | provenance | | +| test.py:26:5:26:20 | container_client | test.py:27:5:27:20 | container_client | provenance | | +| test.py:27:5:27:20 | [post] container_client | test.py:29:19:29:34 | container_client | provenance | | +| test.py:27:5:27:20 | container_client | test.py:27:5:27:20 | [post] container_client | provenance | Config | +| test.py:29:5:29:15 | blob_client | test.py:31:9:31:19 | blob_client | provenance | | +| test.py:29:19:29:34 | container_client | test.py:29:19:29:55 | After Attribute() | provenance | Config | +| test.py:29:19:29:55 | After Attribute() | test.py:29:5:29:15 | blob_client | provenance | | +| test.py:35:5:35:15 | blob_client | test.py:36:5:36:15 | blob_client | provenance | | +| test.py:35:19:35:21 | BSC | test.py:35:19:35:42 | After Attribute() | provenance | Config | +| test.py:35:19:35:42 | After Attribute() | test.py:35:5:35:15 | blob_client | provenance | | +| test.py:36:5:36:15 | blob_client | test.py:37:5:37:15 | blob_client | provenance | | +| test.py:37:5:37:15 | [post] blob_client | test.py:43:9:43:19 | blob_client | provenance | | +| test.py:37:5:37:15 | blob_client | test.py:37:5:37:15 | [post] blob_client | provenance | Config | +| test.py:66:5:66:15 | blob_client | test.py:67:5:67:15 | blob_client | provenance | | +| test.py:66:19:66:21 | BSC | test.py:66:19:66:42 | After Attribute() | provenance | Config | +| test.py:66:19:66:42 | After Attribute() | test.py:66:5:66:15 | blob_client | provenance | | +| test.py:67:5:67:15 | blob_client | test.py:68:5:68:15 | blob_client | provenance | | +| test.py:68:5:68:15 | [post] blob_client | test.py:69:12:69:22 | blob_client | provenance | | +| test.py:68:5:68:15 | blob_client | test.py:68:5:68:15 | [post] blob_client | provenance | Config | +| test.py:69:12:69:22 | blob_client | test.py:73:10:73:33 | After get_unsafe_blob_client() | provenance | | +| test.py:73:5:73:6 | bc | test.py:75:9:75:10 | bc | provenance | | +| test.py:73:10:73:33 | After get_unsafe_blob_client() | test.py:73:5:73:6 | bc | provenance | | nodes -| test.py:3:1:3:3 | ControlFlowNode for BSC | semmle.label | ControlFlowNode for BSC | -| test.py:3:7:3:51 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| test.py:7:5:7:15 | ControlFlowNode for blob_client | semmle.label | ControlFlowNode for blob_client | -| test.py:7:19:7:21 | ControlFlowNode for BSC | semmle.label | ControlFlowNode for BSC | -| test.py:7:19:7:42 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| test.py:8:5:8:15 | ControlFlowNode for blob_client | semmle.label | ControlFlowNode for blob_client | -| test.py:9:5:9:15 | ControlFlowNode for blob_client | semmle.label | ControlFlowNode for blob_client | -| test.py:9:5:9:15 | [post] ControlFlowNode for blob_client | semmle.label | [post] ControlFlowNode for blob_client | -| test.py:11:9:11:19 | ControlFlowNode for blob_client | semmle.label | ControlFlowNode for blob_client | -| test.py:15:5:15:23 | ControlFlowNode for blob_service_client | semmle.label | ControlFlowNode for blob_service_client | -| test.py:15:27:15:71 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| test.py:16:5:16:23 | ControlFlowNode for blob_service_client | semmle.label | ControlFlowNode for blob_service_client | -| test.py:17:5:17:23 | ControlFlowNode for blob_service_client | semmle.label | ControlFlowNode for blob_service_client | -| test.py:17:5:17:23 | [post] ControlFlowNode for blob_service_client | semmle.label | [post] ControlFlowNode for blob_service_client | -| test.py:19:5:19:15 | ControlFlowNode for blob_client | semmle.label | ControlFlowNode for blob_client | -| test.py:19:19:19:37 | ControlFlowNode for blob_service_client | semmle.label | ControlFlowNode for blob_service_client | -| test.py:19:19:19:58 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| test.py:21:9:21:19 | ControlFlowNode for blob_client | semmle.label | ControlFlowNode for blob_client | -| test.py:25:5:25:20 | ControlFlowNode for container_client | semmle.label | ControlFlowNode for container_client | -| test.py:25:24:25:66 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| test.py:26:5:26:20 | ControlFlowNode for container_client | semmle.label | ControlFlowNode for container_client | -| test.py:27:5:27:20 | ControlFlowNode for container_client | semmle.label | ControlFlowNode for container_client | -| test.py:27:5:27:20 | [post] ControlFlowNode for container_client | semmle.label | [post] ControlFlowNode for container_client | -| test.py:29:5:29:15 | ControlFlowNode for blob_client | semmle.label | ControlFlowNode for blob_client | -| test.py:29:19:29:34 | ControlFlowNode for container_client | semmle.label | ControlFlowNode for container_client | -| test.py:29:19:29:55 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| test.py:31:9:31:19 | ControlFlowNode for blob_client | semmle.label | ControlFlowNode for blob_client | -| test.py:35:5:35:15 | ControlFlowNode for blob_client | semmle.label | ControlFlowNode for blob_client | -| test.py:35:19:35:21 | ControlFlowNode for BSC | semmle.label | ControlFlowNode for BSC | -| test.py:35:19:35:42 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| test.py:36:5:36:15 | ControlFlowNode for blob_client | semmle.label | ControlFlowNode for blob_client | -| test.py:37:5:37:15 | ControlFlowNode for blob_client | semmle.label | ControlFlowNode for blob_client | -| test.py:37:5:37:15 | [post] ControlFlowNode for blob_client | semmle.label | [post] ControlFlowNode for blob_client | -| test.py:43:9:43:19 | ControlFlowNode for blob_client | semmle.label | ControlFlowNode for blob_client | -| test.py:66:5:66:15 | ControlFlowNode for blob_client | semmle.label | ControlFlowNode for blob_client | -| test.py:66:19:66:21 | ControlFlowNode for BSC | semmle.label | ControlFlowNode for BSC | -| test.py:66:19:66:42 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| test.py:67:5:67:15 | ControlFlowNode for blob_client | semmle.label | ControlFlowNode for blob_client | -| test.py:68:5:68:15 | ControlFlowNode for blob_client | semmle.label | ControlFlowNode for blob_client | -| test.py:68:5:68:15 | [post] ControlFlowNode for blob_client | semmle.label | [post] ControlFlowNode for blob_client | -| test.py:69:12:69:22 | ControlFlowNode for blob_client | semmle.label | ControlFlowNode for blob_client | -| test.py:73:5:73:6 | ControlFlowNode for bc | semmle.label | ControlFlowNode for bc | -| test.py:73:10:73:33 | ControlFlowNode for get_unsafe_blob_client() | semmle.label | ControlFlowNode for get_unsafe_blob_client() | -| test.py:75:9:75:10 | ControlFlowNode for bc | semmle.label | ControlFlowNode for bc | +| test.py:3:1:3:3 | BSC | semmle.label | BSC | +| test.py:3:7:3:51 | After Attribute() | semmle.label | After Attribute() | +| test.py:7:5:7:15 | blob_client | semmle.label | blob_client | +| test.py:7:19:7:21 | BSC | semmle.label | BSC | +| test.py:7:19:7:42 | After Attribute() | semmle.label | After Attribute() | +| test.py:8:5:8:15 | blob_client | semmle.label | blob_client | +| test.py:9:5:9:15 | [post] blob_client | semmle.label | [post] blob_client | +| test.py:9:5:9:15 | blob_client | semmle.label | blob_client | +| test.py:11:9:11:19 | blob_client | semmle.label | blob_client | +| test.py:15:5:15:23 | blob_service_client | semmle.label | blob_service_client | +| test.py:15:27:15:71 | After Attribute() | semmle.label | After Attribute() | +| test.py:16:5:16:23 | blob_service_client | semmle.label | blob_service_client | +| test.py:17:5:17:23 | [post] blob_service_client | semmle.label | [post] blob_service_client | +| test.py:17:5:17:23 | blob_service_client | semmle.label | blob_service_client | +| test.py:19:5:19:15 | blob_client | semmle.label | blob_client | +| test.py:19:19:19:37 | blob_service_client | semmle.label | blob_service_client | +| test.py:19:19:19:58 | After Attribute() | semmle.label | After Attribute() | +| test.py:21:9:21:19 | blob_client | semmle.label | blob_client | +| test.py:25:5:25:20 | container_client | semmle.label | container_client | +| test.py:25:24:25:66 | After Attribute() | semmle.label | After Attribute() | +| test.py:26:5:26:20 | container_client | semmle.label | container_client | +| test.py:27:5:27:20 | [post] container_client | semmle.label | [post] container_client | +| test.py:27:5:27:20 | container_client | semmle.label | container_client | +| test.py:29:5:29:15 | blob_client | semmle.label | blob_client | +| test.py:29:19:29:34 | container_client | semmle.label | container_client | +| test.py:29:19:29:55 | After Attribute() | semmle.label | After Attribute() | +| test.py:31:9:31:19 | blob_client | semmle.label | blob_client | +| test.py:35:5:35:15 | blob_client | semmle.label | blob_client | +| test.py:35:19:35:21 | BSC | semmle.label | BSC | +| test.py:35:19:35:42 | After Attribute() | semmle.label | After Attribute() | +| test.py:36:5:36:15 | blob_client | semmle.label | blob_client | +| test.py:37:5:37:15 | [post] blob_client | semmle.label | [post] blob_client | +| test.py:37:5:37:15 | blob_client | semmle.label | blob_client | +| test.py:43:9:43:19 | blob_client | semmle.label | blob_client | +| test.py:66:5:66:15 | blob_client | semmle.label | blob_client | +| test.py:66:19:66:21 | BSC | semmle.label | BSC | +| test.py:66:19:66:42 | After Attribute() | semmle.label | After Attribute() | +| test.py:67:5:67:15 | blob_client | semmle.label | blob_client | +| test.py:68:5:68:15 | [post] blob_client | semmle.label | [post] blob_client | +| test.py:68:5:68:15 | blob_client | semmle.label | blob_client | +| test.py:69:12:69:22 | blob_client | semmle.label | blob_client | +| test.py:73:5:73:6 | bc | semmle.label | bc | +| test.py:73:10:73:33 | After get_unsafe_blob_client() | semmle.label | After get_unsafe_blob_client() | +| test.py:75:9:75:10 | bc | semmle.label | bc | subpaths +#select +| test.py:11:9:11:19 | blob_client | test.py:3:7:3:51 | After Attribute() | test.py:11:9:11:19 | blob_client | Unsafe usage of v1 version of Azure Storage client-side encryption | +| test.py:21:9:21:19 | blob_client | test.py:15:27:15:71 | After Attribute() | test.py:21:9:21:19 | blob_client | Unsafe usage of v1 version of Azure Storage client-side encryption | +| test.py:31:9:31:19 | blob_client | test.py:25:24:25:66 | After Attribute() | test.py:31:9:31:19 | blob_client | Unsafe usage of v1 version of Azure Storage client-side encryption | +| test.py:43:9:43:19 | blob_client | test.py:3:7:3:51 | After Attribute() | test.py:43:9:43:19 | blob_client | Unsafe usage of v1 version of Azure Storage client-side encryption | +| test.py:75:9:75:10 | bc | test.py:3:7:3:51 | After Attribute() | test.py:75:9:75:10 | bc | Unsafe usage of v1 version of Azure Storage client-side encryption | diff --git a/python/ql/test/experimental/query-tests/Security/CWE-338/InsecureRandomness.expected b/python/ql/test/experimental/query-tests/Security/CWE-338/InsecureRandomness.expected index 29ecd398a0af..d8c15f53d115 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-338/InsecureRandomness.expected +++ b/python/ql/test/experimental/query-tests/Security/CWE-338/InsecureRandomness.expected @@ -1,6 +1,6 @@ edges nodes -| InsecureRandomness.py:5:12:5:26 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | +| InsecureRandomness.py:5:12:5:26 | After Attribute() | semmle.label | After Attribute() | subpaths #select -| InsecureRandomness.py:5:12:5:26 | ControlFlowNode for Attribute() | InsecureRandomness.py:5:12:5:26 | ControlFlowNode for Attribute() | InsecureRandomness.py:5:12:5:26 | ControlFlowNode for Attribute() | Cryptographically insecure $@ in a security context. | InsecureRandomness.py:5:12:5:26 | ControlFlowNode for Attribute() | random value | +| InsecureRandomness.py:5:12:5:26 | After Attribute() | InsecureRandomness.py:5:12:5:26 | After Attribute() | InsecureRandomness.py:5:12:5:26 | After Attribute() | Cryptographically insecure $@ in a security context. | InsecureRandomness.py:5:12:5:26 | After Attribute() | random value | diff --git a/python/ql/test/experimental/query-tests/Security/CWE-346/CorsBypass.expected b/python/ql/test/experimental/query-tests/Security/CWE-346/CorsBypass.expected index 32d807c6f6e5..3b8cdb6c1a63 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-346/CorsBypass.expected +++ b/python/ql/test/experimental/query-tests/Security/CWE-346/CorsBypass.expected @@ -1,13 +1,13 @@ edges -| Cors.py:7:9:7:14 | ControlFlowNode for origin | Cors.py:8:12:8:17 | ControlFlowNode for origin | provenance | | -| Cors.py:7:18:7:32 | ControlFlowNode for Attribute | Cors.py:7:18:7:52 | ControlFlowNode for Attribute() | provenance | Config | -| Cors.py:7:18:7:32 | ControlFlowNode for Attribute | Cors.py:7:18:7:52 | ControlFlowNode for Attribute() | provenance | dict.get | -| Cors.py:7:18:7:52 | ControlFlowNode for Attribute() | Cors.py:7:9:7:14 | ControlFlowNode for origin | provenance | | +| Cors.py:7:9:7:14 | origin | Cors.py:8:12:8:17 | origin | provenance | | +| Cors.py:7:18:7:32 | After Attribute | Cors.py:7:18:7:52 | After Attribute() | provenance | Config | +| Cors.py:7:18:7:32 | After Attribute | Cors.py:7:18:7:52 | After Attribute() | provenance | dict.get | +| Cors.py:7:18:7:52 | After Attribute() | Cors.py:7:9:7:14 | origin | provenance | | nodes -| Cors.py:7:9:7:14 | ControlFlowNode for origin | semmle.label | ControlFlowNode for origin | -| Cors.py:7:18:7:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| Cors.py:7:18:7:52 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| Cors.py:8:12:8:17 | ControlFlowNode for origin | semmle.label | ControlFlowNode for origin | +| Cors.py:7:9:7:14 | origin | semmle.label | origin | +| Cors.py:7:18:7:32 | After Attribute | semmle.label | After Attribute | +| Cors.py:7:18:7:52 | After Attribute() | semmle.label | After Attribute() | +| Cors.py:8:12:8:17 | origin | semmle.label | origin | subpaths #select -| Cors.py:8:12:8:17 | ControlFlowNode for origin | Cors.py:7:18:7:32 | ControlFlowNode for Attribute | Cors.py:8:12:8:17 | ControlFlowNode for origin | Potentially incorrect string comparison which could lead to a CORS bypass. | +| Cors.py:8:12:8:17 | origin | Cors.py:7:18:7:32 | After Attribute | Cors.py:8:12:8:17 | origin | Potentially incorrect string comparison which could lead to a CORS bypass. | diff --git a/python/ql/test/experimental/query-tests/Security/CWE-347/JWTEmptyKeyOrAlgorithm.expected b/python/ql/test/experimental/query-tests/Security/CWE-347/JWTEmptyKeyOrAlgorithm.expected index a429fa386daa..74a42fe4ba6a 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-347/JWTEmptyKeyOrAlgorithm.expected +++ b/python/ql/test/experimental/query-tests/Security/CWE-347/JWTEmptyKeyOrAlgorithm.expected @@ -1,8 +1,8 @@ -| authlib.py:11:1:11:39 | ControlFlowNode for Attribute() | This JWT encoding has an empty key. | -| authlib.py:12:1:12:50 | ControlFlowNode for Attribute() | This JWT encoding has an empty key. | -| pyjwt.py:10:1:10:29 | ControlFlowNode for Attribute() | This JWT encoding has an empty algorithm. | -| pyjwt.py:10:1:10:29 | ControlFlowNode for Attribute() | This JWT encoding has an empty key. | -| pyjwt.py:13:1:13:40 | ControlFlowNode for Attribute() | This JWT encoding has an empty key. | -| pyjwt.py:14:1:14:44 | ControlFlowNode for Attribute() | This JWT encoding has an empty key. | -| python_jose.py:10:1:10:40 | ControlFlowNode for Attribute() | This JWT encoding has an empty key. | -| python_jose.py:11:1:11:44 | ControlFlowNode for Attribute() | This JWT encoding has an empty key. | +| authlib.py:11:1:11:39 | After Attribute() | This JWT encoding has an empty key. | +| authlib.py:12:1:12:50 | After Attribute() | This JWT encoding has an empty key. | +| pyjwt.py:10:1:10:29 | After Attribute() | This JWT encoding has an empty algorithm. | +| pyjwt.py:10:1:10:29 | After Attribute() | This JWT encoding has an empty key. | +| pyjwt.py:13:1:13:40 | After Attribute() | This JWT encoding has an empty key. | +| pyjwt.py:14:1:14:44 | After Attribute() | This JWT encoding has an empty key. | +| python_jose.py:10:1:10:40 | After Attribute() | This JWT encoding has an empty key. | +| python_jose.py:11:1:11:44 | After Attribute() | This JWT encoding has an empty key. | diff --git a/python/ql/test/experimental/query-tests/Security/CWE-347/JWTMissingSecretOrPublicKeyVerification.expected b/python/ql/test/experimental/query-tests/Security/CWE-347/JWTMissingSecretOrPublicKeyVerification.expected index 4ce437fdb9b4..fc5167a002cb 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-347/JWTMissingSecretOrPublicKeyVerification.expected +++ b/python/ql/test/experimental/query-tests/Security/CWE-347/JWTMissingSecretOrPublicKeyVerification.expected @@ -1,4 +1,4 @@ -| pyjwt.py:22:12:22:16 | ControlFlowNode for token | is not verified with a cryptographic secret or public key. | -| pyjwt.py:23:12:23:16 | ControlFlowNode for token | is not verified with a cryptographic secret or public key. | -| python_jose.py:19:12:19:16 | ControlFlowNode for token | is not verified with a cryptographic secret or public key. | -| python_jwt.py:14:28:14:32 | ControlFlowNode for token | is not verified with a cryptographic secret or public key. | +| pyjwt.py:22:12:22:16 | token | is not verified with a cryptographic secret or public key. | +| pyjwt.py:23:12:23:16 | token | is not verified with a cryptographic secret or public key. | +| python_jose.py:19:12:19:16 | token | is not verified with a cryptographic secret or public key. | +| python_jwt.py:14:28:14:32 | token | is not verified with a cryptographic secret or public key. | diff --git a/python/ql/test/experimental/query-tests/Security/CWE-348/ClientSuppliedIpUsedInSecurityCheck.expected b/python/ql/test/experimental/query-tests/Security/CWE-348/ClientSuppliedIpUsedInSecurityCheck.expected index 1d529f3b3ea0..67e3afd40421 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-348/ClientSuppliedIpUsedInSecurityCheck.expected +++ b/python/ql/test/experimental/query-tests/Security/CWE-348/ClientSuppliedIpUsedInSecurityCheck.expected @@ -1,22 +1,22 @@ edges -| flask_bad.py:13:5:13:13 | ControlFlowNode for client_ip | flask_bad.py:14:12:14:20 | ControlFlowNode for client_ip | provenance | | -| flask_bad.py:13:17:13:54 | ControlFlowNode for Attribute() | flask_bad.py:13:5:13:13 | ControlFlowNode for client_ip | provenance | | -| flask_bad.py:20:5:20:13 | ControlFlowNode for client_ip | flask_bad.py:21:12:21:20 | ControlFlowNode for client_ip | provenance | | -| flask_bad.py:20:17:20:54 | ControlFlowNode for Attribute() | flask_bad.py:20:5:20:13 | ControlFlowNode for client_ip | provenance | | -| tornado_bad.py:22:13:22:21 | ControlFlowNode for client_ip | tornado_bad.py:23:16:23:24 | ControlFlowNode for client_ip | provenance | | -| tornado_bad.py:22:25:22:69 | ControlFlowNode for Attribute() | tornado_bad.py:22:13:22:21 | ControlFlowNode for client_ip | provenance | | +| flask_bad.py:13:5:13:13 | client_ip | flask_bad.py:14:12:14:20 | client_ip | provenance | | +| flask_bad.py:13:17:13:54 | After Attribute() | flask_bad.py:13:5:13:13 | client_ip | provenance | | +| flask_bad.py:20:5:20:13 | client_ip | flask_bad.py:21:12:21:20 | client_ip | provenance | | +| flask_bad.py:20:17:20:54 | After Attribute() | flask_bad.py:20:5:20:13 | client_ip | provenance | | +| tornado_bad.py:22:13:22:21 | client_ip | tornado_bad.py:23:16:23:24 | client_ip | provenance | | +| tornado_bad.py:22:25:22:69 | After Attribute() | tornado_bad.py:22:13:22:21 | client_ip | provenance | | nodes -| flask_bad.py:13:5:13:13 | ControlFlowNode for client_ip | semmle.label | ControlFlowNode for client_ip | -| flask_bad.py:13:17:13:54 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| flask_bad.py:14:12:14:20 | ControlFlowNode for client_ip | semmle.label | ControlFlowNode for client_ip | -| flask_bad.py:20:5:20:13 | ControlFlowNode for client_ip | semmle.label | ControlFlowNode for client_ip | -| flask_bad.py:20:17:20:54 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| flask_bad.py:21:12:21:20 | ControlFlowNode for client_ip | semmle.label | ControlFlowNode for client_ip | -| tornado_bad.py:22:13:22:21 | ControlFlowNode for client_ip | semmle.label | ControlFlowNode for client_ip | -| tornado_bad.py:22:25:22:69 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| tornado_bad.py:23:16:23:24 | ControlFlowNode for client_ip | semmle.label | ControlFlowNode for client_ip | +| flask_bad.py:13:5:13:13 | client_ip | semmle.label | client_ip | +| flask_bad.py:13:17:13:54 | After Attribute() | semmle.label | After Attribute() | +| flask_bad.py:14:12:14:20 | client_ip | semmle.label | client_ip | +| flask_bad.py:20:5:20:13 | client_ip | semmle.label | client_ip | +| flask_bad.py:20:17:20:54 | After Attribute() | semmle.label | After Attribute() | +| flask_bad.py:21:12:21:20 | client_ip | semmle.label | client_ip | +| tornado_bad.py:22:13:22:21 | client_ip | semmle.label | client_ip | +| tornado_bad.py:22:25:22:69 | After Attribute() | semmle.label | After Attribute() | +| tornado_bad.py:23:16:23:24 | client_ip | semmle.label | client_ip | subpaths #select -| flask_bad.py:14:12:14:20 | ControlFlowNode for client_ip | flask_bad.py:13:17:13:54 | ControlFlowNode for Attribute() | flask_bad.py:14:12:14:20 | ControlFlowNode for client_ip | IP address spoofing might include code from $@. | flask_bad.py:13:17:13:54 | ControlFlowNode for Attribute() | this user input | -| flask_bad.py:21:12:21:20 | ControlFlowNode for client_ip | flask_bad.py:20:17:20:54 | ControlFlowNode for Attribute() | flask_bad.py:21:12:21:20 | ControlFlowNode for client_ip | IP address spoofing might include code from $@. | flask_bad.py:20:17:20:54 | ControlFlowNode for Attribute() | this user input | -| tornado_bad.py:23:16:23:24 | ControlFlowNode for client_ip | tornado_bad.py:22:25:22:69 | ControlFlowNode for Attribute() | tornado_bad.py:23:16:23:24 | ControlFlowNode for client_ip | IP address spoofing might include code from $@. | tornado_bad.py:22:25:22:69 | ControlFlowNode for Attribute() | this user input | +| flask_bad.py:14:12:14:20 | client_ip | flask_bad.py:13:17:13:54 | After Attribute() | flask_bad.py:14:12:14:20 | client_ip | IP address spoofing might include code from $@. | flask_bad.py:13:17:13:54 | After Attribute() | this user input | +| flask_bad.py:21:12:21:20 | client_ip | flask_bad.py:20:17:20:54 | After Attribute() | flask_bad.py:21:12:21:20 | client_ip | IP address spoofing might include code from $@. | flask_bad.py:20:17:20:54 | After Attribute() | this user input | +| tornado_bad.py:23:16:23:24 | client_ip | tornado_bad.py:22:25:22:69 | After Attribute() | tornado_bad.py:23:16:23:24 | client_ip | IP address spoofing might include code from $@. | tornado_bad.py:22:25:22:69 | After Attribute() | this user input | diff --git a/python/ql/test/experimental/query-tests/Security/CWE-409/DecompressionBombs.expected b/python/ql/test/experimental/query-tests/Security/CWE-409/DecompressionBombs.expected index c9f584c987e5..19253b561cbc 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-409/DecompressionBombs.expected +++ b/python/ql/test/experimental/query-tests/Security/CWE-409/DecompressionBombs.expected @@ -1,126 +1,126 @@ #select -| test.py:11:5:11:52 | ControlFlowNode for Attribute() | test.py:10:16:10:24 | ControlFlowNode for file_path | test.py:11:5:11:52 | ControlFlowNode for Attribute() | This uncontrolled file extraction is $@. | test.py:10:16:10:24 | ControlFlowNode for file_path | depends on this user controlled data | -| test.py:12:5:12:48 | ControlFlowNode for Attribute() | test.py:10:16:10:24 | ControlFlowNode for file_path | test.py:12:5:12:48 | ControlFlowNode for Attribute() | This uncontrolled file extraction is $@. | test.py:10:16:10:24 | ControlFlowNode for file_path | depends on this user controlled data | -| test.py:15:14:15:29 | ControlFlowNode for Attribute() | test.py:10:16:10:24 | ControlFlowNode for file_path | test.py:15:14:15:29 | ControlFlowNode for Attribute() | This uncontrolled file extraction is $@. | test.py:10:16:10:24 | ControlFlowNode for file_path | depends on this user controlled data | -| test.py:19:14:19:39 | ControlFlowNode for Attribute() | test.py:10:16:10:24 | ControlFlowNode for file_path | test.py:19:14:19:39 | ControlFlowNode for Attribute() | This uncontrolled file extraction is $@. | test.py:10:16:10:24 | ControlFlowNode for file_path | depends on this user controlled data | -| test.py:22:5:22:60 | ControlFlowNode for Attribute() | test.py:10:16:10:24 | ControlFlowNode for file_path | test.py:22:5:22:60 | ControlFlowNode for Attribute() | This uncontrolled file extraction is $@. | test.py:10:16:10:24 | ControlFlowNode for file_path | depends on this user controlled data | -| test.py:24:5:24:52 | ControlFlowNode for Attribute() | test.py:10:16:10:24 | ControlFlowNode for file_path | test.py:24:5:24:52 | ControlFlowNode for Attribute() | This uncontrolled file extraction is $@. | test.py:10:16:10:24 | ControlFlowNode for file_path | depends on this user controlled data | -| test.py:25:5:25:55 | ControlFlowNode for Attribute() | test.py:10:16:10:24 | ControlFlowNode for file_path | test.py:25:5:25:55 | ControlFlowNode for Attribute() | This uncontrolled file extraction is $@. | test.py:10:16:10:24 | ControlFlowNode for file_path | depends on this user controlled data | -| test.py:26:5:26:57 | ControlFlowNode for Attribute() | test.py:10:16:10:24 | ControlFlowNode for file_path | test.py:26:5:26:57 | ControlFlowNode for Attribute() | This uncontrolled file extraction is $@. | test.py:10:16:10:24 | ControlFlowNode for file_path | depends on this user controlled data | -| test.py:27:5:27:50 | ControlFlowNode for Attribute() | test.py:10:16:10:24 | ControlFlowNode for file_path | test.py:27:5:27:50 | ControlFlowNode for Attribute() | This uncontrolled file extraction is $@. | test.py:10:16:10:24 | ControlFlowNode for file_path | depends on this user controlled data | -| test.py:28:5:28:60 | ControlFlowNode for Attribute() | test.py:10:16:10:24 | ControlFlowNode for file_path | test.py:28:5:28:60 | ControlFlowNode for Attribute() | This uncontrolled file extraction is $@. | test.py:10:16:10:24 | ControlFlowNode for file_path | depends on this user controlled data | -| test.py:35:27:35:35 | ControlFlowNode for file_path | test.py:10:16:10:24 | ControlFlowNode for file_path | test.py:35:27:35:35 | ControlFlowNode for file_path | This uncontrolled file extraction is $@. | test.py:10:16:10:24 | ControlFlowNode for file_path | depends on this user controlled data | -| test.py:39:15:39:23 | ControlFlowNode for file_path | test.py:10:16:10:24 | ControlFlowNode for file_path | test.py:39:15:39:23 | ControlFlowNode for file_path | This uncontrolled file extraction is $@. | test.py:10:16:10:24 | ControlFlowNode for file_path | depends on this user controlled data | -| test.py:40:19:40:27 | ControlFlowNode for file_path | test.py:10:16:10:24 | ControlFlowNode for file_path | test.py:40:19:40:27 | ControlFlowNode for file_path | This uncontrolled file extraction is $@. | test.py:10:16:10:24 | ControlFlowNode for file_path | depends on this user controlled data | -| test.py:44:14:44:22 | ControlFlowNode for file_path | test.py:10:16:10:24 | ControlFlowNode for file_path | test.py:44:14:44:22 | ControlFlowNode for file_path | This uncontrolled file extraction is $@. | test.py:10:16:10:24 | ControlFlowNode for file_path | depends on this user controlled data | -| test.py:45:17:45:25 | ControlFlowNode for file_path | test.py:10:16:10:24 | ControlFlowNode for file_path | test.py:45:17:45:25 | ControlFlowNode for file_path | This uncontrolled file extraction is $@. | test.py:10:16:10:24 | ControlFlowNode for file_path | depends on this user controlled data | -| test.py:49:15:49:23 | ControlFlowNode for file_path | test.py:10:16:10:24 | ControlFlowNode for file_path | test.py:49:15:49:23 | ControlFlowNode for file_path | This uncontrolled file extraction is $@. | test.py:10:16:10:24 | ControlFlowNode for file_path | depends on this user controlled data | -| test.py:50:19:50:27 | ControlFlowNode for file_path | test.py:10:16:10:24 | ControlFlowNode for file_path | test.py:50:19:50:27 | ControlFlowNode for file_path | This uncontrolled file extraction is $@. | test.py:10:16:10:24 | ControlFlowNode for file_path | depends on this user controlled data | -| test.py:54:15:54:23 | ControlFlowNode for file_path | test.py:10:16:10:24 | ControlFlowNode for file_path | test.py:54:15:54:23 | ControlFlowNode for file_path | This uncontrolled file extraction is $@. | test.py:10:16:10:24 | ControlFlowNode for file_path | depends on this user controlled data | -| test.py:55:19:55:27 | ControlFlowNode for file_path | test.py:10:16:10:24 | ControlFlowNode for file_path | test.py:55:19:55:27 | ControlFlowNode for file_path | This uncontrolled file extraction is $@. | test.py:10:16:10:24 | ControlFlowNode for file_path | depends on this user controlled data | -| test.py:59:40:59:48 | ControlFlowNode for file_path | test.py:10:16:10:24 | ControlFlowNode for file_path | test.py:59:40:59:48 | ControlFlowNode for file_path | This uncontrolled file extraction is $@. | test.py:10:16:10:24 | ControlFlowNode for file_path | depends on this user controlled data | -| test.py:61:23:61:31 | ControlFlowNode for file_path | test.py:10:16:10:24 | ControlFlowNode for file_path | test.py:61:23:61:31 | ControlFlowNode for file_path | This uncontrolled file extraction is $@. | test.py:10:16:10:24 | ControlFlowNode for file_path | depends on this user controlled data | -| test.py:62:21:62:29 | ControlFlowNode for file_path | test.py:10:16:10:24 | ControlFlowNode for file_path | test.py:62:21:62:29 | ControlFlowNode for file_path | This uncontrolled file extraction is $@. | test.py:10:16:10:24 | ControlFlowNode for file_path | depends on this user controlled data | -| test.py:64:40:64:48 | ControlFlowNode for file_path | test.py:10:16:10:24 | ControlFlowNode for file_path | test.py:64:40:64:48 | ControlFlowNode for file_path | This uncontrolled file extraction is $@. | test.py:10:16:10:24 | ControlFlowNode for file_path | depends on this user controlled data | -| test.py:65:22:65:30 | ControlFlowNode for file_path | test.py:10:16:10:24 | ControlFlowNode for file_path | test.py:65:22:65:30 | ControlFlowNode for file_path | This uncontrolled file extraction is $@. | test.py:10:16:10:24 | ControlFlowNode for file_path | depends on this user controlled data | -| test.py:66:21:66:29 | ControlFlowNode for file_path | test.py:10:16:10:24 | ControlFlowNode for file_path | test.py:66:21:66:29 | ControlFlowNode for file_path | This uncontrolled file extraction is $@. | test.py:10:16:10:24 | ControlFlowNode for file_path | depends on this user controlled data | -| test.py:67:42:67:50 | ControlFlowNode for file_path | test.py:10:16:10:24 | ControlFlowNode for file_path | test.py:67:42:67:50 | ControlFlowNode for file_path | This uncontrolled file extraction is $@. | test.py:10:16:10:24 | ControlFlowNode for file_path | depends on this user controlled data | -| test.py:68:23:68:31 | ControlFlowNode for file_path | test.py:10:16:10:24 | ControlFlowNode for file_path | test.py:68:23:68:31 | ControlFlowNode for file_path | This uncontrolled file extraction is $@. | test.py:10:16:10:24 | ControlFlowNode for file_path | depends on this user controlled data | -| test.py:69:36:69:44 | ControlFlowNode for file_path | test.py:10:16:10:24 | ControlFlowNode for file_path | test.py:69:36:69:44 | ControlFlowNode for file_path | This uncontrolled file extraction is $@. | test.py:10:16:10:24 | ControlFlowNode for file_path | depends on this user controlled data | +| test.py:11:5:11:52 | After Attribute() | test.py:10:16:10:24 | file_path | test.py:11:5:11:52 | After Attribute() | This uncontrolled file extraction is $@. | test.py:10:16:10:24 | file_path | depends on this user controlled data | +| test.py:12:5:12:48 | After Attribute() | test.py:10:16:10:24 | file_path | test.py:12:5:12:48 | After Attribute() | This uncontrolled file extraction is $@. | test.py:10:16:10:24 | file_path | depends on this user controlled data | +| test.py:15:14:15:29 | After Attribute() | test.py:10:16:10:24 | file_path | test.py:15:14:15:29 | After Attribute() | This uncontrolled file extraction is $@. | test.py:10:16:10:24 | file_path | depends on this user controlled data | +| test.py:19:14:19:39 | After Attribute() | test.py:10:16:10:24 | file_path | test.py:19:14:19:39 | After Attribute() | This uncontrolled file extraction is $@. | test.py:10:16:10:24 | file_path | depends on this user controlled data | +| test.py:22:5:22:60 | After Attribute() | test.py:10:16:10:24 | file_path | test.py:22:5:22:60 | After Attribute() | This uncontrolled file extraction is $@. | test.py:10:16:10:24 | file_path | depends on this user controlled data | +| test.py:24:5:24:52 | After Attribute() | test.py:10:16:10:24 | file_path | test.py:24:5:24:52 | After Attribute() | This uncontrolled file extraction is $@. | test.py:10:16:10:24 | file_path | depends on this user controlled data | +| test.py:25:5:25:55 | After Attribute() | test.py:10:16:10:24 | file_path | test.py:25:5:25:55 | After Attribute() | This uncontrolled file extraction is $@. | test.py:10:16:10:24 | file_path | depends on this user controlled data | +| test.py:26:5:26:57 | After Attribute() | test.py:10:16:10:24 | file_path | test.py:26:5:26:57 | After Attribute() | This uncontrolled file extraction is $@. | test.py:10:16:10:24 | file_path | depends on this user controlled data | +| test.py:27:5:27:50 | After Attribute() | test.py:10:16:10:24 | file_path | test.py:27:5:27:50 | After Attribute() | This uncontrolled file extraction is $@. | test.py:10:16:10:24 | file_path | depends on this user controlled data | +| test.py:28:5:28:60 | After Attribute() | test.py:10:16:10:24 | file_path | test.py:28:5:28:60 | After Attribute() | This uncontrolled file extraction is $@. | test.py:10:16:10:24 | file_path | depends on this user controlled data | +| test.py:35:27:35:35 | file_path | test.py:10:16:10:24 | file_path | test.py:35:27:35:35 | file_path | This uncontrolled file extraction is $@. | test.py:10:16:10:24 | file_path | depends on this user controlled data | +| test.py:39:15:39:23 | file_path | test.py:10:16:10:24 | file_path | test.py:39:15:39:23 | file_path | This uncontrolled file extraction is $@. | test.py:10:16:10:24 | file_path | depends on this user controlled data | +| test.py:40:19:40:27 | file_path | test.py:10:16:10:24 | file_path | test.py:40:19:40:27 | file_path | This uncontrolled file extraction is $@. | test.py:10:16:10:24 | file_path | depends on this user controlled data | +| test.py:44:14:44:22 | file_path | test.py:10:16:10:24 | file_path | test.py:44:14:44:22 | file_path | This uncontrolled file extraction is $@. | test.py:10:16:10:24 | file_path | depends on this user controlled data | +| test.py:45:17:45:25 | file_path | test.py:10:16:10:24 | file_path | test.py:45:17:45:25 | file_path | This uncontrolled file extraction is $@. | test.py:10:16:10:24 | file_path | depends on this user controlled data | +| test.py:49:15:49:23 | file_path | test.py:10:16:10:24 | file_path | test.py:49:15:49:23 | file_path | This uncontrolled file extraction is $@. | test.py:10:16:10:24 | file_path | depends on this user controlled data | +| test.py:50:19:50:27 | file_path | test.py:10:16:10:24 | file_path | test.py:50:19:50:27 | file_path | This uncontrolled file extraction is $@. | test.py:10:16:10:24 | file_path | depends on this user controlled data | +| test.py:54:15:54:23 | file_path | test.py:10:16:10:24 | file_path | test.py:54:15:54:23 | file_path | This uncontrolled file extraction is $@. | test.py:10:16:10:24 | file_path | depends on this user controlled data | +| test.py:55:19:55:27 | file_path | test.py:10:16:10:24 | file_path | test.py:55:19:55:27 | file_path | This uncontrolled file extraction is $@. | test.py:10:16:10:24 | file_path | depends on this user controlled data | +| test.py:59:40:59:48 | file_path | test.py:10:16:10:24 | file_path | test.py:59:40:59:48 | file_path | This uncontrolled file extraction is $@. | test.py:10:16:10:24 | file_path | depends on this user controlled data | +| test.py:61:23:61:31 | file_path | test.py:10:16:10:24 | file_path | test.py:61:23:61:31 | file_path | This uncontrolled file extraction is $@. | test.py:10:16:10:24 | file_path | depends on this user controlled data | +| test.py:62:21:62:29 | file_path | test.py:10:16:10:24 | file_path | test.py:62:21:62:29 | file_path | This uncontrolled file extraction is $@. | test.py:10:16:10:24 | file_path | depends on this user controlled data | +| test.py:64:40:64:48 | file_path | test.py:10:16:10:24 | file_path | test.py:64:40:64:48 | file_path | This uncontrolled file extraction is $@. | test.py:10:16:10:24 | file_path | depends on this user controlled data | +| test.py:65:22:65:30 | file_path | test.py:10:16:10:24 | file_path | test.py:65:22:65:30 | file_path | This uncontrolled file extraction is $@. | test.py:10:16:10:24 | file_path | depends on this user controlled data | +| test.py:66:21:66:29 | file_path | test.py:10:16:10:24 | file_path | test.py:66:21:66:29 | file_path | This uncontrolled file extraction is $@. | test.py:10:16:10:24 | file_path | depends on this user controlled data | +| test.py:67:42:67:50 | file_path | test.py:10:16:10:24 | file_path | test.py:67:42:67:50 | file_path | This uncontrolled file extraction is $@. | test.py:10:16:10:24 | file_path | depends on this user controlled data | +| test.py:68:23:68:31 | file_path | test.py:10:16:10:24 | file_path | test.py:68:23:68:31 | file_path | This uncontrolled file extraction is $@. | test.py:10:16:10:24 | file_path | depends on this user controlled data | +| test.py:69:36:69:44 | file_path | test.py:10:16:10:24 | file_path | test.py:69:36:69:44 | file_path | This uncontrolled file extraction is $@. | test.py:10:16:10:24 | file_path | depends on this user controlled data | edges -| test.py:10:16:10:24 | ControlFlowNode for file_path | test.py:11:21:11:29 | ControlFlowNode for file_path | provenance | | -| test.py:11:5:11:35 | ControlFlowNode for Attribute() | test.py:11:5:11:52 | ControlFlowNode for Attribute() | provenance | Config | -| test.py:11:21:11:29 | ControlFlowNode for file_path | test.py:11:5:11:35 | ControlFlowNode for Attribute() | provenance | MaD:1 | -| test.py:11:21:11:29 | ControlFlowNode for file_path | test.py:11:5:11:52 | ControlFlowNode for Attribute() | provenance | Config | -| test.py:11:21:11:29 | ControlFlowNode for file_path | test.py:12:21:12:29 | ControlFlowNode for file_path | provenance | | -| test.py:12:5:12:35 | ControlFlowNode for Attribute() | test.py:12:5:12:48 | ControlFlowNode for Attribute() | provenance | Config | -| test.py:12:21:12:29 | ControlFlowNode for file_path | test.py:12:5:12:35 | ControlFlowNode for Attribute() | provenance | MaD:1 | -| test.py:12:21:12:29 | ControlFlowNode for file_path | test.py:12:5:12:48 | ControlFlowNode for Attribute() | provenance | Config | -| test.py:12:21:12:29 | ControlFlowNode for file_path | test.py:14:26:14:34 | ControlFlowNode for file_path | provenance | | -| test.py:14:10:14:35 | ControlFlowNode for Attribute() | test.py:15:14:15:29 | ControlFlowNode for Attribute() | provenance | Config | -| test.py:14:26:14:34 | ControlFlowNode for file_path | test.py:14:10:14:35 | ControlFlowNode for Attribute() | provenance | MaD:1 | -| test.py:14:26:14:34 | ControlFlowNode for file_path | test.py:15:14:15:29 | ControlFlowNode for Attribute() | provenance | Config | -| test.py:14:26:14:34 | ControlFlowNode for file_path | test.py:18:26:18:34 | ControlFlowNode for file_path | provenance | | -| test.py:18:10:18:35 | ControlFlowNode for Attribute() | test.py:19:14:19:39 | ControlFlowNode for Attribute() | provenance | Config | -| test.py:18:26:18:34 | ControlFlowNode for file_path | test.py:18:10:18:35 | ControlFlowNode for Attribute() | provenance | MaD:1 | -| test.py:18:26:18:34 | ControlFlowNode for file_path | test.py:19:14:19:39 | ControlFlowNode for Attribute() | provenance | Config | -| test.py:18:26:18:34 | ControlFlowNode for file_path | test.py:22:21:22:29 | ControlFlowNode for file_path | provenance | | -| test.py:22:5:22:30 | ControlFlowNode for Attribute() | test.py:22:5:22:60 | ControlFlowNode for Attribute() | provenance | Config | -| test.py:22:21:22:29 | ControlFlowNode for file_path | test.py:22:5:22:30 | ControlFlowNode for Attribute() | provenance | MaD:1 | -| test.py:22:21:22:29 | ControlFlowNode for file_path | test.py:22:5:22:60 | ControlFlowNode for Attribute() | provenance | Config | -| test.py:22:21:22:29 | ControlFlowNode for file_path | test.py:24:18:24:26 | ControlFlowNode for file_path | provenance | | -| test.py:24:18:24:26 | ControlFlowNode for file_path | test.py:24:5:24:52 | ControlFlowNode for Attribute() | provenance | Config | -| test.py:24:18:24:26 | ControlFlowNode for file_path | test.py:25:26:25:34 | ControlFlowNode for file_path | provenance | | -| test.py:25:26:25:34 | ControlFlowNode for file_path | test.py:25:5:25:55 | ControlFlowNode for Attribute() | provenance | Config | -| test.py:25:26:25:34 | ControlFlowNode for file_path | test.py:26:28:26:36 | ControlFlowNode for file_path | provenance | | -| test.py:26:28:26:36 | ControlFlowNode for file_path | test.py:26:5:26:57 | ControlFlowNode for Attribute() | provenance | Config | -| test.py:26:28:26:36 | ControlFlowNode for file_path | test.py:27:28:27:36 | ControlFlowNode for file_path | provenance | | -| test.py:27:28:27:36 | ControlFlowNode for file_path | test.py:27:5:27:50 | ControlFlowNode for Attribute() | provenance | Config | -| test.py:27:28:27:36 | ControlFlowNode for file_path | test.py:28:26:28:34 | ControlFlowNode for file_path | provenance | | -| test.py:28:26:28:34 | ControlFlowNode for file_path | test.py:28:5:28:60 | ControlFlowNode for Attribute() | provenance | Config | -| test.py:28:26:28:34 | ControlFlowNode for file_path | test.py:35:27:35:35 | ControlFlowNode for file_path | provenance | | -| test.py:28:26:28:34 | ControlFlowNode for file_path | test.py:39:15:39:23 | ControlFlowNode for file_path | provenance | | -| test.py:28:26:28:34 | ControlFlowNode for file_path | test.py:40:19:40:27 | ControlFlowNode for file_path | provenance | | -| test.py:28:26:28:34 | ControlFlowNode for file_path | test.py:44:14:44:22 | ControlFlowNode for file_path | provenance | | -| test.py:28:26:28:34 | ControlFlowNode for file_path | test.py:45:17:45:25 | ControlFlowNode for file_path | provenance | | -| test.py:28:26:28:34 | ControlFlowNode for file_path | test.py:49:15:49:23 | ControlFlowNode for file_path | provenance | | -| test.py:28:26:28:34 | ControlFlowNode for file_path | test.py:50:19:50:27 | ControlFlowNode for file_path | provenance | | -| test.py:28:26:28:34 | ControlFlowNode for file_path | test.py:54:15:54:23 | ControlFlowNode for file_path | provenance | | -| test.py:28:26:28:34 | ControlFlowNode for file_path | test.py:55:19:55:27 | ControlFlowNode for file_path | provenance | | -| test.py:28:26:28:34 | ControlFlowNode for file_path | test.py:59:40:59:48 | ControlFlowNode for file_path | provenance | | -| test.py:28:26:28:34 | ControlFlowNode for file_path | test.py:61:23:61:31 | ControlFlowNode for file_path | provenance | | -| test.py:28:26:28:34 | ControlFlowNode for file_path | test.py:62:21:62:29 | ControlFlowNode for file_path | provenance | | -| test.py:28:26:28:34 | ControlFlowNode for file_path | test.py:64:40:64:48 | ControlFlowNode for file_path | provenance | | -| test.py:28:26:28:34 | ControlFlowNode for file_path | test.py:65:22:65:30 | ControlFlowNode for file_path | provenance | | -| test.py:28:26:28:34 | ControlFlowNode for file_path | test.py:66:21:66:29 | ControlFlowNode for file_path | provenance | | -| test.py:28:26:28:34 | ControlFlowNode for file_path | test.py:67:42:67:50 | ControlFlowNode for file_path | provenance | | -| test.py:28:26:28:34 | ControlFlowNode for file_path | test.py:68:23:68:31 | ControlFlowNode for file_path | provenance | | -| test.py:28:26:28:34 | ControlFlowNode for file_path | test.py:69:36:69:44 | ControlFlowNode for file_path | provenance | | +| test.py:10:16:10:24 | file_path | test.py:11:21:11:29 | file_path | provenance | | +| test.py:11:5:11:35 | After Attribute() | test.py:11:5:11:52 | After Attribute() | provenance | Config | +| test.py:11:21:11:29 | file_path | test.py:11:5:11:35 | After Attribute() | provenance | MaD:1 | +| test.py:11:21:11:29 | file_path | test.py:11:5:11:52 | After Attribute() | provenance | Config | +| test.py:11:21:11:29 | file_path | test.py:12:21:12:29 | file_path | provenance | | +| test.py:12:5:12:35 | After Attribute() | test.py:12:5:12:48 | After Attribute() | provenance | Config | +| test.py:12:21:12:29 | file_path | test.py:12:5:12:35 | After Attribute() | provenance | MaD:1 | +| test.py:12:21:12:29 | file_path | test.py:12:5:12:48 | After Attribute() | provenance | Config | +| test.py:12:21:12:29 | file_path | test.py:14:26:14:34 | file_path | provenance | | +| test.py:14:10:14:35 | After Attribute() | test.py:15:14:15:29 | After Attribute() | provenance | Config | +| test.py:14:26:14:34 | file_path | test.py:14:10:14:35 | After Attribute() | provenance | MaD:1 | +| test.py:14:26:14:34 | file_path | test.py:15:14:15:29 | After Attribute() | provenance | Config | +| test.py:14:26:14:34 | file_path | test.py:18:26:18:34 | file_path | provenance | | +| test.py:18:10:18:35 | After Attribute() | test.py:19:14:19:39 | After Attribute() | provenance | Config | +| test.py:18:26:18:34 | file_path | test.py:18:10:18:35 | After Attribute() | provenance | MaD:1 | +| test.py:18:26:18:34 | file_path | test.py:19:14:19:39 | After Attribute() | provenance | Config | +| test.py:18:26:18:34 | file_path | test.py:22:21:22:29 | file_path | provenance | | +| test.py:22:5:22:30 | After Attribute() | test.py:22:5:22:60 | After Attribute() | provenance | Config | +| test.py:22:21:22:29 | file_path | test.py:22:5:22:30 | After Attribute() | provenance | MaD:1 | +| test.py:22:21:22:29 | file_path | test.py:22:5:22:60 | After Attribute() | provenance | Config | +| test.py:22:21:22:29 | file_path | test.py:24:18:24:26 | file_path | provenance | | +| test.py:24:18:24:26 | file_path | test.py:24:5:24:52 | After Attribute() | provenance | Config | +| test.py:24:18:24:26 | file_path | test.py:25:26:25:34 | file_path | provenance | | +| test.py:25:26:25:34 | file_path | test.py:25:5:25:55 | After Attribute() | provenance | Config | +| test.py:25:26:25:34 | file_path | test.py:26:28:26:36 | file_path | provenance | | +| test.py:26:28:26:36 | file_path | test.py:26:5:26:57 | After Attribute() | provenance | Config | +| test.py:26:28:26:36 | file_path | test.py:27:28:27:36 | file_path | provenance | | +| test.py:27:28:27:36 | file_path | test.py:27:5:27:50 | After Attribute() | provenance | Config | +| test.py:27:28:27:36 | file_path | test.py:28:26:28:34 | file_path | provenance | | +| test.py:28:26:28:34 | file_path | test.py:28:5:28:60 | After Attribute() | provenance | Config | +| test.py:28:26:28:34 | file_path | test.py:35:27:35:35 | file_path | provenance | | +| test.py:28:26:28:34 | file_path | test.py:39:15:39:23 | file_path | provenance | | +| test.py:28:26:28:34 | file_path | test.py:40:19:40:27 | file_path | provenance | | +| test.py:28:26:28:34 | file_path | test.py:44:14:44:22 | file_path | provenance | | +| test.py:28:26:28:34 | file_path | test.py:45:17:45:25 | file_path | provenance | | +| test.py:28:26:28:34 | file_path | test.py:49:15:49:23 | file_path | provenance | | +| test.py:28:26:28:34 | file_path | test.py:50:19:50:27 | file_path | provenance | | +| test.py:28:26:28:34 | file_path | test.py:54:15:54:23 | file_path | provenance | | +| test.py:28:26:28:34 | file_path | test.py:55:19:55:27 | file_path | provenance | | +| test.py:28:26:28:34 | file_path | test.py:59:40:59:48 | file_path | provenance | | +| test.py:28:26:28:34 | file_path | test.py:61:23:61:31 | file_path | provenance | | +| test.py:28:26:28:34 | file_path | test.py:62:21:62:29 | file_path | provenance | | +| test.py:28:26:28:34 | file_path | test.py:64:40:64:48 | file_path | provenance | | +| test.py:28:26:28:34 | file_path | test.py:65:22:65:30 | file_path | provenance | | +| test.py:28:26:28:34 | file_path | test.py:66:21:66:29 | file_path | provenance | | +| test.py:28:26:28:34 | file_path | test.py:67:42:67:50 | file_path | provenance | | +| test.py:28:26:28:34 | file_path | test.py:68:23:68:31 | file_path | provenance | | +| test.py:28:26:28:34 | file_path | test.py:69:36:69:44 | file_path | provenance | | models | 1 | Summary: zipfile.ZipFile!; Subclass.Call; Argument[0,file:]; ReturnValue; taint | nodes -| test.py:10:16:10:24 | ControlFlowNode for file_path | semmle.label | ControlFlowNode for file_path | -| test.py:11:5:11:35 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| test.py:11:5:11:52 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| test.py:11:21:11:29 | ControlFlowNode for file_path | semmle.label | ControlFlowNode for file_path | -| test.py:12:5:12:35 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| test.py:12:5:12:48 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| test.py:12:21:12:29 | ControlFlowNode for file_path | semmle.label | ControlFlowNode for file_path | -| test.py:14:10:14:35 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| test.py:14:26:14:34 | ControlFlowNode for file_path | semmle.label | ControlFlowNode for file_path | -| test.py:15:14:15:29 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| test.py:18:10:18:35 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| test.py:18:26:18:34 | ControlFlowNode for file_path | semmle.label | ControlFlowNode for file_path | -| test.py:19:14:19:39 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| test.py:22:5:22:30 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| test.py:22:5:22:60 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| test.py:22:21:22:29 | ControlFlowNode for file_path | semmle.label | ControlFlowNode for file_path | -| test.py:24:5:24:52 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| test.py:24:18:24:26 | ControlFlowNode for file_path | semmle.label | ControlFlowNode for file_path | -| test.py:25:5:25:55 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| test.py:25:26:25:34 | ControlFlowNode for file_path | semmle.label | ControlFlowNode for file_path | -| test.py:26:5:26:57 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| test.py:26:28:26:36 | ControlFlowNode for file_path | semmle.label | ControlFlowNode for file_path | -| test.py:27:5:27:50 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| test.py:27:28:27:36 | ControlFlowNode for file_path | semmle.label | ControlFlowNode for file_path | -| test.py:28:5:28:60 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| test.py:28:26:28:34 | ControlFlowNode for file_path | semmle.label | ControlFlowNode for file_path | -| test.py:35:27:35:35 | ControlFlowNode for file_path | semmle.label | ControlFlowNode for file_path | -| test.py:39:15:39:23 | ControlFlowNode for file_path | semmle.label | ControlFlowNode for file_path | -| test.py:40:19:40:27 | ControlFlowNode for file_path | semmle.label | ControlFlowNode for file_path | -| test.py:44:14:44:22 | ControlFlowNode for file_path | semmle.label | ControlFlowNode for file_path | -| test.py:45:17:45:25 | ControlFlowNode for file_path | semmle.label | ControlFlowNode for file_path | -| test.py:49:15:49:23 | ControlFlowNode for file_path | semmle.label | ControlFlowNode for file_path | -| test.py:50:19:50:27 | ControlFlowNode for file_path | semmle.label | ControlFlowNode for file_path | -| test.py:54:15:54:23 | ControlFlowNode for file_path | semmle.label | ControlFlowNode for file_path | -| test.py:55:19:55:27 | ControlFlowNode for file_path | semmle.label | ControlFlowNode for file_path | -| test.py:59:40:59:48 | ControlFlowNode for file_path | semmle.label | ControlFlowNode for file_path | -| test.py:61:23:61:31 | ControlFlowNode for file_path | semmle.label | ControlFlowNode for file_path | -| test.py:62:21:62:29 | ControlFlowNode for file_path | semmle.label | ControlFlowNode for file_path | -| test.py:64:40:64:48 | ControlFlowNode for file_path | semmle.label | ControlFlowNode for file_path | -| test.py:65:22:65:30 | ControlFlowNode for file_path | semmle.label | ControlFlowNode for file_path | -| test.py:66:21:66:29 | ControlFlowNode for file_path | semmle.label | ControlFlowNode for file_path | -| test.py:67:42:67:50 | ControlFlowNode for file_path | semmle.label | ControlFlowNode for file_path | -| test.py:68:23:68:31 | ControlFlowNode for file_path | semmle.label | ControlFlowNode for file_path | -| test.py:69:36:69:44 | ControlFlowNode for file_path | semmle.label | ControlFlowNode for file_path | +| test.py:10:16:10:24 | file_path | semmle.label | file_path | +| test.py:11:5:11:35 | After Attribute() | semmle.label | After Attribute() | +| test.py:11:5:11:52 | After Attribute() | semmle.label | After Attribute() | +| test.py:11:21:11:29 | file_path | semmle.label | file_path | +| test.py:12:5:12:35 | After Attribute() | semmle.label | After Attribute() | +| test.py:12:5:12:48 | After Attribute() | semmle.label | After Attribute() | +| test.py:12:21:12:29 | file_path | semmle.label | file_path | +| test.py:14:10:14:35 | After Attribute() | semmle.label | After Attribute() | +| test.py:14:26:14:34 | file_path | semmle.label | file_path | +| test.py:15:14:15:29 | After Attribute() | semmle.label | After Attribute() | +| test.py:18:10:18:35 | After Attribute() | semmle.label | After Attribute() | +| test.py:18:26:18:34 | file_path | semmle.label | file_path | +| test.py:19:14:19:39 | After Attribute() | semmle.label | After Attribute() | +| test.py:22:5:22:30 | After Attribute() | semmle.label | After Attribute() | +| test.py:22:5:22:60 | After Attribute() | semmle.label | After Attribute() | +| test.py:22:21:22:29 | file_path | semmle.label | file_path | +| test.py:24:5:24:52 | After Attribute() | semmle.label | After Attribute() | +| test.py:24:18:24:26 | file_path | semmle.label | file_path | +| test.py:25:5:25:55 | After Attribute() | semmle.label | After Attribute() | +| test.py:25:26:25:34 | file_path | semmle.label | file_path | +| test.py:26:5:26:57 | After Attribute() | semmle.label | After Attribute() | +| test.py:26:28:26:36 | file_path | semmle.label | file_path | +| test.py:27:5:27:50 | After Attribute() | semmle.label | After Attribute() | +| test.py:27:28:27:36 | file_path | semmle.label | file_path | +| test.py:28:5:28:60 | After Attribute() | semmle.label | After Attribute() | +| test.py:28:26:28:34 | file_path | semmle.label | file_path | +| test.py:35:27:35:35 | file_path | semmle.label | file_path | +| test.py:39:15:39:23 | file_path | semmle.label | file_path | +| test.py:40:19:40:27 | file_path | semmle.label | file_path | +| test.py:44:14:44:22 | file_path | semmle.label | file_path | +| test.py:45:17:45:25 | file_path | semmle.label | file_path | +| test.py:49:15:49:23 | file_path | semmle.label | file_path | +| test.py:50:19:50:27 | file_path | semmle.label | file_path | +| test.py:54:15:54:23 | file_path | semmle.label | file_path | +| test.py:55:19:55:27 | file_path | semmle.label | file_path | +| test.py:59:40:59:48 | file_path | semmle.label | file_path | +| test.py:61:23:61:31 | file_path | semmle.label | file_path | +| test.py:62:21:62:29 | file_path | semmle.label | file_path | +| test.py:64:40:64:48 | file_path | semmle.label | file_path | +| test.py:65:22:65:30 | file_path | semmle.label | file_path | +| test.py:66:21:66:29 | file_path | semmle.label | file_path | +| test.py:67:42:67:50 | file_path | semmle.label | file_path | +| test.py:68:23:68:31 | file_path | semmle.label | file_path | +| test.py:69:36:69:44 | file_path | semmle.label | file_path | subpaths diff --git a/python/ql/test/experimental/query-tests/Security/CWE-522/LdapInsecureAuth.expected b/python/ql/test/experimental/query-tests/Security/CWE-522/LdapInsecureAuth.expected index b07d47c203c5..edf097ffb8bb 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-522/LdapInsecureAuth.expected +++ b/python/ql/test/experimental/query-tests/Security/CWE-522/LdapInsecureAuth.expected @@ -1,36 +1,36 @@ edges -| ldap3_remote.py:2:19:2:25 | ControlFlowNode for ImportMember | ldap3_remote.py:2:19:2:25 | ControlFlowNode for request | provenance | | -| ldap3_remote.py:2:19:2:25 | ControlFlowNode for request | ldap3_remote.py:138:21:138:27 | ControlFlowNode for request | provenance | | -| ldap3_remote.py:101:5:101:8 | ControlFlowNode for host | ldap3_remote.py:102:18:102:21 | ControlFlowNode for host | provenance | | -| ldap3_remote.py:101:12:101:49 | ControlFlowNode for BinaryExpr | ldap3_remote.py:101:5:101:8 | ControlFlowNode for host | provenance | | -| ldap3_remote.py:114:5:114:8 | ControlFlowNode for host | ldap3_remote.py:115:18:115:21 | ControlFlowNode for host | provenance | | -| ldap3_remote.py:114:12:114:49 | ControlFlowNode for BinaryExpr | ldap3_remote.py:114:5:114:8 | ControlFlowNode for host | provenance | | -| ldap3_remote.py:126:5:126:8 | ControlFlowNode for host | ldap3_remote.py:127:18:127:21 | ControlFlowNode for host | provenance | | -| ldap3_remote.py:126:12:126:31 | ControlFlowNode for BinaryExpr | ldap3_remote.py:126:5:126:8 | ControlFlowNode for host | provenance | | -| ldap3_remote.py:138:5:138:8 | ControlFlowNode for host | ldap3_remote.py:139:18:139:21 | ControlFlowNode for host | provenance | | -| ldap3_remote.py:138:21:138:27 | ControlFlowNode for request | ldap3_remote.py:138:5:138:8 | ControlFlowNode for host | provenance | AdditionalTaintStep | +| ldap3_remote.py:2:19:2:25 | After ImportMember | ldap3_remote.py:2:19:2:25 | request | provenance | | +| ldap3_remote.py:2:19:2:25 | request | ldap3_remote.py:138:21:138:27 | request | provenance | | +| ldap3_remote.py:101:5:101:8 | host | ldap3_remote.py:102:18:102:21 | host | provenance | | +| ldap3_remote.py:101:12:101:49 | After BinaryExpr | ldap3_remote.py:101:5:101:8 | host | provenance | | +| ldap3_remote.py:114:5:114:8 | host | ldap3_remote.py:115:18:115:21 | host | provenance | | +| ldap3_remote.py:114:12:114:49 | After BinaryExpr | ldap3_remote.py:114:5:114:8 | host | provenance | | +| ldap3_remote.py:126:5:126:8 | host | ldap3_remote.py:127:18:127:21 | host | provenance | | +| ldap3_remote.py:126:12:126:31 | After BinaryExpr | ldap3_remote.py:126:5:126:8 | host | provenance | | +| ldap3_remote.py:138:5:138:8 | host | ldap3_remote.py:139:18:139:21 | host | provenance | | +| ldap3_remote.py:138:21:138:27 | request | ldap3_remote.py:138:5:138:8 | host | provenance | AdditionalTaintStep | nodes -| ldap2_remote.py:45:41:45:60 | ControlFlowNode for BinaryExpr | semmle.label | ControlFlowNode for BinaryExpr | -| ldap2_remote.py:56:41:56:60 | ControlFlowNode for BinaryExpr | semmle.label | ControlFlowNode for BinaryExpr | -| ldap3_remote.py:2:19:2:25 | ControlFlowNode for ImportMember | semmle.label | ControlFlowNode for ImportMember | -| ldap3_remote.py:2:19:2:25 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| ldap3_remote.py:101:5:101:8 | ControlFlowNode for host | semmle.label | ControlFlowNode for host | -| ldap3_remote.py:101:12:101:49 | ControlFlowNode for BinaryExpr | semmle.label | ControlFlowNode for BinaryExpr | -| ldap3_remote.py:102:18:102:21 | ControlFlowNode for host | semmle.label | ControlFlowNode for host | -| ldap3_remote.py:114:5:114:8 | ControlFlowNode for host | semmle.label | ControlFlowNode for host | -| ldap3_remote.py:114:12:114:49 | ControlFlowNode for BinaryExpr | semmle.label | ControlFlowNode for BinaryExpr | -| ldap3_remote.py:115:18:115:21 | ControlFlowNode for host | semmle.label | ControlFlowNode for host | -| ldap3_remote.py:126:5:126:8 | ControlFlowNode for host | semmle.label | ControlFlowNode for host | -| ldap3_remote.py:126:12:126:31 | ControlFlowNode for BinaryExpr | semmle.label | ControlFlowNode for BinaryExpr | -| ldap3_remote.py:127:18:127:21 | ControlFlowNode for host | semmle.label | ControlFlowNode for host | -| ldap3_remote.py:138:5:138:8 | ControlFlowNode for host | semmle.label | ControlFlowNode for host | -| ldap3_remote.py:138:21:138:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| ldap3_remote.py:139:18:139:21 | ControlFlowNode for host | semmle.label | ControlFlowNode for host | +| ldap2_remote.py:45:41:45:60 | After BinaryExpr | semmle.label | After BinaryExpr | +| ldap2_remote.py:56:41:56:60 | After BinaryExpr | semmle.label | After BinaryExpr | +| ldap3_remote.py:2:19:2:25 | After ImportMember | semmle.label | After ImportMember | +| ldap3_remote.py:2:19:2:25 | request | semmle.label | request | +| ldap3_remote.py:101:5:101:8 | host | semmle.label | host | +| ldap3_remote.py:101:12:101:49 | After BinaryExpr | semmle.label | After BinaryExpr | +| ldap3_remote.py:102:18:102:21 | host | semmle.label | host | +| ldap3_remote.py:114:5:114:8 | host | semmle.label | host | +| ldap3_remote.py:114:12:114:49 | After BinaryExpr | semmle.label | After BinaryExpr | +| ldap3_remote.py:115:18:115:21 | host | semmle.label | host | +| ldap3_remote.py:126:5:126:8 | host | semmle.label | host | +| ldap3_remote.py:126:12:126:31 | After BinaryExpr | semmle.label | After BinaryExpr | +| ldap3_remote.py:127:18:127:21 | host | semmle.label | host | +| ldap3_remote.py:138:5:138:8 | host | semmle.label | host | +| ldap3_remote.py:138:21:138:27 | request | semmle.label | request | +| ldap3_remote.py:139:18:139:21 | host | semmle.label | host | subpaths #select -| ldap2_remote.py:45:41:45:60 | ControlFlowNode for BinaryExpr | ldap2_remote.py:45:41:45:60 | ControlFlowNode for BinaryExpr | ldap2_remote.py:45:41:45:60 | ControlFlowNode for BinaryExpr | This LDAP host is authenticated insecurely. | -| ldap2_remote.py:56:41:56:60 | ControlFlowNode for BinaryExpr | ldap2_remote.py:56:41:56:60 | ControlFlowNode for BinaryExpr | ldap2_remote.py:56:41:56:60 | ControlFlowNode for BinaryExpr | This LDAP host is authenticated insecurely. | -| ldap3_remote.py:102:18:102:21 | ControlFlowNode for host | ldap3_remote.py:101:12:101:49 | ControlFlowNode for BinaryExpr | ldap3_remote.py:102:18:102:21 | ControlFlowNode for host | This LDAP host is authenticated insecurely. | -| ldap3_remote.py:115:18:115:21 | ControlFlowNode for host | ldap3_remote.py:114:12:114:49 | ControlFlowNode for BinaryExpr | ldap3_remote.py:115:18:115:21 | ControlFlowNode for host | This LDAP host is authenticated insecurely. | -| ldap3_remote.py:127:18:127:21 | ControlFlowNode for host | ldap3_remote.py:126:12:126:31 | ControlFlowNode for BinaryExpr | ldap3_remote.py:127:18:127:21 | ControlFlowNode for host | This LDAP host is authenticated insecurely. | -| ldap3_remote.py:139:18:139:21 | ControlFlowNode for host | ldap3_remote.py:2:19:2:25 | ControlFlowNode for ImportMember | ldap3_remote.py:139:18:139:21 | ControlFlowNode for host | This LDAP host is authenticated insecurely. | +| ldap2_remote.py:45:41:45:60 | After BinaryExpr | ldap2_remote.py:45:41:45:60 | After BinaryExpr | ldap2_remote.py:45:41:45:60 | After BinaryExpr | This LDAP host is authenticated insecurely. | +| ldap2_remote.py:56:41:56:60 | After BinaryExpr | ldap2_remote.py:56:41:56:60 | After BinaryExpr | ldap2_remote.py:56:41:56:60 | After BinaryExpr | This LDAP host is authenticated insecurely. | +| ldap3_remote.py:102:18:102:21 | host | ldap3_remote.py:101:12:101:49 | After BinaryExpr | ldap3_remote.py:102:18:102:21 | host | This LDAP host is authenticated insecurely. | +| ldap3_remote.py:115:18:115:21 | host | ldap3_remote.py:114:12:114:49 | After BinaryExpr | ldap3_remote.py:115:18:115:21 | host | This LDAP host is authenticated insecurely. | +| ldap3_remote.py:127:18:127:21 | host | ldap3_remote.py:126:12:126:31 | After BinaryExpr | ldap3_remote.py:127:18:127:21 | host | This LDAP host is authenticated insecurely. | +| ldap3_remote.py:139:18:139:21 | host | ldap3_remote.py:2:19:2:25 | After ImportMember | ldap3_remote.py:139:18:139:21 | host | This LDAP host is authenticated insecurely. | diff --git a/python/ql/test/experimental/query-tests/Security/CWE-611-SimpleXmlRpcServer/SimpleXmlRpcServer.expected b/python/ql/test/experimental/query-tests/Security/CWE-611-SimpleXmlRpcServer/SimpleXmlRpcServer.expected index 30438f410831..efe35edb600f 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-611-SimpleXmlRpcServer/SimpleXmlRpcServer.expected +++ b/python/ql/test/experimental/query-tests/Security/CWE-611-SimpleXmlRpcServer/SimpleXmlRpcServer.expected @@ -1 +1 @@ -| xmlrpc_server.py:7:10:7:48 | ControlFlowNode for SimpleXMLRPCServer() | SimpleXMLRPCServer is vulnerable to XML bombs. | +| xmlrpc_server.py:7:10:7:48 | After SimpleXMLRPCServer() | SimpleXMLRPCServer is vulnerable to XML bombs. | diff --git a/python/ql/test/experimental/query-tests/Security/CWE-770/UnicodeDoS.expected b/python/ql/test/experimental/query-tests/Security/CWE-770/UnicodeDoS.expected index 430e7558fdc6..6da3a668b3e9 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-770/UnicodeDoS.expected +++ b/python/ql/test/experimental/query-tests/Security/CWE-770/UnicodeDoS.expected @@ -1,73 +1,73 @@ edges -| tests.py:1:35:1:41 | ControlFlowNode for ImportMember | tests.py:1:35:1:41 | ControlFlowNode for request | provenance | | -| tests.py:1:35:1:41 | ControlFlowNode for request | tests.py:12:17:12:23 | ControlFlowNode for request | provenance | | -| tests.py:1:35:1:41 | ControlFlowNode for request | tests.py:24:9:24:15 | ControlFlowNode for request | provenance | | -| tests.py:1:35:1:41 | ControlFlowNode for request | tests.py:36:9:36:15 | ControlFlowNode for request | provenance | | -| tests.py:1:35:1:41 | ControlFlowNode for request | tests.py:48:9:48:15 | ControlFlowNode for request | provenance | | -| tests.py:1:35:1:41 | ControlFlowNode for request | tests.py:60:9:60:15 | ControlFlowNode for request | provenance | | -| tests.py:1:35:1:41 | ControlFlowNode for request | tests.py:72:9:72:15 | ControlFlowNode for request | provenance | | -| tests.py:12:5:12:13 | ControlFlowNode for file_path | tests.py:16:39:16:47 | ControlFlowNode for file_path | provenance | | -| tests.py:12:17:12:23 | ControlFlowNode for request | tests.py:12:17:12:28 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | -| tests.py:12:17:12:28 | ControlFlowNode for Attribute | tests.py:12:17:12:49 | ControlFlowNode for Attribute() | provenance | dict.get | -| tests.py:12:17:12:49 | ControlFlowNode for Attribute() | tests.py:12:5:12:13 | ControlFlowNode for file_path | provenance | | -| tests.py:24:5:24:5 | ControlFlowNode for r | tests.py:28:43:28:43 | ControlFlowNode for r | provenance | | -| tests.py:24:9:24:15 | ControlFlowNode for request | tests.py:24:9:24:20 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | -| tests.py:24:9:24:20 | ControlFlowNode for Attribute | tests.py:24:9:24:33 | ControlFlowNode for Attribute() | provenance | dict.get | -| tests.py:24:9:24:33 | ControlFlowNode for Attribute() | tests.py:24:5:24:5 | ControlFlowNode for r | provenance | | -| tests.py:36:5:36:5 | ControlFlowNode for r | tests.py:40:43:40:43 | ControlFlowNode for r | provenance | | -| tests.py:36:9:36:15 | ControlFlowNode for request | tests.py:36:9:36:20 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | -| tests.py:36:9:36:20 | ControlFlowNode for Attribute | tests.py:36:9:36:33 | ControlFlowNode for Attribute() | provenance | dict.get | -| tests.py:36:9:36:33 | ControlFlowNode for Attribute() | tests.py:36:5:36:5 | ControlFlowNode for r | provenance | | -| tests.py:48:5:48:5 | ControlFlowNode for r | tests.py:52:43:52:43 | ControlFlowNode for r | provenance | | -| tests.py:48:9:48:15 | ControlFlowNode for request | tests.py:48:9:48:20 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | -| tests.py:48:9:48:20 | ControlFlowNode for Attribute | tests.py:48:9:48:33 | ControlFlowNode for Attribute() | provenance | dict.get | -| tests.py:48:9:48:33 | ControlFlowNode for Attribute() | tests.py:48:5:48:5 | ControlFlowNode for r | provenance | | -| tests.py:60:5:60:5 | ControlFlowNode for r | tests.py:64:43:64:43 | ControlFlowNode for r | provenance | | -| tests.py:60:9:60:15 | ControlFlowNode for request | tests.py:60:9:60:20 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | -| tests.py:60:9:60:20 | ControlFlowNode for Attribute | tests.py:60:9:60:33 | ControlFlowNode for Attribute() | provenance | dict.get | -| tests.py:60:9:60:33 | ControlFlowNode for Attribute() | tests.py:60:5:60:5 | ControlFlowNode for r | provenance | | -| tests.py:72:5:72:5 | ControlFlowNode for r | tests.py:76:43:76:43 | ControlFlowNode for r | provenance | | -| tests.py:72:9:72:15 | ControlFlowNode for request | tests.py:72:9:72:20 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | -| tests.py:72:9:72:20 | ControlFlowNode for Attribute | tests.py:72:9:72:33 | ControlFlowNode for Attribute() | provenance | dict.get | -| tests.py:72:9:72:33 | ControlFlowNode for Attribute() | tests.py:72:5:72:5 | ControlFlowNode for r | provenance | | +| tests.py:1:35:1:41 | After ImportMember | tests.py:1:35:1:41 | request | provenance | | +| tests.py:1:35:1:41 | request | tests.py:12:17:12:23 | request | provenance | | +| tests.py:1:35:1:41 | request | tests.py:24:9:24:15 | request | provenance | | +| tests.py:1:35:1:41 | request | tests.py:36:9:36:15 | request | provenance | | +| tests.py:1:35:1:41 | request | tests.py:48:9:48:15 | request | provenance | | +| tests.py:1:35:1:41 | request | tests.py:60:9:60:15 | request | provenance | | +| tests.py:1:35:1:41 | request | tests.py:72:9:72:15 | request | provenance | | +| tests.py:12:5:12:13 | file_path | tests.py:16:39:16:47 | file_path | provenance | | +| tests.py:12:17:12:23 | request | tests.py:12:17:12:28 | After Attribute | provenance | AdditionalTaintStep | +| tests.py:12:17:12:28 | After Attribute | tests.py:12:17:12:49 | After Attribute() | provenance | dict.get | +| tests.py:12:17:12:49 | After Attribute() | tests.py:12:5:12:13 | file_path | provenance | | +| tests.py:24:5:24:5 | r | tests.py:28:43:28:43 | r | provenance | | +| tests.py:24:9:24:15 | request | tests.py:24:9:24:20 | After Attribute | provenance | AdditionalTaintStep | +| tests.py:24:9:24:20 | After Attribute | tests.py:24:9:24:33 | After Attribute() | provenance | dict.get | +| tests.py:24:9:24:33 | After Attribute() | tests.py:24:5:24:5 | r | provenance | | +| tests.py:36:5:36:5 | r | tests.py:40:43:40:43 | r | provenance | | +| tests.py:36:9:36:15 | request | tests.py:36:9:36:20 | After Attribute | provenance | AdditionalTaintStep | +| tests.py:36:9:36:20 | After Attribute | tests.py:36:9:36:33 | After Attribute() | provenance | dict.get | +| tests.py:36:9:36:33 | After Attribute() | tests.py:36:5:36:5 | r | provenance | | +| tests.py:48:5:48:5 | r | tests.py:52:43:52:43 | r | provenance | | +| tests.py:48:9:48:15 | request | tests.py:48:9:48:20 | After Attribute | provenance | AdditionalTaintStep | +| tests.py:48:9:48:20 | After Attribute | tests.py:48:9:48:33 | After Attribute() | provenance | dict.get | +| tests.py:48:9:48:33 | After Attribute() | tests.py:48:5:48:5 | r | provenance | | +| tests.py:60:5:60:5 | r | tests.py:64:43:64:43 | r | provenance | | +| tests.py:60:9:60:15 | request | tests.py:60:9:60:20 | After Attribute | provenance | AdditionalTaintStep | +| tests.py:60:9:60:20 | After Attribute | tests.py:60:9:60:33 | After Attribute() | provenance | dict.get | +| tests.py:60:9:60:33 | After Attribute() | tests.py:60:5:60:5 | r | provenance | | +| tests.py:72:5:72:5 | r | tests.py:76:43:76:43 | r | provenance | | +| tests.py:72:9:72:15 | request | tests.py:72:9:72:20 | After Attribute | provenance | AdditionalTaintStep | +| tests.py:72:9:72:20 | After Attribute | tests.py:72:9:72:33 | After Attribute() | provenance | dict.get | +| tests.py:72:9:72:33 | After Attribute() | tests.py:72:5:72:5 | r | provenance | | nodes -| tests.py:1:35:1:41 | ControlFlowNode for ImportMember | semmle.label | ControlFlowNode for ImportMember | -| tests.py:1:35:1:41 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| tests.py:12:5:12:13 | ControlFlowNode for file_path | semmle.label | ControlFlowNode for file_path | -| tests.py:12:17:12:23 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| tests.py:12:17:12:28 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| tests.py:12:17:12:49 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| tests.py:16:39:16:47 | ControlFlowNode for file_path | semmle.label | ControlFlowNode for file_path | -| tests.py:24:5:24:5 | ControlFlowNode for r | semmle.label | ControlFlowNode for r | -| tests.py:24:9:24:15 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| tests.py:24:9:24:20 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| tests.py:24:9:24:33 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| tests.py:28:43:28:43 | ControlFlowNode for r | semmle.label | ControlFlowNode for r | -| tests.py:36:5:36:5 | ControlFlowNode for r | semmle.label | ControlFlowNode for r | -| tests.py:36:9:36:15 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| tests.py:36:9:36:20 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| tests.py:36:9:36:33 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| tests.py:40:43:40:43 | ControlFlowNode for r | semmle.label | ControlFlowNode for r | -| tests.py:48:5:48:5 | ControlFlowNode for r | semmle.label | ControlFlowNode for r | -| tests.py:48:9:48:15 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| tests.py:48:9:48:20 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| tests.py:48:9:48:33 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| tests.py:52:43:52:43 | ControlFlowNode for r | semmle.label | ControlFlowNode for r | -| tests.py:60:5:60:5 | ControlFlowNode for r | semmle.label | ControlFlowNode for r | -| tests.py:60:9:60:15 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| tests.py:60:9:60:20 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| tests.py:60:9:60:33 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| tests.py:64:43:64:43 | ControlFlowNode for r | semmle.label | ControlFlowNode for r | -| tests.py:72:5:72:5 | ControlFlowNode for r | semmle.label | ControlFlowNode for r | -| tests.py:72:9:72:15 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| tests.py:72:9:72:20 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| tests.py:72:9:72:33 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| tests.py:76:43:76:43 | ControlFlowNode for r | semmle.label | ControlFlowNode for r | +| tests.py:1:35:1:41 | After ImportMember | semmle.label | After ImportMember | +| tests.py:1:35:1:41 | request | semmle.label | request | +| tests.py:12:5:12:13 | file_path | semmle.label | file_path | +| tests.py:12:17:12:23 | request | semmle.label | request | +| tests.py:12:17:12:28 | After Attribute | semmle.label | After Attribute | +| tests.py:12:17:12:49 | After Attribute() | semmle.label | After Attribute() | +| tests.py:16:39:16:47 | file_path | semmle.label | file_path | +| tests.py:24:5:24:5 | r | semmle.label | r | +| tests.py:24:9:24:15 | request | semmle.label | request | +| tests.py:24:9:24:20 | After Attribute | semmle.label | After Attribute | +| tests.py:24:9:24:33 | After Attribute() | semmle.label | After Attribute() | +| tests.py:28:43:28:43 | r | semmle.label | r | +| tests.py:36:5:36:5 | r | semmle.label | r | +| tests.py:36:9:36:15 | request | semmle.label | request | +| tests.py:36:9:36:20 | After Attribute | semmle.label | After Attribute | +| tests.py:36:9:36:33 | After Attribute() | semmle.label | After Attribute() | +| tests.py:40:43:40:43 | r | semmle.label | r | +| tests.py:48:5:48:5 | r | semmle.label | r | +| tests.py:48:9:48:15 | request | semmle.label | request | +| tests.py:48:9:48:20 | After Attribute | semmle.label | After Attribute | +| tests.py:48:9:48:33 | After Attribute() | semmle.label | After Attribute() | +| tests.py:52:43:52:43 | r | semmle.label | r | +| tests.py:60:5:60:5 | r | semmle.label | r | +| tests.py:60:9:60:15 | request | semmle.label | request | +| tests.py:60:9:60:20 | After Attribute | semmle.label | After Attribute | +| tests.py:60:9:60:33 | After Attribute() | semmle.label | After Attribute() | +| tests.py:64:43:64:43 | r | semmle.label | r | +| tests.py:72:5:72:5 | r | semmle.label | r | +| tests.py:72:9:72:15 | request | semmle.label | request | +| tests.py:72:9:72:20 | After Attribute | semmle.label | After Attribute | +| tests.py:72:9:72:33 | After Attribute() | semmle.label | After Attribute() | +| tests.py:76:43:76:43 | r | semmle.label | r | subpaths #select -| tests.py:16:39:16:47 | ControlFlowNode for file_path | tests.py:1:35:1:41 | ControlFlowNode for ImportMember | tests.py:16:39:16:47 | ControlFlowNode for file_path | This $@ can reach a $@. | tests.py:1:35:1:41 | ControlFlowNode for ImportMember | user-provided value | tests.py:16:39:16:47 | ControlFlowNode for file_path | costly Unicode normalization operation | -| tests.py:28:43:28:43 | ControlFlowNode for r | tests.py:1:35:1:41 | ControlFlowNode for ImportMember | tests.py:28:43:28:43 | ControlFlowNode for r | This $@ can reach a $@. | tests.py:1:35:1:41 | ControlFlowNode for ImportMember | user-provided value | tests.py:28:43:28:43 | ControlFlowNode for r | costly Unicode normalization operation | -| tests.py:40:43:40:43 | ControlFlowNode for r | tests.py:1:35:1:41 | ControlFlowNode for ImportMember | tests.py:40:43:40:43 | ControlFlowNode for r | This $@ can reach a $@. | tests.py:1:35:1:41 | ControlFlowNode for ImportMember | user-provided value | tests.py:40:43:40:43 | ControlFlowNode for r | costly Unicode normalization operation | -| tests.py:52:43:52:43 | ControlFlowNode for r | tests.py:1:35:1:41 | ControlFlowNode for ImportMember | tests.py:52:43:52:43 | ControlFlowNode for r | This $@ can reach a $@. | tests.py:1:35:1:41 | ControlFlowNode for ImportMember | user-provided value | tests.py:52:43:52:43 | ControlFlowNode for r | costly Unicode normalization operation | -| tests.py:64:43:64:43 | ControlFlowNode for r | tests.py:1:35:1:41 | ControlFlowNode for ImportMember | tests.py:64:43:64:43 | ControlFlowNode for r | This $@ can reach a $@. | tests.py:1:35:1:41 | ControlFlowNode for ImportMember | user-provided value | tests.py:64:43:64:43 | ControlFlowNode for r | costly Unicode normalization operation | -| tests.py:76:43:76:43 | ControlFlowNode for r | tests.py:1:35:1:41 | ControlFlowNode for ImportMember | tests.py:76:43:76:43 | ControlFlowNode for r | This $@ can reach a $@. | tests.py:1:35:1:41 | ControlFlowNode for ImportMember | user-provided value | tests.py:76:43:76:43 | ControlFlowNode for r | costly Unicode normalization operation | +| tests.py:16:39:16:47 | file_path | tests.py:1:35:1:41 | After ImportMember | tests.py:16:39:16:47 | file_path | This $@ can reach a $@. | tests.py:1:35:1:41 | After ImportMember | user-provided value | tests.py:16:39:16:47 | file_path | costly Unicode normalization operation | +| tests.py:28:43:28:43 | r | tests.py:1:35:1:41 | After ImportMember | tests.py:28:43:28:43 | r | This $@ can reach a $@. | tests.py:1:35:1:41 | After ImportMember | user-provided value | tests.py:28:43:28:43 | r | costly Unicode normalization operation | +| tests.py:40:43:40:43 | r | tests.py:1:35:1:41 | After ImportMember | tests.py:40:43:40:43 | r | This $@ can reach a $@. | tests.py:1:35:1:41 | After ImportMember | user-provided value | tests.py:40:43:40:43 | r | costly Unicode normalization operation | +| tests.py:52:43:52:43 | r | tests.py:1:35:1:41 | After ImportMember | tests.py:52:43:52:43 | r | This $@ can reach a $@. | tests.py:1:35:1:41 | After ImportMember | user-provided value | tests.py:52:43:52:43 | r | costly Unicode normalization operation | +| tests.py:64:43:64:43 | r | tests.py:1:35:1:41 | After ImportMember | tests.py:64:43:64:43 | r | This $@ can reach a $@. | tests.py:1:35:1:41 | After ImportMember | user-provided value | tests.py:64:43:64:43 | r | costly Unicode normalization operation | +| tests.py:76:43:76:43 | r | tests.py:1:35:1:41 | After ImportMember | tests.py:76:43:76:43 | r | This $@ can reach a $@. | tests.py:1:35:1:41 | After ImportMember | user-provided value | tests.py:76:43:76:43 | r | costly Unicode normalization operation | diff --git a/python/ql/test/extractor-tests/syntax_error/CONSISTENCY/CfgConsistency.expected b/python/ql/test/extractor-tests/syntax_error/CONSISTENCY/CfgConsistency.expected new file mode 100644 index 000000000000..91a01a3a3d93 --- /dev/null +++ b/python/ql/test/extractor-tests/syntax_error/CONSISTENCY/CfgConsistency.expected @@ -0,0 +1,4 @@ +consistencyOverview +| deadEnd | 1 | +deadEnd +| without_loop.py:7:5:7:9 | Break | diff --git a/python/ql/test/library-tests/ApiGraphs/py3/ModuleImportWithDots.expected b/python/ql/test/library-tests/ApiGraphs/py3/ModuleImportWithDots.expected index a6798920cdee..1b0d0a0cf3ad 100644 --- a/python/ql/test/library-tests/ApiGraphs/py3/ModuleImportWithDots.expected +++ b/python/ql/test/library-tests/ApiGraphs/py3/ModuleImportWithDots.expected @@ -1,5 +1,5 @@ moduleImportWithDots doesntFullyWork works -| test.py:25:6:25:18 | ControlFlowNode for Attribute() | -| test.py:28:10:28:17 | ControlFlowNode for method() | +| test.py:25:6:25:18 | After Attribute() | +| test.py:28:10:28:17 | After method() | diff --git a/python/ql/test/library-tests/ApiGraphs/py3/test_crosstalk.expected b/python/ql/test/library-tests/ApiGraphs/py3/test_crosstalk.expected index 58698e5ec9d6..24c2b88cb4aa 100644 --- a/python/ql/test/library-tests/ApiGraphs/py3/test_crosstalk.expected +++ b/python/ql/test/library-tests/ApiGraphs/py3/test_crosstalk.expected @@ -1,2 +1,2 @@ -| test_crosstalk.py:8:16:8:18 | ControlFlowNode for f() | bar | -| test_crosstalk.py:13:16:13:18 | ControlFlowNode for g() | baz | +| test_crosstalk.py:8:16:8:18 | After f() | bar | +| test_crosstalk.py:13:16:13:18 | After g() | baz | diff --git a/python/ql/test/library-tests/ControlFlow/bindings/BindingsTest.expected b/python/ql/test/library-tests/ControlFlow/bindings/BindingsTest.expected new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/ql/test/library-tests/ControlFlow/bindings/BindingsTest.ql b/python/ql/test/library-tests/ControlFlow/bindings/BindingsTest.ql new file mode 100644 index 000000000000..a507878911b1 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/bindings/BindingsTest.ql @@ -0,0 +1,32 @@ +/** + * Phase -1 of the dataflow CFG migration: verifies that every variable + * binding visible to the AST (`Name.defines(v)`) corresponds to a CFG node + * in the new CFG (`semmle.python.controlflow.internal.AstNodeImpl`). + * + * The expected tag is `cfgdefines=`. Each binding annotation in the + * test sources looks like `# $ cfgdefines=x` for a binding currently + * covered by the new CFG, or `# $ MISSING: cfgdefines=x` for a binding + * that is known to be uncovered (a "red" test case that should be + * green-flipped once the corresponding `cfg-ext-*` extension lands). + */ + +import python +import semmle.python.controlflow.internal.AstNodeImpl as CfgImpl +import utils.test.InlineExpectationsTest + +module CfgBindingsTest implements TestSig { + string getARelevantTag() { result = "cfgdefines" } + + predicate hasActualResult(Location location, string element, string tag, string value) { + exists(Name n, Variable v, CfgImpl::ControlFlowNode cfg | + n.defines(v) and + cfg.getAstNode().asExpr() = n and + location = n.getLocation() and + element = n.toString() and + tag = "cfgdefines" and + value = v.getId() + ) + } +} + +import MakeTest diff --git a/python/ql/test/library-tests/ControlFlow/bindings/annassign.py b/python/ql/test/library-tests/ControlFlow/bindings/annassign.py new file mode 100644 index 000000000000..7a9ae3ab6c79 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/bindings/annassign.py @@ -0,0 +1,13 @@ +# Annotated assignment (PEP 526). Both with and without an initializer. + +a: int = 1 # $ cfgdefines=a +b: str = "hi" # $ cfgdefines=b + +# Annotation without value: the AST records `c` as defined, +# and the new CFG now visits it via the AnnAssignStmt wrapper. +c: int # $ cfgdefines=c + +class K: # $ cfgdefines=K + field: int = 0 # $ cfgdefines=field + + diff --git a/python/ql/test/library-tests/ControlFlow/bindings/compound.py b/python/ql/test/library-tests/ControlFlow/bindings/compound.py new file mode 100644 index 000000000000..cb2f36f12ffe --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/bindings/compound.py @@ -0,0 +1,14 @@ +# Compound (tuple/list) assignment targets — actually wired in the new CFG. + +a, b = (1, 2) # $ cfgdefines=a cfgdefines=b +[c, d] = [3, 4] # $ cfgdefines=c cfgdefines=d + +# Nested unpacking. +(e, (f, g)) = (1, (2, 3)) # $ cfgdefines=e cfgdefines=f cfgdefines=g + +# Star unpacking. +h, *i = [1, 2, 3] # $ cfgdefines=h cfgdefines=i + +# Chained assignment with compound target. +j = k, l = (5, 6) # $ cfgdefines=j cfgdefines=k cfgdefines=l + diff --git a/python/ql/test/library-tests/ControlFlow/bindings/comprehension.py b/python/ql/test/library-tests/ControlFlow/bindings/comprehension.py new file mode 100644 index 000000000000..6b5f722c1f7e --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/bindings/comprehension.py @@ -0,0 +1,21 @@ +# Comprehension and `for` loop targets — wired in the new CFG. +# Comprehensions are nested function scopes with a synthetic `.0` parameter +# bound to the iterable. + +# Bare-name `for` target. +for i in range(3): # $ cfgdefines=i + pass + +# Compound `for` target. +for k, v in [(1, 2)]: # $ cfgdefines=k cfgdefines=v + pass + +# Comprehension targets. +_ = [x for x in range(3)] # $ cfgdefines=_ cfgdefines=x cfgdefines=.0 +_ = {y: z for y, z in []} # $ cfgdefines=_ cfgdefines=y cfgdefines=z cfgdefines=.0 +_ = (a for a in []) # $ cfgdefines=_ cfgdefines=a cfgdefines=.0 + +# Nested comprehensions. +_ = [b for c in [] for b in c] # $ cfgdefines=_ cfgdefines=c cfgdefines=b cfgdefines=.0 + + diff --git a/python/ql/test/library-tests/ControlFlow/bindings/dead_under_no_raise.py b/python/ql/test/library-tests/ControlFlow/bindings/dead_under_no_raise.py new file mode 100644 index 000000000000..9058f2b71165 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/bindings/dead_under_no_raise.py @@ -0,0 +1,53 @@ +# Reachability of code following a try whose body always returns. +# +# The new CFG models exception edges for raise-prone expressions when +# they appear inside a `try` (or `with`) statement, mirroring Java's +# `mayThrow`. This means the body of a `try` has both a normal +# completion edge and an exception edge to its handlers, so code +# following the try-statement is reachable via the except-handler path +# even when the try-body would otherwise always return. +# +# Code that is not reachable under either normal or exception flow +# (for example, the `else` clause of a try whose body unconditionally +# raises) remains correctly classified as dead. + + +def f(obj): # $ cfgdefines=f cfgdefines=obj + try: + return len(obj) + except TypeError: + pass + + # The try-body always returns, but `len(obj)` can raise (it is + # inside the try, so we model its exception edge). The + # `except TypeError: pass` handler falls through to here, making + # the code below reachable. + try: + hint = type(obj).__length_hint__ # $ cfgdefines=hint + except AttributeError: + return None + return hint + + +def g(): # $ cfgdefines=g + try: + raise Exception("inner") + except: + raise Exception("outer") + else: + # Unreachable: the inner try body always raises (via an explicit + # `raise`, which is modelled unconditionally), so the `else:` + # clause never runs. + hit_inner_else = True + + +def h(cache, key): # $ cfgdefines=h cfgdefines=cache cfgdefines=key + try: + return cache[key] + except KeyError: + pass + + # Same pattern as `f`: reachable via the except-handler fall-through. + value = compute(key) # $ cfgdefines=value + cache[key] = value + return value diff --git a/python/ql/test/library-tests/ControlFlow/bindings/decorated.py b/python/ql/test/library-tests/ControlFlow/bindings/decorated.py new file mode 100644 index 000000000000..9b93c166acec --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/bindings/decorated.py @@ -0,0 +1,30 @@ +# Decorated `def`/`class` — wired in the new CFG. + + +def deco(f): # $ cfgdefines=deco cfgdefines=f + return f + + +@deco +def decorated_func(): # $ cfgdefines=decorated_func + pass + + +@deco +class DecoratedClass: # $ cfgdefines=DecoratedClass + pass + + +# Stacked decorators. +@deco +@deco +def doubly(): # $ cfgdefines=doubly + pass + + +# Inside a class body. +class Outer: # $ cfgdefines=Outer + @staticmethod + def inner(): # $ cfgdefines=inner + pass + diff --git a/python/ql/test/library-tests/ControlFlow/bindings/except_handler.py b/python/ql/test/library-tests/ControlFlow/bindings/except_handler.py new file mode 100644 index 000000000000..57b6c99fe9b6 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/bindings/except_handler.py @@ -0,0 +1,19 @@ +# Exception-handler name bindings. These are already wired in the new +# CFG provided the try body can raise; `raise` statements are reliably +# treated as exception sources. + +try: + raise ValueError("oops") +except ValueError as e: # $ cfgdefines=e + pass + +try: + raise TypeError("oops") +except (TypeError, KeyError) as err: # $ cfgdefines=err + pass + +# Exception groups (Python 3.11+). +try: + raise ValueError("oops") +except* ValueError as eg: # $ cfgdefines=eg + pass diff --git a/python/ql/test/library-tests/ControlFlow/bindings/imports.py b/python/ql/test/library-tests/ControlFlow/bindings/imports.py new file mode 100644 index 000000000000..c8834b5332a0 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/bindings/imports.py @@ -0,0 +1,14 @@ +# Import aliases — all bound names below are now reachable via the new +# CFG's `ImportStmt` wrapper. + +import os # $ cfgdefines=os +import os.path # $ cfgdefines=os +import os as o # $ cfgdefines=o +from os import path # $ cfgdefines=path +from os import path as p # $ cfgdefines=p +from os import sep, linesep # $ cfgdefines=sep cfgdefines=linesep +from os import ( + getcwd, # $ cfgdefines=getcwd + getcwdb, # $ cfgdefines=getcwdb +) + diff --git a/python/ql/test/library-tests/ControlFlow/bindings/match_pattern.py b/python/ql/test/library-tests/ControlFlow/bindings/match_pattern.py new file mode 100644 index 000000000000..0868a2680d0a --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/bindings/match_pattern.py @@ -0,0 +1,24 @@ +# Match-statement pattern bindings — wired in the new CFG. + +def f(subject): # $ cfgdefines=f cfgdefines=subject + match subject: + case x: # $ cfgdefines=x + pass + case [a, b]: # $ cfgdefines=a cfgdefines=b + pass + case {"k": v}: # $ cfgdefines=v + pass + case Point(p, q): # $ cfgdefines=p cfgdefines=q + pass + case [_, *rest]: # $ cfgdefines=rest + pass + case (1 | 2) as n: # $ cfgdefines=n + pass + + +class Point: # $ cfgdefines=Point + __match_args__ = ("x", "y") # $ cfgdefines=__match_args__ + x: int # $ cfgdefines=x + y: int # $ cfgdefines=y + + diff --git a/python/ql/test/library-tests/ControlFlow/bindings/parameters.py b/python/ql/test/library-tests/ControlFlow/bindings/parameters.py new file mode 100644 index 000000000000..7fe5e01e4c4b --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/bindings/parameters.py @@ -0,0 +1,42 @@ +# Function parameters. + +def positional(a, b): # $ cfgdefines=positional cfgdefines=a cfgdefines=b + pass + + +def with_default(x=1, y=2): # $ cfgdefines=with_default cfgdefines=x cfgdefines=y + pass + + +def with_vararg(*args): # $ cfgdefines=with_vararg cfgdefines=args + pass + + +def with_kwarg(**kwargs): # $ cfgdefines=with_kwarg cfgdefines=kwargs + pass + + +def with_kwonly(*, k1, k2=5): # $ cfgdefines=with_kwonly cfgdefines=k1 cfgdefines=k2 + pass + + +def kitchen_sink(a, b=2, *args, k1, k2=5, **kw): # $ cfgdefines=kitchen_sink cfgdefines=a cfgdefines=b cfgdefines=args cfgdefines=k1 cfgdefines=k2 cfgdefines=kw + pass + + +# Methods get `self` / `cls`. +class C: # $ cfgdefines=C + def method(self, x): # $ cfgdefines=method cfgdefines=self cfgdefines=x + pass + + @classmethod + def cmethod(cls, x): # $ cfgdefines=cmethod cfgdefines=cls cfgdefines=x + pass + + +# Lambda parameter. +_ = lambda p: p + 1 # $ cfgdefines=_ cfgdefines=p + +# PEP 570 positional-only. +def pos_only(a, b, /, c): # $ cfgdefines=pos_only cfgdefines=a cfgdefines=b cfgdefines=c + pass diff --git a/python/ql/test/library-tests/ControlFlow/bindings/simple.py b/python/ql/test/library-tests/ControlFlow/bindings/simple.py new file mode 100644 index 000000000000..51cb7d828c91 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/bindings/simple.py @@ -0,0 +1,14 @@ +# Simple bindings that should already work in the new CFG. +# No MISSING annotations expected. + +x = 1 # $ cfgdefines=x +y = x + 1 # $ cfgdefines=y + +def f(): # $ cfgdefines=f + pass + +class C: # $ cfgdefines=C + pass + +# Re-assignment. +x = 2 # $ cfgdefines=x diff --git a/python/ql/test/library-tests/ControlFlow/bindings/type_params.py b/python/ql/test/library-tests/ControlFlow/bindings/type_params.py new file mode 100644 index 000000000000..2bd34dc3f0ee --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/bindings/type_params.py @@ -0,0 +1,21 @@ +# PEP 695 type parameters (Python 3.12+). + +# PEP 695 type-param names on `def`/`class` bind in an annotation scope +# that nests the function/class body — they have no CFG node in the +# enclosing scope (matching the legacy CFG). +def func[T](x: T) -> T: # $ cfgdefines=func cfgdefines=x + return x + + +class Box[T]: # $ cfgdefines=Box + item: T # $ cfgdefines=item + + +# Multi-parameter, with bound and variadics. +def multi[T: int, *Ts, **P](x: T, *args: *Ts, **kwargs: P.kwargs) -> T: # $ cfgdefines=multi cfgdefines=x cfgdefines=args cfgdefines=kwargs + return x + + +# `type` statement (PEP 695). +type Alias[T] = list[T] # $ cfgdefines=Alias cfgdefines=T + diff --git a/python/ql/test/library-tests/ControlFlow/bindings/walrus_starred.py b/python/ql/test/library-tests/ControlFlow/bindings/walrus_starred.py new file mode 100644 index 000000000000..5c0c1bd83191 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/bindings/walrus_starred.py @@ -0,0 +1,14 @@ +# Walrus and starred-target edge cases — wired in the new CFG. + +# Walrus in expression context. +if (y := 5) > 0: # $ cfgdefines=y + pass + +# Walrus in a comprehension. The comprehension introduces a synthetic +# `.0` parameter bound to the iterable. +_ = [w for _ in range(3) if (w := 1)] # $ cfgdefines=_ cfgdefines=w cfgdefines=.0 + +# Starred target in a Tuple LHS. +*head, tail = [1, 2, 3] # $ cfgdefines=head cfgdefines=tail + + diff --git a/python/ql/test/library-tests/ControlFlow/bindings/with_stmt.py b/python/ql/test/library-tests/ControlFlow/bindings/with_stmt.py new file mode 100644 index 000000000000..5fffe46c5d40 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/bindings/with_stmt.py @@ -0,0 +1,21 @@ +# `with cm() as x:` bindings — wired in the new CFG. + +class CM: # $ cfgdefines=CM + def __enter__(self): return self # $ cfgdefines=__enter__ cfgdefines=self + def __exit__(self, *a): pass # $ cfgdefines=__exit__ cfgdefines=self cfgdefines=a + +with CM() as x: # $ cfgdefines=x + pass + +# Multiple items. +with CM() as a, CM() as b: # $ cfgdefines=a cfgdefines=b + pass + +# Parenthesised form (Python 3.10+). +with (CM() as p, CM() as q): # $ cfgdefines=p cfgdefines=q + pass + +# Compound target in `with`. +with CM() as (m, n): # $ cfgdefines=m cfgdefines=n + pass + diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/AllLiveReachable.ql b/python/ql/test/library-tests/ControlFlow/evaluation-order/AllLiveReachable.ql index 886ccb4c3489..de44daa3e2c2 100644 --- a/python/ql/test/library-tests/ControlFlow/evaluation-order/AllLiveReachable.ql +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/AllLiveReachable.ql @@ -5,6 +5,8 @@ * have separate CFGs and are excluded from this check. */ +import python +import TimerUtils import OldCfgImpl private module Utils = EvalOrderCfgUtils; diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/AnnotationHasCfgNode.ql b/python/ql/test/library-tests/ControlFlow/evaluation-order/AnnotationHasCfgNode.ql index 04c01abf8a67..5311d118576b 100644 --- a/python/ql/test/library-tests/ControlFlow/evaluation-order/AnnotationHasCfgNode.ql +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/AnnotationHasCfgNode.ql @@ -2,6 +2,8 @@ * Checks that every timer annotation has a corresponding CFG node. */ +import python +import TimerUtils import OldCfgImpl private module Utils = EvalOrderCfgUtils; diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/BasicBlockAnnotationGap.ql b/python/ql/test/library-tests/ControlFlow/evaluation-order/BasicBlockAnnotationGap.ql index 691144e06e4f..0a2b08ff3fdd 100644 --- a/python/ql/test/library-tests/ControlFlow/evaluation-order/BasicBlockAnnotationGap.ql +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/BasicBlockAnnotationGap.ql @@ -8,6 +8,8 @@ * edge leaves the basic block and the normal successor may be dead. */ +import python +import TimerUtils import OldCfgImpl private module Utils = EvalOrderCfgUtils; diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/BasicBlockOrdering.expected b/python/ql/test/library-tests/ControlFlow/evaluation-order/BasicBlockOrdering.expected index 910fd3c8a80d..c5ef1ba93945 100644 --- a/python/ql/test/library-tests/ControlFlow/evaluation-order/BasicBlockOrdering.expected +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/BasicBlockOrdering.expected @@ -1,7 +1,7 @@ | test_boolean.py:9:10:9:43 | ControlFlowNode for BoolExpr | Basic block ordering: $@ appears before $@ | test_boolean.py:9:59:9:59 | IntegerLiteral | timestamp 2 | test_boolean.py:9:19:9:19 | IntegerLiteral | timestamp 0 | | test_boolean.py:15:10:15:43 | ControlFlowNode for BoolExpr | Basic block ordering: $@ appears before $@ | test_boolean.py:15:50:15:50 | IntegerLiteral | timestamp 1 | test_boolean.py:15:20:15:20 | IntegerLiteral | timestamp 0 | | test_boolean.py:21:10:21:42 | ControlFlowNode for BoolExpr | Basic block ordering: $@ appears before $@ | test_boolean.py:21:49:21:49 | IntegerLiteral | timestamp 1 | test_boolean.py:21:19:21:19 | IntegerLiteral | timestamp 0 | -| test_boolean.py:27:10:27:34 | ControlFlowNode for BoolExpr | Basic block ordering: $@ appears before $@ | test_boolean.py:27:50:27:50 | IntegerLiteral | timestamp 2 | test_boolean.py:27:20:27:20 | IntegerLiteral | timestamp 0 | +| test_boolean.py:27:10:27:43 | ControlFlowNode for BoolExpr | Basic block ordering: $@ appears before $@ | test_boolean.py:27:59:27:59 | IntegerLiteral | timestamp 2 | test_boolean.py:27:20:27:20 | IntegerLiteral | timestamp 0 | | test_boolean.py:40:10:40:61 | ControlFlowNode for BoolExpr | Basic block ordering: $@ appears before $@ | test_boolean.py:40:86:40:86 | IntegerLiteral | timestamp 3 | test_boolean.py:40:16:40:16 | IntegerLiteral | timestamp 0 | | test_boolean.py:46:10:46:61 | ControlFlowNode for BoolExpr | Basic block ordering: $@ appears before $@ | test_boolean.py:46:86:46:86 | IntegerLiteral | timestamp 3 | test_boolean.py:46:16:46:16 | IntegerLiteral | timestamp 0 | | test_boolean.py:52:10:52:95 | ControlFlowNode for BoolExpr | Basic block ordering: $@ appears before $@ | test_boolean.py:52:120:52:120 | IntegerLiteral | timestamp 4 | test_boolean.py:52:20:52:20 | IntegerLiteral | timestamp 0 | diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/BasicBlockOrdering.ql b/python/ql/test/library-tests/ControlFlow/evaluation-order/BasicBlockOrdering.ql index 6c08d44a5a59..30697f1403e2 100644 --- a/python/ql/test/library-tests/ControlFlow/evaluation-order/BasicBlockOrdering.ql +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/BasicBlockOrdering.ql @@ -3,6 +3,8 @@ * increasing minimum-timestamp order. */ +import python +import TimerUtils import OldCfgImpl private module Utils = EvalOrderCfgUtils; diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/ConsecutiveTimestamps.ql b/python/ql/test/library-tests/ControlFlow/evaluation-order/ConsecutiveTimestamps.ql index 01ff59b49bf6..709fd5665ea4 100644 --- a/python/ql/test/library-tests/ControlFlow/evaluation-order/ConsecutiveTimestamps.ql +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/ConsecutiveTimestamps.ql @@ -11,6 +11,8 @@ * lambdas that have annotations in nested scopes). */ +import python +import TimerUtils import OldCfgImpl private module Utils = EvalOrderCfgUtils; diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/ContiguousTimestamps.ql b/python/ql/test/library-tests/ControlFlow/evaluation-order/ContiguousTimestamps.ql index f18c52750b52..456ebf447dad 100644 --- a/python/ql/test/library-tests/ControlFlow/evaluation-order/ContiguousTimestamps.ql +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/ContiguousTimestamps.ql @@ -4,6 +4,7 @@ * in at least one annotation (live or dead). */ +import python import TimerUtils from TestFunction f, int missing, int maxTs, TimerAnnotation maxAnn diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NeverReachable.ql b/python/ql/test/library-tests/ControlFlow/evaluation-order/NeverReachable.ql index 9fbb9115814a..b09a936a0a40 100644 --- a/python/ql/test/library-tests/ControlFlow/evaluation-order/NeverReachable.ql +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/NeverReachable.ql @@ -4,6 +4,8 @@ * entry (including within the same basic block). */ +import python +import TimerUtils import OldCfgImpl private module Utils = EvalOrderCfgUtils; diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgAllLiveReachable.expected b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgAllLiveReachable.expected new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgAllLiveReachable.ql b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgAllLiveReachable.ql new file mode 100644 index 000000000000..75f02d14a9cb --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgAllLiveReachable.ql @@ -0,0 +1,14 @@ +/** New-CFG version of AllLiveReachable. */ + +import python +import TimerUtils +import NewCfgImpl + +private module Utils = EvalOrderCfgUtils; + +private import Utils +private import Utils::CfgTests + +from TimerCfgNode a, TestFunction f +where allLiveReachable(a, f) +select a, "Unreachable live annotation; entry of $@ does not reach this node", f, f.getName() diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgAnnotationHasCfgNode.expected b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgAnnotationHasCfgNode.expected new file mode 100644 index 000000000000..8b137891791f --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgAnnotationHasCfgNode.expected @@ -0,0 +1 @@ + diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgAnnotationHasCfgNode.ql b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgAnnotationHasCfgNode.ql new file mode 100644 index 000000000000..4b1d82e27e67 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgAnnotationHasCfgNode.ql @@ -0,0 +1,18 @@ +/** + * New-CFG version of AnnotationHasCfgNode. + * + * Checks that every timer annotation has a corresponding CFG node. + */ + +import python +import TimerUtils +import NewCfgImpl + +private module Utils = EvalOrderCfgUtils; + +private import Utils::CfgTests + +from TimerAnnotation ann +where annotationWithoutCfgNode(ann) +select ann, "Annotation in $@ has no CFG node", ann.getTestFunction(), + ann.getTestFunction().getName() diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgBasicBlockAnnotationGap.expected b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgBasicBlockAnnotationGap.expected new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgBasicBlockAnnotationGap.ql b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgBasicBlockAnnotationGap.ql new file mode 100644 index 000000000000..80dd759a3651 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgBasicBlockAnnotationGap.ql @@ -0,0 +1,26 @@ +/** + * New-CFG version of BasicBlockAnnotationGap. + * + * Original: + * Checks that within a basic block, if a node is annotated then its + * successor is also annotated (or excluded). A gap in annotations + * within a basic block indicates a missing annotation, since there + * are no branches to justify the gap. + * + * Nodes with exceptional successors are excluded, as the exception + * edge leaves the basic block and the normal successor may be dead. + */ + +import python +import TimerUtils +import NewCfgImpl + +private module Utils = EvalOrderCfgUtils; + +private import Utils +private import Utils::CfgTests + +from TimerCfgNode a, CfgNode succ +where basicBlockAnnotationGap(a, succ) +select a, "Annotated node followed by unannotated $@ in the same basic block", succ, + succ.getNode().toString() diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgBasicBlockOrdering.expected b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgBasicBlockOrdering.expected new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgBasicBlockOrdering.ql b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgBasicBlockOrdering.ql new file mode 100644 index 000000000000..f06d08d937e3 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgBasicBlockOrdering.ql @@ -0,0 +1,21 @@ +/** + * New-CFG version of BasicBlockOrdering. + * + * Original: + * Checks that within a single basic block, annotations appear in + * increasing minimum-timestamp order. + */ + +import python +import TimerUtils +import NewCfgImpl + +private module Utils = EvalOrderCfgUtils; + +private import Utils +private import Utils::CfgTests + +from TimerCfgNode a, TimerCfgNode b, int minA, int minB +where basicBlockOrdering(a, b, minA, minB) +select a, "Basic block ordering: $@ appears before $@", a.getTimestampExpr(minA), + "timestamp " + minA, b.getTimestampExpr(minB), "timestamp " + minB diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgBranchTimestamps.expected b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgBranchTimestamps.expected new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgBranchTimestamps.ql b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgBranchTimestamps.ql new file mode 100644 index 000000000000..cfd8ffb4e4bd --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgBranchTimestamps.ql @@ -0,0 +1,80 @@ +/** + * New-CFG version of BranchTimestamps. + * + * Checks that when a node has both a true and false successor, the + * live timestamps on one branch are marked as dead on the other. + * This ensures that boolean branches are fully annotated with dead() + * markers for the paths not taken. + * + * Limitation: the `@ t[ts, ...]` / `dead(ts)` annotation scheme can only + * model branch-dead-ness for plain boolean control flow that reconverges + * linearly after the split — i.e. `if`-with-else and `if`-expression. + * It cannot model: + * + * * loops (`while` / `for`): body timestamps repeat across iterations, + * so the loop-exit annotation can't list them as dead; + * * `match` statements: each `case` body is a syntactically distinct + * sub-tree, and the branches don't reconverge through a common + * annotation point in the timeline; + * * `try` / `with` and `raise` / `assert`: exception edges are modelled + * as true/false but flow to syntactically distinct handlers, with no + * reconvergence in the linear annotation order; + * * short-circuit `and` / `or` (`BoolExpr`): the branches reconverge at + * the BoolExpr's after-node, so timestamps on one branch are live + * downstream of the other rather than dead; + * * `if` without an `else` clause, and `if`/`elif` chains: the false + * branch reconverges with the true branch at the post-if statement + * (no-else) or fans out across multiple elif-test annotations, + * neither of which fit the binary annotation scheme. + * + * Branch nodes inside those constructs are therefore whitelisted out + * below. The check still fires (and is useful) for plain `if`/`else` + * and conditional-expression branching. + */ + +import python +import TimerUtils +import NewCfgImpl + +private module Utils = EvalOrderCfgUtils; + +private import Utils +private import Utils::CfgTests + +/** + * Holds if `f` contains a construct whose branches the linear-timestamp + * annotation scheme cannot describe (see file-level comment). + */ +private predicate hasUnmodellableBranching(Function f) { + exists(AstNode bad | + bad.getScope() = f and + ( + bad instanceof While + or + bad instanceof For + or + bad instanceof MatchStmt + or + bad instanceof Try + or + bad instanceof With + or + bad instanceof Raise + or + bad instanceof Assert + or + bad instanceof BoolExpr + or + bad instanceof If and + (not exists(bad.(If).getAnOrelse()) or bad.(If).isElif()) + ) + ) +} + +from TimerCfgNode node, int ts, string branch +where + missingBranchTimestamp(node, ts, branch) and + not hasUnmodellableBranching(node.getTestFunction()) +select node, + "Timestamp " + ts + " on true/false branch is missing a dead() annotation on the " + branch + + " successor in $@", node.getTestFunction(), node.getTestFunction().getName() diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgConsecutivePredecessorTimestamps.expected b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgConsecutivePredecessorTimestamps.expected new file mode 100644 index 000000000000..8b137891791f --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgConsecutivePredecessorTimestamps.expected @@ -0,0 +1 @@ + diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgConsecutivePredecessorTimestamps.ql b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgConsecutivePredecessorTimestamps.ql new file mode 100644 index 000000000000..3feacae264e5 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgConsecutivePredecessorTimestamps.ql @@ -0,0 +1,22 @@ +/** + * New-CFG version of ConsecutivePredecessorTimestamps. + * + * Checks that each annotated node (except the minimum timestamp) has + * a predecessor annotation with timestamp `a - 1`. This is the reverse + * of ConsecutiveTimestamps: it catches nodes that are reachable but + * arrived at from the wrong place (skipping an intermediate node). + */ + +import python +import TimerUtils +import NewCfgImpl + +private module Utils = EvalOrderCfgUtils; + +private import Utils +private import Utils::CfgTests + +from TimerAnnotation ann, int a +where consecutivePredecessorTimestamps(ann, a) +select ann, "$@ in $@ has no consecutive predecessor (expected " + (a - 1) + ")", + ann.getTimestampExpr(a), "Timestamp " + a, ann.getTestFunction(), ann.getTestFunction().getName() diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgConsecutiveTimestamps.expected b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgConsecutiveTimestamps.expected new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgConsecutiveTimestamps.ql b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgConsecutiveTimestamps.ql new file mode 100644 index 000000000000..8e52663d6eaf --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgConsecutiveTimestamps.ql @@ -0,0 +1,29 @@ +/** + * New-CFG version of ConsecutiveTimestamps. + * + * Original: + * Checks that consecutive annotated nodes have consecutive timestamps: + * for each annotation with timestamp `a`, some CFG node for that annotation + * must have a next annotation containing `a + 1`. + * + * Handles CFG splitting (e.g., finally blocks duplicated for normal/exceptional + * flow) by checking that at least one split has the required successor. + * + * Only applies to functions where all annotations are in the function's + * own scope (excludes tests with generators, async, comprehensions, or + * lambdas that have annotations in nested scopes). + */ + +import python +import TimerUtils +import NewCfgImpl + +private module Utils = EvalOrderCfgUtils; + +private import Utils +private import Utils::CfgTests + +from TimerAnnotation ann, int a +where consecutiveTimestamps(ann, a) +select ann, "$@ in $@ has no consecutive successor (expected " + (a + 1) + ")", + ann.getTimestampExpr(a), "Timestamp " + a, ann.getTestFunction(), ann.getTestFunction().getName() diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgImpl.qll b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgImpl.qll new file mode 100644 index 000000000000..1da80d2ee0dd --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgImpl.qll @@ -0,0 +1,101 @@ +/** + * Implementation of the evaluation-order CFG signature using the new + * shared control flow graph from AstNodeImpl. + */ + +private import python as Py +import TimerUtils +private import semmle.python.controlflow.internal.AstNodeImpl as CfgImpl +private import codeql.controlflow.SuccessorType + +private class NewControlFlowNode = CfgImpl::ControlFlowNode; + +private class NewBasicBlock = CfgImpl::BasicBlock; + +/** New (shared) CFG implementation of the evaluation-order signature. */ +module NewCfg implements EvalOrderCfgSig { + class CfgNode instanceof NewControlFlowNode { + // Use the post-order representative for each AST node: the "after" node. + // For simple leaf nodes this is the merged before/after node. For + // post-order expressions this is the TAstNode. For pre-order expressions + // (and/or/not/ternary) this uses an AfterValueNode, which places the + // expression after its operands — matching the timer test expectations. + CfgNode() { NewControlFlowNode.super.isAfter(_) } + + string toString() { result = NewControlFlowNode.super.toString() } + + Py::Location getLocation() { result = NewControlFlowNode.super.getLocation() } + + Py::AstNode getNode() { + result = CfgImpl::astNodeToPyNode(NewControlFlowNode.super.getAstNode()) + } + + CfgNode getASuccessor() { nextCfgNode(this, result) } + + CfgNode getATrueSuccessor() { + NewControlFlowNode.super.isAfterTrue(_) and + // Only where there's also a false branch (true boolean split) + exists(NewControlFlowNode other | other.isAfterFalse(NewControlFlowNode.super.getAstNode())) and + nextCfgNodeFrom(this, result) + } + + CfgNode getAFalseSuccessor() { + NewControlFlowNode.super.isAfterFalse(_) and + // Only where there's also a true branch (true boolean split) + exists(NewControlFlowNode other | other.isAfterTrue(NewControlFlowNode.super.getAstNode())) and + nextCfgNodeFrom(this, result) + } + + CfgNode getAnExceptionalSuccessor() { + exists(NewControlFlowNode mid | + mid = NewControlFlowNode.super.getAnExceptionSuccessor() and + nextCfgNodeFrom(mid, result) + ) + } + + Py::Scope getScope() { result = NewControlFlowNode.super.getEnclosingCallable().asScope() } + + BasicBlock getBasicBlock() { + exists(NewBasicBlock bb, int i | bb.getNode(i) = this and result = bb) + } + } + + /** + * Holds if `next` is the nearest CfgNode reachable from `n` via + * one or more raw CFG successor edges, skipping non-CfgNode intermediaries. + */ + private predicate nextCfgNodeFrom(NewControlFlowNode n, CfgNode next) { + next = n.getASuccessor() + or + exists(NewControlFlowNode mid | + mid = n.getASuccessor() and + not mid instanceof CfgNode and + nextCfgNodeFrom(mid, next) + ) + } + + /** + * Holds if `next` is the nearest CfgNode successor of `n`, + * skipping synthetic intermediate nodes. + */ + private predicate nextCfgNode(CfgNode n, CfgNode next) { nextCfgNodeFrom(n, next) } + + class BasicBlock instanceof NewBasicBlock { + string toString() { result = NewBasicBlock.super.toString() } + + CfgNode getNode(int n) { result = NewBasicBlock.super.getNode(n) } + + predicate reaches(BasicBlock bb) { this = bb or this.strictlyReaches(bb) } + + predicate strictlyReaches(BasicBlock bb) { NewBasicBlock.super.getASuccessor+() = bb } + + predicate strictlyDominates(BasicBlock bb) { NewBasicBlock.super.strictlyDominates(bb) } + } + + CfgNode scopeGetEntryNode(Py::Scope s) { + exists(CfgImpl::ControlFlow::EntryNode entry | + entry.getEnclosingCallable().asScope() = s and + nextCfgNodeFrom(entry, result) + ) + } +} diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNeverReachable.expected b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNeverReachable.expected new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNeverReachable.ql b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNeverReachable.ql new file mode 100644 index 000000000000..6949b2cc6e9b --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNeverReachable.ql @@ -0,0 +1,21 @@ +/** + * New-CFG version of NeverReachable. + * + * Original: + * Checks that expressions annotated with `t.never` either have no CFG + * node, or if they do, that the node is not reachable from its scope's + * entry (including within the same basic block). + */ + +import python +import TimerUtils +import NewCfgImpl + +private module Utils = EvalOrderCfgUtils; + +private import Utils::CfgTests + +from TimerAnnotation ann +where neverReachable(ann) +select ann, "Node annotated with t.never is reachable in $@", ann.getTestFunction(), + ann.getTestFunction().getName() diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNoBackwardFlow.expected b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNoBackwardFlow.expected new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNoBackwardFlow.ql b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNoBackwardFlow.ql new file mode 100644 index 000000000000..442ca5f5456c --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNoBackwardFlow.ql @@ -0,0 +1,22 @@ +/** + * New-CFG version of NoBackwardFlow. + * + * Original: + * Checks that time never flows backward between consecutive timer annotations + * in the CFG. For each pair of consecutive annotated nodes (A -> B), there must + * exist timestamps a in A and b in B with a < b. + */ + +import python +import TimerUtils +import NewCfgImpl + +private module Utils = EvalOrderCfgUtils; + +private import Utils +private import Utils::CfgTests + +from TimerCfgNode a, TimerCfgNode b, int minA, int maxB +where noBackwardFlow(a, b, minA, maxB) +select a, "Backward flow: $@ flows to $@ (max timestamp $@)", a.getTimestampExpr(minA), + minA.toString(), b, b.getNode().toString(), b.getTimestampExpr(maxB), maxB.toString() diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNoBasicBlock.expected b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNoBasicBlock.expected new file mode 100644 index 000000000000..8b137891791f --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNoBasicBlock.expected @@ -0,0 +1 @@ + diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNoBasicBlock.ql b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNoBasicBlock.ql new file mode 100644 index 000000000000..e07890f72502 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNoBasicBlock.ql @@ -0,0 +1,18 @@ +/** + * New-CFG version of NoBasicBlock. + * + * Checks that every annotated CFG node belongs to a basic block. + */ + +import python +import TimerUtils +import NewCfgImpl + +private module Utils = EvalOrderCfgUtils; + +private import Utils +private import Utils::CfgTests + +from CfgNode n, TestFunction f +where noBasicBlock(n, f) +select n, "CFG node in $@ does not belong to any basic block", f, f.getName() diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNoSharedReachable.expected b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNoSharedReachable.expected new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNoSharedReachable.ql b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNoSharedReachable.ql new file mode 100644 index 000000000000..5a1a1aba2a7a --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNoSharedReachable.ql @@ -0,0 +1,21 @@ +/** + * New-CFG version of NoSharedReachable. + * + * Original: + * Checks that two annotations sharing a timestamp value are on + * mutually exclusive CFG paths (neither can reach the other). + */ + +import python +import TimerUtils +import NewCfgImpl + +private module Utils = EvalOrderCfgUtils; + +private import Utils +private import Utils::CfgTests + +from TimerCfgNode a, TimerCfgNode b, int ts +where noSharedReachable(a, b, ts) +select a, "Shared timestamp $@ but this node reaches $@", a.getTimestampExpr(ts), ts.toString(), b, + b.getNode().toString() diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgStrictForward.expected b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgStrictForward.expected new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgStrictForward.ql b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgStrictForward.ql new file mode 100644 index 000000000000..ebbc60346db0 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgStrictForward.ql @@ -0,0 +1,22 @@ +/** + * New-CFG version of StrictForward. + * + * Original: + * Stronger version of NoBackwardFlow: for consecutive annotated nodes + * A -> B that both have a single timestamp (non-loop code) and B does + * NOT dominate A (forward edge), requires max(A) < min(B). + */ + +import python +import TimerUtils +import NewCfgImpl + +private module Utils = EvalOrderCfgUtils; + +private import Utils +private import Utils::CfgTests + +from TimerCfgNode a, TimerCfgNode b, int maxA, int minB +where strictForward(a, b, maxA, minB) +select a, "Strict forward violation: $@ flows to $@", a.getTimestampExpr(maxA), "timestamp " + maxA, + b.getTimestampExpr(minB), "timestamp " + minB diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NoBackwardFlow.expected b/python/ql/test/library-tests/ControlFlow/evaluation-order/NoBackwardFlow.expected index 6e8ea12c9dd4..775cc7bdbbfd 100644 --- a/python/ql/test/library-tests/ControlFlow/evaluation-order/NoBackwardFlow.expected +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/NoBackwardFlow.expected @@ -1,7 +1,7 @@ | test_boolean.py:9:10:9:43 | ControlFlowNode for BoolExpr | Backward flow: $@ flows to $@ (max timestamp $@) | test_boolean.py:9:59:9:59 | IntegerLiteral | 2 | test_boolean.py:9:10:9:13 | ControlFlowNode for True | True | test_boolean.py:9:19:9:19 | IntegerLiteral | 0 | | test_boolean.py:15:10:15:43 | ControlFlowNode for BoolExpr | Backward flow: $@ flows to $@ (max timestamp $@) | test_boolean.py:15:50:15:50 | IntegerLiteral | 1 | test_boolean.py:15:10:15:14 | ControlFlowNode for False | False | test_boolean.py:15:20:15:20 | IntegerLiteral | 0 | | test_boolean.py:21:10:21:42 | ControlFlowNode for BoolExpr | Backward flow: $@ flows to $@ (max timestamp $@) | test_boolean.py:21:49:21:49 | IntegerLiteral | 1 | test_boolean.py:21:10:21:13 | ControlFlowNode for True | True | test_boolean.py:21:19:21:19 | IntegerLiteral | 0 | -| test_boolean.py:27:10:27:34 | ControlFlowNode for BoolExpr | Backward flow: $@ flows to $@ (max timestamp $@) | test_boolean.py:27:50:27:50 | IntegerLiteral | 2 | test_boolean.py:27:10:27:14 | ControlFlowNode for False | False | test_boolean.py:27:20:27:20 | IntegerLiteral | 0 | +| test_boolean.py:27:10:27:43 | ControlFlowNode for BoolExpr | Backward flow: $@ flows to $@ (max timestamp $@) | test_boolean.py:27:59:27:59 | IntegerLiteral | 2 | test_boolean.py:27:10:27:14 | ControlFlowNode for False | False | test_boolean.py:27:20:27:20 | IntegerLiteral | 0 | | test_boolean.py:40:10:40:61 | ControlFlowNode for BoolExpr | Backward flow: $@ flows to $@ (max timestamp $@) | test_boolean.py:40:86:40:86 | IntegerLiteral | 3 | test_boolean.py:40:10:40:10 | ControlFlowNode for IntegerLiteral | IntegerLiteral | test_boolean.py:40:16:40:16 | IntegerLiteral | 0 | | test_boolean.py:46:10:46:61 | ControlFlowNode for BoolExpr | Backward flow: $@ flows to $@ (max timestamp $@) | test_boolean.py:46:86:46:86 | IntegerLiteral | 3 | test_boolean.py:46:10:46:10 | ControlFlowNode for IntegerLiteral | IntegerLiteral | test_boolean.py:46:16:46:16 | IntegerLiteral | 0 | | test_boolean.py:52:10:52:95 | ControlFlowNode for BoolExpr | Backward flow: $@ flows to $@ (max timestamp $@) | test_boolean.py:52:120:52:120 | IntegerLiteral | 4 | test_boolean.py:52:11:52:47 | ControlFlowNode for BoolExpr | BoolExpr | test_boolean.py:52:63:52:63 | IntegerLiteral | 2 | diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NoBackwardFlow.ql b/python/ql/test/library-tests/ControlFlow/evaluation-order/NoBackwardFlow.ql index e9926284295f..4acf45db3cda 100644 --- a/python/ql/test/library-tests/ControlFlow/evaluation-order/NoBackwardFlow.ql +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/NoBackwardFlow.ql @@ -4,6 +4,8 @@ * exist timestamps a in A and b in B with a < b. */ +import python +import TimerUtils import OldCfgImpl private module Utils = EvalOrderCfgUtils; diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NoBasicBlock.ql b/python/ql/test/library-tests/ControlFlow/evaluation-order/NoBasicBlock.ql index 82d9589a9750..5568bd2a9a4a 100644 --- a/python/ql/test/library-tests/ControlFlow/evaluation-order/NoBasicBlock.ql +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/NoBasicBlock.ql @@ -2,6 +2,8 @@ * Checks that every annotated CFG node belongs to a basic block. */ +import python +import TimerUtils import OldCfgImpl private module Utils = EvalOrderCfgUtils; diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NoSharedReachable.ql b/python/ql/test/library-tests/ControlFlow/evaluation-order/NoSharedReachable.ql index e9f685e8ffae..1fcceb2aca98 100644 --- a/python/ql/test/library-tests/ControlFlow/evaluation-order/NoSharedReachable.ql +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/NoSharedReachable.ql @@ -3,6 +3,8 @@ * mutually exclusive CFG paths (neither can reach the other). */ +import python +import TimerUtils import OldCfgImpl private module Utils = EvalOrderCfgUtils; diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/OldCfgImpl.qll b/python/ql/test/library-tests/ControlFlow/evaluation-order/OldCfgImpl.qll index cb7bbb495b87..fc52c8dd3ed1 100644 --- a/python/ql/test/library-tests/ControlFlow/evaluation-order/OldCfgImpl.qll +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/OldCfgImpl.qll @@ -3,14 +3,14 @@ * Python control flow graph. */ -private import python as PY +private import python as Py import TimerUtils /** Existing Python CFG implementation of the evaluation-order signature. */ module OldCfg implements EvalOrderCfgSig { - class CfgNode = PY::ControlFlowNode; + class CfgNode = Py::ControlFlowNode; - class BasicBlock = PY::BasicBlock; + class BasicBlock = Py::BasicBlock; - CfgNode scopeGetEntryNode(PY::Scope s) { result = s.getEntryNode() } + CfgNode scopeGetEntryNode(Py::Scope s) { result = s.getEntryNode() } } diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/StrictForward.expected b/python/ql/test/library-tests/ControlFlow/evaluation-order/StrictForward.expected index 6562ff9f7b2f..34e050b0f8aa 100644 --- a/python/ql/test/library-tests/ControlFlow/evaluation-order/StrictForward.expected +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/StrictForward.expected @@ -1,7 +1,7 @@ | test_boolean.py:9:10:9:43 | ControlFlowNode for BoolExpr | Strict forward violation: $@ flows to $@ | test_boolean.py:9:59:9:59 | IntegerLiteral | timestamp 2 | test_boolean.py:9:19:9:19 | IntegerLiteral | timestamp 0 | | test_boolean.py:15:10:15:43 | ControlFlowNode for BoolExpr | Strict forward violation: $@ flows to $@ | test_boolean.py:15:50:15:50 | IntegerLiteral | timestamp 1 | test_boolean.py:15:20:15:20 | IntegerLiteral | timestamp 0 | | test_boolean.py:21:10:21:42 | ControlFlowNode for BoolExpr | Strict forward violation: $@ flows to $@ | test_boolean.py:21:49:21:49 | IntegerLiteral | timestamp 1 | test_boolean.py:21:19:21:19 | IntegerLiteral | timestamp 0 | -| test_boolean.py:27:10:27:34 | ControlFlowNode for BoolExpr | Strict forward violation: $@ flows to $@ | test_boolean.py:27:50:27:50 | IntegerLiteral | timestamp 2 | test_boolean.py:27:20:27:20 | IntegerLiteral | timestamp 0 | +| test_boolean.py:27:10:27:43 | ControlFlowNode for BoolExpr | Strict forward violation: $@ flows to $@ | test_boolean.py:27:59:27:59 | IntegerLiteral | timestamp 2 | test_boolean.py:27:20:27:20 | IntegerLiteral | timestamp 0 | | test_boolean.py:40:10:40:61 | ControlFlowNode for BoolExpr | Strict forward violation: $@ flows to $@ | test_boolean.py:40:86:40:86 | IntegerLiteral | timestamp 3 | test_boolean.py:40:16:40:16 | IntegerLiteral | timestamp 0 | | test_boolean.py:46:10:46:61 | ControlFlowNode for BoolExpr | Strict forward violation: $@ flows to $@ | test_boolean.py:46:86:46:86 | IntegerLiteral | timestamp 3 | test_boolean.py:46:16:46:16 | IntegerLiteral | timestamp 0 | | test_boolean.py:52:10:52:95 | ControlFlowNode for BoolExpr | Strict forward violation: $@ flows to $@ | test_boolean.py:52:120:52:120 | IntegerLiteral | timestamp 4 | test_boolean.py:52:63:52:63 | IntegerLiteral | timestamp 2 | diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/StrictForward.ql b/python/ql/test/library-tests/ControlFlow/evaluation-order/StrictForward.ql index 79b383a4acfa..9e64770bab4d 100644 --- a/python/ql/test/library-tests/ControlFlow/evaluation-order/StrictForward.ql +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/StrictForward.ql @@ -4,6 +4,8 @@ * NOT dominate A (forward edge), requires max(A) < min(B). */ +import python +import TimerUtils import OldCfgImpl private module Utils = EvalOrderCfgUtils; diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/test_boolean.py b/python/ql/test/library-tests/ControlFlow/evaluation-order/test_boolean.py index a12975634f49..a3b2268a8315 100644 --- a/python/ql/test/library-tests/ControlFlow/evaluation-order/test_boolean.py +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/test_boolean.py @@ -24,7 +24,7 @@ def test_or_short_circuit(t): @test def test_or_both_sides(t): # False or X — both operands evaluated, result is X - x = (False @ t[0] or 42 @ t[1]) @ t[dead(1), 2] + x = (False @ t[0] or 42 @ t[1, dead(2)]) @ t[dead(1), 2] @test diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/test_if.py b/python/ql/test/library-tests/ControlFlow/evaluation-order/test_if.py index 8880aaaef348..a6eb6c7d5cac 100644 --- a/python/ql/test/library-tests/ControlFlow/evaluation-order/test_if.py +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/test_if.py @@ -85,7 +85,7 @@ def test_nested_if_else(t): else: z = 2 @ t[dead(4)] else: - z = 3 @ t[dead(4)] + z = 3 @ t[dead(3), dead(4)] w = 0 @ t[5] diff --git a/python/ql/test/library-tests/ControlFlow/store-load/StoreLoadTest.expected b/python/ql/test/library-tests/ControlFlow/store-load/StoreLoadTest.expected new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/ql/test/library-tests/ControlFlow/store-load/StoreLoadTest.ql b/python/ql/test/library-tests/ControlFlow/store-load/StoreLoadTest.ql new file mode 100644 index 000000000000..4ab2ef5be8fb --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/store-load/StoreLoadTest.ql @@ -0,0 +1,41 @@ +/** + * Inline-expectations test for the store/load/delete/parameter + * classification predicates on the new-CFG facade. + * + * Each tag fires when the corresponding predicate (`isLoad`, + * `isStore`, `isDelete`, `isParameter`, `isAugLoad`, `isAugStore`) + * holds on the canonical CFG node wrapping a `Py::Name` with the + * given identifier. Subscript and attribute stores are not covered + * by these tags — only the `Name`-typed targets/loads they involve. + */ + +import python +import semmle.python.controlflow.internal.Cfg as Cfg +import utils.test.InlineExpectationsTest + +module StoreLoadTest implements TestSig { + string getARelevantTag() { result = ["load", "store", "delete", "param", "augload", "augstore"] } + + predicate hasActualResult(Location location, string element, string tag, string value) { + exists(Cfg::NameNode n | + location = n.getLocation() and + element = n.toString() and + value = n.getId() and + ( + n.isLoad() and not n.isAugLoad() and tag = "load" + or + n.isStore() and not n.isAugStore() and tag = "store" + or + n.isDelete() and tag = "delete" + or + n.isParameter() and tag = "param" + or + n.isAugLoad() and tag = "augload" + or + n.isAugStore() and tag = "augstore" + ) + ) + } +} + +import MakeTest diff --git a/python/ql/test/library-tests/ControlFlow/store-load/test.py b/python/ql/test/library-tests/ControlFlow/store-load/test.py new file mode 100644 index 000000000000..dfca45a0b47b --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/store-load/test.py @@ -0,0 +1,56 @@ +# Store/load/delete/parameter classification on the new-CFG facade. +# +# Each annotated location carries the (sorted, deduplicated) set of +# kinds the CFG facade reports there. Comparing against the legacy +# 'semmle.python.Flow' classification is done by the comparison query +# 'StoreLoadParity.ql' — annotations here are only the positive +# assertions for the new facade. +# +# Tags: +# load= -- isLoad() fires on the Name +# store= -- isStore() fires +# delete= -- isDelete() fires +# param= -- isParameter() fires +# augload= -- isAugLoad() fires (the LHS of x += ... when read) +# augstore= -- isAugStore() fires (the LHS of x += ... when written) + + +# --- plain load / store / delete --- + +x = 1 # $ store=x +y = x + 1 # $ store=y load=x +print(y) # $ load=print load=y +del x # $ delete=x + + +# --- function definitions (parameters) --- + +def f(a, b=2, *args, c, **kwargs): # $ store=f param=a param=b param=args param=c param=kwargs + return a + b + c # $ load=a load=b load=c + + +# --- augmented assignment splits one Name into load + store halves --- + +def aug(): # $ store=aug + n = 0 # $ store=n + n += 1 # $ augload=n augstore=n + return n # $ load=n + + +# --- subscript / attribute stores --- + +class C: # $ store=C + pass + + +def stores(obj, container, idx): # $ store=stores param=obj param=container param=idx + obj.attr = 1 # $ load=obj + container[idx] = 2 # $ load=container load=idx + return obj # $ load=obj + + +# --- tuple unpacking --- + +def unpack(pair): # $ store=unpack param=pair + a, b = pair # $ store=a store=b load=pair + return a + b # $ load=a load=b diff --git a/python/ql/test/library-tests/PointsTo/new/ImpliesDataflow.expected b/python/ql/test/library-tests/PointsTo/new/ImpliesDataflow.expected index 96663031d9a0..e6fc40a7151d 100644 --- a/python/ql/test/library-tests/PointsTo/new/ImpliesDataflow.expected +++ b/python/ql/test/library-tests/PointsTo/new/ImpliesDataflow.expected @@ -1,7 +1,7 @@ -| code/h_classes.py:3:1:3:16 | ControlFlowNode for ClassExpr | code/h_classes.py:10:1:10:9 | ControlFlowNode for type() | -| code/h_classes.py:3:1:3:16 | ControlFlowNode for ClassExpr | code/h_classes.py:15:5:15:13 | ControlFlowNode for type() | -| code/l_calls.py:12:1:12:20 | ControlFlowNode for ClassExpr | code/l_calls.py:16:16:16:18 | ControlFlowNode for cls | -| code/l_calls.py:12:1:12:20 | ControlFlowNode for ClassExpr | code/l_calls.py:24:13:24:22 | ControlFlowNode for Attribute() | -| code/l_calls.py:12:1:12:20 | ControlFlowNode for ClassExpr | code/l_calls.py:25:16:25:16 | ControlFlowNode for a | -| code/t_type.py:3:1:3:16 | ControlFlowNode for ClassExpr | code/t_type.py:6:1:6:9 | ControlFlowNode for type() | -| code/t_type.py:3:1:3:16 | ControlFlowNode for ClassExpr | code/t_type.py:13:5:13:13 | ControlFlowNode for type() | +| code/h_classes.py:3:1:3:16 | After ClassExpr | code/h_classes.py:10:1:10:9 | After type() | +| code/h_classes.py:3:1:3:16 | After ClassExpr | code/h_classes.py:15:5:15:13 | After type() | +| code/l_calls.py:12:1:12:20 | After ClassExpr | code/l_calls.py:16:16:16:18 | cls | +| code/l_calls.py:12:1:12:20 | After ClassExpr | code/l_calls.py:24:13:24:22 | After Attribute() | +| code/l_calls.py:12:1:12:20 | After ClassExpr | code/l_calls.py:25:16:25:16 | a | +| code/t_type.py:3:1:3:16 | After ClassExpr | code/t_type.py:6:1:6:9 | After type() | +| code/t_type.py:3:1:3:16 | After ClassExpr | code/t_type.py:13:5:13:13 | After type() | diff --git a/python/ql/test/library-tests/PointsTo/new/ImpliesDataflow.ql b/python/ql/test/library-tests/PointsTo/new/ImpliesDataflow.ql index da4b46595e67..ebe0071a5801 100644 --- a/python/ql/test/library-tests/PointsTo/new/ImpliesDataflow.ql +++ b/python/ql/test/library-tests/PointsTo/new/ImpliesDataflow.ql @@ -8,7 +8,11 @@ private import LegacyPointsTo import semmle.python.dataflow.new.DataFlow predicate pointsToOrigin(DataFlow::CfgNode pointer, DataFlow::CfgNode origin) { - origin.getNode() = pointer.getNode().(ControlFlowNodeWithPointsTo).pointsTo().getOrigin() + exists(ControlFlowNodeWithPointsTo legacyPointer, ControlFlowNode legacyOrigin | + legacyPointer.getNode() = pointer.getNode().getNode() and + legacyOrigin = legacyPointer.pointsTo().getOrigin() and + legacyOrigin.getNode() = origin.getNode().getNode() + ) } module PointsToConfig implements DataFlow::ConfigSig { diff --git a/python/ql/test/library-tests/dataflow-new-ssa-vs-legacy/CmpTest.expected b/python/ql/test/library-tests/dataflow-new-ssa-vs-legacy/CmpTest.expected new file mode 100644 index 000000000000..6872cf59e041 --- /dev/null +++ b/python/ql/test/library-tests/dataflow-new-ssa-vs-legacy/CmpTest.expected @@ -0,0 +1,5 @@ +| def-only-old | $:0:0 | +| def-only-old | __name__:0:0 | +| def-only-old | __package__:0:0 | +| def-only-old | e:37:1 | +| def-only-old | x:20:1 | diff --git a/python/ql/test/library-tests/dataflow-new-ssa-vs-legacy/CmpTest.ql b/python/ql/test/library-tests/dataflow-new-ssa-vs-legacy/CmpTest.ql new file mode 100644 index 000000000000..590f5ebed47a --- /dev/null +++ b/python/ql/test/library-tests/dataflow-new-ssa-vs-legacy/CmpTest.ql @@ -0,0 +1,59 @@ +/** + * Compares the new-CFG SSA against the legacy ESSA on the same Python + * sources. Reports definitions present in one implementation but not + * the other, identified by variable name + source position. + * + * The `.expected` file records the current diff as a snapshot: as the + * new SSA matures (closing captured-variable gap, exception bindings, + * etc.) and tracks more variables, the snapshot should monotonically + * shrink. + * + * Known categories of `def-only-old` mismatches: + * - Function / class / global definitions with no in-scope read + * (intentional: SSA is liveness-pruned, write-only variables are + * not tracked). + * - Captured / closure variables (gap: new SSA does not yet model + * closure captures). + * - Module variables `__name__`, `__package__`, `$` (legacy ESSA + * adds implicit bindings the new SSA does not). + * - Exception-handler `as` bindings (depend on raise modelling). + * + * `def-only-new` mismatches would indicate the new SSA produces spurious + * definitions; currently none are expected. + */ + +import python +import semmle.python.dataflow.new.internal.SsaImpl as NewSsa +import semmle.python.controlflow.internal.Cfg as Cfg +import semmle.python.essa.Essa + +string newDefSig(NewSsa::EssaNodeDefinition def) { + exists(Cfg::ControlFlowNode n | n = def.getDefiningNode() | + result = + def.getVariable().getVariable().getId() + ":" + n.getLocation().getStartLine() + ":" + + n.getLocation().getStartColumn() + ) +} + +string legacyDefSig(EssaNodeDefinition def) { + exists(ControlFlowNode n | n = def.getDefiningNode() | + result = + def.getSourceVariable().getName() + ":" + n.getLocation().getStartLine() + ":" + + n.getLocation().getStartColumn() + ) +} + +from string kind, string sig +where + kind = "def-only-new" and + exists(NewSsa::EssaNodeDefinition def | + sig = newDefSig(def) and + not exists(EssaNodeDefinition legacyDef | sig = legacyDefSig(legacyDef)) + ) + or + kind = "def-only-old" and + exists(EssaNodeDefinition legacyDef | + sig = legacyDefSig(legacyDef) and + not exists(NewSsa::EssaNodeDefinition def | sig = newDefSig(def)) + ) +select kind, sig diff --git a/python/ql/test/library-tests/dataflow-new-ssa-vs-legacy/test.py b/python/ql/test/library-tests/dataflow-new-ssa-vs-legacy/test.py new file mode 100644 index 000000000000..8b061109bf2c --- /dev/null +++ b/python/ql/test/library-tests/dataflow-new-ssa-vs-legacy/test.py @@ -0,0 +1,53 @@ +def simple_assign(): + x = 1 + return x + + +def reassignment(): + x = 1 + x = 2 + return x + + +def if_else_branch(cond): + if cond: + x = 1 + else: + x = 2 + return x + + +def loop(xs): + total = 0 + for x in xs: + total = total + x + return total + + +def parameter(a, b=2, *args, **kwargs): + return a + b + sum(args) + + +def closure(x): + def inner(): + return x + return inner + + +def exception_binding(): + try: + compute() + except Exception as e: + return e + + +def with_binding(): + with open("file") as f: + return f.read() + + +GLOBAL = 1 + + +def read_global(): + return GLOBAL diff --git a/python/ql/test/library-tests/dataflow-new-ssa/SsaTest.expected b/python/ql/test/library-tests/dataflow-new-ssa/SsaTest.expected new file mode 100644 index 000000000000..d87d63fc11f1 --- /dev/null +++ b/python/ql/test/library-tests/dataflow-new-ssa/SsaTest.expected @@ -0,0 +1,6 @@ +| test.py:14:5:14:15 | basic_param | Unexpected result: def=basic_param | +| test.py:18:5:18:16 | basic_assign | Unexpected result: def=basic_assign | +| test.py:23:5:23:16 | reassignment | Unexpected result: def=reassignment | +| test.py:29:5:29:15 | if_else_phi | Unexpected result: def=if_else_phi | +| test.py:37:5:37:14 | use_global | Unexpected result: def=use_global | +| test.py:38:28:38:49 | Comment # $ use=some_undefined | Missing result: use=some_undefined | diff --git a/python/ql/test/library-tests/dataflow-new-ssa/SsaTest.ql b/python/ql/test/library-tests/dataflow-new-ssa/SsaTest.ql new file mode 100644 index 000000000000..0bebf4a637d0 --- /dev/null +++ b/python/ql/test/library-tests/dataflow-new-ssa/SsaTest.ql @@ -0,0 +1,59 @@ +/** + * Inline-expectations test for the new-CFG SSA adapter + * (`semmle.python.dataflow.new.internal.SsaImpl`). + * + * Tags: + * - `def=`: there is an SSA write definition of `` at this + * line (parameter init, plain assignment, augmented assignment, + * exception-handler binding, deletion, etc.). + * - `use=`: `` is used at this line, and some SSA definition + * of `` reaches the read. + * - `phi=`: there is an SSA phi definition of `` whose BB + * starts on this line. + */ + +import python +import semmle.python.dataflow.new.internal.SsaImpl as SsaImpl +import semmle.python.controlflow.internal.AstNodeImpl as CfgImpl +import semmle.python.controlflow.internal.Cfg as Cfg +import utils.test.InlineExpectationsTest + +module SsaTest implements TestSig { + string getARelevantTag() { result = ["def", "use", "phi"] } + + predicate hasActualResult(Location location, string element, string tag, string value) { + // A `def=` fires when an SSA WriteDefinition is at a CFG node + // on the given line. + exists(SsaImpl::Ssa::WriteDefinition def, CfgImpl::BasicBlock bb, int i, Cfg::NameNode n | + def.definesAt(_, bb, i) and + bb.getNode(i) = n and + tag = "def" and + location = n.getLocation() and + element = n.toString() and + value = n.getId() + ) + or + // A `use=` fires when an SSA Definition reaches a read at this + // CFG node. + exists(SsaImpl::Ssa::Definition def, CfgImpl::BasicBlock bb, int i, Cfg::NameNode n | + SsaImpl::Ssa::ssaDefReachesRead(_, def, bb, i) and + bb.getNode(i) = n and + tag = "use" and + location = n.getLocation() and + element = n.toString() and + value = n.getId() + ) + or + // A `phi=` fires when there is a phi node whose BB's first + // CFG node is on the given line. + exists(SsaImpl::Ssa::PhiNode phi, CfgImpl::BasicBlock bb | + phi.definesAt(_, bb, _) and + tag = "phi" and + location = bb.getNode(0).getLocation() and + element = bb.toString() and + value = phi.getSourceVariable().(SsaImpl::SsaSourceVariable).getVariable().getId() + ) + } +} + +import MakeTest diff --git a/python/ql/test/library-tests/dataflow-new-ssa/test.py b/python/ql/test/library-tests/dataflow-new-ssa/test.py new file mode 100644 index 000000000000..c6cdc22c3b36 --- /dev/null +++ b/python/ql/test/library-tests/dataflow-new-ssa/test.py @@ -0,0 +1,40 @@ +# Basic SSA tests for the new-CFG SSA adapter. +# +# The shared SSA implementation prunes its construction by liveness: +# definitions of variables that are not read are never materialised. +# This is by design — write-only variables would only bloat the SSA +# graph. Tests therefore must always include a read of each variable +# being verified. +# +# Annotations: +# def=: there is an SSA write definition of at this line +# use=: is used here and the read resolves to some def + + +def basic_param(x): # $ def=x + return x # $ use=x + + +def basic_assign(): + y = 1 # $ def=y + return y # $ use=y + + +def reassignment(): + x = 1 + x = 2 # $ def=x + return x # $ use=x + + +def if_else_phi(cond): # $ def=cond + if cond: # $ use=cond phi=x + x = 1 # $ def=x + else: + x = 2 # $ def=x + return x # $ use=x + + +def use_global(): + return some_undefined # $ use=some_undefined + + diff --git a/python/ql/test/library-tests/dataflow/basic/callGraph.expected b/python/ql/test/library-tests/dataflow/basic/callGraph.expected index 222e11cb54f6..969a9c76056f 100644 --- a/python/ql/test/library-tests/dataflow/basic/callGraph.expected +++ b/python/ql/test/library-tests/dataflow/basic/callGraph.expected @@ -1,3 +1,3 @@ -| test.py:4:10:4:10 | ControlFlowNode for z | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | -| test.py:7:19:7:19 | ControlFlowNode for a | test.py:1:19:1:19 | ControlFlowNode for x | -| test.py:7:19:7:19 | ControlFlowNode for a | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | +| test.py:4:10:4:10 | z | test.py:7:5:7:20 | obfuscated_id() | +| test.py:7:19:7:19 | a | test.py:1:19:1:19 | x | +| test.py:7:19:7:19 | a | test.py:7:5:7:20 | obfuscated_id() | diff --git a/python/ql/test/library-tests/dataflow/basic/callGraphSinks.expected b/python/ql/test/library-tests/dataflow/basic/callGraphSinks.expected index e4b8f905530b..3cfc6a6d7355 100644 --- a/python/ql/test/library-tests/dataflow/basic/callGraphSinks.expected +++ b/python/ql/test/library-tests/dataflow/basic/callGraphSinks.expected @@ -1,3 +1,3 @@ | test.py:1:1:1:21 | SynthDictSplatParameterNode | -| test.py:1:19:1:19 | ControlFlowNode for x | -| test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | +| test.py:1:19:1:19 | x | +| test.py:7:5:7:20 | obfuscated_id() | diff --git a/python/ql/test/library-tests/dataflow/basic/callGraphSources.expected b/python/ql/test/library-tests/dataflow/basic/callGraphSources.expected index 4023ba8f3ea1..a8fea599f65c 100644 --- a/python/ql/test/library-tests/dataflow/basic/callGraphSources.expected +++ b/python/ql/test/library-tests/dataflow/basic/callGraphSources.expected @@ -1,2 +1,2 @@ -| test.py:4:10:4:10 | ControlFlowNode for z | -| test.py:7:19:7:19 | ControlFlowNode for a | +| test.py:4:10:4:10 | z | +| test.py:7:19:7:19 | a | diff --git a/python/ql/test/library-tests/dataflow/basic/global.expected b/python/ql/test/library-tests/dataflow/basic/global.expected index 9e0ef2e6751b..693c64e4f468 100644 --- a/python/ql/test/library-tests/dataflow/basic/global.expected +++ b/python/ql/test/library-tests/dataflow/basic/global.expected @@ -1,73 +1,73 @@ -| test.py:1:1:1:21 | ControlFlowNode for FunctionExpr | test.py:0:0:0:0 | ModuleVariableNode in Module test for obfuscated_id | -| test.py:1:1:1:21 | ControlFlowNode for FunctionExpr | test.py:1:5:1:17 | ControlFlowNode for obfuscated_id | -| test.py:1:1:1:21 | ControlFlowNode for FunctionExpr | test.py:7:5:7:17 | ControlFlowNode for obfuscated_id | -| test.py:1:5:1:17 | ControlFlowNode for obfuscated_id | test.py:0:0:0:0 | ModuleVariableNode in Module test for obfuscated_id | -| test.py:1:5:1:17 | ControlFlowNode for obfuscated_id | test.py:7:5:7:17 | ControlFlowNode for obfuscated_id | -| test.py:1:19:1:19 | ControlFlowNode for x | test.py:0:0:0:0 | ModuleVariableNode in Module test for b | -| test.py:1:19:1:19 | ControlFlowNode for x | test.py:2:3:2:3 | ControlFlowNode for y | -| test.py:1:19:1:19 | ControlFlowNode for x | test.py:2:7:2:7 | ControlFlowNode for x | -| test.py:1:19:1:19 | ControlFlowNode for x | test.py:3:3:3:3 | ControlFlowNode for z | -| test.py:1:19:1:19 | ControlFlowNode for x | test.py:3:7:3:7 | ControlFlowNode for y | -| test.py:1:19:1:19 | ControlFlowNode for x | test.py:4:10:4:10 | ControlFlowNode for z | -| test.py:1:19:1:19 | ControlFlowNode for x | test.py:7:1:7:1 | ControlFlowNode for b | -| test.py:1:19:1:19 | ControlFlowNode for x | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | -| test.py:2:3:2:3 | ControlFlowNode for y | test.py:0:0:0:0 | ModuleVariableNode in Module test for b | -| test.py:2:3:2:3 | ControlFlowNode for y | test.py:3:3:3:3 | ControlFlowNode for z | -| test.py:2:3:2:3 | ControlFlowNode for y | test.py:3:7:3:7 | ControlFlowNode for y | -| test.py:2:3:2:3 | ControlFlowNode for y | test.py:4:10:4:10 | ControlFlowNode for z | -| test.py:2:3:2:3 | ControlFlowNode for y | test.py:7:1:7:1 | ControlFlowNode for b | -| test.py:2:3:2:3 | ControlFlowNode for y | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | -| test.py:2:7:2:7 | ControlFlowNode for x | test.py:0:0:0:0 | ModuleVariableNode in Module test for b | -| test.py:2:7:2:7 | ControlFlowNode for x | test.py:2:3:2:3 | ControlFlowNode for y | -| test.py:2:7:2:7 | ControlFlowNode for x | test.py:3:3:3:3 | ControlFlowNode for z | -| test.py:2:7:2:7 | ControlFlowNode for x | test.py:3:7:3:7 | ControlFlowNode for y | -| test.py:2:7:2:7 | ControlFlowNode for x | test.py:4:10:4:10 | ControlFlowNode for z | -| test.py:2:7:2:7 | ControlFlowNode for x | test.py:7:1:7:1 | ControlFlowNode for b | -| test.py:2:7:2:7 | ControlFlowNode for x | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | -| test.py:3:3:3:3 | ControlFlowNode for z | test.py:0:0:0:0 | ModuleVariableNode in Module test for b | -| test.py:3:3:3:3 | ControlFlowNode for z | test.py:4:10:4:10 | ControlFlowNode for z | -| test.py:3:3:3:3 | ControlFlowNode for z | test.py:7:1:7:1 | ControlFlowNode for b | -| test.py:3:3:3:3 | ControlFlowNode for z | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | -| test.py:3:7:3:7 | ControlFlowNode for y | test.py:0:0:0:0 | ModuleVariableNode in Module test for b | -| test.py:3:7:3:7 | ControlFlowNode for y | test.py:3:3:3:3 | ControlFlowNode for z | -| test.py:3:7:3:7 | ControlFlowNode for y | test.py:4:10:4:10 | ControlFlowNode for z | -| test.py:3:7:3:7 | ControlFlowNode for y | test.py:7:1:7:1 | ControlFlowNode for b | -| test.py:3:7:3:7 | ControlFlowNode for y | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | -| test.py:4:10:4:10 | ControlFlowNode for z | test.py:0:0:0:0 | ModuleVariableNode in Module test for b | -| test.py:4:10:4:10 | ControlFlowNode for z | test.py:7:1:7:1 | ControlFlowNode for b | -| test.py:4:10:4:10 | ControlFlowNode for z | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | -| test.py:6:1:6:1 | ControlFlowNode for a | test.py:0:0:0:0 | ModuleVariableNode in Module test for a | -| test.py:6:1:6:1 | ControlFlowNode for a | test.py:0:0:0:0 | ModuleVariableNode in Module test for b | -| test.py:6:1:6:1 | ControlFlowNode for a | test.py:1:19:1:19 | ControlFlowNode for x | -| test.py:6:1:6:1 | ControlFlowNode for a | test.py:2:3:2:3 | ControlFlowNode for y | -| test.py:6:1:6:1 | ControlFlowNode for a | test.py:2:7:2:7 | ControlFlowNode for x | -| test.py:6:1:6:1 | ControlFlowNode for a | test.py:3:3:3:3 | ControlFlowNode for z | -| test.py:6:1:6:1 | ControlFlowNode for a | test.py:3:7:3:7 | ControlFlowNode for y | -| test.py:6:1:6:1 | ControlFlowNode for a | test.py:4:10:4:10 | ControlFlowNode for z | -| test.py:6:1:6:1 | ControlFlowNode for a | test.py:7:1:7:1 | ControlFlowNode for b | -| test.py:6:1:6:1 | ControlFlowNode for a | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | -| test.py:6:1:6:1 | ControlFlowNode for a | test.py:7:19:7:19 | ControlFlowNode for a | -| test.py:6:5:6:6 | ControlFlowNode for IntegerLiteral | test.py:0:0:0:0 | ModuleVariableNode in Module test for a | -| test.py:6:5:6:6 | ControlFlowNode for IntegerLiteral | test.py:0:0:0:0 | ModuleVariableNode in Module test for b | -| test.py:6:5:6:6 | ControlFlowNode for IntegerLiteral | test.py:1:19:1:19 | ControlFlowNode for x | -| test.py:6:5:6:6 | ControlFlowNode for IntegerLiteral | test.py:2:3:2:3 | ControlFlowNode for y | -| test.py:6:5:6:6 | ControlFlowNode for IntegerLiteral | test.py:2:7:2:7 | ControlFlowNode for x | -| test.py:6:5:6:6 | ControlFlowNode for IntegerLiteral | test.py:3:3:3:3 | ControlFlowNode for z | -| test.py:6:5:6:6 | ControlFlowNode for IntegerLiteral | test.py:3:7:3:7 | ControlFlowNode for y | -| test.py:6:5:6:6 | ControlFlowNode for IntegerLiteral | test.py:4:10:4:10 | ControlFlowNode for z | -| test.py:6:5:6:6 | ControlFlowNode for IntegerLiteral | test.py:6:1:6:1 | ControlFlowNode for a | -| test.py:6:5:6:6 | ControlFlowNode for IntegerLiteral | test.py:7:1:7:1 | ControlFlowNode for b | -| test.py:6:5:6:6 | ControlFlowNode for IntegerLiteral | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | -| test.py:6:5:6:6 | ControlFlowNode for IntegerLiteral | test.py:7:19:7:19 | ControlFlowNode for a | -| test.py:7:1:7:1 | ControlFlowNode for b | test.py:0:0:0:0 | ModuleVariableNode in Module test for b | -| test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | test.py:0:0:0:0 | ModuleVariableNode in Module test for b | -| test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | test.py:7:1:7:1 | ControlFlowNode for b | -| test.py:7:19:7:19 | ControlFlowNode for a | test.py:0:0:0:0 | ModuleVariableNode in Module test for b | -| test.py:7:19:7:19 | ControlFlowNode for a | test.py:1:19:1:19 | ControlFlowNode for x | -| test.py:7:19:7:19 | ControlFlowNode for a | test.py:2:3:2:3 | ControlFlowNode for y | -| test.py:7:19:7:19 | ControlFlowNode for a | test.py:2:7:2:7 | ControlFlowNode for x | -| test.py:7:19:7:19 | ControlFlowNode for a | test.py:3:3:3:3 | ControlFlowNode for z | -| test.py:7:19:7:19 | ControlFlowNode for a | test.py:3:7:3:7 | ControlFlowNode for y | -| test.py:7:19:7:19 | ControlFlowNode for a | test.py:4:10:4:10 | ControlFlowNode for z | -| test.py:7:19:7:19 | ControlFlowNode for a | test.py:7:1:7:1 | ControlFlowNode for b | -| test.py:7:19:7:19 | ControlFlowNode for a | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | +| test.py:1:1:1:21 | FunctionExpr | test.py:0:0:0:0 | ModuleVariableNode in Module test for obfuscated_id | +| test.py:1:1:1:21 | FunctionExpr | test.py:1:5:1:17 | obfuscated_id | +| test.py:1:1:1:21 | FunctionExpr | test.py:7:5:7:17 | obfuscated_id | +| test.py:1:5:1:17 | obfuscated_id | test.py:0:0:0:0 | ModuleVariableNode in Module test for obfuscated_id | +| test.py:1:5:1:17 | obfuscated_id | test.py:7:5:7:17 | obfuscated_id | +| test.py:1:19:1:19 | x | test.py:0:0:0:0 | ModuleVariableNode in Module test for b | +| test.py:1:19:1:19 | x | test.py:2:3:2:3 | y | +| test.py:1:19:1:19 | x | test.py:2:7:2:7 | x | +| test.py:1:19:1:19 | x | test.py:3:3:3:3 | z | +| test.py:1:19:1:19 | x | test.py:3:7:3:7 | y | +| test.py:1:19:1:19 | x | test.py:4:10:4:10 | z | +| test.py:1:19:1:19 | x | test.py:7:1:7:1 | b | +| test.py:1:19:1:19 | x | test.py:7:5:7:20 | obfuscated_id() | +| test.py:2:3:2:3 | y | test.py:0:0:0:0 | ModuleVariableNode in Module test for b | +| test.py:2:3:2:3 | y | test.py:3:3:3:3 | z | +| test.py:2:3:2:3 | y | test.py:3:7:3:7 | y | +| test.py:2:3:2:3 | y | test.py:4:10:4:10 | z | +| test.py:2:3:2:3 | y | test.py:7:1:7:1 | b | +| test.py:2:3:2:3 | y | test.py:7:5:7:20 | obfuscated_id() | +| test.py:2:7:2:7 | x | test.py:0:0:0:0 | ModuleVariableNode in Module test for b | +| test.py:2:7:2:7 | x | test.py:2:3:2:3 | y | +| test.py:2:7:2:7 | x | test.py:3:3:3:3 | z | +| test.py:2:7:2:7 | x | test.py:3:7:3:7 | y | +| test.py:2:7:2:7 | x | test.py:4:10:4:10 | z | +| test.py:2:7:2:7 | x | test.py:7:1:7:1 | b | +| test.py:2:7:2:7 | x | test.py:7:5:7:20 | obfuscated_id() | +| test.py:3:3:3:3 | z | test.py:0:0:0:0 | ModuleVariableNode in Module test for b | +| test.py:3:3:3:3 | z | test.py:4:10:4:10 | z | +| test.py:3:3:3:3 | z | test.py:7:1:7:1 | b | +| test.py:3:3:3:3 | z | test.py:7:5:7:20 | obfuscated_id() | +| test.py:3:7:3:7 | y | test.py:0:0:0:0 | ModuleVariableNode in Module test for b | +| test.py:3:7:3:7 | y | test.py:3:3:3:3 | z | +| test.py:3:7:3:7 | y | test.py:4:10:4:10 | z | +| test.py:3:7:3:7 | y | test.py:7:1:7:1 | b | +| test.py:3:7:3:7 | y | test.py:7:5:7:20 | obfuscated_id() | +| test.py:4:10:4:10 | z | test.py:0:0:0:0 | ModuleVariableNode in Module test for b | +| test.py:4:10:4:10 | z | test.py:7:1:7:1 | b | +| test.py:4:10:4:10 | z | test.py:7:5:7:20 | obfuscated_id() | +| test.py:6:1:6:1 | a | test.py:0:0:0:0 | ModuleVariableNode in Module test for a | +| test.py:6:1:6:1 | a | test.py:0:0:0:0 | ModuleVariableNode in Module test for b | +| test.py:6:1:6:1 | a | test.py:1:19:1:19 | x | +| test.py:6:1:6:1 | a | test.py:2:3:2:3 | y | +| test.py:6:1:6:1 | a | test.py:2:7:2:7 | x | +| test.py:6:1:6:1 | a | test.py:3:3:3:3 | z | +| test.py:6:1:6:1 | a | test.py:3:7:3:7 | y | +| test.py:6:1:6:1 | a | test.py:4:10:4:10 | z | +| test.py:6:1:6:1 | a | test.py:7:1:7:1 | b | +| test.py:6:1:6:1 | a | test.py:7:5:7:20 | obfuscated_id() | +| test.py:6:1:6:1 | a | test.py:7:19:7:19 | a | +| test.py:6:5:6:6 | IntegerLiteral | test.py:0:0:0:0 | ModuleVariableNode in Module test for a | +| test.py:6:5:6:6 | IntegerLiteral | test.py:0:0:0:0 | ModuleVariableNode in Module test for b | +| test.py:6:5:6:6 | IntegerLiteral | test.py:1:19:1:19 | x | +| test.py:6:5:6:6 | IntegerLiteral | test.py:2:3:2:3 | y | +| test.py:6:5:6:6 | IntegerLiteral | test.py:2:7:2:7 | x | +| test.py:6:5:6:6 | IntegerLiteral | test.py:3:3:3:3 | z | +| test.py:6:5:6:6 | IntegerLiteral | test.py:3:7:3:7 | y | +| test.py:6:5:6:6 | IntegerLiteral | test.py:4:10:4:10 | z | +| test.py:6:5:6:6 | IntegerLiteral | test.py:6:1:6:1 | a | +| test.py:6:5:6:6 | IntegerLiteral | test.py:7:1:7:1 | b | +| test.py:6:5:6:6 | IntegerLiteral | test.py:7:5:7:20 | obfuscated_id() | +| test.py:6:5:6:6 | IntegerLiteral | test.py:7:19:7:19 | a | +| test.py:7:1:7:1 | b | test.py:0:0:0:0 | ModuleVariableNode in Module test for b | +| test.py:7:5:7:20 | obfuscated_id() | test.py:0:0:0:0 | ModuleVariableNode in Module test for b | +| test.py:7:5:7:20 | obfuscated_id() | test.py:7:1:7:1 | b | +| test.py:7:19:7:19 | a | test.py:0:0:0:0 | ModuleVariableNode in Module test for b | +| test.py:7:19:7:19 | a | test.py:1:19:1:19 | x | +| test.py:7:19:7:19 | a | test.py:2:3:2:3 | y | +| test.py:7:19:7:19 | a | test.py:2:7:2:7 | x | +| test.py:7:19:7:19 | a | test.py:3:3:3:3 | z | +| test.py:7:19:7:19 | a | test.py:3:7:3:7 | y | +| test.py:7:19:7:19 | a | test.py:4:10:4:10 | z | +| test.py:7:19:7:19 | a | test.py:7:1:7:1 | b | +| test.py:7:19:7:19 | a | test.py:7:5:7:20 | obfuscated_id() | diff --git a/python/ql/test/library-tests/dataflow/basic/globalStep.expected b/python/ql/test/library-tests/dataflow/basic/globalStep.expected index 26d8902e7bbe..e6eb8fce67c0 100644 --- a/python/ql/test/library-tests/dataflow/basic/globalStep.expected +++ b/python/ql/test/library-tests/dataflow/basic/globalStep.expected @@ -1,46 +1,46 @@ -| test.py:1:1:1:21 | ControlFlowNode for FunctionExpr | test.py:1:5:1:17 | ControlFlowNode for obfuscated_id | -| test.py:1:1:1:21 | ControlFlowNode for FunctionExpr | test.py:1:5:1:17 | ControlFlowNode for obfuscated_id | -| test.py:1:5:1:17 | ControlFlowNode for obfuscated_id | test.py:0:0:0:0 | ModuleVariableNode in Module test for obfuscated_id | -| test.py:1:5:1:17 | ControlFlowNode for obfuscated_id | test.py:7:5:7:17 | ControlFlowNode for obfuscated_id | -| test.py:1:19:1:19 | ControlFlowNode for x | test.py:2:3:2:3 | ControlFlowNode for y | -| test.py:1:19:1:19 | ControlFlowNode for x | test.py:2:3:2:3 | ControlFlowNode for y | -| test.py:1:19:1:19 | ControlFlowNode for x | test.py:2:3:2:3 | ControlFlowNode for y | -| test.py:1:19:1:19 | ControlFlowNode for x | test.py:2:3:2:3 | ControlFlowNode for y | -| test.py:1:19:1:19 | ControlFlowNode for x | test.py:2:7:2:7 | ControlFlowNode for x | -| test.py:1:19:1:19 | ControlFlowNode for x | test.py:2:7:2:7 | ControlFlowNode for x | -| test.py:1:19:1:19 | ControlFlowNode for x | test.py:2:7:2:7 | ControlFlowNode for x | -| test.py:1:19:1:19 | ControlFlowNode for x | test.py:2:7:2:7 | ControlFlowNode for x | -| test.py:2:3:2:3 | ControlFlowNode for y | test.py:3:3:3:3 | ControlFlowNode for z | -| test.py:2:3:2:3 | ControlFlowNode for y | test.py:3:3:3:3 | ControlFlowNode for z | -| test.py:2:3:2:3 | ControlFlowNode for y | test.py:3:3:3:3 | ControlFlowNode for z | -| test.py:2:3:2:3 | ControlFlowNode for y | test.py:3:3:3:3 | ControlFlowNode for z | -| test.py:2:3:2:3 | ControlFlowNode for y | test.py:3:7:3:7 | ControlFlowNode for y | -| test.py:2:3:2:3 | ControlFlowNode for y | test.py:3:7:3:7 | ControlFlowNode for y | -| test.py:2:3:2:3 | ControlFlowNode for y | test.py:3:7:3:7 | ControlFlowNode for y | -| test.py:2:3:2:3 | ControlFlowNode for y | test.py:3:7:3:7 | ControlFlowNode for y | -| test.py:2:7:2:7 | ControlFlowNode for x | test.py:2:3:2:3 | ControlFlowNode for y | -| test.py:2:7:2:7 | ControlFlowNode for x | test.py:2:3:2:3 | ControlFlowNode for y | -| test.py:2:7:2:7 | ControlFlowNode for x | test.py:2:3:2:3 | ControlFlowNode for y | -| test.py:2:7:2:7 | ControlFlowNode for x | test.py:2:3:2:3 | ControlFlowNode for y | -| test.py:3:3:3:3 | ControlFlowNode for z | test.py:4:10:4:10 | ControlFlowNode for z | -| test.py:3:3:3:3 | ControlFlowNode for z | test.py:4:10:4:10 | ControlFlowNode for z | -| test.py:3:3:3:3 | ControlFlowNode for z | test.py:4:10:4:10 | ControlFlowNode for z | -| test.py:3:3:3:3 | ControlFlowNode for z | test.py:4:10:4:10 | ControlFlowNode for z | -| test.py:3:7:3:7 | ControlFlowNode for y | test.py:3:3:3:3 | ControlFlowNode for z | -| test.py:3:7:3:7 | ControlFlowNode for y | test.py:3:3:3:3 | ControlFlowNode for z | -| test.py:3:7:3:7 | ControlFlowNode for y | test.py:3:3:3:3 | ControlFlowNode for z | -| test.py:3:7:3:7 | ControlFlowNode for y | test.py:3:3:3:3 | ControlFlowNode for z | -| test.py:4:10:4:10 | ControlFlowNode for z | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | -| test.py:4:10:4:10 | ControlFlowNode for z | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | -| test.py:6:1:6:1 | ControlFlowNode for a | test.py:0:0:0:0 | ModuleVariableNode in Module test for a | -| test.py:6:1:6:1 | ControlFlowNode for a | test.py:7:19:7:19 | ControlFlowNode for a | -| test.py:6:1:6:1 | ControlFlowNode for a | test.py:7:19:7:19 | ControlFlowNode for a | -| test.py:6:5:6:6 | ControlFlowNode for IntegerLiteral | test.py:6:1:6:1 | ControlFlowNode for a | -| test.py:6:5:6:6 | ControlFlowNode for IntegerLiteral | test.py:6:1:6:1 | ControlFlowNode for a | -| test.py:7:1:7:1 | ControlFlowNode for b | test.py:0:0:0:0 | ModuleVariableNode in Module test for b | -| test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | test.py:7:1:7:1 | ControlFlowNode for b | -| test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | test.py:7:1:7:1 | ControlFlowNode for b | -| test.py:7:19:7:19 | ControlFlowNode for a | test.py:1:19:1:19 | ControlFlowNode for x | -| test.py:7:19:7:19 | ControlFlowNode for a | test.py:1:19:1:19 | ControlFlowNode for x | -| test.py:7:19:7:19 | ControlFlowNode for a | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | -| test.py:7:19:7:19 | ControlFlowNode for a | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | +| test.py:1:1:1:21 | FunctionExpr | test.py:1:5:1:17 | obfuscated_id | +| test.py:1:1:1:21 | FunctionExpr | test.py:1:5:1:17 | obfuscated_id | +| test.py:1:5:1:17 | obfuscated_id | test.py:0:0:0:0 | ModuleVariableNode in Module test for obfuscated_id | +| test.py:1:5:1:17 | obfuscated_id | test.py:7:5:7:17 | obfuscated_id | +| test.py:1:19:1:19 | x | test.py:2:3:2:3 | y | +| test.py:1:19:1:19 | x | test.py:2:3:2:3 | y | +| test.py:1:19:1:19 | x | test.py:2:3:2:3 | y | +| test.py:1:19:1:19 | x | test.py:2:3:2:3 | y | +| test.py:1:19:1:19 | x | test.py:2:7:2:7 | x | +| test.py:1:19:1:19 | x | test.py:2:7:2:7 | x | +| test.py:1:19:1:19 | x | test.py:2:7:2:7 | x | +| test.py:1:19:1:19 | x | test.py:2:7:2:7 | x | +| test.py:2:3:2:3 | y | test.py:3:3:3:3 | z | +| test.py:2:3:2:3 | y | test.py:3:3:3:3 | z | +| test.py:2:3:2:3 | y | test.py:3:3:3:3 | z | +| test.py:2:3:2:3 | y | test.py:3:3:3:3 | z | +| test.py:2:3:2:3 | y | test.py:3:7:3:7 | y | +| test.py:2:3:2:3 | y | test.py:3:7:3:7 | y | +| test.py:2:3:2:3 | y | test.py:3:7:3:7 | y | +| test.py:2:3:2:3 | y | test.py:3:7:3:7 | y | +| test.py:2:7:2:7 | x | test.py:2:3:2:3 | y | +| test.py:2:7:2:7 | x | test.py:2:3:2:3 | y | +| test.py:2:7:2:7 | x | test.py:2:3:2:3 | y | +| test.py:2:7:2:7 | x | test.py:2:3:2:3 | y | +| test.py:3:3:3:3 | z | test.py:4:10:4:10 | z | +| test.py:3:3:3:3 | z | test.py:4:10:4:10 | z | +| test.py:3:3:3:3 | z | test.py:4:10:4:10 | z | +| test.py:3:3:3:3 | z | test.py:4:10:4:10 | z | +| test.py:3:7:3:7 | y | test.py:3:3:3:3 | z | +| test.py:3:7:3:7 | y | test.py:3:3:3:3 | z | +| test.py:3:7:3:7 | y | test.py:3:3:3:3 | z | +| test.py:3:7:3:7 | y | test.py:3:3:3:3 | z | +| test.py:4:10:4:10 | z | test.py:7:5:7:20 | obfuscated_id() | +| test.py:4:10:4:10 | z | test.py:7:5:7:20 | obfuscated_id() | +| test.py:6:1:6:1 | a | test.py:0:0:0:0 | ModuleVariableNode in Module test for a | +| test.py:6:1:6:1 | a | test.py:7:19:7:19 | a | +| test.py:6:1:6:1 | a | test.py:7:19:7:19 | a | +| test.py:6:5:6:6 | IntegerLiteral | test.py:6:1:6:1 | a | +| test.py:6:5:6:6 | IntegerLiteral | test.py:6:1:6:1 | a | +| test.py:7:1:7:1 | b | test.py:0:0:0:0 | ModuleVariableNode in Module test for b | +| test.py:7:5:7:20 | obfuscated_id() | test.py:7:1:7:1 | b | +| test.py:7:5:7:20 | obfuscated_id() | test.py:7:1:7:1 | b | +| test.py:7:19:7:19 | a | test.py:1:19:1:19 | x | +| test.py:7:19:7:19 | a | test.py:1:19:1:19 | x | +| test.py:7:19:7:19 | a | test.py:7:5:7:20 | obfuscated_id() | +| test.py:7:19:7:19 | a | test.py:7:5:7:20 | obfuscated_id() | diff --git a/python/ql/test/library-tests/dataflow/basic/local.expected b/python/ql/test/library-tests/dataflow/basic/local.expected index 96d402325129..9332e686ebcc 100644 --- a/python/ql/test/library-tests/dataflow/basic/local.expected +++ b/python/ql/test/library-tests/dataflow/basic/local.expected @@ -3,45 +3,45 @@ | test.py:0:0:0:0 | ModuleVariableNode in Module test for a | test.py:0:0:0:0 | ModuleVariableNode in Module test for a | | test.py:0:0:0:0 | ModuleVariableNode in Module test for b | test.py:0:0:0:0 | ModuleVariableNode in Module test for b | | test.py:0:0:0:0 | ModuleVariableNode in Module test for obfuscated_id | test.py:0:0:0:0 | ModuleVariableNode in Module test for obfuscated_id | -| test.py:1:1:1:21 | ControlFlowNode for FunctionExpr | test.py:1:1:1:21 | ControlFlowNode for FunctionExpr | -| test.py:1:1:1:21 | ControlFlowNode for FunctionExpr | test.py:1:5:1:17 | ControlFlowNode for obfuscated_id | -| test.py:1:1:1:21 | ControlFlowNode for FunctionExpr | test.py:7:5:7:17 | ControlFlowNode for obfuscated_id | +| test.py:1:1:1:21 | FunctionExpr | test.py:1:1:1:21 | FunctionExpr | +| test.py:1:1:1:21 | FunctionExpr | test.py:1:5:1:17 | obfuscated_id | +| test.py:1:1:1:21 | FunctionExpr | test.py:7:5:7:17 | obfuscated_id | | test.py:1:1:1:21 | SynthDictSplatParameterNode | test.py:1:1:1:21 | SynthDictSplatParameterNode | -| test.py:1:5:1:17 | ControlFlowNode for obfuscated_id | test.py:1:5:1:17 | ControlFlowNode for obfuscated_id | -| test.py:1:5:1:17 | ControlFlowNode for obfuscated_id | test.py:7:5:7:17 | ControlFlowNode for obfuscated_id | -| test.py:1:19:1:19 | ControlFlowNode for x | test.py:1:19:1:19 | ControlFlowNode for x | -| test.py:1:19:1:19 | ControlFlowNode for x | test.py:2:3:2:3 | ControlFlowNode for y | -| test.py:1:19:1:19 | ControlFlowNode for x | test.py:2:7:2:7 | ControlFlowNode for x | -| test.py:1:19:1:19 | ControlFlowNode for x | test.py:3:3:3:3 | ControlFlowNode for z | -| test.py:1:19:1:19 | ControlFlowNode for x | test.py:3:7:3:7 | ControlFlowNode for y | -| test.py:1:19:1:19 | ControlFlowNode for x | test.py:4:10:4:10 | ControlFlowNode for z | -| test.py:2:3:2:3 | ControlFlowNode for y | test.py:2:3:2:3 | ControlFlowNode for y | -| test.py:2:3:2:3 | ControlFlowNode for y | test.py:3:3:3:3 | ControlFlowNode for z | -| test.py:2:3:2:3 | ControlFlowNode for y | test.py:3:7:3:7 | ControlFlowNode for y | -| test.py:2:3:2:3 | ControlFlowNode for y | test.py:4:10:4:10 | ControlFlowNode for z | -| test.py:2:7:2:7 | ControlFlowNode for x | test.py:2:3:2:3 | ControlFlowNode for y | -| test.py:2:7:2:7 | ControlFlowNode for x | test.py:2:7:2:7 | ControlFlowNode for x | -| test.py:2:7:2:7 | ControlFlowNode for x | test.py:3:3:3:3 | ControlFlowNode for z | -| test.py:2:7:2:7 | ControlFlowNode for x | test.py:3:7:3:7 | ControlFlowNode for y | -| test.py:2:7:2:7 | ControlFlowNode for x | test.py:4:10:4:10 | ControlFlowNode for z | -| test.py:3:3:3:3 | ControlFlowNode for z | test.py:3:3:3:3 | ControlFlowNode for z | -| test.py:3:3:3:3 | ControlFlowNode for z | test.py:4:10:4:10 | ControlFlowNode for z | -| test.py:3:7:3:7 | ControlFlowNode for y | test.py:3:3:3:3 | ControlFlowNode for z | -| test.py:3:7:3:7 | ControlFlowNode for y | test.py:3:7:3:7 | ControlFlowNode for y | -| test.py:3:7:3:7 | ControlFlowNode for y | test.py:4:10:4:10 | ControlFlowNode for z | -| test.py:4:10:4:10 | ControlFlowNode for z | test.py:4:10:4:10 | ControlFlowNode for z | -| test.py:6:1:6:1 | ControlFlowNode for a | test.py:6:1:6:1 | ControlFlowNode for a | -| test.py:6:1:6:1 | ControlFlowNode for a | test.py:7:19:7:19 | ControlFlowNode for a | -| test.py:6:5:6:6 | ControlFlowNode for IntegerLiteral | test.py:6:1:6:1 | ControlFlowNode for a | -| test.py:6:5:6:6 | ControlFlowNode for IntegerLiteral | test.py:6:5:6:6 | ControlFlowNode for IntegerLiteral | -| test.py:6:5:6:6 | ControlFlowNode for IntegerLiteral | test.py:7:19:7:19 | ControlFlowNode for a | -| test.py:7:1:7:1 | ControlFlowNode for b | test.py:7:1:7:1 | ControlFlowNode for b | +| test.py:1:5:1:17 | obfuscated_id | test.py:1:5:1:17 | obfuscated_id | +| test.py:1:5:1:17 | obfuscated_id | test.py:7:5:7:17 | obfuscated_id | +| test.py:1:19:1:19 | x | test.py:1:19:1:19 | x | +| test.py:1:19:1:19 | x | test.py:2:3:2:3 | y | +| test.py:1:19:1:19 | x | test.py:2:7:2:7 | x | +| test.py:1:19:1:19 | x | test.py:3:3:3:3 | z | +| test.py:1:19:1:19 | x | test.py:3:7:3:7 | y | +| test.py:1:19:1:19 | x | test.py:4:10:4:10 | z | +| test.py:2:3:2:3 | y | test.py:2:3:2:3 | y | +| test.py:2:3:2:3 | y | test.py:3:3:3:3 | z | +| test.py:2:3:2:3 | y | test.py:3:7:3:7 | y | +| test.py:2:3:2:3 | y | test.py:4:10:4:10 | z | +| test.py:2:7:2:7 | x | test.py:2:3:2:3 | y | +| test.py:2:7:2:7 | x | test.py:2:7:2:7 | x | +| test.py:2:7:2:7 | x | test.py:3:3:3:3 | z | +| test.py:2:7:2:7 | x | test.py:3:7:3:7 | y | +| test.py:2:7:2:7 | x | test.py:4:10:4:10 | z | +| test.py:3:3:3:3 | z | test.py:3:3:3:3 | z | +| test.py:3:3:3:3 | z | test.py:4:10:4:10 | z | +| test.py:3:7:3:7 | y | test.py:3:3:3:3 | z | +| test.py:3:7:3:7 | y | test.py:3:7:3:7 | y | +| test.py:3:7:3:7 | y | test.py:4:10:4:10 | z | +| test.py:4:10:4:10 | z | test.py:4:10:4:10 | z | +| test.py:6:1:6:1 | a | test.py:6:1:6:1 | a | +| test.py:6:1:6:1 | a | test.py:7:19:7:19 | a | +| test.py:6:5:6:6 | IntegerLiteral | test.py:6:1:6:1 | a | +| test.py:6:5:6:6 | IntegerLiteral | test.py:6:5:6:6 | IntegerLiteral | +| test.py:6:5:6:6 | IntegerLiteral | test.py:7:19:7:19 | a | +| test.py:7:1:7:1 | b | test.py:7:1:7:1 | b | | test.py:7:5:7:17 | Capturing closure argument | test.py:7:5:7:17 | Capturing closure argument | -| test.py:7:5:7:17 | ControlFlowNode for obfuscated_id | test.py:7:5:7:17 | ControlFlowNode for obfuscated_id | | test.py:7:5:7:17 | [post] Capturing closure argument | test.py:7:5:7:17 | [post] Capturing closure argument | -| test.py:7:5:7:17 | [post] ControlFlowNode for obfuscated_id | test.py:7:5:7:17 | [post] ControlFlowNode for obfuscated_id | -| test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | test.py:7:1:7:1 | ControlFlowNode for b | -| test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | -| test.py:7:5:7:20 | [pre] ControlFlowNode for obfuscated_id() | test.py:7:5:7:20 | [pre] ControlFlowNode for obfuscated_id() | -| test.py:7:19:7:19 | ControlFlowNode for a | test.py:7:19:7:19 | ControlFlowNode for a | -| test.py:7:19:7:19 | [post] ControlFlowNode for a | test.py:7:19:7:19 | [post] ControlFlowNode for a | +| test.py:7:5:7:17 | [post] obfuscated_id | test.py:7:5:7:17 | [post] obfuscated_id | +| test.py:7:5:7:17 | obfuscated_id | test.py:7:5:7:17 | obfuscated_id | +| test.py:7:5:7:20 | [pre] obfuscated_id() | test.py:7:5:7:20 | [pre] obfuscated_id() | +| test.py:7:5:7:20 | obfuscated_id() | test.py:7:1:7:1 | b | +| test.py:7:5:7:20 | obfuscated_id() | test.py:7:5:7:20 | obfuscated_id() | +| test.py:7:19:7:19 | [post] a | test.py:7:19:7:19 | [post] a | +| test.py:7:19:7:19 | a | test.py:7:19:7:19 | a | diff --git a/python/ql/test/library-tests/dataflow/basic/localStep.expected b/python/ql/test/library-tests/dataflow/basic/localStep.expected index ce190945d363..78286e6f545b 100644 --- a/python/ql/test/library-tests/dataflow/basic/localStep.expected +++ b/python/ql/test/library-tests/dataflow/basic/localStep.expected @@ -1,10 +1,10 @@ -| test.py:1:1:1:21 | ControlFlowNode for FunctionExpr | test.py:1:5:1:17 | ControlFlowNode for obfuscated_id | -| test.py:1:5:1:17 | ControlFlowNode for obfuscated_id | test.py:7:5:7:17 | ControlFlowNode for obfuscated_id | -| test.py:1:19:1:19 | ControlFlowNode for x | test.py:2:7:2:7 | ControlFlowNode for x | -| test.py:2:3:2:3 | ControlFlowNode for y | test.py:3:7:3:7 | ControlFlowNode for y | -| test.py:2:7:2:7 | ControlFlowNode for x | test.py:2:3:2:3 | ControlFlowNode for y | -| test.py:3:3:3:3 | ControlFlowNode for z | test.py:4:10:4:10 | ControlFlowNode for z | -| test.py:3:7:3:7 | ControlFlowNode for y | test.py:3:3:3:3 | ControlFlowNode for z | -| test.py:6:1:6:1 | ControlFlowNode for a | test.py:7:19:7:19 | ControlFlowNode for a | -| test.py:6:5:6:6 | ControlFlowNode for IntegerLiteral | test.py:6:1:6:1 | ControlFlowNode for a | -| test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | test.py:7:1:7:1 | ControlFlowNode for b | +| test.py:1:1:1:21 | FunctionExpr | test.py:1:5:1:17 | obfuscated_id | +| test.py:1:5:1:17 | obfuscated_id | test.py:7:5:7:17 | obfuscated_id | +| test.py:1:19:1:19 | x | test.py:2:7:2:7 | x | +| test.py:2:3:2:3 | y | test.py:3:7:3:7 | y | +| test.py:2:7:2:7 | x | test.py:2:3:2:3 | y | +| test.py:3:3:3:3 | z | test.py:4:10:4:10 | z | +| test.py:3:7:3:7 | y | test.py:3:3:3:3 | z | +| test.py:6:1:6:1 | a | test.py:7:19:7:19 | a | +| test.py:6:5:6:6 | IntegerLiteral | test.py:6:1:6:1 | a | +| test.py:7:5:7:20 | obfuscated_id() | test.py:7:1:7:1 | b | diff --git a/python/ql/test/library-tests/dataflow/basic/maximalFlows.expected b/python/ql/test/library-tests/dataflow/basic/maximalFlows.expected index 421918620455..3be31d554c39 100644 --- a/python/ql/test/library-tests/dataflow/basic/maximalFlows.expected +++ b/python/ql/test/library-tests/dataflow/basic/maximalFlows.expected @@ -1,12 +1,12 @@ -| test.py:1:1:1:21 | ControlFlowNode for FunctionExpr | test.py:0:0:0:0 | ModuleVariableNode in Module test for obfuscated_id | -| test.py:1:1:1:21 | ControlFlowNode for FunctionExpr | test.py:7:5:7:17 | ControlFlowNode for obfuscated_id | -| test.py:1:19:1:19 | ControlFlowNode for x | test.py:0:0:0:0 | ModuleVariableNode in Module test for b | -| test.py:1:19:1:19 | ControlFlowNode for x | test.py:4:10:4:10 | ControlFlowNode for z | -| test.py:1:19:1:19 | ControlFlowNode for x | test.py:7:1:7:1 | ControlFlowNode for b | -| test.py:6:5:6:6 | ControlFlowNode for IntegerLiteral | test.py:0:0:0:0 | ModuleVariableNode in Module test for a | -| test.py:6:5:6:6 | ControlFlowNode for IntegerLiteral | test.py:0:0:0:0 | ModuleVariableNode in Module test for b | -| test.py:6:5:6:6 | ControlFlowNode for IntegerLiteral | test.py:4:10:4:10 | ControlFlowNode for z | -| test.py:6:5:6:6 | ControlFlowNode for IntegerLiteral | test.py:7:1:7:1 | ControlFlowNode for b | -| test.py:6:5:6:6 | ControlFlowNode for IntegerLiteral | test.py:7:19:7:19 | ControlFlowNode for a | -| test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | test.py:0:0:0:0 | ModuleVariableNode in Module test for b | -| test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | test.py:7:1:7:1 | ControlFlowNode for b | +| test.py:1:1:1:21 | FunctionExpr | test.py:0:0:0:0 | ModuleVariableNode in Module test for obfuscated_id | +| test.py:1:1:1:21 | FunctionExpr | test.py:7:5:7:17 | obfuscated_id | +| test.py:1:19:1:19 | x | test.py:0:0:0:0 | ModuleVariableNode in Module test for b | +| test.py:1:19:1:19 | x | test.py:4:10:4:10 | z | +| test.py:1:19:1:19 | x | test.py:7:1:7:1 | b | +| test.py:6:5:6:6 | IntegerLiteral | test.py:0:0:0:0 | ModuleVariableNode in Module test for a | +| test.py:6:5:6:6 | IntegerLiteral | test.py:0:0:0:0 | ModuleVariableNode in Module test for b | +| test.py:6:5:6:6 | IntegerLiteral | test.py:4:10:4:10 | z | +| test.py:6:5:6:6 | IntegerLiteral | test.py:7:1:7:1 | b | +| test.py:6:5:6:6 | IntegerLiteral | test.py:7:19:7:19 | a | +| test.py:7:5:7:20 | obfuscated_id() | test.py:0:0:0:0 | ModuleVariableNode in Module test for b | +| test.py:7:5:7:20 | obfuscated_id() | test.py:7:1:7:1 | b | diff --git a/python/ql/test/library-tests/dataflow/basic/sinks.expected b/python/ql/test/library-tests/dataflow/basic/sinks.expected index 80055f9a2f2b..cdf683f94fc3 100644 --- a/python/ql/test/library-tests/dataflow/basic/sinks.expected +++ b/python/ql/test/library-tests/dataflow/basic/sinks.expected @@ -3,23 +3,23 @@ | test.py:0:0:0:0 | ModuleVariableNode in Module test for a | | test.py:0:0:0:0 | ModuleVariableNode in Module test for b | | test.py:0:0:0:0 | ModuleVariableNode in Module test for obfuscated_id | -| test.py:1:1:1:21 | ControlFlowNode for FunctionExpr | +| test.py:1:1:1:21 | FunctionExpr | | test.py:1:1:1:21 | SynthDictSplatParameterNode | -| test.py:1:5:1:17 | ControlFlowNode for obfuscated_id | -| test.py:1:19:1:19 | ControlFlowNode for x | -| test.py:2:3:2:3 | ControlFlowNode for y | -| test.py:2:7:2:7 | ControlFlowNode for x | -| test.py:3:3:3:3 | ControlFlowNode for z | -| test.py:3:7:3:7 | ControlFlowNode for y | -| test.py:4:10:4:10 | ControlFlowNode for z | -| test.py:6:1:6:1 | ControlFlowNode for a | -| test.py:6:5:6:6 | ControlFlowNode for IntegerLiteral | -| test.py:7:1:7:1 | ControlFlowNode for b | +| test.py:1:5:1:17 | obfuscated_id | +| test.py:1:19:1:19 | x | +| test.py:2:3:2:3 | y | +| test.py:2:7:2:7 | x | +| test.py:3:3:3:3 | z | +| test.py:3:7:3:7 | y | +| test.py:4:10:4:10 | z | +| test.py:6:1:6:1 | a | +| test.py:6:5:6:6 | IntegerLiteral | +| test.py:7:1:7:1 | b | | test.py:7:5:7:17 | Capturing closure argument | -| test.py:7:5:7:17 | ControlFlowNode for obfuscated_id | | test.py:7:5:7:17 | [post] Capturing closure argument | -| test.py:7:5:7:17 | [post] ControlFlowNode for obfuscated_id | -| test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | -| test.py:7:5:7:20 | [pre] ControlFlowNode for obfuscated_id() | -| test.py:7:19:7:19 | ControlFlowNode for a | -| test.py:7:19:7:19 | [post] ControlFlowNode for a | +| test.py:7:5:7:17 | [post] obfuscated_id | +| test.py:7:5:7:17 | obfuscated_id | +| test.py:7:5:7:20 | [pre] obfuscated_id() | +| test.py:7:5:7:20 | obfuscated_id() | +| test.py:7:19:7:19 | [post] a | +| test.py:7:19:7:19 | a | diff --git a/python/ql/test/library-tests/dataflow/basic/sources.expected b/python/ql/test/library-tests/dataflow/basic/sources.expected index 80055f9a2f2b..cdf683f94fc3 100644 --- a/python/ql/test/library-tests/dataflow/basic/sources.expected +++ b/python/ql/test/library-tests/dataflow/basic/sources.expected @@ -3,23 +3,23 @@ | test.py:0:0:0:0 | ModuleVariableNode in Module test for a | | test.py:0:0:0:0 | ModuleVariableNode in Module test for b | | test.py:0:0:0:0 | ModuleVariableNode in Module test for obfuscated_id | -| test.py:1:1:1:21 | ControlFlowNode for FunctionExpr | +| test.py:1:1:1:21 | FunctionExpr | | test.py:1:1:1:21 | SynthDictSplatParameterNode | -| test.py:1:5:1:17 | ControlFlowNode for obfuscated_id | -| test.py:1:19:1:19 | ControlFlowNode for x | -| test.py:2:3:2:3 | ControlFlowNode for y | -| test.py:2:7:2:7 | ControlFlowNode for x | -| test.py:3:3:3:3 | ControlFlowNode for z | -| test.py:3:7:3:7 | ControlFlowNode for y | -| test.py:4:10:4:10 | ControlFlowNode for z | -| test.py:6:1:6:1 | ControlFlowNode for a | -| test.py:6:5:6:6 | ControlFlowNode for IntegerLiteral | -| test.py:7:1:7:1 | ControlFlowNode for b | +| test.py:1:5:1:17 | obfuscated_id | +| test.py:1:19:1:19 | x | +| test.py:2:3:2:3 | y | +| test.py:2:7:2:7 | x | +| test.py:3:3:3:3 | z | +| test.py:3:7:3:7 | y | +| test.py:4:10:4:10 | z | +| test.py:6:1:6:1 | a | +| test.py:6:5:6:6 | IntegerLiteral | +| test.py:7:1:7:1 | b | | test.py:7:5:7:17 | Capturing closure argument | -| test.py:7:5:7:17 | ControlFlowNode for obfuscated_id | | test.py:7:5:7:17 | [post] Capturing closure argument | -| test.py:7:5:7:17 | [post] ControlFlowNode for obfuscated_id | -| test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | -| test.py:7:5:7:20 | [pre] ControlFlowNode for obfuscated_id() | -| test.py:7:19:7:19 | ControlFlowNode for a | -| test.py:7:19:7:19 | [post] ControlFlowNode for a | +| test.py:7:5:7:17 | [post] obfuscated_id | +| test.py:7:5:7:17 | obfuscated_id | +| test.py:7:5:7:20 | [pre] obfuscated_id() | +| test.py:7:5:7:20 | obfuscated_id() | +| test.py:7:19:7:19 | [post] a | +| test.py:7:19:7:19 | a | diff --git a/python/ql/test/library-tests/dataflow/callgraph_crosstalk/Arguments.expected b/python/ql/test/library-tests/dataflow/callgraph_crosstalk/Arguments.expected index 99c2d987d16d..df1596bed04d 100644 --- a/python/ql/test/library-tests/dataflow/callgraph_crosstalk/Arguments.expected +++ b/python/ql/test/library-tests/dataflow/callgraph_crosstalk/Arguments.expected @@ -1,13 +1,13 @@ -| test.py:32:8:32:23 | CrosstalkTestX() | test.py:9:5:9:23 | Function __init__ | test.py:32:8:32:23 | [pre] ControlFlowNode for CrosstalkTestX() | self | -| test.py:33:8:33:23 | CrosstalkTestY() | test.py:21:5:21:23 | Function __init__ | test.py:33:8:33:23 | [pre] ControlFlowNode for CrosstalkTestY() | self | -| test.py:43:1:43:8 | func() | test.py:13:5:13:26 | Function setx | test.py:36:12:36:15 | ControlFlowNode for objx | self | -| test.py:43:1:43:8 | func() | test.py:13:5:13:26 | Function setx | test.py:43:6:43:7 | ControlFlowNode for IntegerLiteral | position 0 | -| test.py:43:1:43:8 | func() | test.py:25:5:25:26 | Function sety | test.py:38:12:38:15 | ControlFlowNode for objy | self | -| test.py:43:1:43:8 | func() | test.py:25:5:25:26 | Function sety | test.py:43:6:43:7 | ControlFlowNode for IntegerLiteral | position 0 | -| test.py:51:1:51:8 | func() | test.py:16:5:16:30 | Function setvalue | test.py:47:12:47:15 | ControlFlowNode for objx | self | -| test.py:51:1:51:8 | func() | test.py:16:5:16:30 | Function setvalue | test.py:51:6:51:7 | ControlFlowNode for IntegerLiteral | position 0 | -| test.py:51:1:51:8 | func() | test.py:28:5:28:30 | Function setvalue | test.py:49:12:49:15 | ControlFlowNode for objy | self | -| test.py:51:1:51:8 | func() | test.py:28:5:28:30 | Function setvalue | test.py:51:6:51:7 | ControlFlowNode for IntegerLiteral | position 0 | -| test.py:70:1:70:8 | func() | test.py:58:5:58:33 | Function foo | test.py:63:12:63:12 | ControlFlowNode for a | self | -| test.py:70:1:70:8 | func() | test.py:58:5:58:33 | Function foo | test.py:70:6:70:7 | ControlFlowNode for IntegerLiteral | position 0 | -| test.py:70:1:70:8 | func() | test.py:58:5:58:33 | Function foo | test.py:70:6:70:7 | ControlFlowNode for IntegerLiteral | self | +| test.py:32:8:32:23 | CrosstalkTestX() | test.py:9:5:9:23 | Function __init__ | test.py:32:8:32:23 | [pre] CrosstalkTestX() | self | +| test.py:33:8:33:23 | CrosstalkTestY() | test.py:21:5:21:23 | Function __init__ | test.py:33:8:33:23 | [pre] CrosstalkTestY() | self | +| test.py:43:1:43:8 | func() | test.py:13:5:13:26 | Function setx | test.py:36:12:36:15 | objx | self | +| test.py:43:1:43:8 | func() | test.py:13:5:13:26 | Function setx | test.py:43:6:43:7 | IntegerLiteral | position 0 | +| test.py:43:1:43:8 | func() | test.py:25:5:25:26 | Function sety | test.py:38:12:38:15 | objy | self | +| test.py:43:1:43:8 | func() | test.py:25:5:25:26 | Function sety | test.py:43:6:43:7 | IntegerLiteral | position 0 | +| test.py:51:1:51:8 | func() | test.py:16:5:16:30 | Function setvalue | test.py:47:12:47:15 | objx | self | +| test.py:51:1:51:8 | func() | test.py:16:5:16:30 | Function setvalue | test.py:51:6:51:7 | IntegerLiteral | position 0 | +| test.py:51:1:51:8 | func() | test.py:28:5:28:30 | Function setvalue | test.py:49:12:49:15 | objy | self | +| test.py:51:1:51:8 | func() | test.py:28:5:28:30 | Function setvalue | test.py:51:6:51:7 | IntegerLiteral | position 0 | +| test.py:70:1:70:8 | func() | test.py:58:5:58:33 | Function foo | test.py:63:12:63:12 | a | self | +| test.py:70:1:70:8 | func() | test.py:58:5:58:33 | Function foo | test.py:70:6:70:7 | IntegerLiteral | position 0 | +| test.py:70:1:70:8 | func() | test.py:58:5:58:33 | Function foo | test.py:70:6:70:7 | IntegerLiteral | self | diff --git a/python/ql/test/library-tests/dataflow/coverage/argumentRoutingTest.ql b/python/ql/test/library-tests/dataflow/coverage/argumentRoutingTest.ql index 7851dc4dda80..bd5ad3059f9b 100644 --- a/python/ql/test/library-tests/dataflow/coverage/argumentRoutingTest.ql +++ b/python/ql/test/library-tests/dataflow/coverage/argumentRoutingTest.ql @@ -1,4 +1,6 @@ import python +private import semmle.python.controlflow.internal.Cfg as Cfg +private import semmle.python.dataflow.new.internal.SsaImpl as SsaImpl import semmle.python.dataflow.new.DataFlow private import semmle.python.dataflow.new.internal.DataFlowPrivate as DataFlowPrivate import utils.test.dataflow.RoutingTest @@ -26,21 +28,21 @@ class ArgNumber extends int { module ArgumentRoutingConfig implements DataFlow::ConfigSig { additional predicate isArgSource(DataFlow::Node node, ArgNumber argNumber) { - node.(DataFlow::CfgNode).getNode().(NameNode).getId() = "arg" + argNumber + node.(DataFlow::CfgNode).getNode().(Cfg::NameNode).getId() = "arg" + argNumber } predicate isSource(DataFlow::Node node) { isArgSource(node, _) } additional predicate isGoodSink(DataFlow::Node node, ArgNumber argNumber) { - exists(CallNode call | - call.getFunction().(NameNode).getId() = "SINK" + argNumber and + exists(Cfg::CallNode call | + call.getFunction().(Cfg::NameNode).getId() = "SINK" + argNumber and node.(DataFlow::CfgNode).getNode() = call.getAnArg() ) } additional predicate isBadSink(DataFlow::Node node, ArgNumber argNumber) { - exists(CallNode call | - call.getFunction().(NameNode).getId() = "SINK" + argNumber + "_F" and + exists(Cfg::CallNode call | + call.getFunction().(Cfg::NameNode).getId() = "SINK" + argNumber + "_F" and node.(DataFlow::CfgNode).getNode() = call.getAnArg() ) } @@ -60,17 +62,17 @@ module ArgumentRoutingFlow = DataFlow::Global; module Argument1ExtraRoutingConfig implements DataFlow::ConfigSig { predicate isSource(DataFlow::Node node) { - exists(AssignmentDefinition def, DataFlow::CallCfgNode call | + exists(SsaImpl::AssignmentDefinition def, DataFlow::CallCfgNode call | def.getDefiningNode() = node.(DataFlow::CfgNode).getNode() and def.getValue() = call.getNode() and - call.getFunction().asCfgNode().(NameNode).getId().matches("With\\_%") + call.getFunction().asCfgNode().(Cfg::NameNode).getId().matches("With\\_%") ) and - node.(DataFlow::CfgNode).getNode().(NameNode).getId().matches("with\\_%") + node.(DataFlow::CfgNode).getNode().(Cfg::NameNode).getId().matches("with\\_%") } predicate isSink(DataFlow::Node node) { - exists(CallNode call | - call.getFunction().(NameNode).getId() = "SINK1" and + exists(Cfg::CallNode call | + call.getFunction().(Cfg::NameNode).getId() = "SINK1" and node.(DataFlow::CfgNode).getNode() = call.getAnArg() ) } diff --git a/python/ql/test/library-tests/dataflow/coverage/localFlow.expected b/python/ql/test/library-tests/dataflow/coverage/localFlow.expected index 665fb1aa12b8..247b01764592 100644 --- a/python/ql/test/library-tests/dataflow/coverage/localFlow.expected +++ b/python/ql/test/library-tests/dataflow/coverage/localFlow.expected @@ -1,11 +1,11 @@ -| test.py:41:1:41:33 | Entry definition for SsaSourceVariable NONSOURCE | test.py:42:10:42:18 | ControlFlowNode for NONSOURCE | -| test.py:41:1:41:33 | Entry definition for SsaSourceVariable SINK | test.py:44:5:44:8 | ControlFlowNode for SINK | -| test.py:41:1:41:33 | Entry definition for SsaSourceVariable SOURCE | test.py:42:21:42:26 | ControlFlowNode for SOURCE | -| test.py:42:5:42:5 | ControlFlowNode for x | test.py:43:9:43:9 | ControlFlowNode for x | -| test.py:42:10:42:26 | ControlFlowNode for Tuple | test.py:42:5:42:5 | ControlFlowNode for x | -| test.py:43:5:43:5 | ControlFlowNode for y | test.py:44:10:44:10 | ControlFlowNode for y | -| test.py:43:9:43:12 | ControlFlowNode for Subscript | test.py:43:5:43:5 | ControlFlowNode for y | -| test.py:208:1:208:53 | Entry definition for SsaSourceVariable SINK | test.py:210:5:210:8 | ControlFlowNode for SINK | -| test.py:208:1:208:53 | Entry definition for SsaSourceVariable SOURCE | test.py:209:25:209:30 | ControlFlowNode for SOURCE | -| test.py:209:5:209:5 | ControlFlowNode for x | test.py:210:10:210:10 | ControlFlowNode for x | -| test.py:209:9:209:68 | ControlFlowNode for ListComp | test.py:209:5:209:5 | ControlFlowNode for x | +| test.py:41:1:41:33 | Entry definition for Global Variable NONSOURCE | test.py:42:10:42:18 | NONSOURCE | +| test.py:41:1:41:33 | Entry definition for Global Variable SINK | test.py:44:5:44:8 | SINK | +| test.py:41:1:41:33 | Entry definition for Global Variable SOURCE | test.py:42:21:42:26 | SOURCE | +| test.py:42:5:42:5 | x | test.py:43:9:43:9 | x | +| test.py:42:10:42:26 | Tuple | test.py:42:5:42:5 | x | +| test.py:43:5:43:5 | y | test.py:44:10:44:10 | y | +| test.py:43:9:43:12 | Subscript | test.py:43:5:43:5 | y | +| test.py:208:1:208:53 | Entry definition for Global Variable SINK | test.py:210:5:210:8 | SINK | +| test.py:208:1:208:53 | Entry definition for Global Variable SOURCE | test.py:209:25:209:30 | SOURCE | +| test.py:209:5:209:5 | x | test.py:210:10:210:10 | x | +| test.py:209:9:209:68 | ListComp | test.py:209:5:209:5 | x | diff --git a/python/ql/test/library-tests/dataflow/def-use-flow/def_use_counts.expected b/python/ql/test/library-tests/dataflow/def-use-flow/def_use_counts.expected index 1fe1d1d105a5..a30ed74b89f6 100644 --- a/python/ql/test/library-tests/dataflow/def-use-flow/def_use_counts.expected +++ b/python/ql/test/library-tests/dataflow/def-use-flow/def_use_counts.expected @@ -1,31 +1,41 @@ def_count | 4 | def -| def_use_flow.py:10:5:10:5 | Essa node definition | -| def_use_flow.py:17:11:17:11 | Essa node definition | -| def_use_flow.py:19:9:19:9 | Essa node definition | -| def_use_flow.py:21:7:21:7 | Essa node definition | +| def_use_flow.py:10:5:10:5 | SSA def(Local Variable x) | +| def_use_flow.py:17:11:17:11 | SSA def(Local Variable x) | +| def_use_flow.py:19:9:19:9 | SSA def(Local Variable x) | +| def_use_flow.py:21:7:21:7 | SSA def(Local Variable x) | implicit_use_count -| 0 | +| 1 | implicit_use +| def_use_flow.py:9:1:9:12 | Normal Exit | source_use_count | 3 | source_use -| def_use_flow.py:28:15:28:15 | ControlFlowNode for x | -| def_use_flow.py:30:13:30:13 | ControlFlowNode for x | -| def_use_flow.py:32:11:32:11 | ControlFlowNode for x | +| def_use_flow.py:28:15:28:15 | x | +| def_use_flow.py:30:13:30:13 | x | +| def_use_flow.py:32:11:32:11 | x | def_use_edge_count -| 12 | +| 21 | def_use_edge -| def_use_flow.py:10:5:10:5 | SSA variable x | def_use_flow.py:28:15:28:15 | ControlFlowNode for x | -| def_use_flow.py:10:5:10:5 | SSA variable x | def_use_flow.py:30:13:30:13 | ControlFlowNode for x | -| def_use_flow.py:10:5:10:5 | SSA variable x | def_use_flow.py:32:11:32:11 | ControlFlowNode for x | -| def_use_flow.py:17:11:17:11 | SSA variable x | def_use_flow.py:28:15:28:15 | ControlFlowNode for x | -| def_use_flow.py:17:11:17:11 | SSA variable x | def_use_flow.py:30:13:30:13 | ControlFlowNode for x | -| def_use_flow.py:17:11:17:11 | SSA variable x | def_use_flow.py:32:11:32:11 | ControlFlowNode for x | -| def_use_flow.py:19:9:19:9 | SSA variable x | def_use_flow.py:28:15:28:15 | ControlFlowNode for x | -| def_use_flow.py:19:9:19:9 | SSA variable x | def_use_flow.py:30:13:30:13 | ControlFlowNode for x | -| def_use_flow.py:19:9:19:9 | SSA variable x | def_use_flow.py:32:11:32:11 | ControlFlowNode for x | -| def_use_flow.py:21:7:21:7 | SSA variable x | def_use_flow.py:28:15:28:15 | ControlFlowNode for x | -| def_use_flow.py:21:7:21:7 | SSA variable x | def_use_flow.py:30:13:30:13 | ControlFlowNode for x | -| def_use_flow.py:21:7:21:7 | SSA variable x | def_use_flow.py:32:11:32:11 | ControlFlowNode for x | +| def_use_flow.py:10:5:10:5 | SSA def(Local Variable x) | def_use_flow.py:28:15:28:15 | x | +| def_use_flow.py:10:5:10:5 | SSA def(Local Variable x) | def_use_flow.py:30:13:30:13 | x | +| def_use_flow.py:10:5:10:5 | SSA def(Local Variable x) | def_use_flow.py:32:11:32:11 | x | +| def_use_flow.py:12:5:12:17 | SSA phi(Local Variable x) | def_use_flow.py:28:15:28:15 | x | +| def_use_flow.py:12:5:12:17 | SSA phi(Local Variable x) | def_use_flow.py:30:13:30:13 | x | +| def_use_flow.py:12:5:12:17 | SSA phi(Local Variable x) | def_use_flow.py:32:11:32:11 | x | +| def_use_flow.py:13:7:13:19 | SSA phi(Local Variable x) | def_use_flow.py:28:15:28:15 | x | +| def_use_flow.py:13:7:13:19 | SSA phi(Local Variable x) | def_use_flow.py:30:13:30:13 | x | +| def_use_flow.py:13:7:13:19 | SSA phi(Local Variable x) | def_use_flow.py:32:11:32:11 | x | +| def_use_flow.py:14:9:14:21 | SSA phi(Local Variable x) | def_use_flow.py:28:15:28:15 | x | +| def_use_flow.py:14:9:14:21 | SSA phi(Local Variable x) | def_use_flow.py:30:13:30:13 | x | +| def_use_flow.py:14:9:14:21 | SSA phi(Local Variable x) | def_use_flow.py:32:11:32:11 | x | +| def_use_flow.py:17:11:17:11 | SSA def(Local Variable x) | def_use_flow.py:28:15:28:15 | x | +| def_use_flow.py:17:11:17:11 | SSA def(Local Variable x) | def_use_flow.py:30:13:30:13 | x | +| def_use_flow.py:17:11:17:11 | SSA def(Local Variable x) | def_use_flow.py:32:11:32:11 | x | +| def_use_flow.py:19:9:19:9 | SSA def(Local Variable x) | def_use_flow.py:28:15:28:15 | x | +| def_use_flow.py:19:9:19:9 | SSA def(Local Variable x) | def_use_flow.py:30:13:30:13 | x | +| def_use_flow.py:19:9:19:9 | SSA def(Local Variable x) | def_use_flow.py:32:11:32:11 | x | +| def_use_flow.py:21:7:21:7 | SSA def(Local Variable x) | def_use_flow.py:28:15:28:15 | x | +| def_use_flow.py:21:7:21:7 | SSA def(Local Variable x) | def_use_flow.py:30:13:30:13 | x | +| def_use_flow.py:21:7:21:7 | SSA def(Local Variable x) | def_use_flow.py:32:11:32:11 | x | diff --git a/python/ql/test/library-tests/dataflow/def-use-flow/def_use_counts.ql b/python/ql/test/library-tests/dataflow/def-use-flow/def_use_counts.ql index 0f0d5953a367..1e461a7caf1a 100644 --- a/python/ql/test/library-tests/dataflow/def-use-flow/def_use_counts.ql +++ b/python/ql/test/library-tests/dataflow/def-use-flow/def_use_counts.ql @@ -1,36 +1,38 @@ import python +private import semmle.python.controlflow.internal.Cfg as Cfg +private import semmle.python.dataflow.new.internal.SsaImpl as SsaImpl private import semmle.python.dataflow.new.internal.DataFlowPrivate query int def_count() { - exists(SsaSourceVariable x | x.getName() = "x" | - result = count(EssaNodeDefinition def | def.getSourceVariable() = x) + exists(SsaImpl::SsaSourceVariable x | x.getName() = "x" | + result = count(SsaImpl::EssaNodeDefinition def | def.getSourceVariable() = x) ) } -query EssaNodeDefinition def() { - exists(SsaSourceVariable x | x.getName() = "x" | result.getSourceVariable() = x) +query SsaImpl::EssaNodeDefinition def() { + exists(SsaImpl::SsaSourceVariable x | x.getName() = "x" | result.getSourceVariable() = x) } query int implicit_use_count() { - exists(SsaSourceVariable x | x.getName() = "x" | result = count(x.getAnImplicitUse())) + exists(SsaImpl::SsaSourceVariable x | x.getName() = "x" | result = count(x.getAnImplicitUse())) } -query ControlFlowNode implicit_use() { - exists(SsaSourceVariable x | x.getName() = "x" | result = x.getAnImplicitUse()) +query Cfg::ControlFlowNode implicit_use() { + exists(SsaImpl::SsaSourceVariable x | x.getName() = "x" | result = x.getAnImplicitUse()) } query int source_use_count() { - exists(SsaSourceVariable x | x.getName() = "x" | result = count(x.getASourceUse())) + exists(SsaImpl::SsaSourceVariable x | x.getName() = "x" | result = count(x.getASourceUse())) } -query ControlFlowNode source_use() { - exists(SsaSourceVariable x | x.getName() = "x" | result = x.getASourceUse()) +query Cfg::ControlFlowNode source_use() { + exists(SsaImpl::SsaSourceVariable x | x.getName() = "x" | result = x.getASourceUse()) } query int def_use_edge_count() { - exists(SsaSourceVariable x | x.getName() = "x" | + exists(SsaImpl::SsaSourceVariable x | x.getName() = "x" | result = - count(EssaVariable v, NameNode use | + count(SsaImpl::EssaVariable v, Cfg::NameNode use | v.getSourceVariable() = x and use = x.getAUse() and LocalFlow::defToFirstUse(v, use) @@ -38,8 +40,8 @@ query int def_use_edge_count() { ) } -query predicate def_use_edge(EssaVariable v, NameNode use) { - exists(SsaSourceVariable x | x.getName() = "x" | +query predicate def_use_edge(SsaImpl::EssaVariable v, Cfg::NameNode use) { + exists(SsaImpl::SsaSourceVariable x | x.getName() = "x" | v.getSourceVariable() = x and use = x.getAUse() and LocalFlow::defToFirstUse(v, use) diff --git a/python/ql/test/library-tests/dataflow/enclosing-callable/EnclosingCallable.expected b/python/ql/test/library-tests/dataflow/enclosing-callable/EnclosingCallable.expected index c168ea8c3916..3f81bd41846e 100644 --- a/python/ql/test/library-tests/dataflow/enclosing-callable/EnclosingCallable.expected +++ b/python/ql/test/library-tests/dataflow/enclosing-callable/EnclosingCallable.expected @@ -1,24 +1,24 @@ -| class_example.py:0:0:0:0 | Module class_example | class_example.py:1:1:1:3 | ControlFlowNode for wat | -| class_example.py:0:0:0:0 | Module class_example | class_example.py:1:7:1:7 | ControlFlowNode for IntegerLiteral | -| class_example.py:0:0:0:0 | Module class_example | class_example.py:3:1:3:10 | ControlFlowNode for ClassExpr | -| class_example.py:0:0:0:0 | Module class_example | class_example.py:3:7:3:9 | ControlFlowNode for Wat | -| class_example.py:0:0:0:0 | Module class_example | class_example.py:4:5:4:7 | ControlFlowNode for wat | -| class_example.py:0:0:0:0 | Module class_example | class_example.py:4:11:4:11 | ControlFlowNode for IntegerLiteral | -| class_example.py:0:0:0:0 | Module class_example | class_example.py:5:5:5:9 | ControlFlowNode for print | -| class_example.py:0:0:0:0 | Module class_example | class_example.py:5:5:5:26 | ControlFlowNode for print() | -| class_example.py:0:0:0:0 | Module class_example | class_example.py:5:11:5:20 | ControlFlowNode for StringLiteral | -| class_example.py:0:0:0:0 | Module class_example | class_example.py:5:23:5:25 | ControlFlowNode for wat | -| class_example.py:0:0:0:0 | Module class_example | class_example.py:7:1:7:5 | ControlFlowNode for print | -| class_example.py:0:0:0:0 | Module class_example | class_example.py:7:1:7:23 | ControlFlowNode for print() | -| class_example.py:0:0:0:0 | Module class_example | class_example.py:7:7:7:17 | ControlFlowNode for StringLiteral | -| class_example.py:0:0:0:0 | Module class_example | class_example.py:7:20:7:22 | ControlFlowNode for wat | -| generator.py:0:0:0:0 | Module generator | generator.py:1:1:1:23 | ControlFlowNode for FunctionExpr | -| generator.py:0:0:0:0 | Module generator | generator.py:1:5:1:18 | ControlFlowNode for generator_func | -| generator.py:1:1:1:23 | Function generator_func | generator.py:1:20:1:21 | ControlFlowNode for xs | -| generator.py:1:1:1:23 | Function generator_func | generator.py:2:12:2:26 | ControlFlowNode for ListComp | -| generator.py:1:1:1:23 | Function generator_func | generator.py:2:24:2:25 | ControlFlowNode for xs | -| generator.py:2:12:2:26 | Function listcomp | generator.py:2:12:2:26 | ControlFlowNode for .0 | -| generator.py:2:12:2:26 | Function listcomp | generator.py:2:12:2:26 | ControlFlowNode for .0 | -| generator.py:2:12:2:26 | Function listcomp | generator.py:2:13:2:13 | ControlFlowNode for Yield | -| generator.py:2:12:2:26 | Function listcomp | generator.py:2:13:2:13 | ControlFlowNode for x | -| generator.py:2:12:2:26 | Function listcomp | generator.py:2:19:2:19 | ControlFlowNode for x | +| class_example.py:0:0:0:0 | Module class_example | class_example.py:1:1:1:3 | wat | +| class_example.py:0:0:0:0 | Module class_example | class_example.py:1:7:1:7 | IntegerLiteral | +| class_example.py:0:0:0:0 | Module class_example | class_example.py:3:1:3:10 | ClassExpr | +| class_example.py:0:0:0:0 | Module class_example | class_example.py:3:7:3:9 | Wat | +| class_example.py:0:0:0:0 | Module class_example | class_example.py:4:5:4:7 | wat | +| class_example.py:0:0:0:0 | Module class_example | class_example.py:4:11:4:11 | IntegerLiteral | +| class_example.py:0:0:0:0 | Module class_example | class_example.py:5:5:5:9 | print | +| class_example.py:0:0:0:0 | Module class_example | class_example.py:5:5:5:26 | print() | +| class_example.py:0:0:0:0 | Module class_example | class_example.py:5:11:5:20 | StringLiteral | +| class_example.py:0:0:0:0 | Module class_example | class_example.py:5:23:5:25 | wat | +| class_example.py:0:0:0:0 | Module class_example | class_example.py:7:1:7:5 | print | +| class_example.py:0:0:0:0 | Module class_example | class_example.py:7:1:7:23 | print() | +| class_example.py:0:0:0:0 | Module class_example | class_example.py:7:7:7:17 | StringLiteral | +| class_example.py:0:0:0:0 | Module class_example | class_example.py:7:20:7:22 | wat | +| generator.py:0:0:0:0 | Module generator | generator.py:1:1:1:23 | FunctionExpr | +| generator.py:0:0:0:0 | Module generator | generator.py:1:5:1:18 | generator_func | +| generator.py:1:1:1:23 | Function generator_func | generator.py:1:20:1:21 | xs | +| generator.py:1:1:1:23 | Function generator_func | generator.py:2:12:2:26 | ListComp | +| generator.py:1:1:1:23 | Function generator_func | generator.py:2:24:2:25 | xs | +| generator.py:2:12:2:26 | Function listcomp | generator.py:2:12:2:26 | .0 | +| generator.py:2:12:2:26 | Function listcomp | generator.py:2:12:2:26 | .0 | +| generator.py:2:12:2:26 | Function listcomp | generator.py:2:13:2:13 | Yield | +| generator.py:2:12:2:26 | Function listcomp | generator.py:2:13:2:13 | x | +| generator.py:2:12:2:26 | Function listcomp | generator.py:2:19:2:19 | x | diff --git a/python/ql/test/library-tests/dataflow/fieldflow/UnresolvedCalls.expected b/python/ql/test/library-tests/dataflow/fieldflow/UnresolvedCalls.expected index 593b6e118874..784e033c1f82 100644 --- a/python/ql/test/library-tests/dataflow/fieldflow/UnresolvedCalls.expected +++ b/python/ql/test/library-tests/dataflow/fieldflow/UnresolvedCalls.expected @@ -1,4 +1,4 @@ -| test.py:4:17:4:60 | ControlFlowNode for Attribute() | Unexpected result: unresolved_call=os.path.dirname(..) | -| test.py:4:33:4:59 | ControlFlowNode for Attribute() | Unexpected result: unresolved_call=os.path.dirname(..) | -| test_dict.py:4:17:4:60 | ControlFlowNode for Attribute() | Unexpected result: unresolved_call=os.path.dirname(..) | -| test_dict.py:4:33:4:59 | ControlFlowNode for Attribute() | Unexpected result: unresolved_call=os.path.dirname(..) | +| test.py:4:17:4:60 | Attribute() | Unexpected result: unresolved_call=os.path.dirname(..) | +| test.py:4:33:4:59 | Attribute() | Unexpected result: unresolved_call=os.path.dirname(..) | +| test_dict.py:4:17:4:60 | Attribute() | Unexpected result: unresolved_call=os.path.dirname(..) | +| test_dict.py:4:33:4:59 | Attribute() | Unexpected result: unresolved_call=os.path.dirname(..) | diff --git a/python/ql/test/library-tests/dataflow/fieldflow/UnresolvedCalls.ql b/python/ql/test/library-tests/dataflow/fieldflow/UnresolvedCalls.ql index 57e8e7f880fd..13c8664cd34c 100644 --- a/python/ql/test/library-tests/dataflow/fieldflow/UnresolvedCalls.ql +++ b/python/ql/test/library-tests/dataflow/fieldflow/UnresolvedCalls.ql @@ -1,9 +1,10 @@ import python +private import semmle.python.controlflow.internal.Cfg as Cfg import utils.test.dataflow.UnresolvedCalls private import semmle.python.dataflow.new.DataFlow module IgnoreDictMethod implements UnresolvedCallExpectationsSig { - predicate unresolvedCall(CallNode call) { + predicate unresolvedCall(Cfg::CallNode call) { DefaultUnresolvedCallExpectations::unresolvedCall(call) and not any(DataFlow::MethodCallNode methodCall | methodCall.getMethodName() in ["get", "setdefault"] diff --git a/python/ql/test/library-tests/dataflow/global-flow/test.py b/python/ql/test/library-tests/dataflow/global-flow/test.py index 2f122364d37e..dde5b80f7399 100644 --- a/python/ql/test/library-tests/dataflow/global-flow/test.py +++ b/python/ql/test/library-tests/dataflow/global-flow/test.py @@ -17,7 +17,7 @@ # Modification by reassignment -g_mod = [] +g_mod = [] # $ SPURIOUS: writes=g_mod # This assignment does not produce any flow, since `g_mod` is immediately reassigned. # The following assignment should not be a `ModuleVariableNode`, diff --git a/python/ql/test/library-tests/dataflow/import-star/global.expected b/python/ql/test/library-tests/dataflow/import-star/global.expected index 95f2481489f3..1110ca22a3cc 100644 --- a/python/ql/test/library-tests/dataflow/import-star/global.expected +++ b/python/ql/test/library-tests/dataflow/import-star/global.expected @@ -1,22 +1,22 @@ -| test3.py:1:17:1:19 | ControlFlowNode for ImportMember | test3.py:1:17:1:19 | ControlFlowNode for foo | -| test3.py:1:17:1:19 | ControlFlowNode for ImportMember | test3.py:2:7:2:9 | ControlFlowNode for foo | -| test3.py:1:17:1:19 | ControlFlowNode for foo | test3.py:2:7:2:9 | ControlFlowNode for foo | -| three.py:1:1:1:3 | ControlFlowNode for foo | test1.py:2:7:2:9 | ControlFlowNode for foo | -| three.py:1:1:1:3 | ControlFlowNode for foo | test3.py:1:17:1:19 | ControlFlowNode for ImportMember | -| three.py:1:1:1:3 | ControlFlowNode for foo | test3.py:1:17:1:19 | ControlFlowNode for foo | -| three.py:1:1:1:3 | ControlFlowNode for foo | test3.py:2:7:2:9 | ControlFlowNode for foo | -| three.py:1:1:1:3 | ControlFlowNode for foo | two.py:2:7:2:9 | ControlFlowNode for foo | -| three.py:1:7:1:7 | ControlFlowNode for IntegerLiteral | test1.py:2:7:2:9 | ControlFlowNode for foo | -| three.py:1:7:1:7 | ControlFlowNode for IntegerLiteral | test3.py:1:17:1:19 | ControlFlowNode for ImportMember | -| three.py:1:7:1:7 | ControlFlowNode for IntegerLiteral | test3.py:1:17:1:19 | ControlFlowNode for foo | -| three.py:1:7:1:7 | ControlFlowNode for IntegerLiteral | test3.py:2:7:2:9 | ControlFlowNode for foo | -| three.py:1:7:1:7 | ControlFlowNode for IntegerLiteral | three.py:1:1:1:3 | ControlFlowNode for foo | -| three.py:1:7:1:7 | ControlFlowNode for IntegerLiteral | two.py:2:7:2:9 | ControlFlowNode for foo | -| trois.py:1:1:1:3 | ControlFlowNode for foo | deux.py:2:7:2:9 | ControlFlowNode for foo | -| trois.py:1:1:1:3 | ControlFlowNode for foo | test2.py:2:7:2:9 | ControlFlowNode for foo | -| trois.py:1:7:1:7 | ControlFlowNode for IntegerLiteral | deux.py:2:7:2:9 | ControlFlowNode for foo | -| trois.py:1:7:1:7 | ControlFlowNode for IntegerLiteral | test2.py:2:7:2:9 | ControlFlowNode for foo | -| trois.py:1:7:1:7 | ControlFlowNode for IntegerLiteral | trois.py:1:1:1:3 | ControlFlowNode for foo | -| two.py:2:7:2:9 | ControlFlowNode for foo | test3.py:1:17:1:19 | ControlFlowNode for ImportMember | -| two.py:2:7:2:9 | ControlFlowNode for foo | test3.py:1:17:1:19 | ControlFlowNode for foo | -| two.py:2:7:2:9 | ControlFlowNode for foo | test3.py:2:7:2:9 | ControlFlowNode for foo | +| test3.py:1:17:1:19 | ImportMember | test3.py:1:17:1:19 | foo | +| test3.py:1:17:1:19 | ImportMember | test3.py:2:7:2:9 | foo | +| test3.py:1:17:1:19 | foo | test3.py:2:7:2:9 | foo | +| three.py:1:1:1:3 | foo | test1.py:2:7:2:9 | foo | +| three.py:1:1:1:3 | foo | test3.py:1:17:1:19 | ImportMember | +| three.py:1:1:1:3 | foo | test3.py:1:17:1:19 | foo | +| three.py:1:1:1:3 | foo | test3.py:2:7:2:9 | foo | +| three.py:1:1:1:3 | foo | two.py:2:7:2:9 | foo | +| three.py:1:7:1:7 | IntegerLiteral | test1.py:2:7:2:9 | foo | +| three.py:1:7:1:7 | IntegerLiteral | test3.py:1:17:1:19 | ImportMember | +| three.py:1:7:1:7 | IntegerLiteral | test3.py:1:17:1:19 | foo | +| three.py:1:7:1:7 | IntegerLiteral | test3.py:2:7:2:9 | foo | +| three.py:1:7:1:7 | IntegerLiteral | three.py:1:1:1:3 | foo | +| three.py:1:7:1:7 | IntegerLiteral | two.py:2:7:2:9 | foo | +| trois.py:1:1:1:3 | foo | deux.py:2:7:2:9 | foo | +| trois.py:1:1:1:3 | foo | test2.py:2:7:2:9 | foo | +| trois.py:1:7:1:7 | IntegerLiteral | deux.py:2:7:2:9 | foo | +| trois.py:1:7:1:7 | IntegerLiteral | test2.py:2:7:2:9 | foo | +| trois.py:1:7:1:7 | IntegerLiteral | trois.py:1:1:1:3 | foo | +| two.py:2:7:2:9 | foo | test3.py:1:17:1:19 | ImportMember | +| two.py:2:7:2:9 | foo | test3.py:1:17:1:19 | foo | +| two.py:2:7:2:9 | foo | test3.py:2:7:2:9 | foo | diff --git a/python/ql/test/library-tests/dataflow/method-calls/test.expected b/python/ql/test/library-tests/dataflow/method-calls/test.expected index 588c934e8597..1f4878f3a7a0 100644 --- a/python/ql/test/library-tests/dataflow/method-calls/test.expected +++ b/python/ql/test/library-tests/dataflow/method-calls/test.expected @@ -1,8 +1,8 @@ conjunctive_lookup -| test.py:6:1:6:6 | ControlFlowNode for meth() | meth() | obj1 | bar | -| test.py:6:1:6:6 | ControlFlowNode for meth() | meth() | obj1 | foo | -| test.py:6:1:6:6 | ControlFlowNode for meth() | meth() | obj2 | bar | -| test.py:6:1:6:6 | ControlFlowNode for meth() | meth() | obj2 | foo | +| test.py:6:1:6:6 | meth() | meth() | obj1 | bar | +| test.py:6:1:6:6 | meth() | meth() | obj1 | foo | +| test.py:6:1:6:6 | meth() | meth() | obj2 | bar | +| test.py:6:1:6:6 | meth() | meth() | obj2 | foo | calls_lookup -| test.py:6:1:6:6 | ControlFlowNode for meth() | meth() | obj1 | foo | -| test.py:6:1:6:6 | ControlFlowNode for meth() | meth() | obj2 | bar | +| test.py:6:1:6:6 | meth() | meth() | obj1 | foo | +| test.py:6:1:6:6 | meth() | meth() | obj2 | bar | diff --git a/python/ql/test/library-tests/dataflow/module-initialization/localFlow.ql b/python/ql/test/library-tests/dataflow/module-initialization/localFlow.ql index e3ca2484e529..b71ef4fcf247 100644 --- a/python/ql/test/library-tests/dataflow/module-initialization/localFlow.ql +++ b/python/ql/test/library-tests/dataflow/module-initialization/localFlow.ql @@ -3,6 +3,7 @@ import python import utils.test.dataflow.FlowTest private import semmle.python.dataflow.new.internal.PrintNode private import semmle.python.dataflow.new.internal.DataFlowPrivate as DP +private import semmle.python.dataflow.new.internal.SsaImpl as SsaImpl module ImportTimeLocalFlowTest implements FlowTestSig { string flowTag() { result = "importTimeFlow" } @@ -11,8 +12,9 @@ module ImportTimeLocalFlowTest implements FlowTestSig { nodeFrom.getLocation().getFile().getBaseName() = "multiphase.py" and // results are displayed next to `nodeTo`, so we need a line to write on nodeTo.getLocation().getStartLine() > 0 and - exists(GlobalSsaVariable g | - nodeTo.asCfgNode() = g.getDefinition().(EssaNodeDefinition).getDefiningNode() + exists(SsaImpl::EssaVariable g | + g.getSourceVariable().getVariable() instanceof GlobalVariable and + nodeTo.asCfgNode() = g.getDefinition().(SsaImpl::EssaNodeDefinition).getDefiningNode() ) and // nodeTo.asVar() instanceof GlobalSsaVariable and DP::PhaseDependentFlow::importTimeStep(nodeFrom, nodeTo) diff --git a/python/ql/test/library-tests/dataflow/regression/custom_dataflow.expected b/python/ql/test/library-tests/dataflow/regression/custom_dataflow.expected index 0ae109d52aea..2fdbbf2b85cc 100644 --- a/python/ql/test/library-tests/dataflow/regression/custom_dataflow.expected +++ b/python/ql/test/library-tests/dataflow/regression/custom_dataflow.expected @@ -1 +1,2 @@ -| test.py:126:13:126:25 | ControlFlowNode for CUSTOM_SOURCE | test.py:130:21:130:21 | ControlFlowNode for t | +| test.py:126:13:126:25 | CUSTOM_SOURCE | test.py:130:21:130:21 | t | +| test.py:136:13:136:25 | CUSTOM_SOURCE | test.py:140:23:140:23 | t | diff --git a/python/ql/test/library-tests/dataflow/regression/custom_dataflow.ql b/python/ql/test/library-tests/dataflow/regression/custom_dataflow.ql index 69cf6def9996..b89d2ddad230 100644 --- a/python/ql/test/library-tests/dataflow/regression/custom_dataflow.ql +++ b/python/ql/test/library-tests/dataflow/regression/custom_dataflow.ql @@ -8,14 +8,17 @@ */ import python +private import semmle.python.controlflow.internal.Cfg as Cfg import semmle.python.dataflow.new.DataFlow module CustomTestConfig implements DataFlow::ConfigSig { - predicate isSource(DataFlow::Node node) { node.asCfgNode().(NameNode).getId() = "CUSTOM_SOURCE" } + predicate isSource(DataFlow::Node node) { + node.asCfgNode().(Cfg::NameNode).getId() = "CUSTOM_SOURCE" + } predicate isSink(DataFlow::Node node) { - exists(CallNode call | - call.getFunction().(NameNode).getId() in ["CUSTOM_SINK", "CUSTOM_SINK_F"] and + exists(Cfg::CallNode call | + call.getFunction().(Cfg::NameNode).getId() in ["CUSTOM_SINK", "CUSTOM_SINK_F"] and node.asCfgNode() = call.getAnArg() ) } diff --git a/python/ql/test/library-tests/dataflow/regression/dataflow.expected b/python/ql/test/library-tests/dataflow/regression/dataflow.expected index c8ffed514463..eccdb62cdc70 100644 --- a/python/ql/test/library-tests/dataflow/regression/dataflow.expected +++ b/python/ql/test/library-tests/dataflow/regression/dataflow.expected @@ -1,26 +1,28 @@ -| module.py:1:13:1:18 | ControlFlowNode for SOURCE | test.py:89:10:89:10 | ControlFlowNode for t | -| module.py:1:13:1:18 | ControlFlowNode for SOURCE | test.py:106:10:106:14 | ControlFlowNode for Attribute | -| module.py:1:13:1:18 | ControlFlowNode for SOURCE | test.py:111:10:111:12 | ControlFlowNode for Attribute | -| module.py:1:13:1:18 | ControlFlowNode for SOURCE | test.py:156:6:156:11 | ControlFlowNode for unsafe | -| module.py:6:12:6:17 | ControlFlowNode for SOURCE | test.py:101:10:101:10 | ControlFlowNode for t | -| test.py:3:10:3:15 | ControlFlowNode for SOURCE | test.py:3:10:3:15 | ControlFlowNode for SOURCE | -| test.py:6:9:6:14 | ControlFlowNode for SOURCE | test.py:7:10:7:10 | ControlFlowNode for s | -| test.py:10:12:10:17 | ControlFlowNode for SOURCE | test.py:13:10:13:12 | ControlFlowNode for arg | -| test.py:10:12:10:17 | ControlFlowNode for SOURCE | test.py:17:10:17:10 | ControlFlowNode for t | -| test.py:20:9:20:14 | ControlFlowNode for SOURCE | test.py:13:10:13:12 | ControlFlowNode for arg | -| test.py:37:13:37:18 | ControlFlowNode for SOURCE | test.py:41:14:41:14 | ControlFlowNode for t | -| test.py:62:13:62:18 | ControlFlowNode for SOURCE | test.py:13:10:13:12 | ControlFlowNode for arg | -| test.py:67:13:67:18 | ControlFlowNode for SOURCE | test.py:13:10:13:12 | ControlFlowNode for arg | -| test.py:76:9:76:14 | ControlFlowNode for SOURCE | test.py:78:10:78:10 | ControlFlowNode for t | -| test.py:128:13:128:18 | ControlFlowNode for SOURCE | test.py:132:14:132:14 | ControlFlowNode for t | -| test.py:159:10:159:15 | ControlFlowNode for SOURCE | test.py:160:14:160:14 | ControlFlowNode for t | -| test.py:163:9:163:14 | ControlFlowNode for SOURCE | test.py:165:12:165:12 | ControlFlowNode for s | -| test.py:178:9:178:14 | ControlFlowNode for SOURCE | test.py:180:14:180:14 | ControlFlowNode for t | -| test.py:178:9:178:14 | ControlFlowNode for SOURCE | test.py:182:16:182:16 | ControlFlowNode for t | -| test.py:178:9:178:14 | ControlFlowNode for SOURCE | test.py:184:16:184:16 | ControlFlowNode for t | -| test.py:178:9:178:14 | ControlFlowNode for SOURCE | test.py:186:14:186:14 | ControlFlowNode for t | -| test.py:195:9:195:14 | ControlFlowNode for SOURCE | test.py:197:14:197:14 | ControlFlowNode for t | -| test.py:195:9:195:14 | ControlFlowNode for SOURCE | test.py:199:14:199:14 | ControlFlowNode for t | -| test.py:202:10:202:15 | ControlFlowNode for SOURCE | test.py:204:14:204:14 | ControlFlowNode for i | -| test.py:202:10:202:15 | ControlFlowNode for SOURCE | test.py:205:10:205:10 | ControlFlowNode for i | -| test.py:208:12:208:17 | ControlFlowNode for SOURCE | test.py:214:14:214:14 | ControlFlowNode for x | +| module.py:1:13:1:18 | SOURCE | test.py:89:10:89:10 | t | +| module.py:1:13:1:18 | SOURCE | test.py:106:10:106:14 | Attribute | +| module.py:1:13:1:18 | SOURCE | test.py:111:10:111:12 | Attribute | +| module.py:1:13:1:18 | SOURCE | test.py:156:6:156:11 | unsafe | +| module.py:6:12:6:17 | SOURCE | test.py:101:10:101:10 | t | +| test.py:3:10:3:15 | SOURCE | test.py:3:10:3:15 | SOURCE | +| test.py:6:9:6:14 | SOURCE | test.py:7:10:7:10 | s | +| test.py:10:12:10:17 | SOURCE | test.py:13:10:13:12 | arg | +| test.py:10:12:10:17 | SOURCE | test.py:17:10:17:10 | t | +| test.py:20:9:20:14 | SOURCE | test.py:13:10:13:12 | arg | +| test.py:31:13:31:18 | SOURCE | test.py:33:16:33:16 | t | +| test.py:37:13:37:18 | SOURCE | test.py:41:14:41:14 | t | +| test.py:62:13:62:18 | SOURCE | test.py:13:10:13:12 | arg | +| test.py:67:13:67:18 | SOURCE | test.py:13:10:13:12 | arg | +| test.py:76:9:76:14 | SOURCE | test.py:78:10:78:10 | t | +| test.py:128:13:128:18 | SOURCE | test.py:132:14:132:14 | t | +| test.py:138:13:138:18 | SOURCE | test.py:142:16:142:16 | t | +| test.py:159:10:159:15 | SOURCE | test.py:160:14:160:14 | t | +| test.py:163:9:163:14 | SOURCE | test.py:165:12:165:12 | s | +| test.py:178:9:178:14 | SOURCE | test.py:180:14:180:14 | t | +| test.py:178:9:178:14 | SOURCE | test.py:182:16:182:16 | t | +| test.py:178:9:178:14 | SOURCE | test.py:184:16:184:16 | t | +| test.py:178:9:178:14 | SOURCE | test.py:186:14:186:14 | t | +| test.py:195:9:195:14 | SOURCE | test.py:197:14:197:14 | t | +| test.py:195:9:195:14 | SOURCE | test.py:199:14:199:14 | t | +| test.py:202:10:202:15 | SOURCE | test.py:204:14:204:14 | i | +| test.py:202:10:202:15 | SOURCE | test.py:205:10:205:10 | i | +| test.py:208:12:208:17 | SOURCE | test.py:214:14:214:14 | x | diff --git a/python/ql/test/library-tests/dataflow/strange-essaflow/testFlow.expected b/python/ql/test/library-tests/dataflow/strange-essaflow/testFlow.expected index bff38b71fc96..88315c9a13f5 100644 --- a/python/ql/test/library-tests/dataflow/strange-essaflow/testFlow.expected +++ b/python/ql/test/library-tests/dataflow/strange-essaflow/testFlow.expected @@ -1,6 +1,6 @@ os_import -| test.py:2:8:2:9 | ControlFlowNode for os | +| test.py:2:8:2:9 | os | flowstep jumpStep -| test.py:2:8:2:9 | ControlFlowNode for os | test.py:0:0:0:0 | ModuleVariableNode in Module test for os | +| test.py:2:8:2:9 | os | test.py:0:0:0:0 | ModuleVariableNode in Module test for os | essaFlowStep diff --git a/python/ql/test/library-tests/dataflow/strange-essaflow/testFlow.ql b/python/ql/test/library-tests/dataflow/strange-essaflow/testFlow.ql index 056e6ae815af..0f80fc3b89b0 100644 --- a/python/ql/test/library-tests/dataflow/strange-essaflow/testFlow.ql +++ b/python/ql/test/library-tests/dataflow/strange-essaflow/testFlow.ql @@ -1,11 +1,12 @@ import python import semmle.python.dataflow.new.DataFlow private import semmle.python.dataflow.new.internal.DataFlowPrivate as DataFlowPrivate +private import semmle.python.dataflow.new.internal.SsaImpl as SsaImpl /** Gets the `CfgNode` that holds the module imported by the fully qualified module name `name`. */ DataFlow::CfgNode module_import(string name) { - exists(Variable var, AssignmentDefinition def, Import imp, Alias alias | - var = def.getSourceVariable() and + exists(Variable var, SsaImpl::AssignmentDefinition def, Import imp, Alias alias | + var = def.getSourceVariable().getVariable() and result.getNode() = def.getDefiningNode() and alias = imp.getAName() and alias.getAsname() = var.getAStore() diff --git a/python/ql/test/library-tests/dataflow/summaries/TestSummaries.qll b/python/ql/test/library-tests/dataflow/summaries/TestSummaries.qll index 14d68455d621..87e1d7871010 100644 --- a/python/ql/test/library-tests/dataflow/summaries/TestSummaries.qll +++ b/python/ql/test/library-tests/dataflow/summaries/TestSummaries.qll @@ -2,6 +2,7 @@ overlay[local?] module; private import python +private import semmle.python.controlflow.internal.Cfg as Cfg private import semmle.python.dataflow.new.FlowSummary private import semmle.python.ApiGraphs @@ -17,7 +18,7 @@ module RecursionGuard { RecursionGuard() { this = "RecursionGuard" } override DataFlow::CallCfgNode getACall() { - result.getFunction().asCfgNode().(NameNode).getId() = this and + result.getFunction().asCfgNode().(Cfg::NameNode).getId() = this and (TT::callStep(_, _) implies any()) } @@ -33,7 +34,7 @@ private class SummarizedCallableIdentity extends SummarizedCallable::Range { SummarizedCallableIdentity() { this = "identity" } override DataFlow::CallCfgNode getACall() { - result.getFunction().asCfgNode().(NameNode).getId() = this + result.getFunction().asCfgNode().(Cfg::NameNode).getId() = this } override DataFlow::ArgumentNode getACallback() { result.asExpr().(Name).getId() = this } @@ -50,7 +51,7 @@ private class SummarizedCallableApplyLambda extends SummarizedCallable::Range { SummarizedCallableApplyLambda() { this = "apply_lambda" } override DataFlow::CallCfgNode getACall() { - result.getFunction().asCfgNode().(NameNode).getId() = this + result.getFunction().asCfgNode().(Cfg::NameNode).getId() = this } override DataFlow::ArgumentNode getACallback() { result.asExpr().(Name).getId() = this } @@ -70,7 +71,7 @@ private class SummarizedCallableReversed extends SummarizedCallable::Range { SummarizedCallableReversed() { this = "list_reversed" } override DataFlow::CallCfgNode getACall() { - result.getFunction().asCfgNode().(NameNode).getId() = this + result.getFunction().asCfgNode().(Cfg::NameNode).getId() = this } override DataFlow::ArgumentNode getACallback() { result.asExpr().(Name).getId() = this } @@ -86,7 +87,7 @@ private class SummarizedCallableMap extends SummarizedCallable::Range { SummarizedCallableMap() { this = "list_map" } override DataFlow::CallCfgNode getACall() { - result.getFunction().asCfgNode().(NameNode).getId() = this + result.getFunction().asCfgNode().(Cfg::NameNode).getId() = this } override DataFlow::ArgumentNode getACallback() { result.asExpr().(Name).getId() = this } @@ -106,7 +107,7 @@ private class SummarizedCallableAppend extends SummarizedCallable::Range { SummarizedCallableAppend() { this = "append_to_list" } override DataFlow::CallCfgNode getACall() { - result.getFunction().asCfgNode().(NameNode).getId() = this + result.getFunction().asCfgNode().(Cfg::NameNode).getId() = this } override DataFlow::ArgumentNode getACallback() { result.asExpr().(Name).getId() = this } diff --git a/python/ql/test/library-tests/dataflow/summaries/summaries.expected b/python/ql/test/library-tests/dataflow/summaries/summaries.expected index fbc09b5fa6e6..2b3c0c8f446d 100644 --- a/python/ql/test/library-tests/dataflow/summaries/summaries.expected +++ b/python/ql/test/library-tests/dataflow/summaries/summaries.expected @@ -1,108 +1,114 @@ edges -| summaries.py:32:1:32:7 | ControlFlowNode for tainted | summaries.py:33:6:33:12 | ControlFlowNode for tainted | provenance | | -| summaries.py:32:11:32:26 | ControlFlowNode for identity() | summaries.py:32:1:32:7 | ControlFlowNode for tainted | provenance | | -| summaries.py:32:20:32:25 | ControlFlowNode for SOURCE | summaries.py:32:11:32:26 | ControlFlowNode for identity() | provenance | identity | -| summaries.py:36:1:36:14 | ControlFlowNode for tainted_lambda | summaries.py:37:6:37:19 | ControlFlowNode for tainted_lambda | provenance | | -| summaries.py:36:18:36:54 | ControlFlowNode for apply_lambda() | summaries.py:36:1:36:14 | ControlFlowNode for tainted_lambda | provenance | | -| summaries.py:36:38:36:38 | ControlFlowNode for x | summaries.py:36:41:36:45 | ControlFlowNode for BinaryExpr | provenance | | -| summaries.py:36:48:36:53 | ControlFlowNode for SOURCE | summaries.py:36:18:36:54 | ControlFlowNode for apply_lambda() | provenance | apply_lambda | -| summaries.py:36:48:36:53 | ControlFlowNode for SOURCE | summaries.py:36:38:36:38 | ControlFlowNode for x | provenance | apply_lambda | -| summaries.py:44:1:44:12 | ControlFlowNode for tainted_list [List element] | summaries.py:45:6:45:17 | ControlFlowNode for tainted_list [List element] | provenance | | -| summaries.py:44:16:44:33 | ControlFlowNode for reversed() [List element] | summaries.py:44:1:44:12 | ControlFlowNode for tainted_list [List element] | provenance | | -| summaries.py:44:25:44:32 | ControlFlowNode for List [List element] | summaries.py:44:16:44:33 | ControlFlowNode for reversed() [List element] | provenance | builtins.reversed | -| summaries.py:44:26:44:31 | ControlFlowNode for SOURCE | summaries.py:44:25:44:32 | ControlFlowNode for List [List element] | provenance | | -| summaries.py:45:6:45:17 | ControlFlowNode for tainted_list [List element] | summaries.py:45:6:45:20 | ControlFlowNode for Subscript | provenance | | -| summaries.py:48:15:48:15 | ControlFlowNode for x | summaries.py:49:12:49:18 | ControlFlowNode for BinaryExpr | provenance | | -| summaries.py:51:1:51:14 | ControlFlowNode for tainted_mapped [List element] | summaries.py:52:6:52:19 | ControlFlowNode for tainted_mapped [List element] | provenance | | -| summaries.py:51:18:51:46 | ControlFlowNode for list_map() [List element] | summaries.py:51:1:51:14 | ControlFlowNode for tainted_mapped [List element] | provenance | | -| summaries.py:51:38:51:45 | ControlFlowNode for List [List element] | summaries.py:48:15:48:15 | ControlFlowNode for x | provenance | list_map | -| summaries.py:51:38:51:45 | ControlFlowNode for List [List element] | summaries.py:51:18:51:46 | ControlFlowNode for list_map() [List element] | provenance | list_map | -| summaries.py:51:39:51:44 | ControlFlowNode for SOURCE | summaries.py:51:38:51:45 | ControlFlowNode for List [List element] | provenance | | -| summaries.py:52:6:52:19 | ControlFlowNode for tainted_mapped [List element] | summaries.py:52:6:52:22 | ControlFlowNode for Subscript | provenance | | -| summaries.py:54:23:54:23 | ControlFlowNode for x | summaries.py:55:12:55:12 | ControlFlowNode for x | provenance | | -| summaries.py:57:1:57:23 | ControlFlowNode for tainted_mapped_explicit [List element] | summaries.py:58:6:58:28 | ControlFlowNode for tainted_mapped_explicit [List element] | provenance | | -| summaries.py:57:27:57:63 | ControlFlowNode for list_map() [List element] | summaries.py:57:1:57:23 | ControlFlowNode for tainted_mapped_explicit [List element] | provenance | | -| summaries.py:57:55:57:62 | ControlFlowNode for List [List element] | summaries.py:54:23:54:23 | ControlFlowNode for x | provenance | list_map | -| summaries.py:57:55:57:62 | ControlFlowNode for List [List element] | summaries.py:57:27:57:63 | ControlFlowNode for list_map() [List element] | provenance | list_map | -| summaries.py:57:56:57:61 | ControlFlowNode for SOURCE | summaries.py:57:55:57:62 | ControlFlowNode for List [List element] | provenance | | -| summaries.py:58:6:58:28 | ControlFlowNode for tainted_mapped_explicit [List element] | summaries.py:58:6:58:31 | ControlFlowNode for Subscript | provenance | | -| summaries.py:60:1:60:22 | ControlFlowNode for tainted_mapped_summary [List element] | summaries.py:61:6:61:27 | ControlFlowNode for tainted_mapped_summary [List element] | provenance | | -| summaries.py:60:26:60:53 | ControlFlowNode for list_map() [List element] | summaries.py:60:1:60:22 | ControlFlowNode for tainted_mapped_summary [List element] | provenance | | -| summaries.py:60:45:60:52 | ControlFlowNode for List [List element] | summaries.py:60:26:60:53 | ControlFlowNode for list_map() [List element] | provenance | list_map | -| summaries.py:60:46:60:51 | ControlFlowNode for SOURCE | summaries.py:60:45:60:52 | ControlFlowNode for List [List element] | provenance | | -| summaries.py:61:6:61:27 | ControlFlowNode for tainted_mapped_summary [List element] | summaries.py:61:6:61:30 | ControlFlowNode for Subscript | provenance | | -| summaries.py:63:1:63:12 | ControlFlowNode for tainted_list [List element] | summaries.py:64:6:64:17 | ControlFlowNode for tainted_list [List element] | provenance | | -| summaries.py:63:16:63:41 | ControlFlowNode for append_to_list() [List element] | summaries.py:63:1:63:12 | ControlFlowNode for tainted_list [List element] | provenance | | -| summaries.py:63:35:63:40 | ControlFlowNode for SOURCE | summaries.py:63:16:63:41 | ControlFlowNode for append_to_list() [List element] | provenance | append_to_list | -| summaries.py:64:6:64:17 | ControlFlowNode for tainted_list [List element] | summaries.py:64:6:64:20 | ControlFlowNode for Subscript | provenance | | -| summaries.py:67:1:67:18 | ControlFlowNode for tainted_resultlist | summaries.py:68:6:68:26 | ControlFlowNode for Subscript | provenance | | -| summaries.py:67:1:67:18 | ControlFlowNode for tainted_resultlist [List element] | summaries.py:68:6:68:23 | ControlFlowNode for tainted_resultlist [List element] | provenance | | -| summaries.py:67:22:67:39 | ControlFlowNode for json_loads() [List element] | summaries.py:67:1:67:18 | ControlFlowNode for tainted_resultlist [List element] | provenance | | -| summaries.py:67:33:67:38 | ControlFlowNode for SOURCE | summaries.py:67:1:67:18 | ControlFlowNode for tainted_resultlist | provenance | | -| summaries.py:67:33:67:38 | ControlFlowNode for SOURCE | summaries.py:67:1:67:18 | ControlFlowNode for tainted_resultlist | provenance | Decoding-JSON | -| summaries.py:67:33:67:38 | ControlFlowNode for SOURCE | summaries.py:67:22:67:39 | ControlFlowNode for json_loads() [List element] | provenance | json.loads | -| summaries.py:68:6:68:23 | ControlFlowNode for tainted_resultlist [List element] | summaries.py:68:6:68:26 | ControlFlowNode for Subscript | provenance | | +| summaries.py:32:1:32:7 | tainted | summaries.py:33:6:33:12 | tainted | provenance | | +| summaries.py:32:11:32:26 | identity() | summaries.py:32:1:32:7 | tainted | provenance | | +| summaries.py:32:20:32:25 | SOURCE | summaries.py:32:11:32:26 | identity() | provenance | identity | +| summaries.py:36:1:36:14 | tainted_lambda | summaries.py:37:6:37:19 | tainted_lambda | provenance | | +| summaries.py:36:18:36:54 | apply_lambda() | summaries.py:36:1:36:14 | tainted_lambda | provenance | | +| summaries.py:36:38:36:38 | x | summaries.py:36:41:36:45 | BinaryExpr | provenance | | +| summaries.py:36:48:36:53 | SOURCE | summaries.py:36:18:36:54 | apply_lambda() | provenance | apply_lambda | +| summaries.py:36:48:36:53 | SOURCE | summaries.py:36:38:36:38 | x | provenance | apply_lambda | +| summaries.py:44:1:44:12 | tainted_list | summaries.py:45:6:45:20 | Subscript | provenance | | +| summaries.py:44:1:44:12 | tainted_list [List element] | summaries.py:45:6:45:17 | tainted_list [List element] | provenance | | +| summaries.py:44:16:44:33 | reversed() | summaries.py:44:1:44:12 | tainted_list | provenance | | +| summaries.py:44:16:44:33 | reversed() [List element] | summaries.py:44:1:44:12 | tainted_list [List element] | provenance | | +| summaries.py:44:25:44:32 | List | summaries.py:44:16:44:33 | reversed() | provenance | builtins.reversed | +| summaries.py:44:25:44:32 | List [List element] | summaries.py:44:16:44:33 | reversed() [List element] | provenance | builtins.reversed | +| summaries.py:44:26:44:31 | SOURCE | summaries.py:44:25:44:32 | List | provenance | | +| summaries.py:44:26:44:31 | SOURCE | summaries.py:44:25:44:32 | List [List element] | provenance | | +| summaries.py:45:6:45:17 | tainted_list [List element] | summaries.py:45:6:45:20 | Subscript | provenance | | +| summaries.py:48:15:48:15 | x | summaries.py:49:12:49:18 | BinaryExpr | provenance | | +| summaries.py:51:1:51:14 | tainted_mapped [List element] | summaries.py:52:6:52:19 | tainted_mapped [List element] | provenance | | +| summaries.py:51:18:51:46 | list_map() [List element] | summaries.py:51:1:51:14 | tainted_mapped [List element] | provenance | | +| summaries.py:51:38:51:45 | List [List element] | summaries.py:48:15:48:15 | x | provenance | list_map | +| summaries.py:51:38:51:45 | List [List element] | summaries.py:51:18:51:46 | list_map() [List element] | provenance | list_map | +| summaries.py:51:39:51:44 | SOURCE | summaries.py:51:38:51:45 | List [List element] | provenance | | +| summaries.py:52:6:52:19 | tainted_mapped [List element] | summaries.py:52:6:52:22 | Subscript | provenance | | +| summaries.py:54:23:54:23 | x | summaries.py:55:12:55:12 | x | provenance | | +| summaries.py:57:1:57:23 | tainted_mapped_explicit [List element] | summaries.py:58:6:58:28 | tainted_mapped_explicit [List element] | provenance | | +| summaries.py:57:27:57:63 | list_map() [List element] | summaries.py:57:1:57:23 | tainted_mapped_explicit [List element] | provenance | | +| summaries.py:57:55:57:62 | List [List element] | summaries.py:54:23:54:23 | x | provenance | list_map | +| summaries.py:57:55:57:62 | List [List element] | summaries.py:57:27:57:63 | list_map() [List element] | provenance | list_map | +| summaries.py:57:56:57:61 | SOURCE | summaries.py:57:55:57:62 | List [List element] | provenance | | +| summaries.py:58:6:58:28 | tainted_mapped_explicit [List element] | summaries.py:58:6:58:31 | Subscript | provenance | | +| summaries.py:60:1:60:22 | tainted_mapped_summary [List element] | summaries.py:61:6:61:27 | tainted_mapped_summary [List element] | provenance | | +| summaries.py:60:26:60:53 | list_map() [List element] | summaries.py:60:1:60:22 | tainted_mapped_summary [List element] | provenance | | +| summaries.py:60:45:60:52 | List [List element] | summaries.py:60:26:60:53 | list_map() [List element] | provenance | list_map | +| summaries.py:60:46:60:51 | SOURCE | summaries.py:60:45:60:52 | List [List element] | provenance | | +| summaries.py:61:6:61:27 | tainted_mapped_summary [List element] | summaries.py:61:6:61:30 | Subscript | provenance | | +| summaries.py:63:1:63:12 | tainted_list [List element] | summaries.py:64:6:64:17 | tainted_list [List element] | provenance | | +| summaries.py:63:16:63:41 | append_to_list() [List element] | summaries.py:63:1:63:12 | tainted_list [List element] | provenance | | +| summaries.py:63:35:63:40 | SOURCE | summaries.py:63:16:63:41 | append_to_list() [List element] | provenance | append_to_list | +| summaries.py:64:6:64:17 | tainted_list [List element] | summaries.py:64:6:64:20 | Subscript | provenance | | +| summaries.py:67:1:67:18 | tainted_resultlist | summaries.py:68:6:68:26 | Subscript | provenance | | +| summaries.py:67:1:67:18 | tainted_resultlist [List element] | summaries.py:68:6:68:23 | tainted_resultlist [List element] | provenance | | +| summaries.py:67:22:67:39 | json_loads() [List element] | summaries.py:67:1:67:18 | tainted_resultlist [List element] | provenance | | +| summaries.py:67:33:67:38 | SOURCE | summaries.py:67:1:67:18 | tainted_resultlist | provenance | Decoding-JSON | +| summaries.py:67:33:67:38 | SOURCE | summaries.py:67:22:67:39 | json_loads() [List element] | provenance | json.loads | +| summaries.py:68:6:68:23 | tainted_resultlist [List element] | summaries.py:68:6:68:26 | Subscript | provenance | | nodes -| summaries.py:32:1:32:7 | ControlFlowNode for tainted | semmle.label | ControlFlowNode for tainted | -| summaries.py:32:11:32:26 | ControlFlowNode for identity() | semmle.label | ControlFlowNode for identity() | -| summaries.py:32:20:32:25 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE | -| summaries.py:33:6:33:12 | ControlFlowNode for tainted | semmle.label | ControlFlowNode for tainted | -| summaries.py:36:1:36:14 | ControlFlowNode for tainted_lambda | semmle.label | ControlFlowNode for tainted_lambda | -| summaries.py:36:18:36:54 | ControlFlowNode for apply_lambda() | semmle.label | ControlFlowNode for apply_lambda() | -| summaries.py:36:38:36:38 | ControlFlowNode for x | semmle.label | ControlFlowNode for x | -| summaries.py:36:41:36:45 | ControlFlowNode for BinaryExpr | semmle.label | ControlFlowNode for BinaryExpr | -| summaries.py:36:48:36:53 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE | -| summaries.py:37:6:37:19 | ControlFlowNode for tainted_lambda | semmle.label | ControlFlowNode for tainted_lambda | -| summaries.py:44:1:44:12 | ControlFlowNode for tainted_list [List element] | semmle.label | ControlFlowNode for tainted_list [List element] | -| summaries.py:44:16:44:33 | ControlFlowNode for reversed() [List element] | semmle.label | ControlFlowNode for reversed() [List element] | -| summaries.py:44:25:44:32 | ControlFlowNode for List [List element] | semmle.label | ControlFlowNode for List [List element] | -| summaries.py:44:26:44:31 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE | -| summaries.py:45:6:45:17 | ControlFlowNode for tainted_list [List element] | semmle.label | ControlFlowNode for tainted_list [List element] | -| summaries.py:45:6:45:20 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript | -| summaries.py:48:15:48:15 | ControlFlowNode for x | semmle.label | ControlFlowNode for x | -| summaries.py:49:12:49:18 | ControlFlowNode for BinaryExpr | semmle.label | ControlFlowNode for BinaryExpr | -| summaries.py:51:1:51:14 | ControlFlowNode for tainted_mapped [List element] | semmle.label | ControlFlowNode for tainted_mapped [List element] | -| summaries.py:51:18:51:46 | ControlFlowNode for list_map() [List element] | semmle.label | ControlFlowNode for list_map() [List element] | -| summaries.py:51:38:51:45 | ControlFlowNode for List [List element] | semmle.label | ControlFlowNode for List [List element] | -| summaries.py:51:39:51:44 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE | -| summaries.py:52:6:52:19 | ControlFlowNode for tainted_mapped [List element] | semmle.label | ControlFlowNode for tainted_mapped [List element] | -| summaries.py:52:6:52:22 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript | -| summaries.py:54:23:54:23 | ControlFlowNode for x | semmle.label | ControlFlowNode for x | -| summaries.py:55:12:55:12 | ControlFlowNode for x | semmle.label | ControlFlowNode for x | -| summaries.py:57:1:57:23 | ControlFlowNode for tainted_mapped_explicit [List element] | semmle.label | ControlFlowNode for tainted_mapped_explicit [List element] | -| summaries.py:57:27:57:63 | ControlFlowNode for list_map() [List element] | semmle.label | ControlFlowNode for list_map() [List element] | -| summaries.py:57:55:57:62 | ControlFlowNode for List [List element] | semmle.label | ControlFlowNode for List [List element] | -| summaries.py:57:56:57:61 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE | -| summaries.py:58:6:58:28 | ControlFlowNode for tainted_mapped_explicit [List element] | semmle.label | ControlFlowNode for tainted_mapped_explicit [List element] | -| summaries.py:58:6:58:31 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript | -| summaries.py:60:1:60:22 | ControlFlowNode for tainted_mapped_summary [List element] | semmle.label | ControlFlowNode for tainted_mapped_summary [List element] | -| summaries.py:60:26:60:53 | ControlFlowNode for list_map() [List element] | semmle.label | ControlFlowNode for list_map() [List element] | -| summaries.py:60:45:60:52 | ControlFlowNode for List [List element] | semmle.label | ControlFlowNode for List [List element] | -| summaries.py:60:46:60:51 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE | -| summaries.py:61:6:61:27 | ControlFlowNode for tainted_mapped_summary [List element] | semmle.label | ControlFlowNode for tainted_mapped_summary [List element] | -| summaries.py:61:6:61:30 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript | -| summaries.py:63:1:63:12 | ControlFlowNode for tainted_list [List element] | semmle.label | ControlFlowNode for tainted_list [List element] | -| summaries.py:63:16:63:41 | ControlFlowNode for append_to_list() [List element] | semmle.label | ControlFlowNode for append_to_list() [List element] | -| summaries.py:63:35:63:40 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE | -| summaries.py:64:6:64:17 | ControlFlowNode for tainted_list [List element] | semmle.label | ControlFlowNode for tainted_list [List element] | -| summaries.py:64:6:64:20 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript | -| summaries.py:67:1:67:18 | ControlFlowNode for tainted_resultlist | semmle.label | ControlFlowNode for tainted_resultlist | -| summaries.py:67:1:67:18 | ControlFlowNode for tainted_resultlist [List element] | semmle.label | ControlFlowNode for tainted_resultlist [List element] | -| summaries.py:67:22:67:39 | ControlFlowNode for json_loads() [List element] | semmle.label | ControlFlowNode for json_loads() [List element] | -| summaries.py:67:33:67:38 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE | -| summaries.py:68:6:68:23 | ControlFlowNode for tainted_resultlist [List element] | semmle.label | ControlFlowNode for tainted_resultlist [List element] | -| summaries.py:68:6:68:26 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript | +| summaries.py:32:1:32:7 | tainted | semmle.label | tainted | +| summaries.py:32:11:32:26 | identity() | semmle.label | identity() | +| summaries.py:32:20:32:25 | SOURCE | semmle.label | SOURCE | +| summaries.py:33:6:33:12 | tainted | semmle.label | tainted | +| summaries.py:36:1:36:14 | tainted_lambda | semmle.label | tainted_lambda | +| summaries.py:36:18:36:54 | apply_lambda() | semmle.label | apply_lambda() | +| summaries.py:36:38:36:38 | x | semmle.label | x | +| summaries.py:36:41:36:45 | BinaryExpr | semmle.label | BinaryExpr | +| summaries.py:36:48:36:53 | SOURCE | semmle.label | SOURCE | +| summaries.py:37:6:37:19 | tainted_lambda | semmle.label | tainted_lambda | +| summaries.py:44:1:44:12 | tainted_list | semmle.label | tainted_list | +| summaries.py:44:1:44:12 | tainted_list [List element] | semmle.label | tainted_list [List element] | +| summaries.py:44:16:44:33 | reversed() | semmle.label | reversed() | +| summaries.py:44:16:44:33 | reversed() [List element] | semmle.label | reversed() [List element] | +| summaries.py:44:25:44:32 | List | semmle.label | List | +| summaries.py:44:25:44:32 | List [List element] | semmle.label | List [List element] | +| summaries.py:44:26:44:31 | SOURCE | semmle.label | SOURCE | +| summaries.py:45:6:45:17 | tainted_list [List element] | semmle.label | tainted_list [List element] | +| summaries.py:45:6:45:20 | Subscript | semmle.label | Subscript | +| summaries.py:48:15:48:15 | x | semmle.label | x | +| summaries.py:49:12:49:18 | BinaryExpr | semmle.label | BinaryExpr | +| summaries.py:51:1:51:14 | tainted_mapped [List element] | semmle.label | tainted_mapped [List element] | +| summaries.py:51:18:51:46 | list_map() [List element] | semmle.label | list_map() [List element] | +| summaries.py:51:38:51:45 | List [List element] | semmle.label | List [List element] | +| summaries.py:51:39:51:44 | SOURCE | semmle.label | SOURCE | +| summaries.py:52:6:52:19 | tainted_mapped [List element] | semmle.label | tainted_mapped [List element] | +| summaries.py:52:6:52:22 | Subscript | semmle.label | Subscript | +| summaries.py:54:23:54:23 | x | semmle.label | x | +| summaries.py:55:12:55:12 | x | semmle.label | x | +| summaries.py:57:1:57:23 | tainted_mapped_explicit [List element] | semmle.label | tainted_mapped_explicit [List element] | +| summaries.py:57:27:57:63 | list_map() [List element] | semmle.label | list_map() [List element] | +| summaries.py:57:55:57:62 | List [List element] | semmle.label | List [List element] | +| summaries.py:57:56:57:61 | SOURCE | semmle.label | SOURCE | +| summaries.py:58:6:58:28 | tainted_mapped_explicit [List element] | semmle.label | tainted_mapped_explicit [List element] | +| summaries.py:58:6:58:31 | Subscript | semmle.label | Subscript | +| summaries.py:60:1:60:22 | tainted_mapped_summary [List element] | semmle.label | tainted_mapped_summary [List element] | +| summaries.py:60:26:60:53 | list_map() [List element] | semmle.label | list_map() [List element] | +| summaries.py:60:45:60:52 | List [List element] | semmle.label | List [List element] | +| summaries.py:60:46:60:51 | SOURCE | semmle.label | SOURCE | +| summaries.py:61:6:61:27 | tainted_mapped_summary [List element] | semmle.label | tainted_mapped_summary [List element] | +| summaries.py:61:6:61:30 | Subscript | semmle.label | Subscript | +| summaries.py:63:1:63:12 | tainted_list [List element] | semmle.label | tainted_list [List element] | +| summaries.py:63:16:63:41 | append_to_list() [List element] | semmle.label | append_to_list() [List element] | +| summaries.py:63:35:63:40 | SOURCE | semmle.label | SOURCE | +| summaries.py:64:6:64:17 | tainted_list [List element] | semmle.label | tainted_list [List element] | +| summaries.py:64:6:64:20 | Subscript | semmle.label | Subscript | +| summaries.py:67:1:67:18 | tainted_resultlist | semmle.label | tainted_resultlist | +| summaries.py:67:1:67:18 | tainted_resultlist [List element] | semmle.label | tainted_resultlist [List element] | +| summaries.py:67:22:67:39 | json_loads() [List element] | semmle.label | json_loads() [List element] | +| summaries.py:67:33:67:38 | SOURCE | semmle.label | SOURCE | +| summaries.py:68:6:68:23 | tainted_resultlist [List element] | semmle.label | tainted_resultlist [List element] | +| summaries.py:68:6:68:26 | Subscript | semmle.label | Subscript | subpaths -| summaries.py:36:48:36:53 | ControlFlowNode for SOURCE | summaries.py:36:38:36:38 | ControlFlowNode for x | summaries.py:36:41:36:45 | ControlFlowNode for BinaryExpr | summaries.py:36:18:36:54 | ControlFlowNode for apply_lambda() | -| summaries.py:51:38:51:45 | ControlFlowNode for List [List element] | summaries.py:48:15:48:15 | ControlFlowNode for x | summaries.py:49:12:49:18 | ControlFlowNode for BinaryExpr | summaries.py:51:18:51:46 | ControlFlowNode for list_map() [List element] | -| summaries.py:57:55:57:62 | ControlFlowNode for List [List element] | summaries.py:54:23:54:23 | ControlFlowNode for x | summaries.py:55:12:55:12 | ControlFlowNode for x | summaries.py:57:27:57:63 | ControlFlowNode for list_map() [List element] | +| summaries.py:36:48:36:53 | SOURCE | summaries.py:36:38:36:38 | x | summaries.py:36:41:36:45 | BinaryExpr | summaries.py:36:18:36:54 | apply_lambda() | +| summaries.py:51:38:51:45 | List [List element] | summaries.py:48:15:48:15 | x | summaries.py:49:12:49:18 | BinaryExpr | summaries.py:51:18:51:46 | list_map() [List element] | +| summaries.py:57:55:57:62 | List [List element] | summaries.py:54:23:54:23 | x | summaries.py:55:12:55:12 | x | summaries.py:57:27:57:63 | list_map() [List element] | invalidSpecComponent #select -| summaries.py:33:6:33:12 | ControlFlowNode for tainted | summaries.py:32:20:32:25 | ControlFlowNode for SOURCE | summaries.py:33:6:33:12 | ControlFlowNode for tainted | $@ | summaries.py:32:20:32:25 | ControlFlowNode for SOURCE | ControlFlowNode for SOURCE | -| summaries.py:37:6:37:19 | ControlFlowNode for tainted_lambda | summaries.py:36:48:36:53 | ControlFlowNode for SOURCE | summaries.py:37:6:37:19 | ControlFlowNode for tainted_lambda | $@ | summaries.py:36:48:36:53 | ControlFlowNode for SOURCE | ControlFlowNode for SOURCE | -| summaries.py:45:6:45:20 | ControlFlowNode for Subscript | summaries.py:44:26:44:31 | ControlFlowNode for SOURCE | summaries.py:45:6:45:20 | ControlFlowNode for Subscript | $@ | summaries.py:44:26:44:31 | ControlFlowNode for SOURCE | ControlFlowNode for SOURCE | -| summaries.py:52:6:52:22 | ControlFlowNode for Subscript | summaries.py:51:39:51:44 | ControlFlowNode for SOURCE | summaries.py:52:6:52:22 | ControlFlowNode for Subscript | $@ | summaries.py:51:39:51:44 | ControlFlowNode for SOURCE | ControlFlowNode for SOURCE | -| summaries.py:58:6:58:31 | ControlFlowNode for Subscript | summaries.py:57:56:57:61 | ControlFlowNode for SOURCE | summaries.py:58:6:58:31 | ControlFlowNode for Subscript | $@ | summaries.py:57:56:57:61 | ControlFlowNode for SOURCE | ControlFlowNode for SOURCE | -| summaries.py:61:6:61:30 | ControlFlowNode for Subscript | summaries.py:60:46:60:51 | ControlFlowNode for SOURCE | summaries.py:61:6:61:30 | ControlFlowNode for Subscript | $@ | summaries.py:60:46:60:51 | ControlFlowNode for SOURCE | ControlFlowNode for SOURCE | -| summaries.py:64:6:64:20 | ControlFlowNode for Subscript | summaries.py:63:35:63:40 | ControlFlowNode for SOURCE | summaries.py:64:6:64:20 | ControlFlowNode for Subscript | $@ | summaries.py:63:35:63:40 | ControlFlowNode for SOURCE | ControlFlowNode for SOURCE | -| summaries.py:68:6:68:26 | ControlFlowNode for Subscript | summaries.py:67:33:67:38 | ControlFlowNode for SOURCE | summaries.py:68:6:68:26 | ControlFlowNode for Subscript | $@ | summaries.py:67:33:67:38 | ControlFlowNode for SOURCE | ControlFlowNode for SOURCE | +| summaries.py:33:6:33:12 | tainted | summaries.py:32:20:32:25 | SOURCE | summaries.py:33:6:33:12 | tainted | $@ | summaries.py:32:20:32:25 | SOURCE | SOURCE | +| summaries.py:37:6:37:19 | tainted_lambda | summaries.py:36:48:36:53 | SOURCE | summaries.py:37:6:37:19 | tainted_lambda | $@ | summaries.py:36:48:36:53 | SOURCE | SOURCE | +| summaries.py:45:6:45:20 | Subscript | summaries.py:44:26:44:31 | SOURCE | summaries.py:45:6:45:20 | Subscript | $@ | summaries.py:44:26:44:31 | SOURCE | SOURCE | +| summaries.py:52:6:52:22 | Subscript | summaries.py:51:39:51:44 | SOURCE | summaries.py:52:6:52:22 | Subscript | $@ | summaries.py:51:39:51:44 | SOURCE | SOURCE | +| summaries.py:58:6:58:31 | Subscript | summaries.py:57:56:57:61 | SOURCE | summaries.py:58:6:58:31 | Subscript | $@ | summaries.py:57:56:57:61 | SOURCE | SOURCE | +| summaries.py:61:6:61:30 | Subscript | summaries.py:60:46:60:51 | SOURCE | summaries.py:61:6:61:30 | Subscript | $@ | summaries.py:60:46:60:51 | SOURCE | SOURCE | +| summaries.py:64:6:64:20 | Subscript | summaries.py:63:35:63:40 | SOURCE | summaries.py:64:6:64:20 | Subscript | $@ | summaries.py:63:35:63:40 | SOURCE | SOURCE | +| summaries.py:68:6:68:26 | Subscript | summaries.py:67:33:67:38 | SOURCE | summaries.py:68:6:68:26 | Subscript | $@ | summaries.py:67:33:67:38 | SOURCE | SOURCE | diff --git a/python/ql/test/library-tests/dataflow/tainttracking/TestTaintLib.qll b/python/ql/test/library-tests/dataflow/tainttracking/TestTaintLib.qll index 4d7d9201e3ec..cb014631208e 100644 --- a/python/ql/test/library-tests/dataflow/tainttracking/TestTaintLib.qll +++ b/python/ql/test/library-tests/dataflow/tainttracking/TestTaintLib.qll @@ -1,4 +1,5 @@ import python +private import semmle.python.controlflow.internal.Cfg as Cfg import semmle.python.dataflow.new.TaintTracking import semmle.python.dataflow.new.DataFlow private import semmle.python.dataflow.new.internal.PrintNode @@ -6,20 +7,20 @@ private import semmle.python.dataflow.new.internal.PrintNode module TestTaintTrackingConfig implements DataFlow::ConfigSig { predicate isSource(DataFlow::Node source) { // Standard sources - source.(DataFlow::CfgNode).getNode().(NameNode).getId() in [ + source.(DataFlow::CfgNode).getNode().(Cfg::NameNode).getId() in [ "TAINTED_STRING", "TAINTED_BYTES", "TAINTED_LIST", "TAINTED_DICT" ] or // User defined sources - exists(CallNode call | - call.getFunction().(NameNode).getId() = "taint" and + exists(Cfg::CallNode call | + call.getFunction().(Cfg::NameNode).getId() = "taint" and source.(DataFlow::CfgNode).getNode() = call.getAnArg() ) } predicate isSink(DataFlow::Node sink) { - exists(CallNode call | - call.getFunction().(NameNode).getId() in ["ensure_tainted", "ensure_not_tainted"] and + exists(Cfg::CallNode call | + call.getFunction().(Cfg::NameNode).getId() in ["ensure_tainted", "ensure_not_tainted"] and sink.(DataFlow::CfgNode).getNode() = call.getAnArg() ) } diff --git a/python/ql/test/library-tests/dataflow/tainttracking/basic/GlobalTaintTracking.expected b/python/ql/test/library-tests/dataflow/tainttracking/basic/GlobalTaintTracking.expected index 23bb0fcce7a4..9d1b4cb7c72a 100644 --- a/python/ql/test/library-tests/dataflow/tainttracking/basic/GlobalTaintTracking.expected +++ b/python/ql/test/library-tests/dataflow/tainttracking/basic/GlobalTaintTracking.expected @@ -1,2 +1,2 @@ -| test.py:3:11:3:16 | ControlFlowNode for SOURCE | test.py:4:6:4:12 | ControlFlowNode for tainted | -| test.py:7:20:7:25 | ControlFlowNode for SOURCE | test.py:8:10:8:21 | ControlFlowNode for also_tainted | +| test.py:3:11:3:16 | SOURCE | test.py:4:6:4:12 | tainted | +| test.py:7:20:7:25 | SOURCE | test.py:8:10:8:21 | also_tainted | diff --git a/python/ql/test/library-tests/dataflow/tainttracking/basic/GlobalTaintTracking.ql b/python/ql/test/library-tests/dataflow/tainttracking/basic/GlobalTaintTracking.ql index 1fd0a9600b3a..710cd61ac262 100644 --- a/python/ql/test/library-tests/dataflow/tainttracking/basic/GlobalTaintTracking.ql +++ b/python/ql/test/library-tests/dataflow/tainttracking/basic/GlobalTaintTracking.ql @@ -1,15 +1,16 @@ import python +private import semmle.python.controlflow.internal.Cfg as Cfg import semmle.python.dataflow.new.TaintTracking import semmle.python.dataflow.new.DataFlow module TestTaintTrackingConfig implements DataFlow::ConfigSig { predicate isSource(DataFlow::Node source) { - source.(DataFlow::CfgNode).getNode().(NameNode).getId() = "SOURCE" + source.(DataFlow::CfgNode).getNode().(Cfg::NameNode).getId() = "SOURCE" } predicate isSink(DataFlow::Node sink) { - exists(CallNode call | - call.getFunction().(NameNode).getId() = "SINK" and + exists(Cfg::CallNode call | + call.getFunction().(Cfg::NameNode).getId() = "SINK" and sink.(DataFlow::CfgNode).getNode() = call.getAnArg() ) } diff --git a/python/ql/test/library-tests/dataflow/tainttracking/basic/LocalTaintStep.expected b/python/ql/test/library-tests/dataflow/tainttracking/basic/LocalTaintStep.expected index b2b151f6dedb..1b6d2d2cbd4b 100644 --- a/python/ql/test/library-tests/dataflow/tainttracking/basic/LocalTaintStep.expected +++ b/python/ql/test/library-tests/dataflow/tainttracking/basic/LocalTaintStep.expected @@ -1,5 +1,5 @@ -| test.py:3:1:3:7 | ControlFlowNode for tainted | test.py:4:6:4:12 | ControlFlowNode for tainted | -| test.py:3:11:3:16 | ControlFlowNode for SOURCE | test.py:3:1:3:7 | ControlFlowNode for tainted | -| test.py:6:1:6:11 | ControlFlowNode for FunctionExpr | test.py:6:5:6:8 | ControlFlowNode for func | -| test.py:7:5:7:16 | ControlFlowNode for also_tainted | test.py:8:10:8:21 | ControlFlowNode for also_tainted | -| test.py:7:20:7:25 | ControlFlowNode for SOURCE | test.py:7:5:7:16 | ControlFlowNode for also_tainted | +| test.py:3:1:3:7 | tainted | test.py:4:6:4:12 | tainted | +| test.py:3:11:3:16 | SOURCE | test.py:3:1:3:7 | tainted | +| test.py:6:1:6:11 | FunctionExpr | test.py:6:5:6:8 | func | +| test.py:7:5:7:16 | also_tainted | test.py:8:10:8:21 | also_tainted | +| test.py:7:20:7:25 | SOURCE | test.py:7:5:7:16 | also_tainted | diff --git a/python/ql/test/library-tests/dataflow/tainttracking/customSanitizer/InlineTaintTest.expected b/python/ql/test/library-tests/dataflow/tainttracking/customSanitizer/InlineTaintTest.expected index 89849279d446..996dd663fbab 100644 --- a/python/ql/test/library-tests/dataflow/tainttracking/customSanitizer/InlineTaintTest.expected +++ b/python/ql/test/library-tests/dataflow/tainttracking/customSanitizer/InlineTaintTest.expected @@ -2,32 +2,32 @@ argumentToEnsureNotTaintedNotMarkedAsSpurious untaintedArgumentToEnsureTaintedNotMarkedAsMissing testFailures isSanitizer -| test.py:21:39:21:39 | ControlFlowNode for s | -| test.py:34:39:34:39 | ControlFlowNode for s | -| test.py:52:28:52:28 | ControlFlowNode for s | -| test.py:66:10:66:29 | ControlFlowNode for emulated_escaping() | -| test_logical.py:33:28:33:28 | ControlFlowNode for s | -| test_logical.py:40:28:40:28 | ControlFlowNode for s | -| test_logical.py:48:28:48:28 | ControlFlowNode for s | -| test_logical.py:53:28:53:28 | ControlFlowNode for s | -| test_logical.py:92:28:92:28 | ControlFlowNode for s | -| test_logical.py:103:28:103:28 | ControlFlowNode for s | -| test_logical.py:111:28:111:28 | ControlFlowNode for s | -| test_logical.py:130:28:130:28 | ControlFlowNode for s | -| test_logical.py:137:28:137:28 | ControlFlowNode for s | -| test_logical.py:148:28:148:28 | ControlFlowNode for s | -| test_logical.py:151:28:151:28 | ControlFlowNode for s | -| test_logical.py:158:28:158:28 | ControlFlowNode for s | -| test_logical.py:167:24:167:24 | ControlFlowNode for s | -| test_logical.py:176:24:176:24 | ControlFlowNode for s | -| test_logical.py:185:24:185:24 | ControlFlowNode for s | -| test_logical.py:193:24:193:24 | ControlFlowNode for s | -| test_logical.py:199:28:199:28 | ControlFlowNode for s | -| test_logical.py:206:28:206:28 | ControlFlowNode for s | -| test_logical.py:211:28:211:28 | ControlFlowNode for s | -| test_logical.py:214:28:214:28 | ControlFlowNode for s | -| test_logical.py:219:28:219:28 | ControlFlowNode for s | -| test_logical.py:226:28:226:28 | ControlFlowNode for s | -| test_logical.py:231:28:231:28 | ControlFlowNode for s | -| test_logical.py:234:28:234:28 | ControlFlowNode for s | -| test_reference.py:31:28:31:28 | ControlFlowNode for s | +| test.py:21:39:21:39 | s | +| test.py:34:39:34:39 | s | +| test.py:52:28:52:28 | s | +| test.py:66:10:66:29 | emulated_escaping() | +| test_logical.py:33:28:33:28 | s | +| test_logical.py:40:28:40:28 | s | +| test_logical.py:48:28:48:28 | s | +| test_logical.py:53:28:53:28 | s | +| test_logical.py:92:28:92:28 | s | +| test_logical.py:103:28:103:28 | s | +| test_logical.py:111:28:111:28 | s | +| test_logical.py:130:28:130:28 | s | +| test_logical.py:137:28:137:28 | s | +| test_logical.py:148:28:148:28 | s | +| test_logical.py:151:28:151:28 | s | +| test_logical.py:158:28:158:28 | s | +| test_logical.py:167:24:167:24 | s | +| test_logical.py:176:24:176:24 | s | +| test_logical.py:185:24:185:24 | s | +| test_logical.py:193:24:193:24 | s | +| test_logical.py:199:28:199:28 | s | +| test_logical.py:206:28:206:28 | s | +| test_logical.py:211:28:211:28 | s | +| test_logical.py:214:28:214:28 | s | +| test_logical.py:219:28:219:28 | s | +| test_logical.py:226:28:226:28 | s | +| test_logical.py:231:28:231:28 | s | +| test_logical.py:234:28:234:28 | s | +| test_reference.py:31:28:31:28 | s | diff --git a/python/ql/test/library-tests/dataflow/tainttracking/customSanitizer/InlineTaintTest.ql b/python/ql/test/library-tests/dataflow/tainttracking/customSanitizer/InlineTaintTest.ql index 597f368b02ff..346bdbcd6026 100644 --- a/python/ql/test/library-tests/dataflow/tainttracking/customSanitizer/InlineTaintTest.ql +++ b/python/ql/test/library-tests/dataflow/tainttracking/customSanitizer/InlineTaintTest.ql @@ -1,14 +1,15 @@ import experimental.meta.InlineTaintTest +private import semmle.python.controlflow.internal.Cfg as Cfg -predicate isSafeCheck(DataFlow::GuardNode g, ControlFlowNode node, boolean branch) { - g.(CallNode).getNode().getFunc().(Name).getId() in ["is_safe", "emulated_is_safe"] and - node = g.(CallNode).getAnArg() and +predicate isSafeCheck(DataFlow::GuardNode g, Cfg::ControlFlowNode node, boolean branch) { + g.(Cfg::CallNode).getNode().getFunc().(Name).getId() in ["is_safe", "emulated_is_safe"] and + node = g.(Cfg::CallNode).getAnArg() and branch = true } -predicate isUnsafeCheck(DataFlow::GuardNode g, ControlFlowNode node, boolean branch) { - g.(CallNode).getNode().getFunc().(Name).getId() in ["is_unsafe", "emulated_is_unsafe"] and - node = g.(CallNode).getAnArg() and +predicate isUnsafeCheck(DataFlow::GuardNode g, Cfg::ControlFlowNode node, boolean branch) { + g.(Cfg::CallNode).getNode().getFunc().(Name).getId() in ["is_unsafe", "emulated_is_unsafe"] and + node = g.(Cfg::CallNode).getAnArg() and branch = false } diff --git a/python/ql/test/library-tests/dataflow/tainttracking/customSanitizer/test.py b/python/ql/test/library-tests/dataflow/tainttracking/customSanitizer/test.py index 27b5c59827ad..f99998e586b9 100644 --- a/python/ql/test/library-tests/dataflow/tainttracking/customSanitizer/test.py +++ b/python/ql/test/library-tests/dataflow/tainttracking/customSanitizer/test.py @@ -21,7 +21,7 @@ def test_custom_sanitizer_exception_raise(): emulated_authentication_check(s) ensure_not_tainted(s) except: - ensure_tainted(s) # $ tainted + ensure_tainted(s) # $ MISSING: tainted raise ensure_not_tainted(s) @@ -34,10 +34,10 @@ def test_custom_sanitizer_exception_pass(): emulated_authentication_check(s) ensure_not_tainted(s) except: - ensure_tainted(s) # $ tainted + ensure_tainted(s) # $ MISSING: tainted pass - ensure_tainted(s) # $ tainted + ensure_tainted(s) # $ MISSING: tainted def emulated_is_safe(arg): diff --git a/python/ql/test/library-tests/dataflow/typetracking-summaries/TestSummaries.qll b/python/ql/test/library-tests/dataflow/typetracking-summaries/TestSummaries.qll index 57e0013b6e0e..4651d5c6180c 100644 --- a/python/ql/test/library-tests/dataflow/typetracking-summaries/TestSummaries.qll +++ b/python/ql/test/library-tests/dataflow/typetracking-summaries/TestSummaries.qll @@ -2,6 +2,7 @@ overlay[local?] module; private import python +private import semmle.python.controlflow.internal.Cfg as Cfg private import semmle.python.dataflow.new.FlowSummary private import semmle.python.ApiGraphs @@ -17,7 +18,7 @@ module RecursionGuard { RecursionGuard() { this = "TypeTrackingSummariesRecursionGuard" } override DataFlow::CallCfgNode getACall() { - result.getFunction().asCfgNode().(NameNode).getId() = this and + result.getFunction().asCfgNode().(Cfg::NameNode).getId() = this and (TT::callStep(_, _) implies any()) } @@ -41,7 +42,7 @@ private class SummarizedCallableIdentity extends SummarizedCallable::Range { override DataFlow::CallCfgNode getACall() { none() } override DataFlow::CallCfgNode getACallSimple() { - result.getFunction().asCfgNode().(NameNode).getId() = this + result.getFunction().asCfgNode().(Cfg::NameNode).getId() = this } override DataFlow::ArgumentNode getACallback() { result.asExpr().(Name).getId() = this } @@ -60,7 +61,7 @@ private class SummarizedCallableApplyLambda extends SummarizedCallable::Range { override DataFlow::CallCfgNode getACall() { none() } override DataFlow::CallCfgNode getACallSimple() { - result.getFunction().asCfgNode().(NameNode).getId() = this + result.getFunction().asCfgNode().(Cfg::NameNode).getId() = this } override DataFlow::ArgumentNode getACallback() { result.asExpr().(Name).getId() = this } @@ -82,7 +83,7 @@ private class SummarizedCallableReversed extends SummarizedCallable::Range { override DataFlow::CallCfgNode getACall() { none() } override DataFlow::CallCfgNode getACallSimple() { - result.getFunction().asCfgNode().(NameNode).getId() = this + result.getFunction().asCfgNode().(Cfg::NameNode).getId() = this } override DataFlow::ArgumentNode getACallback() { result.asExpr().(Name).getId() = this } @@ -100,7 +101,7 @@ private class SummarizedCallableMap extends SummarizedCallable::Range { override DataFlow::CallCfgNode getACall() { none() } override DataFlow::CallCfgNode getACallSimple() { - result.getFunction().asCfgNode().(NameNode).getId() = this + result.getFunction().asCfgNode().(Cfg::NameNode).getId() = this } override DataFlow::ArgumentNode getACallback() { result.asExpr().(Name).getId() = this } @@ -122,7 +123,7 @@ private class SummarizedCallableAppend extends SummarizedCallable::Range { override DataFlow::CallCfgNode getACall() { none() } override DataFlow::CallCfgNode getACallSimple() { - result.getFunction().asCfgNode().(NameNode).getId() = this + result.getFunction().asCfgNode().(Cfg::NameNode).getId() = this } override DataFlow::ArgumentNode getACallback() { result.asExpr().(Name).getId() = this } @@ -165,7 +166,7 @@ private class SummarizedCallableReadSecret extends SummarizedCallable::Range { override DataFlow::CallCfgNode getACall() { none() } override DataFlow::CallCfgNode getACallSimple() { - result.getFunction().asCfgNode().(NameNode).getId() = this + result.getFunction().asCfgNode().(Cfg::NameNode).getId() = this } override DataFlow::ArgumentNode getACallback() { result.asExpr().(Name).getId() = this } @@ -183,7 +184,7 @@ private class SummarizedCallableSetSecret extends SummarizedCallable::Range { override DataFlow::CallCfgNode getACall() { none() } override DataFlow::CallCfgNode getACallSimple() { - result.getFunction().asCfgNode().(NameNode).getId() = this + result.getFunction().asCfgNode().(Cfg::NameNode).getId() = this } override DataFlow::ArgumentNode getACallback() { result.asExpr().(Name).getId() = this } diff --git a/python/ql/test/library-tests/dataflow/typetracking-summaries/tracked.ql b/python/ql/test/library-tests/dataflow/typetracking-summaries/tracked.ql index c4ed2522092f..893194ead710 100644 --- a/python/ql/test/library-tests/dataflow/typetracking-summaries/tracked.ql +++ b/python/ql/test/library-tests/dataflow/typetracking-summaries/tracked.ql @@ -1,4 +1,5 @@ import python +private import semmle.python.controlflow.internal.Cfg as Cfg import semmle.python.dataflow.new.DataFlow import semmle.python.dataflow.new.TypeTracking import utils.test.InlineExpectationsTest @@ -10,7 +11,7 @@ import TestSummaries // ----------------------------------------------------------------------------- private DataFlow::TypeTrackingNode tracked(TypeTracker t) { t.start() and - result.asCfgNode() = any(NameNode n | n.getId() = "tracked") + result.asCfgNode() = any(Cfg::NameNode n | n.getId() = "tracked") or exists(TypeTracker t2 | result = tracked(t2).track(t2, t)) } diff --git a/python/ql/test/library-tests/dataflow/typetracking/moduleattr.expected b/python/ql/test/library-tests/dataflow/typetracking/moduleattr.expected index 06b560623929..9b3c6099ec08 100644 --- a/python/ql/test/library-tests/dataflow/typetracking/moduleattr.expected +++ b/python/ql/test/library-tests/dataflow/typetracking/moduleattr.expected @@ -1,12 +1,12 @@ module_tracker -| import_as_attr.py:1:6:1:11 | ControlFlowNode for ImportExpr | +| import_as_attr.py:1:6:1:11 | ImportExpr | module_attr_tracker | import_as_attr.py:0:0:0:0 | ModuleVariableNode in Module import_as_attr for attr_ref | | import_as_attr.py:0:0:0:0 | ModuleVariableNode in Module import_as_attr for x | -| import_as_attr.py:1:20:1:35 | ControlFlowNode for ImportMember | -| import_as_attr.py:1:28:1:35 | ControlFlowNode for attr_ref | -| import_as_attr.py:3:1:3:1 | ControlFlowNode for x | -| import_as_attr.py:3:5:3:12 | ControlFlowNode for attr_ref | -| import_as_attr.py:5:1:5:10 | Entry definition for SsaSourceVariable attr_ref | -| import_as_attr.py:6:5:6:5 | ControlFlowNode for y | -| import_as_attr.py:6:9:6:16 | ControlFlowNode for attr_ref | +| import_as_attr.py:1:20:1:35 | ImportMember | +| import_as_attr.py:1:28:1:35 | attr_ref | +| import_as_attr.py:3:1:3:1 | x | +| import_as_attr.py:3:5:3:12 | attr_ref | +| import_as_attr.py:5:1:5:10 | Entry definition for Global Variable attr_ref | +| import_as_attr.py:6:5:6:5 | y | +| import_as_attr.py:6:9:6:16 | attr_ref | diff --git a/python/ql/test/library-tests/dataflow/typetracking/test.py b/python/ql/test/library-tests/dataflow/typetracking/test.py index 74ee091cc230..19d5bd76f5fa 100644 --- a/python/ql/test/library-tests/dataflow/typetracking/test.py +++ b/python/ql/test/library-tests/dataflow/typetracking/test.py @@ -90,9 +90,9 @@ def my_decorator(func): def wrapper(): print("before function call") - val = func() # $ MISSING: tracked + val = func() # $ tracked print("after function call") - return val # $ MISSING: tracked + return val # $ tracked return wrapper @my_decorator @@ -105,7 +105,7 @@ def unrelated_func(): def use_funcs_with_decorators(): x = get_tracked2() # $ tracked - y = unrelated_func() + y = unrelated_func() # $ SPURIOUS: tracked # ------------------------------------------------------------------------------ diff --git a/python/ql/test/library-tests/dataflow/typetracking/tracked.ql b/python/ql/test/library-tests/dataflow/typetracking/tracked.ql index e720fd3c451b..c6168985da2f 100644 --- a/python/ql/test/library-tests/dataflow/typetracking/tracked.ql +++ b/python/ql/test/library-tests/dataflow/typetracking/tracked.ql @@ -10,7 +10,7 @@ private import semmle.python.dataflow.new.internal.DataFlowPrivate as DP // ----------------------------------------------------------------------------- private DataFlow::TypeTrackingNode tracked(TypeTracker t) { t.start() and - result.asCfgNode() = any(NameNode n | n.getId() = "tracked") + result.asCfgNode().getNode() = any(Name n | n.getId() = "tracked") or exists(TypeTracker t2 | result = tracked(t2).track(t2, t)) } @@ -51,14 +51,14 @@ module TrackedTest implements TestSig { // ----------------------------------------------------------------------------- private DataFlow::TypeTrackingNode int_type(TypeTracker t) { t.start() and - result.asCfgNode() = any(CallNode c | c.getFunction().(NameNode).getId() = "int") + result.asCfgNode().getNode() = any(Call c | c.getFunc().(Name).getId() = "int") or exists(TypeTracker t2 | result = int_type(t2).track(t2, t)) } private DataFlow::TypeTrackingNode string_type(TypeTracker t) { t.start() and - result.asCfgNode() = any(CallNode c | c.getFunction().(NameNode).getId() = "str") + result.asCfgNode().getNode() = any(Call c | c.getFunc().(Name).getId() = "str") or exists(TypeTracker t2 | result = string_type(t2).track(t2, t)) } diff --git a/python/ql/test/library-tests/dataflow/typetracking_imports/highlight_problem.expected b/python/ql/test/library-tests/dataflow/typetracking_imports/highlight_problem.expected index 9aa55c97f1cb..61426b651467 100644 --- a/python/ql/test/library-tests/dataflow/typetracking_imports/highlight_problem.expected +++ b/python/ql/test/library-tests/dataflow/typetracking_imports/highlight_problem.expected @@ -1,9 +1,7 @@ -| pkg/alias_only_direct.py:0:0:0:0 | Module pkg.alias_only_direct | pkg/alias_only_direct.py:1:22:1:24 | GSSA Variable foo | use to normal exit | -| pkg/alias_problem.py:0:0:0:0 | Module pkg.alias_problem | pkg/alias_problem.py:1:22:1:24 | GSSA Variable foo | no use to normal exit | -| pkg/alias_problem.py:0:0:0:0 | Module pkg.alias_problem | pkg/alias_problem.py:2:1:2:20 | GSSA Variable foo | use to normal exit | -| pkg/alias_problem_fixed.py:0:0:0:0 | Module pkg.alias_problem_fixed | pkg/alias_problem_fixed.py:0:0:0:0 | GSSA Variable foo | no use to normal exit | -| pkg/alias_problem_fixed.py:0:0:0:0 | Module pkg.alias_problem_fixed | pkg/alias_problem_fixed.py:3:22:3:24 | GSSA Variable foo | use to normal exit | -| pkg/problem_absolute_import.py:0:0:0:0 | Module pkg.problem_absolute_import | pkg/problem_absolute_import.py:1:25:1:27 | GSSA Variable foo | no use to normal exit | -| pkg/problem_absolute_import.py:0:0:0:0 | Module pkg.problem_absolute_import | pkg/problem_absolute_import.py:2:1:2:23 | GSSA Variable foo | use to normal exit | -| pkg/works_absolute_import.py:0:0:0:0 | Module pkg.works_absolute_import | pkg/works_absolute_import.py:0:0:0:0 | GSSA Variable foo | no use to normal exit | -| pkg/works_absolute_import.py:0:0:0:0 | Module pkg.works_absolute_import | pkg/works_absolute_import.py:2:25:2:27 | GSSA Variable foo | use to normal exit | +| pkg/alias_only_direct.py:0:0:0:0 | Module pkg.alias_only_direct | pkg/alias_only_direct.py:1:22:1:24 | SSA def(Global Variable foo) | use to normal exit | +| pkg/alias_problem.py:0:0:0:0 | Module pkg.alias_problem | pkg/alias_problem.py:1:22:1:24 | SSA def(Global Variable foo) | no use to normal exit | +| pkg/alias_problem.py:0:0:0:0 | Module pkg.alias_problem | pkg/alias_problem.py:2:1:2:20 | SSA def(Global Variable foo) | use to normal exit | +| pkg/alias_problem_fixed.py:0:0:0:0 | Module pkg.alias_problem_fixed | pkg/alias_problem_fixed.py:3:22:3:24 | SSA def(Global Variable foo) | use to normal exit | +| pkg/problem_absolute_import.py:0:0:0:0 | Module pkg.problem_absolute_import | pkg/problem_absolute_import.py:1:25:1:27 | SSA def(Global Variable foo) | no use to normal exit | +| pkg/problem_absolute_import.py:0:0:0:0 | Module pkg.problem_absolute_import | pkg/problem_absolute_import.py:2:1:2:23 | SSA def(Global Variable foo) | use to normal exit | +| pkg/works_absolute_import.py:0:0:0:0 | Module pkg.works_absolute_import | pkg/works_absolute_import.py:2:25:2:27 | SSA def(Global Variable foo) | use to normal exit | diff --git a/python/ql/test/library-tests/dataflow/typetracking_imports/highlight_problem.ql b/python/ql/test/library-tests/dataflow/typetracking_imports/highlight_problem.ql index fc1441be4797..cc8049e00d08 100644 --- a/python/ql/test/library-tests/dataflow/typetracking_imports/highlight_problem.ql +++ b/python/ql/test/library-tests/dataflow/typetracking_imports/highlight_problem.ql @@ -1,15 +1,20 @@ import python +private import semmle.python.controlflow.internal.Cfg as Cfg +private import semmle.python.dataflow.new.internal.SsaImpl as SsaImpl // looking at `module_export` predicate in DataFlowPrivate, the core of the problem is // that in alias_problem.py, the direct import of `foo` does not flow to a normal exit of // the module. Instead there is a second variable foo coming from `from .other import*` that // goes to the normal exit of the module. -from Module m, EssaVariable v, string useToNormalExit +from Module m, SsaImpl::EssaVariable v, string useToNormalExit where m = v.getScope().getEnclosingModule() and not m.getName() in ["pkg.use", "pkg.foo_def"] and v.getName() = "foo" and - if v.getAUse() = m.getANormalExit() + if + exists(Cfg::ControlFlowNode exit | + exit.isNormalExit() and exit.getScope() = m and v.getAUse() = exit + ) then useToNormalExit = "use to normal exit" else useToNormalExit = "no use to normal exit" select m, v, useToNormalExit diff --git a/python/ql/test/library-tests/dataflow/use-use-flow/use-use-counts.expected b/python/ql/test/library-tests/dataflow/use-use-flow/use-use-counts.expected index 92f5114fb8f4..ee3c09b7995d 100644 --- a/python/ql/test/library-tests/dataflow/use-use-flow/use-use-counts.expected +++ b/python/ql/test/library-tests/dataflow/use-use-flow/use-use-counts.expected @@ -1,24 +1,25 @@ implicit_use_count -| 0 | +| 1 | implicit_use +| read_explosion.py:9:1:9:12 | Normal Exit | source_use_count | 6 | source_use -| read_explosion.py:17:15:17:15 | ControlFlowNode for x | -| read_explosion.py:19:13:19:13 | ControlFlowNode for x | -| read_explosion.py:21:11:21:11 | ControlFlowNode for x | -| read_explosion.py:28:15:28:15 | ControlFlowNode for x | -| read_explosion.py:30:13:30:13 | ControlFlowNode for x | -| read_explosion.py:32:11:32:11 | ControlFlowNode for x | +| read_explosion.py:17:15:17:15 | x | +| read_explosion.py:19:13:19:13 | x | +| read_explosion.py:21:11:21:11 | x | +| read_explosion.py:28:15:28:15 | x | +| read_explosion.py:30:13:30:13 | x | +| read_explosion.py:32:11:32:11 | x | use_use_edge_count | 9 | use_use_edge -| read_explosion.py:17:15:17:15 | ControlFlowNode for x | read_explosion.py:28:15:28:15 | ControlFlowNode for x | -| read_explosion.py:17:15:17:15 | ControlFlowNode for x | read_explosion.py:30:13:30:13 | ControlFlowNode for x | -| read_explosion.py:17:15:17:15 | ControlFlowNode for x | read_explosion.py:32:11:32:11 | ControlFlowNode for x | -| read_explosion.py:19:13:19:13 | ControlFlowNode for x | read_explosion.py:28:15:28:15 | ControlFlowNode for x | -| read_explosion.py:19:13:19:13 | ControlFlowNode for x | read_explosion.py:30:13:30:13 | ControlFlowNode for x | -| read_explosion.py:19:13:19:13 | ControlFlowNode for x | read_explosion.py:32:11:32:11 | ControlFlowNode for x | -| read_explosion.py:21:11:21:11 | ControlFlowNode for x | read_explosion.py:28:15:28:15 | ControlFlowNode for x | -| read_explosion.py:21:11:21:11 | ControlFlowNode for x | read_explosion.py:30:13:30:13 | ControlFlowNode for x | -| read_explosion.py:21:11:21:11 | ControlFlowNode for x | read_explosion.py:32:11:32:11 | ControlFlowNode for x | +| read_explosion.py:17:15:17:15 | x | read_explosion.py:28:15:28:15 | x | +| read_explosion.py:17:15:17:15 | x | read_explosion.py:30:13:30:13 | x | +| read_explosion.py:17:15:17:15 | x | read_explosion.py:32:11:32:11 | x | +| read_explosion.py:19:13:19:13 | x | read_explosion.py:28:15:28:15 | x | +| read_explosion.py:19:13:19:13 | x | read_explosion.py:30:13:30:13 | x | +| read_explosion.py:19:13:19:13 | x | read_explosion.py:32:11:32:11 | x | +| read_explosion.py:21:11:21:11 | x | read_explosion.py:28:15:28:15 | x | +| read_explosion.py:21:11:21:11 | x | read_explosion.py:30:13:30:13 | x | +| read_explosion.py:21:11:21:11 | x | read_explosion.py:32:11:32:11 | x | diff --git a/python/ql/test/library-tests/dataflow/use-use-flow/use-use-counts.ql b/python/ql/test/library-tests/dataflow/use-use-flow/use-use-counts.ql index ff18cc66f68b..f00e808b574c 100644 --- a/python/ql/test/library-tests/dataflow/use-use-flow/use-use-counts.ql +++ b/python/ql/test/library-tests/dataflow/use-use-flow/use-use-counts.ql @@ -1,26 +1,28 @@ import python +private import semmle.python.controlflow.internal.Cfg as Cfg +private import semmle.python.dataflow.new.internal.SsaImpl as SsaImpl private import semmle.python.dataflow.new.internal.DataFlowPrivate query int implicit_use_count() { - exists(SsaSourceVariable x | x.getName() = "x" | result = count(x.getAnImplicitUse())) + exists(SsaImpl::SsaSourceVariable x | x.getName() = "x" | result = count(x.getAnImplicitUse())) } -query ControlFlowNode implicit_use() { - exists(SsaSourceVariable x | x.getName() = "x" | result = x.getAnImplicitUse()) +query Cfg::ControlFlowNode implicit_use() { + exists(SsaImpl::SsaSourceVariable x | x.getName() = "x" | result = x.getAnImplicitUse()) } query int source_use_count() { - exists(SsaSourceVariable x | x.getName() = "x" | result = count(x.getASourceUse())) + exists(SsaImpl::SsaSourceVariable x | x.getName() = "x" | result = count(x.getASourceUse())) } -query ControlFlowNode source_use() { - exists(SsaSourceVariable x | x.getName() = "x" | result = x.getASourceUse()) +query Cfg::ControlFlowNode source_use() { + exists(SsaImpl::SsaSourceVariable x | x.getName() = "x" | result = x.getASourceUse()) } query int use_use_edge_count() { - exists(SsaSourceVariable x | x.getName() = "x" | + exists(SsaImpl::SsaSourceVariable x | x.getName() = "x" | result = - count(NameNode use1, NameNode use2 | + count(Cfg::NameNode use1, Cfg::NameNode use2 | use1 = x.getAUse() and use2 = x.getAUse() and LocalFlow::useToNextUse(use1, use2) @@ -28,8 +30,8 @@ query int use_use_edge_count() { ) } -query predicate use_use_edge(NameNode use1, NameNode use2) { - exists(SsaSourceVariable x | x.getName() = "x" | +query predicate use_use_edge(Cfg::NameNode use1, Cfg::NameNode use2) { + exists(SsaImpl::SsaSourceVariable x | x.getName() = "x" | use1 = x.getAUse() and use2 = x.getAUse() and LocalFlow::useToNextUse(use1, use2) diff --git a/python/ql/test/library-tests/essa/ssa-compute/CONSISTENCY/TypeTrackingConsistency.expected b/python/ql/test/library-tests/essa/ssa-compute/CONSISTENCY/TypeTrackingConsistency.expected deleted file mode 100644 index 0e829fd207f0..000000000000 --- a/python/ql/test/library-tests/essa/ssa-compute/CONSISTENCY/TypeTrackingConsistency.expected +++ /dev/null @@ -1,6 +0,0 @@ -unreachableNode -| test2.py:16:17:16:17 | ControlFlowNode for y | Unreachable node in step of kind load Attribute bar. | -| test2.py:25:23:25:23 | ControlFlowNode for x | Unreachable node in step of kind load Attribute attribute. | -| test2.py:25:23:25:23 | ControlFlowNode for x | Unreachable node in step of kind simpleLocalSmallStep. | -| test2.py:26:17:26:17 | ControlFlowNode for y | Unreachable node in step of kind load Attribute bar. | -| test2.py:27:23:27:23 | ControlFlowNode for x | Unreachable node in step of kind simpleLocalSmallStep. | diff --git a/python/ql/test/library-tests/frameworks/aiohttp/InlineTaintTest.expected b/python/ql/test/library-tests/frameworks/aiohttp/InlineTaintTest.expected index 020c338fd192..8f8d5d302fb6 100644 --- a/python/ql/test/library-tests/frameworks/aiohttp/InlineTaintTest.expected +++ b/python/ql/test/library-tests/frameworks/aiohttp/InlineTaintTest.expected @@ -1,3 +1,10 @@ argumentToEnsureNotTaintedNotMarkedAsSpurious untaintedArgumentToEnsureTaintedNotMarkedAsMissing +| taint_test.py:151:9:151:15 | taint_test.py:151 | ERROR, you should add `# $ MISSING: tainted` annotation | request | +| taint_test.py:152:9:152:19 | taint_test.py:152 | ERROR, you should add `# $ MISSING: tainted` annotation | request.url | +| taint_test.py:153:9:153:36 | taint_test.py:153 | ERROR, you should add `# $ MISSING: tainted` annotation | Await | testFailures +| taint_test.py:151:18:151:28 | Comment # $ tainted | Missing result: tainted | +| taint_test.py:152:22:152:32 | Comment # $ tainted | Missing result: tainted | +| taint_test.py:153:39:153:49 | Comment # $ tainted | Missing result: tainted | +| taint_test.py:168:76:168:96 | Comment # $ SPURIOUS: tainted | Fixed spurious result: tainted | diff --git a/python/ql/test/library-tests/frameworks/aiohttp/InlineTaintTest.ql b/python/ql/test/library-tests/frameworks/aiohttp/InlineTaintTest.ql index caaa22ef1942..9b9604760054 100644 --- a/python/ql/test/library-tests/frameworks/aiohttp/InlineTaintTest.ql +++ b/python/ql/test/library-tests/frameworks/aiohttp/InlineTaintTest.ql @@ -1,8 +1,9 @@ import experimental.meta.InlineTaintTest +private import semmle.python.controlflow.internal.Cfg as Cfg -predicate isSafe(DataFlow::GuardNode g, ControlFlowNode node, boolean branch) { - g.(CallNode).getFunction().(NameNode).getId() = "is_safe" and - node = g.(CallNode).getArg(_) and +predicate isSafe(DataFlow::GuardNode g, Cfg::ControlFlowNode node, boolean branch) { + g.(Cfg::CallNode).getFunction().(Cfg::NameNode).getId() = "is_safe" and + node = g.(Cfg::CallNode).getArg(_) and branch = true } diff --git a/python/ql/test/library-tests/frameworks/cryptography/EcKeygenOrigin.expected b/python/ql/test/library-tests/frameworks/cryptography/EcKeygenOrigin.expected index a94092533f09..672e394a7271 100644 --- a/python/ql/test/library-tests/frameworks/cryptography/EcKeygenOrigin.expected +++ b/python/ql/test/library-tests/frameworks/cryptography/EcKeygenOrigin.expected @@ -1,5 +1,5 @@ -| ec_keygen_origin.py:8:1:8:45 | ControlFlowNode for Attribute() | 384 | ec_keygen_origin.py:8:31:8:42 | ControlFlowNode for Attribute | -| ec_keygen_origin.py:9:1:9:43 | ControlFlowNode for Attribute() | 384 | ec_keygen_origin.py:9:31:9:42 | ControlFlowNode for Attribute | -| ec_keygen_origin.py:12:1:12:36 | ControlFlowNode for Attribute() | 384 | ec_keygen_origin.py:11:9:11:20 | ControlFlowNode for Attribute | -| ec_keygen_origin.py:15:1:15:39 | ControlFlowNode for Attribute() | 384 | ec_keygen_origin.py:11:9:11:20 | ControlFlowNode for Attribute | -| ec_keygen_origin.py:20:1:20:32 | ControlFlowNode for Attribute() | 384 | ec_keygen_origin.py:6:58:6:66 | ControlFlowNode for ImportMember | +| ec_keygen_origin.py:8:1:8:45 | After Attribute() | 384 | ec_keygen_origin.py:8:31:8:42 | After Attribute | +| ec_keygen_origin.py:9:1:9:43 | After Attribute() | 384 | ec_keygen_origin.py:9:31:9:42 | After Attribute | +| ec_keygen_origin.py:12:1:12:36 | After Attribute() | 384 | ec_keygen_origin.py:11:9:11:20 | After Attribute | +| ec_keygen_origin.py:15:1:15:39 | After Attribute() | 384 | ec_keygen_origin.py:11:9:11:20 | After Attribute | +| ec_keygen_origin.py:20:1:20:32 | After Attribute() | 384 | ec_keygen_origin.py:6:58:6:66 | After ImportMember | diff --git a/python/ql/test/library-tests/frameworks/data/test.expected b/python/ql/test/library-tests/frameworks/data/test.expected index 84cc34585ca6..db383626b49c 100644 --- a/python/ql/test/library-tests/frameworks/data/test.expected +++ b/python/ql/test/library-tests/frameworks/data/test.expected @@ -1,114 +1,114 @@ taintFlow -| test.py:3:5:3:15 | ControlFlowNode for getSource() | test.py:4:8:4:8 | ControlFlowNode for x | -| test.py:3:5:3:15 | ControlFlowNode for getSource() | test.py:7:17:7:17 | ControlFlowNode for x | -| test.py:9:8:9:14 | ControlFlowNode for alias() | test.py:9:8:9:14 | ControlFlowNode for alias() | -| test.py:10:8:10:22 | ControlFlowNode for Attribute() | test.py:10:8:10:22 | ControlFlowNode for Attribute() | -| test.py:11:8:11:30 | ControlFlowNode for Attribute() | test.py:11:8:11:30 | ControlFlowNode for Attribute() | -| test.py:71:28:71:38 | ControlFlowNode for getSource() | test.py:71:8:71:39 | ControlFlowNode for Attribute() | -| test.py:75:5:75:15 | ControlFlowNode for getSource() | test.py:76:22:76:22 | ControlFlowNode for x | -| test.py:75:5:75:15 | ControlFlowNode for getSource() | test.py:77:22:77:22 | ControlFlowNode for y | -| test.py:81:36:81:46 | ControlFlowNode for getSource() | test.py:81:8:81:47 | ControlFlowNode for Attribute() | -| test.py:83:50:83:60 | ControlFlowNode for getSource() | test.py:83:8:83:61 | ControlFlowNode for Attribute() | -| test.py:86:49:86:59 | ControlFlowNode for getSource() | test.py:86:8:86:60 | ControlFlowNode for Attribute() | -| test.py:87:56:87:66 | ControlFlowNode for getSource() | test.py:87:8:87:67 | ControlFlowNode for Attribute() | -| test.py:114:19:114:29 | ControlFlowNode for getSource() | test.py:114:19:114:29 | ControlFlowNode for getSource() | -| test.py:115:20:115:30 | ControlFlowNode for getSource() | test.py:115:20:115:30 | ControlFlowNode for getSource() | -| test.py:116:31:116:41 | ControlFlowNode for getSource() | test.py:116:31:116:41 | ControlFlowNode for getSource() | -| test.py:117:31:117:41 | ControlFlowNode for getSource() | test.py:117:31:117:41 | ControlFlowNode for getSource() | -| test.py:118:35:118:45 | ControlFlowNode for getSource() | test.py:118:35:118:45 | ControlFlowNode for getSource() | +| test.py:3:5:3:15 | After getSource() | test.py:4:8:4:8 | x | +| test.py:3:5:3:15 | After getSource() | test.py:7:17:7:17 | x | +| test.py:9:8:9:14 | After alias() | test.py:9:8:9:14 | After alias() | +| test.py:10:8:10:22 | After Attribute() | test.py:10:8:10:22 | After Attribute() | +| test.py:11:8:11:30 | After Attribute() | test.py:11:8:11:30 | After Attribute() | +| test.py:71:28:71:38 | After getSource() | test.py:71:8:71:39 | After Attribute() | +| test.py:75:5:75:15 | After getSource() | test.py:76:22:76:22 | x | +| test.py:75:5:75:15 | After getSource() | test.py:77:22:77:22 | y | +| test.py:81:36:81:46 | After getSource() | test.py:81:8:81:47 | After Attribute() | +| test.py:83:50:83:60 | After getSource() | test.py:83:8:83:61 | After Attribute() | +| test.py:86:49:86:59 | After getSource() | test.py:86:8:86:60 | After Attribute() | +| test.py:87:56:87:66 | After getSource() | test.py:87:8:87:67 | After Attribute() | +| test.py:114:19:114:29 | After getSource() | test.py:114:19:114:29 | After getSource() | +| test.py:115:20:115:30 | After getSource() | test.py:115:20:115:30 | After getSource() | +| test.py:116:31:116:41 | After getSource() | test.py:116:31:116:41 | After getSource() | +| test.py:117:31:117:41 | After getSource() | test.py:117:31:117:41 | After getSource() | +| test.py:118:35:118:45 | After getSource() | test.py:118:35:118:45 | After getSource() | isSink -| test.py:4:8:4:8 | ControlFlowNode for x | test-sink | -| test.py:7:17:7:17 | ControlFlowNode for x | test-sink | -| test.py:9:8:9:14 | ControlFlowNode for alias() | test-sink | -| test.py:10:8:10:22 | ControlFlowNode for Attribute() | test-sink | -| test.py:11:8:11:30 | ControlFlowNode for Attribute() | test-sink | -| test.py:12:8:12:34 | ControlFlowNode for Attribute() | test-sink | -| test.py:16:11:16:13 | ControlFlowNode for one | test-sink | -| test.py:17:19:17:21 | ControlFlowNode for two | test-sink | -| test.py:17:24:17:28 | ControlFlowNode for three | test-sink | -| test.py:17:31:17:34 | ControlFlowNode for four | test-sink | -| test.py:18:37:18:40 | ControlFlowNode for five | test-sink | -| test.py:19:21:19:26 | ControlFlowNode for second | test-sink | -| test.py:30:21:30:23 | ControlFlowNode for one | test-sink | -| test.py:32:22:32:24 | ControlFlowNode for one | test-sink | -| test.py:32:27:32:29 | ControlFlowNode for two | test-sink | -| test.py:33:22:33:24 | ControlFlowNode for one | test-sink | -| test.py:33:27:33:29 | ControlFlowNode for two | test-sink | -| test.py:33:32:33:36 | ControlFlowNode for three | test-sink | -| test.py:57:27:57:33 | ControlFlowNode for arg_pos | test-sink | -| test.py:66:17:66:20 | ControlFlowNode for arg1 | test-sink | -| test.py:66:23:66:26 | ControlFlowNode for arg2 | test-sink | -| test.py:66:34:66:43 | ControlFlowNode for namedThing | test-sink | -| test.py:67:34:67:44 | ControlFlowNode for secondNamed | test-sink | -| test.py:71:8:71:39 | ControlFlowNode for Attribute() | test-sink | -| test.py:72:8:72:47 | ControlFlowNode for Attribute() | test-sink | -| test.py:76:22:76:22 | ControlFlowNode for x | test-sink | -| test.py:77:22:77:22 | ControlFlowNode for y | test-sink | -| test.py:78:22:78:22 | ControlFlowNode for z | test-sink | -| test.py:81:8:81:47 | ControlFlowNode for Attribute() | test-sink | -| test.py:82:8:82:54 | ControlFlowNode for Attribute() | test-sink | -| test.py:83:8:83:61 | ControlFlowNode for Attribute() | test-sink | -| test.py:85:8:85:53 | ControlFlowNode for Attribute() | test-sink | -| test.py:86:8:86:60 | ControlFlowNode for Attribute() | test-sink | -| test.py:87:8:87:67 | ControlFlowNode for Attribute() | test-sink | -| test.py:89:21:89:23 | ControlFlowNode for one | test-sink | -| test.py:91:21:91:23 | ControlFlowNode for one | test-sink | -| test.py:91:30:91:32 | ControlFlowNode for two | test-sink | -| test.py:98:6:98:9 | ControlFlowNode for baz2 | test-sink | -| test.py:114:19:114:29 | ControlFlowNode for getSource() | test-sink | -| test.py:115:20:115:30 | ControlFlowNode for getSource() | test-sink | -| test.py:116:31:116:41 | ControlFlowNode for getSource() | test-sink | -| test.py:117:31:117:41 | ControlFlowNode for getSource() | test-sink | -| test.py:118:35:118:45 | ControlFlowNode for getSource() | test-sink | +| test.py:4:8:4:8 | x | test-sink | +| test.py:7:17:7:17 | x | test-sink | +| test.py:9:8:9:14 | After alias() | test-sink | +| test.py:10:8:10:22 | After Attribute() | test-sink | +| test.py:11:8:11:30 | After Attribute() | test-sink | +| test.py:12:8:12:34 | After Attribute() | test-sink | +| test.py:16:11:16:13 | one | test-sink | +| test.py:17:19:17:21 | two | test-sink | +| test.py:17:24:17:28 | three | test-sink | +| test.py:17:31:17:34 | four | test-sink | +| test.py:18:37:18:40 | five | test-sink | +| test.py:19:21:19:26 | second | test-sink | +| test.py:30:21:30:23 | one | test-sink | +| test.py:32:22:32:24 | one | test-sink | +| test.py:32:27:32:29 | two | test-sink | +| test.py:33:22:33:24 | one | test-sink | +| test.py:33:27:33:29 | two | test-sink | +| test.py:33:32:33:36 | three | test-sink | +| test.py:57:27:57:33 | arg_pos | test-sink | +| test.py:66:17:66:20 | arg1 | test-sink | +| test.py:66:23:66:26 | arg2 | test-sink | +| test.py:66:34:66:43 | namedThing | test-sink | +| test.py:67:34:67:44 | secondNamed | test-sink | +| test.py:71:8:71:39 | After Attribute() | test-sink | +| test.py:72:8:72:47 | After Attribute() | test-sink | +| test.py:76:22:76:22 | x | test-sink | +| test.py:77:22:77:22 | y | test-sink | +| test.py:78:22:78:22 | z | test-sink | +| test.py:81:8:81:47 | After Attribute() | test-sink | +| test.py:82:8:82:54 | After Attribute() | test-sink | +| test.py:83:8:83:61 | After Attribute() | test-sink | +| test.py:85:8:85:53 | After Attribute() | test-sink | +| test.py:86:8:86:60 | After Attribute() | test-sink | +| test.py:87:8:87:67 | After Attribute() | test-sink | +| test.py:89:21:89:23 | one | test-sink | +| test.py:91:21:91:23 | one | test-sink | +| test.py:91:30:91:32 | two | test-sink | +| test.py:98:6:98:9 | baz2 | test-sink | +| test.py:114:19:114:29 | After getSource() | test-sink | +| test.py:115:20:115:30 | After getSource() | test-sink | +| test.py:116:31:116:41 | After getSource() | test-sink | +| test.py:117:31:117:41 | After getSource() | test-sink | +| test.py:118:35:118:45 | After getSource() | test-sink | isSource -| test.py:3:5:3:15 | ControlFlowNode for getSource() | test-source | -| test.py:9:8:9:14 | ControlFlowNode for alias() | test-source | -| test.py:10:8:10:14 | ControlFlowNode for alias() | test-source | -| test.py:10:8:10:22 | ControlFlowNode for Attribute() | test-source | -| test.py:11:8:11:14 | ControlFlowNode for alias() | test-source | -| test.py:11:8:11:22 | ControlFlowNode for Attribute() | test-source | -| test.py:11:8:11:30 | ControlFlowNode for Attribute() | test-source | -| test.py:12:8:12:14 | ControlFlowNode for alias() | test-source | -| test.py:12:8:12:22 | ControlFlowNode for Attribute() | test-source | -| test.py:23:24:23:26 | ControlFlowNode for one | test-source | -| test.py:24:33:24:35 | ControlFlowNode for two | test-source | -| test.py:24:38:24:42 | ControlFlowNode for three | test-source | -| test.py:24:45:24:48 | ControlFlowNode for four | test-source | -| test.py:25:34:25:39 | ControlFlowNode for second | test-source | -| test.py:39:11:39:20 | ControlFlowNode for Await | test-source | -| test.py:41:8:41:27 | ControlFlowNode for Attribute() | test-source | -| test.py:46:7:46:16 | ControlFlowNode for SubClass() | test-source | -| test.py:51:8:51:18 | ControlFlowNode for Sub2Class() | test-source | -| test.py:53:7:53:16 | ControlFlowNode for Attribute() | test-source | -| test.py:60:13:60:16 | ControlFlowNode for self | test-source | -| test.py:60:24:60:28 | ControlFlowNode for named | test-source | -| test.py:63:36:63:39 | ControlFlowNode for arg2 | test-source | -| test.py:63:42:63:45 | ControlFlowNode for arg3 | test-source | -| test.py:63:48:63:51 | ControlFlowNode for arg4 | test-source | -| test.py:63:54:63:57 | ControlFlowNode for arg5 | test-source | -| test.py:71:28:71:38 | ControlFlowNode for getSource() | test-source | -| test.py:72:36:72:46 | ControlFlowNode for getSource() | test-source | -| test.py:75:5:75:15 | ControlFlowNode for getSource() | test-source | -| test.py:81:36:81:46 | ControlFlowNode for getSource() | test-source | -| test.py:82:43:82:53 | ControlFlowNode for getSource() | test-source | -| test.py:83:50:83:60 | ControlFlowNode for getSource() | test-source | -| test.py:85:42:85:52 | ControlFlowNode for getSource() | test-source | -| test.py:86:49:86:59 | ControlFlowNode for getSource() | test-source | -| test.py:87:56:87:66 | ControlFlowNode for getSource() | test-source | -| test.py:101:29:101:31 | ControlFlowNode for arg | test-source | -| test.py:104:24:104:29 | ControlFlowNode for param1 | test-source | -| test.py:104:32:104:37 | ControlFlowNode for param2 | test-source | -| test.py:107:24:107:28 | ControlFlowNode for name1 | test-source | -| test.py:107:31:107:35 | ControlFlowNode for name2 | test-source | -| test.py:114:19:114:29 | ControlFlowNode for getSource() | test-source | -| test.py:115:20:115:30 | ControlFlowNode for getSource() | test-source | -| test.py:116:31:116:41 | ControlFlowNode for getSource() | test-source | -| test.py:117:31:117:41 | ControlFlowNode for getSource() | test-source | -| test.py:118:35:118:45 | ControlFlowNode for getSource() | test-source | -| test.py:119:20:119:30 | ControlFlowNode for getSource() | test-source | -| test.py:124:1:124:33 | ControlFlowNode for Attribute() | test-source | -| test.py:126:11:126:43 | ControlFlowNode for Attribute() | test-source | -| test.py:129:11:129:39 | ControlFlowNode for Attribute() | test-source | +| test.py:3:5:3:15 | After getSource() | test-source | +| test.py:9:8:9:14 | After alias() | test-source | +| test.py:10:8:10:14 | After alias() | test-source | +| test.py:10:8:10:22 | After Attribute() | test-source | +| test.py:11:8:11:14 | After alias() | test-source | +| test.py:11:8:11:22 | After Attribute() | test-source | +| test.py:11:8:11:30 | After Attribute() | test-source | +| test.py:12:8:12:14 | After alias() | test-source | +| test.py:12:8:12:22 | After Attribute() | test-source | +| test.py:23:24:23:26 | one | test-source | +| test.py:24:33:24:35 | two | test-source | +| test.py:24:38:24:42 | three | test-source | +| test.py:24:45:24:48 | four | test-source | +| test.py:25:34:25:39 | second | test-source | +| test.py:39:11:39:20 | After Await | test-source | +| test.py:41:8:41:27 | After Attribute() | test-source | +| test.py:46:7:46:16 | After SubClass() | test-source | +| test.py:51:8:51:18 | After Sub2Class() | test-source | +| test.py:53:7:53:16 | After Attribute() | test-source | +| test.py:60:13:60:16 | self | test-source | +| test.py:60:24:60:28 | named | test-source | +| test.py:63:36:63:39 | arg2 | test-source | +| test.py:63:42:63:45 | arg3 | test-source | +| test.py:63:48:63:51 | arg4 | test-source | +| test.py:63:54:63:57 | arg5 | test-source | +| test.py:71:28:71:38 | After getSource() | test-source | +| test.py:72:36:72:46 | After getSource() | test-source | +| test.py:75:5:75:15 | After getSource() | test-source | +| test.py:81:36:81:46 | After getSource() | test-source | +| test.py:82:43:82:53 | After getSource() | test-source | +| test.py:83:50:83:60 | After getSource() | test-source | +| test.py:85:42:85:52 | After getSource() | test-source | +| test.py:86:49:86:59 | After getSource() | test-source | +| test.py:87:56:87:66 | After getSource() | test-source | +| test.py:101:29:101:31 | arg | test-source | +| test.py:104:24:104:29 | param1 | test-source | +| test.py:104:32:104:37 | param2 | test-source | +| test.py:107:24:107:28 | name1 | test-source | +| test.py:107:31:107:35 | name2 | test-source | +| test.py:114:19:114:29 | After getSource() | test-source | +| test.py:115:20:115:30 | After getSource() | test-source | +| test.py:116:31:116:41 | After getSource() | test-source | +| test.py:117:31:117:41 | After getSource() | test-source | +| test.py:118:35:118:45 | After getSource() | test-source | +| test.py:119:20:119:30 | After getSource() | test-source | +| test.py:124:1:124:33 | After Attribute() | test-source | +| test.py:126:11:126:43 | After Attribute() | test-source | +| test.py:129:11:129:39 | After Attribute() | test-source | syntaxErrors | Member[foo | | Member[foo] .Member[bar] | diff --git a/python/ql/test/library-tests/frameworks/django-orm/CONSISTENCY/DataFlowConsistency.expected b/python/ql/test/library-tests/frameworks/django-orm/CONSISTENCY/DataFlowConsistency.expected index 8160545f7139..dfdfd1758365 100644 --- a/python/ql/test/library-tests/frameworks/django-orm/CONSISTENCY/DataFlowConsistency.expected +++ b/python/ql/test/library-tests/frameworks/django-orm/CONSISTENCY/DataFlowConsistency.expected @@ -1,49 +1,49 @@ storeStepIsLocal -| testapp/orm_form_test.py:6:1:6:28 | [orm-model] Class MyModel | testapp/tests.py:83:16:83:36 | ControlFlowNode for Attribute() | Store step does not preserve enclosing callable. | -| testapp/orm_form_test.py:6:1:6:28 | [orm-model] Class MyModel | testapp/tests.py:84:16:84:43 | ControlFlowNode for Attribute() | Store step does not preserve enclosing callable. | -| testapp/orm_form_test.py:6:1:6:28 | [orm-model] Class MyModel | testapp/tests.py:85:16:85:36 | ControlFlowNode for Attribute() | Store step does not preserve enclosing callable. | -| testapp/orm_inheritance.py:45:15:45:20 | ControlFlowNode for SOURCE | testapp/orm_inheritance.py:29:1:29:25 | [orm-model] Class Book | Store step does not preserve enclosing callable. | -| testapp/orm_inheritance.py:76:15:76:20 | ControlFlowNode for SOURCE | testapp/orm_inheritance.py:29:1:29:25 | [orm-model] Class Book | Store step does not preserve enclosing callable. | -| testapp/orm_inheritance.py:76:15:76:20 | ControlFlowNode for SOURCE | testapp/orm_inheritance.py:33:1:33:25 | [orm-model] Class PhysicalBook | Store step does not preserve enclosing callable. | -| testapp/orm_inheritance.py:77:27:77:32 | ControlFlowNode for SOURCE | testapp/orm_inheritance.py:33:1:33:25 | [orm-model] Class PhysicalBook | Store step does not preserve enclosing callable. | -| testapp/orm_inheritance.py:78:35:78:40 | ControlFlowNode for SOURCE | testapp/orm_inheritance.py:33:1:33:25 | [orm-model] Class PhysicalBook | Store step does not preserve enclosing callable. | -| testapp/orm_inheritance.py:93:15:93:26 | ControlFlowNode for StringLiteral | testapp/orm_inheritance.py:29:1:29:25 | [orm-model] Class Book | Store step does not preserve enclosing callable. | -| testapp/orm_inheritance.py:93:15:93:26 | ControlFlowNode for StringLiteral | testapp/orm_inheritance.py:38:1:38:18 | [orm-model] Class EBook | Store step does not preserve enclosing callable. | -| testapp/orm_inheritance.py:94:23:94:28 | ControlFlowNode for StringLiteral | testapp/orm_inheritance.py:38:1:38:18 | [orm-model] Class EBook | Store step does not preserve enclosing callable. | -| testapp/orm_inheritance.py:95:35:95:40 | ControlFlowNode for StringLiteral | testapp/orm_inheritance.py:38:1:38:18 | [orm-model] Class EBook | Store step does not preserve enclosing callable. | -| testapp/orm_inheritance.py:133:15:133:20 | ControlFlowNode for SOURCE | testapp/orm_inheritance.py:117:1:117:33 | [orm-model] Class PolyBook | Store step does not preserve enclosing callable. | -| testapp/orm_inheritance.py:167:15:167:20 | ControlFlowNode for SOURCE | testapp/orm_inheritance.py:117:1:117:33 | [orm-model] Class PolyBook | Store step does not preserve enclosing callable. | -| testapp/orm_inheritance.py:167:15:167:20 | ControlFlowNode for SOURCE | testapp/orm_inheritance.py:121:1:121:33 | [orm-model] Class PolyPhysicalBook | Store step does not preserve enclosing callable. | -| testapp/orm_inheritance.py:168:27:168:32 | ControlFlowNode for SOURCE | testapp/orm_inheritance.py:121:1:121:33 | [orm-model] Class PolyPhysicalBook | Store step does not preserve enclosing callable. | -| testapp/orm_inheritance.py:169:35:169:40 | ControlFlowNode for SOURCE | testapp/orm_inheritance.py:121:1:121:33 | [orm-model] Class PolyPhysicalBook | Store step does not preserve enclosing callable. | -| testapp/orm_inheritance.py:183:15:183:26 | ControlFlowNode for StringLiteral | testapp/orm_inheritance.py:117:1:117:33 | [orm-model] Class PolyBook | Store step does not preserve enclosing callable. | -| testapp/orm_inheritance.py:183:15:183:26 | ControlFlowNode for StringLiteral | testapp/orm_inheritance.py:126:1:126:26 | [orm-model] Class PolyEBook | Store step does not preserve enclosing callable. | -| testapp/orm_inheritance.py:184:23:184:28 | ControlFlowNode for StringLiteral | testapp/orm_inheritance.py:126:1:126:26 | [orm-model] Class PolyEBook | Store step does not preserve enclosing callable. | -| testapp/orm_inheritance.py:185:35:185:40 | ControlFlowNode for StringLiteral | testapp/orm_inheritance.py:126:1:126:26 | [orm-model] Class PolyEBook | Store step does not preserve enclosing callable. | -| testapp/orm_security_tests.py:15:1:15:27 | [orm-model] Class Person | testapp/orm_security_tests.py:42:23:42:42 | ControlFlowNode for Attribute() | Store step does not preserve enclosing callable. | -| testapp/orm_tests.py:115:41:115:46 | ControlFlowNode for SOURCE | testapp/orm_tests.py:110:1:110:30 | [orm-model] Class TestSave5 | Store step does not preserve enclosing callable. | -| testapp/orm_tests.py:131:86:131:91 | ControlFlowNode for SOURCE | testapp/orm_tests.py:126:1:126:30 | [orm-model] Class TestSave6 | Store step does not preserve enclosing callable. | -| testapp/orm_tests.py:149:89:149:94 | ControlFlowNode for SOURCE | testapp/orm_tests.py:144:1:144:30 | [orm-model] Class TestSave7 | Store step does not preserve enclosing callable. | -| testapp/orm_tests.py:161:1:161:30 | [orm-model] Class TestSave8 | testapp/orm_tests.py:168:22:168:44 | ControlFlowNode for Attribute() | Store step does not preserve enclosing callable. | -| testapp/orm_tests.py:165:35:165:39 | ControlFlowNode for StringLiteral | testapp/orm_tests.py:161:1:161:30 | [orm-model] Class TestSave8 | Store step does not preserve enclosing callable. | -| testapp/orm_tests.py:168:58:168:63 | ControlFlowNode for SOURCE | testapp/orm_tests.py:161:1:161:30 | [orm-model] Class TestSave8 | Store step does not preserve enclosing callable. | -| testapp/orm_tests.py:184:41:184:45 | ControlFlowNode for StringLiteral | testapp/orm_tests.py:177:1:177:30 | [orm-model] Class TestSave9 | Store step does not preserve enclosing callable. | -| testapp/orm_tests.py:185:49:185:51 | ControlFlowNode for obj | testapp/orm_tests.py:180:1:180:44 | [orm-model] Class TestSave9WithForeignKey | Store step does not preserve enclosing callable. | -| testapp/orm_tests.py:212:55:212:59 | ControlFlowNode for StringLiteral | testapp/orm_tests.py:206:1:206:35 | [orm-model] Class save10_Comment | Store step does not preserve enclosing callable. | -| testapp/orm_tests.py:239:55:239:59 | ControlFlowNode for StringLiteral | testapp/orm_tests.py:233:1:233:35 | [orm-model] Class save11_Comment | Store step does not preserve enclosing callable. | -| testapp/orm_tests.py:273:1:273:31 | [orm-model] Class TestSave13 | testapp/orm_tests.py:281:12:281:35 | ControlFlowNode for Attribute() | Store step does not preserve enclosing callable. | -| testapp/orm_tests.py:294:1:294:29 | [orm-model] Class TestLoad | testapp/orm_tests.py:308:12:308:33 | ControlFlowNode for Attribute() | Store step does not preserve enclosing callable. | -| testapp/orm_tests.py:294:1:294:29 | [orm-model] Class TestLoad | testapp/orm_tests.py:314:12:314:33 | ControlFlowNode for Attribute() | Store step does not preserve enclosing callable. | -| testapp/orm_tests.py:294:1:294:29 | [orm-model] Class TestLoad | testapp/orm_tests.py:320:11:320:32 | ControlFlowNode for Attribute() | Store step does not preserve enclosing callable. | -| testapp/orm_tests.py:294:1:294:29 | [orm-model] Class TestLoad | testapp/orm_tests.py:320:11:320:59 | ControlFlowNode for Attribute() | Store step does not preserve enclosing callable. | -| testapp/orm_tests.py:294:1:294:29 | [orm-model] Class TestLoad | testapp/orm_tests.py:320:11:320:78 | ControlFlowNode for Attribute() | Store step does not preserve enclosing callable. | -| testapp/orm_tests.py:294:1:294:29 | [orm-model] Class TestLoad | testapp/orm_tests.py:324:12:324:33 | ControlFlowNode for Attribute() | Store step does not preserve enclosing callable. | -| testapp/orm_tests.py:294:1:294:29 | [orm-model] Class TestLoad | testapp/orm_tests.py:324:12:324:60 | ControlFlowNode for Attribute() | Store step does not preserve enclosing callable. | -| testapp/orm_tests.py:294:1:294:29 | [orm-model] Class TestLoad | testapp/orm_tests.py:324:12:324:79 | ControlFlowNode for Attribute() | Store step does not preserve enclosing callable. | -| testapp/orm_tests.py:294:1:294:29 | [orm-model] Class TestLoad | testapp/orm_tests.py:331:12:331:33 | ControlFlowNode for Attribute() | Store step does not preserve enclosing callable. | -| testapp/orm_tests.py:294:1:294:29 | [orm-model] Class TestLoad | testapp/orm_tests.py:337:12:337:33 | ControlFlowNode for Attribute() | Store step does not preserve enclosing callable. | -| testapp/orm_tests.py:294:1:294:29 | [orm-model] Class TestLoad | testapp/orm_tests.py:344:12:344:33 | ControlFlowNode for Attribute() | Store step does not preserve enclosing callable. | -| testapp/orm_tests.py:294:1:294:29 | [orm-model] Class TestLoad | testapp/orm_tests.py:350:12:350:33 | ControlFlowNode for Attribute() | Store step does not preserve enclosing callable. | -| testapp/orm_tests.py:294:1:294:29 | [orm-model] Class TestLoad | testapp/orm_tests.py:356:12:356:33 | ControlFlowNode for Attribute() | Store step does not preserve enclosing callable. | -| testapp/orm_tests.py:294:1:294:29 | [orm-model] Class TestLoad | testapp/orm_tests.py:363:9:363:37 | ControlFlowNode for Attribute() | Store step does not preserve enclosing callable. | -| testapp/tests.py:81:33:81:37 | ControlFlowNode for StringLiteral | testapp/orm_form_test.py:6:1:6:28 | [orm-model] Class MyModel | Store step does not preserve enclosing callable. | +| testapp/orm_form_test.py:6:1:6:28 | [orm-model] Class MyModel | testapp/tests.py:83:16:83:36 | After Attribute() | Store step does not preserve enclosing callable. | +| testapp/orm_form_test.py:6:1:6:28 | [orm-model] Class MyModel | testapp/tests.py:84:16:84:43 | After Attribute() | Store step does not preserve enclosing callable. | +| testapp/orm_form_test.py:6:1:6:28 | [orm-model] Class MyModel | testapp/tests.py:85:16:85:36 | After Attribute() | Store step does not preserve enclosing callable. | +| testapp/orm_inheritance.py:45:15:45:20 | SOURCE | testapp/orm_inheritance.py:29:1:29:25 | [orm-model] Class Book | Store step does not preserve enclosing callable. | +| testapp/orm_inheritance.py:76:15:76:20 | SOURCE | testapp/orm_inheritance.py:29:1:29:25 | [orm-model] Class Book | Store step does not preserve enclosing callable. | +| testapp/orm_inheritance.py:76:15:76:20 | SOURCE | testapp/orm_inheritance.py:33:1:33:25 | [orm-model] Class PhysicalBook | Store step does not preserve enclosing callable. | +| testapp/orm_inheritance.py:77:27:77:32 | SOURCE | testapp/orm_inheritance.py:33:1:33:25 | [orm-model] Class PhysicalBook | Store step does not preserve enclosing callable. | +| testapp/orm_inheritance.py:78:35:78:40 | SOURCE | testapp/orm_inheritance.py:33:1:33:25 | [orm-model] Class PhysicalBook | Store step does not preserve enclosing callable. | +| testapp/orm_inheritance.py:93:15:93:26 | StringLiteral | testapp/orm_inheritance.py:29:1:29:25 | [orm-model] Class Book | Store step does not preserve enclosing callable. | +| testapp/orm_inheritance.py:93:15:93:26 | StringLiteral | testapp/orm_inheritance.py:38:1:38:18 | [orm-model] Class EBook | Store step does not preserve enclosing callable. | +| testapp/orm_inheritance.py:94:23:94:28 | StringLiteral | testapp/orm_inheritance.py:38:1:38:18 | [orm-model] Class EBook | Store step does not preserve enclosing callable. | +| testapp/orm_inheritance.py:95:35:95:40 | StringLiteral | testapp/orm_inheritance.py:38:1:38:18 | [orm-model] Class EBook | Store step does not preserve enclosing callable. | +| testapp/orm_inheritance.py:133:15:133:20 | SOURCE | testapp/orm_inheritance.py:117:1:117:33 | [orm-model] Class PolyBook | Store step does not preserve enclosing callable. | +| testapp/orm_inheritance.py:167:15:167:20 | SOURCE | testapp/orm_inheritance.py:117:1:117:33 | [orm-model] Class PolyBook | Store step does not preserve enclosing callable. | +| testapp/orm_inheritance.py:167:15:167:20 | SOURCE | testapp/orm_inheritance.py:121:1:121:33 | [orm-model] Class PolyPhysicalBook | Store step does not preserve enclosing callable. | +| testapp/orm_inheritance.py:168:27:168:32 | SOURCE | testapp/orm_inheritance.py:121:1:121:33 | [orm-model] Class PolyPhysicalBook | Store step does not preserve enclosing callable. | +| testapp/orm_inheritance.py:169:35:169:40 | SOURCE | testapp/orm_inheritance.py:121:1:121:33 | [orm-model] Class PolyPhysicalBook | Store step does not preserve enclosing callable. | +| testapp/orm_inheritance.py:183:15:183:26 | StringLiteral | testapp/orm_inheritance.py:117:1:117:33 | [orm-model] Class PolyBook | Store step does not preserve enclosing callable. | +| testapp/orm_inheritance.py:183:15:183:26 | StringLiteral | testapp/orm_inheritance.py:126:1:126:26 | [orm-model] Class PolyEBook | Store step does not preserve enclosing callable. | +| testapp/orm_inheritance.py:184:23:184:28 | StringLiteral | testapp/orm_inheritance.py:126:1:126:26 | [orm-model] Class PolyEBook | Store step does not preserve enclosing callable. | +| testapp/orm_inheritance.py:185:35:185:40 | StringLiteral | testapp/orm_inheritance.py:126:1:126:26 | [orm-model] Class PolyEBook | Store step does not preserve enclosing callable. | +| testapp/orm_security_tests.py:15:1:15:27 | [orm-model] Class Person | testapp/orm_security_tests.py:42:23:42:42 | After Attribute() [empty] | Store step does not preserve enclosing callable. | +| testapp/orm_tests.py:115:41:115:46 | SOURCE | testapp/orm_tests.py:110:1:110:30 | [orm-model] Class TestSave5 | Store step does not preserve enclosing callable. | +| testapp/orm_tests.py:131:86:131:91 | SOURCE | testapp/orm_tests.py:126:1:126:30 | [orm-model] Class TestSave6 | Store step does not preserve enclosing callable. | +| testapp/orm_tests.py:149:89:149:94 | SOURCE | testapp/orm_tests.py:144:1:144:30 | [orm-model] Class TestSave7 | Store step does not preserve enclosing callable. | +| testapp/orm_tests.py:161:1:161:30 | [orm-model] Class TestSave8 | testapp/orm_tests.py:168:22:168:44 | After Attribute() | Store step does not preserve enclosing callable. | +| testapp/orm_tests.py:165:35:165:39 | StringLiteral | testapp/orm_tests.py:161:1:161:30 | [orm-model] Class TestSave8 | Store step does not preserve enclosing callable. | +| testapp/orm_tests.py:168:58:168:63 | SOURCE | testapp/orm_tests.py:161:1:161:30 | [orm-model] Class TestSave8 | Store step does not preserve enclosing callable. | +| testapp/orm_tests.py:184:41:184:45 | StringLiteral | testapp/orm_tests.py:177:1:177:30 | [orm-model] Class TestSave9 | Store step does not preserve enclosing callable. | +| testapp/orm_tests.py:185:49:185:51 | obj | testapp/orm_tests.py:180:1:180:44 | [orm-model] Class TestSave9WithForeignKey | Store step does not preserve enclosing callable. | +| testapp/orm_tests.py:212:55:212:59 | StringLiteral | testapp/orm_tests.py:206:1:206:35 | [orm-model] Class save10_Comment | Store step does not preserve enclosing callable. | +| testapp/orm_tests.py:239:55:239:59 | StringLiteral | testapp/orm_tests.py:233:1:233:35 | [orm-model] Class save11_Comment | Store step does not preserve enclosing callable. | +| testapp/orm_tests.py:273:1:273:31 | [orm-model] Class TestSave13 | testapp/orm_tests.py:281:12:281:35 | After Attribute() | Store step does not preserve enclosing callable. | +| testapp/orm_tests.py:294:1:294:29 | [orm-model] Class TestLoad | testapp/orm_tests.py:308:12:308:33 | After Attribute() | Store step does not preserve enclosing callable. | +| testapp/orm_tests.py:294:1:294:29 | [orm-model] Class TestLoad | testapp/orm_tests.py:314:12:314:33 | After Attribute() | Store step does not preserve enclosing callable. | +| testapp/orm_tests.py:294:1:294:29 | [orm-model] Class TestLoad | testapp/orm_tests.py:320:11:320:32 | After Attribute() | Store step does not preserve enclosing callable. | +| testapp/orm_tests.py:294:1:294:29 | [orm-model] Class TestLoad | testapp/orm_tests.py:320:11:320:59 | After Attribute() | Store step does not preserve enclosing callable. | +| testapp/orm_tests.py:294:1:294:29 | [orm-model] Class TestLoad | testapp/orm_tests.py:320:11:320:78 | After Attribute() | Store step does not preserve enclosing callable. | +| testapp/orm_tests.py:294:1:294:29 | [orm-model] Class TestLoad | testapp/orm_tests.py:324:12:324:33 | After Attribute() | Store step does not preserve enclosing callable. | +| testapp/orm_tests.py:294:1:294:29 | [orm-model] Class TestLoad | testapp/orm_tests.py:324:12:324:60 | After Attribute() | Store step does not preserve enclosing callable. | +| testapp/orm_tests.py:294:1:294:29 | [orm-model] Class TestLoad | testapp/orm_tests.py:324:12:324:79 | After Attribute() | Store step does not preserve enclosing callable. | +| testapp/orm_tests.py:294:1:294:29 | [orm-model] Class TestLoad | testapp/orm_tests.py:331:12:331:33 | After Attribute() | Store step does not preserve enclosing callable. | +| testapp/orm_tests.py:294:1:294:29 | [orm-model] Class TestLoad | testapp/orm_tests.py:337:12:337:33 | After Attribute() | Store step does not preserve enclosing callable. | +| testapp/orm_tests.py:294:1:294:29 | [orm-model] Class TestLoad | testapp/orm_tests.py:344:12:344:33 | After Attribute() | Store step does not preserve enclosing callable. | +| testapp/orm_tests.py:294:1:294:29 | [orm-model] Class TestLoad | testapp/orm_tests.py:350:12:350:33 | After Attribute() | Store step does not preserve enclosing callable. | +| testapp/orm_tests.py:294:1:294:29 | [orm-model] Class TestLoad | testapp/orm_tests.py:356:12:356:33 | After Attribute() | Store step does not preserve enclosing callable. | +| testapp/orm_tests.py:294:1:294:29 | [orm-model] Class TestLoad | testapp/orm_tests.py:363:9:363:37 | After Attribute() | Store step does not preserve enclosing callable. | +| testapp/tests.py:81:33:81:37 | StringLiteral | testapp/orm_form_test.py:6:1:6:28 | [orm-model] Class MyModel | Store step does not preserve enclosing callable. | diff --git a/python/ql/test/library-tests/frameworks/django-orm/NormalDataflowTest.expected b/python/ql/test/library-tests/frameworks/django-orm/NormalDataflowTest.expected index 2fad7bb9a843..6c21fdd237e8 100644 --- a/python/ql/test/library-tests/frameworks/django-orm/NormalDataflowTest.expected +++ b/python/ql/test/library-tests/frameworks/django-orm/NormalDataflowTest.expected @@ -1,2 +1,3 @@ missingAnnotationOnSink testFailures +| testapp/orm_tests.py:316:14:316:21 | After Attribute | Unexpected result: flow="SOURCE, l:-16 -> obj.text" | diff --git a/python/ql/test/library-tests/frameworks/django-orm/ReflectedXss.expected b/python/ql/test/library-tests/frameworks/django-orm/ReflectedXss.expected index 938e4d2c4e99..63f4e751a890 100644 --- a/python/ql/test/library-tests/frameworks/django-orm/ReflectedXss.expected +++ b/python/ql/test/library-tests/frameworks/django-orm/ReflectedXss.expected @@ -1,107 +1,107 @@ edges -| testapp/orm_security_tests.py:15:1:15:27 | [orm-model] Class Person [Attribute age] | testapp/orm_security_tests.py:42:23:42:42 | ControlFlowNode for Attribute() [List element, Attribute age] | provenance | | -| testapp/orm_security_tests.py:15:1:15:27 | [orm-model] Class Person [Attribute age] | testapp/orm_security_tests.py:51:14:51:53 | ControlFlowNode for Attribute() [Attribute age] | provenance | | -| testapp/orm_security_tests.py:15:1:15:27 | [orm-model] Class Person [Attribute name] | testapp/orm_security_tests.py:42:23:42:42 | ControlFlowNode for Attribute() [List element, Attribute name] | provenance | | -| testapp/orm_security_tests.py:15:1:15:27 | [orm-model] Class Person [Attribute name] | testapp/orm_security_tests.py:47:14:47:53 | ControlFlowNode for Attribute() [Attribute name] | provenance | | -| testapp/orm_security_tests.py:19:12:19:18 | ControlFlowNode for request | testapp/orm_security_tests.py:22:23:22:42 | ControlFlowNode for Subscript | provenance | AdditionalTaintStep | -| testapp/orm_security_tests.py:19:12:19:18 | ControlFlowNode for request | testapp/orm_security_tests.py:23:22:23:40 | ControlFlowNode for Subscript | provenance | AdditionalTaintStep | -| testapp/orm_security_tests.py:22:9:22:14 | [post] ControlFlowNode for person [Attribute name] | testapp/orm_security_tests.py:23:9:23:14 | ControlFlowNode for person [Attribute name] | provenance | | -| testapp/orm_security_tests.py:22:23:22:42 | ControlFlowNode for Subscript | testapp/orm_security_tests.py:22:9:22:14 | [post] ControlFlowNode for person [Attribute name] | provenance | | -| testapp/orm_security_tests.py:23:9:23:14 | ControlFlowNode for person [Attribute name] | testapp/orm_security_tests.py:28:9:28:14 | ControlFlowNode for person [Attribute name] | provenance | | -| testapp/orm_security_tests.py:23:9:23:14 | [post] ControlFlowNode for person [Attribute age] | testapp/orm_security_tests.py:28:9:28:14 | ControlFlowNode for person [Attribute age] | provenance | | -| testapp/orm_security_tests.py:23:22:23:40 | ControlFlowNode for Subscript | testapp/orm_security_tests.py:23:9:23:14 | [post] ControlFlowNode for person [Attribute age] | provenance | | -| testapp/orm_security_tests.py:28:9:28:14 | ControlFlowNode for person [Attribute age] | testapp/orm_security_tests.py:15:1:15:27 | [orm-model] Class Person [Attribute age] | provenance | | -| testapp/orm_security_tests.py:28:9:28:14 | ControlFlowNode for person [Attribute name] | testapp/orm_security_tests.py:15:1:15:27 | [orm-model] Class Person [Attribute name] | provenance | | -| testapp/orm_security_tests.py:42:13:42:18 | ControlFlowNode for person [Attribute age] | testapp/orm_security_tests.py:43:62:43:67 | ControlFlowNode for person [Attribute age] | provenance | | -| testapp/orm_security_tests.py:42:13:42:18 | ControlFlowNode for person [Attribute name] | testapp/orm_security_tests.py:43:49:43:54 | ControlFlowNode for person [Attribute name] | provenance | | -| testapp/orm_security_tests.py:42:23:42:42 | ControlFlowNode for Attribute() [List element, Attribute age] | testapp/orm_security_tests.py:42:13:42:18 | ControlFlowNode for person [Attribute age] | provenance | | -| testapp/orm_security_tests.py:42:23:42:42 | ControlFlowNode for Attribute() [List element, Attribute name] | testapp/orm_security_tests.py:42:13:42:18 | ControlFlowNode for person [Attribute name] | provenance | | -| testapp/orm_security_tests.py:43:13:43:21 | ControlFlowNode for resp_text | testapp/orm_security_tests.py:44:29:44:37 | ControlFlowNode for resp_text | provenance | | -| testapp/orm_security_tests.py:43:49:43:54 | ControlFlowNode for person [Attribute name] | testapp/orm_security_tests.py:43:49:43:59 | ControlFlowNode for Attribute | provenance | | -| testapp/orm_security_tests.py:43:49:43:59 | ControlFlowNode for Attribute | testapp/orm_security_tests.py:43:13:43:21 | ControlFlowNode for resp_text | provenance | | -| testapp/orm_security_tests.py:43:62:43:67 | ControlFlowNode for person [Attribute age] | testapp/orm_security_tests.py:43:62:43:71 | ControlFlowNode for Attribute | provenance | | -| testapp/orm_security_tests.py:43:62:43:71 | ControlFlowNode for Attribute | testapp/orm_security_tests.py:43:13:43:21 | ControlFlowNode for resp_text | provenance | | -| testapp/orm_security_tests.py:47:5:47:10 | ControlFlowNode for person [Attribute name] | testapp/orm_security_tests.py:48:46:48:51 | ControlFlowNode for person [Attribute name] | provenance | | -| testapp/orm_security_tests.py:47:14:47:53 | ControlFlowNode for Attribute() [Attribute name] | testapp/orm_security_tests.py:47:5:47:10 | ControlFlowNode for person [Attribute name] | provenance | | -| testapp/orm_security_tests.py:48:46:48:51 | ControlFlowNode for person [Attribute name] | testapp/orm_security_tests.py:48:46:48:56 | ControlFlowNode for Attribute | provenance | | -| testapp/orm_security_tests.py:48:46:48:56 | ControlFlowNode for Attribute | testapp/orm_security_tests.py:48:25:48:57 | ControlFlowNode for Attribute() | provenance | | -| testapp/orm_security_tests.py:51:5:51:10 | ControlFlowNode for person [Attribute age] | testapp/orm_security_tests.py:55:45:55:50 | ControlFlowNode for person [Attribute age] | provenance | | -| testapp/orm_security_tests.py:51:14:51:53 | ControlFlowNode for Attribute() [Attribute age] | testapp/orm_security_tests.py:51:5:51:10 | ControlFlowNode for person [Attribute age] | provenance | | -| testapp/orm_security_tests.py:55:45:55:50 | ControlFlowNode for person [Attribute age] | testapp/orm_security_tests.py:55:45:55:54 | ControlFlowNode for Attribute | provenance | | -| testapp/orm_security_tests.py:55:45:55:54 | ControlFlowNode for Attribute | testapp/orm_security_tests.py:55:25:55:55 | ControlFlowNode for Attribute() | provenance | | -| testapp/orm_security_tests.py:92:1:92:44 | [orm-model] Class CommentValidatorNotUsed [Attribute text] | testapp/orm_security_tests.py:101:15:101:52 | ControlFlowNode for Attribute() [Attribute text] | provenance | | -| testapp/orm_security_tests.py:95:37:95:43 | ControlFlowNode for request | testapp/orm_security_tests.py:96:44:96:63 | ControlFlowNode for Subscript | provenance | AdditionalTaintStep | -| testapp/orm_security_tests.py:96:5:96:11 | ControlFlowNode for comment [Attribute text] | testapp/orm_security_tests.py:97:5:97:11 | ControlFlowNode for comment [Attribute text] | provenance | | -| testapp/orm_security_tests.py:96:15:96:64 | ControlFlowNode for CommentValidatorNotUsed() [Attribute text] | testapp/orm_security_tests.py:96:5:96:11 | ControlFlowNode for comment [Attribute text] | provenance | | -| testapp/orm_security_tests.py:96:44:96:63 | ControlFlowNode for Subscript | testapp/orm_security_tests.py:96:15:96:64 | ControlFlowNode for CommentValidatorNotUsed() [Attribute text] | provenance | | -| testapp/orm_security_tests.py:97:5:97:11 | ControlFlowNode for comment [Attribute text] | testapp/orm_security_tests.py:92:1:92:44 | [orm-model] Class CommentValidatorNotUsed [Attribute text] | provenance | | -| testapp/orm_security_tests.py:101:5:101:11 | ControlFlowNode for comment [Attribute text] | testapp/orm_security_tests.py:102:25:102:31 | ControlFlowNode for comment [Attribute text] | provenance | | -| testapp/orm_security_tests.py:101:15:101:52 | ControlFlowNode for Attribute() [Attribute text] | testapp/orm_security_tests.py:101:5:101:11 | ControlFlowNode for comment [Attribute text] | provenance | | -| testapp/orm_security_tests.py:102:25:102:31 | ControlFlowNode for comment [Attribute text] | testapp/orm_security_tests.py:102:25:102:36 | ControlFlowNode for Attribute | provenance | | -| testapp/orm_security_tests.py:111:1:111:41 | [orm-model] Class CommentValidatorUsed [Attribute text] | testapp/orm_security_tests.py:120:15:120:49 | ControlFlowNode for Attribute() [Attribute text] | provenance | | -| testapp/orm_security_tests.py:114:33:114:39 | ControlFlowNode for request | testapp/orm_security_tests.py:115:41:115:60 | ControlFlowNode for Subscript | provenance | AdditionalTaintStep | -| testapp/orm_security_tests.py:115:5:115:11 | ControlFlowNode for comment [Attribute text] | testapp/orm_security_tests.py:117:5:117:11 | ControlFlowNode for comment [Attribute text] | provenance | | -| testapp/orm_security_tests.py:115:15:115:61 | ControlFlowNode for CommentValidatorUsed() [Attribute text] | testapp/orm_security_tests.py:115:5:115:11 | ControlFlowNode for comment [Attribute text] | provenance | | -| testapp/orm_security_tests.py:115:41:115:60 | ControlFlowNode for Subscript | testapp/orm_security_tests.py:115:15:115:61 | ControlFlowNode for CommentValidatorUsed() [Attribute text] | provenance | | -| testapp/orm_security_tests.py:117:5:117:11 | ControlFlowNode for comment [Attribute text] | testapp/orm_security_tests.py:111:1:111:41 | [orm-model] Class CommentValidatorUsed [Attribute text] | provenance | | -| testapp/orm_security_tests.py:120:5:120:11 | ControlFlowNode for comment [Attribute text] | testapp/orm_security_tests.py:121:25:121:31 | ControlFlowNode for comment [Attribute text] | provenance | | -| testapp/orm_security_tests.py:120:15:120:49 | ControlFlowNode for Attribute() [Attribute text] | testapp/orm_security_tests.py:120:5:120:11 | ControlFlowNode for comment [Attribute text] | provenance | | -| testapp/orm_security_tests.py:121:25:121:31 | ControlFlowNode for comment [Attribute text] | testapp/orm_security_tests.py:121:25:121:36 | ControlFlowNode for Attribute | provenance | | +| testapp/orm_security_tests.py:15:1:15:27 | [orm-model] Class Person [Attribute age] | testapp/orm_security_tests.py:42:23:42:42 | After Attribute() [empty] [List element, Attribute age] | provenance | | +| testapp/orm_security_tests.py:15:1:15:27 | [orm-model] Class Person [Attribute age] | testapp/orm_security_tests.py:51:14:51:53 | After Attribute() [Attribute age] | provenance | | +| testapp/orm_security_tests.py:15:1:15:27 | [orm-model] Class Person [Attribute name] | testapp/orm_security_tests.py:42:23:42:42 | After Attribute() [empty] [List element, Attribute name] | provenance | | +| testapp/orm_security_tests.py:15:1:15:27 | [orm-model] Class Person [Attribute name] | testapp/orm_security_tests.py:47:14:47:53 | After Attribute() [Attribute name] | provenance | | +| testapp/orm_security_tests.py:19:12:19:18 | request | testapp/orm_security_tests.py:22:23:22:42 | After Subscript | provenance | AdditionalTaintStep | +| testapp/orm_security_tests.py:19:12:19:18 | request | testapp/orm_security_tests.py:23:22:23:40 | After Subscript | provenance | AdditionalTaintStep | +| testapp/orm_security_tests.py:22:9:22:14 | [post] person [Attribute name] | testapp/orm_security_tests.py:23:9:23:14 | person [Attribute name] | provenance | | +| testapp/orm_security_tests.py:22:23:22:42 | After Subscript | testapp/orm_security_tests.py:22:9:22:14 | [post] person [Attribute name] | provenance | | +| testapp/orm_security_tests.py:23:9:23:14 | [post] person [Attribute age] | testapp/orm_security_tests.py:28:9:28:14 | person [Attribute age] | provenance | | +| testapp/orm_security_tests.py:23:9:23:14 | person [Attribute name] | testapp/orm_security_tests.py:28:9:28:14 | person [Attribute name] | provenance | | +| testapp/orm_security_tests.py:23:22:23:40 | After Subscript | testapp/orm_security_tests.py:23:9:23:14 | [post] person [Attribute age] | provenance | | +| testapp/orm_security_tests.py:28:9:28:14 | person [Attribute age] | testapp/orm_security_tests.py:15:1:15:27 | [orm-model] Class Person [Attribute age] | provenance | | +| testapp/orm_security_tests.py:28:9:28:14 | person [Attribute name] | testapp/orm_security_tests.py:15:1:15:27 | [orm-model] Class Person [Attribute name] | provenance | | +| testapp/orm_security_tests.py:42:13:42:18 | person [Attribute age] | testapp/orm_security_tests.py:43:62:43:67 | person [Attribute age] | provenance | | +| testapp/orm_security_tests.py:42:13:42:18 | person [Attribute name] | testapp/orm_security_tests.py:43:49:43:54 | person [Attribute name] | provenance | | +| testapp/orm_security_tests.py:42:23:42:42 | After Attribute() [empty] [List element, Attribute age] | testapp/orm_security_tests.py:42:13:42:18 | person [Attribute age] | provenance | | +| testapp/orm_security_tests.py:42:23:42:42 | After Attribute() [empty] [List element, Attribute name] | testapp/orm_security_tests.py:42:13:42:18 | person [Attribute name] | provenance | | +| testapp/orm_security_tests.py:43:13:43:21 | resp_text | testapp/orm_security_tests.py:44:29:44:37 | resp_text | provenance | | +| testapp/orm_security_tests.py:43:49:43:54 | person [Attribute name] | testapp/orm_security_tests.py:43:49:43:59 | After Attribute | provenance | | +| testapp/orm_security_tests.py:43:49:43:59 | After Attribute | testapp/orm_security_tests.py:43:13:43:21 | resp_text | provenance | | +| testapp/orm_security_tests.py:43:62:43:67 | person [Attribute age] | testapp/orm_security_tests.py:43:62:43:71 | After Attribute | provenance | | +| testapp/orm_security_tests.py:43:62:43:71 | After Attribute | testapp/orm_security_tests.py:43:13:43:21 | resp_text | provenance | | +| testapp/orm_security_tests.py:47:5:47:10 | person [Attribute name] | testapp/orm_security_tests.py:48:46:48:51 | person [Attribute name] | provenance | | +| testapp/orm_security_tests.py:47:14:47:53 | After Attribute() [Attribute name] | testapp/orm_security_tests.py:47:5:47:10 | person [Attribute name] | provenance | | +| testapp/orm_security_tests.py:48:46:48:51 | person [Attribute name] | testapp/orm_security_tests.py:48:46:48:56 | After Attribute | provenance | | +| testapp/orm_security_tests.py:48:46:48:56 | After Attribute | testapp/orm_security_tests.py:48:25:48:57 | After Attribute() | provenance | | +| testapp/orm_security_tests.py:51:5:51:10 | person [Attribute age] | testapp/orm_security_tests.py:55:45:55:50 | person [Attribute age] | provenance | | +| testapp/orm_security_tests.py:51:14:51:53 | After Attribute() [Attribute age] | testapp/orm_security_tests.py:51:5:51:10 | person [Attribute age] | provenance | | +| testapp/orm_security_tests.py:55:45:55:50 | person [Attribute age] | testapp/orm_security_tests.py:55:45:55:54 | After Attribute | provenance | | +| testapp/orm_security_tests.py:55:45:55:54 | After Attribute | testapp/orm_security_tests.py:55:25:55:55 | After Attribute() | provenance | | +| testapp/orm_security_tests.py:92:1:92:44 | [orm-model] Class CommentValidatorNotUsed [Attribute text] | testapp/orm_security_tests.py:101:15:101:52 | After Attribute() [Attribute text] | provenance | | +| testapp/orm_security_tests.py:95:37:95:43 | request | testapp/orm_security_tests.py:96:44:96:63 | After Subscript | provenance | AdditionalTaintStep | +| testapp/orm_security_tests.py:96:5:96:11 | comment [Attribute text] | testapp/orm_security_tests.py:97:5:97:11 | comment [Attribute text] | provenance | | +| testapp/orm_security_tests.py:96:15:96:64 | After CommentValidatorNotUsed() [Attribute text] | testapp/orm_security_tests.py:96:5:96:11 | comment [Attribute text] | provenance | | +| testapp/orm_security_tests.py:96:44:96:63 | After Subscript | testapp/orm_security_tests.py:96:15:96:64 | After CommentValidatorNotUsed() [Attribute text] | provenance | | +| testapp/orm_security_tests.py:97:5:97:11 | comment [Attribute text] | testapp/orm_security_tests.py:92:1:92:44 | [orm-model] Class CommentValidatorNotUsed [Attribute text] | provenance | | +| testapp/orm_security_tests.py:101:5:101:11 | comment [Attribute text] | testapp/orm_security_tests.py:102:25:102:31 | comment [Attribute text] | provenance | | +| testapp/orm_security_tests.py:101:15:101:52 | After Attribute() [Attribute text] | testapp/orm_security_tests.py:101:5:101:11 | comment [Attribute text] | provenance | | +| testapp/orm_security_tests.py:102:25:102:31 | comment [Attribute text] | testapp/orm_security_tests.py:102:25:102:36 | After Attribute | provenance | | +| testapp/orm_security_tests.py:111:1:111:41 | [orm-model] Class CommentValidatorUsed [Attribute text] | testapp/orm_security_tests.py:120:15:120:49 | After Attribute() [Attribute text] | provenance | | +| testapp/orm_security_tests.py:114:33:114:39 | request | testapp/orm_security_tests.py:115:41:115:60 | After Subscript | provenance | AdditionalTaintStep | +| testapp/orm_security_tests.py:115:5:115:11 | comment [Attribute text] | testapp/orm_security_tests.py:117:5:117:11 | comment [Attribute text] | provenance | | +| testapp/orm_security_tests.py:115:15:115:61 | After CommentValidatorUsed() [Attribute text] | testapp/orm_security_tests.py:115:5:115:11 | comment [Attribute text] | provenance | | +| testapp/orm_security_tests.py:115:41:115:60 | After Subscript | testapp/orm_security_tests.py:115:15:115:61 | After CommentValidatorUsed() [Attribute text] | provenance | | +| testapp/orm_security_tests.py:117:5:117:11 | comment [Attribute text] | testapp/orm_security_tests.py:111:1:111:41 | [orm-model] Class CommentValidatorUsed [Attribute text] | provenance | | +| testapp/orm_security_tests.py:120:5:120:11 | comment [Attribute text] | testapp/orm_security_tests.py:121:25:121:31 | comment [Attribute text] | provenance | | +| testapp/orm_security_tests.py:120:15:120:49 | After Attribute() [Attribute text] | testapp/orm_security_tests.py:120:5:120:11 | comment [Attribute text] | provenance | | +| testapp/orm_security_tests.py:121:25:121:31 | comment [Attribute text] | testapp/orm_security_tests.py:121:25:121:36 | After Attribute | provenance | | nodes | testapp/orm_security_tests.py:15:1:15:27 | [orm-model] Class Person [Attribute age] | semmle.label | [orm-model] Class Person [Attribute age] | | testapp/orm_security_tests.py:15:1:15:27 | [orm-model] Class Person [Attribute name] | semmle.label | [orm-model] Class Person [Attribute name] | -| testapp/orm_security_tests.py:19:12:19:18 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| testapp/orm_security_tests.py:22:9:22:14 | [post] ControlFlowNode for person [Attribute name] | semmle.label | [post] ControlFlowNode for person [Attribute name] | -| testapp/orm_security_tests.py:22:23:22:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript | -| testapp/orm_security_tests.py:23:9:23:14 | ControlFlowNode for person [Attribute name] | semmle.label | ControlFlowNode for person [Attribute name] | -| testapp/orm_security_tests.py:23:9:23:14 | [post] ControlFlowNode for person [Attribute age] | semmle.label | [post] ControlFlowNode for person [Attribute age] | -| testapp/orm_security_tests.py:23:22:23:40 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript | -| testapp/orm_security_tests.py:28:9:28:14 | ControlFlowNode for person [Attribute age] | semmle.label | ControlFlowNode for person [Attribute age] | -| testapp/orm_security_tests.py:28:9:28:14 | ControlFlowNode for person [Attribute name] | semmle.label | ControlFlowNode for person [Attribute name] | -| testapp/orm_security_tests.py:42:13:42:18 | ControlFlowNode for person [Attribute age] | semmle.label | ControlFlowNode for person [Attribute age] | -| testapp/orm_security_tests.py:42:13:42:18 | ControlFlowNode for person [Attribute name] | semmle.label | ControlFlowNode for person [Attribute name] | -| testapp/orm_security_tests.py:42:23:42:42 | ControlFlowNode for Attribute() [List element, Attribute age] | semmle.label | ControlFlowNode for Attribute() [List element, Attribute age] | -| testapp/orm_security_tests.py:42:23:42:42 | ControlFlowNode for Attribute() [List element, Attribute name] | semmle.label | ControlFlowNode for Attribute() [List element, Attribute name] | -| testapp/orm_security_tests.py:43:13:43:21 | ControlFlowNode for resp_text | semmle.label | ControlFlowNode for resp_text | -| testapp/orm_security_tests.py:43:49:43:54 | ControlFlowNode for person [Attribute name] | semmle.label | ControlFlowNode for person [Attribute name] | -| testapp/orm_security_tests.py:43:49:43:59 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| testapp/orm_security_tests.py:43:62:43:67 | ControlFlowNode for person [Attribute age] | semmle.label | ControlFlowNode for person [Attribute age] | -| testapp/orm_security_tests.py:43:62:43:71 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| testapp/orm_security_tests.py:44:29:44:37 | ControlFlowNode for resp_text | semmle.label | ControlFlowNode for resp_text | -| testapp/orm_security_tests.py:47:5:47:10 | ControlFlowNode for person [Attribute name] | semmle.label | ControlFlowNode for person [Attribute name] | -| testapp/orm_security_tests.py:47:14:47:53 | ControlFlowNode for Attribute() [Attribute name] | semmle.label | ControlFlowNode for Attribute() [Attribute name] | -| testapp/orm_security_tests.py:48:25:48:57 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| testapp/orm_security_tests.py:48:46:48:51 | ControlFlowNode for person [Attribute name] | semmle.label | ControlFlowNode for person [Attribute name] | -| testapp/orm_security_tests.py:48:46:48:56 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| testapp/orm_security_tests.py:51:5:51:10 | ControlFlowNode for person [Attribute age] | semmle.label | ControlFlowNode for person [Attribute age] | -| testapp/orm_security_tests.py:51:14:51:53 | ControlFlowNode for Attribute() [Attribute age] | semmle.label | ControlFlowNode for Attribute() [Attribute age] | -| testapp/orm_security_tests.py:55:25:55:55 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| testapp/orm_security_tests.py:55:45:55:50 | ControlFlowNode for person [Attribute age] | semmle.label | ControlFlowNode for person [Attribute age] | -| testapp/orm_security_tests.py:55:45:55:54 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | +| testapp/orm_security_tests.py:19:12:19:18 | request | semmle.label | request | +| testapp/orm_security_tests.py:22:9:22:14 | [post] person [Attribute name] | semmle.label | [post] person [Attribute name] | +| testapp/orm_security_tests.py:22:23:22:42 | After Subscript | semmle.label | After Subscript | +| testapp/orm_security_tests.py:23:9:23:14 | [post] person [Attribute age] | semmle.label | [post] person [Attribute age] | +| testapp/orm_security_tests.py:23:9:23:14 | person [Attribute name] | semmle.label | person [Attribute name] | +| testapp/orm_security_tests.py:23:22:23:40 | After Subscript | semmle.label | After Subscript | +| testapp/orm_security_tests.py:28:9:28:14 | person [Attribute age] | semmle.label | person [Attribute age] | +| testapp/orm_security_tests.py:28:9:28:14 | person [Attribute name] | semmle.label | person [Attribute name] | +| testapp/orm_security_tests.py:42:13:42:18 | person [Attribute age] | semmle.label | person [Attribute age] | +| testapp/orm_security_tests.py:42:13:42:18 | person [Attribute name] | semmle.label | person [Attribute name] | +| testapp/orm_security_tests.py:42:23:42:42 | After Attribute() [empty] [List element, Attribute age] | semmle.label | After Attribute() [empty] [List element, Attribute age] | +| testapp/orm_security_tests.py:42:23:42:42 | After Attribute() [empty] [List element, Attribute name] | semmle.label | After Attribute() [empty] [List element, Attribute name] | +| testapp/orm_security_tests.py:43:13:43:21 | resp_text | semmle.label | resp_text | +| testapp/orm_security_tests.py:43:49:43:54 | person [Attribute name] | semmle.label | person [Attribute name] | +| testapp/orm_security_tests.py:43:49:43:59 | After Attribute | semmle.label | After Attribute | +| testapp/orm_security_tests.py:43:62:43:67 | person [Attribute age] | semmle.label | person [Attribute age] | +| testapp/orm_security_tests.py:43:62:43:71 | After Attribute | semmle.label | After Attribute | +| testapp/orm_security_tests.py:44:29:44:37 | resp_text | semmle.label | resp_text | +| testapp/orm_security_tests.py:47:5:47:10 | person [Attribute name] | semmle.label | person [Attribute name] | +| testapp/orm_security_tests.py:47:14:47:53 | After Attribute() [Attribute name] | semmle.label | After Attribute() [Attribute name] | +| testapp/orm_security_tests.py:48:25:48:57 | After Attribute() | semmle.label | After Attribute() | +| testapp/orm_security_tests.py:48:46:48:51 | person [Attribute name] | semmle.label | person [Attribute name] | +| testapp/orm_security_tests.py:48:46:48:56 | After Attribute | semmle.label | After Attribute | +| testapp/orm_security_tests.py:51:5:51:10 | person [Attribute age] | semmle.label | person [Attribute age] | +| testapp/orm_security_tests.py:51:14:51:53 | After Attribute() [Attribute age] | semmle.label | After Attribute() [Attribute age] | +| testapp/orm_security_tests.py:55:25:55:55 | After Attribute() | semmle.label | After Attribute() | +| testapp/orm_security_tests.py:55:45:55:50 | person [Attribute age] | semmle.label | person [Attribute age] | +| testapp/orm_security_tests.py:55:45:55:54 | After Attribute | semmle.label | After Attribute | | testapp/orm_security_tests.py:92:1:92:44 | [orm-model] Class CommentValidatorNotUsed [Attribute text] | semmle.label | [orm-model] Class CommentValidatorNotUsed [Attribute text] | -| testapp/orm_security_tests.py:95:37:95:43 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| testapp/orm_security_tests.py:96:5:96:11 | ControlFlowNode for comment [Attribute text] | semmle.label | ControlFlowNode for comment [Attribute text] | -| testapp/orm_security_tests.py:96:15:96:64 | ControlFlowNode for CommentValidatorNotUsed() [Attribute text] | semmle.label | ControlFlowNode for CommentValidatorNotUsed() [Attribute text] | -| testapp/orm_security_tests.py:96:44:96:63 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript | -| testapp/orm_security_tests.py:97:5:97:11 | ControlFlowNode for comment [Attribute text] | semmle.label | ControlFlowNode for comment [Attribute text] | -| testapp/orm_security_tests.py:101:5:101:11 | ControlFlowNode for comment [Attribute text] | semmle.label | ControlFlowNode for comment [Attribute text] | -| testapp/orm_security_tests.py:101:15:101:52 | ControlFlowNode for Attribute() [Attribute text] | semmle.label | ControlFlowNode for Attribute() [Attribute text] | -| testapp/orm_security_tests.py:102:25:102:31 | ControlFlowNode for comment [Attribute text] | semmle.label | ControlFlowNode for comment [Attribute text] | -| testapp/orm_security_tests.py:102:25:102:36 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | +| testapp/orm_security_tests.py:95:37:95:43 | request | semmle.label | request | +| testapp/orm_security_tests.py:96:5:96:11 | comment [Attribute text] | semmle.label | comment [Attribute text] | +| testapp/orm_security_tests.py:96:15:96:64 | After CommentValidatorNotUsed() [Attribute text] | semmle.label | After CommentValidatorNotUsed() [Attribute text] | +| testapp/orm_security_tests.py:96:44:96:63 | After Subscript | semmle.label | After Subscript | +| testapp/orm_security_tests.py:97:5:97:11 | comment [Attribute text] | semmle.label | comment [Attribute text] | +| testapp/orm_security_tests.py:101:5:101:11 | comment [Attribute text] | semmle.label | comment [Attribute text] | +| testapp/orm_security_tests.py:101:15:101:52 | After Attribute() [Attribute text] | semmle.label | After Attribute() [Attribute text] | +| testapp/orm_security_tests.py:102:25:102:31 | comment [Attribute text] | semmle.label | comment [Attribute text] | +| testapp/orm_security_tests.py:102:25:102:36 | After Attribute | semmle.label | After Attribute | | testapp/orm_security_tests.py:111:1:111:41 | [orm-model] Class CommentValidatorUsed [Attribute text] | semmle.label | [orm-model] Class CommentValidatorUsed [Attribute text] | -| testapp/orm_security_tests.py:114:33:114:39 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| testapp/orm_security_tests.py:115:5:115:11 | ControlFlowNode for comment [Attribute text] | semmle.label | ControlFlowNode for comment [Attribute text] | -| testapp/orm_security_tests.py:115:15:115:61 | ControlFlowNode for CommentValidatorUsed() [Attribute text] | semmle.label | ControlFlowNode for CommentValidatorUsed() [Attribute text] | -| testapp/orm_security_tests.py:115:41:115:60 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript | -| testapp/orm_security_tests.py:117:5:117:11 | ControlFlowNode for comment [Attribute text] | semmle.label | ControlFlowNode for comment [Attribute text] | -| testapp/orm_security_tests.py:120:5:120:11 | ControlFlowNode for comment [Attribute text] | semmle.label | ControlFlowNode for comment [Attribute text] | -| testapp/orm_security_tests.py:120:15:120:49 | ControlFlowNode for Attribute() [Attribute text] | semmle.label | ControlFlowNode for Attribute() [Attribute text] | -| testapp/orm_security_tests.py:121:25:121:31 | ControlFlowNode for comment [Attribute text] | semmle.label | ControlFlowNode for comment [Attribute text] | -| testapp/orm_security_tests.py:121:25:121:36 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | +| testapp/orm_security_tests.py:114:33:114:39 | request | semmle.label | request | +| testapp/orm_security_tests.py:115:5:115:11 | comment [Attribute text] | semmle.label | comment [Attribute text] | +| testapp/orm_security_tests.py:115:15:115:61 | After CommentValidatorUsed() [Attribute text] | semmle.label | After CommentValidatorUsed() [Attribute text] | +| testapp/orm_security_tests.py:115:41:115:60 | After Subscript | semmle.label | After Subscript | +| testapp/orm_security_tests.py:117:5:117:11 | comment [Attribute text] | semmle.label | comment [Attribute text] | +| testapp/orm_security_tests.py:120:5:120:11 | comment [Attribute text] | semmle.label | comment [Attribute text] | +| testapp/orm_security_tests.py:120:15:120:49 | After Attribute() [Attribute text] | semmle.label | After Attribute() [Attribute text] | +| testapp/orm_security_tests.py:121:25:121:31 | comment [Attribute text] | semmle.label | comment [Attribute text] | +| testapp/orm_security_tests.py:121:25:121:36 | After Attribute | semmle.label | After Attribute | subpaths #select -| testapp/orm_security_tests.py:44:29:44:37 | ControlFlowNode for resp_text | testapp/orm_security_tests.py:19:12:19:18 | ControlFlowNode for request | testapp/orm_security_tests.py:44:29:44:37 | ControlFlowNode for resp_text | Cross-site scripting vulnerability due to a $@. | testapp/orm_security_tests.py:19:12:19:18 | ControlFlowNode for request | user-provided value | -| testapp/orm_security_tests.py:48:25:48:57 | ControlFlowNode for Attribute() | testapp/orm_security_tests.py:19:12:19:18 | ControlFlowNode for request | testapp/orm_security_tests.py:48:25:48:57 | ControlFlowNode for Attribute() | Cross-site scripting vulnerability due to a $@. | testapp/orm_security_tests.py:19:12:19:18 | ControlFlowNode for request | user-provided value | -| testapp/orm_security_tests.py:55:25:55:55 | ControlFlowNode for Attribute() | testapp/orm_security_tests.py:19:12:19:18 | ControlFlowNode for request | testapp/orm_security_tests.py:55:25:55:55 | ControlFlowNode for Attribute() | Cross-site scripting vulnerability due to a $@. | testapp/orm_security_tests.py:19:12:19:18 | ControlFlowNode for request | user-provided value | -| testapp/orm_security_tests.py:102:25:102:36 | ControlFlowNode for Attribute | testapp/orm_security_tests.py:95:37:95:43 | ControlFlowNode for request | testapp/orm_security_tests.py:102:25:102:36 | ControlFlowNode for Attribute | Cross-site scripting vulnerability due to a $@. | testapp/orm_security_tests.py:95:37:95:43 | ControlFlowNode for request | user-provided value | -| testapp/orm_security_tests.py:121:25:121:36 | ControlFlowNode for Attribute | testapp/orm_security_tests.py:114:33:114:39 | ControlFlowNode for request | testapp/orm_security_tests.py:121:25:121:36 | ControlFlowNode for Attribute | Cross-site scripting vulnerability due to a $@. | testapp/orm_security_tests.py:114:33:114:39 | ControlFlowNode for request | user-provided value | +| testapp/orm_security_tests.py:44:29:44:37 | resp_text | testapp/orm_security_tests.py:19:12:19:18 | request | testapp/orm_security_tests.py:44:29:44:37 | resp_text | Cross-site scripting vulnerability due to a $@. | testapp/orm_security_tests.py:19:12:19:18 | request | user-provided value | +| testapp/orm_security_tests.py:48:25:48:57 | After Attribute() | testapp/orm_security_tests.py:19:12:19:18 | request | testapp/orm_security_tests.py:48:25:48:57 | After Attribute() | Cross-site scripting vulnerability due to a $@. | testapp/orm_security_tests.py:19:12:19:18 | request | user-provided value | +| testapp/orm_security_tests.py:55:25:55:55 | After Attribute() | testapp/orm_security_tests.py:19:12:19:18 | request | testapp/orm_security_tests.py:55:25:55:55 | After Attribute() | Cross-site scripting vulnerability due to a $@. | testapp/orm_security_tests.py:19:12:19:18 | request | user-provided value | +| testapp/orm_security_tests.py:102:25:102:36 | After Attribute | testapp/orm_security_tests.py:95:37:95:43 | request | testapp/orm_security_tests.py:102:25:102:36 | After Attribute | Cross-site scripting vulnerability due to a $@. | testapp/orm_security_tests.py:95:37:95:43 | request | user-provided value | +| testapp/orm_security_tests.py:121:25:121:36 | After Attribute | testapp/orm_security_tests.py:114:33:114:39 | request | testapp/orm_security_tests.py:121:25:121:36 | After Attribute | Cross-site scripting vulnerability due to a $@. | testapp/orm_security_tests.py:114:33:114:39 | request | user-provided value | diff --git a/python/ql/test/library-tests/frameworks/django/CONSISTENCY/DataFlowConsistency.expected b/python/ql/test/library-tests/frameworks/django/CONSISTENCY/DataFlowConsistency.expected index 802e325c3b2f..4c2ddfaa6af0 100644 --- a/python/ql/test/library-tests/frameworks/django/CONSISTENCY/DataFlowConsistency.expected +++ b/python/ql/test/library-tests/frameworks/django/CONSISTENCY/DataFlowConsistency.expected @@ -1,13 +1,13 @@ storeStepIsLocal -| SqlExecution.py:16:1:16:25 | [orm-model] Class User | SqlExecution.py:21:5:21:32 | ControlFlowNode for Attribute() | Store step does not preserve enclosing callable. | -| SqlExecution.py:16:1:16:25 | [orm-model] Class User | SqlExecution.py:23:5:23:45 | ControlFlowNode for Attribute() | Store step does not preserve enclosing callable. | -| SqlExecution.py:16:1:16:25 | [orm-model] Class User | SqlExecution.py:24:5:24:55 | ControlFlowNode for Attribute() | Store step does not preserve enclosing callable. | -| SqlExecution.py:16:1:16:25 | [orm-model] Class User | SqlExecution.py:25:5:25:49 | ControlFlowNode for Attribute() | Store step does not preserve enclosing callable. | -| SqlExecution.py:16:1:16:25 | [orm-model] Class User | SqlExecution.py:27:5:27:52 | ControlFlowNode for Attribute() | Store step does not preserve enclosing callable. | -| SqlExecution.py:16:1:16:25 | [orm-model] Class User | SqlExecution.py:28:5:28:46 | ControlFlowNode for Attribute() | Store step does not preserve enclosing callable. | -| SqlExecution.py:16:1:16:25 | [orm-model] Class User | SqlExecution.py:30:5:30:34 | ControlFlowNode for Attribute() | Store step does not preserve enclosing callable. | -| SqlExecution.py:16:1:16:25 | [orm-model] Class User | SqlExecution.py:31:5:31:92 | ControlFlowNode for Attribute() | Store step does not preserve enclosing callable. | -| SqlExecution.py:16:1:16:25 | [orm-model] Class User | SqlExecution.py:34:5:34:34 | ControlFlowNode for Attribute() | Store step does not preserve enclosing callable. | -| SqlExecution.py:16:1:16:25 | [orm-model] Class User | SqlExecution.py:37:5:37:33 | ControlFlowNode for Attribute() | Store step does not preserve enclosing callable. | -| SqlExecution.py:16:1:16:25 | [orm-model] Class User | SqlExecution.py:37:5:37:59 | ControlFlowNode for Attribute() | Store step does not preserve enclosing callable. | -| SqlExecution.py:16:1:16:25 | [orm-model] Class User | SqlExecution.py:37:5:37:77 | ControlFlowNode for Attribute() | Store step does not preserve enclosing callable. | +| SqlExecution.py:16:1:16:25 | [orm-model] Class User | SqlExecution.py:21:5:21:32 | After Attribute() | Store step does not preserve enclosing callable. | +| SqlExecution.py:16:1:16:25 | [orm-model] Class User | SqlExecution.py:23:5:23:45 | After Attribute() | Store step does not preserve enclosing callable. | +| SqlExecution.py:16:1:16:25 | [orm-model] Class User | SqlExecution.py:24:5:24:55 | After Attribute() | Store step does not preserve enclosing callable. | +| SqlExecution.py:16:1:16:25 | [orm-model] Class User | SqlExecution.py:25:5:25:49 | After Attribute() | Store step does not preserve enclosing callable. | +| SqlExecution.py:16:1:16:25 | [orm-model] Class User | SqlExecution.py:27:5:27:52 | After Attribute() | Store step does not preserve enclosing callable. | +| SqlExecution.py:16:1:16:25 | [orm-model] Class User | SqlExecution.py:28:5:28:46 | After Attribute() | Store step does not preserve enclosing callable. | +| SqlExecution.py:16:1:16:25 | [orm-model] Class User | SqlExecution.py:30:5:30:34 | After Attribute() | Store step does not preserve enclosing callable. | +| SqlExecution.py:16:1:16:25 | [orm-model] Class User | SqlExecution.py:31:5:31:92 | After Attribute() | Store step does not preserve enclosing callable. | +| SqlExecution.py:16:1:16:25 | [orm-model] Class User | SqlExecution.py:34:5:34:34 | After Attribute() | Store step does not preserve enclosing callable. | +| SqlExecution.py:16:1:16:25 | [orm-model] Class User | SqlExecution.py:37:5:37:33 | After Attribute() | Store step does not preserve enclosing callable. | +| SqlExecution.py:16:1:16:25 | [orm-model] Class User | SqlExecution.py:37:5:37:59 | After Attribute() | Store step does not preserve enclosing callable. | +| SqlExecution.py:16:1:16:25 | [orm-model] Class User | SqlExecution.py:37:5:37:77 | After Attribute() | Store step does not preserve enclosing callable. | diff --git a/python/ql/test/library-tests/frameworks/fastapi/ConceptsTest.expected b/python/ql/test/library-tests/frameworks/fastapi/ConceptsTest.expected index e69de29bb2d1..1c7200610ea4 100644 --- a/python/ql/test/library-tests/frameworks/fastapi/ConceptsTest.expected +++ b/python/ql/test/library-tests/frameworks/fastapi/ConceptsTest.expected @@ -0,0 +1,45 @@ +| response_test.py:11:30:11:37 | Parameter | Unexpected result: routedParameter=response | +| response_test.py:12:41:12:151 | Comment # $ CookieWrite CookieName="key" CookieValue="value" CookieSecure=false CookieHttpOnly=false CookieSameSite=Lax | Missing result: CookieHttpOnly=false | +| response_test.py:12:41:12:151 | Comment # $ CookieWrite CookieName="key" CookieValue="value" CookieSecure=false CookieHttpOnly=false CookieSameSite=Lax | Missing result: CookieName="key" | +| response_test.py:12:41:12:151 | Comment # $ CookieWrite CookieName="key" CookieValue="value" CookieSecure=false CookieHttpOnly=false CookieSameSite=Lax | Missing result: CookieSameSite=Lax | +| response_test.py:12:41:12:151 | Comment # $ CookieWrite CookieName="key" CookieValue="value" CookieSecure=false CookieHttpOnly=false CookieSameSite=Lax | Missing result: CookieSecure=false | +| response_test.py:12:41:12:151 | Comment # $ CookieWrite CookieName="key" CookieValue="value" CookieSecure=false CookieHttpOnly=false CookieSameSite=Lax | Missing result: CookieValue="value" | +| response_test.py:12:41:12:151 | Comment # $ CookieWrite CookieName="key" CookieValue="value" CookieSecure=false CookieHttpOnly=false CookieSameSite=Lax | Missing result: CookieWrite | +| response_test.py:13:51:13:161 | Comment # $ CookieWrite CookieName="key" CookieValue="value" CookieSecure=false CookieHttpOnly=false CookieSameSite=Lax | Missing result: CookieHttpOnly=false | +| response_test.py:13:51:13:161 | Comment # $ CookieWrite CookieName="key" CookieValue="value" CookieSecure=false CookieHttpOnly=false CookieSameSite=Lax | Missing result: CookieName="key" | +| response_test.py:13:51:13:161 | Comment # $ CookieWrite CookieName="key" CookieValue="value" CookieSecure=false CookieHttpOnly=false CookieSameSite=Lax | Missing result: CookieSameSite=Lax | +| response_test.py:13:51:13:161 | Comment # $ CookieWrite CookieName="key" CookieValue="value" CookieSecure=false CookieHttpOnly=false CookieSameSite=Lax | Missing result: CookieSecure=false | +| response_test.py:13:51:13:161 | Comment # $ CookieWrite CookieName="key" CookieValue="value" CookieSecure=false CookieHttpOnly=false CookieSameSite=Lax | Missing result: CookieValue="value" | +| response_test.py:13:51:13:161 | Comment # $ CookieWrite CookieName="key" CookieValue="value" CookieSecure=false CookieHttpOnly=false CookieSameSite=Lax | Missing result: CookieWrite | +| response_test.py:14:96:14:205 | Comment # $ CookieWrite CookieName="key" CookieValue="value" CookieSecure=false CookieHttpOnly=true CookieSameSite=Lax | Missing result: CookieHttpOnly=true | +| response_test.py:14:96:14:205 | Comment # $ CookieWrite CookieName="key" CookieValue="value" CookieSecure=false CookieHttpOnly=true CookieSameSite=Lax | Missing result: CookieName="key" | +| response_test.py:14:96:14:205 | Comment # $ CookieWrite CookieName="key" CookieValue="value" CookieSecure=false CookieHttpOnly=true CookieSameSite=Lax | Missing result: CookieSameSite=Lax | +| response_test.py:14:96:14:205 | Comment # $ CookieWrite CookieName="key" CookieValue="value" CookieSecure=false CookieHttpOnly=true CookieSameSite=Lax | Missing result: CookieSecure=false | +| response_test.py:14:96:14:205 | Comment # $ CookieWrite CookieName="key" CookieValue="value" CookieSecure=false CookieHttpOnly=true CookieSameSite=Lax | Missing result: CookieValue="value" | +| response_test.py:14:96:14:205 | Comment # $ CookieWrite CookieName="key" CookieValue="value" CookieSecure=false CookieHttpOnly=true CookieSameSite=Lax | Missing result: CookieWrite | +| response_test.py:15:58:15:221 | Comment # $ headerWriteName="Set-Cookie" headerWriteValue="key2=value2" CookieWrite CookieRawHeader="key2=value2" CookieSecure=false CookieHttpOnly=false CookieSameSite=Lax | Missing result: CookieHttpOnly=false | +| response_test.py:15:58:15:221 | Comment # $ headerWriteName="Set-Cookie" headerWriteValue="key2=value2" CookieWrite CookieRawHeader="key2=value2" CookieSecure=false CookieHttpOnly=false CookieSameSite=Lax | Missing result: CookieRawHeader="key2=value2" | +| response_test.py:15:58:15:221 | Comment # $ headerWriteName="Set-Cookie" headerWriteValue="key2=value2" CookieWrite CookieRawHeader="key2=value2" CookieSecure=false CookieHttpOnly=false CookieSameSite=Lax | Missing result: CookieSameSite=Lax | +| response_test.py:15:58:15:221 | Comment # $ headerWriteName="Set-Cookie" headerWriteValue="key2=value2" CookieWrite CookieRawHeader="key2=value2" CookieSecure=false CookieHttpOnly=false CookieSameSite=Lax | Missing result: CookieSecure=false | +| response_test.py:15:58:15:221 | Comment # $ headerWriteName="Set-Cookie" headerWriteValue="key2=value2" CookieWrite CookieRawHeader="key2=value2" CookieSecure=false CookieHttpOnly=false CookieSameSite=Lax | Missing result: CookieWrite | +| response_test.py:15:58:15:221 | Comment # $ headerWriteName="Set-Cookie" headerWriteValue="key2=value2" CookieWrite CookieRawHeader="key2=value2" CookieSecure=false CookieHttpOnly=false CookieSameSite=Lax | Missing result: headerWriteName="Set-Cookie" | +| response_test.py:15:58:15:221 | Comment # $ headerWriteName="Set-Cookie" headerWriteValue="key2=value2" CookieWrite CookieRawHeader="key2=value2" CookieSecure=false CookieHttpOnly=false CookieSameSite=Lax | Missing result: headerWriteValue="key2=value2" | +| response_test.py:16:68:16:231 | Comment # $ headerWriteName="Set-Cookie" headerWriteValue="key2=value2" CookieWrite CookieRawHeader="key2=value2" CookieSecure=false CookieHttpOnly=false CookieSameSite=Lax | Missing result: CookieHttpOnly=false | +| response_test.py:16:68:16:231 | Comment # $ headerWriteName="Set-Cookie" headerWriteValue="key2=value2" CookieWrite CookieRawHeader="key2=value2" CookieSecure=false CookieHttpOnly=false CookieSameSite=Lax | Missing result: CookieRawHeader="key2=value2" | +| response_test.py:16:68:16:231 | Comment # $ headerWriteName="Set-Cookie" headerWriteValue="key2=value2" CookieWrite CookieRawHeader="key2=value2" CookieSecure=false CookieHttpOnly=false CookieSameSite=Lax | Missing result: CookieSameSite=Lax | +| response_test.py:16:68:16:231 | Comment # $ headerWriteName="Set-Cookie" headerWriteValue="key2=value2" CookieWrite CookieRawHeader="key2=value2" CookieSecure=false CookieHttpOnly=false CookieSameSite=Lax | Missing result: CookieSecure=false | +| response_test.py:16:68:16:231 | Comment # $ headerWriteName="Set-Cookie" headerWriteValue="key2=value2" CookieWrite CookieRawHeader="key2=value2" CookieSecure=false CookieHttpOnly=false CookieSameSite=Lax | Missing result: CookieWrite | +| response_test.py:16:68:16:231 | Comment # $ headerWriteName="Set-Cookie" headerWriteValue="key2=value2" CookieWrite CookieRawHeader="key2=value2" CookieSecure=false CookieHttpOnly=false CookieSameSite=Lax | Missing result: headerWriteName="Set-Cookie" | +| response_test.py:16:68:16:231 | Comment # $ headerWriteName="Set-Cookie" headerWriteValue="key2=value2" CookieWrite CookieRawHeader="key2=value2" CookieSecure=false CookieHttpOnly=false CookieSameSite=Lax | Missing result: headerWriteValue="key2=value2" | +| response_test.py:17:53:17:116 | Comment # $ headerWriteName="X-MyHeader" headerWriteValue="header-value" | Missing result: headerWriteName="X-MyHeader" | +| response_test.py:17:53:17:116 | Comment # $ headerWriteName="X-MyHeader" headerWriteValue="header-value" | Missing result: headerWriteValue="header-value" | +| response_test.py:23:26:23:29 | Parameter | Unexpected result: routedParameter=resp | +| response_test.py:41:42:41:49 | Parameter | Unexpected result: routedParameter=response | +| response_test.py:48:41:48:151 | Comment # $ CookieWrite CookieName="key" CookieValue="value" CookieSecure=false CookieHttpOnly=false CookieSameSite=Lax | Missing result: CookieHttpOnly=false | +| response_test.py:48:41:48:151 | Comment # $ CookieWrite CookieName="key" CookieValue="value" CookieSecure=false CookieHttpOnly=false CookieSameSite=Lax | Missing result: CookieName="key" | +| response_test.py:48:41:48:151 | Comment # $ CookieWrite CookieName="key" CookieValue="value" CookieSecure=false CookieHttpOnly=false CookieSameSite=Lax | Missing result: CookieSameSite=Lax | +| response_test.py:48:41:48:151 | Comment # $ CookieWrite CookieName="key" CookieValue="value" CookieSecure=false CookieHttpOnly=false CookieSameSite=Lax | Missing result: CookieSecure=false | +| response_test.py:48:41:48:151 | Comment # $ CookieWrite CookieName="key" CookieValue="value" CookieSecure=false CookieHttpOnly=false CookieSameSite=Lax | Missing result: CookieValue="value" | +| response_test.py:48:41:48:151 | Comment # $ CookieWrite CookieName="key" CookieValue="value" CookieSecure=false CookieHttpOnly=false CookieSameSite=Lax | Missing result: CookieWrite | +| response_test.py:49:87:49:184 | Comment # $ headerWriteName="Custom-Response-Type" headerWriteValue="yes, but only after function has run" | Missing result: headerWriteName="Custom-Response-Type" | +| response_test.py:49:87:49:184 | Comment # $ headerWriteName="Custom-Response-Type" headerWriteValue="yes, but only after function has run" | Missing result: headerWriteValue="yes, but only after function has run" | diff --git a/python/ql/test/library-tests/frameworks/fastapi/InlineTaintTest.expected b/python/ql/test/library-tests/frameworks/fastapi/InlineTaintTest.expected index 020c338fd192..4b34068dccfb 100644 --- a/python/ql/test/library-tests/frameworks/fastapi/InlineTaintTest.expected +++ b/python/ql/test/library-tests/frameworks/fastapi/InlineTaintTest.expected @@ -1,3 +1,107 @@ argumentToEnsureNotTaintedNotMarkedAsSpurious untaintedArgumentToEnsureTaintedNotMarkedAsMissing +| taint_test.py:33:9:33:24 | taint_test.py:33 | ERROR, you should add `# $ MISSING: tainted` annotation | also_input.field | +| taint_test.py:35:9:35:27 | taint_test.py:35 | ERROR, you should add `# $ MISSING: tainted` annotation | also_input.main_foo | +| taint_test.py:36:9:36:31 | taint_test.py:36 | ERROR, you should add `# $ MISSING: tainted` annotation | also_input.main_foo.foo | +| taint_test.py:38:9:38:29 | taint_test.py:38 | ERROR, you should add `# $ MISSING: tainted` annotation | also_input.other_foos | +| taint_test.py:39:9:39:32 | taint_test.py:39 | ERROR, you should add `# $ MISSING: tainted` annotation | also_input.other_foos[0] | +| taint_test.py:40:9:40:36 | taint_test.py:40 | ERROR, you should add `# $ MISSING: tainted` annotation | also_input.other_foos[0].foo | +| taint_test.py:43:9:43:30 | taint_test.py:43 | ERROR, you should add `# $ MISSING: tainted` annotation | also_input.nested_foos | +| taint_test.py:44:9:44:33 | taint_test.py:44 | ERROR, you should add `# $ MISSING: tainted` annotation | also_input.nested_foos[0] | +| taint_test.py:45:9:45:36 | taint_test.py:45 | ERROR, you should add `# $ MISSING: tainted` annotation | also_input.nested_foos[0][0] | +| taint_test.py:46:9:46:40 | taint_test.py:46 | ERROR, you should add `# $ MISSING: tainted` annotation | also_input.nested_foos[0][0].foo | +| taint_test.py:52:9:52:18 | taint_test.py:52 | ERROR, you should add `# $ MISSING: tainted` annotation | other_foos | +| taint_test.py:53:9:53:21 | taint_test.py:53 | ERROR, you should add `# $ MISSING: tainted` annotation | other_foos[0] | +| taint_test.py:54:9:54:25 | taint_test.py:54 | ERROR, you should add `# $ MISSING: tainted` annotation | other_foos[0].foo | +| taint_test.py:140:9:140:21 | taint_test.py:140 | ERROR, you should add `# $ MISSING: tainted` annotation | websocket.url | +| taint_test.py:142:9:142:28 | taint_test.py:142 | ERROR, you should add `# $ MISSING: tainted` annotation | websocket.url.netloc | +| taint_test.py:143:9:143:26 | taint_test.py:143 | ERROR, you should add `# $ MISSING: tainted` annotation | websocket.url.path | +| taint_test.py:144:9:144:27 | taint_test.py:144 | ERROR, you should add `# $ MISSING: tainted` annotation | websocket.url.query | +| taint_test.py:145:9:145:30 | taint_test.py:145 | ERROR, you should add `# $ MISSING: tainted` annotation | websocket.url.fragment | +| taint_test.py:146:9:146:30 | taint_test.py:146 | ERROR, you should add `# $ MISSING: tainted` annotation | websocket.url.username | +| taint_test.py:147:9:147:30 | taint_test.py:147 | ERROR, you should add `# $ MISSING: tainted` annotation | websocket.url.password | +| taint_test.py:148:9:148:30 | taint_test.py:148 | ERROR, you should add `# $ MISSING: tainted` annotation | websocket.url.hostname | +| taint_test.py:149:9:149:26 | taint_test.py:149 | ERROR, you should add `# $ MISSING: tainted` annotation | websocket.url.port | +| taint_test.py:151:9:151:32 | taint_test.py:151 | ERROR, you should add `# $ MISSING: tainted` annotation | websocket.url.components | +| taint_test.py:152:9:152:39 | taint_test.py:152 | ERROR, you should add `# $ MISSING: tainted` annotation | websocket.url.components.netloc | +| taint_test.py:153:9:153:37 | taint_test.py:153 | ERROR, you should add `# $ MISSING: tainted` annotation | websocket.url.components.path | +| taint_test.py:154:9:154:38 | taint_test.py:154 | ERROR, you should add `# $ MISSING: tainted` annotation | websocket.url.components.query | +| taint_test.py:155:9:155:41 | taint_test.py:155 | ERROR, you should add `# $ MISSING: tainted` annotation | websocket.url.components.fragment | +| taint_test.py:156:9:156:41 | taint_test.py:156 | ERROR, you should add `# $ MISSING: tainted` annotation | websocket.url.components.username | +| taint_test.py:157:9:157:41 | taint_test.py:157 | ERROR, you should add `# $ MISSING: tainted` annotation | websocket.url.components.password | +| taint_test.py:158:9:158:41 | taint_test.py:158 | ERROR, you should add `# $ MISSING: tainted` annotation | websocket.url.components.hostname | +| taint_test.py:159:9:159:37 | taint_test.py:159 | ERROR, you should add `# $ MISSING: tainted` annotation | websocket.url.components.port | +| taint_test.py:161:9:161:25 | taint_test.py:161 | ERROR, you should add `# $ MISSING: tainted` annotation | websocket.headers | +| taint_test.py:162:9:162:32 | taint_test.py:162 | ERROR, you should add `# $ MISSING: tainted` annotation | websocket.headers["key"] | +| taint_test.py:164:9:164:30 | taint_test.py:164 | ERROR, you should add `# $ MISSING: tainted` annotation | websocket.query_params | +| taint_test.py:165:9:165:37 | taint_test.py:165 | ERROR, you should add `# $ MISSING: tainted` annotation | websocket.query_params["key"] | +| taint_test.py:167:9:167:25 | taint_test.py:167 | ERROR, you should add `# $ MISSING: tainted` annotation | websocket.cookies | +| taint_test.py:168:9:168:32 | taint_test.py:168 | ERROR, you should add `# $ MISSING: tainted` annotation | websocket.cookies["key"] | +| taint_test.py:170:9:170:33 | taint_test.py:170 | ERROR, you should add `# $ MISSING: tainted` annotation | Await | +| taint_test.py:171:9:171:39 | taint_test.py:171 | ERROR, you should add `# $ MISSING: tainted` annotation | Await | +| taint_test.py:172:9:172:38 | taint_test.py:172 | ERROR, you should add `# $ MISSING: tainted` annotation | Await | +| taint_test.py:173:9:173:38 | taint_test.py:173 | ERROR, you should add `# $ MISSING: tainted` annotation | Await | +| taint_test.py:183:24:183:27 | taint_test.py:183 | ERROR, you should add `# $ MISSING: tainted` annotation | data | +| taint_test.py:186:24:186:27 | taint_test.py:186 | ERROR, you should add `# $ MISSING: tainted` annotation | data | +| taint_test.py:189:24:189:27 | taint_test.py:189 | ERROR, you should add `# $ MISSING: tainted` annotation | data | +| taint_test.py:205:9:205:28 | taint_test.py:205 | ERROR, you should add `# $ MISSING: tainted` annotation | Await | +| taint_test.py:207:9:207:28 | taint_test.py:207 | ERROR, you should add `# $ MISSING: tainted` annotation | Await | +| taint_test.py:208:9:208:35 | taint_test.py:208 | ERROR, you should add `# $ MISSING: tainted` annotation | Await | +| taint_test.py:211:9:211:28 | taint_test.py:211 | ERROR, you should add `# $ MISSING: tainted` annotation | Await | +| taint_test.py:212:9:212:35 | taint_test.py:212 | ERROR, you should add `# $ MISSING: tainted` annotation | Await | +| taint_test.py:219:9:219:23 | taint_test.py:219 | ERROR, you should add `# $ MISSING: tainted` annotation | request.cookies | +| taint_test.py:220:9:220:30 | taint_test.py:220 | ERROR, you should add `# $ MISSING: tainted` annotation | request.cookies["key"] | +| taint_test.py:224:24:224:28 | taint_test.py:224 | ERROR, you should add `# $ MISSING: tainted` annotation | chunk | testFailures +| taint_test.py:33:27:33:37 | Comment # $ tainted | Missing result: tainted | +| taint_test.py:35:30:35:40 | Comment # $ tainted | Missing result: tainted | +| taint_test.py:36:34:36:44 | Comment # $ tainted | Missing result: tainted | +| taint_test.py:38:32:38:42 | Comment # $ tainted | Missing result: tainted | +| taint_test.py:39:35:39:45 | Comment # $ tainted | Missing result: tainted | +| taint_test.py:40:39:40:49 | Comment # $ tainted | Missing result: tainted | +| taint_test.py:43:33:43:43 | Comment # $ tainted | Missing result: tainted | +| taint_test.py:44:36:44:46 | Comment # $ tainted | Missing result: tainted | +| taint_test.py:45:39:45:49 | Comment # $ tainted | Missing result: tainted | +| taint_test.py:46:43:46:53 | Comment # $ tainted | Missing result: tainted | +| taint_test.py:52:21:52:31 | Comment # $ tainted | Missing result: tainted | +| taint_test.py:53:24:53:34 | Comment # $ tainted | Missing result: tainted | +| taint_test.py:54:28:54:38 | Comment # $ tainted | Missing result: tainted | +| taint_test.py:140:24:140:34 | Comment # $ tainted | Missing result: tainted | +| taint_test.py:142:31:142:41 | Comment # $ tainted | Missing result: tainted | +| taint_test.py:143:29:143:39 | Comment # $ tainted | Missing result: tainted | +| taint_test.py:144:30:144:40 | Comment # $ tainted | Missing result: tainted | +| taint_test.py:145:33:145:43 | Comment # $ tainted | Missing result: tainted | +| taint_test.py:146:33:146:43 | Comment # $ tainted | Missing result: tainted | +| taint_test.py:147:33:147:43 | Comment # $ tainted | Missing result: tainted | +| taint_test.py:148:33:148:43 | Comment # $ tainted | Missing result: tainted | +| taint_test.py:149:29:149:39 | Comment # $ tainted | Missing result: tainted | +| taint_test.py:151:35:151:45 | Comment # $ tainted | Missing result: tainted | +| taint_test.py:152:42:152:52 | Comment # $ tainted | Missing result: tainted | +| taint_test.py:153:40:153:50 | Comment # $ tainted | Missing result: tainted | +| taint_test.py:154:41:154:51 | Comment # $ tainted | Missing result: tainted | +| taint_test.py:155:44:155:54 | Comment # $ tainted | Missing result: tainted | +| taint_test.py:156:44:156:54 | Comment # $ tainted | Missing result: tainted | +| taint_test.py:157:44:157:54 | Comment # $ tainted | Missing result: tainted | +| taint_test.py:158:44:158:54 | Comment # $ tainted | Missing result: tainted | +| taint_test.py:159:40:159:50 | Comment # $ tainted | Missing result: tainted | +| taint_test.py:161:28:161:38 | Comment # $ tainted | Missing result: tainted | +| taint_test.py:162:35:162:45 | Comment # $ tainted | Missing result: tainted | +| taint_test.py:164:33:164:43 | Comment # $ tainted | Missing result: tainted | +| taint_test.py:165:40:165:50 | Comment # $ tainted | Missing result: tainted | +| taint_test.py:167:28:167:38 | Comment # $ tainted | Missing result: tainted | +| taint_test.py:168:35:168:45 | Comment # $ tainted | Missing result: tainted | +| taint_test.py:170:36:170:46 | Comment # $ tainted | Missing result: tainted | +| taint_test.py:171:42:171:52 | Comment # $ tainted | Missing result: tainted | +| taint_test.py:172:41:172:51 | Comment # $ tainted | Missing result: tainted | +| taint_test.py:173:41:173:51 | Comment # $ tainted | Missing result: tainted | +| taint_test.py:183:30:183:40 | Comment # $ tainted | Missing result: tainted | +| taint_test.py:186:30:186:40 | Comment # $ tainted | Missing result: tainted | +| taint_test.py:189:30:189:40 | Comment # $ tainted | Missing result: tainted | +| taint_test.py:205:31:205:41 | Comment # $ tainted | Missing result: tainted | +| taint_test.py:207:31:207:41 | Comment # $ tainted | Missing result: tainted | +| taint_test.py:208:38:208:48 | Comment # $ tainted | Missing result: tainted | +| taint_test.py:211:31:211:41 | Comment # $ tainted | Missing result: tainted | +| taint_test.py:212:38:212:48 | Comment # $ tainted | Missing result: tainted | +| taint_test.py:219:26:219:36 | Comment # $ tainted | Missing result: tainted | +| taint_test.py:220:33:220:43 | Comment # $ tainted | Missing result: tainted | +| taint_test.py:224:31:224:41 | Comment # $ tainted | Missing result: tainted | diff --git a/python/ql/test/library-tests/frameworks/gradio/taint_step_test.expected b/python/ql/test/library-tests/frameworks/gradio/taint_step_test.expected index e617488aac15..4843afe82a45 100644 --- a/python/ql/test/library-tests/frameworks/gradio/taint_step_test.expected +++ b/python/ql/test/library-tests/frameworks/gradio/taint_step_test.expected @@ -1,30 +1,26 @@ edges -| taint_step_test.py:5:5:5:8 | ControlFlowNode for path | taint_step_test.py:19:43:19:46 | ControlFlowNode for path | provenance | | -| taint_step_test.py:5:12:5:35 | ControlFlowNode for Attribute() | taint_step_test.py:5:5:5:8 | ControlFlowNode for path | provenance | | -| taint_step_test.py:6:5:6:8 | ControlFlowNode for file | taint_step_test.py:19:48:19:51 | ControlFlowNode for file | provenance | | -| taint_step_test.py:6:12:6:35 | ControlFlowNode for Attribute() | taint_step_test.py:6:5:6:8 | ControlFlowNode for file | provenance | | -| taint_step_test.py:11:18:11:21 | ControlFlowNode for path | taint_step_test.py:12:9:12:16 | ControlFlowNode for filepath | provenance | AdditionalTaintStep | -| taint_step_test.py:11:18:11:21 | ControlFlowNode for path | taint_step_test.py:12:33:12:36 | ControlFlowNode for path | provenance | | -| taint_step_test.py:11:24:11:27 | ControlFlowNode for file | taint_step_test.py:12:9:12:16 | ControlFlowNode for filepath | provenance | AdditionalTaintStep | -| taint_step_test.py:12:9:12:16 | ControlFlowNode for filepath | taint_step_test.py:13:19:13:26 | ControlFlowNode for filepath | provenance | | -| taint_step_test.py:12:20:12:43 | ControlFlowNode for Attribute() | taint_step_test.py:12:9:12:16 | ControlFlowNode for filepath | provenance | | -| taint_step_test.py:12:33:12:36 | ControlFlowNode for path | taint_step_test.py:12:20:12:43 | ControlFlowNode for Attribute() | provenance | str.join | -| taint_step_test.py:19:43:19:46 | ControlFlowNode for path | taint_step_test.py:11:18:11:21 | ControlFlowNode for path | provenance | AdditionalTaintStep | -| taint_step_test.py:19:48:19:51 | ControlFlowNode for file | taint_step_test.py:11:24:11:27 | ControlFlowNode for file | provenance | AdditionalTaintStep | +| taint_step_test.py:5:5:5:8 | path | taint_step_test.py:19:43:19:46 | path | provenance | | +| taint_step_test.py:5:12:5:35 | After Attribute() | taint_step_test.py:5:5:5:8 | path | provenance | | +| taint_step_test.py:6:5:6:8 | file | taint_step_test.py:19:48:19:51 | file | provenance | | +| taint_step_test.py:6:12:6:35 | After Attribute() | taint_step_test.py:6:5:6:8 | file | provenance | | +| taint_step_test.py:11:18:11:21 | path | taint_step_test.py:12:9:12:16 | filepath | provenance | | +| taint_step_test.py:11:18:11:21 | path | taint_step_test.py:12:9:12:16 | filepath | provenance | AdditionalTaintStep | +| taint_step_test.py:11:24:11:27 | file | taint_step_test.py:12:9:12:16 | filepath | provenance | AdditionalTaintStep | +| taint_step_test.py:12:9:12:16 | filepath | taint_step_test.py:13:19:13:26 | filepath | provenance | | +| taint_step_test.py:19:43:19:46 | path | taint_step_test.py:11:18:11:21 | path | provenance | AdditionalTaintStep | +| taint_step_test.py:19:48:19:51 | file | taint_step_test.py:11:24:11:27 | file | provenance | AdditionalTaintStep | nodes -| taint_step_test.py:5:5:5:8 | ControlFlowNode for path | semmle.label | ControlFlowNode for path | -| taint_step_test.py:5:12:5:35 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| taint_step_test.py:6:5:6:8 | ControlFlowNode for file | semmle.label | ControlFlowNode for file | -| taint_step_test.py:6:12:6:35 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| taint_step_test.py:11:18:11:21 | ControlFlowNode for path | semmle.label | ControlFlowNode for path | -| taint_step_test.py:11:24:11:27 | ControlFlowNode for file | semmle.label | ControlFlowNode for file | -| taint_step_test.py:12:9:12:16 | ControlFlowNode for filepath | semmle.label | ControlFlowNode for filepath | -| taint_step_test.py:12:20:12:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| taint_step_test.py:12:33:12:36 | ControlFlowNode for path | semmle.label | ControlFlowNode for path | -| taint_step_test.py:13:19:13:26 | ControlFlowNode for filepath | semmle.label | ControlFlowNode for filepath | -| taint_step_test.py:19:43:19:46 | ControlFlowNode for path | semmle.label | ControlFlowNode for path | -| taint_step_test.py:19:48:19:51 | ControlFlowNode for file | semmle.label | ControlFlowNode for file | +| taint_step_test.py:5:5:5:8 | path | semmle.label | path | +| taint_step_test.py:5:12:5:35 | After Attribute() | semmle.label | After Attribute() | +| taint_step_test.py:6:5:6:8 | file | semmle.label | file | +| taint_step_test.py:6:12:6:35 | After Attribute() | semmle.label | After Attribute() | +| taint_step_test.py:11:18:11:21 | path | semmle.label | path | +| taint_step_test.py:11:24:11:27 | file | semmle.label | file | +| taint_step_test.py:12:9:12:16 | filepath | semmle.label | filepath | +| taint_step_test.py:13:19:13:26 | filepath | semmle.label | filepath | +| taint_step_test.py:19:43:19:46 | path | semmle.label | path | +| taint_step_test.py:19:48:19:51 | file | semmle.label | file | subpaths #select -| taint_step_test.py:13:19:13:26 | ControlFlowNode for filepath | taint_step_test.py:5:12:5:35 | ControlFlowNode for Attribute() | taint_step_test.py:13:19:13:26 | ControlFlowNode for filepath | This path depends on a $@. | taint_step_test.py:5:12:5:35 | ControlFlowNode for Attribute() | user-provided value | -| taint_step_test.py:13:19:13:26 | ControlFlowNode for filepath | taint_step_test.py:6:12:6:35 | ControlFlowNode for Attribute() | taint_step_test.py:13:19:13:26 | ControlFlowNode for filepath | This path depends on a $@. | taint_step_test.py:6:12:6:35 | ControlFlowNode for Attribute() | user-provided value | +| taint_step_test.py:13:19:13:26 | filepath | taint_step_test.py:5:12:5:35 | After Attribute() | taint_step_test.py:13:19:13:26 | filepath | This path depends on a $@. | taint_step_test.py:5:12:5:35 | After Attribute() | user-provided value | +| taint_step_test.py:13:19:13:26 | filepath | taint_step_test.py:6:12:6:35 | After Attribute() | taint_step_test.py:13:19:13:26 | filepath | This path depends on a $@. | taint_step_test.py:6:12:6:35 | After Attribute() | user-provided value | diff --git a/python/ql/test/library-tests/frameworks/lxml/InlineTaintTest.expected b/python/ql/test/library-tests/frameworks/lxml/InlineTaintTest.expected index 020c338fd192..36d192b057e8 100644 --- a/python/ql/test/library-tests/frameworks/lxml/InlineTaintTest.expected +++ b/python/ql/test/library-tests/frameworks/lxml/InlineTaintTest.expected @@ -1,3 +1,5 @@ argumentToEnsureNotTaintedNotMarkedAsSpurious untaintedArgumentToEnsureTaintedNotMarkedAsMissing +| taint_test.py:133:13:133:35 | taint_test.py:133 | ERROR, you should add `# $ MISSING: tainted` annotation | tree_arg.getroot().text | testFailures +| taint_test.py:133:37:133:82 | Comment # $ tainted # Type tracking from the type hint | Missing result: tainted | diff --git a/python/ql/test/library-tests/frameworks/lxml/taint_test.py b/python/ql/test/library-tests/frameworks/lxml/taint_test.py index cb8103aad18a..917c4c55fae8 100644 --- a/python/ql/test/library-tests/frameworks/lxml/taint_test.py +++ b/python/ql/test/library-tests/frameworks/lxml/taint_test.py @@ -80,7 +80,7 @@ def test(): for ch in elem: ensure_tainted( ch, # $ tainted - ch.text # $ MISSING: tainted # API node getASubscript() appears to not consider things like for loops + ch.text # $ tainted ) buf = io.StringIO(src) diff --git a/python/ql/test/library-tests/frameworks/modeling-example/NaiveModel.expected b/python/ql/test/library-tests/frameworks/modeling-example/NaiveModel.expected index 178f63b4aabb..93475614b77d 100644 --- a/python/ql/test/library-tests/frameworks/modeling-example/NaiveModel.expected +++ b/python/ql/test/library-tests/frameworks/modeling-example/NaiveModel.expected @@ -1,46 +1,46 @@ edges -| test.py:21:11:21:18 | ControlFlowNode for source() | test.py:22:10:22:24 | ControlFlowNode for Attribute() | provenance | AdditionalTaintStep | -| test.py:29:11:29:18 | ControlFlowNode for source() | test.py:32:5:32:7 | ControlFlowNode for val | provenance | AdditionalTaintStep | -| test.py:32:5:32:7 | ControlFlowNode for val | test.py:33:10:33:12 | ControlFlowNode for val | provenance | | -| test.py:40:5:40:7 | ControlFlowNode for val | test.py:41:10:41:12 | ControlFlowNode for val | provenance | | -| test.py:40:11:40:25 | ControlFlowNode for Attribute() | test.py:40:5:40:7 | ControlFlowNode for val | provenance | | -| test.py:45:11:45:18 | ControlFlowNode for source() | test.py:40:11:40:25 | ControlFlowNode for Attribute() | provenance | AdditionalTaintStep | -| test.py:53:5:53:7 | ControlFlowNode for val | test.py:54:10:54:12 | ControlFlowNode for val | provenance | | -| test.py:53:11:53:25 | ControlFlowNode for Attribute() | test.py:53:5:53:7 | ControlFlowNode for val | provenance | | -| test.py:70:11:70:18 | ControlFlowNode for source() | test.py:53:11:53:25 | ControlFlowNode for Attribute() | provenance | AdditionalTaintStep | -| test.py:78:5:78:7 | ControlFlowNode for val | test.py:79:10:79:12 | ControlFlowNode for val | provenance | | -| test.py:78:11:78:14 | ControlFlowNode for bm() | test.py:78:5:78:7 | ControlFlowNode for val | provenance | | -| test.py:83:11:83:18 | ControlFlowNode for source() | test.py:78:11:78:14 | ControlFlowNode for bm() | provenance | AdditionalTaintStep | -| test.py:90:5:90:7 | ControlFlowNode for val | test.py:91:10:91:12 | ControlFlowNode for val | provenance | | -| test.py:90:11:90:14 | ControlFlowNode for bm() | test.py:90:5:90:7 | ControlFlowNode for val | provenance | | -| test.py:107:11:107:18 | ControlFlowNode for source() | test.py:90:11:90:14 | ControlFlowNode for bm() | provenance | AdditionalTaintStep | +| test.py:21:11:21:18 | After source() | test.py:22:10:22:24 | After Attribute() | provenance | AdditionalTaintStep | +| test.py:29:11:29:18 | After source() | test.py:32:5:32:7 | val | provenance | AdditionalTaintStep | +| test.py:32:5:32:7 | val | test.py:33:10:33:12 | val | provenance | | +| test.py:40:5:40:7 | val | test.py:41:10:41:12 | val | provenance | | +| test.py:40:11:40:25 | After Attribute() | test.py:40:5:40:7 | val | provenance | | +| test.py:45:11:45:18 | After source() | test.py:40:11:40:25 | After Attribute() | provenance | AdditionalTaintStep | +| test.py:53:5:53:7 | val | test.py:54:10:54:12 | val | provenance | | +| test.py:53:11:53:25 | After Attribute() | test.py:53:5:53:7 | val | provenance | | +| test.py:70:11:70:18 | After source() | test.py:53:11:53:25 | After Attribute() | provenance | AdditionalTaintStep | +| test.py:78:5:78:7 | val | test.py:79:10:79:12 | val | provenance | | +| test.py:78:11:78:14 | After bm() | test.py:78:5:78:7 | val | provenance | | +| test.py:83:11:83:18 | After source() | test.py:78:11:78:14 | After bm() | provenance | AdditionalTaintStep | +| test.py:90:5:90:7 | val | test.py:91:10:91:12 | val | provenance | | +| test.py:90:11:90:14 | After bm() | test.py:90:5:90:7 | val | provenance | | +| test.py:107:11:107:18 | After source() | test.py:90:11:90:14 | After bm() | provenance | AdditionalTaintStep | nodes -| test.py:21:11:21:18 | ControlFlowNode for source() | semmle.label | ControlFlowNode for source() | -| test.py:22:10:22:24 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| test.py:29:11:29:18 | ControlFlowNode for source() | semmle.label | ControlFlowNode for source() | -| test.py:32:5:32:7 | ControlFlowNode for val | semmle.label | ControlFlowNode for val | -| test.py:33:10:33:12 | ControlFlowNode for val | semmle.label | ControlFlowNode for val | -| test.py:40:5:40:7 | ControlFlowNode for val | semmle.label | ControlFlowNode for val | -| test.py:40:11:40:25 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| test.py:41:10:41:12 | ControlFlowNode for val | semmle.label | ControlFlowNode for val | -| test.py:45:11:45:18 | ControlFlowNode for source() | semmle.label | ControlFlowNode for source() | -| test.py:53:5:53:7 | ControlFlowNode for val | semmle.label | ControlFlowNode for val | -| test.py:53:11:53:25 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| test.py:54:10:54:12 | ControlFlowNode for val | semmle.label | ControlFlowNode for val | -| test.py:70:11:70:18 | ControlFlowNode for source() | semmle.label | ControlFlowNode for source() | -| test.py:78:5:78:7 | ControlFlowNode for val | semmle.label | ControlFlowNode for val | -| test.py:78:11:78:14 | ControlFlowNode for bm() | semmle.label | ControlFlowNode for bm() | -| test.py:79:10:79:12 | ControlFlowNode for val | semmle.label | ControlFlowNode for val | -| test.py:83:11:83:18 | ControlFlowNode for source() | semmle.label | ControlFlowNode for source() | -| test.py:90:5:90:7 | ControlFlowNode for val | semmle.label | ControlFlowNode for val | -| test.py:90:11:90:14 | ControlFlowNode for bm() | semmle.label | ControlFlowNode for bm() | -| test.py:91:10:91:12 | ControlFlowNode for val | semmle.label | ControlFlowNode for val | -| test.py:107:11:107:18 | ControlFlowNode for source() | semmle.label | ControlFlowNode for source() | +| test.py:21:11:21:18 | After source() | semmle.label | After source() | +| test.py:22:10:22:24 | After Attribute() | semmle.label | After Attribute() | +| test.py:29:11:29:18 | After source() | semmle.label | After source() | +| test.py:32:5:32:7 | val | semmle.label | val | +| test.py:33:10:33:12 | val | semmle.label | val | +| test.py:40:5:40:7 | val | semmle.label | val | +| test.py:40:11:40:25 | After Attribute() | semmle.label | After Attribute() | +| test.py:41:10:41:12 | val | semmle.label | val | +| test.py:45:11:45:18 | After source() | semmle.label | After source() | +| test.py:53:5:53:7 | val | semmle.label | val | +| test.py:53:11:53:25 | After Attribute() | semmle.label | After Attribute() | +| test.py:54:10:54:12 | val | semmle.label | val | +| test.py:70:11:70:18 | After source() | semmle.label | After source() | +| test.py:78:5:78:7 | val | semmle.label | val | +| test.py:78:11:78:14 | After bm() | semmle.label | After bm() | +| test.py:79:10:79:12 | val | semmle.label | val | +| test.py:83:11:83:18 | After source() | semmle.label | After source() | +| test.py:90:5:90:7 | val | semmle.label | val | +| test.py:90:11:90:14 | After bm() | semmle.label | After bm() | +| test.py:91:10:91:12 | val | semmle.label | val | +| test.py:107:11:107:18 | After source() | semmle.label | After source() | subpaths #select -| test.py:22:10:22:24 | ControlFlowNode for Attribute() | test.py:21:11:21:18 | ControlFlowNode for source() | test.py:22:10:22:24 | ControlFlowNode for Attribute() | test flow (naive): test_simple | -| test.py:33:10:33:12 | ControlFlowNode for val | test.py:29:11:29:18 | ControlFlowNode for source() | test.py:33:10:33:12 | ControlFlowNode for val | test flow (naive): test_alias | -| test.py:41:10:41:12 | ControlFlowNode for val | test.py:45:11:45:18 | ControlFlowNode for source() | test.py:41:10:41:12 | ControlFlowNode for val | test flow (naive): test_across_functions | -| test.py:54:10:54:12 | ControlFlowNode for val | test.py:70:11:70:18 | ControlFlowNode for source() | test.py:54:10:54:12 | ControlFlowNode for val | test flow (naive): test_deeply_nested | -| test.py:79:10:79:12 | ControlFlowNode for val | test.py:83:11:83:18 | ControlFlowNode for source() | test.py:79:10:79:12 | ControlFlowNode for val | test flow (naive): test_pass_bound_method | -| test.py:91:10:91:12 | ControlFlowNode for val | test.py:107:11:107:18 | ControlFlowNode for source() | test.py:91:10:91:12 | ControlFlowNode for val | test flow (naive): test_deeply_nested_bound_method | +| test.py:22:10:22:24 | After Attribute() | test.py:21:11:21:18 | After source() | test.py:22:10:22:24 | After Attribute() | test flow (naive): test_simple | +| test.py:33:10:33:12 | val | test.py:29:11:29:18 | After source() | test.py:33:10:33:12 | val | test flow (naive): test_alias | +| test.py:41:10:41:12 | val | test.py:45:11:45:18 | After source() | test.py:41:10:41:12 | val | test flow (naive): test_across_functions | +| test.py:54:10:54:12 | val | test.py:70:11:70:18 | After source() | test.py:54:10:54:12 | val | test flow (naive): test_deeply_nested | +| test.py:79:10:79:12 | val | test.py:83:11:83:18 | After source() | test.py:79:10:79:12 | val | test flow (naive): test_pass_bound_method | +| test.py:91:10:91:12 | val | test.py:107:11:107:18 | After source() | test.py:91:10:91:12 | val | test flow (naive): test_deeply_nested_bound_method | diff --git a/python/ql/test/library-tests/frameworks/modeling-example/NaiveModel.ql b/python/ql/test/library-tests/frameworks/modeling-example/NaiveModel.ql index 8b6eee5113fc..56d352eef4cb 100644 --- a/python/ql/test/library-tests/frameworks/modeling-example/NaiveModel.ql +++ b/python/ql/test/library-tests/frameworks/modeling-example/NaiveModel.ql @@ -3,6 +3,7 @@ */ private import python +private import semmle.python.controlflow.internal.Cfg as Cfg private import semmle.python.dataflow.new.DataFlow private import semmle.python.dataflow.new.TaintTracking import SharedFlow::PathGraph @@ -13,7 +14,7 @@ class MyClassGetValueAdditionalTaintStep extends TaintTracking::AdditionalTaintS // obj -> obj.get_value() exists(DataFlow::Node bound_method | bound_method = myClassGetValue(nodeFrom) and - nodeTo.asCfgNode().(CallNode).getFunction() = bound_method.asCfgNode() + nodeTo.asCfgNode().(Cfg::CallNode).getFunction() = bound_method.asCfgNode() ) } } diff --git a/python/ql/test/library-tests/frameworks/modeling-example/ProperModel.expected b/python/ql/test/library-tests/frameworks/modeling-example/ProperModel.expected index 86e0a1958f28..3355dfea9879 100644 --- a/python/ql/test/library-tests/frameworks/modeling-example/ProperModel.expected +++ b/python/ql/test/library-tests/frameworks/modeling-example/ProperModel.expected @@ -1,94 +1,94 @@ edges -| test.py:21:5:21:7 | ControlFlowNode for src | test.py:22:10:22:24 | ControlFlowNode for Attribute() | provenance | AdditionalTaintStep | -| test.py:21:11:21:18 | ControlFlowNode for source() | test.py:21:5:21:7 | ControlFlowNode for src | provenance | | -| test.py:29:5:29:7 | ControlFlowNode for src | test.py:30:5:30:7 | ControlFlowNode for foo | provenance | | -| test.py:29:11:29:18 | ControlFlowNode for source() | test.py:29:5:29:7 | ControlFlowNode for src | provenance | | -| test.py:30:5:30:7 | ControlFlowNode for foo | test.py:31:5:31:16 | ControlFlowNode for bound_method | provenance | AdditionalTaintStep | -| test.py:31:5:31:16 | ControlFlowNode for bound_method | test.py:32:5:32:7 | ControlFlowNode for val | provenance | AdditionalTaintStep | -| test.py:32:5:32:7 | ControlFlowNode for val | test.py:33:10:33:12 | ControlFlowNode for val | provenance | | -| test.py:39:15:39:17 | ControlFlowNode for arg | test.py:40:5:40:7 | ControlFlowNode for val | provenance | AdditionalTaintStep | -| test.py:40:5:40:7 | ControlFlowNode for val | test.py:41:10:41:12 | ControlFlowNode for val | provenance | | -| test.py:45:5:45:7 | ControlFlowNode for src | test.py:46:15:46:17 | ControlFlowNode for src | provenance | | -| test.py:45:11:45:18 | ControlFlowNode for source() | test.py:45:5:45:7 | ControlFlowNode for src | provenance | | -| test.py:46:15:46:17 | ControlFlowNode for src | test.py:39:15:39:17 | ControlFlowNode for arg | provenance | | -| test.py:52:24:52:26 | ControlFlowNode for arg | test.py:53:5:53:7 | ControlFlowNode for val | provenance | AdditionalTaintStep | -| test.py:53:5:53:7 | ControlFlowNode for val | test.py:54:10:54:12 | ControlFlowNode for val | provenance | | -| test.py:57:33:57:35 | ControlFlowNode for arg | test.py:58:24:58:26 | ControlFlowNode for arg | provenance | | -| test.py:58:24:58:26 | ControlFlowNode for arg | test.py:52:24:52:26 | ControlFlowNode for arg | provenance | | -| test.py:61:33:61:35 | ControlFlowNode for arg | test.py:62:33:62:35 | ControlFlowNode for arg | provenance | | -| test.py:62:33:62:35 | ControlFlowNode for arg | test.py:57:33:57:35 | ControlFlowNode for arg | provenance | | -| test.py:65:33:65:35 | ControlFlowNode for arg | test.py:66:33:66:35 | ControlFlowNode for arg | provenance | | -| test.py:66:33:66:35 | ControlFlowNode for arg | test.py:61:33:61:35 | ControlFlowNode for arg | provenance | | -| test.py:70:5:70:7 | ControlFlowNode for src | test.py:71:33:71:35 | ControlFlowNode for src | provenance | | -| test.py:70:11:70:18 | ControlFlowNode for source() | test.py:70:5:70:7 | ControlFlowNode for src | provenance | | -| test.py:71:33:71:35 | ControlFlowNode for src | test.py:65:33:65:35 | ControlFlowNode for arg | provenance | | -| test.py:77:23:77:24 | ControlFlowNode for bm | test.py:78:5:78:7 | ControlFlowNode for val | provenance | AdditionalTaintStep | -| test.py:78:5:78:7 | ControlFlowNode for val | test.py:79:10:79:12 | ControlFlowNode for val | provenance | | -| test.py:83:5:83:7 | ControlFlowNode for src | test.py:84:23:84:35 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | -| test.py:83:11:83:18 | ControlFlowNode for source() | test.py:83:5:83:7 | ControlFlowNode for src | provenance | | -| test.py:84:23:84:35 | ControlFlowNode for Attribute | test.py:77:23:77:24 | ControlFlowNode for bm | provenance | | -| test.py:89:37:89:38 | ControlFlowNode for bm | test.py:90:5:90:7 | ControlFlowNode for val | provenance | AdditionalTaintStep | -| test.py:90:5:90:7 | ControlFlowNode for val | test.py:91:10:91:12 | ControlFlowNode for val | provenance | | -| test.py:94:46:94:47 | ControlFlowNode for bm | test.py:95:37:95:38 | ControlFlowNode for bm | provenance | | -| test.py:95:37:95:38 | ControlFlowNode for bm | test.py:89:37:89:38 | ControlFlowNode for bm | provenance | | -| test.py:98:46:98:47 | ControlFlowNode for bm | test.py:99:46:99:47 | ControlFlowNode for bm | provenance | | -| test.py:99:46:99:47 | ControlFlowNode for bm | test.py:94:46:94:47 | ControlFlowNode for bm | provenance | | -| test.py:102:46:102:47 | ControlFlowNode for bm | test.py:103:46:103:47 | ControlFlowNode for bm | provenance | | -| test.py:103:46:103:47 | ControlFlowNode for bm | test.py:98:46:98:47 | ControlFlowNode for bm | provenance | | -| test.py:107:5:107:7 | ControlFlowNode for src | test.py:108:46:108:58 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | -| test.py:107:11:107:18 | ControlFlowNode for source() | test.py:107:5:107:7 | ControlFlowNode for src | provenance | | -| test.py:108:46:108:58 | ControlFlowNode for Attribute | test.py:102:46:102:47 | ControlFlowNode for bm | provenance | | +| test.py:21:5:21:7 | src | test.py:22:10:22:24 | After Attribute() | provenance | AdditionalTaintStep | +| test.py:21:11:21:18 | After source() | test.py:21:5:21:7 | src | provenance | | +| test.py:29:5:29:7 | src | test.py:30:5:30:7 | foo | provenance | | +| test.py:29:11:29:18 | After source() | test.py:29:5:29:7 | src | provenance | | +| test.py:30:5:30:7 | foo | test.py:31:5:31:16 | bound_method | provenance | AdditionalTaintStep | +| test.py:31:5:31:16 | bound_method | test.py:32:5:32:7 | val | provenance | AdditionalTaintStep | +| test.py:32:5:32:7 | val | test.py:33:10:33:12 | val | provenance | | +| test.py:39:15:39:17 | arg | test.py:40:5:40:7 | val | provenance | AdditionalTaintStep | +| test.py:40:5:40:7 | val | test.py:41:10:41:12 | val | provenance | | +| test.py:45:5:45:7 | src | test.py:46:15:46:17 | src | provenance | | +| test.py:45:11:45:18 | After source() | test.py:45:5:45:7 | src | provenance | | +| test.py:46:15:46:17 | src | test.py:39:15:39:17 | arg | provenance | | +| test.py:52:24:52:26 | arg | test.py:53:5:53:7 | val | provenance | AdditionalTaintStep | +| test.py:53:5:53:7 | val | test.py:54:10:54:12 | val | provenance | | +| test.py:57:33:57:35 | arg | test.py:58:24:58:26 | arg | provenance | | +| test.py:58:24:58:26 | arg | test.py:52:24:52:26 | arg | provenance | | +| test.py:61:33:61:35 | arg | test.py:62:33:62:35 | arg | provenance | | +| test.py:62:33:62:35 | arg | test.py:57:33:57:35 | arg | provenance | | +| test.py:65:33:65:35 | arg | test.py:66:33:66:35 | arg | provenance | | +| test.py:66:33:66:35 | arg | test.py:61:33:61:35 | arg | provenance | | +| test.py:70:5:70:7 | src | test.py:71:33:71:35 | src | provenance | | +| test.py:70:11:70:18 | After source() | test.py:70:5:70:7 | src | provenance | | +| test.py:71:33:71:35 | src | test.py:65:33:65:35 | arg | provenance | | +| test.py:77:23:77:24 | bm | test.py:78:5:78:7 | val | provenance | AdditionalTaintStep | +| test.py:78:5:78:7 | val | test.py:79:10:79:12 | val | provenance | | +| test.py:83:5:83:7 | src | test.py:84:23:84:35 | After Attribute | provenance | AdditionalTaintStep | +| test.py:83:11:83:18 | After source() | test.py:83:5:83:7 | src | provenance | | +| test.py:84:23:84:35 | After Attribute | test.py:77:23:77:24 | bm | provenance | | +| test.py:89:37:89:38 | bm | test.py:90:5:90:7 | val | provenance | AdditionalTaintStep | +| test.py:90:5:90:7 | val | test.py:91:10:91:12 | val | provenance | | +| test.py:94:46:94:47 | bm | test.py:95:37:95:38 | bm | provenance | | +| test.py:95:37:95:38 | bm | test.py:89:37:89:38 | bm | provenance | | +| test.py:98:46:98:47 | bm | test.py:99:46:99:47 | bm | provenance | | +| test.py:99:46:99:47 | bm | test.py:94:46:94:47 | bm | provenance | | +| test.py:102:46:102:47 | bm | test.py:103:46:103:47 | bm | provenance | | +| test.py:103:46:103:47 | bm | test.py:98:46:98:47 | bm | provenance | | +| test.py:107:5:107:7 | src | test.py:108:46:108:58 | After Attribute | provenance | AdditionalTaintStep | +| test.py:107:11:107:18 | After source() | test.py:107:5:107:7 | src | provenance | | +| test.py:108:46:108:58 | After Attribute | test.py:102:46:102:47 | bm | provenance | | nodes -| test.py:21:5:21:7 | ControlFlowNode for src | semmle.label | ControlFlowNode for src | -| test.py:21:11:21:18 | ControlFlowNode for source() | semmle.label | ControlFlowNode for source() | -| test.py:22:10:22:24 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| test.py:29:5:29:7 | ControlFlowNode for src | semmle.label | ControlFlowNode for src | -| test.py:29:11:29:18 | ControlFlowNode for source() | semmle.label | ControlFlowNode for source() | -| test.py:30:5:30:7 | ControlFlowNode for foo | semmle.label | ControlFlowNode for foo | -| test.py:31:5:31:16 | ControlFlowNode for bound_method | semmle.label | ControlFlowNode for bound_method | -| test.py:32:5:32:7 | ControlFlowNode for val | semmle.label | ControlFlowNode for val | -| test.py:33:10:33:12 | ControlFlowNode for val | semmle.label | ControlFlowNode for val | -| test.py:39:15:39:17 | ControlFlowNode for arg | semmle.label | ControlFlowNode for arg | -| test.py:40:5:40:7 | ControlFlowNode for val | semmle.label | ControlFlowNode for val | -| test.py:41:10:41:12 | ControlFlowNode for val | semmle.label | ControlFlowNode for val | -| test.py:45:5:45:7 | ControlFlowNode for src | semmle.label | ControlFlowNode for src | -| test.py:45:11:45:18 | ControlFlowNode for source() | semmle.label | ControlFlowNode for source() | -| test.py:46:15:46:17 | ControlFlowNode for src | semmle.label | ControlFlowNode for src | -| test.py:52:24:52:26 | ControlFlowNode for arg | semmle.label | ControlFlowNode for arg | -| test.py:53:5:53:7 | ControlFlowNode for val | semmle.label | ControlFlowNode for val | -| test.py:54:10:54:12 | ControlFlowNode for val | semmle.label | ControlFlowNode for val | -| test.py:57:33:57:35 | ControlFlowNode for arg | semmle.label | ControlFlowNode for arg | -| test.py:58:24:58:26 | ControlFlowNode for arg | semmle.label | ControlFlowNode for arg | -| test.py:61:33:61:35 | ControlFlowNode for arg | semmle.label | ControlFlowNode for arg | -| test.py:62:33:62:35 | ControlFlowNode for arg | semmle.label | ControlFlowNode for arg | -| test.py:65:33:65:35 | ControlFlowNode for arg | semmle.label | ControlFlowNode for arg | -| test.py:66:33:66:35 | ControlFlowNode for arg | semmle.label | ControlFlowNode for arg | -| test.py:70:5:70:7 | ControlFlowNode for src | semmle.label | ControlFlowNode for src | -| test.py:70:11:70:18 | ControlFlowNode for source() | semmle.label | ControlFlowNode for source() | -| test.py:71:33:71:35 | ControlFlowNode for src | semmle.label | ControlFlowNode for src | -| test.py:77:23:77:24 | ControlFlowNode for bm | semmle.label | ControlFlowNode for bm | -| test.py:78:5:78:7 | ControlFlowNode for val | semmle.label | ControlFlowNode for val | -| test.py:79:10:79:12 | ControlFlowNode for val | semmle.label | ControlFlowNode for val | -| test.py:83:5:83:7 | ControlFlowNode for src | semmle.label | ControlFlowNode for src | -| test.py:83:11:83:18 | ControlFlowNode for source() | semmle.label | ControlFlowNode for source() | -| test.py:84:23:84:35 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| test.py:89:37:89:38 | ControlFlowNode for bm | semmle.label | ControlFlowNode for bm | -| test.py:90:5:90:7 | ControlFlowNode for val | semmle.label | ControlFlowNode for val | -| test.py:91:10:91:12 | ControlFlowNode for val | semmle.label | ControlFlowNode for val | -| test.py:94:46:94:47 | ControlFlowNode for bm | semmle.label | ControlFlowNode for bm | -| test.py:95:37:95:38 | ControlFlowNode for bm | semmle.label | ControlFlowNode for bm | -| test.py:98:46:98:47 | ControlFlowNode for bm | semmle.label | ControlFlowNode for bm | -| test.py:99:46:99:47 | ControlFlowNode for bm | semmle.label | ControlFlowNode for bm | -| test.py:102:46:102:47 | ControlFlowNode for bm | semmle.label | ControlFlowNode for bm | -| test.py:103:46:103:47 | ControlFlowNode for bm | semmle.label | ControlFlowNode for bm | -| test.py:107:5:107:7 | ControlFlowNode for src | semmle.label | ControlFlowNode for src | -| test.py:107:11:107:18 | ControlFlowNode for source() | semmle.label | ControlFlowNode for source() | -| test.py:108:46:108:58 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | +| test.py:21:5:21:7 | src | semmle.label | src | +| test.py:21:11:21:18 | After source() | semmle.label | After source() | +| test.py:22:10:22:24 | After Attribute() | semmle.label | After Attribute() | +| test.py:29:5:29:7 | src | semmle.label | src | +| test.py:29:11:29:18 | After source() | semmle.label | After source() | +| test.py:30:5:30:7 | foo | semmle.label | foo | +| test.py:31:5:31:16 | bound_method | semmle.label | bound_method | +| test.py:32:5:32:7 | val | semmle.label | val | +| test.py:33:10:33:12 | val | semmle.label | val | +| test.py:39:15:39:17 | arg | semmle.label | arg | +| test.py:40:5:40:7 | val | semmle.label | val | +| test.py:41:10:41:12 | val | semmle.label | val | +| test.py:45:5:45:7 | src | semmle.label | src | +| test.py:45:11:45:18 | After source() | semmle.label | After source() | +| test.py:46:15:46:17 | src | semmle.label | src | +| test.py:52:24:52:26 | arg | semmle.label | arg | +| test.py:53:5:53:7 | val | semmle.label | val | +| test.py:54:10:54:12 | val | semmle.label | val | +| test.py:57:33:57:35 | arg | semmle.label | arg | +| test.py:58:24:58:26 | arg | semmle.label | arg | +| test.py:61:33:61:35 | arg | semmle.label | arg | +| test.py:62:33:62:35 | arg | semmle.label | arg | +| test.py:65:33:65:35 | arg | semmle.label | arg | +| test.py:66:33:66:35 | arg | semmle.label | arg | +| test.py:70:5:70:7 | src | semmle.label | src | +| test.py:70:11:70:18 | After source() | semmle.label | After source() | +| test.py:71:33:71:35 | src | semmle.label | src | +| test.py:77:23:77:24 | bm | semmle.label | bm | +| test.py:78:5:78:7 | val | semmle.label | val | +| test.py:79:10:79:12 | val | semmle.label | val | +| test.py:83:5:83:7 | src | semmle.label | src | +| test.py:83:11:83:18 | After source() | semmle.label | After source() | +| test.py:84:23:84:35 | After Attribute | semmle.label | After Attribute | +| test.py:89:37:89:38 | bm | semmle.label | bm | +| test.py:90:5:90:7 | val | semmle.label | val | +| test.py:91:10:91:12 | val | semmle.label | val | +| test.py:94:46:94:47 | bm | semmle.label | bm | +| test.py:95:37:95:38 | bm | semmle.label | bm | +| test.py:98:46:98:47 | bm | semmle.label | bm | +| test.py:99:46:99:47 | bm | semmle.label | bm | +| test.py:102:46:102:47 | bm | semmle.label | bm | +| test.py:103:46:103:47 | bm | semmle.label | bm | +| test.py:107:5:107:7 | src | semmle.label | src | +| test.py:107:11:107:18 | After source() | semmle.label | After source() | +| test.py:108:46:108:58 | After Attribute | semmle.label | After Attribute | subpaths #select -| test.py:22:10:22:24 | ControlFlowNode for Attribute() | test.py:21:11:21:18 | ControlFlowNode for source() | test.py:22:10:22:24 | ControlFlowNode for Attribute() | test flow (proper): test_simple | -| test.py:33:10:33:12 | ControlFlowNode for val | test.py:29:11:29:18 | ControlFlowNode for source() | test.py:33:10:33:12 | ControlFlowNode for val | test flow (proper): test_alias | -| test.py:41:10:41:12 | ControlFlowNode for val | test.py:45:11:45:18 | ControlFlowNode for source() | test.py:41:10:41:12 | ControlFlowNode for val | test flow (proper): test_across_functions | -| test.py:54:10:54:12 | ControlFlowNode for val | test.py:70:11:70:18 | ControlFlowNode for source() | test.py:54:10:54:12 | ControlFlowNode for val | test flow (proper): test_deeply_nested | -| test.py:79:10:79:12 | ControlFlowNode for val | test.py:83:11:83:18 | ControlFlowNode for source() | test.py:79:10:79:12 | ControlFlowNode for val | test flow (proper): test_pass_bound_method | -| test.py:91:10:91:12 | ControlFlowNode for val | test.py:107:11:107:18 | ControlFlowNode for source() | test.py:91:10:91:12 | ControlFlowNode for val | test flow (proper): test_deeply_nested_bound_method | +| test.py:22:10:22:24 | After Attribute() | test.py:21:11:21:18 | After source() | test.py:22:10:22:24 | After Attribute() | test flow (proper): test_simple | +| test.py:33:10:33:12 | val | test.py:29:11:29:18 | After source() | test.py:33:10:33:12 | val | test flow (proper): test_alias | +| test.py:41:10:41:12 | val | test.py:45:11:45:18 | After source() | test.py:41:10:41:12 | val | test flow (proper): test_across_functions | +| test.py:54:10:54:12 | val | test.py:70:11:70:18 | After source() | test.py:54:10:54:12 | val | test flow (proper): test_deeply_nested | +| test.py:79:10:79:12 | val | test.py:83:11:83:18 | After source() | test.py:79:10:79:12 | val | test flow (proper): test_pass_bound_method | +| test.py:91:10:91:12 | val | test.py:107:11:107:18 | After source() | test.py:91:10:91:12 | val | test flow (proper): test_deeply_nested_bound_method | diff --git a/python/ql/test/library-tests/frameworks/modeling-example/ProperModel.ql b/python/ql/test/library-tests/frameworks/modeling-example/ProperModel.ql index 98bb40501b83..b246847b3b49 100644 --- a/python/ql/test/library-tests/frameworks/modeling-example/ProperModel.ql +++ b/python/ql/test/library-tests/frameworks/modeling-example/ProperModel.ql @@ -3,6 +3,7 @@ */ private import python +private import semmle.python.controlflow.internal.Cfg as Cfg private import semmle.python.dataflow.new.DataFlow private import semmle.python.dataflow.new.TaintTracking import SharedFlow::PathGraph @@ -11,12 +12,12 @@ import SharedCode class MyClassGetValueAdditionalTaintStep extends TaintTracking::AdditionalTaintStep { override predicate step(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { // obj -> obj.get_value - nodeTo.asCfgNode().(AttrNode).getObject("get_value") = nodeFrom.asCfgNode() and + nodeTo.asCfgNode().(Cfg::AttrNode).getObject("get_value") = nodeFrom.asCfgNode() and nodeTo = myClassGetValue(_) or // get_value -> get_value() nodeFrom = myClassGetValue(_) and - nodeTo.asCfgNode().(CallNode).getFunction() = nodeFrom.asCfgNode() + nodeTo.asCfgNode().(Cfg::CallNode).getFunction() = nodeFrom.asCfgNode() } } diff --git a/python/ql/test/library-tests/frameworks/modeling-example/SharedCode.qll b/python/ql/test/library-tests/frameworks/modeling-example/SharedCode.qll index a541a7e2c818..3a5938ea8f30 100644 --- a/python/ql/test/library-tests/frameworks/modeling-example/SharedCode.qll +++ b/python/ql/test/library-tests/frameworks/modeling-example/SharedCode.qll @@ -1,4 +1,5 @@ private import python +private import semmle.python.controlflow.internal.Cfg as Cfg private import semmle.python.dataflow.new.DataFlow private import semmle.python.dataflow.new.TaintTracking @@ -19,15 +20,15 @@ DataFlow::Node myClassGetValue(MyClass qualifier) { // Config class SourceCall extends DataFlow::Node, MyClass { - SourceCall() { this.asCfgNode().(CallNode).getFunction().(NameNode).getId() = "source" } + SourceCall() { this.asCfgNode().(Cfg::CallNode).getFunction().(Cfg::NameNode).getId() = "source" } } private module SharedConfig implements DataFlow::ConfigSig { predicate isSource(DataFlow::Node source) { source instanceof SourceCall } predicate isSink(DataFlow::Node sink) { - exists(CallNode call | - call.getFunction().(NameNode).getId() = "sink" and + exists(Cfg::CallNode call | + call.getFunction().(Cfg::NameNode).getId() = "sink" and call.getArg(0) = sink.asCfgNode() ) } diff --git a/python/ql/test/library-tests/frameworks/rest_framework/CONSISTENCY/DataFlowConsistency.expected b/python/ql/test/library-tests/frameworks/rest_framework/CONSISTENCY/DataFlowConsistency.expected index e25f560dd83c..3cfad55fd47b 100644 --- a/python/ql/test/library-tests/frameworks/rest_framework/CONSISTENCY/DataFlowConsistency.expected +++ b/python/ql/test/library-tests/frameworks/rest_framework/CONSISTENCY/DataFlowConsistency.expected @@ -1,4 +1,4 @@ storeStepIsLocal -| testapp/models.py:6:1:6:24 | [orm-model] Class Foo | testapp/views.py:14:16:14:32 | ControlFlowNode for Attribute() | Store step does not preserve enclosing callable. | -| testapp/models.py:11:1:11:24 | [orm-model] Class Bar | testapp/views.py:19:16:19:32 | ControlFlowNode for Attribute() | Store step does not preserve enclosing callable. | -| testapp/models.py:11:1:11:24 | [orm-model] Class Bar | testapp/views.py:23:16:23:32 | ControlFlowNode for Attribute() | Store step does not preserve enclosing callable. | +| testapp/models.py:6:1:6:24 | [orm-model] Class Foo | testapp/views.py:14:16:14:32 | After Attribute() | Store step does not preserve enclosing callable. | +| testapp/models.py:11:1:11:24 | [orm-model] Class Bar | testapp/views.py:19:16:19:32 | After Attribute() | Store step does not preserve enclosing callable. | +| testapp/models.py:11:1:11:24 | [orm-model] Class Bar | testapp/views.py:23:16:23:32 | After Attribute() | Store step does not preserve enclosing callable. | diff --git a/python/ql/test/library-tests/frameworks/sqlalchemy/ConceptsTest.expected b/python/ql/test/library-tests/frameworks/sqlalchemy/ConceptsTest.expected index e69de29bb2d1..e0db8b3adb45 100644 --- a/python/ql/test/library-tests/frameworks/sqlalchemy/ConceptsTest.expected +++ b/python/ql/test/library-tests/frameworks/sqlalchemy/ConceptsTest.expected @@ -0,0 +1,20 @@ +| new_tests.py:49:32:49:49 | Comment # $ getSql=raw_sql | Missing result: getSql=raw_sql | +| new_tests.py:51:42:51:59 | Comment # $ getSql=raw_sql | Missing result: getSql=raw_sql | +| new_tests.py:54:33:54:51 | Comment # $ getSql=text_sql | Missing result: getSql=text_sql | +| new_tests.py:56:43:56:61 | Comment # $ getSql=text_sql | Missing result: getSql=text_sql | +| new_tests.py:60:38:60:55 | Comment # $ getSql=raw_sql | Missing result: getSql=raw_sql | +| new_tests.py:62:46:62:63 | Comment # $ getSql=raw_sql | Missing result: getSql=raw_sql | +| new_tests.py:65:39:65:57 | Comment # $ getSql=text_sql | Missing result: getSql=text_sql | +| new_tests.py:67:47:67:65 | Comment # $ getSql=text_sql | Missing result: getSql=text_sql | +| new_tests.py:72:40:72:57 | Comment # $ getSql=raw_sql | Missing result: getSql=raw_sql | +| new_tests.py:268:31:268:58 | Comment # $ SPURIOUS: getSql=raw_sql | Fixed spurious result: getSql=raw_sql | +| new_tests.py:273:37:273:55 | Comment # $ getSql=text_sql | Missing result: getSql=text_sql | +| new_tests.py:275:47:275:65 | Comment # $ getSql=text_sql | Missing result: getSql=text_sql | +| new_tests.py:278:44:278:61 | Comment # $ getSql=raw_sql | Missing result: getSql=raw_sql | +| new_tests.py:282:40:282:57 | Comment # $ getSql=raw_sql | Missing result: getSql=raw_sql | +| new_tests.py:294:58:294:76 | Comment # $ getSql=text_sql | Missing result: getSql=text_sql | +| new_tests.py:299:30:299:57 | Comment # $ SPURIOUS: getSql=raw_sql | Fixed spurious result: getSql=raw_sql | +| new_tests.py:302:43:302:61 | Comment # $ getSql=text_sql | Missing result: getSql=text_sql | +| new_tests.py:304:53:304:71 | Comment # $ getSql=text_sql | Missing result: getSql=text_sql | +| new_tests.py:309:35:309:51 | Comment # $ getSql=select | Missing result: getSql=select | +| new_tests.py:314:35:314:51 | Comment # $ getSql=select | Missing result: getSql=select | diff --git a/python/ql/test/library-tests/frameworks/stdlib-py2/ConceptsTest.expected b/python/ql/test/library-tests/frameworks/stdlib-py2/ConceptsTest.expected index e69de29bb2d1..cc005cabafa4 100644 --- a/python/ql/test/library-tests/frameworks/stdlib-py2/ConceptsTest.expected +++ b/python/ql/test/library-tests/frameworks/stdlib-py2/ConceptsTest.expected @@ -0,0 +1 @@ +| CodeExecution.py:2:19:2:41 | Comment # $ getCode="print(42)" | Missing result: getCode="print(42)" | diff --git a/python/ql/test/library-tests/frameworks/stdlib/InlineTaintTest.expected b/python/ql/test/library-tests/frameworks/stdlib/InlineTaintTest.expected index 020c338fd192..818d060db79f 100644 --- a/python/ql/test/library-tests/frameworks/stdlib/InlineTaintTest.expected +++ b/python/ql/test/library-tests/frameworks/stdlib/InlineTaintTest.expected @@ -1,3 +1,7 @@ argumentToEnsureNotTaintedNotMarkedAsSpurious untaintedArgumentToEnsureTaintedNotMarkedAsMissing +| http_server.py:43:9:43:54 | http_server.py:43 | ERROR, you should add `# $ MISSING: tainted` annotation | ListComp | +| test_re.py:46:5:46:49 | test_re.py:46 | ERROR, you should add `# $ MISSING: tainted` annotation | ListComp | testFailures +| http_server.py:43:57:43:67 | Comment # $ tainted | Missing result: tainted | +| test_re.py:46:52:46:62 | Comment # $ tainted | Missing result: tainted | diff --git a/python/ql/test/query-tests/Classes/init-calls-subclass-method/InitCallsSubclassMethod.expected b/python/ql/test/query-tests/Classes/init-calls-subclass-method/InitCallsSubclassMethod.expected index f06282e133b6..d5dda619abba 100644 --- a/python/ql/test/query-tests/Classes/init-calls-subclass-method/InitCallsSubclassMethod.expected +++ b/python/ql/test/query-tests/Classes/init-calls-subclass-method/InitCallsSubclassMethod.expected @@ -1,2 +1,2 @@ -| init_calls_subclass.py:8:13:8:28 | ControlFlowNode for Attribute() | This call to $@ in an initialization method is overridden by $@. | init_calls_subclass.py:11:9:11:30 | Function set_up | bad1.Super.set_up | init_calls_subclass.py:20:9:20:30 | Function set_up | bad1.Sub.set_up | -| init_calls_subclass.py:32:13:32:27 | ControlFlowNode for Attribute() | This call to $@ in an initialization method is overridden by $@. | init_calls_subclass.py:34:9:34:27 | Function postproc | bad2.Super.postproc | init_calls_subclass.py:43:9:43:27 | Function postproc | bad2.Sub.postproc | +| init_calls_subclass.py:8:13:8:28 | After Attribute() | This call to $@ in an initialization method is overridden by $@. | init_calls_subclass.py:11:9:11:30 | Function set_up | bad1.Super.set_up | init_calls_subclass.py:20:9:20:30 | Function set_up | bad1.Sub.set_up | +| init_calls_subclass.py:32:13:32:27 | After Attribute() | This call to $@ in an initialization method is overridden by $@. | init_calls_subclass.py:34:9:34:27 | Function postproc | bad2.Super.postproc | init_calls_subclass.py:43:9:43:27 | Function postproc | bad2.Sub.postproc | diff --git a/python/ql/test/query-tests/Classes/multiple/multiple-del/SuperclassDelCalledMultipleTimes.expected b/python/ql/test/query-tests/Classes/multiple/multiple-del/SuperclassDelCalledMultipleTimes.expected index b7ee48feba78..6e16880914b3 100644 --- a/python/ql/test/query-tests/Classes/multiple/multiple-del/SuperclassDelCalledMultipleTimes.expected +++ b/python/ql/test/query-tests/Classes/multiple/multiple-del/SuperclassDelCalledMultipleTimes.expected @@ -1,2 +1,2 @@ -| multiple_del.py:21:5:21:22 | Function __del__ | This finalization method calls $@ multiple times, via $@ and $@, resolving to $@ and $@ respectively. | multiple_del.py:9:5:9:22 | Function __del__ | Y1.__del__ | multiple_del.py:23:9:23:24 | ControlFlowNode for Attribute() | this call | multiple_del.py:24:9:24:24 | ControlFlowNode for Attribute() | this call | multiple_del.py:9:5:9:22 | Function __del__ | Y1.__del__ | multiple_del.py:15:5:15:22 | Function __del__ | Y2.__del__ | -| multiple_del.py:43:5:43:22 | Function __del__ | This finalization method calls $@ multiple times, via $@ and $@, resolving to $@ and $@ respectively. | multiple_del.py:32:5:32:22 | Function __del__ | Z1.__del__ | multiple_del.py:45:9:45:24 | ControlFlowNode for Attribute() | this call | multiple_del.py:46:9:46:24 | ControlFlowNode for Attribute() | this call | multiple_del.py:32:5:32:22 | Function __del__ | Z1.__del__ | multiple_del.py:37:5:37:22 | Function __del__ | Z2.__del__ | +| multiple_del.py:21:5:21:22 | Function __del__ | This finalization method calls $@ multiple times, via $@ and $@, resolving to $@ and $@ respectively. | multiple_del.py:9:5:9:22 | Function __del__ | Y1.__del__ | multiple_del.py:23:9:23:24 | After Attribute() | this call | multiple_del.py:24:9:24:24 | After Attribute() | this call | multiple_del.py:9:5:9:22 | Function __del__ | Y1.__del__ | multiple_del.py:15:5:15:22 | Function __del__ | Y2.__del__ | +| multiple_del.py:43:5:43:22 | Function __del__ | This finalization method calls $@ multiple times, via $@ and $@, resolving to $@ and $@ respectively. | multiple_del.py:32:5:32:22 | Function __del__ | Z1.__del__ | multiple_del.py:45:9:45:24 | After Attribute() | this call | multiple_del.py:46:9:46:24 | After Attribute() | this call | multiple_del.py:32:5:32:22 | Function __del__ | Z1.__del__ | multiple_del.py:37:5:37:22 | Function __del__ | Z2.__del__ | diff --git a/python/ql/test/query-tests/Classes/multiple/multiple-init/SuperclassInitCalledMultipleTimes.expected b/python/ql/test/query-tests/Classes/multiple/multiple-init/SuperclassInitCalledMultipleTimes.expected index 024d0c6425ab..8c032ebb673a 100644 --- a/python/ql/test/query-tests/Classes/multiple/multiple-init/SuperclassInitCalledMultipleTimes.expected +++ b/python/ql/test/query-tests/Classes/multiple/multiple-init/SuperclassInitCalledMultipleTimes.expected @@ -1,4 +1,4 @@ -| multiple_init.py:21:5:21:23 | Function __init__ | This initialization method calls $@ multiple times, via $@ and $@, resolving to $@ and $@ respectively. | multiple_init.py:9:5:9:23 | Function __init__ | C1.__init__ | multiple_init.py:23:9:23:25 | ControlFlowNode for Attribute() | this call | multiple_init.py:24:9:24:25 | ControlFlowNode for Attribute() | this call | multiple_init.py:9:5:9:23 | Function __init__ | C1.__init__ | multiple_init.py:15:5:15:23 | Function __init__ | C2.__init__ | -| multiple_init.py:42:5:42:23 | Function __init__ | This initialization method calls $@ multiple times, via $@ and $@, resolving to $@ and $@ respectively. | multiple_init.py:31:5:31:23 | Function __init__ | D1.__init__ | multiple_init.py:44:9:44:25 | ControlFlowNode for Attribute() | this call | multiple_init.py:45:9:45:25 | ControlFlowNode for Attribute() | this call | multiple_init.py:31:5:31:23 | Function __init__ | D1.__init__ | multiple_init.py:36:5:36:23 | Function __init__ | D2.__init__ | -| multiple_init.py:84:5:84:23 | Function __init__ | This initialization method calls $@ multiple times, via $@ and $@, resolving to $@ and $@ respectively. | multiple_init.py:80:5:80:23 | Function __init__ | F3.__init__ | multiple_init.py:86:9:86:25 | ControlFlowNode for Attribute() | this call | multiple_init.py:87:9:87:25 | ControlFlowNode for Attribute() | this call | multiple_init.py:75:5:75:23 | Function __init__ | F2.__init__ | multiple_init.py:80:5:80:23 | Function __init__ | F3.__init__ | -| multiple_init.py:111:5:111:23 | Function __init__ | This initialization method calls $@ multiple times, via $@ and $@, resolving to $@ and $@ respectively. | multiple_init.py:92:5:92:23 | Function __init__ | G1.__init__ | multiple_init.py:113:9:113:25 | ControlFlowNode for Attribute() | this call | multiple_init.py:114:9:114:25 | ControlFlowNode for Attribute() | this call | multiple_init.py:96:5:96:23 | Function __init__ | G2.__init__ | multiple_init.py:101:5:101:23 | Function __init__ | G3.__init__ | +| multiple_init.py:21:5:21:23 | Function __init__ | This initialization method calls $@ multiple times, via $@ and $@, resolving to $@ and $@ respectively. | multiple_init.py:9:5:9:23 | Function __init__ | C1.__init__ | multiple_init.py:23:9:23:25 | After Attribute() | this call | multiple_init.py:24:9:24:25 | After Attribute() | this call | multiple_init.py:9:5:9:23 | Function __init__ | C1.__init__ | multiple_init.py:15:5:15:23 | Function __init__ | C2.__init__ | +| multiple_init.py:42:5:42:23 | Function __init__ | This initialization method calls $@ multiple times, via $@ and $@, resolving to $@ and $@ respectively. | multiple_init.py:31:5:31:23 | Function __init__ | D1.__init__ | multiple_init.py:44:9:44:25 | After Attribute() | this call | multiple_init.py:45:9:45:25 | After Attribute() | this call | multiple_init.py:31:5:31:23 | Function __init__ | D1.__init__ | multiple_init.py:36:5:36:23 | Function __init__ | D2.__init__ | +| multiple_init.py:84:5:84:23 | Function __init__ | This initialization method calls $@ multiple times, via $@ and $@, resolving to $@ and $@ respectively. | multiple_init.py:80:5:80:23 | Function __init__ | F3.__init__ | multiple_init.py:86:9:86:25 | After Attribute() | this call | multiple_init.py:87:9:87:25 | After Attribute() | this call | multiple_init.py:75:5:75:23 | Function __init__ | F2.__init__ | multiple_init.py:80:5:80:23 | Function __init__ | F3.__init__ | +| multiple_init.py:111:5:111:23 | Function __init__ | This initialization method calls $@ multiple times, via $@ and $@, resolving to $@ and $@ respectively. | multiple_init.py:92:5:92:23 | Function __init__ | G1.__init__ | multiple_init.py:113:9:113:25 | After Attribute() | this call | multiple_init.py:114:9:114:25 | After Attribute() | this call | multiple_init.py:96:5:96:23 | Function __init__ | G2.__init__ | multiple_init.py:101:5:101:23 | Function __init__ | G3.__init__ | diff --git a/python/ql/test/query-tests/Classes/subclass-shadowing/SubclassShadowing.expected b/python/ql/test/query-tests/Classes/subclass-shadowing/SubclassShadowing.expected index 94912eb1f914..172fc487f46e 100644 --- a/python/ql/test/query-tests/Classes/subclass-shadowing/SubclassShadowing.expected +++ b/python/ql/test/query-tests/Classes/subclass-shadowing/SubclassShadowing.expected @@ -1,2 +1,2 @@ -| subclass_shadowing.py:11:5:11:21 | Function shadow | This method is shadowed by $@ in superclass $@. | subclass_shadowing.py:7:9:7:19 | ControlFlowNode for Attribute | attribute shadow | subclass_shadowing.py:4:1:4:11 | Class Base | Base | -| subclass_shadowing.py:41:5:41:18 | Function foo | This method is shadowed by $@ in superclass $@. (read-only property may cause an error if written to in the superclass) | subclass_shadowing.py:35:9:35:16 | ControlFlowNode for Attribute | attribute foo | subclass_shadowing.py:33:1:33:12 | Class Base3 | Base3 | +| subclass_shadowing.py:11:5:11:21 | Function shadow | This method is shadowed by $@ in superclass $@. | subclass_shadowing.py:7:9:7:19 | After Attribute | attribute shadow | subclass_shadowing.py:4:1:4:11 | Class Base | Base | +| subclass_shadowing.py:41:5:41:18 | Function foo | This method is shadowed by $@ in superclass $@. (read-only property may cause an error if written to in the superclass) | subclass_shadowing.py:35:9:35:16 | After Attribute | attribute foo | subclass_shadowing.py:33:1:33:12 | Class Base3 | Base3 | diff --git a/python/ql/test/query-tests/Expressions/super/CallToSuperWrongClass.expected b/python/ql/test/query-tests/Expressions/super/CallToSuperWrongClass.expected index 859e4624a01b..8db500312311 100644 --- a/python/ql/test/query-tests/Expressions/super/CallToSuperWrongClass.expected +++ b/python/ql/test/query-tests/Expressions/super/CallToSuperWrongClass.expected @@ -1 +1 @@ -| test.py:10:9:10:27 | ControlFlowNode for super() | First argument to super() should be NotMyDict. | +| test.py:10:9:10:27 | After super() | First argument to super() should be NotMyDict. | diff --git a/python/ql/test/query-tests/Functions/ModificationOfParameterWithDefault/ModificationOfParameterWithDefault.expected b/python/ql/test/query-tests/Functions/ModificationOfParameterWithDefault/ModificationOfParameterWithDefault.expected index 2bed4495c438..1c02375e1b2b 100644 --- a/python/ql/test/query-tests/Functions/ModificationOfParameterWithDefault/ModificationOfParameterWithDefault.expected +++ b/python/ql/test/query-tests/Functions/ModificationOfParameterWithDefault/ModificationOfParameterWithDefault.expected @@ -1,140 +1,140 @@ edges -| test.py:2:12:2:12 | ControlFlowNode for l | test.py:3:5:3:5 | ControlFlowNode for l | provenance | | -| test.py:7:11:7:11 | ControlFlowNode for l | test.py:8:5:8:5 | ControlFlowNode for l | provenance | | -| test.py:12:14:12:14 | ControlFlowNode for l | test.py:13:9:13:9 | ControlFlowNode for l | provenance | | -| test.py:17:15:17:15 | ControlFlowNode for l | test.py:18:5:18:5 | ControlFlowNode for l | provenance | | -| test.py:22:15:22:15 | ControlFlowNode for l | test.py:23:5:23:5 | ControlFlowNode for l | provenance | | -| test.py:27:12:27:12 | ControlFlowNode for l | test.py:28:5:28:5 | ControlFlowNode for l | provenance | | -| test.py:38:13:38:13 | ControlFlowNode for l | test.py:39:5:39:5 | ControlFlowNode for l | provenance | | -| test.py:43:14:43:14 | ControlFlowNode for l | test.py:44:13:44:13 | ControlFlowNode for l | provenance | | -| test.py:44:13:44:13 | ControlFlowNode for l | test.py:38:13:38:13 | ControlFlowNode for l | provenance | | -| test.py:48:14:48:14 | ControlFlowNode for l | test.py:49:5:49:5 | ControlFlowNode for l | provenance | | -| test.py:53:10:53:10 | ControlFlowNode for d | test.py:54:5:54:5 | ControlFlowNode for d | provenance | | -| test.py:58:19:58:19 | ControlFlowNode for d | test.py:59:5:59:5 | ControlFlowNode for d | provenance | | -| test.py:63:28:63:28 | ControlFlowNode for d | test.py:64:5:64:5 | ControlFlowNode for d | provenance | | -| test.py:67:14:67:14 | ControlFlowNode for d | test.py:68:5:68:5 | ControlFlowNode for d | provenance | | -| test.py:72:19:72:19 | ControlFlowNode for d | test.py:73:14:73:14 | ControlFlowNode for d | provenance | | -| test.py:73:14:73:14 | ControlFlowNode for d | test.py:67:14:67:14 | ControlFlowNode for d | provenance | | -| test.py:77:17:77:17 | ControlFlowNode for d | test.py:78:5:78:5 | ControlFlowNode for d | provenance | | -| test.py:82:26:82:26 | ControlFlowNode for d | test.py:83:5:83:5 | ControlFlowNode for d | provenance | | -| test.py:87:35:87:35 | ControlFlowNode for d | test.py:88:5:88:5 | ControlFlowNode for d | provenance | | -| test.py:91:21:91:21 | ControlFlowNode for d | test.py:92:5:92:5 | ControlFlowNode for d | provenance | | -| test.py:96:26:96:26 | ControlFlowNode for d | test.py:97:21:97:21 | ControlFlowNode for d | provenance | | -| test.py:97:21:97:21 | ControlFlowNode for d | test.py:91:21:91:21 | ControlFlowNode for d | provenance | | -| test.py:108:14:108:14 | ControlFlowNode for d | test.py:109:9:109:9 | ControlFlowNode for d | provenance | | -| test.py:113:20:113:20 | ControlFlowNode for d | test.py:115:5:115:5 | ControlFlowNode for d | provenance | | -| test.py:119:29:119:29 | ControlFlowNode for d | test.py:121:5:121:5 | ControlFlowNode for d | provenance | | -| test.py:124:15:124:15 | ControlFlowNode for l | test.py:128:9:128:9 | ControlFlowNode for l | provenance | | -| test.py:131:23:131:23 | ControlFlowNode for l | test.py:135:9:135:9 | ControlFlowNode for l | provenance | | -| test.py:138:15:138:15 | ControlFlowNode for l | test.py:140:9:140:9 | ControlFlowNode for l | provenance | | -| test.py:145:23:145:23 | ControlFlowNode for l | test.py:147:9:147:9 | ControlFlowNode for l | provenance | | -| test.py:153:25:153:25 | ControlFlowNode for x | test.py:154:5:154:5 | ControlFlowNode for x | provenance | | -| test.py:156:21:156:21 | ControlFlowNode for x | test.py:157:5:157:5 | ControlFlowNode for x | provenance | | -| test.py:159:27:159:27 | ControlFlowNode for y | test.py:160:25:160:25 | ControlFlowNode for y | provenance | | -| test.py:159:27:159:27 | ControlFlowNode for y | test.py:161:21:161:21 | ControlFlowNode for y | provenance | | -| test.py:160:25:160:25 | ControlFlowNode for y | test.py:153:25:153:25 | ControlFlowNode for x | provenance | | -| test.py:161:21:161:21 | ControlFlowNode for y | test.py:156:21:156:21 | ControlFlowNode for x | provenance | | -| test.py:181:28:181:28 | ControlFlowNode for x | test.py:185:9:185:9 | ControlFlowNode for x | provenance | | -| test.py:181:28:181:28 | ControlFlowNode for x | test.py:187:9:187:9 | ControlFlowNode for x | provenance | | -| test.py:194:18:194:18 | ControlFlowNode for x | test.py:195:28:195:28 | ControlFlowNode for x | provenance | | -| test.py:195:28:195:28 | ControlFlowNode for x | test.py:181:28:181:28 | ControlFlowNode for x | provenance | | -| test.py:197:18:197:18 | ControlFlowNode for x | test.py:198:28:198:28 | ControlFlowNode for x | provenance | | -| test.py:198:28:198:28 | ControlFlowNode for x | test.py:181:28:181:28 | ControlFlowNode for x | provenance | | +| test.py:2:12:2:12 | l | test.py:3:5:3:5 | l | provenance | | +| test.py:7:11:7:11 | l | test.py:8:5:8:5 | l | provenance | | +| test.py:12:14:12:14 | l | test.py:13:9:13:9 | l | provenance | | +| test.py:17:15:17:15 | l | test.py:18:5:18:5 | l | provenance | | +| test.py:22:15:22:15 | l | test.py:23:5:23:5 | l | provenance | | +| test.py:27:12:27:12 | l | test.py:28:5:28:5 | l | provenance | | +| test.py:38:13:38:13 | l | test.py:39:5:39:5 | l | provenance | | +| test.py:43:14:43:14 | l | test.py:44:13:44:13 | l | provenance | | +| test.py:44:13:44:13 | l | test.py:38:13:38:13 | l | provenance | | +| test.py:48:14:48:14 | l | test.py:49:5:49:5 | l | provenance | | +| test.py:53:10:53:10 | d | test.py:54:5:54:5 | d | provenance | | +| test.py:58:19:58:19 | d | test.py:59:5:59:5 | d | provenance | | +| test.py:63:28:63:28 | d | test.py:64:5:64:5 | d | provenance | | +| test.py:67:14:67:14 | d | test.py:68:5:68:5 | d | provenance | | +| test.py:72:19:72:19 | d | test.py:73:14:73:14 | d | provenance | | +| test.py:73:14:73:14 | d | test.py:67:14:67:14 | d | provenance | | +| test.py:77:17:77:17 | d | test.py:78:5:78:5 | d | provenance | | +| test.py:82:26:82:26 | d | test.py:83:5:83:5 | d | provenance | | +| test.py:87:35:87:35 | d | test.py:88:5:88:5 | d | provenance | | +| test.py:91:21:91:21 | d | test.py:92:5:92:5 | d | provenance | | +| test.py:96:26:96:26 | d | test.py:97:21:97:21 | d | provenance | | +| test.py:97:21:97:21 | d | test.py:91:21:91:21 | d | provenance | | +| test.py:108:14:108:14 | d | test.py:109:9:109:9 | d | provenance | | +| test.py:113:20:113:20 | d | test.py:115:5:115:5 | d | provenance | | +| test.py:119:29:119:29 | d | test.py:121:5:121:5 | d | provenance | | +| test.py:124:15:124:15 | l | test.py:128:9:128:9 | l | provenance | | +| test.py:131:23:131:23 | l | test.py:135:9:135:9 | l | provenance | | +| test.py:138:15:138:15 | l | test.py:140:9:140:9 | l | provenance | | +| test.py:145:23:145:23 | l | test.py:147:9:147:9 | l | provenance | | +| test.py:153:25:153:25 | x | test.py:154:5:154:5 | x | provenance | | +| test.py:156:21:156:21 | x | test.py:157:5:157:5 | x | provenance | | +| test.py:159:27:159:27 | y | test.py:160:25:160:25 | y | provenance | | +| test.py:159:27:159:27 | y | test.py:161:21:161:21 | y | provenance | | +| test.py:160:25:160:25 | y | test.py:153:25:153:25 | x | provenance | | +| test.py:161:21:161:21 | y | test.py:156:21:156:21 | x | provenance | | +| test.py:181:28:181:28 | x | test.py:185:9:185:9 | x | provenance | | +| test.py:181:28:181:28 | x | test.py:187:9:187:9 | x | provenance | | +| test.py:194:18:194:18 | x | test.py:195:28:195:28 | x | provenance | | +| test.py:195:28:195:28 | x | test.py:181:28:181:28 | x | provenance | | +| test.py:197:18:197:18 | x | test.py:198:28:198:28 | x | provenance | | +| test.py:198:28:198:28 | x | test.py:181:28:181:28 | x | provenance | | nodes -| test.py:2:12:2:12 | ControlFlowNode for l | semmle.label | ControlFlowNode for l | -| test.py:3:5:3:5 | ControlFlowNode for l | semmle.label | ControlFlowNode for l | -| test.py:7:11:7:11 | ControlFlowNode for l | semmle.label | ControlFlowNode for l | -| test.py:8:5:8:5 | ControlFlowNode for l | semmle.label | ControlFlowNode for l | -| test.py:12:14:12:14 | ControlFlowNode for l | semmle.label | ControlFlowNode for l | -| test.py:13:9:13:9 | ControlFlowNode for l | semmle.label | ControlFlowNode for l | -| test.py:17:15:17:15 | ControlFlowNode for l | semmle.label | ControlFlowNode for l | -| test.py:18:5:18:5 | ControlFlowNode for l | semmle.label | ControlFlowNode for l | -| test.py:22:15:22:15 | ControlFlowNode for l | semmle.label | ControlFlowNode for l | -| test.py:23:5:23:5 | ControlFlowNode for l | semmle.label | ControlFlowNode for l | -| test.py:27:12:27:12 | ControlFlowNode for l | semmle.label | ControlFlowNode for l | -| test.py:28:5:28:5 | ControlFlowNode for l | semmle.label | ControlFlowNode for l | -| test.py:38:13:38:13 | ControlFlowNode for l | semmle.label | ControlFlowNode for l | -| test.py:39:5:39:5 | ControlFlowNode for l | semmle.label | ControlFlowNode for l | -| test.py:43:14:43:14 | ControlFlowNode for l | semmle.label | ControlFlowNode for l | -| test.py:44:13:44:13 | ControlFlowNode for l | semmle.label | ControlFlowNode for l | -| test.py:48:14:48:14 | ControlFlowNode for l | semmle.label | ControlFlowNode for l | -| test.py:49:5:49:5 | ControlFlowNode for l | semmle.label | ControlFlowNode for l | -| test.py:53:10:53:10 | ControlFlowNode for d | semmle.label | ControlFlowNode for d | -| test.py:54:5:54:5 | ControlFlowNode for d | semmle.label | ControlFlowNode for d | -| test.py:58:19:58:19 | ControlFlowNode for d | semmle.label | ControlFlowNode for d | -| test.py:59:5:59:5 | ControlFlowNode for d | semmle.label | ControlFlowNode for d | -| test.py:63:28:63:28 | ControlFlowNode for d | semmle.label | ControlFlowNode for d | -| test.py:64:5:64:5 | ControlFlowNode for d | semmle.label | ControlFlowNode for d | -| test.py:67:14:67:14 | ControlFlowNode for d | semmle.label | ControlFlowNode for d | -| test.py:68:5:68:5 | ControlFlowNode for d | semmle.label | ControlFlowNode for d | -| test.py:72:19:72:19 | ControlFlowNode for d | semmle.label | ControlFlowNode for d | -| test.py:73:14:73:14 | ControlFlowNode for d | semmle.label | ControlFlowNode for d | -| test.py:77:17:77:17 | ControlFlowNode for d | semmle.label | ControlFlowNode for d | -| test.py:78:5:78:5 | ControlFlowNode for d | semmle.label | ControlFlowNode for d | -| test.py:82:26:82:26 | ControlFlowNode for d | semmle.label | ControlFlowNode for d | -| test.py:83:5:83:5 | ControlFlowNode for d | semmle.label | ControlFlowNode for d | -| test.py:87:35:87:35 | ControlFlowNode for d | semmle.label | ControlFlowNode for d | -| test.py:88:5:88:5 | ControlFlowNode for d | semmle.label | ControlFlowNode for d | -| test.py:91:21:91:21 | ControlFlowNode for d | semmle.label | ControlFlowNode for d | -| test.py:92:5:92:5 | ControlFlowNode for d | semmle.label | ControlFlowNode for d | -| test.py:96:26:96:26 | ControlFlowNode for d | semmle.label | ControlFlowNode for d | -| test.py:97:21:97:21 | ControlFlowNode for d | semmle.label | ControlFlowNode for d | -| test.py:108:14:108:14 | ControlFlowNode for d | semmle.label | ControlFlowNode for d | -| test.py:109:9:109:9 | ControlFlowNode for d | semmle.label | ControlFlowNode for d | -| test.py:113:20:113:20 | ControlFlowNode for d | semmle.label | ControlFlowNode for d | -| test.py:115:5:115:5 | ControlFlowNode for d | semmle.label | ControlFlowNode for d | -| test.py:119:29:119:29 | ControlFlowNode for d | semmle.label | ControlFlowNode for d | -| test.py:121:5:121:5 | ControlFlowNode for d | semmle.label | ControlFlowNode for d | -| test.py:124:15:124:15 | ControlFlowNode for l | semmle.label | ControlFlowNode for l | -| test.py:128:9:128:9 | ControlFlowNode for l | semmle.label | ControlFlowNode for l | -| test.py:131:23:131:23 | ControlFlowNode for l | semmle.label | ControlFlowNode for l | -| test.py:135:9:135:9 | ControlFlowNode for l | semmle.label | ControlFlowNode for l | -| test.py:138:15:138:15 | ControlFlowNode for l | semmle.label | ControlFlowNode for l | -| test.py:140:9:140:9 | ControlFlowNode for l | semmle.label | ControlFlowNode for l | -| test.py:145:23:145:23 | ControlFlowNode for l | semmle.label | ControlFlowNode for l | -| test.py:147:9:147:9 | ControlFlowNode for l | semmle.label | ControlFlowNode for l | -| test.py:153:25:153:25 | ControlFlowNode for x | semmle.label | ControlFlowNode for x | -| test.py:154:5:154:5 | ControlFlowNode for x | semmle.label | ControlFlowNode for x | -| test.py:156:21:156:21 | ControlFlowNode for x | semmle.label | ControlFlowNode for x | -| test.py:157:5:157:5 | ControlFlowNode for x | semmle.label | ControlFlowNode for x | -| test.py:159:27:159:27 | ControlFlowNode for y | semmle.label | ControlFlowNode for y | -| test.py:160:25:160:25 | ControlFlowNode for y | semmle.label | ControlFlowNode for y | -| test.py:161:21:161:21 | ControlFlowNode for y | semmle.label | ControlFlowNode for y | -| test.py:181:28:181:28 | ControlFlowNode for x | semmle.label | ControlFlowNode for x | -| test.py:185:9:185:9 | ControlFlowNode for x | semmle.label | ControlFlowNode for x | -| test.py:187:9:187:9 | ControlFlowNode for x | semmle.label | ControlFlowNode for x | -| test.py:194:18:194:18 | ControlFlowNode for x | semmle.label | ControlFlowNode for x | -| test.py:195:28:195:28 | ControlFlowNode for x | semmle.label | ControlFlowNode for x | -| test.py:197:18:197:18 | ControlFlowNode for x | semmle.label | ControlFlowNode for x | -| test.py:198:28:198:28 | ControlFlowNode for x | semmle.label | ControlFlowNode for x | +| test.py:2:12:2:12 | l | semmle.label | l | +| test.py:3:5:3:5 | l | semmle.label | l | +| test.py:7:11:7:11 | l | semmle.label | l | +| test.py:8:5:8:5 | l | semmle.label | l | +| test.py:12:14:12:14 | l | semmle.label | l | +| test.py:13:9:13:9 | l | semmle.label | l | +| test.py:17:15:17:15 | l | semmle.label | l | +| test.py:18:5:18:5 | l | semmle.label | l | +| test.py:22:15:22:15 | l | semmle.label | l | +| test.py:23:5:23:5 | l | semmle.label | l | +| test.py:27:12:27:12 | l | semmle.label | l | +| test.py:28:5:28:5 | l | semmle.label | l | +| test.py:38:13:38:13 | l | semmle.label | l | +| test.py:39:5:39:5 | l | semmle.label | l | +| test.py:43:14:43:14 | l | semmle.label | l | +| test.py:44:13:44:13 | l | semmle.label | l | +| test.py:48:14:48:14 | l | semmle.label | l | +| test.py:49:5:49:5 | l | semmle.label | l | +| test.py:53:10:53:10 | d | semmle.label | d | +| test.py:54:5:54:5 | d | semmle.label | d | +| test.py:58:19:58:19 | d | semmle.label | d | +| test.py:59:5:59:5 | d | semmle.label | d | +| test.py:63:28:63:28 | d | semmle.label | d | +| test.py:64:5:64:5 | d | semmle.label | d | +| test.py:67:14:67:14 | d | semmle.label | d | +| test.py:68:5:68:5 | d | semmle.label | d | +| test.py:72:19:72:19 | d | semmle.label | d | +| test.py:73:14:73:14 | d | semmle.label | d | +| test.py:77:17:77:17 | d | semmle.label | d | +| test.py:78:5:78:5 | d | semmle.label | d | +| test.py:82:26:82:26 | d | semmle.label | d | +| test.py:83:5:83:5 | d | semmle.label | d | +| test.py:87:35:87:35 | d | semmle.label | d | +| test.py:88:5:88:5 | d | semmle.label | d | +| test.py:91:21:91:21 | d | semmle.label | d | +| test.py:92:5:92:5 | d | semmle.label | d | +| test.py:96:26:96:26 | d | semmle.label | d | +| test.py:97:21:97:21 | d | semmle.label | d | +| test.py:108:14:108:14 | d | semmle.label | d | +| test.py:109:9:109:9 | d | semmle.label | d | +| test.py:113:20:113:20 | d | semmle.label | d | +| test.py:115:5:115:5 | d | semmle.label | d | +| test.py:119:29:119:29 | d | semmle.label | d | +| test.py:121:5:121:5 | d | semmle.label | d | +| test.py:124:15:124:15 | l | semmle.label | l | +| test.py:128:9:128:9 | l | semmle.label | l | +| test.py:131:23:131:23 | l | semmle.label | l | +| test.py:135:9:135:9 | l | semmle.label | l | +| test.py:138:15:138:15 | l | semmle.label | l | +| test.py:140:9:140:9 | l | semmle.label | l | +| test.py:145:23:145:23 | l | semmle.label | l | +| test.py:147:9:147:9 | l | semmle.label | l | +| test.py:153:25:153:25 | x | semmle.label | x | +| test.py:154:5:154:5 | x | semmle.label | x | +| test.py:156:21:156:21 | x | semmle.label | x | +| test.py:157:5:157:5 | x | semmle.label | x | +| test.py:159:27:159:27 | y | semmle.label | y | +| test.py:160:25:160:25 | y | semmle.label | y | +| test.py:161:21:161:21 | y | semmle.label | y | +| test.py:181:28:181:28 | x | semmle.label | x | +| test.py:185:9:185:9 | x | semmle.label | x | +| test.py:187:9:187:9 | x | semmle.label | x | +| test.py:194:18:194:18 | x | semmle.label | x | +| test.py:195:28:195:28 | x | semmle.label | x | +| test.py:197:18:197:18 | x | semmle.label | x | +| test.py:198:28:198:28 | x | semmle.label | x | subpaths #select -| test.py:3:5:3:5 | ControlFlowNode for l | test.py:2:12:2:12 | ControlFlowNode for l | test.py:3:5:3:5 | ControlFlowNode for l | This expression mutates a $@. | test.py:2:12:2:12 | ControlFlowNode for l | default value | -| test.py:8:5:8:5 | ControlFlowNode for l | test.py:7:11:7:11 | ControlFlowNode for l | test.py:8:5:8:5 | ControlFlowNode for l | This expression mutates a $@. | test.py:7:11:7:11 | ControlFlowNode for l | default value | -| test.py:13:9:13:9 | ControlFlowNode for l | test.py:12:14:12:14 | ControlFlowNode for l | test.py:13:9:13:9 | ControlFlowNode for l | This expression mutates a $@. | test.py:12:14:12:14 | ControlFlowNode for l | default value | -| test.py:18:5:18:5 | ControlFlowNode for l | test.py:17:15:17:15 | ControlFlowNode for l | test.py:18:5:18:5 | ControlFlowNode for l | This expression mutates a $@. | test.py:17:15:17:15 | ControlFlowNode for l | default value | -| test.py:23:5:23:5 | ControlFlowNode for l | test.py:22:15:22:15 | ControlFlowNode for l | test.py:23:5:23:5 | ControlFlowNode for l | This expression mutates a $@. | test.py:22:15:22:15 | ControlFlowNode for l | default value | -| test.py:28:5:28:5 | ControlFlowNode for l | test.py:27:12:27:12 | ControlFlowNode for l | test.py:28:5:28:5 | ControlFlowNode for l | This expression mutates a $@. | test.py:27:12:27:12 | ControlFlowNode for l | default value | -| test.py:39:5:39:5 | ControlFlowNode for l | test.py:43:14:43:14 | ControlFlowNode for l | test.py:39:5:39:5 | ControlFlowNode for l | This expression mutates a $@. | test.py:43:14:43:14 | ControlFlowNode for l | default value | -| test.py:49:5:49:5 | ControlFlowNode for l | test.py:48:14:48:14 | ControlFlowNode for l | test.py:49:5:49:5 | ControlFlowNode for l | This expression mutates a $@. | test.py:48:14:48:14 | ControlFlowNode for l | default value | -| test.py:54:5:54:5 | ControlFlowNode for d | test.py:53:10:53:10 | ControlFlowNode for d | test.py:54:5:54:5 | ControlFlowNode for d | This expression mutates a $@. | test.py:53:10:53:10 | ControlFlowNode for d | default value | -| test.py:59:5:59:5 | ControlFlowNode for d | test.py:58:19:58:19 | ControlFlowNode for d | test.py:59:5:59:5 | ControlFlowNode for d | This expression mutates a $@. | test.py:58:19:58:19 | ControlFlowNode for d | default value | -| test.py:64:5:64:5 | ControlFlowNode for d | test.py:63:28:63:28 | ControlFlowNode for d | test.py:64:5:64:5 | ControlFlowNode for d | This expression mutates a $@. | test.py:63:28:63:28 | ControlFlowNode for d | default value | -| test.py:68:5:68:5 | ControlFlowNode for d | test.py:72:19:72:19 | ControlFlowNode for d | test.py:68:5:68:5 | ControlFlowNode for d | This expression mutates a $@. | test.py:72:19:72:19 | ControlFlowNode for d | default value | -| test.py:78:5:78:5 | ControlFlowNode for d | test.py:77:17:77:17 | ControlFlowNode for d | test.py:78:5:78:5 | ControlFlowNode for d | This expression mutates a $@. | test.py:77:17:77:17 | ControlFlowNode for d | default value | -| test.py:83:5:83:5 | ControlFlowNode for d | test.py:82:26:82:26 | ControlFlowNode for d | test.py:83:5:83:5 | ControlFlowNode for d | This expression mutates a $@. | test.py:82:26:82:26 | ControlFlowNode for d | default value | -| test.py:88:5:88:5 | ControlFlowNode for d | test.py:87:35:87:35 | ControlFlowNode for d | test.py:88:5:88:5 | ControlFlowNode for d | This expression mutates a $@. | test.py:87:35:87:35 | ControlFlowNode for d | default value | -| test.py:92:5:92:5 | ControlFlowNode for d | test.py:96:26:96:26 | ControlFlowNode for d | test.py:92:5:92:5 | ControlFlowNode for d | This expression mutates a $@. | test.py:96:26:96:26 | ControlFlowNode for d | default value | -| test.py:109:9:109:9 | ControlFlowNode for d | test.py:108:14:108:14 | ControlFlowNode for d | test.py:109:9:109:9 | ControlFlowNode for d | This expression mutates a $@. | test.py:108:14:108:14 | ControlFlowNode for d | default value | -| test.py:115:5:115:5 | ControlFlowNode for d | test.py:113:20:113:20 | ControlFlowNode for d | test.py:115:5:115:5 | ControlFlowNode for d | This expression mutates a $@. | test.py:113:20:113:20 | ControlFlowNode for d | default value | -| test.py:121:5:121:5 | ControlFlowNode for d | test.py:119:29:119:29 | ControlFlowNode for d | test.py:121:5:121:5 | ControlFlowNode for d | This expression mutates a $@. | test.py:119:29:119:29 | ControlFlowNode for d | default value | -| test.py:128:9:128:9 | ControlFlowNode for l | test.py:124:15:124:15 | ControlFlowNode for l | test.py:128:9:128:9 | ControlFlowNode for l | This expression mutates a $@. | test.py:124:15:124:15 | ControlFlowNode for l | default value | -| test.py:135:9:135:9 | ControlFlowNode for l | test.py:131:23:131:23 | ControlFlowNode for l | test.py:135:9:135:9 | ControlFlowNode for l | This expression mutates a $@. | test.py:131:23:131:23 | ControlFlowNode for l | default value | -| test.py:140:9:140:9 | ControlFlowNode for l | test.py:138:15:138:15 | ControlFlowNode for l | test.py:140:9:140:9 | ControlFlowNode for l | This expression mutates a $@. | test.py:138:15:138:15 | ControlFlowNode for l | default value | -| test.py:147:9:147:9 | ControlFlowNode for l | test.py:145:23:145:23 | ControlFlowNode for l | test.py:147:9:147:9 | ControlFlowNode for l | This expression mutates a $@. | test.py:145:23:145:23 | ControlFlowNode for l | default value | -| test.py:154:5:154:5 | ControlFlowNode for x | test.py:159:27:159:27 | ControlFlowNode for y | test.py:154:5:154:5 | ControlFlowNode for x | This expression mutates a $@. | test.py:159:27:159:27 | ControlFlowNode for y | default value | -| test.py:157:5:157:5 | ControlFlowNode for x | test.py:159:27:159:27 | ControlFlowNode for y | test.py:157:5:157:5 | ControlFlowNode for x | This expression mutates a $@. | test.py:159:27:159:27 | ControlFlowNode for y | default value | -| test.py:185:9:185:9 | ControlFlowNode for x | test.py:194:18:194:18 | ControlFlowNode for x | test.py:185:9:185:9 | ControlFlowNode for x | This expression mutates a $@. | test.py:194:18:194:18 | ControlFlowNode for x | default value | -| test.py:185:9:185:9 | ControlFlowNode for x | test.py:197:18:197:18 | ControlFlowNode for x | test.py:185:9:185:9 | ControlFlowNode for x | This expression mutates a $@. | test.py:197:18:197:18 | ControlFlowNode for x | default value | -| test.py:187:9:187:9 | ControlFlowNode for x | test.py:194:18:194:18 | ControlFlowNode for x | test.py:187:9:187:9 | ControlFlowNode for x | This expression mutates a $@. | test.py:194:18:194:18 | ControlFlowNode for x | default value | -| test.py:187:9:187:9 | ControlFlowNode for x | test.py:197:18:197:18 | ControlFlowNode for x | test.py:187:9:187:9 | ControlFlowNode for x | This expression mutates a $@. | test.py:197:18:197:18 | ControlFlowNode for x | default value | +| test.py:3:5:3:5 | l | test.py:2:12:2:12 | l | test.py:3:5:3:5 | l | This expression mutates a $@. | test.py:2:12:2:12 | l | default value | +| test.py:8:5:8:5 | l | test.py:7:11:7:11 | l | test.py:8:5:8:5 | l | This expression mutates a $@. | test.py:7:11:7:11 | l | default value | +| test.py:13:9:13:9 | l | test.py:12:14:12:14 | l | test.py:13:9:13:9 | l | This expression mutates a $@. | test.py:12:14:12:14 | l | default value | +| test.py:18:5:18:5 | l | test.py:17:15:17:15 | l | test.py:18:5:18:5 | l | This expression mutates a $@. | test.py:17:15:17:15 | l | default value | +| test.py:23:5:23:5 | l | test.py:22:15:22:15 | l | test.py:23:5:23:5 | l | This expression mutates a $@. | test.py:22:15:22:15 | l | default value | +| test.py:28:5:28:5 | l | test.py:27:12:27:12 | l | test.py:28:5:28:5 | l | This expression mutates a $@. | test.py:27:12:27:12 | l | default value | +| test.py:39:5:39:5 | l | test.py:43:14:43:14 | l | test.py:39:5:39:5 | l | This expression mutates a $@. | test.py:43:14:43:14 | l | default value | +| test.py:49:5:49:5 | l | test.py:48:14:48:14 | l | test.py:49:5:49:5 | l | This expression mutates a $@. | test.py:48:14:48:14 | l | default value | +| test.py:54:5:54:5 | d | test.py:53:10:53:10 | d | test.py:54:5:54:5 | d | This expression mutates a $@. | test.py:53:10:53:10 | d | default value | +| test.py:59:5:59:5 | d | test.py:58:19:58:19 | d | test.py:59:5:59:5 | d | This expression mutates a $@. | test.py:58:19:58:19 | d | default value | +| test.py:64:5:64:5 | d | test.py:63:28:63:28 | d | test.py:64:5:64:5 | d | This expression mutates a $@. | test.py:63:28:63:28 | d | default value | +| test.py:68:5:68:5 | d | test.py:72:19:72:19 | d | test.py:68:5:68:5 | d | This expression mutates a $@. | test.py:72:19:72:19 | d | default value | +| test.py:78:5:78:5 | d | test.py:77:17:77:17 | d | test.py:78:5:78:5 | d | This expression mutates a $@. | test.py:77:17:77:17 | d | default value | +| test.py:83:5:83:5 | d | test.py:82:26:82:26 | d | test.py:83:5:83:5 | d | This expression mutates a $@. | test.py:82:26:82:26 | d | default value | +| test.py:88:5:88:5 | d | test.py:87:35:87:35 | d | test.py:88:5:88:5 | d | This expression mutates a $@. | test.py:87:35:87:35 | d | default value | +| test.py:92:5:92:5 | d | test.py:96:26:96:26 | d | test.py:92:5:92:5 | d | This expression mutates a $@. | test.py:96:26:96:26 | d | default value | +| test.py:109:9:109:9 | d | test.py:108:14:108:14 | d | test.py:109:9:109:9 | d | This expression mutates a $@. | test.py:108:14:108:14 | d | default value | +| test.py:115:5:115:5 | d | test.py:113:20:113:20 | d | test.py:115:5:115:5 | d | This expression mutates a $@. | test.py:113:20:113:20 | d | default value | +| test.py:121:5:121:5 | d | test.py:119:29:119:29 | d | test.py:121:5:121:5 | d | This expression mutates a $@. | test.py:119:29:119:29 | d | default value | +| test.py:128:9:128:9 | l | test.py:124:15:124:15 | l | test.py:128:9:128:9 | l | This expression mutates a $@. | test.py:124:15:124:15 | l | default value | +| test.py:135:9:135:9 | l | test.py:131:23:131:23 | l | test.py:135:9:135:9 | l | This expression mutates a $@. | test.py:131:23:131:23 | l | default value | +| test.py:140:9:140:9 | l | test.py:138:15:138:15 | l | test.py:140:9:140:9 | l | This expression mutates a $@. | test.py:138:15:138:15 | l | default value | +| test.py:147:9:147:9 | l | test.py:145:23:145:23 | l | test.py:147:9:147:9 | l | This expression mutates a $@. | test.py:145:23:145:23 | l | default value | +| test.py:154:5:154:5 | x | test.py:159:27:159:27 | y | test.py:154:5:154:5 | x | This expression mutates a $@. | test.py:159:27:159:27 | y | default value | +| test.py:157:5:157:5 | x | test.py:159:27:159:27 | y | test.py:157:5:157:5 | x | This expression mutates a $@. | test.py:159:27:159:27 | y | default value | +| test.py:185:9:185:9 | x | test.py:194:18:194:18 | x | test.py:185:9:185:9 | x | This expression mutates a $@. | test.py:194:18:194:18 | x | default value | +| test.py:185:9:185:9 | x | test.py:197:18:197:18 | x | test.py:185:9:185:9 | x | This expression mutates a $@. | test.py:197:18:197:18 | x | default value | +| test.py:187:9:187:9 | x | test.py:194:18:194:18 | x | test.py:187:9:187:9 | x | This expression mutates a $@. | test.py:194:18:194:18 | x | default value | +| test.py:187:9:187:9 | x | test.py:197:18:197:18 | x | test.py:187:9:187:9 | x | This expression mutates a $@. | test.py:197:18:197:18 | x | default value | diff --git a/python/ql/test/query-tests/Imports/deprecated/DeprecatedModule.expected b/python/ql/test/query-tests/Imports/deprecated/DeprecatedModule.expected index d379a896f20a..7a35d384d822 100644 --- a/python/ql/test/query-tests/Imports/deprecated/DeprecatedModule.expected +++ b/python/ql/test/query-tests/Imports/deprecated/DeprecatedModule.expected @@ -1,3 +1,4 @@ | test.py:2:8:2:13 | ImportExpr | The rfc822 module was deprecated in version 2.3. Use email module instead. | | test.py:3:8:3:16 | ImportExpr | The posixfile module was deprecated in version 1.5. Use fcntl module instead. | | test.py:8:16:8:18 | ImportExpr | The md5 module was deprecated in version 2.5. Use hashlib module instead. | +| test.py:14:10:14:12 | ImportExpr | The md5 module was deprecated in version 2.5. Use hashlib module instead. | diff --git a/python/ql/test/query-tests/Numerics/Pythagorean.expected b/python/ql/test/query-tests/Numerics/Pythagorean.expected index a289983af539..f2fb01bbb545 100644 --- a/python/ql/test/query-tests/Numerics/Pythagorean.expected +++ b/python/ql/test/query-tests/Numerics/Pythagorean.expected @@ -1,3 +1,3 @@ -| pythagorean_test.py:6:12:6:28 | ControlFlowNode for sqrt() | Pythagorean calculation with sub-optimal numerics. | -| pythagorean_test.py:9:12:9:26 | ControlFlowNode for sqrt() | Pythagorean calculation with sub-optimal numerics. | -| pythagorean_test.py:14:12:14:24 | ControlFlowNode for sqrt() | Pythagorean calculation with sub-optimal numerics. | +| pythagorean_test.py:6:12:6:28 | After sqrt() | Pythagorean calculation with sub-optimal numerics. | +| pythagorean_test.py:9:12:9:26 | After sqrt() | Pythagorean calculation with sub-optimal numerics. | +| pythagorean_test.py:14:12:14:24 | After sqrt() | Pythagorean calculation with sub-optimal numerics. | diff --git a/python/ql/test/query-tests/Resources/FileNotAlwaysClosed/FileNotAlwaysClosed.expected b/python/ql/test/query-tests/Resources/FileNotAlwaysClosed/FileNotAlwaysClosed.expected index b7d9d37785b0..8bd14d88aa33 100644 --- a/python/ql/test/query-tests/Resources/FileNotAlwaysClosed/FileNotAlwaysClosed.expected +++ b/python/ql/test/query-tests/Resources/FileNotAlwaysClosed/FileNotAlwaysClosed.expected @@ -1,9 +1,9 @@ -| resources_test.py:6:10:6:25 | ControlFlowNode for open() | File may not be closed if $@ raises an exception. | resources_test.py:7:5:7:33 | ControlFlowNode for Attribute() | this operation | -| resources_test.py:11:10:11:25 | ControlFlowNode for open() | File is opened but is not closed. | file://:0:0:0:0 | (none) | this operation | -| resources_test.py:110:11:110:20 | ControlFlowNode for open() | File is opened but is not closed. | file://:0:0:0:0 | (none) | this operation | -| resources_test.py:114:11:114:28 | ControlFlowNode for opener_func2() | File may not be closed if $@ raises an exception. | resources_test.py:115:5:115:22 | ControlFlowNode for Attribute() | this operation | -| resources_test.py:125:11:125:24 | ControlFlowNode for opener_func2() | File is opened but is not closed. | file://:0:0:0:0 | (none) | this operation | -| resources_test.py:131:15:131:24 | ControlFlowNode for open() | File may not be closed if $@ raises an exception. | resources_test.py:132:9:132:26 | ControlFlowNode for Attribute() | this operation | -| resources_test.py:250:11:250:25 | ControlFlowNode for open() | File is opened but is not closed. | file://:0:0:0:0 | (none) | this operation | -| resources_test.py:271:10:271:27 | ControlFlowNode for Attribute() | File may not be closed if $@ raises an exception. | resources_test.py:273:5:273:19 | ControlFlowNode for Attribute() | this operation | -| resources_test.py:287:11:287:20 | ControlFlowNode for open() | File may not be closed if $@ raises an exception. | resources_test.py:289:5:289:31 | ControlFlowNode for Attribute() | this operation | +| resources_test.py:4:10:4:25 | After open() | File may not be closed if $@ raises an exception. | resources_test.py:5:5:5:33 | After Attribute() | this operation | +| resources_test.py:9:10:9:25 | After open() | File is opened but is not closed. | file://:0:0:0:0 | (none) | this operation | +| resources_test.py:108:11:108:20 | After open() | File is opened but is not closed. | file://:0:0:0:0 | (none) | this operation | +| resources_test.py:112:11:112:28 | After opener_func2() | File may not be closed if $@ raises an exception. | resources_test.py:113:5:113:22 | After Attribute() | this operation | +| resources_test.py:123:11:123:24 | After opener_func2() | File is opened but is not closed. | file://:0:0:0:0 | (none) | this operation | +| resources_test.py:129:15:129:24 | After open() | File may not be closed if $@ raises an exception. | resources_test.py:130:9:130:26 | After Attribute() | this operation | +| resources_test.py:248:11:248:25 | After open() | File is opened but is not closed. | file://:0:0:0:0 | (none) | this operation | +| resources_test.py:269:10:269:27 | After Attribute() | File may not be closed if $@ raises an exception. | resources_test.py:271:5:271:19 | After Attribute() | this operation | +| resources_test.py:285:11:285:20 | After open() | File may not be closed if $@ raises an exception. | resources_test.py:287:5:287:31 | After Attribute() | this operation | diff --git a/python/ql/test/query-tests/Resources/FileNotAlwaysClosed/resources_test.py b/python/ql/test/query-tests/Resources/FileNotAlwaysClosed/resources_test.py index 57568a6eb118..34015d6ca93a 100644 --- a/python/ql/test/query-tests/Resources/FileNotAlwaysClosed/resources_test.py +++ b/python/ql/test/query-tests/Resources/FileNotAlwaysClosed/resources_test.py @@ -48,7 +48,7 @@ def closed7(): def not_closed8(): f8 = None try: - f8 = open("filename") # $ MISSING:Alert # not closed on exception + f8 = open("filename") # $ MISSING:Alert # not closed on exception (FileNotAlwaysClosed is optimistic about exception-flow close paths through buggy guards) f8.write("Error could occur") finally: if f8 is None: # We don't precisely consider this condition, so this result is MISSING. However, this seems uncommon. @@ -140,7 +140,7 @@ def may_raise(): #Not handling all exceptions, but we'll tolerate the false negative def not_closed17(): - f17 = open("filename") # $ MISSING:Alert # not closed on exception + f17 = open("filename") # $ MISSING:Alert # not closed on exception (FileNotAlwaysClosed is optimistic about exception-flow close paths through buggy guards) try: f17.write("IOError could occur") f17.write("IOError could occur") @@ -236,7 +236,7 @@ def closed21(path): def not_closed22(path): - f22 = open(path, "wb") # $ MISSING:Alert # not closed on exception + f22 = open(path, "wb") # $ MISSING:Alert # not closed on exception (FileNotAlwaysClosed is optimistic about exception-flow close paths through buggy guards) try: f22.write(b"foo") may_raise() diff --git a/python/ql/test/query-tests/Security/CVE-2018-1281/BindToAllInterfaces.expected b/python/ql/test/query-tests/Security/CVE-2018-1281/BindToAllInterfaces.expected index c478fe78fd77..418e969391db 100644 --- a/python/ql/test/query-tests/Security/CVE-2018-1281/BindToAllInterfaces.expected +++ b/python/ql/test/query-tests/Security/CVE-2018-1281/BindToAllInterfaces.expected @@ -1,71 +1,63 @@ #select -| BindToAllInterfaces_test.py:5:9:5:24 | ControlFlowNode for Tuple | BindToAllInterfaces_test.py:5:9:5:17 | ControlFlowNode for StringLiteral | BindToAllInterfaces_test.py:5:9:5:24 | ControlFlowNode for Tuple | Binding a socket to all interfaces (using $@) is a security risk. | BindToAllInterfaces_test.py:5:9:5:17 | ControlFlowNode for StringLiteral | '0.0.0.0' | -| BindToAllInterfaces_test.py:9:9:9:16 | ControlFlowNode for Tuple | BindToAllInterfaces_test.py:9:9:9:10 | ControlFlowNode for StringLiteral | BindToAllInterfaces_test.py:9:9:9:16 | ControlFlowNode for Tuple | Binding a socket to all interfaces (using $@) is a security risk. | BindToAllInterfaces_test.py:9:9:9:10 | ControlFlowNode for StringLiteral | '' | -| BindToAllInterfaces_test.py:17:9:17:24 | ControlFlowNode for Tuple | BindToAllInterfaces_test.py:16:14:16:22 | ControlFlowNode for StringLiteral | BindToAllInterfaces_test.py:17:9:17:24 | ControlFlowNode for Tuple | Binding a socket to all interfaces (using $@) is a security risk. | BindToAllInterfaces_test.py:16:14:16:22 | ControlFlowNode for StringLiteral | '0.0.0.0' | -| BindToAllInterfaces_test.py:21:8:21:10 | ControlFlowNode for tup | BindToAllInterfaces_test.py:16:14:16:22 | ControlFlowNode for StringLiteral | BindToAllInterfaces_test.py:21:8:21:10 | ControlFlowNode for tup | Binding a socket to all interfaces (using $@) is a security risk. | BindToAllInterfaces_test.py:16:14:16:22 | ControlFlowNode for StringLiteral | '0.0.0.0' | -| BindToAllInterfaces_test.py:26:9:26:18 | ControlFlowNode for Tuple | BindToAllInterfaces_test.py:26:9:26:12 | ControlFlowNode for StringLiteral | BindToAllInterfaces_test.py:26:9:26:18 | ControlFlowNode for Tuple | Binding a socket to all interfaces (using $@) is a security risk. | BindToAllInterfaces_test.py:26:9:26:12 | ControlFlowNode for StringLiteral | '::' | -| BindToAllInterfaces_test.py:39:17:39:41 | ControlFlowNode for Tuple | BindToAllInterfaces_test.py:34:26:34:34 | ControlFlowNode for StringLiteral | BindToAllInterfaces_test.py:39:17:39:41 | ControlFlowNode for Tuple | Binding a socket to all interfaces (using $@) is a security risk. | BindToAllInterfaces_test.py:34:26:34:34 | ControlFlowNode for StringLiteral | '0.0.0.0' | -| BindToAllInterfaces_test.py:48:9:48:18 | ControlFlowNode for Tuple | BindToAllInterfaces_test.py:46:35:46:43 | ControlFlowNode for StringLiteral | BindToAllInterfaces_test.py:48:9:48:18 | ControlFlowNode for Tuple | Binding a socket to all interfaces (using $@) is a security risk. | BindToAllInterfaces_test.py:46:35:46:43 | ControlFlowNode for StringLiteral | '0.0.0.0' | -| BindToAllInterfaces_test.py:53:10:53:25 | ControlFlowNode for Tuple | BindToAllInterfaces_test.py:53:10:53:18 | ControlFlowNode for StringLiteral | BindToAllInterfaces_test.py:53:10:53:25 | ControlFlowNode for Tuple | Binding a socket to all interfaces (using $@) is a security risk. | BindToAllInterfaces_test.py:53:10:53:18 | ControlFlowNode for StringLiteral | '0.0.0.0' | -| BindToAllInterfaces_test.py:58:10:58:25 | ControlFlowNode for Tuple | BindToAllInterfaces_test.py:58:10:58:18 | ControlFlowNode for StringLiteral | BindToAllInterfaces_test.py:58:10:58:25 | ControlFlowNode for Tuple | Binding a socket to all interfaces (using $@) is a security risk. | BindToAllInterfaces_test.py:58:10:58:18 | ControlFlowNode for StringLiteral | '0.0.0.0' | +| BindToAllInterfaces_test.py:5:9:5:24 | After Tuple | BindToAllInterfaces_test.py:5:9:5:17 | StringLiteral | BindToAllInterfaces_test.py:5:9:5:24 | After Tuple | Binding a socket to all interfaces (using $@) is a security risk. | BindToAllInterfaces_test.py:5:9:5:17 | StringLiteral | '0.0.0.0' | +| BindToAllInterfaces_test.py:9:9:9:16 | After Tuple | BindToAllInterfaces_test.py:9:9:9:10 | StringLiteral | BindToAllInterfaces_test.py:9:9:9:16 | After Tuple | Binding a socket to all interfaces (using $@) is a security risk. | BindToAllInterfaces_test.py:9:9:9:10 | StringLiteral | '' | +| BindToAllInterfaces_test.py:17:9:17:24 | After Tuple | BindToAllInterfaces_test.py:16:14:16:22 | StringLiteral | BindToAllInterfaces_test.py:17:9:17:24 | After Tuple | Binding a socket to all interfaces (using $@) is a security risk. | BindToAllInterfaces_test.py:16:14:16:22 | StringLiteral | '0.0.0.0' | +| BindToAllInterfaces_test.py:21:8:21:10 | tup | BindToAllInterfaces_test.py:16:14:16:22 | StringLiteral | BindToAllInterfaces_test.py:21:8:21:10 | tup | Binding a socket to all interfaces (using $@) is a security risk. | BindToAllInterfaces_test.py:16:14:16:22 | StringLiteral | '0.0.0.0' | +| BindToAllInterfaces_test.py:26:9:26:18 | After Tuple | BindToAllInterfaces_test.py:26:9:26:12 | StringLiteral | BindToAllInterfaces_test.py:26:9:26:18 | After Tuple | Binding a socket to all interfaces (using $@) is a security risk. | BindToAllInterfaces_test.py:26:9:26:12 | StringLiteral | '::' | +| BindToAllInterfaces_test.py:39:17:39:41 | After Tuple | BindToAllInterfaces_test.py:34:26:34:34 | StringLiteral | BindToAllInterfaces_test.py:39:17:39:41 | After Tuple | Binding a socket to all interfaces (using $@) is a security risk. | BindToAllInterfaces_test.py:34:26:34:34 | StringLiteral | '0.0.0.0' | +| BindToAllInterfaces_test.py:48:9:48:18 | After Tuple | BindToAllInterfaces_test.py:46:35:46:43 | StringLiteral | BindToAllInterfaces_test.py:48:9:48:18 | After Tuple | Binding a socket to all interfaces (using $@) is a security risk. | BindToAllInterfaces_test.py:46:35:46:43 | StringLiteral | '0.0.0.0' | +| BindToAllInterfaces_test.py:53:10:53:25 | After Tuple | BindToAllInterfaces_test.py:53:10:53:18 | StringLiteral | BindToAllInterfaces_test.py:53:10:53:25 | After Tuple | Binding a socket to all interfaces (using $@) is a security risk. | BindToAllInterfaces_test.py:53:10:53:18 | StringLiteral | '0.0.0.0' | +| BindToAllInterfaces_test.py:58:10:58:25 | After Tuple | BindToAllInterfaces_test.py:58:10:58:18 | StringLiteral | BindToAllInterfaces_test.py:58:10:58:25 | After Tuple | Binding a socket to all interfaces (using $@) is a security risk. | BindToAllInterfaces_test.py:58:10:58:18 | StringLiteral | '0.0.0.0' | edges -| BindToAllInterfaces_test.py:5:9:5:17 | ControlFlowNode for StringLiteral | BindToAllInterfaces_test.py:5:9:5:24 | ControlFlowNode for Tuple | provenance | Sink:MaD:63 | -| BindToAllInterfaces_test.py:9:9:9:10 | ControlFlowNode for StringLiteral | BindToAllInterfaces_test.py:9:9:9:16 | ControlFlowNode for Tuple | provenance | Sink:MaD:63 | -| BindToAllInterfaces_test.py:16:1:16:10 | ControlFlowNode for ALL_LOCALS | BindToAllInterfaces_test.py:17:9:17:18 | ControlFlowNode for ALL_LOCALS | provenance | | -| BindToAllInterfaces_test.py:16:1:16:10 | ControlFlowNode for ALL_LOCALS | BindToAllInterfaces_test.py:20:8:20:17 | ControlFlowNode for ALL_LOCALS | provenance | | -| BindToAllInterfaces_test.py:16:14:16:22 | ControlFlowNode for StringLiteral | BindToAllInterfaces_test.py:16:1:16:10 | ControlFlowNode for ALL_LOCALS | provenance | | -| BindToAllInterfaces_test.py:17:9:17:18 | ControlFlowNode for ALL_LOCALS | BindToAllInterfaces_test.py:17:9:17:24 | ControlFlowNode for Tuple | provenance | Sink:MaD:63 | -| BindToAllInterfaces_test.py:20:1:20:3 | ControlFlowNode for tup [Tuple element at index 0] | BindToAllInterfaces_test.py:21:8:21:10 | ControlFlowNode for tup | provenance | Sink:MaD:63 | -| BindToAllInterfaces_test.py:20:8:20:17 | ControlFlowNode for ALL_LOCALS | BindToAllInterfaces_test.py:20:8:20:23 | ControlFlowNode for Tuple [Tuple element at index 0] | provenance | | -| BindToAllInterfaces_test.py:20:8:20:23 | ControlFlowNode for Tuple [Tuple element at index 0] | BindToAllInterfaces_test.py:20:1:20:3 | ControlFlowNode for tup [Tuple element at index 0] | provenance | | -| BindToAllInterfaces_test.py:26:9:26:12 | ControlFlowNode for StringLiteral | BindToAllInterfaces_test.py:26:9:26:18 | ControlFlowNode for Tuple | provenance | Sink:MaD:63 | -| BindToAllInterfaces_test.py:33:18:33:21 | ControlFlowNode for self [Return] [Attribute bind_addr] | BindToAllInterfaces_test.py:41:10:41:17 | ControlFlowNode for Server() [Attribute bind_addr] | provenance | | -| BindToAllInterfaces_test.py:34:9:34:12 | [post] ControlFlowNode for self [Attribute bind_addr] | BindToAllInterfaces_test.py:33:18:33:21 | ControlFlowNode for self [Return] [Attribute bind_addr] | provenance | | -| BindToAllInterfaces_test.py:34:26:34:34 | ControlFlowNode for StringLiteral | BindToAllInterfaces_test.py:34:9:34:12 | [post] ControlFlowNode for self [Attribute bind_addr] | provenance | | -| BindToAllInterfaces_test.py:37:15:37:18 | ControlFlowNode for self [Attribute bind_addr] | BindToAllInterfaces_test.py:39:17:39:20 | ControlFlowNode for self [Attribute bind_addr] | provenance | | -| BindToAllInterfaces_test.py:39:17:39:20 | ControlFlowNode for self [Attribute bind_addr] | BindToAllInterfaces_test.py:39:17:39:30 | ControlFlowNode for Attribute | provenance | | -| BindToAllInterfaces_test.py:39:17:39:30 | ControlFlowNode for Attribute | BindToAllInterfaces_test.py:39:17:39:41 | ControlFlowNode for Tuple | provenance | Sink:MaD:63 | -| BindToAllInterfaces_test.py:41:1:41:6 | ControlFlowNode for server [Attribute bind_addr] | BindToAllInterfaces_test.py:42:1:42:6 | ControlFlowNode for server [Attribute bind_addr] | provenance | | -| BindToAllInterfaces_test.py:41:10:41:17 | ControlFlowNode for Server() [Attribute bind_addr] | BindToAllInterfaces_test.py:41:1:41:6 | ControlFlowNode for server [Attribute bind_addr] | provenance | | -| BindToAllInterfaces_test.py:42:1:42:6 | ControlFlowNode for server [Attribute bind_addr] | BindToAllInterfaces_test.py:37:15:37:18 | ControlFlowNode for self [Attribute bind_addr] | provenance | | -| BindToAllInterfaces_test.py:46:1:46:4 | ControlFlowNode for host | BindToAllInterfaces_test.py:48:9:48:12 | ControlFlowNode for host | provenance | | -| BindToAllInterfaces_test.py:46:8:46:44 | ControlFlowNode for Attribute() | BindToAllInterfaces_test.py:46:1:46:4 | ControlFlowNode for host | provenance | | -| BindToAllInterfaces_test.py:46:35:46:43 | ControlFlowNode for StringLiteral | BindToAllInterfaces_test.py:46:8:46:44 | ControlFlowNode for Attribute() | provenance | dict.get | -| BindToAllInterfaces_test.py:48:9:48:12 | ControlFlowNode for host | BindToAllInterfaces_test.py:48:9:48:18 | ControlFlowNode for Tuple | provenance | Sink:MaD:63 | -| BindToAllInterfaces_test.py:53:10:53:18 | ControlFlowNode for StringLiteral | BindToAllInterfaces_test.py:53:10:53:25 | ControlFlowNode for Tuple | provenance | Sink:MaD:63 | -| BindToAllInterfaces_test.py:58:10:58:18 | ControlFlowNode for StringLiteral | BindToAllInterfaces_test.py:58:10:58:25 | ControlFlowNode for Tuple | provenance | Sink:MaD:63 | +| BindToAllInterfaces_test.py:5:9:5:17 | StringLiteral | BindToAllInterfaces_test.py:5:9:5:24 | After Tuple | provenance | Sink:MaD:63 | +| BindToAllInterfaces_test.py:9:9:9:10 | StringLiteral | BindToAllInterfaces_test.py:9:9:9:16 | After Tuple | provenance | Sink:MaD:63 | +| BindToAllInterfaces_test.py:16:1:16:10 | ALL_LOCALS | BindToAllInterfaces_test.py:17:9:17:24 | After Tuple | provenance | Sink:MaD:63 | +| BindToAllInterfaces_test.py:16:1:16:10 | ALL_LOCALS | BindToAllInterfaces_test.py:20:1:20:3 | tup | provenance | | +| BindToAllInterfaces_test.py:16:14:16:22 | StringLiteral | BindToAllInterfaces_test.py:16:1:16:10 | ALL_LOCALS | provenance | | +| BindToAllInterfaces_test.py:20:1:20:3 | tup | BindToAllInterfaces_test.py:21:8:21:10 | tup | provenance | Sink:MaD:63 | +| BindToAllInterfaces_test.py:26:9:26:12 | StringLiteral | BindToAllInterfaces_test.py:26:9:26:18 | After Tuple | provenance | Sink:MaD:63 | +| BindToAllInterfaces_test.py:33:18:33:21 | self [Return] [Attribute bind_addr] | BindToAllInterfaces_test.py:41:10:41:17 | After Server() [Attribute bind_addr] | provenance | | +| BindToAllInterfaces_test.py:34:9:34:12 | [post] self [Attribute bind_addr] | BindToAllInterfaces_test.py:33:18:33:21 | self [Return] [Attribute bind_addr] | provenance | | +| BindToAllInterfaces_test.py:34:26:34:34 | StringLiteral | BindToAllInterfaces_test.py:34:9:34:12 | [post] self [Attribute bind_addr] | provenance | | +| BindToAllInterfaces_test.py:37:15:37:18 | self [Attribute bind_addr] | BindToAllInterfaces_test.py:39:17:39:20 | self [Attribute bind_addr] | provenance | | +| BindToAllInterfaces_test.py:39:17:39:20 | self [Attribute bind_addr] | BindToAllInterfaces_test.py:39:17:39:30 | After Attribute | provenance | | +| BindToAllInterfaces_test.py:39:17:39:30 | After Attribute | BindToAllInterfaces_test.py:39:17:39:41 | After Tuple | provenance | Sink:MaD:63 | +| BindToAllInterfaces_test.py:41:1:41:6 | server [Attribute bind_addr] | BindToAllInterfaces_test.py:42:1:42:6 | server [Attribute bind_addr] | provenance | | +| BindToAllInterfaces_test.py:41:10:41:17 | After Server() [Attribute bind_addr] | BindToAllInterfaces_test.py:41:1:41:6 | server [Attribute bind_addr] | provenance | | +| BindToAllInterfaces_test.py:42:1:42:6 | server [Attribute bind_addr] | BindToAllInterfaces_test.py:37:15:37:18 | self [Attribute bind_addr] | provenance | | +| BindToAllInterfaces_test.py:46:1:46:4 | host | BindToAllInterfaces_test.py:48:9:48:18 | After Tuple | provenance | Sink:MaD:63 | +| BindToAllInterfaces_test.py:46:8:46:44 | After Attribute() | BindToAllInterfaces_test.py:46:1:46:4 | host | provenance | | +| BindToAllInterfaces_test.py:46:35:46:43 | StringLiteral | BindToAllInterfaces_test.py:46:8:46:44 | After Attribute() | provenance | dict.get | +| BindToAllInterfaces_test.py:53:10:53:18 | StringLiteral | BindToAllInterfaces_test.py:53:10:53:25 | After Tuple | provenance | Sink:MaD:63 | +| BindToAllInterfaces_test.py:58:10:58:18 | StringLiteral | BindToAllInterfaces_test.py:58:10:58:25 | After Tuple | provenance | Sink:MaD:63 | nodes -| BindToAllInterfaces_test.py:5:9:5:17 | ControlFlowNode for StringLiteral | semmle.label | ControlFlowNode for StringLiteral | -| BindToAllInterfaces_test.py:5:9:5:24 | ControlFlowNode for Tuple | semmle.label | ControlFlowNode for Tuple | -| BindToAllInterfaces_test.py:9:9:9:10 | ControlFlowNode for StringLiteral | semmle.label | ControlFlowNode for StringLiteral | -| BindToAllInterfaces_test.py:9:9:9:16 | ControlFlowNode for Tuple | semmle.label | ControlFlowNode for Tuple | -| BindToAllInterfaces_test.py:16:1:16:10 | ControlFlowNode for ALL_LOCALS | semmle.label | ControlFlowNode for ALL_LOCALS | -| BindToAllInterfaces_test.py:16:14:16:22 | ControlFlowNode for StringLiteral | semmle.label | ControlFlowNode for StringLiteral | -| BindToAllInterfaces_test.py:17:9:17:18 | ControlFlowNode for ALL_LOCALS | semmle.label | ControlFlowNode for ALL_LOCALS | -| BindToAllInterfaces_test.py:17:9:17:24 | ControlFlowNode for Tuple | semmle.label | ControlFlowNode for Tuple | -| BindToAllInterfaces_test.py:20:1:20:3 | ControlFlowNode for tup [Tuple element at index 0] | semmle.label | ControlFlowNode for tup [Tuple element at index 0] | -| BindToAllInterfaces_test.py:20:8:20:17 | ControlFlowNode for ALL_LOCALS | semmle.label | ControlFlowNode for ALL_LOCALS | -| BindToAllInterfaces_test.py:20:8:20:23 | ControlFlowNode for Tuple [Tuple element at index 0] | semmle.label | ControlFlowNode for Tuple [Tuple element at index 0] | -| BindToAllInterfaces_test.py:21:8:21:10 | ControlFlowNode for tup | semmle.label | ControlFlowNode for tup | -| BindToAllInterfaces_test.py:26:9:26:12 | ControlFlowNode for StringLiteral | semmle.label | ControlFlowNode for StringLiteral | -| BindToAllInterfaces_test.py:26:9:26:18 | ControlFlowNode for Tuple | semmle.label | ControlFlowNode for Tuple | -| BindToAllInterfaces_test.py:33:18:33:21 | ControlFlowNode for self [Return] [Attribute bind_addr] | semmle.label | ControlFlowNode for self [Return] [Attribute bind_addr] | -| BindToAllInterfaces_test.py:34:9:34:12 | [post] ControlFlowNode for self [Attribute bind_addr] | semmle.label | [post] ControlFlowNode for self [Attribute bind_addr] | -| BindToAllInterfaces_test.py:34:26:34:34 | ControlFlowNode for StringLiteral | semmle.label | ControlFlowNode for StringLiteral | -| BindToAllInterfaces_test.py:37:15:37:18 | ControlFlowNode for self [Attribute bind_addr] | semmle.label | ControlFlowNode for self [Attribute bind_addr] | -| BindToAllInterfaces_test.py:39:17:39:20 | ControlFlowNode for self [Attribute bind_addr] | semmle.label | ControlFlowNode for self [Attribute bind_addr] | -| BindToAllInterfaces_test.py:39:17:39:30 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| BindToAllInterfaces_test.py:39:17:39:41 | ControlFlowNode for Tuple | semmle.label | ControlFlowNode for Tuple | -| BindToAllInterfaces_test.py:41:1:41:6 | ControlFlowNode for server [Attribute bind_addr] | semmle.label | ControlFlowNode for server [Attribute bind_addr] | -| BindToAllInterfaces_test.py:41:10:41:17 | ControlFlowNode for Server() [Attribute bind_addr] | semmle.label | ControlFlowNode for Server() [Attribute bind_addr] | -| BindToAllInterfaces_test.py:42:1:42:6 | ControlFlowNode for server [Attribute bind_addr] | semmle.label | ControlFlowNode for server [Attribute bind_addr] | -| BindToAllInterfaces_test.py:46:1:46:4 | ControlFlowNode for host | semmle.label | ControlFlowNode for host | -| BindToAllInterfaces_test.py:46:8:46:44 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| BindToAllInterfaces_test.py:46:35:46:43 | ControlFlowNode for StringLiteral | semmle.label | ControlFlowNode for StringLiteral | -| BindToAllInterfaces_test.py:48:9:48:12 | ControlFlowNode for host | semmle.label | ControlFlowNode for host | -| BindToAllInterfaces_test.py:48:9:48:18 | ControlFlowNode for Tuple | semmle.label | ControlFlowNode for Tuple | -| BindToAllInterfaces_test.py:53:10:53:18 | ControlFlowNode for StringLiteral | semmle.label | ControlFlowNode for StringLiteral | -| BindToAllInterfaces_test.py:53:10:53:25 | ControlFlowNode for Tuple | semmle.label | ControlFlowNode for Tuple | -| BindToAllInterfaces_test.py:58:10:58:18 | ControlFlowNode for StringLiteral | semmle.label | ControlFlowNode for StringLiteral | -| BindToAllInterfaces_test.py:58:10:58:25 | ControlFlowNode for Tuple | semmle.label | ControlFlowNode for Tuple | +| BindToAllInterfaces_test.py:5:9:5:17 | StringLiteral | semmle.label | StringLiteral | +| BindToAllInterfaces_test.py:5:9:5:24 | After Tuple | semmle.label | After Tuple | +| BindToAllInterfaces_test.py:9:9:9:10 | StringLiteral | semmle.label | StringLiteral | +| BindToAllInterfaces_test.py:9:9:9:16 | After Tuple | semmle.label | After Tuple | +| BindToAllInterfaces_test.py:16:1:16:10 | ALL_LOCALS | semmle.label | ALL_LOCALS | +| BindToAllInterfaces_test.py:16:14:16:22 | StringLiteral | semmle.label | StringLiteral | +| BindToAllInterfaces_test.py:17:9:17:24 | After Tuple | semmle.label | After Tuple | +| BindToAllInterfaces_test.py:20:1:20:3 | tup | semmle.label | tup | +| BindToAllInterfaces_test.py:21:8:21:10 | tup | semmle.label | tup | +| BindToAllInterfaces_test.py:26:9:26:12 | StringLiteral | semmle.label | StringLiteral | +| BindToAllInterfaces_test.py:26:9:26:18 | After Tuple | semmle.label | After Tuple | +| BindToAllInterfaces_test.py:33:18:33:21 | self [Return] [Attribute bind_addr] | semmle.label | self [Return] [Attribute bind_addr] | +| BindToAllInterfaces_test.py:34:9:34:12 | [post] self [Attribute bind_addr] | semmle.label | [post] self [Attribute bind_addr] | +| BindToAllInterfaces_test.py:34:26:34:34 | StringLiteral | semmle.label | StringLiteral | +| BindToAllInterfaces_test.py:37:15:37:18 | self [Attribute bind_addr] | semmle.label | self [Attribute bind_addr] | +| BindToAllInterfaces_test.py:39:17:39:20 | self [Attribute bind_addr] | semmle.label | self [Attribute bind_addr] | +| BindToAllInterfaces_test.py:39:17:39:30 | After Attribute | semmle.label | After Attribute | +| BindToAllInterfaces_test.py:39:17:39:41 | After Tuple | semmle.label | After Tuple | +| BindToAllInterfaces_test.py:41:1:41:6 | server [Attribute bind_addr] | semmle.label | server [Attribute bind_addr] | +| BindToAllInterfaces_test.py:41:10:41:17 | After Server() [Attribute bind_addr] | semmle.label | After Server() [Attribute bind_addr] | +| BindToAllInterfaces_test.py:42:1:42:6 | server [Attribute bind_addr] | semmle.label | server [Attribute bind_addr] | +| BindToAllInterfaces_test.py:46:1:46:4 | host | semmle.label | host | +| BindToAllInterfaces_test.py:46:8:46:44 | After Attribute() | semmle.label | After Attribute() | +| BindToAllInterfaces_test.py:46:35:46:43 | StringLiteral | semmle.label | StringLiteral | +| BindToAllInterfaces_test.py:48:9:48:18 | After Tuple | semmle.label | After Tuple | +| BindToAllInterfaces_test.py:53:10:53:18 | StringLiteral | semmle.label | StringLiteral | +| BindToAllInterfaces_test.py:53:10:53:25 | After Tuple | semmle.label | After Tuple | +| BindToAllInterfaces_test.py:58:10:58:18 | StringLiteral | semmle.label | StringLiteral | +| BindToAllInterfaces_test.py:58:10:58:25 | After Tuple | semmle.label | After Tuple | subpaths diff --git a/python/ql/test/query-tests/Security/CWE-020-CookieInjection/CookieInjection.expected b/python/ql/test/query-tests/Security/CWE-020-CookieInjection/CookieInjection.expected index 6e9c8ff47dc8..f5a3607f0475 100644 --- a/python/ql/test/query-tests/Security/CWE-020-CookieInjection/CookieInjection.expected +++ b/python/ql/test/query-tests/Security/CWE-020-CookieInjection/CookieInjection.expected @@ -1,28 +1,28 @@ -#select -| django_tests.py:6:21:6:43 | ControlFlowNode for Attribute() | django_tests.py:4:25:4:31 | ControlFlowNode for request | django_tests.py:6:21:6:43 | ControlFlowNode for Attribute() | Cookie is constructed from a $@. | django_tests.py:4:25:4:31 | ControlFlowNode for request | user-supplied input | -| django_tests.py:7:21:7:44 | ControlFlowNode for Attribute() | django_tests.py:4:25:4:31 | ControlFlowNode for request | django_tests.py:7:21:7:44 | ControlFlowNode for Attribute() | Cookie is constructed from a $@. | django_tests.py:4:25:4:31 | ControlFlowNode for request | user-supplied input | -| django_tests.py:13:30:13:100 | ControlFlowNode for Fstring | django_tests.py:11:26:11:32 | ControlFlowNode for request | django_tests.py:13:30:13:100 | ControlFlowNode for Fstring | Cookie is constructed from a $@. | django_tests.py:11:26:11:32 | ControlFlowNode for request | user-supplied input | edges -| django_tests.py:4:25:4:31 | ControlFlowNode for request | django_tests.py:6:21:6:31 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | -| django_tests.py:4:25:4:31 | ControlFlowNode for request | django_tests.py:7:21:7:31 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | -| django_tests.py:6:21:6:31 | ControlFlowNode for Attribute | django_tests.py:6:21:6:43 | ControlFlowNode for Attribute() | provenance | dict.get | -| django_tests.py:7:21:7:31 | ControlFlowNode for Attribute | django_tests.py:7:21:7:44 | ControlFlowNode for Attribute() | provenance | dict.get | -| django_tests.py:11:26:11:32 | ControlFlowNode for request | django_tests.py:13:33:13:43 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | -| django_tests.py:11:26:11:32 | ControlFlowNode for request | django_tests.py:13:59:13:69 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | -| django_tests.py:13:33:13:43 | ControlFlowNode for Attribute | django_tests.py:13:33:13:55 | ControlFlowNode for Attribute() | provenance | dict.get | -| django_tests.py:13:33:13:55 | ControlFlowNode for Attribute() | django_tests.py:13:30:13:100 | ControlFlowNode for Fstring | provenance | | -| django_tests.py:13:59:13:69 | ControlFlowNode for Attribute | django_tests.py:13:59:13:82 | ControlFlowNode for Attribute() | provenance | dict.get | -| django_tests.py:13:59:13:82 | ControlFlowNode for Attribute() | django_tests.py:13:30:13:100 | ControlFlowNode for Fstring | provenance | | +| django_tests.py:4:25:4:31 | request | django_tests.py:6:21:6:31 | After Attribute | provenance | AdditionalTaintStep | +| django_tests.py:4:25:4:31 | request | django_tests.py:7:21:7:31 | After Attribute | provenance | AdditionalTaintStep | +| django_tests.py:6:21:6:31 | After Attribute | django_tests.py:6:21:6:43 | After Attribute() | provenance | dict.get | +| django_tests.py:7:21:7:31 | After Attribute | django_tests.py:7:21:7:44 | After Attribute() | provenance | dict.get | +| django_tests.py:11:26:11:32 | request | django_tests.py:13:33:13:43 | After Attribute | provenance | AdditionalTaintStep | +| django_tests.py:11:26:11:32 | request | django_tests.py:13:59:13:69 | After Attribute | provenance | AdditionalTaintStep | +| django_tests.py:13:33:13:43 | After Attribute | django_tests.py:13:33:13:55 | After Attribute() | provenance | dict.get | +| django_tests.py:13:33:13:55 | After Attribute() | django_tests.py:13:30:13:100 | After Fstring | provenance | | +| django_tests.py:13:59:13:69 | After Attribute | django_tests.py:13:59:13:82 | After Attribute() | provenance | dict.get | +| django_tests.py:13:59:13:82 | After Attribute() | django_tests.py:13:30:13:100 | After Fstring | provenance | | nodes -| django_tests.py:4:25:4:31 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| django_tests.py:6:21:6:31 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| django_tests.py:6:21:6:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| django_tests.py:7:21:7:31 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| django_tests.py:7:21:7:44 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| django_tests.py:11:26:11:32 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| django_tests.py:13:30:13:100 | ControlFlowNode for Fstring | semmle.label | ControlFlowNode for Fstring | -| django_tests.py:13:33:13:43 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| django_tests.py:13:33:13:55 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| django_tests.py:13:59:13:69 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| django_tests.py:13:59:13:82 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | +| django_tests.py:4:25:4:31 | request | semmle.label | request | +| django_tests.py:6:21:6:31 | After Attribute | semmle.label | After Attribute | +| django_tests.py:6:21:6:43 | After Attribute() | semmle.label | After Attribute() | +| django_tests.py:7:21:7:31 | After Attribute | semmle.label | After Attribute | +| django_tests.py:7:21:7:44 | After Attribute() | semmle.label | After Attribute() | +| django_tests.py:11:26:11:32 | request | semmle.label | request | +| django_tests.py:13:30:13:100 | After Fstring | semmle.label | After Fstring | +| django_tests.py:13:33:13:43 | After Attribute | semmle.label | After Attribute | +| django_tests.py:13:33:13:55 | After Attribute() | semmle.label | After Attribute() | +| django_tests.py:13:59:13:69 | After Attribute | semmle.label | After Attribute | +| django_tests.py:13:59:13:82 | After Attribute() | semmle.label | After Attribute() | subpaths +#select +| django_tests.py:6:21:6:43 | After Attribute() | django_tests.py:4:25:4:31 | request | django_tests.py:6:21:6:43 | After Attribute() | Cookie is constructed from a $@. | django_tests.py:4:25:4:31 | request | user-supplied input | +| django_tests.py:7:21:7:44 | After Attribute() | django_tests.py:4:25:4:31 | request | django_tests.py:7:21:7:44 | After Attribute() | Cookie is constructed from a $@. | django_tests.py:4:25:4:31 | request | user-supplied input | +| django_tests.py:13:30:13:100 | After Fstring | django_tests.py:11:26:11:32 | request | django_tests.py:13:30:13:100 | After Fstring | Cookie is constructed from a $@. | django_tests.py:11:26:11:32 | request | user-supplied input | diff --git a/python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/UntrustedDataToExternalAPI.expected b/python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/UntrustedDataToExternalAPI.expected index 7f83ceae8fe0..bfa1ee5b7d9d 100644 --- a/python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/UntrustedDataToExternalAPI.expected +++ b/python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/UntrustedDataToExternalAPI.expected @@ -1,77 +1,75 @@ edges -| test.py:5:26:5:32 | ControlFlowNode for ImportMember | test.py:5:26:5:32 | ControlFlowNode for request | provenance | | -| test.py:5:26:5:32 | ControlFlowNode for request | test.py:13:16:13:22 | ControlFlowNode for request | provenance | | -| test.py:5:26:5:32 | ControlFlowNode for request | test.py:23:16:23:22 | ControlFlowNode for request | provenance | | -| test.py:5:26:5:32 | ControlFlowNode for request | test.py:34:12:34:18 | ControlFlowNode for request | provenance | | -| test.py:5:26:5:32 | ControlFlowNode for request | test.py:42:12:42:18 | ControlFlowNode for request | provenance | | -| test.py:5:26:5:32 | ControlFlowNode for request | test.py:54:12:54:18 | ControlFlowNode for request | provenance | | -| test.py:13:5:13:12 | ControlFlowNode for data_raw | test.py:14:5:14:8 | ControlFlowNode for data | provenance | | -| test.py:13:5:13:12 | ControlFlowNode for data_raw | test.py:14:5:14:8 | ControlFlowNode for data | provenance | Decoding-Base64 | -| test.py:13:16:13:22 | ControlFlowNode for request | test.py:13:16:13:27 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | -| test.py:13:16:13:27 | ControlFlowNode for Attribute | test.py:13:16:13:39 | ControlFlowNode for Attribute() | provenance | dict.get | -| test.py:13:16:13:39 | ControlFlowNode for Attribute() | test.py:13:5:13:12 | ControlFlowNode for data_raw | provenance | | -| test.py:14:5:14:8 | ControlFlowNode for data | test.py:15:36:15:39 | ControlFlowNode for data | provenance | | -| test.py:23:5:23:12 | ControlFlowNode for data_raw | test.py:24:5:24:8 | ControlFlowNode for data | provenance | | -| test.py:23:5:23:12 | ControlFlowNode for data_raw | test.py:24:5:24:8 | ControlFlowNode for data | provenance | Decoding-Base64 | -| test.py:23:16:23:22 | ControlFlowNode for request | test.py:23:16:23:27 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | -| test.py:23:16:23:27 | ControlFlowNode for Attribute | test.py:23:16:23:39 | ControlFlowNode for Attribute() | provenance | dict.get | -| test.py:23:16:23:39 | ControlFlowNode for Attribute() | test.py:23:5:23:12 | ControlFlowNode for data_raw | provenance | | -| test.py:24:5:24:8 | ControlFlowNode for data | test.py:25:44:25:47 | ControlFlowNode for data | provenance | | -| test.py:34:5:34:8 | ControlFlowNode for data | test.py:35:10:35:13 | ControlFlowNode for data | provenance | | -| test.py:34:5:34:8 | ControlFlowNode for data | test.py:36:13:36:16 | ControlFlowNode for data | provenance | | -| test.py:34:12:34:18 | ControlFlowNode for request | test.py:34:12:34:23 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | -| test.py:34:12:34:23 | ControlFlowNode for Attribute | test.py:34:12:34:35 | ControlFlowNode for Attribute() | provenance | dict.get | -| test.py:34:12:34:35 | ControlFlowNode for Attribute() | test.py:34:5:34:8 | ControlFlowNode for data | provenance | | -| test.py:42:5:42:8 | ControlFlowNode for data | test.py:43:22:43:25 | ControlFlowNode for data | provenance | | -| test.py:42:5:42:8 | ControlFlowNode for data | test.py:44:25:44:28 | ControlFlowNode for data | provenance | | -| test.py:42:12:42:18 | ControlFlowNode for request | test.py:42:12:42:23 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | -| test.py:42:12:42:23 | ControlFlowNode for Attribute | test.py:42:12:42:35 | ControlFlowNode for Attribute() | provenance | dict.get | -| test.py:42:12:42:35 | ControlFlowNode for Attribute() | test.py:42:5:42:8 | ControlFlowNode for data | provenance | | -| test.py:47:17:47:19 | ControlFlowNode for arg | test.py:50:32:50:34 | ControlFlowNode for arg | provenance | | -| test.py:54:5:54:8 | ControlFlowNode for data | test.py:55:17:55:20 | ControlFlowNode for data | provenance | | -| test.py:54:12:54:18 | ControlFlowNode for request | test.py:54:12:54:23 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | -| test.py:54:12:54:23 | ControlFlowNode for Attribute | test.py:54:12:54:35 | ControlFlowNode for Attribute() | provenance | dict.get | -| test.py:54:12:54:35 | ControlFlowNode for Attribute() | test.py:54:5:54:8 | ControlFlowNode for data | provenance | | -| test.py:55:17:55:20 | ControlFlowNode for data | test.py:47:17:47:19 | ControlFlowNode for arg | provenance | | +| test.py:5:26:5:32 | After ImportMember | test.py:5:26:5:32 | request | provenance | | +| test.py:5:26:5:32 | request | test.py:13:16:13:22 | request | provenance | | +| test.py:5:26:5:32 | request | test.py:23:16:23:22 | request | provenance | | +| test.py:5:26:5:32 | request | test.py:34:12:34:18 | request | provenance | | +| test.py:5:26:5:32 | request | test.py:42:12:42:18 | request | provenance | | +| test.py:5:26:5:32 | request | test.py:54:12:54:18 | request | provenance | | +| test.py:13:5:13:12 | data_raw | test.py:14:5:14:8 | data | provenance | Decoding-Base64 | +| test.py:13:16:13:22 | request | test.py:13:16:13:27 | After Attribute | provenance | AdditionalTaintStep | +| test.py:13:16:13:27 | After Attribute | test.py:13:16:13:39 | After Attribute() | provenance | dict.get | +| test.py:13:16:13:39 | After Attribute() | test.py:13:5:13:12 | data_raw | provenance | | +| test.py:14:5:14:8 | data | test.py:15:36:15:39 | data | provenance | | +| test.py:23:5:23:12 | data_raw | test.py:24:5:24:8 | data | provenance | Decoding-Base64 | +| test.py:23:16:23:22 | request | test.py:23:16:23:27 | After Attribute | provenance | AdditionalTaintStep | +| test.py:23:16:23:27 | After Attribute | test.py:23:16:23:39 | After Attribute() | provenance | dict.get | +| test.py:23:16:23:39 | After Attribute() | test.py:23:5:23:12 | data_raw | provenance | | +| test.py:24:5:24:8 | data | test.py:25:44:25:47 | data | provenance | | +| test.py:34:5:34:8 | data | test.py:35:10:35:13 | data | provenance | | +| test.py:34:5:34:8 | data | test.py:36:13:36:16 | data | provenance | | +| test.py:34:12:34:18 | request | test.py:34:12:34:23 | After Attribute | provenance | AdditionalTaintStep | +| test.py:34:12:34:23 | After Attribute | test.py:34:12:34:35 | After Attribute() | provenance | dict.get | +| test.py:34:12:34:35 | After Attribute() | test.py:34:5:34:8 | data | provenance | | +| test.py:42:5:42:8 | data | test.py:43:22:43:25 | data | provenance | | +| test.py:42:5:42:8 | data | test.py:44:25:44:28 | data | provenance | | +| test.py:42:12:42:18 | request | test.py:42:12:42:23 | After Attribute | provenance | AdditionalTaintStep | +| test.py:42:12:42:23 | After Attribute | test.py:42:12:42:35 | After Attribute() | provenance | dict.get | +| test.py:42:12:42:35 | After Attribute() | test.py:42:5:42:8 | data | provenance | | +| test.py:47:17:47:19 | arg | test.py:50:32:50:34 | arg | provenance | | +| test.py:54:5:54:8 | data | test.py:55:17:55:20 | data | provenance | | +| test.py:54:12:54:18 | request | test.py:54:12:54:23 | After Attribute | provenance | AdditionalTaintStep | +| test.py:54:12:54:23 | After Attribute | test.py:54:12:54:35 | After Attribute() | provenance | dict.get | +| test.py:54:12:54:35 | After Attribute() | test.py:54:5:54:8 | data | provenance | | +| test.py:55:17:55:20 | data | test.py:47:17:47:19 | arg | provenance | | nodes -| test.py:5:26:5:32 | ControlFlowNode for ImportMember | semmle.label | ControlFlowNode for ImportMember | -| test.py:5:26:5:32 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| test.py:13:5:13:12 | ControlFlowNode for data_raw | semmle.label | ControlFlowNode for data_raw | -| test.py:13:16:13:22 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| test.py:13:16:13:27 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| test.py:13:16:13:39 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| test.py:14:5:14:8 | ControlFlowNode for data | semmle.label | ControlFlowNode for data | -| test.py:15:36:15:39 | ControlFlowNode for data | semmle.label | ControlFlowNode for data | -| test.py:23:5:23:12 | ControlFlowNode for data_raw | semmle.label | ControlFlowNode for data_raw | -| test.py:23:16:23:22 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| test.py:23:16:23:27 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| test.py:23:16:23:39 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| test.py:24:5:24:8 | ControlFlowNode for data | semmle.label | ControlFlowNode for data | -| test.py:25:44:25:47 | ControlFlowNode for data | semmle.label | ControlFlowNode for data | -| test.py:34:5:34:8 | ControlFlowNode for data | semmle.label | ControlFlowNode for data | -| test.py:34:12:34:18 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| test.py:34:12:34:23 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| test.py:34:12:34:35 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| test.py:35:10:35:13 | ControlFlowNode for data | semmle.label | ControlFlowNode for data | -| test.py:36:13:36:16 | ControlFlowNode for data | semmle.label | ControlFlowNode for data | -| test.py:42:5:42:8 | ControlFlowNode for data | semmle.label | ControlFlowNode for data | -| test.py:42:12:42:18 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| test.py:42:12:42:23 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| test.py:42:12:42:35 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| test.py:43:22:43:25 | ControlFlowNode for data | semmle.label | ControlFlowNode for data | -| test.py:44:25:44:28 | ControlFlowNode for data | semmle.label | ControlFlowNode for data | -| test.py:47:17:47:19 | ControlFlowNode for arg | semmle.label | ControlFlowNode for arg | -| test.py:50:32:50:34 | ControlFlowNode for arg | semmle.label | ControlFlowNode for arg | -| test.py:54:5:54:8 | ControlFlowNode for data | semmle.label | ControlFlowNode for data | -| test.py:54:12:54:18 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| test.py:54:12:54:23 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| test.py:54:12:54:35 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| test.py:55:17:55:20 | ControlFlowNode for data | semmle.label | ControlFlowNode for data | +| test.py:5:26:5:32 | After ImportMember | semmle.label | After ImportMember | +| test.py:5:26:5:32 | request | semmle.label | request | +| test.py:13:5:13:12 | data_raw | semmle.label | data_raw | +| test.py:13:16:13:22 | request | semmle.label | request | +| test.py:13:16:13:27 | After Attribute | semmle.label | After Attribute | +| test.py:13:16:13:39 | After Attribute() | semmle.label | After Attribute() | +| test.py:14:5:14:8 | data | semmle.label | data | +| test.py:15:36:15:39 | data | semmle.label | data | +| test.py:23:5:23:12 | data_raw | semmle.label | data_raw | +| test.py:23:16:23:22 | request | semmle.label | request | +| test.py:23:16:23:27 | After Attribute | semmle.label | After Attribute | +| test.py:23:16:23:39 | After Attribute() | semmle.label | After Attribute() | +| test.py:24:5:24:8 | data | semmle.label | data | +| test.py:25:44:25:47 | data | semmle.label | data | +| test.py:34:5:34:8 | data | semmle.label | data | +| test.py:34:12:34:18 | request | semmle.label | request | +| test.py:34:12:34:23 | After Attribute | semmle.label | After Attribute | +| test.py:34:12:34:35 | After Attribute() | semmle.label | After Attribute() | +| test.py:35:10:35:13 | data | semmle.label | data | +| test.py:36:13:36:16 | data | semmle.label | data | +| test.py:42:5:42:8 | data | semmle.label | data | +| test.py:42:12:42:18 | request | semmle.label | request | +| test.py:42:12:42:23 | After Attribute | semmle.label | After Attribute | +| test.py:42:12:42:35 | After Attribute() | semmle.label | After Attribute() | +| test.py:43:22:43:25 | data | semmle.label | data | +| test.py:44:25:44:28 | data | semmle.label | data | +| test.py:47:17:47:19 | arg | semmle.label | arg | +| test.py:50:32:50:34 | arg | semmle.label | arg | +| test.py:54:5:54:8 | data | semmle.label | data | +| test.py:54:12:54:18 | request | semmle.label | request | +| test.py:54:12:54:23 | After Attribute | semmle.label | After Attribute | +| test.py:54:12:54:35 | After Attribute() | semmle.label | After Attribute() | +| test.py:55:17:55:20 | data | semmle.label | data | subpaths #select -| test.py:15:36:15:39 | ControlFlowNode for data | test.py:5:26:5:32 | ControlFlowNode for ImportMember | test.py:15:36:15:39 | ControlFlowNode for data | Call to hmac.new [position 1] with untrusted data from $@. | test.py:5:26:5:32 | ControlFlowNode for ImportMember | ControlFlowNode for ImportMember | -| test.py:25:44:25:47 | ControlFlowNode for data | test.py:5:26:5:32 | ControlFlowNode for ImportMember | test.py:25:44:25:47 | ControlFlowNode for data | Call to hmac.new [keyword msg] with untrusted data from $@. | test.py:5:26:5:32 | ControlFlowNode for ImportMember | ControlFlowNode for ImportMember | -| test.py:35:10:35:13 | ControlFlowNode for data | test.py:5:26:5:32 | ControlFlowNode for ImportMember | test.py:35:10:35:13 | ControlFlowNode for data | Call to unknown.lib.func [position 0] with untrusted data from $@. | test.py:5:26:5:32 | ControlFlowNode for ImportMember | ControlFlowNode for ImportMember | -| test.py:36:13:36:16 | ControlFlowNode for data | test.py:5:26:5:32 | ControlFlowNode for ImportMember | test.py:36:13:36:16 | ControlFlowNode for data | Call to unknown.lib.func [keyword kw] with untrusted data from $@. | test.py:5:26:5:32 | ControlFlowNode for ImportMember | ControlFlowNode for ImportMember | -| test.py:43:22:43:25 | ControlFlowNode for data | test.py:5:26:5:32 | ControlFlowNode for ImportMember | test.py:43:22:43:25 | ControlFlowNode for data | Call to unknown.lib.func [position 0] with untrusted data from $@. | test.py:5:26:5:32 | ControlFlowNode for ImportMember | ControlFlowNode for ImportMember | -| test.py:44:25:44:28 | ControlFlowNode for data | test.py:5:26:5:32 | ControlFlowNode for ImportMember | test.py:44:25:44:28 | ControlFlowNode for data | Call to unknown.lib.func [keyword kw] with untrusted data from $@. | test.py:5:26:5:32 | ControlFlowNode for ImportMember | ControlFlowNode for ImportMember | +| test.py:15:36:15:39 | data | test.py:5:26:5:32 | After ImportMember | test.py:15:36:15:39 | data | Call to hmac.new [position 1] with untrusted data from $@. | test.py:5:26:5:32 | After ImportMember | After ImportMember | +| test.py:25:44:25:47 | data | test.py:5:26:5:32 | After ImportMember | test.py:25:44:25:47 | data | Call to hmac.new [keyword msg] with untrusted data from $@. | test.py:5:26:5:32 | After ImportMember | After ImportMember | +| test.py:35:10:35:13 | data | test.py:5:26:5:32 | After ImportMember | test.py:35:10:35:13 | data | Call to unknown.lib.func [position 0] with untrusted data from $@. | test.py:5:26:5:32 | After ImportMember | After ImportMember | +| test.py:36:13:36:16 | data | test.py:5:26:5:32 | After ImportMember | test.py:36:13:36:16 | data | Call to unknown.lib.func [keyword kw] with untrusted data from $@. | test.py:5:26:5:32 | After ImportMember | After ImportMember | +| test.py:43:22:43:25 | data | test.py:5:26:5:32 | After ImportMember | test.py:43:22:43:25 | data | Call to unknown.lib.func [position 0] with untrusted data from $@. | test.py:5:26:5:32 | After ImportMember | After ImportMember | +| test.py:44:25:44:28 | data | test.py:5:26:5:32 | After ImportMember | test.py:44:25:44:28 | data | Call to unknown.lib.func [keyword kw] with untrusted data from $@. | test.py:5:26:5:32 | After ImportMember | After ImportMember | diff --git a/python/ql/test/query-tests/Security/CWE-020-IncompleteHostnameRegExp/IncompleteHostnameRegExp.expected b/python/ql/test/query-tests/Security/CWE-020-IncompleteHostnameRegExp/IncompleteHostnameRegExp.expected index 046a00a71940..41ab8538dcc4 100644 --- a/python/ql/test/query-tests/Security/CWE-020-IncompleteHostnameRegExp/IncompleteHostnameRegExp.expected +++ b/python/ql/test/query-tests/Security/CWE-020-IncompleteHostnameRegExp/IncompleteHostnameRegExp.expected @@ -1 +1 @@ -| hosttest.py:6:28:6:50 | (www\|beta).example.com/ | This regular expression has an unescaped '.' before 'example.com/', so it might match more hosts than expected. | hosttest.py:6:27:6:51 | ControlFlowNode for StringLiteral | here | +| hosttest.py:6:28:6:50 | (www\|beta).example.com/ | This regular expression has an unescaped '.' before 'example.com/', so it might match more hosts than expected. | hosttest.py:6:27:6:51 | StringLiteral | here | diff --git a/python/ql/test/query-tests/Security/CWE-022-PathInjection/PathInjection.expected b/python/ql/test/query-tests/Security/CWE-022-PathInjection/PathInjection.expected index 79b36070c017..93ec2b86f6dd 100644 --- a/python/ql/test/query-tests/Security/CWE-022-PathInjection/PathInjection.expected +++ b/python/ql/test/query-tests/Security/CWE-022-PathInjection/PathInjection.expected @@ -1,298 +1,295 @@ #select -| fastapi_path_injection.py:7:19:7:26 | ControlFlowNode for filepath | fastapi_path_injection.py:17:21:17:24 | ControlFlowNode for path | fastapi_path_injection.py:7:19:7:26 | ControlFlowNode for filepath | This path depends on a $@. | fastapi_path_injection.py:17:21:17:24 | ControlFlowNode for path | user-provided value | -| fastapi_path_injection.py:7:19:7:26 | ControlFlowNode for filepath | fastapi_path_injection.py:26:21:26:24 | ControlFlowNode for path | fastapi_path_injection.py:7:19:7:26 | ControlFlowNode for filepath | This path depends on a $@. | fastapi_path_injection.py:26:21:26:24 | ControlFlowNode for path | user-provided value | -| fastapi_path_injection.py:7:19:7:26 | ControlFlowNode for filepath | fastapi_path_injection.py:31:21:31:24 | ControlFlowNode for path | fastapi_path_injection.py:7:19:7:26 | ControlFlowNode for filepath | This path depends on a $@. | fastapi_path_injection.py:31:21:31:24 | ControlFlowNode for path | user-provided value | -| fastapi_path_injection.py:7:19:7:26 | ControlFlowNode for filepath | fastapi_path_injection.py:48:21:48:24 | ControlFlowNode for path | fastapi_path_injection.py:7:19:7:26 | ControlFlowNode for filepath | This path depends on a $@. | fastapi_path_injection.py:48:21:48:24 | ControlFlowNode for path | user-provided value | -| flask_path_injection.py:21:32:21:38 | ControlFlowNode for dirname | flask_path_injection.py:1:26:1:32 | ControlFlowNode for ImportMember | flask_path_injection.py:21:32:21:38 | ControlFlowNode for dirname | This path depends on a $@. | flask_path_injection.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value | -| path_injection.py:13:14:13:47 | ControlFlowNode for Attribute() | path_injection.py:3:26:3:32 | ControlFlowNode for ImportMember | path_injection.py:13:14:13:47 | ControlFlowNode for Attribute() | This path depends on a $@. | path_injection.py:3:26:3:32 | ControlFlowNode for ImportMember | user-provided value | -| path_injection.py:21:14:21:18 | ControlFlowNode for npath | path_injection.py:3:26:3:32 | ControlFlowNode for ImportMember | path_injection.py:21:14:21:18 | ControlFlowNode for npath | This path depends on a $@. | path_injection.py:3:26:3:32 | ControlFlowNode for ImportMember | user-provided value | -| path_injection.py:31:14:31:18 | ControlFlowNode for npath | path_injection.py:3:26:3:32 | ControlFlowNode for ImportMember | path_injection.py:31:14:31:18 | ControlFlowNode for npath | This path depends on a $@. | path_injection.py:3:26:3:32 | ControlFlowNode for ImportMember | user-provided value | -| path_injection.py:48:14:48:18 | ControlFlowNode for npath | path_injection.py:3:26:3:32 | ControlFlowNode for ImportMember | path_injection.py:48:14:48:18 | ControlFlowNode for npath | This path depends on a $@. | path_injection.py:3:26:3:32 | ControlFlowNode for ImportMember | user-provided value | -| path_injection.py:65:14:65:18 | ControlFlowNode for npath | path_injection.py:3:26:3:32 | ControlFlowNode for ImportMember | path_injection.py:65:14:65:18 | ControlFlowNode for npath | This path depends on a $@. | path_injection.py:3:26:3:32 | ControlFlowNode for ImportMember | user-provided value | -| path_injection.py:87:18:87:37 | ControlFlowNode for possibly_unsafe_path | path_injection.py:3:26:3:32 | ControlFlowNode for ImportMember | path_injection.py:87:18:87:37 | ControlFlowNode for possibly_unsafe_path | This path depends on a $@. | path_injection.py:3:26:3:32 | ControlFlowNode for ImportMember | user-provided value | -| path_injection.py:94:14:94:17 | ControlFlowNode for path | path_injection.py:91:20:91:25 | ControlFlowNode for foo_id | path_injection.py:94:14:94:17 | ControlFlowNode for path | This path depends on a $@. | path_injection.py:91:20:91:25 | ControlFlowNode for foo_id | user-provided value | -| path_injection.py:102:14:102:17 | ControlFlowNode for path | path_injection.py:98:20:98:22 | ControlFlowNode for foo | path_injection.py:102:14:102:17 | ControlFlowNode for path | This path depends on a $@. | path_injection.py:98:20:98:22 | ControlFlowNode for foo | user-provided value | -| path_injection.py:113:14:113:17 | ControlFlowNode for path | path_injection.py:3:26:3:32 | ControlFlowNode for ImportMember | path_injection.py:113:14:113:17 | ControlFlowNode for path | This path depends on a $@. | path_injection.py:3:26:3:32 | ControlFlowNode for ImportMember | user-provided value | -| path_injection.py:124:14:124:17 | ControlFlowNode for path | path_injection.py:3:26:3:32 | ControlFlowNode for ImportMember | path_injection.py:124:14:124:17 | ControlFlowNode for path | This path depends on a $@. | path_injection.py:3:26:3:32 | ControlFlowNode for ImportMember | user-provided value | -| path_injection.py:132:14:132:22 | ControlFlowNode for sanitized | path_injection.py:3:26:3:32 | ControlFlowNode for ImportMember | path_injection.py:132:14:132:22 | ControlFlowNode for sanitized | This path depends on a $@. | path_injection.py:3:26:3:32 | ControlFlowNode for ImportMember | user-provided value | -| path_injection.py:142:14:142:17 | ControlFlowNode for path | path_injection.py:3:26:3:32 | ControlFlowNode for ImportMember | path_injection.py:142:14:142:17 | ControlFlowNode for path | This path depends on a $@. | path_injection.py:3:26:3:32 | ControlFlowNode for ImportMember | user-provided value | -| path_injection.py:152:18:152:21 | ControlFlowNode for path | path_injection.py:3:26:3:32 | ControlFlowNode for ImportMember | path_injection.py:152:18:152:21 | ControlFlowNode for path | This path depends on a $@. | path_injection.py:3:26:3:32 | ControlFlowNode for ImportMember | user-provided value | -| pathlib_use.py:14:5:14:5 | ControlFlowNode for p | pathlib_use.py:3:26:3:32 | ControlFlowNode for ImportMember | pathlib_use.py:14:5:14:5 | ControlFlowNode for p | This path depends on a $@. | pathlib_use.py:3:26:3:32 | ControlFlowNode for ImportMember | user-provided value | -| pathlib_use.py:17:5:17:6 | ControlFlowNode for p2 | pathlib_use.py:3:26:3:32 | ControlFlowNode for ImportMember | pathlib_use.py:17:5:17:6 | ControlFlowNode for p2 | This path depends on a $@. | pathlib_use.py:3:26:3:32 | ControlFlowNode for ImportMember | user-provided value | -| test.py:19:10:19:10 | ControlFlowNode for x | test.py:3:26:3:32 | ControlFlowNode for ImportMember | test.py:19:10:19:10 | ControlFlowNode for x | This path depends on a $@. | test.py:3:26:3:32 | ControlFlowNode for ImportMember | user-provided value | -| test.py:26:10:26:10 | ControlFlowNode for y | test.py:3:26:3:32 | ControlFlowNode for ImportMember | test.py:26:10:26:10 | ControlFlowNode for y | This path depends on a $@. | test.py:3:26:3:32 | ControlFlowNode for ImportMember | user-provided value | -| test.py:33:14:33:14 | ControlFlowNode for x | test.py:3:26:3:32 | ControlFlowNode for ImportMember | test.py:33:14:33:14 | ControlFlowNode for x | This path depends on a $@. | test.py:3:26:3:32 | ControlFlowNode for ImportMember | user-provided value | -| test.py:49:14:49:14 | ControlFlowNode for y | test.py:3:26:3:32 | ControlFlowNode for ImportMember | test.py:49:14:49:14 | ControlFlowNode for y | This path depends on a $@. | test.py:3:26:3:32 | ControlFlowNode for ImportMember | user-provided value | +| fastapi_path_injection.py:7:19:7:26 | filepath | fastapi_path_injection.py:17:21:17:24 | path | fastapi_path_injection.py:7:19:7:26 | filepath | This path depends on a $@. | fastapi_path_injection.py:17:21:17:24 | path | user-provided value | +| fastapi_path_injection.py:7:19:7:26 | filepath | fastapi_path_injection.py:31:21:31:24 | path | fastapi_path_injection.py:7:19:7:26 | filepath | This path depends on a $@. | fastapi_path_injection.py:31:21:31:24 | path | user-provided value | +| fastapi_path_injection.py:7:19:7:26 | filepath | fastapi_path_injection.py:48:21:48:24 | path | fastapi_path_injection.py:7:19:7:26 | filepath | This path depends on a $@. | fastapi_path_injection.py:48:21:48:24 | path | user-provided value | +| flask_path_injection.py:21:32:21:38 | dirname | flask_path_injection.py:1:26:1:32 | ImportMember | flask_path_injection.py:21:32:21:38 | dirname | This path depends on a $@. | flask_path_injection.py:1:26:1:32 | ImportMember | user-provided value | +| path_injection.py:13:14:13:47 | Attribute() | path_injection.py:3:26:3:32 | ImportMember | path_injection.py:13:14:13:47 | Attribute() | This path depends on a $@. | path_injection.py:3:26:3:32 | ImportMember | user-provided value | +| path_injection.py:21:14:21:18 | npath | path_injection.py:3:26:3:32 | ImportMember | path_injection.py:21:14:21:18 | npath | This path depends on a $@. | path_injection.py:3:26:3:32 | ImportMember | user-provided value | +| path_injection.py:31:14:31:18 | npath | path_injection.py:3:26:3:32 | ImportMember | path_injection.py:31:14:31:18 | npath | This path depends on a $@. | path_injection.py:3:26:3:32 | ImportMember | user-provided value | +| path_injection.py:48:14:48:18 | npath | path_injection.py:3:26:3:32 | ImportMember | path_injection.py:48:14:48:18 | npath | This path depends on a $@. | path_injection.py:3:26:3:32 | ImportMember | user-provided value | +| path_injection.py:65:14:65:18 | npath | path_injection.py:3:26:3:32 | ImportMember | path_injection.py:65:14:65:18 | npath | This path depends on a $@. | path_injection.py:3:26:3:32 | ImportMember | user-provided value | +| path_injection.py:87:18:87:37 | possibly_unsafe_path | path_injection.py:3:26:3:32 | ImportMember | path_injection.py:87:18:87:37 | possibly_unsafe_path | This path depends on a $@. | path_injection.py:3:26:3:32 | ImportMember | user-provided value | +| path_injection.py:94:14:94:17 | path | path_injection.py:91:20:91:25 | foo_id | path_injection.py:94:14:94:17 | path | This path depends on a $@. | path_injection.py:91:20:91:25 | foo_id | user-provided value | +| path_injection.py:102:14:102:17 | path | path_injection.py:98:20:98:22 | foo | path_injection.py:102:14:102:17 | path | This path depends on a $@. | path_injection.py:98:20:98:22 | foo | user-provided value | +| path_injection.py:113:14:113:17 | path | path_injection.py:3:26:3:32 | ImportMember | path_injection.py:113:14:113:17 | path | This path depends on a $@. | path_injection.py:3:26:3:32 | ImportMember | user-provided value | +| path_injection.py:124:14:124:17 | path | path_injection.py:3:26:3:32 | ImportMember | path_injection.py:124:14:124:17 | path | This path depends on a $@. | path_injection.py:3:26:3:32 | ImportMember | user-provided value | +| path_injection.py:132:14:132:22 | sanitized | path_injection.py:3:26:3:32 | ImportMember | path_injection.py:132:14:132:22 | sanitized | This path depends on a $@. | path_injection.py:3:26:3:32 | ImportMember | user-provided value | +| path_injection.py:142:14:142:17 | path | path_injection.py:3:26:3:32 | ImportMember | path_injection.py:142:14:142:17 | path | This path depends on a $@. | path_injection.py:3:26:3:32 | ImportMember | user-provided value | +| path_injection.py:152:18:152:21 | path | path_injection.py:3:26:3:32 | ImportMember | path_injection.py:152:18:152:21 | path | This path depends on a $@. | path_injection.py:3:26:3:32 | ImportMember | user-provided value | +| pathlib_use.py:14:5:14:5 | p | pathlib_use.py:3:26:3:32 | ImportMember | pathlib_use.py:14:5:14:5 | p | This path depends on a $@. | pathlib_use.py:3:26:3:32 | ImportMember | user-provided value | +| pathlib_use.py:17:5:17:6 | p2 | pathlib_use.py:3:26:3:32 | ImportMember | pathlib_use.py:17:5:17:6 | p2 | This path depends on a $@. | pathlib_use.py:3:26:3:32 | ImportMember | user-provided value | +| test.py:19:10:19:10 | x | test.py:3:26:3:32 | ImportMember | test.py:19:10:19:10 | x | This path depends on a $@. | test.py:3:26:3:32 | ImportMember | user-provided value | +| test.py:26:10:26:10 | y | test.py:3:26:3:32 | ImportMember | test.py:26:10:26:10 | y | This path depends on a $@. | test.py:3:26:3:32 | ImportMember | user-provided value | +| test.py:33:14:33:14 | x | test.py:3:26:3:32 | ImportMember | test.py:33:14:33:14 | x | This path depends on a $@. | test.py:3:26:3:32 | ImportMember | user-provided value | +| test.py:49:14:49:14 | y | test.py:3:26:3:32 | ImportMember | test.py:49:14:49:14 | y | This path depends on a $@. | test.py:3:26:3:32 | ImportMember | user-provided value | edges -| fastapi_path_injection.py:6:24:6:31 | ControlFlowNode for filepath | fastapi_path_injection.py:7:19:7:26 | ControlFlowNode for filepath | provenance | | -| fastapi_path_injection.py:17:21:17:24 | ControlFlowNode for path | fastapi_path_injection.py:20:34:20:37 | ControlFlowNode for path | provenance | | -| fastapi_path_injection.py:20:34:20:37 | ControlFlowNode for path | fastapi_path_injection.py:6:24:6:31 | ControlFlowNode for filepath | provenance | | -| fastapi_path_injection.py:26:21:26:24 | ControlFlowNode for path | fastapi_path_injection.py:27:34:27:37 | ControlFlowNode for path | provenance | | -| fastapi_path_injection.py:27:34:27:37 | ControlFlowNode for path | fastapi_path_injection.py:6:24:6:31 | ControlFlowNode for filepath | provenance | | -| fastapi_path_injection.py:31:21:31:24 | ControlFlowNode for path | fastapi_path_injection.py:32:34:32:37 | ControlFlowNode for path | provenance | | -| fastapi_path_injection.py:32:34:32:37 | ControlFlowNode for path | fastapi_path_injection.py:6:24:6:31 | ControlFlowNode for filepath | provenance | | -| fastapi_path_injection.py:48:21:48:24 | ControlFlowNode for path | fastapi_path_injection.py:49:45:49:48 | ControlFlowNode for path | provenance | | -| fastapi_path_injection.py:49:45:49:48 | ControlFlowNode for path | fastapi_path_injection.py:6:24:6:31 | ControlFlowNode for filepath | provenance | | -| flask_path_injection.py:1:26:1:32 | ControlFlowNode for ImportMember | flask_path_injection.py:1:26:1:32 | ControlFlowNode for request | provenance | | -| flask_path_injection.py:1:26:1:32 | ControlFlowNode for request | flask_path_injection.py:19:15:19:21 | ControlFlowNode for request | provenance | | -| flask_path_injection.py:19:5:19:11 | ControlFlowNode for dirname | flask_path_injection.py:21:32:21:38 | ControlFlowNode for dirname | provenance | | -| flask_path_injection.py:19:15:19:21 | ControlFlowNode for request | flask_path_injection.py:19:15:19:26 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | -| flask_path_injection.py:19:15:19:26 | ControlFlowNode for Attribute | flask_path_injection.py:19:15:19:45 | ControlFlowNode for Attribute() | provenance | dict.get | -| flask_path_injection.py:19:15:19:45 | ControlFlowNode for Attribute() | flask_path_injection.py:19:5:19:11 | ControlFlowNode for dirname | provenance | | -| path_injection.py:3:26:3:32 | ControlFlowNode for ImportMember | path_injection.py:3:26:3:32 | ControlFlowNode for request | provenance | | -| path_injection.py:3:26:3:32 | ControlFlowNode for request | path_injection.py:12:16:12:22 | ControlFlowNode for request | provenance | | -| path_injection.py:3:26:3:32 | ControlFlowNode for request | path_injection.py:19:16:19:22 | ControlFlowNode for request | provenance | | -| path_injection.py:3:26:3:32 | ControlFlowNode for request | path_injection.py:27:16:27:22 | ControlFlowNode for request | provenance | | -| path_injection.py:3:26:3:32 | ControlFlowNode for request | path_injection.py:46:16:46:22 | ControlFlowNode for request | provenance | | -| path_injection.py:3:26:3:32 | ControlFlowNode for request | path_injection.py:63:16:63:22 | ControlFlowNode for request | provenance | | -| path_injection.py:3:26:3:32 | ControlFlowNode for request | path_injection.py:84:16:84:22 | ControlFlowNode for request | provenance | | -| path_injection.py:3:26:3:32 | ControlFlowNode for request | path_injection.py:107:16:107:22 | ControlFlowNode for request | provenance | | -| path_injection.py:3:26:3:32 | ControlFlowNode for request | path_injection.py:118:16:118:22 | ControlFlowNode for request | provenance | | -| path_injection.py:3:26:3:32 | ControlFlowNode for request | path_injection.py:129:16:129:22 | ControlFlowNode for request | provenance | | -| path_injection.py:3:26:3:32 | ControlFlowNode for request | path_injection.py:138:16:138:22 | ControlFlowNode for request | provenance | | -| path_injection.py:3:26:3:32 | ControlFlowNode for request | path_injection.py:149:16:149:22 | ControlFlowNode for request | provenance | | -| path_injection.py:12:5:12:12 | ControlFlowNode for filename | path_injection.py:13:14:13:47 | ControlFlowNode for Attribute() | provenance | AdditionalTaintStep | -| path_injection.py:12:16:12:22 | ControlFlowNode for request | path_injection.py:12:16:12:27 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | -| path_injection.py:12:16:12:27 | ControlFlowNode for Attribute | path_injection.py:12:16:12:47 | ControlFlowNode for Attribute() | provenance | dict.get | -| path_injection.py:12:16:12:47 | ControlFlowNode for Attribute() | path_injection.py:12:5:12:12 | ControlFlowNode for filename | provenance | | -| path_injection.py:19:5:19:12 | ControlFlowNode for filename | path_injection.py:20:30:20:63 | ControlFlowNode for Attribute() | provenance | AdditionalTaintStep | -| path_injection.py:19:16:19:22 | ControlFlowNode for request | path_injection.py:19:16:19:27 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | -| path_injection.py:19:16:19:27 | ControlFlowNode for Attribute | path_injection.py:19:16:19:47 | ControlFlowNode for Attribute() | provenance | dict.get | -| path_injection.py:19:16:19:47 | ControlFlowNode for Attribute() | path_injection.py:19:5:19:12 | ControlFlowNode for filename | provenance | | -| path_injection.py:20:5:20:9 | ControlFlowNode for npath | path_injection.py:21:14:21:18 | ControlFlowNode for npath | provenance | | -| path_injection.py:20:13:20:64 | ControlFlowNode for Attribute() | path_injection.py:20:5:20:9 | ControlFlowNode for npath | provenance | | -| path_injection.py:20:30:20:63 | ControlFlowNode for Attribute() | path_injection.py:20:13:20:64 | ControlFlowNode for Attribute() | provenance | Config | -| path_injection.py:27:5:27:12 | ControlFlowNode for filename | path_injection.py:28:30:28:63 | ControlFlowNode for Attribute() | provenance | AdditionalTaintStep | -| path_injection.py:27:16:27:22 | ControlFlowNode for request | path_injection.py:27:16:27:27 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | -| path_injection.py:27:16:27:27 | ControlFlowNode for Attribute | path_injection.py:27:16:27:47 | ControlFlowNode for Attribute() | provenance | dict.get | -| path_injection.py:27:16:27:47 | ControlFlowNode for Attribute() | path_injection.py:27:5:27:12 | ControlFlowNode for filename | provenance | | -| path_injection.py:28:5:28:9 | ControlFlowNode for npath | path_injection.py:31:14:31:18 | ControlFlowNode for npath | provenance | | -| path_injection.py:28:13:28:64 | ControlFlowNode for Attribute() | path_injection.py:28:5:28:9 | ControlFlowNode for npath | provenance | | -| path_injection.py:28:30:28:63 | ControlFlowNode for Attribute() | path_injection.py:28:13:28:64 | ControlFlowNode for Attribute() | provenance | Config | -| path_injection.py:46:5:46:12 | ControlFlowNode for filename | path_injection.py:47:30:47:63 | ControlFlowNode for Attribute() | provenance | AdditionalTaintStep | -| path_injection.py:46:16:46:22 | ControlFlowNode for request | path_injection.py:46:16:46:27 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | -| path_injection.py:46:16:46:27 | ControlFlowNode for Attribute | path_injection.py:46:16:46:47 | ControlFlowNode for Attribute() | provenance | dict.get | -| path_injection.py:46:16:46:47 | ControlFlowNode for Attribute() | path_injection.py:46:5:46:12 | ControlFlowNode for filename | provenance | | -| path_injection.py:47:5:47:9 | ControlFlowNode for npath | path_injection.py:48:14:48:18 | ControlFlowNode for npath | provenance | | -| path_injection.py:47:13:47:64 | ControlFlowNode for Attribute() | path_injection.py:47:5:47:9 | ControlFlowNode for npath | provenance | | -| path_injection.py:47:30:47:63 | ControlFlowNode for Attribute() | path_injection.py:47:13:47:64 | ControlFlowNode for Attribute() | provenance | Config | -| path_injection.py:63:5:63:12 | ControlFlowNode for filename | path_injection.py:64:29:64:62 | ControlFlowNode for Attribute() | provenance | AdditionalTaintStep | -| path_injection.py:63:16:63:22 | ControlFlowNode for request | path_injection.py:63:16:63:27 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | -| path_injection.py:63:16:63:27 | ControlFlowNode for Attribute | path_injection.py:63:16:63:47 | ControlFlowNode for Attribute() | provenance | dict.get | -| path_injection.py:63:16:63:47 | ControlFlowNode for Attribute() | path_injection.py:63:5:63:12 | ControlFlowNode for filename | provenance | | -| path_injection.py:64:5:64:9 | ControlFlowNode for npath | path_injection.py:65:14:65:18 | ControlFlowNode for npath | provenance | | -| path_injection.py:64:13:64:63 | ControlFlowNode for Attribute() | path_injection.py:64:5:64:9 | ControlFlowNode for npath | provenance | | -| path_injection.py:64:29:64:62 | ControlFlowNode for Attribute() | path_injection.py:64:13:64:63 | ControlFlowNode for Attribute() | provenance | Config | -| path_injection.py:84:5:84:12 | ControlFlowNode for filename | path_injection.py:85:5:85:24 | ControlFlowNode for possibly_unsafe_path | provenance | AdditionalTaintStep | -| path_injection.py:84:16:84:22 | ControlFlowNode for request | path_injection.py:84:16:84:27 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | -| path_injection.py:84:16:84:27 | ControlFlowNode for Attribute | path_injection.py:84:16:84:47 | ControlFlowNode for Attribute() | provenance | dict.get | -| path_injection.py:84:16:84:47 | ControlFlowNode for Attribute() | path_injection.py:84:5:84:12 | ControlFlowNode for filename | provenance | | -| path_injection.py:85:5:85:24 | ControlFlowNode for possibly_unsafe_path | path_injection.py:86:24:86:43 | ControlFlowNode for possibly_unsafe_path | provenance | | -| path_injection.py:86:24:86:43 | ControlFlowNode for possibly_unsafe_path | path_injection.py:87:18:87:37 | ControlFlowNode for possibly_unsafe_path | provenance | | -| path_injection.py:91:20:91:25 | ControlFlowNode for foo_id | path_injection.py:93:5:93:8 | ControlFlowNode for path | provenance | AdditionalTaintStep | -| path_injection.py:93:5:93:8 | ControlFlowNode for path | path_injection.py:94:14:94:17 | ControlFlowNode for path | provenance | | -| path_injection.py:98:20:98:22 | ControlFlowNode for foo | path_injection.py:101:5:101:8 | ControlFlowNode for path | provenance | AdditionalTaintStep | -| path_injection.py:101:5:101:8 | ControlFlowNode for path | path_injection.py:102:14:102:17 | ControlFlowNode for path | provenance | | -| path_injection.py:107:5:107:12 | ControlFlowNode for filename | path_injection.py:108:5:108:8 | ControlFlowNode for path | provenance | AdditionalTaintStep | -| path_injection.py:107:16:107:22 | ControlFlowNode for request | path_injection.py:107:16:107:27 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | -| path_injection.py:107:16:107:27 | ControlFlowNode for Attribute | path_injection.py:107:16:107:47 | ControlFlowNode for Attribute() | provenance | dict.get | -| path_injection.py:107:16:107:47 | ControlFlowNode for Attribute() | path_injection.py:107:5:107:12 | ControlFlowNode for filename | provenance | | -| path_injection.py:108:5:108:8 | ControlFlowNode for path | path_injection.py:113:14:113:17 | ControlFlowNode for path | provenance | | -| path_injection.py:118:5:118:12 | ControlFlowNode for filename | path_injection.py:119:5:119:8 | ControlFlowNode for path | provenance | AdditionalTaintStep | -| path_injection.py:118:16:118:22 | ControlFlowNode for request | path_injection.py:118:16:118:27 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | -| path_injection.py:118:16:118:27 | ControlFlowNode for Attribute | path_injection.py:118:16:118:47 | ControlFlowNode for Attribute() | provenance | dict.get | -| path_injection.py:118:16:118:47 | ControlFlowNode for Attribute() | path_injection.py:118:5:118:12 | ControlFlowNode for filename | provenance | | -| path_injection.py:119:5:119:8 | ControlFlowNode for path | path_injection.py:124:14:124:17 | ControlFlowNode for path | provenance | | -| path_injection.py:129:5:129:12 | ControlFlowNode for filename | path_injection.py:130:5:130:8 | ControlFlowNode for path | provenance | AdditionalTaintStep | -| path_injection.py:129:16:129:22 | ControlFlowNode for request | path_injection.py:129:16:129:27 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | -| path_injection.py:129:16:129:27 | ControlFlowNode for Attribute | path_injection.py:129:16:129:47 | ControlFlowNode for Attribute() | provenance | dict.get | -| path_injection.py:129:16:129:47 | ControlFlowNode for Attribute() | path_injection.py:129:5:129:12 | ControlFlowNode for filename | provenance | | -| path_injection.py:130:5:130:8 | ControlFlowNode for path | path_injection.py:131:5:131:13 | ControlFlowNode for sanitized | provenance | | -| path_injection.py:131:5:131:13 | ControlFlowNode for sanitized | path_injection.py:132:14:132:22 | ControlFlowNode for sanitized | provenance | | -| path_injection.py:138:5:138:12 | ControlFlowNode for filename | path_injection.py:139:5:139:8 | ControlFlowNode for path | provenance | AdditionalTaintStep | -| path_injection.py:138:16:138:22 | ControlFlowNode for request | path_injection.py:138:16:138:27 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | -| path_injection.py:138:16:138:27 | ControlFlowNode for Attribute | path_injection.py:138:16:138:47 | ControlFlowNode for Attribute() | provenance | dict.get | -| path_injection.py:138:16:138:47 | ControlFlowNode for Attribute() | path_injection.py:138:5:138:12 | ControlFlowNode for filename | provenance | | -| path_injection.py:139:5:139:8 | ControlFlowNode for path | path_injection.py:140:47:140:50 | ControlFlowNode for path | provenance | | -| path_injection.py:140:47:140:50 | ControlFlowNode for path | path_injection.py:142:14:142:17 | ControlFlowNode for path | provenance | | -| path_injection.py:149:5:149:12 | ControlFlowNode for filename | path_injection.py:151:9:151:12 | ControlFlowNode for path | provenance | AdditionalTaintStep | -| path_injection.py:149:16:149:22 | ControlFlowNode for request | path_injection.py:149:16:149:27 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | -| path_injection.py:149:16:149:27 | ControlFlowNode for Attribute | path_injection.py:149:16:149:47 | ControlFlowNode for Attribute() | provenance | dict.get | -| path_injection.py:149:16:149:47 | ControlFlowNode for Attribute() | path_injection.py:149:5:149:12 | ControlFlowNode for filename | provenance | | -| path_injection.py:151:9:151:12 | ControlFlowNode for path | path_injection.py:152:18:152:21 | ControlFlowNode for path | provenance | | -| pathlib_use.py:3:26:3:32 | ControlFlowNode for ImportMember | pathlib_use.py:3:26:3:32 | ControlFlowNode for request | provenance | | -| pathlib_use.py:3:26:3:32 | ControlFlowNode for request | pathlib_use.py:12:16:12:22 | ControlFlowNode for request | provenance | | -| pathlib_use.py:12:5:12:12 | ControlFlowNode for filename | pathlib_use.py:13:5:13:5 | ControlFlowNode for p | provenance | AdditionalTaintStep | -| pathlib_use.py:12:5:12:12 | ControlFlowNode for filename | pathlib_use.py:16:5:16:6 | ControlFlowNode for p2 | provenance | AdditionalTaintStep | -| pathlib_use.py:12:16:12:22 | ControlFlowNode for request | pathlib_use.py:12:16:12:27 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | -| pathlib_use.py:12:16:12:27 | ControlFlowNode for Attribute | pathlib_use.py:12:16:12:47 | ControlFlowNode for Attribute() | provenance | dict.get | -| pathlib_use.py:12:16:12:47 | ControlFlowNode for Attribute() | pathlib_use.py:12:5:12:12 | ControlFlowNode for filename | provenance | | -| pathlib_use.py:13:5:13:5 | ControlFlowNode for p | pathlib_use.py:14:5:14:5 | ControlFlowNode for p | provenance | | -| pathlib_use.py:16:5:16:6 | ControlFlowNode for p2 | pathlib_use.py:17:5:17:6 | ControlFlowNode for p2 | provenance | | -| test.py:3:26:3:32 | ControlFlowNode for ImportMember | test.py:3:26:3:32 | ControlFlowNode for request | provenance | | -| test.py:3:26:3:32 | ControlFlowNode for request | test.py:9:12:9:18 | ControlFlowNode for request | provenance | | -| test.py:9:12:9:18 | ControlFlowNode for request | test.py:9:12:9:23 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | -| test.py:9:12:9:23 | ControlFlowNode for Attribute | test.py:9:12:9:39 | ControlFlowNode for Attribute() | provenance | dict.get | -| test.py:9:12:9:39 | ControlFlowNode for Attribute() | test.py:18:9:18:16 | ControlFlowNode for source() | provenance | | -| test.py:9:12:9:39 | ControlFlowNode for Attribute() | test.py:24:9:24:16 | ControlFlowNode for source() | provenance | | -| test.py:9:12:9:39 | ControlFlowNode for Attribute() | test.py:31:9:31:16 | ControlFlowNode for source() | provenance | | -| test.py:9:12:9:39 | ControlFlowNode for Attribute() | test.py:46:9:46:16 | ControlFlowNode for source() | provenance | | -| test.py:12:15:12:15 | ControlFlowNode for x | test.py:13:29:13:29 | ControlFlowNode for x | provenance | | -| test.py:13:29:13:29 | ControlFlowNode for x | test.py:13:12:13:30 | ControlFlowNode for Attribute() | provenance | Config | -| test.py:18:5:18:5 | ControlFlowNode for x | test.py:19:10:19:10 | ControlFlowNode for x | provenance | | -| test.py:18:9:18:16 | ControlFlowNode for source() | test.py:18:5:18:5 | ControlFlowNode for x | provenance | | -| test.py:24:5:24:5 | ControlFlowNode for x | test.py:25:19:25:19 | ControlFlowNode for x | provenance | | -| test.py:24:9:24:16 | ControlFlowNode for source() | test.py:24:5:24:5 | ControlFlowNode for x | provenance | | -| test.py:25:5:25:5 | ControlFlowNode for y | test.py:26:10:26:10 | ControlFlowNode for y | provenance | | -| test.py:25:9:25:20 | ControlFlowNode for normalize() | test.py:25:5:25:5 | ControlFlowNode for y | provenance | | -| test.py:25:19:25:19 | ControlFlowNode for x | test.py:12:15:12:15 | ControlFlowNode for x | provenance | | -| test.py:25:19:25:19 | ControlFlowNode for x | test.py:25:9:25:20 | ControlFlowNode for normalize() | provenance | Config | -| test.py:31:5:31:5 | ControlFlowNode for x | test.py:33:14:33:14 | ControlFlowNode for x | provenance | | -| test.py:31:9:31:16 | ControlFlowNode for source() | test.py:31:5:31:5 | ControlFlowNode for x | provenance | | -| test.py:46:5:46:5 | ControlFlowNode for x | test.py:48:23:48:23 | ControlFlowNode for x | provenance | | -| test.py:46:9:46:16 | ControlFlowNode for source() | test.py:46:5:46:5 | ControlFlowNode for x | provenance | | -| test.py:48:9:48:9 | ControlFlowNode for y | test.py:49:14:49:14 | ControlFlowNode for y | provenance | | -| test.py:48:13:48:24 | ControlFlowNode for normalize() | test.py:48:9:48:9 | ControlFlowNode for y | provenance | | -| test.py:48:23:48:23 | ControlFlowNode for x | test.py:12:15:12:15 | ControlFlowNode for x | provenance | | -| test.py:48:23:48:23 | ControlFlowNode for x | test.py:48:13:48:24 | ControlFlowNode for normalize() | provenance | Config | +| fastapi_path_injection.py:6:24:6:31 | filepath | fastapi_path_injection.py:7:19:7:26 | filepath | provenance | | +| fastapi_path_injection.py:17:21:17:24 | path | fastapi_path_injection.py:20:34:20:37 | path | provenance | | +| fastapi_path_injection.py:20:34:20:37 | path | fastapi_path_injection.py:6:24:6:31 | filepath | provenance | | +| fastapi_path_injection.py:31:21:31:24 | path | fastapi_path_injection.py:32:34:32:37 | path | provenance | | +| fastapi_path_injection.py:32:34:32:37 | path | fastapi_path_injection.py:6:24:6:31 | filepath | provenance | | +| fastapi_path_injection.py:48:21:48:24 | path | fastapi_path_injection.py:49:45:49:48 | path | provenance | | +| fastapi_path_injection.py:49:45:49:48 | path | fastapi_path_injection.py:6:24:6:31 | filepath | provenance | | +| flask_path_injection.py:1:26:1:32 | ImportMember | flask_path_injection.py:1:26:1:32 | request | provenance | | +| flask_path_injection.py:1:26:1:32 | request | flask_path_injection.py:19:15:19:21 | request | provenance | | +| flask_path_injection.py:19:5:19:11 | dirname | flask_path_injection.py:21:32:21:38 | dirname | provenance | | +| flask_path_injection.py:19:15:19:21 | request | flask_path_injection.py:19:15:19:26 | Attribute | provenance | AdditionalTaintStep | +| flask_path_injection.py:19:15:19:26 | Attribute | flask_path_injection.py:19:15:19:45 | Attribute() | provenance | dict.get | +| flask_path_injection.py:19:15:19:45 | Attribute() | flask_path_injection.py:19:5:19:11 | dirname | provenance | | +| path_injection.py:3:26:3:32 | ImportMember | path_injection.py:3:26:3:32 | request | provenance | | +| path_injection.py:3:26:3:32 | request | path_injection.py:12:16:12:22 | request | provenance | | +| path_injection.py:3:26:3:32 | request | path_injection.py:19:16:19:22 | request | provenance | | +| path_injection.py:3:26:3:32 | request | path_injection.py:27:16:27:22 | request | provenance | | +| path_injection.py:3:26:3:32 | request | path_injection.py:46:16:46:22 | request | provenance | | +| path_injection.py:3:26:3:32 | request | path_injection.py:63:16:63:22 | request | provenance | | +| path_injection.py:3:26:3:32 | request | path_injection.py:84:16:84:22 | request | provenance | | +| path_injection.py:3:26:3:32 | request | path_injection.py:107:16:107:22 | request | provenance | | +| path_injection.py:3:26:3:32 | request | path_injection.py:118:16:118:22 | request | provenance | | +| path_injection.py:3:26:3:32 | request | path_injection.py:129:16:129:22 | request | provenance | | +| path_injection.py:3:26:3:32 | request | path_injection.py:138:16:138:22 | request | provenance | | +| path_injection.py:3:26:3:32 | request | path_injection.py:149:16:149:22 | request | provenance | | +| path_injection.py:12:5:12:12 | filename | path_injection.py:13:14:13:47 | Attribute() | provenance | AdditionalTaintStep | +| path_injection.py:12:16:12:22 | request | path_injection.py:12:16:12:27 | Attribute | provenance | AdditionalTaintStep | +| path_injection.py:12:16:12:27 | Attribute | path_injection.py:12:16:12:47 | Attribute() | provenance | dict.get | +| path_injection.py:12:16:12:47 | Attribute() | path_injection.py:12:5:12:12 | filename | provenance | | +| path_injection.py:19:5:19:12 | filename | path_injection.py:20:30:20:63 | Attribute() | provenance | AdditionalTaintStep | +| path_injection.py:19:16:19:22 | request | path_injection.py:19:16:19:27 | Attribute | provenance | AdditionalTaintStep | +| path_injection.py:19:16:19:27 | Attribute | path_injection.py:19:16:19:47 | Attribute() | provenance | dict.get | +| path_injection.py:19:16:19:47 | Attribute() | path_injection.py:19:5:19:12 | filename | provenance | | +| path_injection.py:20:5:20:9 | npath | path_injection.py:21:14:21:18 | npath | provenance | | +| path_injection.py:20:13:20:64 | Attribute() | path_injection.py:20:5:20:9 | npath | provenance | | +| path_injection.py:20:30:20:63 | Attribute() | path_injection.py:20:13:20:64 | Attribute() | provenance | Config | +| path_injection.py:27:5:27:12 | filename | path_injection.py:28:30:28:63 | Attribute() | provenance | AdditionalTaintStep | +| path_injection.py:27:16:27:22 | request | path_injection.py:27:16:27:27 | Attribute | provenance | AdditionalTaintStep | +| path_injection.py:27:16:27:27 | Attribute | path_injection.py:27:16:27:47 | Attribute() | provenance | dict.get | +| path_injection.py:27:16:27:47 | Attribute() | path_injection.py:27:5:27:12 | filename | provenance | | +| path_injection.py:28:5:28:9 | npath | path_injection.py:31:14:31:18 | npath | provenance | | +| path_injection.py:28:13:28:64 | Attribute() | path_injection.py:28:5:28:9 | npath | provenance | | +| path_injection.py:28:30:28:63 | Attribute() | path_injection.py:28:13:28:64 | Attribute() | provenance | Config | +| path_injection.py:46:5:46:12 | filename | path_injection.py:47:30:47:63 | Attribute() | provenance | AdditionalTaintStep | +| path_injection.py:46:16:46:22 | request | path_injection.py:46:16:46:27 | Attribute | provenance | AdditionalTaintStep | +| path_injection.py:46:16:46:27 | Attribute | path_injection.py:46:16:46:47 | Attribute() | provenance | dict.get | +| path_injection.py:46:16:46:47 | Attribute() | path_injection.py:46:5:46:12 | filename | provenance | | +| path_injection.py:47:5:47:9 | npath | path_injection.py:48:14:48:18 | npath | provenance | | +| path_injection.py:47:13:47:64 | Attribute() | path_injection.py:47:5:47:9 | npath | provenance | | +| path_injection.py:47:30:47:63 | Attribute() | path_injection.py:47:13:47:64 | Attribute() | provenance | Config | +| path_injection.py:63:5:63:12 | filename | path_injection.py:64:29:64:62 | Attribute() | provenance | AdditionalTaintStep | +| path_injection.py:63:16:63:22 | request | path_injection.py:63:16:63:27 | Attribute | provenance | AdditionalTaintStep | +| path_injection.py:63:16:63:27 | Attribute | path_injection.py:63:16:63:47 | Attribute() | provenance | dict.get | +| path_injection.py:63:16:63:47 | Attribute() | path_injection.py:63:5:63:12 | filename | provenance | | +| path_injection.py:64:5:64:9 | npath | path_injection.py:65:14:65:18 | npath | provenance | | +| path_injection.py:64:13:64:63 | Attribute() | path_injection.py:64:5:64:9 | npath | provenance | | +| path_injection.py:64:29:64:62 | Attribute() | path_injection.py:64:13:64:63 | Attribute() | provenance | Config | +| path_injection.py:84:5:84:12 | filename | path_injection.py:85:5:85:24 | possibly_unsafe_path | provenance | AdditionalTaintStep | +| path_injection.py:84:16:84:22 | request | path_injection.py:84:16:84:27 | Attribute | provenance | AdditionalTaintStep | +| path_injection.py:84:16:84:27 | Attribute | path_injection.py:84:16:84:47 | Attribute() | provenance | dict.get | +| path_injection.py:84:16:84:47 | Attribute() | path_injection.py:84:5:84:12 | filename | provenance | | +| path_injection.py:85:5:85:24 | possibly_unsafe_path | path_injection.py:86:24:86:43 | possibly_unsafe_path | provenance | | +| path_injection.py:86:24:86:43 | possibly_unsafe_path | path_injection.py:87:18:87:37 | possibly_unsafe_path | provenance | | +| path_injection.py:91:20:91:25 | foo_id | path_injection.py:93:5:93:8 | path | provenance | AdditionalTaintStep | +| path_injection.py:93:5:93:8 | path | path_injection.py:94:14:94:17 | path | provenance | | +| path_injection.py:98:20:98:22 | foo | path_injection.py:101:5:101:8 | path | provenance | AdditionalTaintStep | +| path_injection.py:101:5:101:8 | path | path_injection.py:102:14:102:17 | path | provenance | | +| path_injection.py:107:5:107:12 | filename | path_injection.py:108:5:108:8 | path | provenance | AdditionalTaintStep | +| path_injection.py:107:16:107:22 | request | path_injection.py:107:16:107:27 | Attribute | provenance | AdditionalTaintStep | +| path_injection.py:107:16:107:27 | Attribute | path_injection.py:107:16:107:47 | Attribute() | provenance | dict.get | +| path_injection.py:107:16:107:47 | Attribute() | path_injection.py:107:5:107:12 | filename | provenance | | +| path_injection.py:108:5:108:8 | path | path_injection.py:113:14:113:17 | path | provenance | | +| path_injection.py:118:5:118:12 | filename | path_injection.py:119:5:119:8 | path | provenance | AdditionalTaintStep | +| path_injection.py:118:16:118:22 | request | path_injection.py:118:16:118:27 | Attribute | provenance | AdditionalTaintStep | +| path_injection.py:118:16:118:27 | Attribute | path_injection.py:118:16:118:47 | Attribute() | provenance | dict.get | +| path_injection.py:118:16:118:47 | Attribute() | path_injection.py:118:5:118:12 | filename | provenance | | +| path_injection.py:119:5:119:8 | path | path_injection.py:124:14:124:17 | path | provenance | | +| path_injection.py:129:5:129:12 | filename | path_injection.py:130:5:130:8 | path | provenance | AdditionalTaintStep | +| path_injection.py:129:16:129:22 | request | path_injection.py:129:16:129:27 | Attribute | provenance | AdditionalTaintStep | +| path_injection.py:129:16:129:27 | Attribute | path_injection.py:129:16:129:47 | Attribute() | provenance | dict.get | +| path_injection.py:129:16:129:47 | Attribute() | path_injection.py:129:5:129:12 | filename | provenance | | +| path_injection.py:130:5:130:8 | path | path_injection.py:131:5:131:13 | sanitized | provenance | | +| path_injection.py:131:5:131:13 | sanitized | path_injection.py:132:14:132:22 | sanitized | provenance | | +| path_injection.py:138:5:138:12 | filename | path_injection.py:139:5:139:8 | path | provenance | AdditionalTaintStep | +| path_injection.py:138:16:138:22 | request | path_injection.py:138:16:138:27 | Attribute | provenance | AdditionalTaintStep | +| path_injection.py:138:16:138:27 | Attribute | path_injection.py:138:16:138:47 | Attribute() | provenance | dict.get | +| path_injection.py:138:16:138:47 | Attribute() | path_injection.py:138:5:138:12 | filename | provenance | | +| path_injection.py:139:5:139:8 | path | path_injection.py:140:47:140:50 | path | provenance | | +| path_injection.py:140:47:140:50 | path | path_injection.py:142:14:142:17 | path | provenance | | +| path_injection.py:149:5:149:12 | filename | path_injection.py:151:9:151:12 | path | provenance | AdditionalTaintStep | +| path_injection.py:149:16:149:22 | request | path_injection.py:149:16:149:27 | Attribute | provenance | AdditionalTaintStep | +| path_injection.py:149:16:149:27 | Attribute | path_injection.py:149:16:149:47 | Attribute() | provenance | dict.get | +| path_injection.py:149:16:149:47 | Attribute() | path_injection.py:149:5:149:12 | filename | provenance | | +| path_injection.py:151:9:151:12 | path | path_injection.py:152:18:152:21 | path | provenance | | +| pathlib_use.py:3:26:3:32 | ImportMember | pathlib_use.py:3:26:3:32 | request | provenance | | +| pathlib_use.py:3:26:3:32 | request | pathlib_use.py:12:16:12:22 | request | provenance | | +| pathlib_use.py:12:5:12:12 | filename | pathlib_use.py:13:5:13:5 | p | provenance | AdditionalTaintStep | +| pathlib_use.py:12:5:12:12 | filename | pathlib_use.py:16:5:16:6 | p2 | provenance | AdditionalTaintStep | +| pathlib_use.py:12:16:12:22 | request | pathlib_use.py:12:16:12:27 | Attribute | provenance | AdditionalTaintStep | +| pathlib_use.py:12:16:12:27 | Attribute | pathlib_use.py:12:16:12:47 | Attribute() | provenance | dict.get | +| pathlib_use.py:12:16:12:47 | Attribute() | pathlib_use.py:12:5:12:12 | filename | provenance | | +| pathlib_use.py:13:5:13:5 | p | pathlib_use.py:14:5:14:5 | p | provenance | | +| pathlib_use.py:16:5:16:6 | p2 | pathlib_use.py:17:5:17:6 | p2 | provenance | | +| test.py:3:26:3:32 | ImportMember | test.py:3:26:3:32 | request | provenance | | +| test.py:3:26:3:32 | request | test.py:9:12:9:18 | request | provenance | | +| test.py:9:12:9:18 | request | test.py:9:12:9:23 | Attribute | provenance | AdditionalTaintStep | +| test.py:9:12:9:23 | Attribute | test.py:9:12:9:39 | Attribute() | provenance | dict.get | +| test.py:9:12:9:39 | Attribute() | test.py:18:9:18:16 | source() | provenance | | +| test.py:9:12:9:39 | Attribute() | test.py:24:9:24:16 | source() | provenance | | +| test.py:9:12:9:39 | Attribute() | test.py:31:9:31:16 | source() | provenance | | +| test.py:9:12:9:39 | Attribute() | test.py:46:9:46:16 | source() | provenance | | +| test.py:12:15:12:15 | x | test.py:13:29:13:29 | x | provenance | | +| test.py:13:29:13:29 | x | test.py:13:12:13:30 | Attribute() | provenance | Config | +| test.py:18:5:18:5 | x | test.py:19:10:19:10 | x | provenance | | +| test.py:18:9:18:16 | source() | test.py:18:5:18:5 | x | provenance | | +| test.py:24:5:24:5 | x | test.py:25:19:25:19 | x | provenance | | +| test.py:24:9:24:16 | source() | test.py:24:5:24:5 | x | provenance | | +| test.py:25:5:25:5 | y | test.py:26:10:26:10 | y | provenance | | +| test.py:25:9:25:20 | normalize() | test.py:25:5:25:5 | y | provenance | | +| test.py:25:19:25:19 | x | test.py:12:15:12:15 | x | provenance | | +| test.py:25:19:25:19 | x | test.py:25:9:25:20 | normalize() | provenance | Config | +| test.py:31:5:31:5 | x | test.py:33:14:33:14 | x | provenance | | +| test.py:31:9:31:16 | source() | test.py:31:5:31:5 | x | provenance | | +| test.py:46:5:46:5 | x | test.py:48:23:48:23 | x | provenance | | +| test.py:46:9:46:16 | source() | test.py:46:5:46:5 | x | provenance | | +| test.py:48:9:48:9 | y | test.py:49:14:49:14 | y | provenance | | +| test.py:48:13:48:24 | normalize() | test.py:48:9:48:9 | y | provenance | | +| test.py:48:23:48:23 | x | test.py:12:15:12:15 | x | provenance | | +| test.py:48:23:48:23 | x | test.py:48:13:48:24 | normalize() | provenance | Config | nodes -| fastapi_path_injection.py:6:24:6:31 | ControlFlowNode for filepath | semmle.label | ControlFlowNode for filepath | -| fastapi_path_injection.py:7:19:7:26 | ControlFlowNode for filepath | semmle.label | ControlFlowNode for filepath | -| fastapi_path_injection.py:17:21:17:24 | ControlFlowNode for path | semmle.label | ControlFlowNode for path | -| fastapi_path_injection.py:20:34:20:37 | ControlFlowNode for path | semmle.label | ControlFlowNode for path | -| fastapi_path_injection.py:26:21:26:24 | ControlFlowNode for path | semmle.label | ControlFlowNode for path | -| fastapi_path_injection.py:27:34:27:37 | ControlFlowNode for path | semmle.label | ControlFlowNode for path | -| fastapi_path_injection.py:31:21:31:24 | ControlFlowNode for path | semmle.label | ControlFlowNode for path | -| fastapi_path_injection.py:32:34:32:37 | ControlFlowNode for path | semmle.label | ControlFlowNode for path | -| fastapi_path_injection.py:48:21:48:24 | ControlFlowNode for path | semmle.label | ControlFlowNode for path | -| fastapi_path_injection.py:49:45:49:48 | ControlFlowNode for path | semmle.label | ControlFlowNode for path | -| flask_path_injection.py:1:26:1:32 | ControlFlowNode for ImportMember | semmle.label | ControlFlowNode for ImportMember | -| flask_path_injection.py:1:26:1:32 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| flask_path_injection.py:19:5:19:11 | ControlFlowNode for dirname | semmle.label | ControlFlowNode for dirname | -| flask_path_injection.py:19:15:19:21 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| flask_path_injection.py:19:15:19:26 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| flask_path_injection.py:19:15:19:45 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| flask_path_injection.py:21:32:21:38 | ControlFlowNode for dirname | semmle.label | ControlFlowNode for dirname | -| path_injection.py:3:26:3:32 | ControlFlowNode for ImportMember | semmle.label | ControlFlowNode for ImportMember | -| path_injection.py:3:26:3:32 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| path_injection.py:12:5:12:12 | ControlFlowNode for filename | semmle.label | ControlFlowNode for filename | -| path_injection.py:12:16:12:22 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| path_injection.py:12:16:12:27 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| path_injection.py:12:16:12:47 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| path_injection.py:13:14:13:47 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| path_injection.py:19:5:19:12 | ControlFlowNode for filename | semmle.label | ControlFlowNode for filename | -| path_injection.py:19:16:19:22 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| path_injection.py:19:16:19:27 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| path_injection.py:19:16:19:47 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| path_injection.py:20:5:20:9 | ControlFlowNode for npath | semmle.label | ControlFlowNode for npath | -| path_injection.py:20:13:20:64 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| path_injection.py:20:30:20:63 | 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:5:27:12 | ControlFlowNode for filename | semmle.label | ControlFlowNode for filename | -| path_injection.py:27:16:27:22 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| path_injection.py:27:16:27:27 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| path_injection.py:27:16:27:47 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| path_injection.py:28:5:28:9 | ControlFlowNode for npath | semmle.label | ControlFlowNode for npath | -| path_injection.py:28:13:28:64 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| path_injection.py:28:30:28:63 | 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:46:5:46:12 | ControlFlowNode for filename | semmle.label | ControlFlowNode for filename | -| path_injection.py:46:16:46:22 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| path_injection.py:46:16:46:27 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| path_injection.py:46:16:46:47 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| path_injection.py:47:5:47:9 | ControlFlowNode for npath | semmle.label | ControlFlowNode for npath | -| path_injection.py:47:13:47:64 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| path_injection.py:47:30:47:63 | 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:63:5:63:12 | ControlFlowNode for filename | semmle.label | ControlFlowNode for filename | -| path_injection.py:63:16:63:22 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| path_injection.py:63:16:63:27 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| path_injection.py:63:16:63:47 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| path_injection.py:64:5:64:9 | ControlFlowNode for npath | semmle.label | ControlFlowNode for npath | -| path_injection.py:64:13:64:63 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| path_injection.py:64:29:64:62 | 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:84:5:84:12 | ControlFlowNode for filename | semmle.label | ControlFlowNode for filename | -| path_injection.py:84:16:84:22 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| path_injection.py:84:16:84:27 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| path_injection.py:84:16:84:47 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| path_injection.py:85:5:85:24 | ControlFlowNode for possibly_unsafe_path | semmle.label | ControlFlowNode for possibly_unsafe_path | -| path_injection.py:86:24:86:43 | ControlFlowNode for possibly_unsafe_path | semmle.label | ControlFlowNode for possibly_unsafe_path | -| path_injection.py:87:18:87:37 | ControlFlowNode for possibly_unsafe_path | semmle.label | ControlFlowNode for possibly_unsafe_path | -| path_injection.py:91:20:91:25 | ControlFlowNode for foo_id | semmle.label | ControlFlowNode for foo_id | -| path_injection.py:93:5:93:8 | ControlFlowNode for path | semmle.label | ControlFlowNode for path | -| path_injection.py:94:14:94:17 | ControlFlowNode for path | semmle.label | ControlFlowNode for path | -| path_injection.py:98:20:98:22 | ControlFlowNode for foo | semmle.label | ControlFlowNode for foo | -| path_injection.py:101:5:101:8 | ControlFlowNode for path | semmle.label | ControlFlowNode for path | -| path_injection.py:102:14:102:17 | ControlFlowNode for path | semmle.label | ControlFlowNode for path | -| path_injection.py:107:5:107:12 | ControlFlowNode for filename | semmle.label | ControlFlowNode for filename | -| path_injection.py:107:16:107:22 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| path_injection.py:107:16:107:27 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| path_injection.py:107:16:107:47 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| path_injection.py:108:5:108:8 | ControlFlowNode for path | semmle.label | ControlFlowNode for path | -| path_injection.py:113:14:113:17 | ControlFlowNode for path | semmle.label | ControlFlowNode for path | -| path_injection.py:118:5:118:12 | ControlFlowNode for filename | semmle.label | ControlFlowNode for filename | -| path_injection.py:118:16:118:22 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| path_injection.py:118:16:118:27 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| path_injection.py:118:16:118:47 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| path_injection.py:119:5:119:8 | ControlFlowNode for path | semmle.label | ControlFlowNode for path | -| path_injection.py:124:14:124:17 | ControlFlowNode for path | semmle.label | ControlFlowNode for path | -| path_injection.py:129:5:129:12 | ControlFlowNode for filename | semmle.label | ControlFlowNode for filename | -| path_injection.py:129:16:129:22 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| path_injection.py:129:16:129:27 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| path_injection.py:129:16:129:47 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| path_injection.py:130:5:130:8 | ControlFlowNode for path | semmle.label | ControlFlowNode for path | -| path_injection.py:131:5:131:13 | ControlFlowNode for sanitized | semmle.label | ControlFlowNode for sanitized | -| path_injection.py:132:14:132:22 | ControlFlowNode for sanitized | semmle.label | ControlFlowNode for sanitized | -| path_injection.py:138:5:138:12 | ControlFlowNode for filename | semmle.label | ControlFlowNode for filename | -| path_injection.py:138:16:138:22 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| path_injection.py:138:16:138:27 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| path_injection.py:138:16:138:47 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| path_injection.py:139:5:139:8 | ControlFlowNode for path | semmle.label | ControlFlowNode for path | -| path_injection.py:140:47:140:50 | ControlFlowNode for path | semmle.label | ControlFlowNode for path | -| path_injection.py:142:14:142:17 | ControlFlowNode for path | semmle.label | ControlFlowNode for path | -| path_injection.py:149:5:149:12 | ControlFlowNode for filename | semmle.label | ControlFlowNode for filename | -| path_injection.py:149:16:149:22 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| path_injection.py:149:16:149:27 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| path_injection.py:149:16:149:47 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| path_injection.py:151:9:151:12 | ControlFlowNode for path | semmle.label | ControlFlowNode for path | -| path_injection.py:152:18:152:21 | ControlFlowNode for path | semmle.label | ControlFlowNode for path | -| pathlib_use.py:3:26:3:32 | ControlFlowNode for ImportMember | semmle.label | ControlFlowNode for ImportMember | -| pathlib_use.py:3:26:3:32 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| pathlib_use.py:12:5:12:12 | ControlFlowNode for filename | semmle.label | ControlFlowNode for filename | -| pathlib_use.py:12:16:12:22 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| pathlib_use.py:12:16:12:27 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| pathlib_use.py:12:16:12:47 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| pathlib_use.py:13:5:13:5 | ControlFlowNode for p | semmle.label | ControlFlowNode for p | -| pathlib_use.py:14:5:14:5 | ControlFlowNode for p | semmle.label | ControlFlowNode for p | -| pathlib_use.py:16:5:16:6 | ControlFlowNode for p2 | semmle.label | ControlFlowNode for p2 | -| pathlib_use.py:17:5:17:6 | ControlFlowNode for p2 | semmle.label | ControlFlowNode for p2 | -| test.py:3:26:3:32 | ControlFlowNode for ImportMember | semmle.label | ControlFlowNode for ImportMember | -| test.py:3:26:3:32 | 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:23 | 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 | -| test.py:13:12:13:30 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| test.py:13:29:13:29 | ControlFlowNode for x | semmle.label | ControlFlowNode for x | -| test.py:18:5:18:5 | ControlFlowNode for x | semmle.label | ControlFlowNode for x | -| test.py:18:9:18:16 | ControlFlowNode for source() | semmle.label | ControlFlowNode for source() | -| test.py:19:10:19:10 | ControlFlowNode for x | semmle.label | ControlFlowNode for x | -| test.py:24:5:24:5 | ControlFlowNode for x | semmle.label | ControlFlowNode for x | -| test.py:24:9:24:16 | ControlFlowNode for source() | semmle.label | ControlFlowNode for source() | -| test.py:25:5:25:5 | ControlFlowNode for y | semmle.label | ControlFlowNode for y | -| test.py:25:9:25:20 | ControlFlowNode for normalize() | semmle.label | ControlFlowNode for normalize() | -| test.py:25:19:25:19 | ControlFlowNode for x | semmle.label | ControlFlowNode for x | -| test.py:26:10:26:10 | ControlFlowNode for y | semmle.label | ControlFlowNode for y | -| test.py:31:5:31:5 | ControlFlowNode for x | semmle.label | ControlFlowNode for x | -| test.py:31:9:31:16 | ControlFlowNode for source() | semmle.label | ControlFlowNode for source() | -| test.py:33:14:33:14 | ControlFlowNode for x | semmle.label | ControlFlowNode for x | -| test.py:46:5:46:5 | ControlFlowNode for x | semmle.label | ControlFlowNode for x | -| test.py:46:9:46:16 | ControlFlowNode for source() | semmle.label | ControlFlowNode for source() | -| test.py:48:9:48:9 | ControlFlowNode for y | semmle.label | ControlFlowNode for y | -| 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 | +| fastapi_path_injection.py:6:24:6:31 | filepath | semmle.label | filepath | +| fastapi_path_injection.py:7:19:7:26 | filepath | semmle.label | filepath | +| fastapi_path_injection.py:17:21:17:24 | path | semmle.label | path | +| fastapi_path_injection.py:20:34:20:37 | path | semmle.label | path | +| fastapi_path_injection.py:31:21:31:24 | path | semmle.label | path | +| fastapi_path_injection.py:32:34:32:37 | path | semmle.label | path | +| fastapi_path_injection.py:48:21:48:24 | path | semmle.label | path | +| fastapi_path_injection.py:49:45:49:48 | path | semmle.label | path | +| flask_path_injection.py:1:26:1:32 | ImportMember | semmle.label | ImportMember | +| flask_path_injection.py:1:26:1:32 | request | semmle.label | request | +| flask_path_injection.py:19:5:19:11 | dirname | semmle.label | dirname | +| flask_path_injection.py:19:15:19:21 | request | semmle.label | request | +| flask_path_injection.py:19:15:19:26 | Attribute | semmle.label | Attribute | +| flask_path_injection.py:19:15:19:45 | Attribute() | semmle.label | Attribute() | +| flask_path_injection.py:21:32:21:38 | dirname | semmle.label | dirname | +| path_injection.py:3:26:3:32 | ImportMember | semmle.label | ImportMember | +| path_injection.py:3:26:3:32 | request | semmle.label | request | +| path_injection.py:12:5:12:12 | filename | semmle.label | filename | +| path_injection.py:12:16:12:22 | request | semmle.label | request | +| path_injection.py:12:16:12:27 | Attribute | semmle.label | Attribute | +| path_injection.py:12:16:12:47 | Attribute() | semmle.label | Attribute() | +| path_injection.py:13:14:13:47 | Attribute() | semmle.label | Attribute() | +| path_injection.py:19:5:19:12 | filename | semmle.label | filename | +| path_injection.py:19:16:19:22 | request | semmle.label | request | +| path_injection.py:19:16:19:27 | Attribute | semmle.label | Attribute | +| path_injection.py:19:16:19:47 | Attribute() | semmle.label | Attribute() | +| path_injection.py:20:5:20:9 | npath | semmle.label | npath | +| path_injection.py:20:13:20:64 | Attribute() | semmle.label | Attribute() | +| path_injection.py:20:30:20:63 | Attribute() | semmle.label | Attribute() | +| path_injection.py:21:14:21:18 | npath | semmle.label | npath | +| path_injection.py:27:5:27:12 | filename | semmle.label | filename | +| path_injection.py:27:16:27:22 | request | semmle.label | request | +| path_injection.py:27:16:27:27 | Attribute | semmle.label | Attribute | +| path_injection.py:27:16:27:47 | Attribute() | semmle.label | Attribute() | +| path_injection.py:28:5:28:9 | npath | semmle.label | npath | +| path_injection.py:28:13:28:64 | Attribute() | semmle.label | Attribute() | +| path_injection.py:28:30:28:63 | Attribute() | semmle.label | Attribute() | +| path_injection.py:31:14:31:18 | npath | semmle.label | npath | +| path_injection.py:46:5:46:12 | filename | semmle.label | filename | +| path_injection.py:46:16:46:22 | request | semmle.label | request | +| path_injection.py:46:16:46:27 | Attribute | semmle.label | Attribute | +| path_injection.py:46:16:46:47 | Attribute() | semmle.label | Attribute() | +| path_injection.py:47:5:47:9 | npath | semmle.label | npath | +| path_injection.py:47:13:47:64 | Attribute() | semmle.label | Attribute() | +| path_injection.py:47:30:47:63 | Attribute() | semmle.label | Attribute() | +| path_injection.py:48:14:48:18 | npath | semmle.label | npath | +| path_injection.py:63:5:63:12 | filename | semmle.label | filename | +| path_injection.py:63:16:63:22 | request | semmle.label | request | +| path_injection.py:63:16:63:27 | Attribute | semmle.label | Attribute | +| path_injection.py:63:16:63:47 | Attribute() | semmle.label | Attribute() | +| path_injection.py:64:5:64:9 | npath | semmle.label | npath | +| path_injection.py:64:13:64:63 | Attribute() | semmle.label | Attribute() | +| path_injection.py:64:29:64:62 | Attribute() | semmle.label | Attribute() | +| path_injection.py:65:14:65:18 | npath | semmle.label | npath | +| path_injection.py:84:5:84:12 | filename | semmle.label | filename | +| path_injection.py:84:16:84:22 | request | semmle.label | request | +| path_injection.py:84:16:84:27 | Attribute | semmle.label | Attribute | +| path_injection.py:84:16:84:47 | Attribute() | semmle.label | Attribute() | +| path_injection.py:85:5:85:24 | possibly_unsafe_path | semmle.label | possibly_unsafe_path | +| path_injection.py:86:24:86:43 | possibly_unsafe_path | semmle.label | possibly_unsafe_path | +| path_injection.py:87:18:87:37 | possibly_unsafe_path | semmle.label | possibly_unsafe_path | +| path_injection.py:91:20:91:25 | foo_id | semmle.label | foo_id | +| path_injection.py:93:5:93:8 | path | semmle.label | path | +| path_injection.py:94:14:94:17 | path | semmle.label | path | +| path_injection.py:98:20:98:22 | foo | semmle.label | foo | +| path_injection.py:101:5:101:8 | path | semmle.label | path | +| path_injection.py:102:14:102:17 | path | semmle.label | path | +| path_injection.py:107:5:107:12 | filename | semmle.label | filename | +| path_injection.py:107:16:107:22 | request | semmle.label | request | +| path_injection.py:107:16:107:27 | Attribute | semmle.label | Attribute | +| path_injection.py:107:16:107:47 | Attribute() | semmle.label | Attribute() | +| path_injection.py:108:5:108:8 | path | semmle.label | path | +| path_injection.py:113:14:113:17 | path | semmle.label | path | +| path_injection.py:118:5:118:12 | filename | semmle.label | filename | +| path_injection.py:118:16:118:22 | request | semmle.label | request | +| path_injection.py:118:16:118:27 | Attribute | semmle.label | Attribute | +| path_injection.py:118:16:118:47 | Attribute() | semmle.label | Attribute() | +| path_injection.py:119:5:119:8 | path | semmle.label | path | +| path_injection.py:124:14:124:17 | path | semmle.label | path | +| path_injection.py:129:5:129:12 | filename | semmle.label | filename | +| path_injection.py:129:16:129:22 | request | semmle.label | request | +| path_injection.py:129:16:129:27 | Attribute | semmle.label | Attribute | +| path_injection.py:129:16:129:47 | Attribute() | semmle.label | Attribute() | +| path_injection.py:130:5:130:8 | path | semmle.label | path | +| path_injection.py:131:5:131:13 | sanitized | semmle.label | sanitized | +| path_injection.py:132:14:132:22 | sanitized | semmle.label | sanitized | +| path_injection.py:138:5:138:12 | filename | semmle.label | filename | +| path_injection.py:138:16:138:22 | request | semmle.label | request | +| path_injection.py:138:16:138:27 | Attribute | semmle.label | Attribute | +| path_injection.py:138:16:138:47 | Attribute() | semmle.label | Attribute() | +| path_injection.py:139:5:139:8 | path | semmle.label | path | +| path_injection.py:140:47:140:50 | path | semmle.label | path | +| path_injection.py:142:14:142:17 | path | semmle.label | path | +| path_injection.py:149:5:149:12 | filename | semmle.label | filename | +| path_injection.py:149:16:149:22 | request | semmle.label | request | +| path_injection.py:149:16:149:27 | Attribute | semmle.label | Attribute | +| path_injection.py:149:16:149:47 | Attribute() | semmle.label | Attribute() | +| path_injection.py:151:9:151:12 | path | semmle.label | path | +| path_injection.py:152:18:152:21 | path | semmle.label | path | +| pathlib_use.py:3:26:3:32 | ImportMember | semmle.label | ImportMember | +| pathlib_use.py:3:26:3:32 | request | semmle.label | request | +| pathlib_use.py:12:5:12:12 | filename | semmle.label | filename | +| pathlib_use.py:12:16:12:22 | request | semmle.label | request | +| pathlib_use.py:12:16:12:27 | Attribute | semmle.label | Attribute | +| pathlib_use.py:12:16:12:47 | Attribute() | semmle.label | Attribute() | +| pathlib_use.py:13:5:13:5 | p | semmle.label | p | +| pathlib_use.py:14:5:14:5 | p | semmle.label | p | +| pathlib_use.py:16:5:16:6 | p2 | semmle.label | p2 | +| pathlib_use.py:17:5:17:6 | p2 | semmle.label | p2 | +| test.py:3:26:3:32 | ImportMember | semmle.label | ImportMember | +| test.py:3:26:3:32 | request | semmle.label | request | +| test.py:9:12:9:18 | request | semmle.label | request | +| test.py:9:12:9:23 | Attribute | semmle.label | Attribute | +| test.py:9:12:9:39 | Attribute() | semmle.label | Attribute() | +| test.py:12:15:12:15 | x | semmle.label | x | +| test.py:13:12:13:30 | Attribute() | semmle.label | Attribute() | +| test.py:13:29:13:29 | x | semmle.label | x | +| test.py:18:5:18:5 | x | semmle.label | x | +| test.py:18:9:18:16 | source() | semmle.label | source() | +| test.py:19:10:19:10 | x | semmle.label | x | +| test.py:24:5:24:5 | x | semmle.label | x | +| test.py:24:9:24:16 | source() | semmle.label | source() | +| test.py:25:5:25:5 | y | semmle.label | y | +| test.py:25:9:25:20 | normalize() | semmle.label | normalize() | +| test.py:25:19:25:19 | x | semmle.label | x | +| test.py:26:10:26:10 | y | semmle.label | y | +| test.py:31:5:31:5 | x | semmle.label | x | +| test.py:31:9:31:16 | source() | semmle.label | source() | +| test.py:33:14:33:14 | x | semmle.label | x | +| test.py:46:5:46:5 | x | semmle.label | x | +| test.py:46:9:46:16 | source() | semmle.label | source() | +| test.py:48:9:48:9 | y | semmle.label | y | +| test.py:48:13:48:24 | normalize() | semmle.label | normalize() | +| test.py:48:23:48:23 | x | semmle.label | x | +| test.py:49:14:49:14 | y | semmle.label | y | subpaths -| test.py:25:19:25:19 | ControlFlowNode for x | test.py:12:15:12:15 | ControlFlowNode for x | test.py:13:12:13:30 | ControlFlowNode for Attribute() | test.py:25:9:25:20 | ControlFlowNode for normalize() | -| test.py:48:23:48:23 | ControlFlowNode for x | test.py:12:15:12:15 | ControlFlowNode for x | test.py:13:12:13:30 | ControlFlowNode for Attribute() | test.py:48:13:48:24 | ControlFlowNode for normalize() | +| test.py:25:19:25:19 | x | test.py:12:15:12:15 | x | test.py:13:12:13:30 | Attribute() | test.py:25:9:25:20 | normalize() | +| test.py:48:23:48:23 | x | test.py:12:15:12:15 | x | test.py:13:12:13:30 | Attribute() | test.py:48:13:48:24 | normalize() | +testFailures +| fastapi_path_injection.py:26:72:26:81 | Comment # $ Source | Missing result: Source | diff --git a/python/ql/test/query-tests/Security/CWE-022-TarSlip/TarSlip.expected b/python/ql/test/query-tests/Security/CWE-022-TarSlip/TarSlip.expected index abdccddd631b..412ac072854c 100644 --- a/python/ql/test/query-tests/Security/CWE-022-TarSlip/TarSlip.expected +++ b/python/ql/test/query-tests/Security/CWE-022-TarSlip/TarSlip.expected @@ -1,66 +1,66 @@ -#select -| tarslip.py:15:1:15:3 | ControlFlowNode for tar | tarslip.py:14:7:14:39 | ControlFlowNode for Attribute() | tarslip.py:15:1:15:3 | ControlFlowNode for tar | This file extraction depends on a $@. | tarslip.py:14:7:14:39 | ControlFlowNode for Attribute() | potentially untrusted source | -| tarslip.py:20:17:20:21 | ControlFlowNode for entry | tarslip.py:18:7:18:39 | ControlFlowNode for Attribute() | tarslip.py:20:17:20:21 | ControlFlowNode for entry | This file extraction depends on a $@. | tarslip.py:18:7:18:39 | ControlFlowNode for Attribute() | potentially untrusted source | -| tarslip.py:39:17:39:21 | ControlFlowNode for entry | tarslip.py:35:7:35:39 | ControlFlowNode for Attribute() | tarslip.py:39:17:39:21 | ControlFlowNode for entry | This file extraction depends on a $@. | tarslip.py:35:7:35:39 | ControlFlowNode for Attribute() | potentially untrusted source | -| tarslip.py:43:24:43:26 | ControlFlowNode for tar | tarslip.py:42:7:42:39 | ControlFlowNode for Attribute() | tarslip.py:43:24:43:26 | ControlFlowNode for tar | This file extraction depends on a $@. | tarslip.py:42:7:42:39 | ControlFlowNode for Attribute() | potentially untrusted source | -| tarslip.py:61:21:61:25 | ControlFlowNode for entry | tarslip.py:58:7:58:39 | ControlFlowNode for Attribute() | tarslip.py:61:21:61:25 | ControlFlowNode for entry | This file extraction depends on a $@. | tarslip.py:58:7:58:39 | ControlFlowNode for Attribute() | potentially untrusted source | -| tarslip.py:91:1:91:3 | ControlFlowNode for tar | tarslip.py:90:7:90:39 | ControlFlowNode for Attribute() | tarslip.py:91:1:91:3 | ControlFlowNode for tar | This file extraction depends on a $@. | tarslip.py:90:7:90:39 | ControlFlowNode for Attribute() | potentially untrusted source | -| tarslip.py:96:17:96:21 | ControlFlowNode for entry | tarslip.py:94:7:94:39 | ControlFlowNode for Attribute() | tarslip.py:96:17:96:21 | ControlFlowNode for entry | This file extraction depends on a $@. | tarslip.py:94:7:94:39 | ControlFlowNode for Attribute() | potentially untrusted source | -| tarslip.py:110:1:110:3 | ControlFlowNode for tar | tarslip.py:109:7:109:39 | ControlFlowNode for Attribute() | tarslip.py:110:1:110:3 | ControlFlowNode for tar | This file extraction depends on a $@. | tarslip.py:109:7:109:39 | ControlFlowNode for Attribute() | potentially untrusted source | -| tarslip.py:113:24:113:26 | ControlFlowNode for tar | tarslip.py:112:7:112:39 | ControlFlowNode for Attribute() | tarslip.py:113:24:113:26 | ControlFlowNode for tar | This file extraction depends on a $@. | tarslip.py:112:7:112:39 | ControlFlowNode for Attribute() | potentially untrusted source | edges -| tarslip.py:14:1:14:3 | ControlFlowNode for tar | tarslip.py:15:1:15:3 | ControlFlowNode for tar | provenance | | -| tarslip.py:14:7:14:39 | ControlFlowNode for Attribute() | tarslip.py:14:1:14:3 | ControlFlowNode for tar | provenance | | -| tarslip.py:18:1:18:3 | ControlFlowNode for tar | tarslip.py:19:5:19:9 | ControlFlowNode for entry | provenance | | -| tarslip.py:18:7:18:39 | ControlFlowNode for Attribute() | tarslip.py:18:1:18:3 | ControlFlowNode for tar | provenance | | -| tarslip.py:19:5:19:9 | ControlFlowNode for entry | tarslip.py:20:17:20:21 | ControlFlowNode for entry | provenance | | -| tarslip.py:35:1:35:3 | ControlFlowNode for tar | tarslip.py:36:5:36:9 | ControlFlowNode for entry | provenance | | -| tarslip.py:35:7:35:39 | ControlFlowNode for Attribute() | tarslip.py:35:1:35:3 | ControlFlowNode for tar | provenance | | -| tarslip.py:36:5:36:9 | ControlFlowNode for entry | tarslip.py:39:17:39:21 | ControlFlowNode for entry | provenance | | -| tarslip.py:42:1:42:3 | ControlFlowNode for tar | tarslip.py:43:24:43:26 | ControlFlowNode for tar | provenance | | -| tarslip.py:42:7:42:39 | ControlFlowNode for Attribute() | tarslip.py:42:1:42:3 | ControlFlowNode for tar | provenance | | -| tarslip.py:58:1:58:3 | ControlFlowNode for tar | tarslip.py:59:5:59:9 | ControlFlowNode for entry | provenance | | -| tarslip.py:58:7:58:39 | ControlFlowNode for Attribute() | tarslip.py:58:1:58:3 | ControlFlowNode for tar | provenance | | -| tarslip.py:59:5:59:9 | ControlFlowNode for entry | tarslip.py:61:21:61:25 | ControlFlowNode for entry | provenance | | -| tarslip.py:90:1:90:3 | ControlFlowNode for tar | tarslip.py:91:1:91:3 | ControlFlowNode for tar | provenance | | -| tarslip.py:90:7:90:39 | ControlFlowNode for Attribute() | tarslip.py:90:1:90:3 | ControlFlowNode for tar | provenance | | -| tarslip.py:94:1:94:3 | ControlFlowNode for tar | tarslip.py:95:5:95:9 | ControlFlowNode for entry | provenance | | -| tarslip.py:94:7:94:39 | ControlFlowNode for Attribute() | tarslip.py:94:1:94:3 | ControlFlowNode for tar | provenance | | -| tarslip.py:95:5:95:9 | ControlFlowNode for entry | tarslip.py:96:17:96:21 | ControlFlowNode for entry | provenance | | -| tarslip.py:109:1:109:3 | ControlFlowNode for tar | tarslip.py:110:1:110:3 | ControlFlowNode for tar | provenance | | -| tarslip.py:109:7:109:39 | ControlFlowNode for Attribute() | tarslip.py:109:1:109:3 | ControlFlowNode for tar | provenance | | -| tarslip.py:112:1:112:3 | ControlFlowNode for tar | tarslip.py:113:24:113:26 | ControlFlowNode for tar | provenance | | -| tarslip.py:112:7:112:39 | ControlFlowNode for Attribute() | tarslip.py:112:1:112:3 | ControlFlowNode for tar | provenance | | +| tarslip.py:14:1:14:3 | tar | tarslip.py:15:1:15:3 | tar | provenance | | +| tarslip.py:14:7:14:39 | After Attribute() | tarslip.py:14:1:14:3 | tar | provenance | | +| tarslip.py:18:1:18:3 | tar | tarslip.py:19:5:19:9 | entry | provenance | | +| tarslip.py:18:7:18:39 | After Attribute() | tarslip.py:18:1:18:3 | tar | provenance | | +| tarslip.py:19:5:19:9 | entry | tarslip.py:20:17:20:21 | entry | provenance | | +| tarslip.py:35:1:35:3 | tar | tarslip.py:36:5:36:9 | entry | provenance | | +| tarslip.py:35:7:35:39 | After Attribute() | tarslip.py:35:1:35:3 | tar | provenance | | +| tarslip.py:36:5:36:9 | entry | tarslip.py:39:17:39:21 | entry | provenance | | +| tarslip.py:42:1:42:3 | tar | tarslip.py:43:24:43:26 | tar | provenance | | +| tarslip.py:42:7:42:39 | After Attribute() | tarslip.py:42:1:42:3 | tar | provenance | | +| tarslip.py:58:1:58:3 | tar | tarslip.py:59:5:59:9 | entry | provenance | | +| tarslip.py:58:7:58:39 | After Attribute() | tarslip.py:58:1:58:3 | tar | provenance | | +| tarslip.py:59:5:59:9 | entry | tarslip.py:61:21:61:25 | entry | provenance | | +| tarslip.py:90:1:90:3 | tar | tarslip.py:91:1:91:3 | tar | provenance | | +| tarslip.py:90:7:90:39 | After Attribute() | tarslip.py:90:1:90:3 | tar | provenance | | +| tarslip.py:94:1:94:3 | tar | tarslip.py:95:5:95:9 | entry | provenance | | +| tarslip.py:94:7:94:39 | After Attribute() | tarslip.py:94:1:94:3 | tar | provenance | | +| tarslip.py:95:5:95:9 | entry | tarslip.py:96:17:96:21 | entry | provenance | | +| tarslip.py:109:1:109:3 | tar | tarslip.py:110:1:110:3 | tar | provenance | | +| tarslip.py:109:7:109:39 | After Attribute() | tarslip.py:109:1:109:3 | tar | provenance | | +| tarslip.py:112:1:112:3 | tar | tarslip.py:113:24:113:26 | tar | provenance | | +| tarslip.py:112:7:112:39 | After Attribute() | tarslip.py:112:1:112:3 | tar | provenance | | nodes -| tarslip.py:14:1:14:3 | ControlFlowNode for tar | semmle.label | ControlFlowNode for tar | -| tarslip.py:14:7:14:39 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| tarslip.py:15:1:15:3 | ControlFlowNode for tar | semmle.label | ControlFlowNode for tar | -| tarslip.py:18:1:18:3 | ControlFlowNode for tar | semmle.label | ControlFlowNode for tar | -| tarslip.py:18:7:18:39 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| tarslip.py:19:5:19:9 | ControlFlowNode for entry | semmle.label | ControlFlowNode for entry | -| tarslip.py:20:17:20:21 | ControlFlowNode for entry | semmle.label | ControlFlowNode for entry | -| tarslip.py:35:1:35:3 | ControlFlowNode for tar | semmle.label | ControlFlowNode for tar | -| tarslip.py:35:7:35:39 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| tarslip.py:36:5:36:9 | ControlFlowNode for entry | semmle.label | ControlFlowNode for entry | -| tarslip.py:39:17:39:21 | ControlFlowNode for entry | semmle.label | ControlFlowNode for entry | -| tarslip.py:42:1:42:3 | ControlFlowNode for tar | semmle.label | ControlFlowNode for tar | -| tarslip.py:42:7:42:39 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| tarslip.py:43:24:43:26 | ControlFlowNode for tar | semmle.label | ControlFlowNode for tar | -| tarslip.py:58:1:58:3 | ControlFlowNode for tar | semmle.label | ControlFlowNode for tar | -| tarslip.py:58:7:58:39 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| tarslip.py:59:5:59:9 | ControlFlowNode for entry | semmle.label | ControlFlowNode for entry | -| tarslip.py:61:21:61:25 | ControlFlowNode for entry | semmle.label | ControlFlowNode for entry | -| tarslip.py:90:1:90:3 | ControlFlowNode for tar | semmle.label | ControlFlowNode for tar | -| tarslip.py:90:7:90:39 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| tarslip.py:91:1:91:3 | ControlFlowNode for tar | semmle.label | ControlFlowNode for tar | -| tarslip.py:94:1:94:3 | ControlFlowNode for tar | semmle.label | ControlFlowNode for tar | -| tarslip.py:94:7:94:39 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| tarslip.py:95:5:95:9 | ControlFlowNode for entry | semmle.label | ControlFlowNode for entry | -| tarslip.py:96:17:96:21 | ControlFlowNode for entry | semmle.label | ControlFlowNode for entry | -| tarslip.py:109:1:109:3 | ControlFlowNode for tar | semmle.label | ControlFlowNode for tar | -| tarslip.py:109:7:109:39 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| tarslip.py:110:1:110:3 | ControlFlowNode for tar | semmle.label | ControlFlowNode for tar | -| tarslip.py:112:1:112:3 | ControlFlowNode for tar | semmle.label | ControlFlowNode for tar | -| tarslip.py:112:7:112:39 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| tarslip.py:113:24:113:26 | ControlFlowNode for tar | semmle.label | ControlFlowNode for tar | +| tarslip.py:14:1:14:3 | tar | semmle.label | tar | +| tarslip.py:14:7:14:39 | After Attribute() | semmle.label | After Attribute() | +| tarslip.py:15:1:15:3 | tar | semmle.label | tar | +| tarslip.py:18:1:18:3 | tar | semmle.label | tar | +| tarslip.py:18:7:18:39 | After Attribute() | semmle.label | After Attribute() | +| tarslip.py:19:5:19:9 | entry | semmle.label | entry | +| tarslip.py:20:17:20:21 | entry | semmle.label | entry | +| tarslip.py:35:1:35:3 | tar | semmle.label | tar | +| tarslip.py:35:7:35:39 | After Attribute() | semmle.label | After Attribute() | +| tarslip.py:36:5:36:9 | entry | semmle.label | entry | +| tarslip.py:39:17:39:21 | entry | semmle.label | entry | +| tarslip.py:42:1:42:3 | tar | semmle.label | tar | +| tarslip.py:42:7:42:39 | After Attribute() | semmle.label | After Attribute() | +| tarslip.py:43:24:43:26 | tar | semmle.label | tar | +| tarslip.py:58:1:58:3 | tar | semmle.label | tar | +| tarslip.py:58:7:58:39 | After Attribute() | semmle.label | After Attribute() | +| tarslip.py:59:5:59:9 | entry | semmle.label | entry | +| tarslip.py:61:21:61:25 | entry | semmle.label | entry | +| tarslip.py:90:1:90:3 | tar | semmle.label | tar | +| tarslip.py:90:7:90:39 | After Attribute() | semmle.label | After Attribute() | +| tarslip.py:91:1:91:3 | tar | semmle.label | tar | +| tarslip.py:94:1:94:3 | tar | semmle.label | tar | +| tarslip.py:94:7:94:39 | After Attribute() | semmle.label | After Attribute() | +| tarslip.py:95:5:95:9 | entry | semmle.label | entry | +| tarslip.py:96:17:96:21 | entry | semmle.label | entry | +| tarslip.py:109:1:109:3 | tar | semmle.label | tar | +| tarslip.py:109:7:109:39 | After Attribute() | semmle.label | After Attribute() | +| tarslip.py:110:1:110:3 | tar | semmle.label | tar | +| tarslip.py:112:1:112:3 | tar | semmle.label | tar | +| tarslip.py:112:7:112:39 | After Attribute() | semmle.label | After Attribute() | +| tarslip.py:113:24:113:26 | tar | semmle.label | tar | subpaths +#select +| tarslip.py:15:1:15:3 | tar | tarslip.py:14:7:14:39 | After Attribute() | tarslip.py:15:1:15:3 | tar | This file extraction depends on a $@. | tarslip.py:14:7:14:39 | After Attribute() | potentially untrusted source | +| tarslip.py:20:17:20:21 | entry | tarslip.py:18:7:18:39 | After Attribute() | tarslip.py:20:17:20:21 | entry | This file extraction depends on a $@. | tarslip.py:18:7:18:39 | After Attribute() | potentially untrusted source | +| tarslip.py:39:17:39:21 | entry | tarslip.py:35:7:35:39 | After Attribute() | tarslip.py:39:17:39:21 | entry | This file extraction depends on a $@. | tarslip.py:35:7:35:39 | After Attribute() | potentially untrusted source | +| tarslip.py:43:24:43:26 | tar | tarslip.py:42:7:42:39 | After Attribute() | tarslip.py:43:24:43:26 | tar | This file extraction depends on a $@. | tarslip.py:42:7:42:39 | After Attribute() | potentially untrusted source | +| tarslip.py:61:21:61:25 | entry | tarslip.py:58:7:58:39 | After Attribute() | tarslip.py:61:21:61:25 | entry | This file extraction depends on a $@. | tarslip.py:58:7:58:39 | After Attribute() | potentially untrusted source | +| tarslip.py:91:1:91:3 | tar | tarslip.py:90:7:90:39 | After Attribute() | tarslip.py:91:1:91:3 | tar | This file extraction depends on a $@. | tarslip.py:90:7:90:39 | After Attribute() | potentially untrusted source | +| tarslip.py:96:17:96:21 | entry | tarslip.py:94:7:94:39 | After Attribute() | tarslip.py:96:17:96:21 | entry | This file extraction depends on a $@. | tarslip.py:94:7:94:39 | After Attribute() | potentially untrusted source | +| tarslip.py:110:1:110:3 | tar | tarslip.py:109:7:109:39 | After Attribute() | tarslip.py:110:1:110:3 | tar | This file extraction depends on a $@. | tarslip.py:109:7:109:39 | After Attribute() | potentially untrusted source | +| tarslip.py:113:24:113:26 | tar | tarslip.py:112:7:112:39 | After Attribute() | tarslip.py:113:24:113:26 | tar | This file extraction depends on a $@. | tarslip.py:112:7:112:39 | After Attribute() | potentially untrusted source | diff --git a/python/ql/test/query-tests/Security/CWE-074-TemplateInjection/TemplateInjection.expected b/python/ql/test/query-tests/Security/CWE-074-TemplateInjection/TemplateInjection.expected index a4bf57e174c1..4e0761057862 100644 --- a/python/ql/test/query-tests/Security/CWE-074-TemplateInjection/TemplateInjection.expected +++ b/python/ql/test/query-tests/Security/CWE-074-TemplateInjection/TemplateInjection.expected @@ -1,16 +1,16 @@ -#select -| JinjaSsti.py:10:18:10:25 | ControlFlowNode for template | JinjaSsti.py:7:7:7:13 | ControlFlowNode for request | JinjaSsti.py:10:18:10:25 | ControlFlowNode for template | This template construction depends on a $@. | JinjaSsti.py:7:7:7:13 | ControlFlowNode for request | user-provided value | -| JinjaSsti.py:21:25:21:32 | ControlFlowNode for template | JinjaSsti.py:16:7:16:13 | ControlFlowNode for request | JinjaSsti.py:21:25:21:32 | ControlFlowNode for template | This template construction depends on a $@. | JinjaSsti.py:16:7:16:13 | ControlFlowNode for request | user-provided value | edges -| JinjaSsti.py:7:7:7:13 | ControlFlowNode for request | JinjaSsti.py:9:5:9:12 | ControlFlowNode for template | provenance | AdditionalTaintStep | -| JinjaSsti.py:9:5:9:12 | ControlFlowNode for template | JinjaSsti.py:10:18:10:25 | ControlFlowNode for template | provenance | | -| JinjaSsti.py:16:7:16:13 | ControlFlowNode for request | JinjaSsti.py:19:5:19:12 | ControlFlowNode for template | provenance | AdditionalTaintStep | -| JinjaSsti.py:19:5:19:12 | ControlFlowNode for template | JinjaSsti.py:21:25:21:32 | ControlFlowNode for template | provenance | | +| JinjaSsti.py:7:7:7:13 | request | JinjaSsti.py:9:5:9:12 | template | provenance | AdditionalTaintStep | +| JinjaSsti.py:9:5:9:12 | template | JinjaSsti.py:10:18:10:25 | template | provenance | | +| JinjaSsti.py:16:7:16:13 | request | JinjaSsti.py:19:5:19:12 | template | provenance | AdditionalTaintStep | +| JinjaSsti.py:19:5:19:12 | template | JinjaSsti.py:21:25:21:32 | template | provenance | | nodes -| JinjaSsti.py:7:7:7:13 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| JinjaSsti.py:9:5:9:12 | ControlFlowNode for template | semmle.label | ControlFlowNode for template | -| JinjaSsti.py:10:18:10:25 | ControlFlowNode for template | semmle.label | ControlFlowNode for template | -| JinjaSsti.py:16:7:16:13 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| JinjaSsti.py:19:5:19:12 | ControlFlowNode for template | semmle.label | ControlFlowNode for template | -| JinjaSsti.py:21:25:21:32 | ControlFlowNode for template | semmle.label | ControlFlowNode for template | +| JinjaSsti.py:7:7:7:13 | request | semmle.label | request | +| JinjaSsti.py:9:5:9:12 | template | semmle.label | template | +| JinjaSsti.py:10:18:10:25 | template | semmle.label | template | +| JinjaSsti.py:16:7:16:13 | request | semmle.label | request | +| JinjaSsti.py:19:5:19:12 | template | semmle.label | template | +| JinjaSsti.py:21:25:21:32 | template | semmle.label | template | subpaths +#select +| JinjaSsti.py:10:18:10:25 | template | JinjaSsti.py:7:7:7:13 | request | JinjaSsti.py:10:18:10:25 | template | This template construction depends on a $@. | JinjaSsti.py:7:7:7:13 | request | user-provided value | +| JinjaSsti.py:21:25:21:32 | template | JinjaSsti.py:16:7:16:13 | request | JinjaSsti.py:21:25:21:32 | template | This template construction depends on a $@. | JinjaSsti.py:16:7:16:13 | request | user-provided value | diff --git a/python/ql/test/query-tests/Security/CWE-078-CommandInjection-py2/CommandInjection.expected b/python/ql/test/query-tests/Security/CWE-078-CommandInjection-py2/CommandInjection.expected index 563a0ac74aec..ee1131e0c16f 100644 --- a/python/ql/test/query-tests/Security/CWE-078-CommandInjection-py2/CommandInjection.expected +++ b/python/ql/test/query-tests/Security/CWE-078-CommandInjection-py2/CommandInjection.expected @@ -1,42 +1,42 @@ edges -| command_injection.py:5:26:5:32 | ControlFlowNode for ImportMember | command_injection.py:5:26:5:32 | ControlFlowNode for request | provenance | | -| command_injection.py:5:26:5:32 | ControlFlowNode for request | command_injection.py:18:13:18:19 | ControlFlowNode for request | provenance | | -| command_injection.py:18:5:18:9 | ControlFlowNode for files | command_injection.py:19:15:19:27 | ControlFlowNode for BinaryExpr | provenance | | -| command_injection.py:18:5:18:9 | ControlFlowNode for files | command_injection.py:20:15:20:27 | ControlFlowNode for BinaryExpr | provenance | | -| command_injection.py:18:5:18:9 | ControlFlowNode for files | command_injection.py:21:15:21:27 | ControlFlowNode for BinaryExpr | provenance | | -| command_injection.py:18:5:18:9 | ControlFlowNode for files | command_injection.py:23:20:23:32 | ControlFlowNode for BinaryExpr | provenance | | -| command_injection.py:18:5:18:9 | ControlFlowNode for files | command_injection.py:25:19:25:31 | ControlFlowNode for BinaryExpr | provenance | | -| command_injection.py:18:5:18:9 | ControlFlowNode for files | command_injection.py:26:19:26:31 | ControlFlowNode for BinaryExpr | provenance | | -| command_injection.py:18:5:18:9 | ControlFlowNode for files | command_injection.py:27:19:27:31 | ControlFlowNode for BinaryExpr | provenance | | -| command_injection.py:18:5:18:9 | ControlFlowNode for files | command_injection.py:28:19:28:31 | ControlFlowNode for BinaryExpr | provenance | | -| command_injection.py:18:5:18:9 | ControlFlowNode for files | command_injection.py:29:19:29:31 | ControlFlowNode for BinaryExpr | provenance | | -| command_injection.py:18:13:18:19 | ControlFlowNode for request | command_injection.py:18:13:18:24 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | -| command_injection.py:18:13:18:24 | ControlFlowNode for Attribute | command_injection.py:18:13:18:41 | ControlFlowNode for Attribute() | provenance | dict.get | -| command_injection.py:18:13:18:41 | ControlFlowNode for Attribute() | command_injection.py:18:5:18:9 | ControlFlowNode for files | provenance | | +| command_injection.py:5:26:5:32 | After ImportMember | command_injection.py:5:26:5:32 | request | provenance | | +| command_injection.py:5:26:5:32 | request | command_injection.py:18:13:18:19 | request | provenance | | +| command_injection.py:18:5:18:9 | files | command_injection.py:19:15:19:27 | After BinaryExpr | provenance | | +| command_injection.py:18:5:18:9 | files | command_injection.py:20:15:20:27 | After BinaryExpr | provenance | | +| command_injection.py:18:5:18:9 | files | command_injection.py:21:15:21:27 | After BinaryExpr | provenance | | +| command_injection.py:18:5:18:9 | files | command_injection.py:23:20:23:32 | After BinaryExpr | provenance | | +| command_injection.py:18:5:18:9 | files | command_injection.py:25:19:25:31 | After BinaryExpr | provenance | | +| command_injection.py:18:5:18:9 | files | command_injection.py:26:19:26:31 | After BinaryExpr | provenance | | +| command_injection.py:18:5:18:9 | files | command_injection.py:27:19:27:31 | After BinaryExpr | provenance | | +| command_injection.py:18:5:18:9 | files | command_injection.py:28:19:28:31 | After BinaryExpr | provenance | | +| command_injection.py:18:5:18:9 | files | command_injection.py:29:19:29:31 | After BinaryExpr | provenance | | +| command_injection.py:18:13:18:19 | request | command_injection.py:18:13:18:24 | After Attribute | provenance | AdditionalTaintStep | +| command_injection.py:18:13:18:24 | After Attribute | command_injection.py:18:13:18:41 | After Attribute() | provenance | dict.get | +| command_injection.py:18:13:18:41 | After Attribute() | command_injection.py:18:5:18:9 | files | provenance | | nodes -| command_injection.py:5:26:5:32 | ControlFlowNode for ImportMember | semmle.label | ControlFlowNode for ImportMember | -| command_injection.py:5:26:5:32 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| command_injection.py:18:5:18:9 | ControlFlowNode for files | semmle.label | ControlFlowNode for files | -| command_injection.py:18:13:18:19 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| command_injection.py:18:13:18:24 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| command_injection.py:18:13:18:41 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| 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 | -| command_injection.py:23:20:23:32 | ControlFlowNode for BinaryExpr | semmle.label | ControlFlowNode for BinaryExpr | -| command_injection.py:25:19:25:31 | ControlFlowNode for BinaryExpr | semmle.label | ControlFlowNode for BinaryExpr | -| command_injection.py:26:19:26:31 | ControlFlowNode for BinaryExpr | semmle.label | ControlFlowNode for BinaryExpr | -| command_injection.py:27:19:27:31 | ControlFlowNode for BinaryExpr | semmle.label | ControlFlowNode for BinaryExpr | -| 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 | +| command_injection.py:5:26:5:32 | After ImportMember | semmle.label | After ImportMember | +| command_injection.py:5:26:5:32 | request | semmle.label | request | +| command_injection.py:18:5:18:9 | files | semmle.label | files | +| command_injection.py:18:13:18:19 | request | semmle.label | request | +| command_injection.py:18:13:18:24 | After Attribute | semmle.label | After Attribute | +| command_injection.py:18:13:18:41 | After Attribute() | semmle.label | After Attribute() | +| command_injection.py:19:15:19:27 | After BinaryExpr | semmle.label | After BinaryExpr | +| command_injection.py:20:15:20:27 | After BinaryExpr | semmle.label | After BinaryExpr | +| command_injection.py:21:15:21:27 | After BinaryExpr | semmle.label | After BinaryExpr | +| command_injection.py:23:20:23:32 | After BinaryExpr | semmle.label | After BinaryExpr | +| command_injection.py:25:19:25:31 | After BinaryExpr | semmle.label | After BinaryExpr | +| command_injection.py:26:19:26:31 | After BinaryExpr | semmle.label | After BinaryExpr | +| command_injection.py:27:19:27:31 | After BinaryExpr | semmle.label | After BinaryExpr | +| command_injection.py:28:19:28:31 | After BinaryExpr | semmle.label | After BinaryExpr | +| command_injection.py:29:19:29:31 | After BinaryExpr | semmle.label | After BinaryExpr | subpaths #select -| command_injection.py:19:15:19:27 | ControlFlowNode for BinaryExpr | command_injection.py:5:26:5:32 | ControlFlowNode for ImportMember | command_injection.py:19:15:19:27 | ControlFlowNode for BinaryExpr | This command line depends on a $@. | command_injection.py:5:26:5:32 | ControlFlowNode for ImportMember | user-provided value | -| command_injection.py:20:15:20:27 | ControlFlowNode for BinaryExpr | command_injection.py:5:26:5:32 | ControlFlowNode for ImportMember | command_injection.py:20:15:20:27 | ControlFlowNode for BinaryExpr | This command line depends on a $@. | command_injection.py:5:26:5:32 | ControlFlowNode for ImportMember | user-provided value | -| command_injection.py:21:15:21:27 | ControlFlowNode for BinaryExpr | command_injection.py:5:26:5:32 | ControlFlowNode for ImportMember | command_injection.py:21:15:21:27 | ControlFlowNode for BinaryExpr | This command line depends on a $@. | command_injection.py:5:26:5:32 | ControlFlowNode for ImportMember | user-provided value | -| command_injection.py:23:20:23:32 | ControlFlowNode for BinaryExpr | command_injection.py:5:26:5:32 | ControlFlowNode for ImportMember | command_injection.py:23:20:23:32 | ControlFlowNode for BinaryExpr | This command line depends on a $@. | command_injection.py:5:26:5:32 | ControlFlowNode for ImportMember | user-provided value | -| command_injection.py:25:19:25:31 | ControlFlowNode for BinaryExpr | command_injection.py:5:26:5:32 | ControlFlowNode for ImportMember | command_injection.py:25:19:25:31 | ControlFlowNode for BinaryExpr | This command line depends on a $@. | command_injection.py:5:26:5:32 | ControlFlowNode for ImportMember | user-provided value | -| command_injection.py:26:19:26:31 | ControlFlowNode for BinaryExpr | command_injection.py:5:26:5:32 | ControlFlowNode for ImportMember | command_injection.py:26:19:26:31 | ControlFlowNode for BinaryExpr | This command line depends on a $@. | command_injection.py:5:26:5:32 | ControlFlowNode for ImportMember | user-provided value | -| command_injection.py:27:19:27:31 | ControlFlowNode for BinaryExpr | command_injection.py:5:26:5:32 | ControlFlowNode for ImportMember | command_injection.py:27:19:27:31 | ControlFlowNode for BinaryExpr | This command line depends on a $@. | command_injection.py:5:26:5:32 | ControlFlowNode for ImportMember | user-provided value | -| command_injection.py:28:19:28:31 | ControlFlowNode for BinaryExpr | command_injection.py:5:26:5:32 | ControlFlowNode for ImportMember | command_injection.py:28:19:28:31 | ControlFlowNode for BinaryExpr | This command line depends on a $@. | command_injection.py:5:26:5:32 | ControlFlowNode for ImportMember | user-provided value | -| command_injection.py:29:19:29:31 | ControlFlowNode for BinaryExpr | command_injection.py:5:26:5:32 | ControlFlowNode for ImportMember | command_injection.py:29:19:29:31 | ControlFlowNode for BinaryExpr | This command line depends on a $@. | command_injection.py:5:26:5:32 | ControlFlowNode for ImportMember | user-provided value | +| command_injection.py:19:15:19:27 | After BinaryExpr | command_injection.py:5:26:5:32 | After ImportMember | command_injection.py:19:15:19:27 | After BinaryExpr | This command line depends on a $@. | command_injection.py:5:26:5:32 | After ImportMember | user-provided value | +| command_injection.py:20:15:20:27 | After BinaryExpr | command_injection.py:5:26:5:32 | After ImportMember | command_injection.py:20:15:20:27 | After BinaryExpr | This command line depends on a $@. | command_injection.py:5:26:5:32 | After ImportMember | user-provided value | +| command_injection.py:21:15:21:27 | After BinaryExpr | command_injection.py:5:26:5:32 | After ImportMember | command_injection.py:21:15:21:27 | After BinaryExpr | This command line depends on a $@. | command_injection.py:5:26:5:32 | After ImportMember | user-provided value | +| command_injection.py:23:20:23:32 | After BinaryExpr | command_injection.py:5:26:5:32 | After ImportMember | command_injection.py:23:20:23:32 | After BinaryExpr | This command line depends on a $@. | command_injection.py:5:26:5:32 | After ImportMember | user-provided value | +| command_injection.py:25:19:25:31 | After BinaryExpr | command_injection.py:5:26:5:32 | After ImportMember | command_injection.py:25:19:25:31 | After BinaryExpr | This command line depends on a $@. | command_injection.py:5:26:5:32 | After ImportMember | user-provided value | +| command_injection.py:26:19:26:31 | After BinaryExpr | command_injection.py:5:26:5:32 | After ImportMember | command_injection.py:26:19:26:31 | After BinaryExpr | This command line depends on a $@. | command_injection.py:5:26:5:32 | After ImportMember | user-provided value | +| command_injection.py:27:19:27:31 | After BinaryExpr | command_injection.py:5:26:5:32 | After ImportMember | command_injection.py:27:19:27:31 | After BinaryExpr | This command line depends on a $@. | command_injection.py:5:26:5:32 | After ImportMember | user-provided value | +| command_injection.py:28:19:28:31 | After BinaryExpr | command_injection.py:5:26:5:32 | After ImportMember | command_injection.py:28:19:28:31 | After BinaryExpr | This command line depends on a $@. | command_injection.py:5:26:5:32 | After ImportMember | user-provided value | +| command_injection.py:29:19:29:31 | After BinaryExpr | command_injection.py:5:26:5:32 | After ImportMember | command_injection.py:29:19:29:31 | After BinaryExpr | This command line depends on a $@. | command_injection.py:5:26:5:32 | After ImportMember | user-provided value | diff --git a/python/ql/test/query-tests/Security/CWE-078-CommandInjection/CommandInjection.expected b/python/ql/test/query-tests/Security/CWE-078-CommandInjection/CommandInjection.expected index 1e75c67db66b..426dd04cc9e6 100644 --- a/python/ql/test/query-tests/Security/CWE-078-CommandInjection/CommandInjection.expected +++ b/python/ql/test/query-tests/Security/CWE-078-CommandInjection/CommandInjection.expected @@ -1,110 +1,110 @@ edges -| command_injection.py:5:26:5:32 | ControlFlowNode for ImportMember | command_injection.py:5:26:5:32 | ControlFlowNode for request | provenance | | -| command_injection.py:5:26:5:32 | ControlFlowNode for request | command_injection.py:11:13:11:19 | ControlFlowNode for request | provenance | | -| command_injection.py:5:26:5:32 | ControlFlowNode for request | command_injection.py:18:13:18:19 | ControlFlowNode for request | provenance | | -| command_injection.py:5:26:5:32 | ControlFlowNode for request | command_injection.py:25:11:25:17 | ControlFlowNode for request | provenance | | -| command_injection.py:5:26:5:32 | ControlFlowNode for request | command_injection.py:31:13:31:19 | ControlFlowNode for request | provenance | | -| command_injection.py:5:26:5:32 | ControlFlowNode for request | command_injection.py:38:15:38:21 | ControlFlowNode for request | provenance | | -| command_injection.py:5:26:5:32 | ControlFlowNode for request | command_injection.py:54:15:54:21 | ControlFlowNode for request | provenance | | -| command_injection.py:5:26:5:32 | ControlFlowNode for request | command_injection.py:71:12:71:18 | ControlFlowNode for request | provenance | | -| command_injection.py:5:26:5:32 | ControlFlowNode for request | command_injection.py:78:12:78:18 | ControlFlowNode for request | provenance | | -| command_injection.py:11:5:11:9 | ControlFlowNode for files | command_injection.py:13:15:13:27 | ControlFlowNode for BinaryExpr | provenance | | -| command_injection.py:11:13:11:19 | ControlFlowNode for request | command_injection.py:11:13:11:24 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | -| command_injection.py:11:13:11:24 | ControlFlowNode for Attribute | command_injection.py:11:13:11:41 | ControlFlowNode for Attribute() | provenance | dict.get | -| command_injection.py:11:13:11:41 | ControlFlowNode for Attribute() | command_injection.py:11:5:11:9 | ControlFlowNode for files | provenance | | -| command_injection.py:18:5:18:9 | ControlFlowNode for files | command_injection.py:20:22:20:34 | ControlFlowNode for BinaryExpr | provenance | | -| command_injection.py:18:13:18:19 | ControlFlowNode for request | command_injection.py:18:13:18:24 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | -| command_injection.py:18:13:18:24 | ControlFlowNode for Attribute | command_injection.py:18:13:18:41 | ControlFlowNode for Attribute() | provenance | dict.get | -| command_injection.py:18:13:18:41 | ControlFlowNode for Attribute() | command_injection.py:18:5:18:9 | ControlFlowNode for files | provenance | | -| command_injection.py:25:5:25:7 | ControlFlowNode for cmd | command_injection.py:26:23:26:25 | ControlFlowNode for cmd | provenance | | -| command_injection.py:25:11:25:17 | ControlFlowNode for request | command_injection.py:25:11:25:22 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | -| command_injection.py:25:11:25:22 | ControlFlowNode for Attribute | command_injection.py:25:11:25:37 | ControlFlowNode for Attribute() | provenance | dict.get | -| command_injection.py:25:11:25:37 | ControlFlowNode for Attribute() | command_injection.py:25:5:25:7 | ControlFlowNode for cmd | provenance | | -| command_injection.py:31:5:31:9 | ControlFlowNode for files | command_injection.py:33:14:33:26 | ControlFlowNode for BinaryExpr | provenance | | -| command_injection.py:31:13:31:19 | ControlFlowNode for request | command_injection.py:31:13:31:24 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | -| command_injection.py:31:13:31:24 | ControlFlowNode for Attribute | command_injection.py:31:13:31:41 | ControlFlowNode for Attribute() | provenance | dict.get | -| command_injection.py:31:13:31:41 | ControlFlowNode for Attribute() | command_injection.py:31:5:31:9 | ControlFlowNode for files | provenance | | -| command_injection.py:38:5:38:11 | ControlFlowNode for command | command_injection.py:41:15:41:21 | ControlFlowNode for command | provenance | | -| command_injection.py:38:5:38:11 | ControlFlowNode for command | command_injection.py:42:15:42:21 | ControlFlowNode for command | provenance | | -| command_injection.py:38:15:38:21 | ControlFlowNode for request | command_injection.py:38:15:38:26 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | -| command_injection.py:38:15:38:26 | ControlFlowNode for Attribute | command_injection.py:38:15:38:45 | ControlFlowNode for Attribute() | provenance | dict.get | -| command_injection.py:38:15:38:45 | ControlFlowNode for Attribute() | command_injection.py:38:5:38:11 | ControlFlowNode for command | provenance | | -| command_injection.py:54:5:54:11 | ControlFlowNode for command | command_injection.py:55:15:55:21 | ControlFlowNode for command | provenance | | -| command_injection.py:54:5:54:11 | ControlFlowNode for command | command_injection.py:56:14:56:20 | ControlFlowNode for command | provenance | | -| command_injection.py:54:5:54:11 | ControlFlowNode for command | command_injection.py:57:21:57:27 | ControlFlowNode for command | provenance | | -| command_injection.py:54:5:54:11 | ControlFlowNode for command | command_injection.py:58:27:58:33 | ControlFlowNode for command | provenance | | -| command_injection.py:54:5:54:11 | ControlFlowNode for command | command_injection.py:59:20:59:26 | ControlFlowNode for command | provenance | | -| command_injection.py:54:15:54:21 | ControlFlowNode for request | command_injection.py:54:15:54:26 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | -| command_injection.py:54:15:54:26 | ControlFlowNode for Attribute | command_injection.py:54:15:54:45 | ControlFlowNode for Attribute() | provenance | dict.get | -| command_injection.py:54:15:54:45 | ControlFlowNode for Attribute() | command_injection.py:54:5:54:11 | ControlFlowNode for command | provenance | | -| command_injection.py:71:5:71:8 | ControlFlowNode for path | command_injection.py:73:19:73:30 | ControlFlowNode for BinaryExpr | provenance | | -| command_injection.py:71:12:71:18 | ControlFlowNode for request | command_injection.py:71:12:71:23 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | -| command_injection.py:71:12:71:23 | ControlFlowNode for Attribute | command_injection.py:71:12:71:39 | ControlFlowNode for Attribute() | provenance | dict.get | -| command_injection.py:71:12:71:39 | ControlFlowNode for Attribute() | command_injection.py:71:5:71:8 | ControlFlowNode for path | provenance | | -| command_injection.py:78:5:78:8 | ControlFlowNode for path | command_injection.py:80:19:80:30 | ControlFlowNode for BinaryExpr | provenance | | -| command_injection.py:78:12:78:18 | ControlFlowNode for request | command_injection.py:78:12:78:23 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | -| command_injection.py:78:12:78:23 | ControlFlowNode for Attribute | command_injection.py:78:12:78:39 | ControlFlowNode for Attribute() | provenance | dict.get | -| command_injection.py:78:12:78:39 | ControlFlowNode for Attribute() | command_injection.py:78:5:78:8 | ControlFlowNode for path | provenance | | +| command_injection.py:5:26:5:32 | ImportMember | command_injection.py:5:26:5:32 | request | provenance | | +| command_injection.py:5:26:5:32 | request | command_injection.py:11:13:11:19 | request | provenance | | +| command_injection.py:5:26:5:32 | request | command_injection.py:18:13:18:19 | request | provenance | | +| command_injection.py:5:26:5:32 | request | command_injection.py:25:11:25:17 | request | provenance | | +| command_injection.py:5:26:5:32 | request | command_injection.py:31:13:31:19 | request | provenance | | +| command_injection.py:5:26:5:32 | request | command_injection.py:38:15:38:21 | request | provenance | | +| command_injection.py:5:26:5:32 | request | command_injection.py:54:15:54:21 | request | provenance | | +| command_injection.py:5:26:5:32 | request | command_injection.py:71:12:71:18 | request | provenance | | +| command_injection.py:5:26:5:32 | request | command_injection.py:78:12:78:18 | request | provenance | | +| command_injection.py:11:5:11:9 | files | command_injection.py:13:15:13:27 | BinaryExpr | provenance | | +| command_injection.py:11:13:11:19 | request | command_injection.py:11:13:11:24 | Attribute | provenance | AdditionalTaintStep | +| command_injection.py:11:13:11:24 | Attribute | command_injection.py:11:13:11:41 | Attribute() | provenance | dict.get | +| command_injection.py:11:13:11:41 | Attribute() | command_injection.py:11:5:11:9 | files | provenance | | +| command_injection.py:18:5:18:9 | files | command_injection.py:20:22:20:34 | BinaryExpr | provenance | | +| command_injection.py:18:13:18:19 | request | command_injection.py:18:13:18:24 | Attribute | provenance | AdditionalTaintStep | +| command_injection.py:18:13:18:24 | Attribute | command_injection.py:18:13:18:41 | Attribute() | provenance | dict.get | +| command_injection.py:18:13:18:41 | Attribute() | command_injection.py:18:5:18:9 | files | provenance | | +| command_injection.py:25:5:25:7 | cmd | command_injection.py:26:23:26:25 | cmd | provenance | | +| command_injection.py:25:11:25:17 | request | command_injection.py:25:11:25:22 | Attribute | provenance | AdditionalTaintStep | +| command_injection.py:25:11:25:22 | Attribute | command_injection.py:25:11:25:37 | Attribute() | provenance | dict.get | +| command_injection.py:25:11:25:37 | Attribute() | command_injection.py:25:5:25:7 | cmd | provenance | | +| command_injection.py:31:5:31:9 | files | command_injection.py:33:14:33:26 | BinaryExpr | provenance | | +| command_injection.py:31:13:31:19 | request | command_injection.py:31:13:31:24 | Attribute | provenance | AdditionalTaintStep | +| command_injection.py:31:13:31:24 | Attribute | command_injection.py:31:13:31:41 | Attribute() | provenance | dict.get | +| command_injection.py:31:13:31:41 | Attribute() | command_injection.py:31:5:31:9 | files | provenance | | +| command_injection.py:38:5:38:11 | command | command_injection.py:41:15:41:21 | command | provenance | | +| command_injection.py:38:5:38:11 | command | command_injection.py:42:15:42:21 | command | provenance | | +| command_injection.py:38:15:38:21 | request | command_injection.py:38:15:38:26 | Attribute | provenance | AdditionalTaintStep | +| command_injection.py:38:15:38:26 | Attribute | command_injection.py:38:15:38:45 | Attribute() | provenance | dict.get | +| command_injection.py:38:15:38:45 | Attribute() | command_injection.py:38:5:38:11 | command | provenance | | +| command_injection.py:54:5:54:11 | command | command_injection.py:55:15:55:21 | command | provenance | | +| command_injection.py:54:5:54:11 | command | command_injection.py:56:14:56:20 | command | provenance | | +| command_injection.py:54:5:54:11 | command | command_injection.py:57:21:57:27 | command | provenance | | +| command_injection.py:54:5:54:11 | command | command_injection.py:58:27:58:33 | command | provenance | | +| command_injection.py:54:5:54:11 | command | command_injection.py:59:20:59:26 | command | provenance | | +| command_injection.py:54:15:54:21 | request | command_injection.py:54:15:54:26 | Attribute | provenance | AdditionalTaintStep | +| command_injection.py:54:15:54:26 | Attribute | command_injection.py:54:15:54:45 | Attribute() | provenance | dict.get | +| command_injection.py:54:15:54:45 | Attribute() | command_injection.py:54:5:54:11 | command | provenance | | +| command_injection.py:71:5:71:8 | path | command_injection.py:73:19:73:30 | BinaryExpr | provenance | | +| command_injection.py:71:12:71:18 | request | command_injection.py:71:12:71:23 | Attribute | provenance | AdditionalTaintStep | +| command_injection.py:71:12:71:23 | Attribute | command_injection.py:71:12:71:39 | Attribute() | provenance | dict.get | +| command_injection.py:71:12:71:39 | Attribute() | command_injection.py:71:5:71:8 | path | provenance | | +| command_injection.py:78:5:78:8 | path | command_injection.py:80:19:80:30 | BinaryExpr | provenance | | +| command_injection.py:78:12:78:18 | request | command_injection.py:78:12:78:23 | Attribute | provenance | AdditionalTaintStep | +| command_injection.py:78:12:78:23 | Attribute | command_injection.py:78:12:78:39 | Attribute() | provenance | dict.get | +| command_injection.py:78:12:78:39 | Attribute() | command_injection.py:78:5:78:8 | path | provenance | | nodes -| command_injection.py:5:26:5:32 | ControlFlowNode for ImportMember | semmle.label | ControlFlowNode for ImportMember | -| command_injection.py:5:26:5:32 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| command_injection.py:11:5:11:9 | ControlFlowNode for files | semmle.label | ControlFlowNode for files | -| command_injection.py:11:13:11:19 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| command_injection.py:11:13:11:24 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| command_injection.py:11:13:11:41 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| command_injection.py:13:15:13:27 | ControlFlowNode for BinaryExpr | semmle.label | ControlFlowNode for BinaryExpr | -| command_injection.py:18:5:18:9 | ControlFlowNode for files | semmle.label | ControlFlowNode for files | -| command_injection.py:18:13:18:19 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| command_injection.py:18:13:18:24 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| command_injection.py:18:13:18:41 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| command_injection.py:20:22:20:34 | ControlFlowNode for BinaryExpr | semmle.label | ControlFlowNode for BinaryExpr | -| command_injection.py:25:5:25:7 | ControlFlowNode for cmd | semmle.label | ControlFlowNode for cmd | -| command_injection.py:25:11:25:17 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| command_injection.py:25:11:25:22 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| command_injection.py:25:11:25:37 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| command_injection.py:26:23:26:25 | ControlFlowNode for cmd | semmle.label | ControlFlowNode for cmd | -| command_injection.py:31:5:31:9 | ControlFlowNode for files | semmle.label | ControlFlowNode for files | -| command_injection.py:31:13:31:19 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| command_injection.py:31:13:31:24 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| command_injection.py:31:13:31:41 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| command_injection.py:33:14:33:26 | ControlFlowNode for BinaryExpr | semmle.label | ControlFlowNode for BinaryExpr | -| command_injection.py:38:5:38:11 | ControlFlowNode for command | semmle.label | ControlFlowNode for command | -| command_injection.py:38:15:38:21 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| command_injection.py:38:15:38:26 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| command_injection.py:38:15:38:45 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| 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:5:54:11 | ControlFlowNode for command | semmle.label | ControlFlowNode for command | -| command_injection.py:54:15:54:21 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| command_injection.py:54:15:54:26 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| command_injection.py:54:15:54:45 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| 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:5:71:8 | ControlFlowNode for path | semmle.label | ControlFlowNode for path | -| command_injection.py:71:12:71:18 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| command_injection.py:71:12:71:23 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| command_injection.py:71:12:71:39 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| command_injection.py:73:19:73:30 | ControlFlowNode for BinaryExpr | semmle.label | ControlFlowNode for BinaryExpr | -| command_injection.py:78:5:78:8 | ControlFlowNode for path | semmle.label | ControlFlowNode for path | -| command_injection.py:78:12:78:18 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| command_injection.py:78:12:78:23 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| command_injection.py:78:12:78:39 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| command_injection.py:80:19:80:30 | ControlFlowNode for BinaryExpr | semmle.label | ControlFlowNode for BinaryExpr | +| command_injection.py:5:26:5:32 | ImportMember | semmle.label | ImportMember | +| command_injection.py:5:26:5:32 | request | semmle.label | request | +| command_injection.py:11:5:11:9 | files | semmle.label | files | +| command_injection.py:11:13:11:19 | request | semmle.label | request | +| command_injection.py:11:13:11:24 | Attribute | semmle.label | Attribute | +| command_injection.py:11:13:11:41 | Attribute() | semmle.label | Attribute() | +| command_injection.py:13:15:13:27 | BinaryExpr | semmle.label | BinaryExpr | +| command_injection.py:18:5:18:9 | files | semmle.label | files | +| command_injection.py:18:13:18:19 | request | semmle.label | request | +| command_injection.py:18:13:18:24 | Attribute | semmle.label | Attribute | +| command_injection.py:18:13:18:41 | Attribute() | semmle.label | Attribute() | +| command_injection.py:20:22:20:34 | BinaryExpr | semmle.label | BinaryExpr | +| command_injection.py:25:5:25:7 | cmd | semmle.label | cmd | +| command_injection.py:25:11:25:17 | request | semmle.label | request | +| command_injection.py:25:11:25:22 | Attribute | semmle.label | Attribute | +| command_injection.py:25:11:25:37 | Attribute() | semmle.label | Attribute() | +| command_injection.py:26:23:26:25 | cmd | semmle.label | cmd | +| command_injection.py:31:5:31:9 | files | semmle.label | files | +| command_injection.py:31:13:31:19 | request | semmle.label | request | +| command_injection.py:31:13:31:24 | Attribute | semmle.label | Attribute | +| command_injection.py:31:13:31:41 | Attribute() | semmle.label | Attribute() | +| command_injection.py:33:14:33:26 | BinaryExpr | semmle.label | BinaryExpr | +| command_injection.py:38:5:38:11 | command | semmle.label | command | +| command_injection.py:38:15:38:21 | request | semmle.label | request | +| command_injection.py:38:15:38:26 | Attribute | semmle.label | Attribute | +| command_injection.py:38:15:38:45 | Attribute() | semmle.label | Attribute() | +| command_injection.py:41:15:41:21 | command | semmle.label | command | +| command_injection.py:42:15:42:21 | command | semmle.label | command | +| command_injection.py:54:5:54:11 | command | semmle.label | command | +| command_injection.py:54:15:54:21 | request | semmle.label | request | +| command_injection.py:54:15:54:26 | Attribute | semmle.label | Attribute | +| command_injection.py:54:15:54:45 | Attribute() | semmle.label | Attribute() | +| command_injection.py:55:15:55:21 | command | semmle.label | command | +| command_injection.py:56:14:56:20 | command | semmle.label | command | +| command_injection.py:57:21:57:27 | command | semmle.label | command | +| command_injection.py:58:27:58:33 | command | semmle.label | command | +| command_injection.py:59:20:59:26 | command | semmle.label | command | +| command_injection.py:71:5:71:8 | path | semmle.label | path | +| command_injection.py:71:12:71:18 | request | semmle.label | request | +| command_injection.py:71:12:71:23 | Attribute | semmle.label | Attribute | +| command_injection.py:71:12:71:39 | Attribute() | semmle.label | Attribute() | +| command_injection.py:73:19:73:30 | BinaryExpr | semmle.label | BinaryExpr | +| command_injection.py:78:5:78:8 | path | semmle.label | path | +| command_injection.py:78:12:78:18 | request | semmle.label | request | +| command_injection.py:78:12:78:23 | Attribute | semmle.label | Attribute | +| command_injection.py:78:12:78:39 | Attribute() | semmle.label | Attribute() | +| command_injection.py:80:19:80:30 | BinaryExpr | semmle.label | BinaryExpr | subpaths #select -| command_injection.py:13:15:13:27 | ControlFlowNode for BinaryExpr | command_injection.py:5:26:5:32 | ControlFlowNode for ImportMember | command_injection.py:13:15:13:27 | ControlFlowNode for BinaryExpr | This command line depends on a $@. | command_injection.py:5:26:5:32 | ControlFlowNode for ImportMember | user-provided value | -| command_injection.py:20:22:20:34 | ControlFlowNode for BinaryExpr | command_injection.py:5:26:5:32 | ControlFlowNode for ImportMember | command_injection.py:20:22:20:34 | ControlFlowNode for BinaryExpr | This command line depends on a $@. | command_injection.py:5:26:5:32 | ControlFlowNode for ImportMember | user-provided value | -| command_injection.py:26:23:26:25 | ControlFlowNode for cmd | command_injection.py:5:26:5:32 | ControlFlowNode for ImportMember | command_injection.py:26:23:26:25 | ControlFlowNode for cmd | This command line depends on a $@. | command_injection.py:5:26:5:32 | ControlFlowNode for ImportMember | user-provided value | -| command_injection.py:33:14:33:26 | ControlFlowNode for BinaryExpr | command_injection.py:5:26:5:32 | ControlFlowNode for ImportMember | command_injection.py:33:14:33:26 | ControlFlowNode for BinaryExpr | This command line depends on a $@. | command_injection.py:5:26:5:32 | ControlFlowNode for ImportMember | user-provided value | -| command_injection.py:41:15:41:21 | ControlFlowNode for command | command_injection.py:5:26:5:32 | ControlFlowNode for ImportMember | command_injection.py:41:15:41:21 | ControlFlowNode for command | This command line depends on a $@. | command_injection.py:5:26:5:32 | ControlFlowNode for ImportMember | user-provided value | -| command_injection.py:42:15:42:21 | ControlFlowNode for command | command_injection.py:5:26:5:32 | ControlFlowNode for ImportMember | command_injection.py:42:15:42:21 | ControlFlowNode for command | This command line depends on a $@. | command_injection.py:5:26:5:32 | ControlFlowNode for ImportMember | user-provided value | -| command_injection.py:55:15:55:21 | ControlFlowNode for command | command_injection.py:5:26:5:32 | ControlFlowNode for ImportMember | command_injection.py:55:15:55:21 | ControlFlowNode for command | This command line depends on a $@. | command_injection.py:5:26:5:32 | ControlFlowNode for ImportMember | user-provided value | -| command_injection.py:56:14:56:20 | ControlFlowNode for command | command_injection.py:5:26:5:32 | ControlFlowNode for ImportMember | command_injection.py:56:14:56:20 | ControlFlowNode for command | This command line depends on a $@. | command_injection.py:5:26:5:32 | ControlFlowNode for ImportMember | user-provided value | -| command_injection.py:57:21:57:27 | ControlFlowNode for command | command_injection.py:5:26:5:32 | ControlFlowNode for ImportMember | command_injection.py:57:21:57:27 | ControlFlowNode for command | This command line depends on a $@. | command_injection.py:5:26:5:32 | ControlFlowNode for ImportMember | user-provided value | -| command_injection.py:58:27:58:33 | ControlFlowNode for command | command_injection.py:5:26:5:32 | ControlFlowNode for ImportMember | command_injection.py:58:27:58:33 | ControlFlowNode for command | This command line depends on a $@. | command_injection.py:5:26:5:32 | ControlFlowNode for ImportMember | user-provided value | -| command_injection.py:59:20:59:26 | ControlFlowNode for command | command_injection.py:5:26:5:32 | ControlFlowNode for ImportMember | command_injection.py:59:20:59:26 | ControlFlowNode for command | This command line depends on a $@. | command_injection.py:5:26:5:32 | ControlFlowNode for ImportMember | user-provided value | -| command_injection.py:73:19:73:30 | ControlFlowNode for BinaryExpr | command_injection.py:5:26:5:32 | ControlFlowNode for ImportMember | command_injection.py:73:19:73:30 | ControlFlowNode for BinaryExpr | This command line depends on a $@. | command_injection.py:5:26:5:32 | ControlFlowNode for ImportMember | user-provided value | -| command_injection.py:80:19:80:30 | ControlFlowNode for BinaryExpr | command_injection.py:5:26:5:32 | ControlFlowNode for ImportMember | command_injection.py:80:19:80:30 | ControlFlowNode for BinaryExpr | This command line depends on a $@. | command_injection.py:5:26:5:32 | ControlFlowNode for ImportMember | user-provided value | +| command_injection.py:13:15:13:27 | BinaryExpr | command_injection.py:5:26:5:32 | ImportMember | command_injection.py:13:15:13:27 | BinaryExpr | This command line depends on a $@. | command_injection.py:5:26:5:32 | ImportMember | user-provided value | +| command_injection.py:20:22:20:34 | BinaryExpr | command_injection.py:5:26:5:32 | ImportMember | command_injection.py:20:22:20:34 | BinaryExpr | This command line depends on a $@. | command_injection.py:5:26:5:32 | ImportMember | user-provided value | +| command_injection.py:26:23:26:25 | cmd | command_injection.py:5:26:5:32 | ImportMember | command_injection.py:26:23:26:25 | cmd | This command line depends on a $@. | command_injection.py:5:26:5:32 | ImportMember | user-provided value | +| command_injection.py:33:14:33:26 | BinaryExpr | command_injection.py:5:26:5:32 | ImportMember | command_injection.py:33:14:33:26 | BinaryExpr | This command line depends on a $@. | command_injection.py:5:26:5:32 | ImportMember | user-provided value | +| command_injection.py:41:15:41:21 | command | command_injection.py:5:26:5:32 | ImportMember | command_injection.py:41:15:41:21 | command | This command line depends on a $@. | command_injection.py:5:26:5:32 | ImportMember | user-provided value | +| command_injection.py:42:15:42:21 | command | command_injection.py:5:26:5:32 | ImportMember | command_injection.py:42:15:42:21 | command | This command line depends on a $@. | command_injection.py:5:26:5:32 | ImportMember | user-provided value | +| command_injection.py:55:15:55:21 | command | command_injection.py:5:26:5:32 | ImportMember | command_injection.py:55:15:55:21 | command | This command line depends on a $@. | command_injection.py:5:26:5:32 | ImportMember | user-provided value | +| command_injection.py:56:14:56:20 | command | command_injection.py:5:26:5:32 | ImportMember | command_injection.py:56:14:56:20 | command | This command line depends on a $@. | command_injection.py:5:26:5:32 | ImportMember | user-provided value | +| command_injection.py:57:21:57:27 | command | command_injection.py:5:26:5:32 | ImportMember | command_injection.py:57:21:57:27 | command | This command line depends on a $@. | command_injection.py:5:26:5:32 | ImportMember | user-provided value | +| command_injection.py:58:27:58:33 | command | command_injection.py:5:26:5:32 | ImportMember | command_injection.py:58:27:58:33 | command | This command line depends on a $@. | command_injection.py:5:26:5:32 | ImportMember | user-provided value | +| command_injection.py:59:20:59:26 | command | command_injection.py:5:26:5:32 | ImportMember | command_injection.py:59:20:59:26 | command | This command line depends on a $@. | command_injection.py:5:26:5:32 | ImportMember | user-provided value | +| command_injection.py:73:19:73:30 | BinaryExpr | command_injection.py:5:26:5:32 | ImportMember | command_injection.py:73:19:73:30 | BinaryExpr | This command line depends on a $@. | command_injection.py:5:26:5:32 | ImportMember | user-provided value | +| command_injection.py:80:19:80:30 | BinaryExpr | command_injection.py:5:26:5:32 | ImportMember | command_injection.py:80:19:80:30 | BinaryExpr | This command line depends on a $@. | command_injection.py:5:26:5:32 | ImportMember | user-provided value | diff --git a/python/ql/test/query-tests/Security/CWE-078-UnsafeShellCommandConstruction/UnsafeShellCommandConstruction.expected b/python/ql/test/query-tests/Security/CWE-078-UnsafeShellCommandConstruction/UnsafeShellCommandConstruction.expected index 3bc075d618be..e2864afc53e7 100644 --- a/python/ql/test/query-tests/Security/CWE-078-UnsafeShellCommandConstruction/UnsafeShellCommandConstruction.expected +++ b/python/ql/test/query-tests/Security/CWE-078-UnsafeShellCommandConstruction/UnsafeShellCommandConstruction.expected @@ -1,44 +1,38 @@ edges -| src/unsafe_shell_test.py:4:22:4:25 | ControlFlowNode for name | src/unsafe_shell_test.py:5:25:5:28 | ControlFlowNode for name | provenance | | -| src/unsafe_shell_test.py:4:22:4:25 | ControlFlowNode for name | src/unsafe_shell_test.py:8:23:8:26 | ControlFlowNode for name | provenance | | -| src/unsafe_shell_test.py:4:22:4:25 | ControlFlowNode for name | src/unsafe_shell_test.py:11:34:11:37 | ControlFlowNode for name | provenance | | -| src/unsafe_shell_test.py:4:22:4:25 | ControlFlowNode for name | src/unsafe_shell_test.py:14:35:14:38 | ControlFlowNode for name | provenance | | -| src/unsafe_shell_test.py:4:22:4:25 | ControlFlowNode for name | src/unsafe_shell_test.py:17:32:17:35 | ControlFlowNode for name | provenance | | -| src/unsafe_shell_test.py:4:22:4:25 | ControlFlowNode for name | src/unsafe_shell_test.py:20:27:20:30 | ControlFlowNode for name | provenance | | -| src/unsafe_shell_test.py:11:34:11:37 | ControlFlowNode for name | src/unsafe_shell_test.py:11:25:11:38 | ControlFlowNode for Attribute() | provenance | str.join | -| src/unsafe_shell_test.py:14:34:14:39 | ControlFlowNode for List [List element] | src/unsafe_shell_test.py:14:25:14:40 | ControlFlowNode for Attribute() | provenance | str.join | -| src/unsafe_shell_test.py:14:35:14:38 | ControlFlowNode for name | src/unsafe_shell_test.py:14:34:14:39 | ControlFlowNode for List [List element] | provenance | | -| src/unsafe_shell_test.py:26:20:26:23 | ControlFlowNode for name | src/unsafe_shell_test.py:29:30:29:33 | ControlFlowNode for name | provenance | | -| src/unsafe_shell_test.py:36:22:36:25 | ControlFlowNode for name | src/unsafe_shell_test.py:39:30:39:33 | ControlFlowNode for name | provenance | | -| src/unsafe_shell_test.py:36:22:36:25 | ControlFlowNode for name | src/unsafe_shell_test.py:44:20:44:23 | ControlFlowNode for name | provenance | | -| src/unsafe_shell_test.py:41:24:41:24 | ControlFlowNode for x | src/unsafe_shell_test.py:42:34:42:34 | ControlFlowNode for x | provenance | | -| src/unsafe_shell_test.py:44:20:44:23 | ControlFlowNode for name | src/unsafe_shell_test.py:41:24:41:24 | ControlFlowNode for x | provenance | | +| src/unsafe_shell_test.py:4:22:4:25 | name | src/unsafe_shell_test.py:5:25:5:28 | name | provenance | | +| src/unsafe_shell_test.py:4:22:4:25 | name | src/unsafe_shell_test.py:8:23:8:26 | name | provenance | | +| src/unsafe_shell_test.py:4:22:4:25 | name | src/unsafe_shell_test.py:11:25:11:38 | After Attribute() | provenance | | +| src/unsafe_shell_test.py:4:22:4:25 | name | src/unsafe_shell_test.py:14:25:14:40 | After Attribute() | provenance | | +| src/unsafe_shell_test.py:4:22:4:25 | name | src/unsafe_shell_test.py:17:32:17:35 | name | provenance | | +| src/unsafe_shell_test.py:4:22:4:25 | name | src/unsafe_shell_test.py:20:27:20:30 | name | provenance | | +| src/unsafe_shell_test.py:26:20:26:23 | name | src/unsafe_shell_test.py:29:30:29:33 | name | provenance | | +| src/unsafe_shell_test.py:36:22:36:25 | name | src/unsafe_shell_test.py:39:30:39:33 | name | provenance | | +| src/unsafe_shell_test.py:36:22:36:25 | name | src/unsafe_shell_test.py:44:20:44:23 | name | provenance | | +| src/unsafe_shell_test.py:41:24:41:24 | x | src/unsafe_shell_test.py:42:34:42:34 | x | provenance | | +| src/unsafe_shell_test.py:44:20:44:23 | name | src/unsafe_shell_test.py:41:24:41:24 | x | provenance | | nodes -| src/unsafe_shell_test.py:4:22:4:25 | ControlFlowNode for name | semmle.label | ControlFlowNode for name | -| src/unsafe_shell_test.py:5:25:5:28 | ControlFlowNode for name | semmle.label | ControlFlowNode for name | -| src/unsafe_shell_test.py:8:23:8:26 | ControlFlowNode for name | semmle.label | ControlFlowNode for name | -| src/unsafe_shell_test.py:11:25:11:38 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| src/unsafe_shell_test.py:11:34:11:37 | ControlFlowNode for name | semmle.label | ControlFlowNode for name | -| src/unsafe_shell_test.py:14:25:14:40 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| src/unsafe_shell_test.py:14:34:14:39 | ControlFlowNode for List [List element] | semmle.label | ControlFlowNode for List [List element] | -| src/unsafe_shell_test.py:14:35:14:38 | ControlFlowNode for name | semmle.label | ControlFlowNode for name | -| src/unsafe_shell_test.py:17:32:17:35 | ControlFlowNode for name | semmle.label | ControlFlowNode for name | -| src/unsafe_shell_test.py:20:27:20:30 | ControlFlowNode for name | semmle.label | ControlFlowNode for name | -| src/unsafe_shell_test.py:26:20:26:23 | ControlFlowNode for name | semmle.label | ControlFlowNode for name | -| src/unsafe_shell_test.py:29:30:29:33 | ControlFlowNode for name | semmle.label | ControlFlowNode for name | -| src/unsafe_shell_test.py:36:22:36:25 | ControlFlowNode for name | semmle.label | ControlFlowNode for name | -| src/unsafe_shell_test.py:39:30:39:33 | ControlFlowNode for name | semmle.label | ControlFlowNode for name | -| src/unsafe_shell_test.py:41:24:41:24 | ControlFlowNode for x | semmle.label | ControlFlowNode for x | -| src/unsafe_shell_test.py:42:34:42:34 | ControlFlowNode for x | semmle.label | ControlFlowNode for x | -| src/unsafe_shell_test.py:44:20:44:23 | ControlFlowNode for name | semmle.label | ControlFlowNode for name | +| src/unsafe_shell_test.py:4:22:4:25 | name | semmle.label | name | +| src/unsafe_shell_test.py:5:25:5:28 | name | semmle.label | name | +| src/unsafe_shell_test.py:8:23:8:26 | name | semmle.label | name | +| src/unsafe_shell_test.py:11:25:11:38 | After Attribute() | semmle.label | After Attribute() | +| src/unsafe_shell_test.py:14:25:14:40 | After Attribute() | semmle.label | After Attribute() | +| src/unsafe_shell_test.py:17:32:17:35 | name | semmle.label | name | +| src/unsafe_shell_test.py:20:27:20:30 | name | semmle.label | name | +| src/unsafe_shell_test.py:26:20:26:23 | name | semmle.label | name | +| src/unsafe_shell_test.py:29:30:29:33 | name | semmle.label | name | +| src/unsafe_shell_test.py:36:22:36:25 | name | semmle.label | name | +| src/unsafe_shell_test.py:39:30:39:33 | name | semmle.label | name | +| src/unsafe_shell_test.py:41:24:41:24 | x | semmle.label | x | +| src/unsafe_shell_test.py:42:34:42:34 | x | semmle.label | x | +| src/unsafe_shell_test.py:44:20:44:23 | name | semmle.label | name | subpaths #select -| src/unsafe_shell_test.py:5:15:5:28 | ControlFlowNode for BinaryExpr | src/unsafe_shell_test.py:4:22:4:25 | ControlFlowNode for name | src/unsafe_shell_test.py:5:25:5:28 | ControlFlowNode for name | This string concatenation which depends on $@ is later used in a $@. | src/unsafe_shell_test.py:4:22:4:25 | ControlFlowNode for name | library input | src/unsafe_shell_test.py:5:5:5:29 | ControlFlowNode for Attribute() | shell command | -| src/unsafe_shell_test.py:8:15:8:28 | ControlFlowNode for Fstring | src/unsafe_shell_test.py:4:22:4:25 | ControlFlowNode for name | src/unsafe_shell_test.py:8:23:8:26 | ControlFlowNode for name | This f-string which depends on $@ is later used in a $@. | src/unsafe_shell_test.py:4:22:4:25 | ControlFlowNode for name | library input | src/unsafe_shell_test.py:8:5:8:29 | ControlFlowNode for Attribute() | shell command | -| src/unsafe_shell_test.py:11:15:11:38 | ControlFlowNode for BinaryExpr | src/unsafe_shell_test.py:4:22:4:25 | ControlFlowNode for name | src/unsafe_shell_test.py:11:25:11:38 | ControlFlowNode for Attribute() | This string concatenation which depends on $@ is later used in a $@. | src/unsafe_shell_test.py:4:22:4:25 | ControlFlowNode for name | library input | src/unsafe_shell_test.py:11:5:11:39 | ControlFlowNode for Attribute() | shell command | -| src/unsafe_shell_test.py:14:15:14:40 | ControlFlowNode for BinaryExpr | src/unsafe_shell_test.py:4:22:4:25 | ControlFlowNode for name | src/unsafe_shell_test.py:14:25:14:40 | ControlFlowNode for Attribute() | This string concatenation which depends on $@ is later used in a $@. | src/unsafe_shell_test.py:4:22:4:25 | ControlFlowNode for name | library input | src/unsafe_shell_test.py:14:5:14:41 | ControlFlowNode for Attribute() | shell command | -| src/unsafe_shell_test.py:17:15:17:36 | ControlFlowNode for Attribute() | src/unsafe_shell_test.py:4:22:4:25 | ControlFlowNode for name | src/unsafe_shell_test.py:17:32:17:35 | ControlFlowNode for name | This formatted string which depends on $@ is later used in a $@. | src/unsafe_shell_test.py:4:22:4:25 | ControlFlowNode for name | library input | src/unsafe_shell_test.py:17:5:17:37 | ControlFlowNode for Attribute() | shell command | -| src/unsafe_shell_test.py:20:15:20:30 | ControlFlowNode for BinaryExpr | src/unsafe_shell_test.py:4:22:4:25 | ControlFlowNode for name | src/unsafe_shell_test.py:20:27:20:30 | ControlFlowNode for name | This formatted string which depends on $@ is later used in a $@. | src/unsafe_shell_test.py:4:22:4:25 | ControlFlowNode for name | library input | src/unsafe_shell_test.py:20:5:20:31 | ControlFlowNode for Attribute() | shell command | -| src/unsafe_shell_test.py:29:20:29:33 | ControlFlowNode for BinaryExpr | src/unsafe_shell_test.py:26:20:26:23 | ControlFlowNode for name | src/unsafe_shell_test.py:29:30:29:33 | ControlFlowNode for name | This string concatenation which depends on $@ is later used in a $@. | src/unsafe_shell_test.py:26:20:26:23 | ControlFlowNode for name | library input | src/unsafe_shell_test.py:29:5:29:46 | ControlFlowNode for Attribute() | shell command | -| src/unsafe_shell_test.py:39:20:39:33 | ControlFlowNode for BinaryExpr | src/unsafe_shell_test.py:36:22:36:25 | ControlFlowNode for name | src/unsafe_shell_test.py:39:30:39:33 | ControlFlowNode for name | This string concatenation which depends on $@ is later used in a $@. | src/unsafe_shell_test.py:36:22:36:25 | ControlFlowNode for name | library input | src/unsafe_shell_test.py:39:5:39:46 | ControlFlowNode for Attribute() | shell command | -| src/unsafe_shell_test.py:42:24:42:34 | ControlFlowNode for BinaryExpr | src/unsafe_shell_test.py:36:22:36:25 | ControlFlowNode for name | src/unsafe_shell_test.py:42:34:42:34 | ControlFlowNode for x | This string concatenation which depends on $@ is later used in a $@. | src/unsafe_shell_test.py:36:22:36:25 | ControlFlowNode for name | library input | src/unsafe_shell_test.py:42:9:42:47 | ControlFlowNode for Attribute() | shell command | +| src/unsafe_shell_test.py:5:15:5:28 | After BinaryExpr | src/unsafe_shell_test.py:4:22:4:25 | name | src/unsafe_shell_test.py:5:25:5:28 | name | This string concatenation which depends on $@ is later used in a $@. | src/unsafe_shell_test.py:4:22:4:25 | name | library input | src/unsafe_shell_test.py:5:5:5:29 | After Attribute() | shell command | +| src/unsafe_shell_test.py:8:15:8:28 | After Fstring | src/unsafe_shell_test.py:4:22:4:25 | name | src/unsafe_shell_test.py:8:23:8:26 | name | This f-string which depends on $@ is later used in a $@. | src/unsafe_shell_test.py:4:22:4:25 | name | library input | src/unsafe_shell_test.py:8:5:8:29 | After Attribute() | shell command | +| src/unsafe_shell_test.py:11:15:11:38 | After BinaryExpr | src/unsafe_shell_test.py:4:22:4:25 | name | src/unsafe_shell_test.py:11:25:11:38 | After Attribute() | This string concatenation which depends on $@ is later used in a $@. | src/unsafe_shell_test.py:4:22:4:25 | name | library input | src/unsafe_shell_test.py:11:5:11:39 | After Attribute() | shell command | +| src/unsafe_shell_test.py:14:15:14:40 | After BinaryExpr | src/unsafe_shell_test.py:4:22:4:25 | name | src/unsafe_shell_test.py:14:25:14:40 | After Attribute() | This string concatenation which depends on $@ is later used in a $@. | src/unsafe_shell_test.py:4:22:4:25 | name | library input | src/unsafe_shell_test.py:14:5:14:41 | After Attribute() | shell command | +| src/unsafe_shell_test.py:17:15:17:36 | After Attribute() | src/unsafe_shell_test.py:4:22:4:25 | name | src/unsafe_shell_test.py:17:32:17:35 | name | This formatted string which depends on $@ is later used in a $@. | src/unsafe_shell_test.py:4:22:4:25 | name | library input | src/unsafe_shell_test.py:17:5:17:37 | After Attribute() | shell command | +| src/unsafe_shell_test.py:20:15:20:30 | After BinaryExpr | src/unsafe_shell_test.py:4:22:4:25 | name | src/unsafe_shell_test.py:20:27:20:30 | name | This formatted string which depends on $@ is later used in a $@. | src/unsafe_shell_test.py:4:22:4:25 | name | library input | src/unsafe_shell_test.py:20:5:20:31 | After Attribute() | shell command | +| src/unsafe_shell_test.py:29:20:29:33 | After BinaryExpr | src/unsafe_shell_test.py:26:20:26:23 | name | src/unsafe_shell_test.py:29:30:29:33 | name | This string concatenation which depends on $@ is later used in a $@. | src/unsafe_shell_test.py:26:20:26:23 | name | library input | src/unsafe_shell_test.py:29:5:29:46 | After Attribute() | shell command | +| src/unsafe_shell_test.py:39:20:39:33 | After BinaryExpr | src/unsafe_shell_test.py:36:22:36:25 | name | src/unsafe_shell_test.py:39:30:39:33 | name | This string concatenation which depends on $@ is later used in a $@. | src/unsafe_shell_test.py:36:22:36:25 | name | library input | src/unsafe_shell_test.py:39:5:39:46 | After Attribute() | shell command | +| src/unsafe_shell_test.py:42:24:42:34 | After BinaryExpr | src/unsafe_shell_test.py:36:22:36:25 | name | src/unsafe_shell_test.py:42:34:42:34 | x | This string concatenation which depends on $@ is later used in a $@. | src/unsafe_shell_test.py:36:22:36:25 | name | library input | src/unsafe_shell_test.py:42:9:42:47 | After Attribute() | shell command | diff --git a/python/ql/test/query-tests/Security/CWE-079-Jinja2WithoutEscaping/Jinja2WithoutEscaping.expected b/python/ql/test/query-tests/Security/CWE-079-Jinja2WithoutEscaping/Jinja2WithoutEscaping.expected index 918fbdf604d1..fb4064af4552 100644 --- a/python/ql/test/query-tests/Security/CWE-079-Jinja2WithoutEscaping/Jinja2WithoutEscaping.expected +++ b/python/ql/test/query-tests/Security/CWE-079-Jinja2WithoutEscaping/Jinja2WithoutEscaping.expected @@ -1,6 +1,6 @@ -| jinja2_escaping.py:9:14:9:39 | ControlFlowNode for Environment() | Using jinja2 templates with autoescape=False can potentially allow XSS attacks. | -| jinja2_escaping.py:41:5:41:29 | ControlFlowNode for Environment() | Using jinja2 templates with autoescape=False can potentially allow XSS attacks. | -| jinja2_escaping.py:43:1:43:3 | ControlFlowNode for E() | Using jinja2 templates with autoescape=False can potentially allow XSS attacks. | -| jinja2_escaping.py:44:1:44:15 | ControlFlowNode for E() | Using jinja2 templates with autoescape=False can potentially allow XSS attacks. | -| jinja2_escaping.py:50:13:50:40 | ControlFlowNode for Environment() | Using jinja2 templates with autoescape=False can potentially allow XSS attacks. | -| jinja2_escaping.py:53:15:53:43 | ControlFlowNode for Template() | Using jinja2 templates with autoescape=False can potentially allow XSS attacks. | +| jinja2_escaping.py:9:14:9:39 | After Environment() | Using jinja2 templates with autoescape=False can potentially allow XSS attacks. | +| jinja2_escaping.py:41:5:41:29 | After Environment() | Using jinja2 templates with autoescape=False can potentially allow XSS attacks. | +| jinja2_escaping.py:43:1:43:3 | After E() | Using jinja2 templates with autoescape=False can potentially allow XSS attacks. | +| jinja2_escaping.py:44:1:44:15 | After E() | Using jinja2 templates with autoescape=False can potentially allow XSS attacks. | +| jinja2_escaping.py:50:13:50:40 | After Environment() | Using jinja2 templates with autoescape=False can potentially allow XSS attacks. | +| jinja2_escaping.py:53:15:53:43 | After Template() | Using jinja2 templates with autoescape=False can potentially allow XSS attacks. | diff --git a/python/ql/test/query-tests/Security/CWE-079-ReflectedXss/ReflectedXss.expected b/python/ql/test/query-tests/Security/CWE-079-ReflectedXss/ReflectedXss.expected index bf4f584c8157..f2bceb5c02ab 100644 --- a/python/ql/test/query-tests/Security/CWE-079-ReflectedXss/ReflectedXss.expected +++ b/python/ql/test/query-tests/Security/CWE-079-ReflectedXss/ReflectedXss.expected @@ -1,34 +1,32 @@ -#select -| reflected_xss.py:10:26:10:53 | ControlFlowNode for BinaryExpr | reflected_xss.py:2:26:2:32 | ControlFlowNode for ImportMember | reflected_xss.py:10:26:10:53 | ControlFlowNode for BinaryExpr | Cross-site scripting vulnerability due to a $@. | reflected_xss.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value | -| reflected_xss.py:22:26:22:41 | ControlFlowNode for Attribute() | reflected_xss.py:2:26:2:32 | ControlFlowNode for ImportMember | reflected_xss.py:22:26:22:41 | ControlFlowNode for Attribute() | Cross-site scripting vulnerability due to a $@. | reflected_xss.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value | -| reflected_xss.py:28:26:28:41 | ControlFlowNode for Attribute() | reflected_xss.py:2:26:2:32 | ControlFlowNode for ImportMember | reflected_xss.py:28:26:28:41 | ControlFlowNode for Attribute() | Cross-site scripting vulnerability due to a $@. | reflected_xss.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value | edges -| reflected_xss.py:2:26:2:32 | ControlFlowNode for ImportMember | reflected_xss.py:2:26:2:32 | ControlFlowNode for request | provenance | | -| reflected_xss.py:2:26:2:32 | ControlFlowNode for request | reflected_xss.py:9:18:9:24 | ControlFlowNode for request | provenance | | -| reflected_xss.py:2:26:2:32 | ControlFlowNode for request | reflected_xss.py:21:23:21:29 | ControlFlowNode for request | provenance | | -| reflected_xss.py:2:26:2:32 | ControlFlowNode for request | reflected_xss.py:27:23:27:29 | ControlFlowNode for request | provenance | | -| reflected_xss.py:9:5:9:14 | ControlFlowNode for first_name | reflected_xss.py:10:26:10:53 | ControlFlowNode for BinaryExpr | provenance | | -| reflected_xss.py:9:18:9:24 | ControlFlowNode for request | reflected_xss.py:9:18:9:29 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | -| reflected_xss.py:9:18:9:29 | ControlFlowNode for Attribute | reflected_xss.py:9:18:9:45 | ControlFlowNode for Attribute() | provenance | dict.get | -| reflected_xss.py:9:18:9:45 | ControlFlowNode for Attribute() | reflected_xss.py:9:5:9:14 | ControlFlowNode for first_name | provenance | | -| reflected_xss.py:21:5:21:8 | ControlFlowNode for data | reflected_xss.py:22:26:22:41 | ControlFlowNode for Attribute() | provenance | | -| reflected_xss.py:21:5:21:8 | ControlFlowNode for data | reflected_xss.py:22:26:22:41 | ControlFlowNode for Attribute() | provenance | AdditionalTaintStep | -| reflected_xss.py:21:23:21:29 | ControlFlowNode for request | reflected_xss.py:21:5:21:8 | ControlFlowNode for data | provenance | AdditionalTaintStep | -| reflected_xss.py:27:5:27:8 | ControlFlowNode for data | reflected_xss.py:28:26:28:41 | ControlFlowNode for Attribute() | provenance | | -| reflected_xss.py:27:5:27:8 | ControlFlowNode for data | reflected_xss.py:28:26:28:41 | ControlFlowNode for Attribute() | provenance | AdditionalTaintStep | -| reflected_xss.py:27:23:27:29 | ControlFlowNode for request | reflected_xss.py:27:5:27:8 | ControlFlowNode for data | provenance | AdditionalTaintStep | +| reflected_xss.py:2:26:2:32 | After ImportMember | reflected_xss.py:2:26:2:32 | request | provenance | | +| reflected_xss.py:2:26:2:32 | request | reflected_xss.py:9:18:9:24 | request | provenance | | +| reflected_xss.py:2:26:2:32 | request | reflected_xss.py:21:23:21:29 | request | provenance | | +| reflected_xss.py:2:26:2:32 | request | reflected_xss.py:27:23:27:29 | request | provenance | | +| reflected_xss.py:9:5:9:14 | first_name | reflected_xss.py:10:26:10:53 | After BinaryExpr | provenance | | +| reflected_xss.py:9:18:9:24 | request | reflected_xss.py:9:18:9:29 | After Attribute | provenance | AdditionalTaintStep | +| reflected_xss.py:9:18:9:29 | After Attribute | reflected_xss.py:9:18:9:45 | After Attribute() | provenance | dict.get | +| reflected_xss.py:9:18:9:45 | After Attribute() | reflected_xss.py:9:5:9:14 | first_name | provenance | | +| reflected_xss.py:21:5:21:8 | data | reflected_xss.py:22:26:22:41 | After Attribute() | provenance | AdditionalTaintStep | +| reflected_xss.py:21:23:21:29 | request | reflected_xss.py:21:5:21:8 | data | provenance | AdditionalTaintStep | +| reflected_xss.py:27:5:27:8 | data | reflected_xss.py:28:26:28:41 | After Attribute() | provenance | AdditionalTaintStep | +| reflected_xss.py:27:23:27:29 | request | reflected_xss.py:27:5:27:8 | data | provenance | AdditionalTaintStep | nodes -| reflected_xss.py:2:26:2:32 | ControlFlowNode for ImportMember | semmle.label | ControlFlowNode for ImportMember | -| reflected_xss.py:2:26:2:32 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| reflected_xss.py:9:5:9:14 | ControlFlowNode for first_name | semmle.label | ControlFlowNode for first_name | -| reflected_xss.py:9:18:9:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| reflected_xss.py:9:18:9:29 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| reflected_xss.py:9:18:9:45 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| reflected_xss.py:10:26:10:53 | ControlFlowNode for BinaryExpr | semmle.label | ControlFlowNode for BinaryExpr | -| reflected_xss.py:21:5:21:8 | ControlFlowNode for data | semmle.label | ControlFlowNode for data | -| 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:5:27:8 | ControlFlowNode for data | semmle.label | ControlFlowNode for data | -| 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() | +| reflected_xss.py:2:26:2:32 | After ImportMember | semmle.label | After ImportMember | +| reflected_xss.py:2:26:2:32 | request | semmle.label | request | +| reflected_xss.py:9:5:9:14 | first_name | semmle.label | first_name | +| reflected_xss.py:9:18:9:24 | request | semmle.label | request | +| reflected_xss.py:9:18:9:29 | After Attribute | semmle.label | After Attribute | +| reflected_xss.py:9:18:9:45 | After Attribute() | semmle.label | After Attribute() | +| reflected_xss.py:10:26:10:53 | After BinaryExpr | semmle.label | After BinaryExpr | +| reflected_xss.py:21:5:21:8 | data | semmle.label | data | +| reflected_xss.py:21:23:21:29 | request | semmle.label | request | +| reflected_xss.py:22:26:22:41 | After Attribute() | semmle.label | After Attribute() | +| reflected_xss.py:27:5:27:8 | data | semmle.label | data | +| reflected_xss.py:27:23:27:29 | request | semmle.label | request | +| reflected_xss.py:28:26:28:41 | After Attribute() | semmle.label | After Attribute() | subpaths +#select +| reflected_xss.py:10:26:10:53 | After BinaryExpr | reflected_xss.py:2:26:2:32 | After ImportMember | reflected_xss.py:10:26:10:53 | After BinaryExpr | Cross-site scripting vulnerability due to a $@. | reflected_xss.py:2:26:2:32 | After ImportMember | user-provided value | +| reflected_xss.py:22:26:22:41 | After Attribute() | reflected_xss.py:2:26:2:32 | After ImportMember | reflected_xss.py:22:26:22:41 | After Attribute() | Cross-site scripting vulnerability due to a $@. | reflected_xss.py:2:26:2:32 | After ImportMember | user-provided value | +| reflected_xss.py:28:26:28:41 | After Attribute() | reflected_xss.py:2:26:2:32 | After ImportMember | reflected_xss.py:28:26:28:41 | After Attribute() | Cross-site scripting vulnerability due to a $@. | reflected_xss.py:2:26:2:32 | After ImportMember | user-provided value | diff --git a/python/ql/test/query-tests/Security/CWE-089-SqlInjection-local-threat-model/SqlInjection.expected b/python/ql/test/query-tests/Security/CWE-089-SqlInjection-local-threat-model/SqlInjection.expected index 8cf2ec7b8266..6cee1d5ca8bb 100644 --- a/python/ql/test/query-tests/Security/CWE-089-SqlInjection-local-threat-model/SqlInjection.expected +++ b/python/ql/test/query-tests/Security/CWE-089-SqlInjection-local-threat-model/SqlInjection.expected @@ -1,10 +1,10 @@ #select -| test.py:6:14:6:24 | ControlFlowNode for Subscript | test.py:6:14:6:21 | ControlFlowNode for Attribute | test.py:6:14:6:24 | ControlFlowNode for Subscript | This SQL query depends on a $@. | test.py:6:14:6:21 | ControlFlowNode for Attribute | user-provided value | +| test.py:6:14:6:24 | After Subscript | test.py:6:14:6:21 | After Attribute | test.py:6:14:6:24 | After Subscript | This SQL query depends on a $@. | test.py:6:14:6:21 | After Attribute | user-provided value | edges -| test.py:6:14:6:21 | ControlFlowNode for Attribute | test.py:6:14:6:24 | ControlFlowNode for Subscript | provenance | Src:MaD:1 | +| test.py:6:14:6:21 | After Attribute | test.py:6:14:6:24 | After Subscript | provenance | Src:MaD:1 | models | 1 | Source: sys; Member[argv]; commandargs | nodes -| test.py:6:14:6:21 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| test.py:6:14:6:24 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript | +| test.py:6:14:6:21 | After Attribute | semmle.label | After Attribute | +| test.py:6:14:6:24 | After Subscript | semmle.label | After Subscript | subpaths diff --git a/python/ql/test/query-tests/Security/CWE-089-SqlInjection/CONSISTENCY/DataFlowConsistency.expected b/python/ql/test/query-tests/Security/CWE-089-SqlInjection/CONSISTENCY/DataFlowConsistency.expected index ec06da26e30b..b5a0904d0eb1 100644 --- a/python/ql/test/query-tests/Security/CWE-089-SqlInjection/CONSISTENCY/DataFlowConsistency.expected +++ b/python/ql/test/query-tests/Security/CWE-089-SqlInjection/CONSISTENCY/DataFlowConsistency.expected @@ -1,6 +1,6 @@ storeStepIsLocal -| sql_injection.py:10:1:10:25 | [orm-model] Class User | sql_injection.py:18:9:18:80 | ControlFlowNode for Attribute() | Store step does not preserve enclosing callable. | -| sql_injection.py:10:1:10:25 | [orm-model] Class User | sql_injection.py:24:9:24:97 | ControlFlowNode for Attribute() | Store step does not preserve enclosing callable. | -| sql_injection.py:10:1:10:25 | [orm-model] Class User | sql_injection.py:25:9:25:84 | ControlFlowNode for Attribute() | Store step does not preserve enclosing callable. | -| sql_injection.py:10:1:10:25 | [orm-model] Class User | sql_injection.py:26:9:26:86 | ControlFlowNode for Attribute() | Store step does not preserve enclosing callable. | -| sql_injection.py:10:1:10:25 | [orm-model] Class User | sql_injection.py:40:9:40:82 | ControlFlowNode for Attribute() | Store step does not preserve enclosing callable. | +| sql_injection.py:10:1:10:25 | [orm-model] Class User | sql_injection.py:18:9:18:80 | After Attribute() | Store step does not preserve enclosing callable. | +| sql_injection.py:10:1:10:25 | [orm-model] Class User | sql_injection.py:24:9:24:97 | After Attribute() | Store step does not preserve enclosing callable. | +| sql_injection.py:10:1:10:25 | [orm-model] Class User | sql_injection.py:25:9:25:84 | After Attribute() | Store step does not preserve enclosing callable. | +| sql_injection.py:10:1:10:25 | [orm-model] Class User | sql_injection.py:26:9:26:86 | After Attribute() | Store step does not preserve enclosing callable. | +| sql_injection.py:10:1:10:25 | [orm-model] Class User | sql_injection.py:40:9:40:82 | After Attribute() | Store step does not preserve enclosing callable. | diff --git a/python/ql/test/query-tests/Security/CWE-089-SqlInjection/SqlInjection.expected b/python/ql/test/query-tests/Security/CWE-089-SqlInjection/SqlInjection.expected index 8f60394d8a2b..59a29d2ad703 100644 --- a/python/ql/test/query-tests/Security/CWE-089-SqlInjection/SqlInjection.expected +++ b/python/ql/test/query-tests/Security/CWE-089-SqlInjection/SqlInjection.expected @@ -1,84 +1,54 @@ -#select -| app.py:23:20:23:24 | ControlFlowNode for query | app.py:20:18:20:21 | ControlFlowNode for name | app.py:23:20:23:24 | ControlFlowNode for query | This SQL query depends on a $@. | app.py:20:18:20:21 | ControlFlowNode for name | user-provided value | -| app.py:30:20:30:24 | ControlFlowNode for query | app.py:27:19:27:22 | ControlFlowNode for name | app.py:30:20:30:24 | ControlFlowNode for query | This SQL query depends on a $@. | app.py:27:19:27:22 | ControlFlowNode for name | user-provided value | -| app.py:37:20:37:24 | ControlFlowNode for query | app.py:34:19:34:22 | ControlFlowNode for name | app.py:37:20:37:24 | ControlFlowNode for query | This SQL query depends on a $@. | app.py:34:19:34:22 | ControlFlowNode for name | user-provided value | -| app.py:44:20:44:24 | ControlFlowNode for query | app.py:41:19:41:22 | ControlFlowNode for name | app.py:44:20:44:24 | ControlFlowNode for query | This SQL query depends on a $@. | app.py:41:19:41:22 | ControlFlowNode for name | user-provided value | -| app.py:51:20:51:24 | ControlFlowNode for query | app.py:48:19:48:22 | ControlFlowNode for name | app.py:51:20:51:24 | ControlFlowNode for query | This SQL query depends on a $@. | app.py:48:19:48:22 | ControlFlowNode for name | user-provided value | -| sql_injection.py:21:24:21:77 | ControlFlowNode for BinaryExpr | sql_injection.py:14:15:14:22 | ControlFlowNode for username | sql_injection.py:21:24:21:77 | ControlFlowNode for BinaryExpr | This SQL query depends on a $@. | sql_injection.py:14:15:14:22 | ControlFlowNode for username | user-provided value | -| sql_injection.py:24:38:24:95 | ControlFlowNode for BinaryExpr | sql_injection.py:14:15:14:22 | ControlFlowNode for username | sql_injection.py:24:38:24:95 | ControlFlowNode for BinaryExpr | This SQL query depends on a $@. | sql_injection.py:14:15:14:22 | ControlFlowNode for username | user-provided value | -| sql_injection.py:25:26:25:83 | ControlFlowNode for BinaryExpr | sql_injection.py:14:15:14:22 | ControlFlowNode for username | sql_injection.py:25:26:25:83 | ControlFlowNode for BinaryExpr | This SQL query depends on a $@. | sql_injection.py:14:15:14:22 | ControlFlowNode for username | user-provided value | -| sql_injection.py:26:28:26:85 | ControlFlowNode for BinaryExpr | sql_injection.py:14:15:14:22 | ControlFlowNode for username | sql_injection.py:26:28:26:85 | ControlFlowNode for BinaryExpr | This SQL query depends on a $@. | sql_injection.py:14:15:14:22 | ControlFlowNode for username | user-provided value | -| sqlalchemy_textclause.py:27:28:27:87 | ControlFlowNode for Attribute() | sqlalchemy_textclause.py:23:15:23:22 | ControlFlowNode for username | sqlalchemy_textclause.py:27:28:27:87 | ControlFlowNode for Attribute() | This SQL query depends on a $@. | sqlalchemy_textclause.py:23:15:23:22 | ControlFlowNode for username | user-provided value | -| sqlalchemy_textclause.py:31:50:31:72 | ControlFlowNode for Attribute() | sqlalchemy_textclause.py:23:15:23:22 | ControlFlowNode for username | sqlalchemy_textclause.py:31:50:31:72 | ControlFlowNode for Attribute() | This SQL query depends on a $@. | sqlalchemy_textclause.py:23:15:23:22 | ControlFlowNode for username | user-provided value | -| sqlalchemy_textclause.py:41:26:41:33 | ControlFlowNode for username | sqlalchemy_textclause.py:23:15:23:22 | ControlFlowNode for username | sqlalchemy_textclause.py:41:26:41:33 | ControlFlowNode for username | This SQL query depends on a $@. | sqlalchemy_textclause.py:23:15:23:22 | ControlFlowNode for username | user-provided value | -| sqlalchemy_textclause.py:42:31:42:38 | ControlFlowNode for username | sqlalchemy_textclause.py:23:15:23:22 | ControlFlowNode for username | sqlalchemy_textclause.py:42:31:42:38 | ControlFlowNode for username | This SQL query depends on a $@. | sqlalchemy_textclause.py:23:15:23:22 | ControlFlowNode for username | user-provided value | -| sqlalchemy_textclause.py:43:30:43:37 | ControlFlowNode for username | sqlalchemy_textclause.py:23:15:23:22 | ControlFlowNode for username | sqlalchemy_textclause.py:43:30:43:37 | ControlFlowNode for username | This SQL query depends on a $@. | sqlalchemy_textclause.py:23:15:23:22 | ControlFlowNode for username | user-provided value | -| sqlalchemy_textclause.py:44:35:44:42 | ControlFlowNode for username | sqlalchemy_textclause.py:23:15:23:22 | ControlFlowNode for username | sqlalchemy_textclause.py:44:35:44:42 | ControlFlowNode for username | This SQL query depends on a $@. | sqlalchemy_textclause.py:23:15:23:22 | ControlFlowNode for username | user-provided value | -| sqlalchemy_textclause.py:45:41:45:48 | ControlFlowNode for username | sqlalchemy_textclause.py:23:15:23:22 | ControlFlowNode for username | sqlalchemy_textclause.py:45:41:45:48 | ControlFlowNode for username | This SQL query depends on a $@. | sqlalchemy_textclause.py:23:15:23:22 | ControlFlowNode for username | user-provided value | -| sqlalchemy_textclause.py:46:46:46:53 | ControlFlowNode for username | sqlalchemy_textclause.py:23:15:23:22 | ControlFlowNode for username | sqlalchemy_textclause.py:46:46:46:53 | ControlFlowNode for username | This SQL query depends on a $@. | sqlalchemy_textclause.py:23:15:23:22 | ControlFlowNode for username | user-provided value | -| sqlalchemy_textclause.py:47:47:47:54 | ControlFlowNode for username | sqlalchemy_textclause.py:23:15:23:22 | ControlFlowNode for username | sqlalchemy_textclause.py:47:47:47:54 | ControlFlowNode for username | This SQL query depends on a $@. | sqlalchemy_textclause.py:23:15:23:22 | ControlFlowNode for username | user-provided value | -| sqlalchemy_textclause.py:48:52:48:59 | ControlFlowNode for username | sqlalchemy_textclause.py:23:15:23:22 | ControlFlowNode for username | sqlalchemy_textclause.py:48:52:48:59 | ControlFlowNode for username | This SQL query depends on a $@. | sqlalchemy_textclause.py:23:15:23:22 | ControlFlowNode for username | user-provided value | -| sqlalchemy_textclause.py:50:18:50:25 | ControlFlowNode for username | sqlalchemy_textclause.py:23:15:23:22 | ControlFlowNode for username | sqlalchemy_textclause.py:50:18:50:25 | ControlFlowNode for username | This SQL query depends on a $@. | sqlalchemy_textclause.py:23:15:23:22 | ControlFlowNode for username | user-provided value | -| sqlalchemy_textclause.py:51:24:51:31 | ControlFlowNode for username | sqlalchemy_textclause.py:23:15:23:22 | ControlFlowNode for username | sqlalchemy_textclause.py:51:24:51:31 | ControlFlowNode for username | This SQL query depends on a $@. | sqlalchemy_textclause.py:23:15:23:22 | ControlFlowNode for username | user-provided value | edges -| app.py:20:18:20:21 | ControlFlowNode for name | app.py:21:5:21:9 | ControlFlowNode for query | provenance | | -| app.py:21:5:21:9 | ControlFlowNode for query | app.py:23:20:23:24 | ControlFlowNode for query | provenance | | -| app.py:27:19:27:22 | ControlFlowNode for name | app.py:28:5:28:9 | ControlFlowNode for query | provenance | | -| app.py:28:5:28:9 | ControlFlowNode for query | app.py:30:20:30:24 | ControlFlowNode for query | provenance | | -| app.py:34:19:34:22 | ControlFlowNode for name | app.py:35:5:35:9 | ControlFlowNode for query | provenance | | -| app.py:35:5:35:9 | ControlFlowNode for query | app.py:37:20:37:24 | ControlFlowNode for query | provenance | | -| app.py:41:19:41:22 | ControlFlowNode for name | app.py:42:5:42:9 | ControlFlowNode for query | provenance | | -| app.py:42:5:42:9 | ControlFlowNode for query | app.py:44:20:44:24 | ControlFlowNode for query | provenance | | -| app.py:48:19:48:22 | ControlFlowNode for name | app.py:49:5:49:9 | ControlFlowNode for query | provenance | | -| app.py:49:5:49:9 | ControlFlowNode for query | app.py:51:20:51:24 | ControlFlowNode for query | provenance | | -| sql_injection.py:14:15:14:22 | ControlFlowNode for username | sql_injection.py:21:24:21:77 | ControlFlowNode for BinaryExpr | provenance | | -| sql_injection.py:14:15:14:22 | ControlFlowNode for username | sql_injection.py:24:38:24:95 | ControlFlowNode for BinaryExpr | provenance | | -| sql_injection.py:14:15:14:22 | ControlFlowNode for username | sql_injection.py:25:26:25:83 | ControlFlowNode for BinaryExpr | provenance | | -| sql_injection.py:14:15:14:22 | ControlFlowNode for username | sql_injection.py:26:28:26:85 | ControlFlowNode for BinaryExpr | provenance | | -| sqlalchemy_textclause.py:23:15:23:22 | ControlFlowNode for username | sqlalchemy_textclause.py:27:28:27:87 | ControlFlowNode for Attribute() | provenance | | -| sqlalchemy_textclause.py:23:15:23:22 | ControlFlowNode for username | sqlalchemy_textclause.py:31:50:31:72 | ControlFlowNode for Attribute() | provenance | | -| sqlalchemy_textclause.py:23:15:23:22 | ControlFlowNode for username | sqlalchemy_textclause.py:41:26:41:33 | ControlFlowNode for username | provenance | | -| sqlalchemy_textclause.py:23:15:23:22 | ControlFlowNode for username | sqlalchemy_textclause.py:42:31:42:38 | ControlFlowNode for username | provenance | | -| sqlalchemy_textclause.py:23:15:23:22 | ControlFlowNode for username | sqlalchemy_textclause.py:43:30:43:37 | ControlFlowNode for username | provenance | | -| sqlalchemy_textclause.py:23:15:23:22 | ControlFlowNode for username | sqlalchemy_textclause.py:44:35:44:42 | ControlFlowNode for username | provenance | | -| sqlalchemy_textclause.py:23:15:23:22 | ControlFlowNode for username | sqlalchemy_textclause.py:45:41:45:48 | ControlFlowNode for username | provenance | | -| sqlalchemy_textclause.py:23:15:23:22 | ControlFlowNode for username | sqlalchemy_textclause.py:46:46:46:53 | ControlFlowNode for username | provenance | | -| sqlalchemy_textclause.py:23:15:23:22 | ControlFlowNode for username | sqlalchemy_textclause.py:47:47:47:54 | ControlFlowNode for username | provenance | | -| sqlalchemy_textclause.py:23:15:23:22 | ControlFlowNode for username | sqlalchemy_textclause.py:48:52:48:59 | ControlFlowNode for username | provenance | | -| sqlalchemy_textclause.py:23:15:23:22 | ControlFlowNode for username | sqlalchemy_textclause.py:50:18:50:25 | ControlFlowNode for username | provenance | | -| sqlalchemy_textclause.py:23:15:23:22 | ControlFlowNode for username | sqlalchemy_textclause.py:51:24:51:31 | ControlFlowNode for username | provenance | | +| sql_injection.py:14:15:14:22 | username | sql_injection.py:21:24:21:77 | After BinaryExpr | provenance | | +| sql_injection.py:14:15:14:22 | username | sql_injection.py:24:38:24:95 | After BinaryExpr | provenance | | +| sql_injection.py:14:15:14:22 | username | sql_injection.py:25:26:25:83 | After BinaryExpr | provenance | | +| sql_injection.py:14:15:14:22 | username | sql_injection.py:26:28:26:85 | After BinaryExpr | provenance | | +| sqlalchemy_textclause.py:23:15:23:22 | username | sqlalchemy_textclause.py:27:28:27:87 | After Attribute() | provenance | | +| sqlalchemy_textclause.py:23:15:23:22 | username | sqlalchemy_textclause.py:31:50:31:72 | After Attribute() | provenance | | +| sqlalchemy_textclause.py:23:15:23:22 | username | sqlalchemy_textclause.py:41:26:41:33 | username | provenance | | +| sqlalchemy_textclause.py:23:15:23:22 | username | sqlalchemy_textclause.py:42:31:42:38 | username | provenance | | +| sqlalchemy_textclause.py:23:15:23:22 | username | sqlalchemy_textclause.py:43:30:43:37 | username | provenance | | +| sqlalchemy_textclause.py:23:15:23:22 | username | sqlalchemy_textclause.py:44:35:44:42 | username | provenance | | +| sqlalchemy_textclause.py:23:15:23:22 | username | sqlalchemy_textclause.py:45:41:45:48 | username | provenance | | +| sqlalchemy_textclause.py:23:15:23:22 | username | sqlalchemy_textclause.py:46:46:46:53 | username | provenance | | +| sqlalchemy_textclause.py:23:15:23:22 | username | sqlalchemy_textclause.py:47:47:47:54 | username | provenance | | +| sqlalchemy_textclause.py:23:15:23:22 | username | sqlalchemy_textclause.py:48:52:48:59 | username | provenance | | +| sqlalchemy_textclause.py:23:15:23:22 | username | sqlalchemy_textclause.py:50:18:50:25 | username | provenance | | +| sqlalchemy_textclause.py:23:15:23:22 | username | sqlalchemy_textclause.py:51:24:51:31 | username | provenance | | nodes -| app.py:20:18:20:21 | ControlFlowNode for name | semmle.label | ControlFlowNode for name | -| app.py:21:5:21:9 | ControlFlowNode for query | semmle.label | ControlFlowNode for query | -| app.py:23:20:23:24 | ControlFlowNode for query | semmle.label | ControlFlowNode for query | -| app.py:27:19:27:22 | ControlFlowNode for name | semmle.label | ControlFlowNode for name | -| app.py:28:5:28:9 | ControlFlowNode for query | semmle.label | ControlFlowNode for query | -| app.py:30:20:30:24 | ControlFlowNode for query | semmle.label | ControlFlowNode for query | -| app.py:34:19:34:22 | ControlFlowNode for name | semmle.label | ControlFlowNode for name | -| app.py:35:5:35:9 | ControlFlowNode for query | semmle.label | ControlFlowNode for query | -| app.py:37:20:37:24 | ControlFlowNode for query | semmle.label | ControlFlowNode for query | -| app.py:41:19:41:22 | ControlFlowNode for name | semmle.label | ControlFlowNode for name | -| app.py:42:5:42:9 | ControlFlowNode for query | semmle.label | ControlFlowNode for query | -| app.py:44:20:44:24 | ControlFlowNode for query | semmle.label | ControlFlowNode for query | -| app.py:48:19:48:22 | ControlFlowNode for name | semmle.label | ControlFlowNode for name | -| app.py:49:5:49:9 | ControlFlowNode for query | semmle.label | ControlFlowNode for query | -| app.py:51:20:51:24 | ControlFlowNode for query | semmle.label | ControlFlowNode for query | -| sql_injection.py:14:15:14:22 | ControlFlowNode for username | semmle.label | ControlFlowNode for username | -| sql_injection.py:21:24:21:77 | ControlFlowNode for BinaryExpr | semmle.label | ControlFlowNode for BinaryExpr | -| sql_injection.py:24:38:24:95 | ControlFlowNode for BinaryExpr | semmle.label | ControlFlowNode for BinaryExpr | -| sql_injection.py:25:26:25:83 | ControlFlowNode for BinaryExpr | semmle.label | ControlFlowNode for BinaryExpr | -| sql_injection.py:26:28:26:85 | ControlFlowNode for BinaryExpr | semmle.label | ControlFlowNode for BinaryExpr | -| sqlalchemy_textclause.py:23:15:23:22 | ControlFlowNode for username | semmle.label | ControlFlowNode for username | -| sqlalchemy_textclause.py:27:28:27:87 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| sqlalchemy_textclause.py:31:50:31:72 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| sqlalchemy_textclause.py:41:26:41:33 | ControlFlowNode for username | semmle.label | ControlFlowNode for username | -| sqlalchemy_textclause.py:42:31:42:38 | ControlFlowNode for username | semmle.label | ControlFlowNode for username | -| sqlalchemy_textclause.py:43:30:43:37 | ControlFlowNode for username | semmle.label | ControlFlowNode for username | -| sqlalchemy_textclause.py:44:35:44:42 | ControlFlowNode for username | semmle.label | ControlFlowNode for username | -| sqlalchemy_textclause.py:45:41:45:48 | ControlFlowNode for username | semmle.label | ControlFlowNode for username | -| sqlalchemy_textclause.py:46:46:46:53 | ControlFlowNode for username | semmle.label | ControlFlowNode for username | -| sqlalchemy_textclause.py:47:47:47:54 | ControlFlowNode for username | semmle.label | ControlFlowNode for username | -| sqlalchemy_textclause.py:48:52:48:59 | ControlFlowNode for username | semmle.label | ControlFlowNode for username | -| sqlalchemy_textclause.py:50:18:50:25 | ControlFlowNode for username | semmle.label | ControlFlowNode for username | -| sqlalchemy_textclause.py:51:24:51:31 | ControlFlowNode for username | semmle.label | ControlFlowNode for username | +| sql_injection.py:14:15:14:22 | username | semmle.label | username | +| sql_injection.py:21:24:21:77 | After BinaryExpr | semmle.label | After BinaryExpr | +| sql_injection.py:24:38:24:95 | After BinaryExpr | semmle.label | After BinaryExpr | +| sql_injection.py:25:26:25:83 | After BinaryExpr | semmle.label | After BinaryExpr | +| sql_injection.py:26:28:26:85 | After BinaryExpr | semmle.label | After BinaryExpr | +| sqlalchemy_textclause.py:23:15:23:22 | username | semmle.label | username | +| sqlalchemy_textclause.py:27:28:27:87 | After Attribute() | semmle.label | After Attribute() | +| sqlalchemy_textclause.py:31:50:31:72 | After Attribute() | semmle.label | After Attribute() | +| sqlalchemy_textclause.py:41:26:41:33 | username | semmle.label | username | +| sqlalchemy_textclause.py:42:31:42:38 | username | semmle.label | username | +| sqlalchemy_textclause.py:43:30:43:37 | username | semmle.label | username | +| sqlalchemy_textclause.py:44:35:44:42 | username | semmle.label | username | +| sqlalchemy_textclause.py:45:41:45:48 | username | semmle.label | username | +| sqlalchemy_textclause.py:46:46:46:53 | username | semmle.label | username | +| sqlalchemy_textclause.py:47:47:47:54 | username | semmle.label | username | +| sqlalchemy_textclause.py:48:52:48:59 | username | semmle.label | username | +| sqlalchemy_textclause.py:50:18:50:25 | username | semmle.label | username | +| sqlalchemy_textclause.py:51:24:51:31 | username | semmle.label | username | subpaths +#select +| sql_injection.py:21:24:21:77 | After BinaryExpr | sql_injection.py:14:15:14:22 | username | sql_injection.py:21:24:21:77 | After BinaryExpr | This SQL query depends on a $@. | sql_injection.py:14:15:14:22 | username | user-provided value | +| sql_injection.py:24:38:24:95 | After BinaryExpr | sql_injection.py:14:15:14:22 | username | sql_injection.py:24:38:24:95 | After BinaryExpr | This SQL query depends on a $@. | sql_injection.py:14:15:14:22 | username | user-provided value | +| sql_injection.py:25:26:25:83 | After BinaryExpr | sql_injection.py:14:15:14:22 | username | sql_injection.py:25:26:25:83 | After BinaryExpr | This SQL query depends on a $@. | sql_injection.py:14:15:14:22 | username | user-provided value | +| sql_injection.py:26:28:26:85 | After BinaryExpr | sql_injection.py:14:15:14:22 | username | sql_injection.py:26:28:26:85 | After BinaryExpr | This SQL query depends on a $@. | sql_injection.py:14:15:14:22 | username | user-provided value | +| sqlalchemy_textclause.py:27:28:27:87 | After Attribute() | sqlalchemy_textclause.py:23:15:23:22 | username | sqlalchemy_textclause.py:27:28:27:87 | After Attribute() | This SQL query depends on a $@. | sqlalchemy_textclause.py:23:15:23:22 | username | user-provided value | +| sqlalchemy_textclause.py:31:50:31:72 | After Attribute() | sqlalchemy_textclause.py:23:15:23:22 | username | sqlalchemy_textclause.py:31:50:31:72 | After Attribute() | This SQL query depends on a $@. | sqlalchemy_textclause.py:23:15:23:22 | username | user-provided value | +| sqlalchemy_textclause.py:41:26:41:33 | username | sqlalchemy_textclause.py:23:15:23:22 | username | sqlalchemy_textclause.py:41:26:41:33 | username | This SQL query depends on a $@. | sqlalchemy_textclause.py:23:15:23:22 | username | user-provided value | +| sqlalchemy_textclause.py:42:31:42:38 | username | sqlalchemy_textclause.py:23:15:23:22 | username | sqlalchemy_textclause.py:42:31:42:38 | username | This SQL query depends on a $@. | sqlalchemy_textclause.py:23:15:23:22 | username | user-provided value | +| sqlalchemy_textclause.py:43:30:43:37 | username | sqlalchemy_textclause.py:23:15:23:22 | username | sqlalchemy_textclause.py:43:30:43:37 | username | This SQL query depends on a $@. | sqlalchemy_textclause.py:23:15:23:22 | username | user-provided value | +| sqlalchemy_textclause.py:44:35:44:42 | username | sqlalchemy_textclause.py:23:15:23:22 | username | sqlalchemy_textclause.py:44:35:44:42 | username | This SQL query depends on a $@. | sqlalchemy_textclause.py:23:15:23:22 | username | user-provided value | +| sqlalchemy_textclause.py:45:41:45:48 | username | sqlalchemy_textclause.py:23:15:23:22 | username | sqlalchemy_textclause.py:45:41:45:48 | username | This SQL query depends on a $@. | sqlalchemy_textclause.py:23:15:23:22 | username | user-provided value | +| sqlalchemy_textclause.py:46:46:46:53 | username | sqlalchemy_textclause.py:23:15:23:22 | username | sqlalchemy_textclause.py:46:46:46:53 | username | This SQL query depends on a $@. | sqlalchemy_textclause.py:23:15:23:22 | username | user-provided value | +| sqlalchemy_textclause.py:47:47:47:54 | username | sqlalchemy_textclause.py:23:15:23:22 | username | sqlalchemy_textclause.py:47:47:47:54 | username | This SQL query depends on a $@. | sqlalchemy_textclause.py:23:15:23:22 | username | user-provided value | +| sqlalchemy_textclause.py:48:52:48:59 | username | sqlalchemy_textclause.py:23:15:23:22 | username | sqlalchemy_textclause.py:48:52:48:59 | username | This SQL query depends on a $@. | sqlalchemy_textclause.py:23:15:23:22 | username | user-provided value | +| sqlalchemy_textclause.py:50:18:50:25 | username | sqlalchemy_textclause.py:23:15:23:22 | username | sqlalchemy_textclause.py:50:18:50:25 | username | This SQL query depends on a $@. | sqlalchemy_textclause.py:23:15:23:22 | username | user-provided value | +| sqlalchemy_textclause.py:51:24:51:31 | username | sqlalchemy_textclause.py:23:15:23:22 | username | sqlalchemy_textclause.py:51:24:51:31 | username | This SQL query depends on a $@. | sqlalchemy_textclause.py:23:15:23:22 | username | user-provided value | diff --git a/python/ql/test/query-tests/Security/CWE-090-LdapInjection/LdapInjection.expected b/python/ql/test/query-tests/Security/CWE-090-LdapInjection/LdapInjection.expected index 20170029899e..635960e2c48c 100644 --- a/python/ql/test/query-tests/Security/CWE-090-LdapInjection/LdapInjection.expected +++ b/python/ql/test/query-tests/Security/CWE-090-LdapInjection/LdapInjection.expected @@ -1,121 +1,121 @@ edges -| ldap3_bad.py:1:19:1:25 | ControlFlowNode for ImportMember | ldap3_bad.py:1:19:1:25 | ControlFlowNode for request | provenance | | -| ldap3_bad.py:1:19:1:25 | ControlFlowNode for ImportMember | ldap3_bad.py:1:19:1:25 | ControlFlowNode for request | provenance | | -| ldap3_bad.py:1:19:1:25 | ControlFlowNode for request | ldap3_bad.py:13:17:13:23 | ControlFlowNode for request | provenance | | -| ldap3_bad.py:1:19:1:25 | ControlFlowNode for request | ldap3_bad.py:13:17:13:23 | ControlFlowNode for request | provenance | | -| ldap3_bad.py:1:19:1:25 | ControlFlowNode for request | ldap3_bad.py:14:21:14:27 | ControlFlowNode for request | provenance | | -| ldap3_bad.py:1:19:1:25 | ControlFlowNode for request | ldap3_bad.py:30:17:30:23 | ControlFlowNode for request | provenance | | -| ldap3_bad.py:1:19:1:25 | ControlFlowNode for request | ldap3_bad.py:30:17:30:23 | ControlFlowNode for request | provenance | | -| ldap3_bad.py:1:19:1:25 | ControlFlowNode for request | ldap3_bad.py:31:21:31:27 | ControlFlowNode for request | provenance | | -| ldap3_bad.py:13:5:13:13 | ControlFlowNode for unsafe_dc | ldap3_bad.py:16:5:16:6 | ControlFlowNode for dn | provenance | | -| ldap3_bad.py:13:17:13:23 | ControlFlowNode for request | ldap3_bad.py:13:5:13:13 | ControlFlowNode for unsafe_dc | provenance | AdditionalTaintStep | -| ldap3_bad.py:13:17:13:23 | ControlFlowNode for request | ldap3_bad.py:14:5:14:17 | ControlFlowNode for unsafe_filter | provenance | AdditionalTaintStep | -| ldap3_bad.py:14:5:14:17 | ControlFlowNode for unsafe_filter | ldap3_bad.py:17:5:17:17 | ControlFlowNode for search_filter | provenance | | -| ldap3_bad.py:14:21:14:27 | ControlFlowNode for request | ldap3_bad.py:14:5:14:17 | ControlFlowNode for unsafe_filter | provenance | AdditionalTaintStep | -| ldap3_bad.py:16:5:16:6 | ControlFlowNode for dn | ldap3_bad.py:21:17:21:18 | ControlFlowNode for dn | provenance | | -| ldap3_bad.py:17:5:17:17 | ControlFlowNode for search_filter | ldap3_bad.py:21:21:21:33 | ControlFlowNode for search_filter | provenance | | -| ldap3_bad.py:30:5:30:13 | ControlFlowNode for unsafe_dc | ldap3_bad.py:33:5:33:6 | ControlFlowNode for dn | provenance | | -| ldap3_bad.py:30:17:30:23 | ControlFlowNode for request | ldap3_bad.py:30:5:30:13 | ControlFlowNode for unsafe_dc | provenance | AdditionalTaintStep | -| ldap3_bad.py:30:17:30:23 | ControlFlowNode for request | ldap3_bad.py:31:5:31:17 | ControlFlowNode for unsafe_filter | provenance | AdditionalTaintStep | -| ldap3_bad.py:31:5:31:17 | ControlFlowNode for unsafe_filter | ldap3_bad.py:34:5:34:17 | ControlFlowNode for search_filter | provenance | | -| ldap3_bad.py:31:21:31:27 | ControlFlowNode for request | ldap3_bad.py:31:5:31:17 | ControlFlowNode for unsafe_filter | provenance | AdditionalTaintStep | -| ldap3_bad.py:33:5:33:6 | ControlFlowNode for dn | ldap3_bad.py:38:9:38:10 | ControlFlowNode for dn | provenance | | -| ldap3_bad.py:34:5:34:17 | ControlFlowNode for search_filter | ldap3_bad.py:38:13:38:25 | ControlFlowNode for search_filter | provenance | | -| ldap_bad.py:1:19:1:25 | ControlFlowNode for ImportMember | ldap_bad.py:1:19:1:25 | ControlFlowNode for request | provenance | | -| ldap_bad.py:1:19:1:25 | ControlFlowNode for ImportMember | ldap_bad.py:1:19:1:25 | ControlFlowNode for request | provenance | | -| ldap_bad.py:1:19:1:25 | ControlFlowNode for request | ldap_bad.py:13:17:13:23 | ControlFlowNode for request | provenance | | -| ldap_bad.py:1:19:1:25 | ControlFlowNode for request | ldap_bad.py:13:17:13:23 | ControlFlowNode for request | provenance | | -| ldap_bad.py:1:19:1:25 | ControlFlowNode for request | ldap_bad.py:14:21:14:27 | ControlFlowNode for request | provenance | | -| ldap_bad.py:1:19:1:25 | ControlFlowNode for request | ldap_bad.py:30:17:30:23 | ControlFlowNode for request | provenance | | -| ldap_bad.py:1:19:1:25 | ControlFlowNode for request | ldap_bad.py:30:17:30:23 | ControlFlowNode for request | provenance | | -| ldap_bad.py:1:19:1:25 | ControlFlowNode for request | ldap_bad.py:31:21:31:27 | ControlFlowNode for request | provenance | | -| ldap_bad.py:1:19:1:25 | ControlFlowNode for request | ldap_bad.py:47:17:47:23 | ControlFlowNode for request | provenance | | -| ldap_bad.py:1:19:1:25 | ControlFlowNode for request | ldap_bad.py:47:17:47:23 | ControlFlowNode for request | provenance | | -| ldap_bad.py:1:19:1:25 | ControlFlowNode for request | ldap_bad.py:48:21:48:27 | ControlFlowNode for request | provenance | | -| ldap_bad.py:13:5:13:13 | ControlFlowNode for unsafe_dc | ldap_bad.py:16:5:16:6 | ControlFlowNode for dn | provenance | | -| ldap_bad.py:13:17:13:23 | ControlFlowNode for request | ldap_bad.py:13:5:13:13 | ControlFlowNode for unsafe_dc | provenance | AdditionalTaintStep | -| ldap_bad.py:13:17:13:23 | ControlFlowNode for request | ldap_bad.py:14:5:14:17 | ControlFlowNode for unsafe_filter | provenance | AdditionalTaintStep | -| ldap_bad.py:14:5:14:17 | ControlFlowNode for unsafe_filter | ldap_bad.py:17:5:17:17 | ControlFlowNode for search_filter | provenance | | -| ldap_bad.py:14:21:14:27 | ControlFlowNode for request | ldap_bad.py:14:5:14:17 | ControlFlowNode for unsafe_filter | provenance | AdditionalTaintStep | -| ldap_bad.py:16:5:16:6 | ControlFlowNode for dn | ldap_bad.py:21:9:21:10 | ControlFlowNode for dn | provenance | | -| ldap_bad.py:17:5:17:17 | ControlFlowNode for search_filter | ldap_bad.py:21:33:21:45 | ControlFlowNode for search_filter | provenance | | -| ldap_bad.py:30:5:30:13 | ControlFlowNode for unsafe_dc | ldap_bad.py:33:5:33:6 | ControlFlowNode for dn | provenance | | -| ldap_bad.py:30:17:30:23 | ControlFlowNode for request | ldap_bad.py:30:5:30:13 | ControlFlowNode for unsafe_dc | provenance | AdditionalTaintStep | -| ldap_bad.py:30:17:30:23 | ControlFlowNode for request | ldap_bad.py:31:5:31:17 | ControlFlowNode for unsafe_filter | provenance | AdditionalTaintStep | -| ldap_bad.py:31:5:31:17 | ControlFlowNode for unsafe_filter | ldap_bad.py:34:5:34:17 | ControlFlowNode for search_filter | provenance | | -| ldap_bad.py:31:21:31:27 | ControlFlowNode for request | ldap_bad.py:31:5:31:17 | ControlFlowNode for unsafe_filter | provenance | AdditionalTaintStep | -| ldap_bad.py:33:5:33:6 | ControlFlowNode for dn | ldap_bad.py:37:9:37:10 | ControlFlowNode for dn | provenance | | -| ldap_bad.py:34:5:34:17 | ControlFlowNode for search_filter | ldap_bad.py:37:33:37:45 | ControlFlowNode for search_filter | provenance | | -| ldap_bad.py:47:5:47:13 | ControlFlowNode for unsafe_dc | ldap_bad.py:50:5:50:6 | ControlFlowNode for dn | provenance | | -| ldap_bad.py:47:17:47:23 | ControlFlowNode for request | ldap_bad.py:47:5:47:13 | ControlFlowNode for unsafe_dc | provenance | AdditionalTaintStep | -| ldap_bad.py:47:17:47:23 | ControlFlowNode for request | ldap_bad.py:48:5:48:17 | ControlFlowNode for unsafe_filter | provenance | AdditionalTaintStep | -| ldap_bad.py:48:5:48:17 | ControlFlowNode for unsafe_filter | ldap_bad.py:51:5:51:17 | ControlFlowNode for search_filter | provenance | | -| ldap_bad.py:48:21:48:27 | ControlFlowNode for request | ldap_bad.py:48:5:48:17 | ControlFlowNode for unsafe_filter | provenance | AdditionalTaintStep | -| ldap_bad.py:50:5:50:6 | ControlFlowNode for dn | ldap_bad.py:55:9:55:10 | ControlFlowNode for dn | provenance | | -| ldap_bad.py:51:5:51:17 | ControlFlowNode for search_filter | ldap_bad.py:55:43:55:55 | ControlFlowNode for search_filter | provenance | | +| ldap3_bad.py:1:19:1:25 | After ImportMember | ldap3_bad.py:1:19:1:25 | request | provenance | | +| ldap3_bad.py:1:19:1:25 | After ImportMember | ldap3_bad.py:1:19:1:25 | request | provenance | | +| ldap3_bad.py:1:19:1:25 | request | ldap3_bad.py:13:17:13:23 | request | provenance | | +| ldap3_bad.py:1:19:1:25 | request | ldap3_bad.py:13:17:13:23 | request | provenance | | +| ldap3_bad.py:1:19:1:25 | request | ldap3_bad.py:14:21:14:27 | request | provenance | | +| ldap3_bad.py:1:19:1:25 | request | ldap3_bad.py:30:17:30:23 | request | provenance | | +| ldap3_bad.py:1:19:1:25 | request | ldap3_bad.py:30:17:30:23 | request | provenance | | +| ldap3_bad.py:1:19:1:25 | request | ldap3_bad.py:31:21:31:27 | request | provenance | | +| ldap3_bad.py:13:5:13:13 | unsafe_dc | ldap3_bad.py:16:5:16:6 | dn | provenance | | +| ldap3_bad.py:13:17:13:23 | request | ldap3_bad.py:13:5:13:13 | unsafe_dc | provenance | AdditionalTaintStep | +| ldap3_bad.py:13:17:13:23 | request | ldap3_bad.py:14:5:14:17 | unsafe_filter | provenance | AdditionalTaintStep | +| ldap3_bad.py:14:5:14:17 | unsafe_filter | ldap3_bad.py:17:5:17:17 | search_filter | provenance | | +| ldap3_bad.py:14:21:14:27 | request | ldap3_bad.py:14:5:14:17 | unsafe_filter | provenance | AdditionalTaintStep | +| ldap3_bad.py:16:5:16:6 | dn | ldap3_bad.py:21:17:21:18 | dn | provenance | | +| ldap3_bad.py:17:5:17:17 | search_filter | ldap3_bad.py:21:21:21:33 | search_filter | provenance | | +| ldap3_bad.py:30:5:30:13 | unsafe_dc | ldap3_bad.py:33:5:33:6 | dn | provenance | | +| ldap3_bad.py:30:17:30:23 | request | ldap3_bad.py:30:5:30:13 | unsafe_dc | provenance | AdditionalTaintStep | +| ldap3_bad.py:30:17:30:23 | request | ldap3_bad.py:31:5:31:17 | unsafe_filter | provenance | AdditionalTaintStep | +| ldap3_bad.py:31:5:31:17 | unsafe_filter | ldap3_bad.py:34:5:34:17 | search_filter | provenance | | +| ldap3_bad.py:31:21:31:27 | request | ldap3_bad.py:31:5:31:17 | unsafe_filter | provenance | AdditionalTaintStep | +| ldap3_bad.py:33:5:33:6 | dn | ldap3_bad.py:38:9:38:10 | dn | provenance | | +| ldap3_bad.py:34:5:34:17 | search_filter | ldap3_bad.py:38:13:38:25 | search_filter | provenance | | +| ldap_bad.py:1:19:1:25 | After ImportMember | ldap_bad.py:1:19:1:25 | request | provenance | | +| ldap_bad.py:1:19:1:25 | After ImportMember | ldap_bad.py:1:19:1:25 | request | provenance | | +| ldap_bad.py:1:19:1:25 | request | ldap_bad.py:13:17:13:23 | request | provenance | | +| ldap_bad.py:1:19:1:25 | request | ldap_bad.py:13:17:13:23 | request | provenance | | +| ldap_bad.py:1:19:1:25 | request | ldap_bad.py:14:21:14:27 | request | provenance | | +| ldap_bad.py:1:19:1:25 | request | ldap_bad.py:30:17:30:23 | request | provenance | | +| ldap_bad.py:1:19:1:25 | request | ldap_bad.py:30:17:30:23 | request | provenance | | +| ldap_bad.py:1:19:1:25 | request | ldap_bad.py:31:21:31:27 | request | provenance | | +| ldap_bad.py:1:19:1:25 | request | ldap_bad.py:47:17:47:23 | request | provenance | | +| ldap_bad.py:1:19:1:25 | request | ldap_bad.py:47:17:47:23 | request | provenance | | +| ldap_bad.py:1:19:1:25 | request | ldap_bad.py:48:21:48:27 | request | provenance | | +| ldap_bad.py:13:5:13:13 | unsafe_dc | ldap_bad.py:16:5:16:6 | dn | provenance | | +| ldap_bad.py:13:17:13:23 | request | ldap_bad.py:13:5:13:13 | unsafe_dc | provenance | AdditionalTaintStep | +| ldap_bad.py:13:17:13:23 | request | ldap_bad.py:14:5:14:17 | unsafe_filter | provenance | AdditionalTaintStep | +| ldap_bad.py:14:5:14:17 | unsafe_filter | ldap_bad.py:17:5:17:17 | search_filter | provenance | | +| ldap_bad.py:14:21:14:27 | request | ldap_bad.py:14:5:14:17 | unsafe_filter | provenance | AdditionalTaintStep | +| ldap_bad.py:16:5:16:6 | dn | ldap_bad.py:21:9:21:10 | dn | provenance | | +| ldap_bad.py:17:5:17:17 | search_filter | ldap_bad.py:21:33:21:45 | search_filter | provenance | | +| ldap_bad.py:30:5:30:13 | unsafe_dc | ldap_bad.py:33:5:33:6 | dn | provenance | | +| ldap_bad.py:30:17:30:23 | request | ldap_bad.py:30:5:30:13 | unsafe_dc | provenance | AdditionalTaintStep | +| ldap_bad.py:30:17:30:23 | request | ldap_bad.py:31:5:31:17 | unsafe_filter | provenance | AdditionalTaintStep | +| ldap_bad.py:31:5:31:17 | unsafe_filter | ldap_bad.py:34:5:34:17 | search_filter | provenance | | +| ldap_bad.py:31:21:31:27 | request | ldap_bad.py:31:5:31:17 | unsafe_filter | provenance | AdditionalTaintStep | +| ldap_bad.py:33:5:33:6 | dn | ldap_bad.py:37:9:37:10 | dn | provenance | | +| ldap_bad.py:34:5:34:17 | search_filter | ldap_bad.py:37:33:37:45 | search_filter | provenance | | +| ldap_bad.py:47:5:47:13 | unsafe_dc | ldap_bad.py:50:5:50:6 | dn | provenance | | +| ldap_bad.py:47:17:47:23 | request | ldap_bad.py:47:5:47:13 | unsafe_dc | provenance | AdditionalTaintStep | +| ldap_bad.py:47:17:47:23 | request | ldap_bad.py:48:5:48:17 | unsafe_filter | provenance | AdditionalTaintStep | +| ldap_bad.py:48:5:48:17 | unsafe_filter | ldap_bad.py:51:5:51:17 | search_filter | provenance | | +| ldap_bad.py:48:21:48:27 | request | ldap_bad.py:48:5:48:17 | unsafe_filter | provenance | AdditionalTaintStep | +| ldap_bad.py:50:5:50:6 | dn | ldap_bad.py:55:9:55:10 | dn | provenance | | +| ldap_bad.py:51:5:51:17 | search_filter | ldap_bad.py:55:43:55:55 | search_filter | provenance | | nodes -| ldap3_bad.py:1:19:1:25 | ControlFlowNode for ImportMember | semmle.label | ControlFlowNode for ImportMember | -| ldap3_bad.py:1:19:1:25 | ControlFlowNode for ImportMember | semmle.label | ControlFlowNode for ImportMember | -| ldap3_bad.py:1:19:1:25 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| ldap3_bad.py:1:19:1:25 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| ldap3_bad.py:13:5:13:13 | ControlFlowNode for unsafe_dc | semmle.label | ControlFlowNode for unsafe_dc | -| ldap3_bad.py:13:17:13:23 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| ldap3_bad.py:13:17:13:23 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| ldap3_bad.py:14:5:14:17 | ControlFlowNode for unsafe_filter | semmle.label | ControlFlowNode for unsafe_filter | -| ldap3_bad.py:14:21:14:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| ldap3_bad.py:16:5:16:6 | ControlFlowNode for dn | semmle.label | ControlFlowNode for dn | -| ldap3_bad.py:17:5:17:17 | ControlFlowNode for search_filter | semmle.label | ControlFlowNode for search_filter | -| ldap3_bad.py:21:17:21:18 | ControlFlowNode for dn | semmle.label | ControlFlowNode for dn | -| ldap3_bad.py:21:21:21:33 | ControlFlowNode for search_filter | semmle.label | ControlFlowNode for search_filter | -| ldap3_bad.py:30:5:30:13 | ControlFlowNode for unsafe_dc | semmle.label | ControlFlowNode for unsafe_dc | -| ldap3_bad.py:30:17:30:23 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| ldap3_bad.py:30:17:30:23 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| ldap3_bad.py:31:5:31:17 | ControlFlowNode for unsafe_filter | semmle.label | ControlFlowNode for unsafe_filter | -| ldap3_bad.py:31:21:31:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| ldap3_bad.py:33:5:33:6 | ControlFlowNode for dn | semmle.label | ControlFlowNode for dn | -| ldap3_bad.py:34:5:34:17 | ControlFlowNode for search_filter | semmle.label | ControlFlowNode for search_filter | -| ldap3_bad.py:38:9:38:10 | ControlFlowNode for dn | semmle.label | ControlFlowNode for dn | -| ldap3_bad.py:38:13:38:25 | ControlFlowNode for search_filter | semmle.label | ControlFlowNode for search_filter | -| ldap_bad.py:1:19:1:25 | ControlFlowNode for ImportMember | semmle.label | ControlFlowNode for ImportMember | -| ldap_bad.py:1:19:1:25 | ControlFlowNode for ImportMember | semmle.label | ControlFlowNode for ImportMember | -| ldap_bad.py:1:19:1:25 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| ldap_bad.py:1:19:1:25 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| ldap_bad.py:13:5:13:13 | ControlFlowNode for unsafe_dc | semmle.label | ControlFlowNode for unsafe_dc | -| ldap_bad.py:13:17:13:23 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| ldap_bad.py:13:17:13:23 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| ldap_bad.py:14:5:14:17 | ControlFlowNode for unsafe_filter | semmle.label | ControlFlowNode for unsafe_filter | -| ldap_bad.py:14:21:14:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| ldap_bad.py:16:5:16:6 | ControlFlowNode for dn | semmle.label | ControlFlowNode for dn | -| ldap_bad.py:17:5:17:17 | ControlFlowNode for search_filter | semmle.label | ControlFlowNode for search_filter | -| ldap_bad.py:21:9:21:10 | ControlFlowNode for dn | semmle.label | ControlFlowNode for dn | -| ldap_bad.py:21:33:21:45 | ControlFlowNode for search_filter | semmle.label | ControlFlowNode for search_filter | -| ldap_bad.py:30:5:30:13 | ControlFlowNode for unsafe_dc | semmle.label | ControlFlowNode for unsafe_dc | -| ldap_bad.py:30:17:30:23 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| ldap_bad.py:30:17:30:23 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| ldap_bad.py:31:5:31:17 | ControlFlowNode for unsafe_filter | semmle.label | ControlFlowNode for unsafe_filter | -| ldap_bad.py:31:21:31:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| ldap_bad.py:33:5:33:6 | ControlFlowNode for dn | semmle.label | ControlFlowNode for dn | -| ldap_bad.py:34:5:34:17 | ControlFlowNode for search_filter | semmle.label | ControlFlowNode for search_filter | -| ldap_bad.py:37:9:37:10 | ControlFlowNode for dn | semmle.label | ControlFlowNode for dn | -| ldap_bad.py:37:33:37:45 | ControlFlowNode for search_filter | semmle.label | ControlFlowNode for search_filter | -| ldap_bad.py:47:5:47:13 | ControlFlowNode for unsafe_dc | semmle.label | ControlFlowNode for unsafe_dc | -| ldap_bad.py:47:17:47:23 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| ldap_bad.py:47:17:47:23 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| ldap_bad.py:48:5:48:17 | ControlFlowNode for unsafe_filter | semmle.label | ControlFlowNode for unsafe_filter | -| ldap_bad.py:48:21:48:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| ldap_bad.py:50:5:50:6 | ControlFlowNode for dn | semmle.label | ControlFlowNode for dn | -| ldap_bad.py:51:5:51:17 | ControlFlowNode for search_filter | semmle.label | ControlFlowNode for search_filter | -| ldap_bad.py:55:9:55:10 | ControlFlowNode for dn | semmle.label | ControlFlowNode for dn | -| ldap_bad.py:55:43:55:55 | ControlFlowNode for search_filter | semmle.label | ControlFlowNode for search_filter | +| ldap3_bad.py:1:19:1:25 | After ImportMember | semmle.label | After ImportMember | +| ldap3_bad.py:1:19:1:25 | After ImportMember | semmle.label | After ImportMember | +| ldap3_bad.py:1:19:1:25 | request | semmle.label | request | +| ldap3_bad.py:1:19:1:25 | request | semmle.label | request | +| ldap3_bad.py:13:5:13:13 | unsafe_dc | semmle.label | unsafe_dc | +| ldap3_bad.py:13:17:13:23 | request | semmle.label | request | +| ldap3_bad.py:13:17:13:23 | request | semmle.label | request | +| ldap3_bad.py:14:5:14:17 | unsafe_filter | semmle.label | unsafe_filter | +| ldap3_bad.py:14:21:14:27 | request | semmle.label | request | +| ldap3_bad.py:16:5:16:6 | dn | semmle.label | dn | +| ldap3_bad.py:17:5:17:17 | search_filter | semmle.label | search_filter | +| ldap3_bad.py:21:17:21:18 | dn | semmle.label | dn | +| ldap3_bad.py:21:21:21:33 | search_filter | semmle.label | search_filter | +| ldap3_bad.py:30:5:30:13 | unsafe_dc | semmle.label | unsafe_dc | +| ldap3_bad.py:30:17:30:23 | request | semmle.label | request | +| ldap3_bad.py:30:17:30:23 | request | semmle.label | request | +| ldap3_bad.py:31:5:31:17 | unsafe_filter | semmle.label | unsafe_filter | +| ldap3_bad.py:31:21:31:27 | request | semmle.label | request | +| ldap3_bad.py:33:5:33:6 | dn | semmle.label | dn | +| ldap3_bad.py:34:5:34:17 | search_filter | semmle.label | search_filter | +| ldap3_bad.py:38:9:38:10 | dn | semmle.label | dn | +| ldap3_bad.py:38:13:38:25 | search_filter | semmle.label | search_filter | +| ldap_bad.py:1:19:1:25 | After ImportMember | semmle.label | After ImportMember | +| ldap_bad.py:1:19:1:25 | After ImportMember | semmle.label | After ImportMember | +| ldap_bad.py:1:19:1:25 | request | semmle.label | request | +| ldap_bad.py:1:19:1:25 | request | semmle.label | request | +| ldap_bad.py:13:5:13:13 | unsafe_dc | semmle.label | unsafe_dc | +| ldap_bad.py:13:17:13:23 | request | semmle.label | request | +| ldap_bad.py:13:17:13:23 | request | semmle.label | request | +| ldap_bad.py:14:5:14:17 | unsafe_filter | semmle.label | unsafe_filter | +| ldap_bad.py:14:21:14:27 | request | semmle.label | request | +| ldap_bad.py:16:5:16:6 | dn | semmle.label | dn | +| ldap_bad.py:17:5:17:17 | search_filter | semmle.label | search_filter | +| ldap_bad.py:21:9:21:10 | dn | semmle.label | dn | +| ldap_bad.py:21:33:21:45 | search_filter | semmle.label | search_filter | +| ldap_bad.py:30:5:30:13 | unsafe_dc | semmle.label | unsafe_dc | +| ldap_bad.py:30:17:30:23 | request | semmle.label | request | +| ldap_bad.py:30:17:30:23 | request | semmle.label | request | +| ldap_bad.py:31:5:31:17 | unsafe_filter | semmle.label | unsafe_filter | +| ldap_bad.py:31:21:31:27 | request | semmle.label | request | +| ldap_bad.py:33:5:33:6 | dn | semmle.label | dn | +| ldap_bad.py:34:5:34:17 | search_filter | semmle.label | search_filter | +| ldap_bad.py:37:9:37:10 | dn | semmle.label | dn | +| ldap_bad.py:37:33:37:45 | search_filter | semmle.label | search_filter | +| ldap_bad.py:47:5:47:13 | unsafe_dc | semmle.label | unsafe_dc | +| ldap_bad.py:47:17:47:23 | request | semmle.label | request | +| ldap_bad.py:47:17:47:23 | request | semmle.label | request | +| ldap_bad.py:48:5:48:17 | unsafe_filter | semmle.label | unsafe_filter | +| ldap_bad.py:48:21:48:27 | request | semmle.label | request | +| ldap_bad.py:50:5:50:6 | dn | semmle.label | dn | +| ldap_bad.py:51:5:51:17 | search_filter | semmle.label | search_filter | +| ldap_bad.py:55:9:55:10 | dn | semmle.label | dn | +| ldap_bad.py:55:43:55:55 | search_filter | semmle.label | search_filter | subpaths #select -| ldap3_bad.py:21:17:21:18 | ControlFlowNode for dn | ldap3_bad.py:1:19:1:25 | ControlFlowNode for ImportMember | ldap3_bad.py:21:17:21:18 | ControlFlowNode for dn | LDAP query parameter (DN) depends on a $@. | ldap3_bad.py:1:19:1:25 | ControlFlowNode for ImportMember | user-provided value | -| ldap3_bad.py:21:21:21:33 | ControlFlowNode for search_filter | ldap3_bad.py:1:19:1:25 | ControlFlowNode for ImportMember | ldap3_bad.py:21:21:21:33 | ControlFlowNode for search_filter | LDAP query parameter (filter) depends on a $@. | ldap3_bad.py:1:19:1:25 | ControlFlowNode for ImportMember | user-provided value | -| ldap3_bad.py:38:9:38:10 | ControlFlowNode for dn | ldap3_bad.py:1:19:1:25 | ControlFlowNode for ImportMember | ldap3_bad.py:38:9:38:10 | ControlFlowNode for dn | LDAP query parameter (DN) depends on a $@. | ldap3_bad.py:1:19:1:25 | ControlFlowNode for ImportMember | user-provided value | -| ldap3_bad.py:38:13:38:25 | ControlFlowNode for search_filter | ldap3_bad.py:1:19:1:25 | ControlFlowNode for ImportMember | ldap3_bad.py:38:13:38:25 | ControlFlowNode for search_filter | LDAP query parameter (filter) depends on a $@. | ldap3_bad.py:1:19:1:25 | ControlFlowNode for ImportMember | user-provided value | -| ldap_bad.py:21:9:21:10 | ControlFlowNode for dn | ldap_bad.py:1:19:1:25 | ControlFlowNode for ImportMember | ldap_bad.py:21:9:21:10 | ControlFlowNode for dn | LDAP query parameter (DN) depends on a $@. | ldap_bad.py:1:19:1:25 | ControlFlowNode for ImportMember | user-provided value | -| ldap_bad.py:21:33:21:45 | ControlFlowNode for search_filter | ldap_bad.py:1:19:1:25 | ControlFlowNode for ImportMember | ldap_bad.py:21:33:21:45 | ControlFlowNode for search_filter | LDAP query parameter (filter) depends on a $@. | ldap_bad.py:1:19:1:25 | ControlFlowNode for ImportMember | user-provided value | -| ldap_bad.py:37:9:37:10 | ControlFlowNode for dn | ldap_bad.py:1:19:1:25 | ControlFlowNode for ImportMember | ldap_bad.py:37:9:37:10 | ControlFlowNode for dn | LDAP query parameter (DN) depends on a $@. | ldap_bad.py:1:19:1:25 | ControlFlowNode for ImportMember | user-provided value | -| ldap_bad.py:37:33:37:45 | ControlFlowNode for search_filter | ldap_bad.py:1:19:1:25 | ControlFlowNode for ImportMember | ldap_bad.py:37:33:37:45 | ControlFlowNode for search_filter | LDAP query parameter (filter) depends on a $@. | ldap_bad.py:1:19:1:25 | ControlFlowNode for ImportMember | user-provided value | -| ldap_bad.py:55:9:55:10 | ControlFlowNode for dn | ldap_bad.py:1:19:1:25 | ControlFlowNode for ImportMember | ldap_bad.py:55:9:55:10 | ControlFlowNode for dn | LDAP query parameter (DN) depends on a $@. | ldap_bad.py:1:19:1:25 | ControlFlowNode for ImportMember | user-provided value | -| ldap_bad.py:55:43:55:55 | ControlFlowNode for search_filter | ldap_bad.py:1:19:1:25 | ControlFlowNode for ImportMember | ldap_bad.py:55:43:55:55 | ControlFlowNode for search_filter | LDAP query parameter (filter) depends on a $@. | ldap_bad.py:1:19:1:25 | ControlFlowNode for ImportMember | user-provided value | +| ldap3_bad.py:21:17:21:18 | dn | ldap3_bad.py:1:19:1:25 | After ImportMember | ldap3_bad.py:21:17:21:18 | dn | LDAP query parameter (DN) depends on a $@. | ldap3_bad.py:1:19:1:25 | After ImportMember | user-provided value | +| ldap3_bad.py:21:21:21:33 | search_filter | ldap3_bad.py:1:19:1:25 | After ImportMember | ldap3_bad.py:21:21:21:33 | search_filter | LDAP query parameter (filter) depends on a $@. | ldap3_bad.py:1:19:1:25 | After ImportMember | user-provided value | +| ldap3_bad.py:38:9:38:10 | dn | ldap3_bad.py:1:19:1:25 | After ImportMember | ldap3_bad.py:38:9:38:10 | dn | LDAP query parameter (DN) depends on a $@. | ldap3_bad.py:1:19:1:25 | After ImportMember | user-provided value | +| ldap3_bad.py:38:13:38:25 | search_filter | ldap3_bad.py:1:19:1:25 | After ImportMember | ldap3_bad.py:38:13:38:25 | search_filter | LDAP query parameter (filter) depends on a $@. | ldap3_bad.py:1:19:1:25 | After ImportMember | user-provided value | +| ldap_bad.py:21:9:21:10 | dn | ldap_bad.py:1:19:1:25 | After ImportMember | ldap_bad.py:21:9:21:10 | dn | LDAP query parameter (DN) depends on a $@. | ldap_bad.py:1:19:1:25 | After ImportMember | user-provided value | +| ldap_bad.py:21:33:21:45 | search_filter | ldap_bad.py:1:19:1:25 | After ImportMember | ldap_bad.py:21:33:21:45 | search_filter | LDAP query parameter (filter) depends on a $@. | ldap_bad.py:1:19:1:25 | After ImportMember | user-provided value | +| ldap_bad.py:37:9:37:10 | dn | ldap_bad.py:1:19:1:25 | After ImportMember | ldap_bad.py:37:9:37:10 | dn | LDAP query parameter (DN) depends on a $@. | ldap_bad.py:1:19:1:25 | After ImportMember | user-provided value | +| ldap_bad.py:37:33:37:45 | search_filter | ldap_bad.py:1:19:1:25 | After ImportMember | ldap_bad.py:37:33:37:45 | search_filter | LDAP query parameter (filter) depends on a $@. | ldap_bad.py:1:19:1:25 | After ImportMember | user-provided value | +| ldap_bad.py:55:9:55:10 | dn | ldap_bad.py:1:19:1:25 | After ImportMember | ldap_bad.py:55:9:55:10 | dn | LDAP query parameter (DN) depends on a $@. | ldap_bad.py:1:19:1:25 | After ImportMember | user-provided value | +| ldap_bad.py:55:43:55:55 | search_filter | ldap_bad.py:1:19:1:25 | After ImportMember | ldap_bad.py:55:43:55:55 | search_filter | LDAP query parameter (filter) depends on a $@. | ldap_bad.py:1:19:1:25 | After ImportMember | user-provided value | diff --git a/python/ql/test/query-tests/Security/CWE-094-CodeInjection/CodeInjection.expected b/python/ql/test/query-tests/Security/CWE-094-CodeInjection/CodeInjection.expected index 506659aa8256..1c439911cfe0 100644 --- a/python/ql/test/query-tests/Security/CWE-094-CodeInjection/CodeInjection.expected +++ b/python/ql/test/query-tests/Security/CWE-094-CodeInjection/CodeInjection.expected @@ -1,37 +1,37 @@ +#select +| code_injection.py:7:10:7:13 | code | code_injection.py:1:26:1:32 | After ImportMember | code_injection.py:7:10:7:13 | code | This code execution depends on a $@. | code_injection.py:1:26:1:32 | After ImportMember | user-provided value | +| code_injection.py:8:10:8:13 | code | code_injection.py:1:26:1:32 | After ImportMember | code_injection.py:8:10:8:13 | code | This code execution depends on a $@. | code_injection.py:1:26:1:32 | After ImportMember | user-provided value | +| code_injection.py:10:10:10:12 | cmd | code_injection.py:1:26:1:32 | After ImportMember | code_injection.py:10:10:10:12 | cmd | This code execution depends on a $@. | code_injection.py:1:26:1:32 | After ImportMember | user-provided value | +| code_injection.py:21:20:21:27 | obj_name | code_injection.py:1:26:1:32 | After ImportMember | code_injection.py:21:20:21:27 | obj_name | This code execution depends on a $@. | code_injection.py:1:26:1:32 | After ImportMember | user-provided value | edges -| code_injection.py:1:26:1:32 | ControlFlowNode for ImportMember | code_injection.py:1:26:1:32 | ControlFlowNode for request | provenance | | -| code_injection.py:1:26:1:32 | ControlFlowNode for request | code_injection.py:6:12:6:18 | ControlFlowNode for request | provenance | | -| code_injection.py:1:26:1:32 | ControlFlowNode for request | code_injection.py:18:16:18:22 | ControlFlowNode for request | provenance | | -| code_injection.py:6:5:6:8 | ControlFlowNode for code | code_injection.py:7:10:7:13 | ControlFlowNode for code | provenance | | -| code_injection.py:6:5:6:8 | ControlFlowNode for code | code_injection.py:8:10:8:13 | ControlFlowNode for code | provenance | | -| code_injection.py:6:5:6:8 | ControlFlowNode for code | code_injection.py:9:5:9:7 | ControlFlowNode for cmd | provenance | AdditionalTaintStep | -| code_injection.py:6:12:6:18 | ControlFlowNode for request | code_injection.py:6:12:6:23 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | -| code_injection.py:6:12:6:23 | ControlFlowNode for Attribute | code_injection.py:6:12:6:35 | ControlFlowNode for Attribute() | provenance | dict.get | -| code_injection.py:6:12:6:35 | ControlFlowNode for Attribute() | code_injection.py:6:5:6:8 | ControlFlowNode for code | provenance | | -| code_injection.py:9:5:9:7 | ControlFlowNode for cmd | code_injection.py:10:10:10:12 | ControlFlowNode for cmd | provenance | | -| code_injection.py:18:5:18:12 | ControlFlowNode for obj_name | code_injection.py:21:20:21:27 | ControlFlowNode for obj_name | provenance | | -| code_injection.py:18:16:18:22 | ControlFlowNode for request | code_injection.py:18:16:18:27 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | -| code_injection.py:18:16:18:27 | ControlFlowNode for Attribute | code_injection.py:18:16:18:38 | ControlFlowNode for Attribute() | provenance | dict.get | -| code_injection.py:18:16:18:38 | ControlFlowNode for Attribute() | code_injection.py:18:5:18:12 | ControlFlowNode for obj_name | provenance | | +| code_injection.py:1:26:1:32 | After ImportMember | code_injection.py:1:26:1:32 | request | provenance | | +| code_injection.py:1:26:1:32 | request | code_injection.py:6:12:6:18 | request | provenance | | +| code_injection.py:1:26:1:32 | request | code_injection.py:18:16:18:22 | request | provenance | | +| code_injection.py:6:5:6:8 | code | code_injection.py:7:10:7:13 | code | provenance | | +| code_injection.py:6:5:6:8 | code | code_injection.py:8:10:8:13 | code | provenance | | +| code_injection.py:6:5:6:8 | code | code_injection.py:9:5:9:7 | cmd | provenance | AdditionalTaintStep | +| code_injection.py:6:12:6:18 | request | code_injection.py:6:12:6:23 | After Attribute | provenance | AdditionalTaintStep | +| code_injection.py:6:12:6:23 | After Attribute | code_injection.py:6:12:6:35 | After Attribute() | provenance | dict.get | +| code_injection.py:6:12:6:35 | After Attribute() | code_injection.py:6:5:6:8 | code | provenance | | +| code_injection.py:9:5:9:7 | cmd | code_injection.py:10:10:10:12 | cmd | provenance | | +| code_injection.py:18:5:18:12 | obj_name | code_injection.py:21:20:21:27 | obj_name | provenance | | +| code_injection.py:18:16:18:22 | request | code_injection.py:18:16:18:27 | After Attribute | provenance | AdditionalTaintStep | +| code_injection.py:18:16:18:27 | After Attribute | code_injection.py:18:16:18:38 | After Attribute() | provenance | dict.get | +| code_injection.py:18:16:18:38 | After Attribute() | code_injection.py:18:5:18:12 | obj_name | provenance | | nodes -| code_injection.py:1:26:1:32 | ControlFlowNode for ImportMember | semmle.label | ControlFlowNode for ImportMember | -| code_injection.py:1:26:1:32 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| code_injection.py:6:5:6:8 | ControlFlowNode for code | semmle.label | ControlFlowNode for code | -| code_injection.py:6:12:6:18 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| code_injection.py:6:12:6:23 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| code_injection.py:6:12:6:35 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| 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:9:5:9:7 | ControlFlowNode for cmd | semmle.label | ControlFlowNode for cmd | -| code_injection.py:10:10:10:12 | ControlFlowNode for cmd | semmle.label | ControlFlowNode for cmd | -| code_injection.py:18:5:18:12 | ControlFlowNode for obj_name | semmle.label | ControlFlowNode for obj_name | -| code_injection.py:18:16:18:22 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| code_injection.py:18:16:18:27 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| code_injection.py:18:16:18:38 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| code_injection.py:21:20:21:27 | ControlFlowNode for obj_name | semmle.label | ControlFlowNode for obj_name | +| code_injection.py:1:26:1:32 | After ImportMember | semmle.label | After ImportMember | +| code_injection.py:1:26:1:32 | request | semmle.label | request | +| code_injection.py:6:5:6:8 | code | semmle.label | code | +| code_injection.py:6:12:6:18 | request | semmle.label | request | +| code_injection.py:6:12:6:23 | After Attribute | semmle.label | After Attribute | +| code_injection.py:6:12:6:35 | After Attribute() | semmle.label | After Attribute() | +| code_injection.py:7:10:7:13 | code | semmle.label | code | +| code_injection.py:8:10:8:13 | code | semmle.label | code | +| code_injection.py:9:5:9:7 | cmd | semmle.label | cmd | +| code_injection.py:10:10:10:12 | cmd | semmle.label | cmd | +| code_injection.py:18:5:18:12 | obj_name | semmle.label | obj_name | +| code_injection.py:18:16:18:22 | request | semmle.label | request | +| code_injection.py:18:16:18:27 | After Attribute | semmle.label | After Attribute | +| code_injection.py:18:16:18:38 | After Attribute() | semmle.label | After Attribute() | +| code_injection.py:21:20:21:27 | obj_name | semmle.label | obj_name | subpaths -#select -| code_injection.py:7:10:7:13 | ControlFlowNode for code | code_injection.py:1:26:1:32 | ControlFlowNode for ImportMember | code_injection.py:7:10:7:13 | ControlFlowNode for code | This code execution depends on a $@. | code_injection.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value | -| code_injection.py:8:10:8:13 | ControlFlowNode for code | code_injection.py:1:26:1:32 | ControlFlowNode for ImportMember | code_injection.py:8:10:8:13 | ControlFlowNode for code | This code execution depends on a $@. | code_injection.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value | -| code_injection.py:10:10:10:12 | ControlFlowNode for cmd | code_injection.py:1:26:1:32 | ControlFlowNode for ImportMember | code_injection.py:10:10:10:12 | ControlFlowNode for cmd | This code execution depends on a $@. | code_injection.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value | -| code_injection.py:21:20:21:27 | ControlFlowNode for obj_name | code_injection.py:1:26:1:32 | ControlFlowNode for ImportMember | code_injection.py:21:20:21:27 | ControlFlowNode for obj_name | This code execution depends on a $@. | code_injection.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value | diff --git a/python/ql/test/query-tests/Security/CWE-1004-NonHttpOnlyCookie/NonHttpOnlyCookie.expected b/python/ql/test/query-tests/Security/CWE-1004-NonHttpOnlyCookie/NonHttpOnlyCookie.expected index 7af8af8d8708..0911567928d8 100644 --- a/python/ql/test/query-tests/Security/CWE-1004-NonHttpOnlyCookie/NonHttpOnlyCookie.expected +++ b/python/ql/test/query-tests/Security/CWE-1004-NonHttpOnlyCookie/NonHttpOnlyCookie.expected @@ -1,3 +1,3 @@ -| test.py:8:5:8:38 | ControlFlowNode for Attribute() | Sensitive server cookie is set without HttpOnly flag. | -| test.py:9:5:9:51 | ControlFlowNode for Attribute() | Sensitive server cookie is set without HttpOnly flag. | -| test.py:11:5:11:57 | ControlFlowNode for Attribute() | Sensitive server cookie is set without HttpOnly flag. | +| test.py:8:5:8:38 | After Attribute() | Sensitive server cookie is set without HttpOnly flag. | +| test.py:9:5:9:51 | After Attribute() | Sensitive server cookie is set without HttpOnly flag. | +| test.py:11:5:11:57 | After Attribute() | Sensitive server cookie is set without HttpOnly flag. | diff --git a/python/ql/test/query-tests/Security/CWE-113-HeaderInjection/Tests1/HeaderInjection.expected b/python/ql/test/query-tests/Security/CWE-113-HeaderInjection/Tests1/HeaderInjection.expected index 4043b9332435..3aeb354ce061 100644 --- a/python/ql/test/query-tests/Security/CWE-113-HeaderInjection/Tests1/HeaderInjection.expected +++ b/python/ql/test/query-tests/Security/CWE-113-HeaderInjection/Tests1/HeaderInjection.expected @@ -1,68 +1,68 @@ #select -| flask_tests.py:13:17:13:26 | ControlFlowNode for rfs_header | flask_tests.py:1:29:1:35 | ControlFlowNode for ImportMember | flask_tests.py:13:17:13:26 | ControlFlowNode for rfs_header | This HTTP header is constructed from a $@. | flask_tests.py:1:29:1:35 | ControlFlowNode for ImportMember | user-provided value | -| flask_tests.py:20:36:20:61 | ControlFlowNode for Subscript | flask_tests.py:1:29:1:35 | ControlFlowNode for ImportMember | flask_tests.py:20:36:20:61 | ControlFlowNode for Subscript | This HTTP header is constructed from a $@. | flask_tests.py:1:29:1:35 | ControlFlowNode for ImportMember | user-provided value | -| flask_tests.py:33:11:33:20 | ControlFlowNode for rfs_header | flask_tests.py:1:29:1:35 | ControlFlowNode for ImportMember | flask_tests.py:33:11:33:20 | ControlFlowNode for rfs_header | This HTTP header is constructed from a $@. | flask_tests.py:1:29:1:35 | ControlFlowNode for ImportMember | user-provided value | -| flask_tests.py:35:12:35:21 | ControlFlowNode for rfs_header | flask_tests.py:1:29:1:35 | ControlFlowNode for ImportMember | flask_tests.py:35:12:35:21 | ControlFlowNode for rfs_header | This HTTP header is constructed from a $@. | flask_tests.py:1:29:1:35 | ControlFlowNode for ImportMember | user-provided value | -| http_test.py:12:40:12:50 | ControlFlowNode for input_value | http_test.py:5:16:5:19 | ControlFlowNode for self | http_test.py:12:40:12:50 | ControlFlowNode for input_value | This HTTP header is constructed from a $@. | http_test.py:5:16:5:19 | ControlFlowNode for self | user-provided value | -| wsgiref_tests.py:8:17:8:22 | ControlFlowNode for h_name | wsgiref_tests.py:4:14:4:20 | ControlFlowNode for environ | wsgiref_tests.py:8:17:8:22 | ControlFlowNode for h_name | This HTTP header is constructed from a $@. | wsgiref_tests.py:4:14:4:20 | ControlFlowNode for environ | user-provided value | -| wsgiref_tests.py:8:42:8:46 | ControlFlowNode for h_val | wsgiref_tests.py:4:14:4:20 | ControlFlowNode for environ | wsgiref_tests.py:8:42:8:46 | ControlFlowNode for h_val | This HTTP header is constructed from a $@. | wsgiref_tests.py:4:14:4:20 | ControlFlowNode for environ | user-provided value | +| flask_tests.py:13:17:13:26 | rfs_header | flask_tests.py:1:29:1:35 | After ImportMember | flask_tests.py:13:17:13:26 | rfs_header | This HTTP header is constructed from a $@. | flask_tests.py:1:29:1:35 | After ImportMember | user-provided value | +| flask_tests.py:20:36:20:61 | After Subscript | flask_tests.py:1:29:1:35 | After ImportMember | flask_tests.py:20:36:20:61 | After Subscript | This HTTP header is constructed from a $@. | flask_tests.py:1:29:1:35 | After ImportMember | user-provided value | +| flask_tests.py:33:11:33:20 | rfs_header | flask_tests.py:1:29:1:35 | After ImportMember | flask_tests.py:33:11:33:20 | rfs_header | This HTTP header is constructed from a $@. | flask_tests.py:1:29:1:35 | After ImportMember | user-provided value | +| flask_tests.py:35:12:35:21 | rfs_header | flask_tests.py:1:29:1:35 | After ImportMember | flask_tests.py:35:12:35:21 | rfs_header | This HTTP header is constructed from a $@. | flask_tests.py:1:29:1:35 | After ImportMember | user-provided value | +| http_test.py:12:40:12:50 | input_value | http_test.py:5:16:5:19 | self | http_test.py:12:40:12:50 | input_value | This HTTP header is constructed from a $@. | http_test.py:5:16:5:19 | self | user-provided value | +| wsgiref_tests.py:8:17:8:22 | h_name | wsgiref_tests.py:4:14:4:20 | environ | wsgiref_tests.py:8:17:8:22 | h_name | This HTTP header is constructed from a $@. | wsgiref_tests.py:4:14:4:20 | environ | user-provided value | +| wsgiref_tests.py:8:42:8:46 | h_val | wsgiref_tests.py:4:14:4:20 | environ | wsgiref_tests.py:8:42:8:46 | h_val | This HTTP header is constructed from a $@. | wsgiref_tests.py:4:14:4:20 | environ | user-provided value | edges -| flask_tests.py:1:29:1:35 | ControlFlowNode for ImportMember | flask_tests.py:1:29:1:35 | ControlFlowNode for request | provenance | | -| flask_tests.py:1:29:1:35 | ControlFlowNode for request | flask_tests.py:9:18:9:24 | ControlFlowNode for request | provenance | | -| flask_tests.py:1:29:1:35 | ControlFlowNode for request | flask_tests.py:19:18:19:24 | ControlFlowNode for request | provenance | | -| flask_tests.py:1:29:1:35 | ControlFlowNode for request | flask_tests.py:20:36:20:42 | ControlFlowNode for request | provenance | | -| flask_tests.py:1:29:1:35 | ControlFlowNode for request | flask_tests.py:31:18:31:24 | ControlFlowNode for request | provenance | | -| flask_tests.py:9:5:9:14 | ControlFlowNode for rfs_header | flask_tests.py:13:17:13:26 | ControlFlowNode for rfs_header | provenance | | -| flask_tests.py:9:18:9:24 | ControlFlowNode for request | flask_tests.py:9:5:9:14 | ControlFlowNode for rfs_header | provenance | AdditionalTaintStep | -| flask_tests.py:19:18:19:24 | ControlFlowNode for request | flask_tests.py:20:36:20:61 | ControlFlowNode for Subscript | provenance | AdditionalTaintStep | -| flask_tests.py:20:36:20:42 | ControlFlowNode for request | flask_tests.py:20:36:20:61 | ControlFlowNode for Subscript | provenance | AdditionalTaintStep | -| flask_tests.py:31:5:31:14 | ControlFlowNode for rfs_header | flask_tests.py:33:11:33:20 | ControlFlowNode for rfs_header | provenance | | -| flask_tests.py:31:5:31:14 | ControlFlowNode for rfs_header | flask_tests.py:35:12:35:21 | ControlFlowNode for rfs_header | provenance | | -| flask_tests.py:31:18:31:24 | ControlFlowNode for request | flask_tests.py:31:5:31:14 | ControlFlowNode for rfs_header | provenance | AdditionalTaintStep | -| http_test.py:5:16:5:19 | ControlFlowNode for self | http_test.py:6:45:6:53 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | -| http_test.py:6:9:6:19 | ControlFlowNode for parsed_path | http_test.py:7:40:7:56 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | -| http_test.py:6:23:6:54 | ControlFlowNode for Attribute() | http_test.py:6:9:6:19 | ControlFlowNode for parsed_path | provenance | | -| http_test.py:6:45:6:53 | ControlFlowNode for Attribute | http_test.py:6:23:6:54 | ControlFlowNode for Attribute() | provenance | MaD:2 | -| http_test.py:7:9:7:14 | ControlFlowNode for params | http_test.py:8:23:8:28 | ControlFlowNode for params | provenance | | -| http_test.py:7:18:7:57 | ControlFlowNode for Attribute() | http_test.py:7:9:7:14 | ControlFlowNode for params | provenance | | -| http_test.py:7:40:7:56 | ControlFlowNode for Attribute | http_test.py:7:18:7:57 | ControlFlowNode for Attribute() | provenance | MaD:1 | -| http_test.py:8:9:8:19 | ControlFlowNode for input_value | http_test.py:12:40:12:50 | ControlFlowNode for input_value | provenance | | -| http_test.py:8:23:8:28 | ControlFlowNode for params | http_test.py:8:23:8:47 | ControlFlowNode for Attribute() | provenance | dict.get | -| http_test.py:8:23:8:47 | ControlFlowNode for Attribute() | http_test.py:8:9:8:19 | ControlFlowNode for input_value | provenance | | -| wsgiref_tests.py:4:14:4:20 | ControlFlowNode for environ | wsgiref_tests.py:6:5:6:10 | ControlFlowNode for h_name | provenance | | -| wsgiref_tests.py:4:14:4:20 | ControlFlowNode for environ | wsgiref_tests.py:7:5:7:9 | ControlFlowNode for h_val | provenance | | -| wsgiref_tests.py:6:5:6:10 | ControlFlowNode for h_name | wsgiref_tests.py:8:17:8:22 | ControlFlowNode for h_name | provenance | | -| wsgiref_tests.py:7:5:7:9 | ControlFlowNode for h_val | wsgiref_tests.py:8:42:8:46 | ControlFlowNode for h_val | provenance | | +| flask_tests.py:1:29:1:35 | After ImportMember | flask_tests.py:1:29:1:35 | request | provenance | | +| flask_tests.py:1:29:1:35 | request | flask_tests.py:9:18:9:24 | request | provenance | | +| flask_tests.py:1:29:1:35 | request | flask_tests.py:19:18:19:24 | request | provenance | | +| flask_tests.py:1:29:1:35 | request | flask_tests.py:20:36:20:42 | request | provenance | | +| flask_tests.py:1:29:1:35 | request | flask_tests.py:31:18:31:24 | request | provenance | | +| flask_tests.py:9:5:9:14 | rfs_header | flask_tests.py:13:17:13:26 | rfs_header | provenance | | +| flask_tests.py:9:18:9:24 | request | flask_tests.py:9:5:9:14 | rfs_header | provenance | AdditionalTaintStep | +| flask_tests.py:19:18:19:24 | request | flask_tests.py:20:36:20:61 | After Subscript | provenance | AdditionalTaintStep | +| flask_tests.py:20:36:20:42 | request | flask_tests.py:20:36:20:61 | After Subscript | provenance | AdditionalTaintStep | +| flask_tests.py:31:5:31:14 | rfs_header | flask_tests.py:33:11:33:20 | rfs_header | provenance | | +| flask_tests.py:31:5:31:14 | rfs_header | flask_tests.py:35:12:35:21 | rfs_header | provenance | | +| flask_tests.py:31:18:31:24 | request | flask_tests.py:31:5:31:14 | rfs_header | provenance | AdditionalTaintStep | +| http_test.py:5:16:5:19 | self | http_test.py:6:45:6:53 | After Attribute | provenance | AdditionalTaintStep | +| http_test.py:6:9:6:19 | parsed_path | http_test.py:7:40:7:56 | After Attribute | provenance | AdditionalTaintStep | +| http_test.py:6:23:6:54 | After Attribute() | http_test.py:6:9:6:19 | parsed_path | provenance | | +| http_test.py:6:45:6:53 | After Attribute | http_test.py:6:23:6:54 | After Attribute() | provenance | MaD:2 | +| http_test.py:7:9:7:14 | params | http_test.py:8:23:8:28 | params | provenance | | +| http_test.py:7:18:7:57 | After Attribute() | http_test.py:7:9:7:14 | params | provenance | | +| http_test.py:7:40:7:56 | After Attribute | http_test.py:7:18:7:57 | After Attribute() | provenance | MaD:1 | +| http_test.py:8:9:8:19 | input_value | http_test.py:12:40:12:50 | input_value | provenance | | +| http_test.py:8:23:8:28 | params | http_test.py:8:23:8:47 | After Attribute() | provenance | dict.get | +| http_test.py:8:23:8:47 | After Attribute() | http_test.py:8:9:8:19 | input_value | provenance | | +| wsgiref_tests.py:4:14:4:20 | environ | wsgiref_tests.py:6:5:6:10 | h_name | provenance | | +| wsgiref_tests.py:4:14:4:20 | environ | wsgiref_tests.py:7:5:7:9 | h_val | provenance | | +| wsgiref_tests.py:6:5:6:10 | h_name | wsgiref_tests.py:8:17:8:22 | h_name | provenance | | +| wsgiref_tests.py:7:5:7:9 | h_val | wsgiref_tests.py:8:42:8:46 | h_val | provenance | | models | 1 | Summary: urllib; Member[parse].Member[parse_qs]; Argument[0,qs:]; ReturnValue; taint | | 2 | Summary: urllib; Member[parse].Member[urlparse]; Argument[0,urlstring:]; ReturnValue; taint | nodes -| flask_tests.py:1:29:1:35 | ControlFlowNode for ImportMember | semmle.label | ControlFlowNode for ImportMember | -| flask_tests.py:1:29:1:35 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| flask_tests.py:9:5:9:14 | ControlFlowNode for rfs_header | semmle.label | ControlFlowNode for rfs_header | -| flask_tests.py:9:18:9:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| flask_tests.py:13:17:13:26 | ControlFlowNode for rfs_header | semmle.label | ControlFlowNode for rfs_header | -| flask_tests.py:19:18:19:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| flask_tests.py:20:36:20:42 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| flask_tests.py:20:36:20:61 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript | -| flask_tests.py:31:5:31:14 | ControlFlowNode for rfs_header | semmle.label | ControlFlowNode for rfs_header | -| flask_tests.py:31:18:31:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| flask_tests.py:33:11:33:20 | ControlFlowNode for rfs_header | semmle.label | ControlFlowNode for rfs_header | -| flask_tests.py:35:12:35:21 | ControlFlowNode for rfs_header | semmle.label | ControlFlowNode for rfs_header | -| http_test.py:5:16:5:19 | ControlFlowNode for self | semmle.label | ControlFlowNode for self | -| http_test.py:6:9:6:19 | ControlFlowNode for parsed_path | semmle.label | ControlFlowNode for parsed_path | -| http_test.py:6:23:6:54 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| http_test.py:6:45:6:53 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| http_test.py:7:9:7:14 | ControlFlowNode for params | semmle.label | ControlFlowNode for params | -| http_test.py:7:18:7:57 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| http_test.py:7:40:7:56 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| http_test.py:8:9:8:19 | ControlFlowNode for input_value | semmle.label | ControlFlowNode for input_value | -| http_test.py:8:23:8:28 | ControlFlowNode for params | semmle.label | ControlFlowNode for params | -| http_test.py:8:23:8:47 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| http_test.py:12:40:12:50 | ControlFlowNode for input_value | semmle.label | ControlFlowNode for input_value | -| wsgiref_tests.py:4:14:4:20 | ControlFlowNode for environ | semmle.label | ControlFlowNode for environ | -| wsgiref_tests.py:6:5:6:10 | ControlFlowNode for h_name | semmle.label | ControlFlowNode for h_name | -| wsgiref_tests.py:7:5:7:9 | ControlFlowNode for h_val | semmle.label | ControlFlowNode for h_val | -| wsgiref_tests.py:8:17:8:22 | ControlFlowNode for h_name | semmle.label | ControlFlowNode for h_name | -| wsgiref_tests.py:8:42:8:46 | ControlFlowNode for h_val | semmle.label | ControlFlowNode for h_val | +| flask_tests.py:1:29:1:35 | After ImportMember | semmle.label | After ImportMember | +| flask_tests.py:1:29:1:35 | request | semmle.label | request | +| flask_tests.py:9:5:9:14 | rfs_header | semmle.label | rfs_header | +| flask_tests.py:9:18:9:24 | request | semmle.label | request | +| flask_tests.py:13:17:13:26 | rfs_header | semmle.label | rfs_header | +| flask_tests.py:19:18:19:24 | request | semmle.label | request | +| flask_tests.py:20:36:20:42 | request | semmle.label | request | +| flask_tests.py:20:36:20:61 | After Subscript | semmle.label | After Subscript | +| flask_tests.py:31:5:31:14 | rfs_header | semmle.label | rfs_header | +| flask_tests.py:31:18:31:24 | request | semmle.label | request | +| flask_tests.py:33:11:33:20 | rfs_header | semmle.label | rfs_header | +| flask_tests.py:35:12:35:21 | rfs_header | semmle.label | rfs_header | +| http_test.py:5:16:5:19 | self | semmle.label | self | +| http_test.py:6:9:6:19 | parsed_path | semmle.label | parsed_path | +| http_test.py:6:23:6:54 | After Attribute() | semmle.label | After Attribute() | +| http_test.py:6:45:6:53 | After Attribute | semmle.label | After Attribute | +| http_test.py:7:9:7:14 | params | semmle.label | params | +| http_test.py:7:18:7:57 | After Attribute() | semmle.label | After Attribute() | +| http_test.py:7:40:7:56 | After Attribute | semmle.label | After Attribute | +| http_test.py:8:9:8:19 | input_value | semmle.label | input_value | +| http_test.py:8:23:8:28 | params | semmle.label | params | +| http_test.py:8:23:8:47 | After Attribute() | semmle.label | After Attribute() | +| http_test.py:12:40:12:50 | input_value | semmle.label | input_value | +| wsgiref_tests.py:4:14:4:20 | environ | semmle.label | environ | +| wsgiref_tests.py:6:5:6:10 | h_name | semmle.label | h_name | +| wsgiref_tests.py:7:5:7:9 | h_val | semmle.label | h_val | +| wsgiref_tests.py:8:17:8:22 | h_name | semmle.label | h_name | +| wsgiref_tests.py:8:42:8:46 | h_val | semmle.label | h_val | subpaths diff --git a/python/ql/test/query-tests/Security/CWE-113-HeaderInjection/Tests2-with-wsgi-validator/HeaderWriteTest.expected b/python/ql/test/query-tests/Security/CWE-113-HeaderInjection/Tests2-with-wsgi-validator/HeaderWriteTest.expected index 1dcb484b8f46..481cfb869df3 100644 --- a/python/ql/test/query-tests/Security/CWE-113-HeaderInjection/Tests2-with-wsgi-validator/HeaderWriteTest.expected +++ b/python/ql/test/query-tests/Security/CWE-113-HeaderInjection/Tests2-with-wsgi-validator/HeaderWriteTest.expected @@ -1,8 +1,8 @@ source -| wsgiref_tests.py:7:14:7:20 | ControlFlowNode for environ | +| wsgiref_tests.py:7:14:7:20 | environ | sink headerWrite -| wsgiref_tests.py:12:5:12:35 | ControlFlowNode for start_response() | wsgiref_tests.py:11:17:11:22 | ControlFlowNode for h_name | wsgiref_tests.py:11:25:11:29 | ControlFlowNode for StringLiteral | false | false | -| wsgiref_tests.py:12:5:12:35 | ControlFlowNode for start_response() | wsgiref_tests.py:11:17:11:22 | ControlFlowNode for h_name | wsgiref_tests.py:11:42:11:46 | ControlFlowNode for h_val | false | false | -| wsgiref_tests.py:12:5:12:35 | ControlFlowNode for start_response() | wsgiref_tests.py:11:34:11:39 | ControlFlowNode for StringLiteral | wsgiref_tests.py:11:25:11:29 | ControlFlowNode for StringLiteral | false | false | -| wsgiref_tests.py:12:5:12:35 | ControlFlowNode for start_response() | wsgiref_tests.py:11:34:11:39 | ControlFlowNode for StringLiteral | wsgiref_tests.py:11:42:11:46 | ControlFlowNode for h_val | false | false | +| wsgiref_tests.py:12:5:12:35 | After start_response() | wsgiref_tests.py:11:17:11:22 | h_name | wsgiref_tests.py:11:25:11:29 | StringLiteral | false | false | +| wsgiref_tests.py:12:5:12:35 | After start_response() | wsgiref_tests.py:11:17:11:22 | h_name | wsgiref_tests.py:11:42:11:46 | h_val | false | false | +| wsgiref_tests.py:12:5:12:35 | After start_response() | wsgiref_tests.py:11:34:11:39 | StringLiteral | wsgiref_tests.py:11:25:11:29 | StringLiteral | false | false | +| wsgiref_tests.py:12:5:12:35 | After start_response() | wsgiref_tests.py:11:34:11:39 | StringLiteral | wsgiref_tests.py:11:42:11:46 | h_val | false | false | diff --git a/python/ql/test/query-tests/Security/CWE-117-LogInjection/LogInjection.expected b/python/ql/test/query-tests/Security/CWE-117-LogInjection/LogInjection.expected index 67274311bf42..c6aa178800fc 100644 --- a/python/ql/test/query-tests/Security/CWE-117-LogInjection/LogInjection.expected +++ b/python/ql/test/query-tests/Security/CWE-117-LogInjection/LogInjection.expected @@ -1,51 +1,51 @@ -#select -| LogInjectionBad.py:18:21:18:40 | ControlFlowNode for BinaryExpr | LogInjectionBad.py:7:19:7:25 | ControlFlowNode for ImportMember | LogInjectionBad.py:18:21:18:40 | ControlFlowNode for BinaryExpr | This log entry depends on a $@. | LogInjectionBad.py:7:19:7:25 | ControlFlowNode for ImportMember | user-provided value | -| LogInjectionBad.py:24:18:24:37 | ControlFlowNode for BinaryExpr | LogInjectionBad.py:7:19:7:25 | ControlFlowNode for ImportMember | LogInjectionBad.py:24:18:24:37 | ControlFlowNode for BinaryExpr | This log entry depends on a $@. | LogInjectionBad.py:7:19:7:25 | ControlFlowNode for ImportMember | user-provided value | -| LogInjectionBad.py:30:25:30:44 | ControlFlowNode for BinaryExpr | LogInjectionBad.py:7:19:7:25 | ControlFlowNode for ImportMember | LogInjectionBad.py:30:25:30:44 | ControlFlowNode for BinaryExpr | This log entry depends on a $@. | LogInjectionBad.py:7:19:7:25 | ControlFlowNode for ImportMember | user-provided value | -| LogInjectionBad.py:37:19:37:38 | ControlFlowNode for BinaryExpr | LogInjectionBad.py:7:19:7:25 | ControlFlowNode for ImportMember | LogInjectionBad.py:37:19:37:38 | ControlFlowNode for BinaryExpr | This log entry depends on a $@. | LogInjectionBad.py:7:19:7:25 | ControlFlowNode for ImportMember | user-provided value | edges -| LogInjectionBad.py:7:19:7:25 | ControlFlowNode for ImportMember | LogInjectionBad.py:7:19:7:25 | ControlFlowNode for request | provenance | | -| LogInjectionBad.py:7:19:7:25 | ControlFlowNode for request | LogInjectionBad.py:17:12:17:18 | ControlFlowNode for request | provenance | | -| LogInjectionBad.py:7:19:7:25 | ControlFlowNode for request | LogInjectionBad.py:23:12:23:18 | ControlFlowNode for request | provenance | | -| LogInjectionBad.py:7:19:7:25 | ControlFlowNode for request | LogInjectionBad.py:29:12:29:18 | ControlFlowNode for request | provenance | | -| LogInjectionBad.py:7:19:7:25 | ControlFlowNode for request | LogInjectionBad.py:35:12:35:18 | ControlFlowNode for request | provenance | | -| LogInjectionBad.py:17:5:17:8 | ControlFlowNode for name | LogInjectionBad.py:18:21:18:40 | ControlFlowNode for BinaryExpr | provenance | | -| LogInjectionBad.py:17:12:17:18 | ControlFlowNode for request | LogInjectionBad.py:17:12:17:23 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | -| LogInjectionBad.py:17:12:17:23 | ControlFlowNode for Attribute | LogInjectionBad.py:17:12:17:35 | ControlFlowNode for Attribute() | provenance | dict.get | -| LogInjectionBad.py:17:12:17:35 | ControlFlowNode for Attribute() | LogInjectionBad.py:17:5:17:8 | ControlFlowNode for name | provenance | | -| LogInjectionBad.py:23:5:23:8 | ControlFlowNode for name | LogInjectionBad.py:24:18:24:37 | ControlFlowNode for BinaryExpr | provenance | | -| LogInjectionBad.py:23:12:23:18 | ControlFlowNode for request | LogInjectionBad.py:23:12:23:23 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | -| LogInjectionBad.py:23:12:23:23 | ControlFlowNode for Attribute | LogInjectionBad.py:23:12:23:35 | ControlFlowNode for Attribute() | provenance | dict.get | -| LogInjectionBad.py:23:12:23:35 | ControlFlowNode for Attribute() | LogInjectionBad.py:23:5:23:8 | ControlFlowNode for name | provenance | | -| LogInjectionBad.py:29:5:29:8 | ControlFlowNode for name | LogInjectionBad.py:30:25:30:44 | ControlFlowNode for BinaryExpr | provenance | | -| LogInjectionBad.py:29:12:29:18 | ControlFlowNode for request | LogInjectionBad.py:29:12:29:23 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | -| LogInjectionBad.py:29:12:29:23 | ControlFlowNode for Attribute | LogInjectionBad.py:29:12:29:35 | ControlFlowNode for Attribute() | provenance | dict.get | -| LogInjectionBad.py:29:12:29:35 | ControlFlowNode for Attribute() | LogInjectionBad.py:29:5:29:8 | ControlFlowNode for name | provenance | | -| LogInjectionBad.py:35:5:35:8 | ControlFlowNode for name | LogInjectionBad.py:37:19:37:38 | ControlFlowNode for BinaryExpr | provenance | | -| LogInjectionBad.py:35:12:35:18 | ControlFlowNode for request | LogInjectionBad.py:35:12:35:23 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | -| LogInjectionBad.py:35:12:35:23 | ControlFlowNode for Attribute | LogInjectionBad.py:35:12:35:35 | ControlFlowNode for Attribute() | provenance | dict.get | -| LogInjectionBad.py:35:12:35:35 | ControlFlowNode for Attribute() | LogInjectionBad.py:35:5:35:8 | ControlFlowNode for name | provenance | | +| LogInjectionBad.py:7:19:7:25 | After ImportMember | LogInjectionBad.py:7:19:7:25 | request | provenance | | +| LogInjectionBad.py:7:19:7:25 | request | LogInjectionBad.py:17:12:17:18 | request | provenance | | +| LogInjectionBad.py:7:19:7:25 | request | LogInjectionBad.py:23:12:23:18 | request | provenance | | +| LogInjectionBad.py:7:19:7:25 | request | LogInjectionBad.py:29:12:29:18 | request | provenance | | +| LogInjectionBad.py:7:19:7:25 | request | LogInjectionBad.py:35:12:35:18 | request | provenance | | +| LogInjectionBad.py:17:5:17:8 | name | LogInjectionBad.py:18:21:18:40 | After BinaryExpr | provenance | | +| LogInjectionBad.py:17:12:17:18 | request | LogInjectionBad.py:17:12:17:23 | After Attribute | provenance | AdditionalTaintStep | +| LogInjectionBad.py:17:12:17:23 | After Attribute | LogInjectionBad.py:17:12:17:35 | After Attribute() | provenance | dict.get | +| LogInjectionBad.py:17:12:17:35 | After Attribute() | LogInjectionBad.py:17:5:17:8 | name | provenance | | +| LogInjectionBad.py:23:5:23:8 | name | LogInjectionBad.py:24:18:24:37 | After BinaryExpr | provenance | | +| LogInjectionBad.py:23:12:23:18 | request | LogInjectionBad.py:23:12:23:23 | After Attribute | provenance | AdditionalTaintStep | +| LogInjectionBad.py:23:12:23:23 | After Attribute | LogInjectionBad.py:23:12:23:35 | After Attribute() | provenance | dict.get | +| LogInjectionBad.py:23:12:23:35 | After Attribute() | LogInjectionBad.py:23:5:23:8 | name | provenance | | +| LogInjectionBad.py:29:5:29:8 | name | LogInjectionBad.py:30:25:30:44 | After BinaryExpr | provenance | | +| LogInjectionBad.py:29:12:29:18 | request | LogInjectionBad.py:29:12:29:23 | After Attribute | provenance | AdditionalTaintStep | +| LogInjectionBad.py:29:12:29:23 | After Attribute | LogInjectionBad.py:29:12:29:35 | After Attribute() | provenance | dict.get | +| LogInjectionBad.py:29:12:29:35 | After Attribute() | LogInjectionBad.py:29:5:29:8 | name | provenance | | +| LogInjectionBad.py:35:5:35:8 | name | LogInjectionBad.py:37:19:37:38 | After BinaryExpr | provenance | | +| LogInjectionBad.py:35:12:35:18 | request | LogInjectionBad.py:35:12:35:23 | After Attribute | provenance | AdditionalTaintStep | +| LogInjectionBad.py:35:12:35:23 | After Attribute | LogInjectionBad.py:35:12:35:35 | After Attribute() | provenance | dict.get | +| LogInjectionBad.py:35:12:35:35 | After Attribute() | LogInjectionBad.py:35:5:35:8 | name | provenance | | nodes -| LogInjectionBad.py:7:19:7:25 | ControlFlowNode for ImportMember | semmle.label | ControlFlowNode for ImportMember | -| LogInjectionBad.py:7:19:7:25 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| LogInjectionBad.py:17:5:17:8 | ControlFlowNode for name | semmle.label | ControlFlowNode for name | -| LogInjectionBad.py:17:12:17:18 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| LogInjectionBad.py:17:12:17:23 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| LogInjectionBad.py:17:12:17:35 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| LogInjectionBad.py:18:21:18:40 | ControlFlowNode for BinaryExpr | semmle.label | ControlFlowNode for BinaryExpr | -| LogInjectionBad.py:23:5:23:8 | ControlFlowNode for name | semmle.label | ControlFlowNode for name | -| LogInjectionBad.py:23:12:23:18 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| LogInjectionBad.py:23:12:23:23 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| LogInjectionBad.py:23:12:23:35 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| LogInjectionBad.py:24:18:24:37 | ControlFlowNode for BinaryExpr | semmle.label | ControlFlowNode for BinaryExpr | -| LogInjectionBad.py:29:5:29:8 | ControlFlowNode for name | semmle.label | ControlFlowNode for name | -| LogInjectionBad.py:29:12:29:18 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| LogInjectionBad.py:29:12:29:23 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| LogInjectionBad.py:29:12:29:35 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| LogInjectionBad.py:30:25:30:44 | ControlFlowNode for BinaryExpr | semmle.label | ControlFlowNode for BinaryExpr | -| LogInjectionBad.py:35:5:35:8 | ControlFlowNode for name | semmle.label | ControlFlowNode for name | -| LogInjectionBad.py:35:12:35:18 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| LogInjectionBad.py:35:12:35:23 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| LogInjectionBad.py:35:12:35:35 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| LogInjectionBad.py:37:19:37:38 | ControlFlowNode for BinaryExpr | semmle.label | ControlFlowNode for BinaryExpr | +| LogInjectionBad.py:7:19:7:25 | After ImportMember | semmle.label | After ImportMember | +| LogInjectionBad.py:7:19:7:25 | request | semmle.label | request | +| LogInjectionBad.py:17:5:17:8 | name | semmle.label | name | +| LogInjectionBad.py:17:12:17:18 | request | semmle.label | request | +| LogInjectionBad.py:17:12:17:23 | After Attribute | semmle.label | After Attribute | +| LogInjectionBad.py:17:12:17:35 | After Attribute() | semmle.label | After Attribute() | +| LogInjectionBad.py:18:21:18:40 | After BinaryExpr | semmle.label | After BinaryExpr | +| LogInjectionBad.py:23:5:23:8 | name | semmle.label | name | +| LogInjectionBad.py:23:12:23:18 | request | semmle.label | request | +| LogInjectionBad.py:23:12:23:23 | After Attribute | semmle.label | After Attribute | +| LogInjectionBad.py:23:12:23:35 | After Attribute() | semmle.label | After Attribute() | +| LogInjectionBad.py:24:18:24:37 | After BinaryExpr | semmle.label | After BinaryExpr | +| LogInjectionBad.py:29:5:29:8 | name | semmle.label | name | +| LogInjectionBad.py:29:12:29:18 | request | semmle.label | request | +| LogInjectionBad.py:29:12:29:23 | After Attribute | semmle.label | After Attribute | +| LogInjectionBad.py:29:12:29:35 | After Attribute() | semmle.label | After Attribute() | +| LogInjectionBad.py:30:25:30:44 | After BinaryExpr | semmle.label | After BinaryExpr | +| LogInjectionBad.py:35:5:35:8 | name | semmle.label | name | +| LogInjectionBad.py:35:12:35:18 | request | semmle.label | request | +| LogInjectionBad.py:35:12:35:23 | After Attribute | semmle.label | After Attribute | +| LogInjectionBad.py:35:12:35:35 | After Attribute() | semmle.label | After Attribute() | +| LogInjectionBad.py:37:19:37:38 | After BinaryExpr | semmle.label | After BinaryExpr | subpaths +#select +| LogInjectionBad.py:18:21:18:40 | After BinaryExpr | LogInjectionBad.py:7:19:7:25 | After ImportMember | LogInjectionBad.py:18:21:18:40 | After BinaryExpr | This log entry depends on a $@. | LogInjectionBad.py:7:19:7:25 | After ImportMember | user-provided value | +| LogInjectionBad.py:24:18:24:37 | After BinaryExpr | LogInjectionBad.py:7:19:7:25 | After ImportMember | LogInjectionBad.py:24:18:24:37 | After BinaryExpr | This log entry depends on a $@. | LogInjectionBad.py:7:19:7:25 | After ImportMember | user-provided value | +| LogInjectionBad.py:30:25:30:44 | After BinaryExpr | LogInjectionBad.py:7:19:7:25 | After ImportMember | LogInjectionBad.py:30:25:30:44 | After BinaryExpr | This log entry depends on a $@. | LogInjectionBad.py:7:19:7:25 | After ImportMember | user-provided value | +| LogInjectionBad.py:37:19:37:38 | After BinaryExpr | LogInjectionBad.py:7:19:7:25 | After ImportMember | LogInjectionBad.py:37:19:37:38 | After BinaryExpr | This log entry depends on a $@. | LogInjectionBad.py:7:19:7:25 | After ImportMember | user-provided value | diff --git a/python/ql/test/query-tests/Security/CWE-1275-SameSiteNoneCookie/SameSiteNoneCookie.expected b/python/ql/test/query-tests/Security/CWE-1275-SameSiteNoneCookie/SameSiteNoneCookie.expected index 7a8e83a732c6..15b78c94d42a 100644 --- a/python/ql/test/query-tests/Security/CWE-1275-SameSiteNoneCookie/SameSiteNoneCookie.expected +++ b/python/ql/test/query-tests/Security/CWE-1275-SameSiteNoneCookie/SameSiteNoneCookie.expected @@ -1,2 +1,2 @@ -| test.py:10:5:10:60 | ControlFlowNode for Attribute() | Sensitive cookie with SameSite set to 'None'. | -| test.py:13:5:13:78 | ControlFlowNode for Attribute() | Sensitive cookie with SameSite set to 'None'. | +| test.py:10:5:10:60 | After Attribute() | Sensitive cookie with SameSite set to 'None'. | +| test.py:13:5:13:78 | After Attribute() | Sensitive cookie with SameSite set to 'None'. | diff --git a/python/ql/test/query-tests/Security/CWE-209-StackTraceExposure/StackTraceExposure.expected b/python/ql/test/query-tests/Security/CWE-209-StackTraceExposure/StackTraceExposure.expected index b24fd261ea88..9244c4e64bf9 100644 --- a/python/ql/test/query-tests/Security/CWE-209-StackTraceExposure/StackTraceExposure.expected +++ b/python/ql/test/query-tests/Security/CWE-209-StackTraceExposure/StackTraceExposure.expected @@ -1,35 +1,33 @@ edges -| test.py:23:25:23:25 | ControlFlowNode for e | test.py:24:16:24:16 | ControlFlowNode for e | provenance | | -| test.py:31:25:31:25 | ControlFlowNode for e | test.py:32:16:32:16 | ControlFlowNode for e | provenance | | -| test.py:32:16:32:16 | ControlFlowNode for e | test.py:32:16:32:30 | ControlFlowNode for Attribute | provenance | Config | -| test.py:49:9:49:11 | ControlFlowNode for err | test.py:50:29:50:31 | ControlFlowNode for err | provenance | | -| test.py:49:15:49:36 | ControlFlowNode for Attribute() | test.py:49:9:49:11 | ControlFlowNode for err | provenance | | -| test.py:50:29:50:31 | ControlFlowNode for err | test.py:50:16:50:32 | ControlFlowNode for format_error() | provenance | | -| test.py:50:29:50:31 | ControlFlowNode for err | test.py:52:18:52:20 | ControlFlowNode for msg | provenance | | -| test.py:52:18:52:20 | ControlFlowNode for msg | test.py:53:12:53:27 | ControlFlowNode for BinaryExpr | provenance | | -| test.py:65:25:65:25 | ControlFlowNode for e | test.py:66:34:66:39 | ControlFlowNode for str() | provenance | | -| test.py:66:34:66:39 | ControlFlowNode for str() | test.py:66:24:66:40 | ControlFlowNode for Dict | provenance | | +| test.py:23:25:23:25 | e | test.py:24:16:24:16 | e | provenance | | +| test.py:31:25:31:25 | e | test.py:32:16:32:16 | e | provenance | | +| test.py:32:16:32:16 | e | test.py:32:16:32:30 | After Attribute | provenance | Config | +| test.py:49:9:49:11 | err | test.py:50:29:50:31 | err | provenance | | +| test.py:49:15:49:36 | After Attribute() | test.py:49:9:49:11 | err | provenance | | +| test.py:50:29:50:31 | err | test.py:50:16:50:32 | After format_error() | provenance | | +| test.py:50:29:50:31 | err | test.py:52:18:52:20 | msg | provenance | | +| test.py:52:18:52:20 | msg | test.py:53:12:53:27 | After BinaryExpr | provenance | | +| test.py:65:25:65:25 | e | test.py:66:24:66:40 | After Dict | provenance | | nodes -| test.py:16:16:16:37 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| test.py:23:25:23:25 | ControlFlowNode for e | semmle.label | ControlFlowNode for e | -| test.py:24:16:24:16 | ControlFlowNode for e | semmle.label | ControlFlowNode for e | -| test.py:31:25:31:25 | ControlFlowNode for e | semmle.label | ControlFlowNode for e | -| test.py:32:16:32:16 | ControlFlowNode for e | semmle.label | ControlFlowNode for e | -| test.py:32:16:32:30 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| test.py:49:9:49:11 | ControlFlowNode for err | semmle.label | ControlFlowNode for err | -| test.py:49:15:49:36 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| test.py:50:16:50:32 | ControlFlowNode for format_error() | semmle.label | ControlFlowNode for format_error() | -| test.py:50:29:50:31 | ControlFlowNode for err | semmle.label | ControlFlowNode for err | -| test.py:52:18:52:20 | ControlFlowNode for msg | semmle.label | ControlFlowNode for msg | -| test.py:53:12:53:27 | ControlFlowNode for BinaryExpr | semmle.label | ControlFlowNode for BinaryExpr | -| test.py:65:25:65:25 | ControlFlowNode for e | semmle.label | ControlFlowNode for e | -| test.py:66:24:66:40 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict | -| test.py:66:34:66:39 | ControlFlowNode for str() | semmle.label | ControlFlowNode for str() | +| test.py:16:16:16:37 | After Attribute() | semmle.label | After Attribute() | +| test.py:23:25:23:25 | e | semmle.label | e | +| test.py:24:16:24:16 | e | semmle.label | e | +| test.py:31:25:31:25 | e | semmle.label | e | +| test.py:32:16:32:16 | e | semmle.label | e | +| test.py:32:16:32:30 | After Attribute | semmle.label | After Attribute | +| test.py:49:9:49:11 | err | semmle.label | err | +| test.py:49:15:49:36 | After Attribute() | semmle.label | After Attribute() | +| test.py:50:16:50:32 | After format_error() | semmle.label | After format_error() | +| test.py:50:29:50:31 | err | semmle.label | err | +| test.py:52:18:52:20 | msg | semmle.label | msg | +| test.py:53:12:53:27 | After BinaryExpr | semmle.label | After BinaryExpr | +| test.py:65:25:65:25 | e | semmle.label | e | +| test.py:66:24:66:40 | After Dict | semmle.label | After Dict | subpaths -| test.py:50:29:50:31 | ControlFlowNode for err | test.py:52:18:52:20 | ControlFlowNode for msg | test.py:53:12:53:27 | ControlFlowNode for BinaryExpr | test.py:50:16:50:32 | ControlFlowNode for format_error() | +| test.py:50:29:50:31 | err | test.py:52:18:52:20 | msg | test.py:53:12:53:27 | After BinaryExpr | test.py:50:16:50:32 | After format_error() | #select -| test.py:16:16:16:37 | ControlFlowNode for Attribute() | test.py:16:16:16:37 | ControlFlowNode for Attribute() | test.py:16:16:16:37 | ControlFlowNode for Attribute() | $@ flows to this location and may be exposed to an external user. | test.py:16:16:16:37 | ControlFlowNode for Attribute() | Stack trace information | -| test.py:24:16:24:16 | ControlFlowNode for e | test.py:23:25:23:25 | ControlFlowNode for e | test.py:24:16:24:16 | ControlFlowNode for e | $@ flows to this location and may be exposed to an external user. | test.py:23:25:23:25 | ControlFlowNode for e | Stack trace information | -| test.py:32:16:32:30 | ControlFlowNode for Attribute | test.py:31:25:31:25 | ControlFlowNode for e | test.py:32:16:32:30 | ControlFlowNode for Attribute | $@ flows to this location and may be exposed to an external user. | test.py:31:25:31:25 | ControlFlowNode for e | Stack trace information | -| test.py:50:16:50:32 | ControlFlowNode for format_error() | test.py:49:15:49:36 | ControlFlowNode for Attribute() | test.py:50:16:50:32 | ControlFlowNode for format_error() | $@ flows to this location and may be exposed to an external user. | test.py:49:15:49:36 | ControlFlowNode for Attribute() | Stack trace information | -| test.py:66:24:66:40 | ControlFlowNode for Dict | test.py:65:25:65:25 | ControlFlowNode for e | test.py:66:24:66:40 | ControlFlowNode for Dict | $@ flows to this location and may be exposed to an external user. | test.py:65:25:65:25 | ControlFlowNode for e | Stack trace information | +| test.py:16:16:16:37 | After Attribute() | test.py:16:16:16:37 | After Attribute() | test.py:16:16:16:37 | After Attribute() | $@ flows to this location and may be exposed to an external user. | test.py:16:16:16:37 | After Attribute() | Stack trace information | +| test.py:24:16:24:16 | e | test.py:23:25:23:25 | e | test.py:24:16:24:16 | e | $@ flows to this location and may be exposed to an external user. | test.py:23:25:23:25 | e | Stack trace information | +| test.py:32:16:32:30 | After Attribute | test.py:31:25:31:25 | e | test.py:32:16:32:30 | After Attribute | $@ flows to this location and may be exposed to an external user. | test.py:31:25:31:25 | e | Stack trace information | +| test.py:50:16:50:32 | After format_error() | test.py:49:15:49:36 | After Attribute() | test.py:50:16:50:32 | After format_error() | $@ flows to this location and may be exposed to an external user. | test.py:49:15:49:36 | After Attribute() | Stack trace information | +| test.py:66:24:66:40 | After Dict | test.py:65:25:65:25 | e | test.py:66:24:66:40 | After Dict | $@ flows to this location and may be exposed to an external user. | test.py:65:25:65:25 | e | Stack trace information | diff --git a/python/ql/test/query-tests/Security/CWE-215-FlaskDebug/FlaskDebug.expected b/python/ql/test/query-tests/Security/CWE-215-FlaskDebug/FlaskDebug.expected index e6c2a98d9303..239621092107 100644 --- a/python/ql/test/query-tests/Security/CWE-215-FlaskDebug/FlaskDebug.expected +++ b/python/ql/test/query-tests/Security/CWE-215-FlaskDebug/FlaskDebug.expected @@ -1,6 +1,6 @@ -| test.py:10:1:10:19 | ControlFlowNode for Attribute() | A Flask app appears to be run in debug mode. This may allow an attacker to run arbitrary code through the debugger. | -| test.py:11:1:11:27 | ControlFlowNode for Attribute() | A Flask app appears to be run in debug mode. This may allow an attacker to run arbitrary code through the debugger. | -| test.py:26:1:26:20 | ControlFlowNode for Attribute() | A Flask app appears to be run in debug mode. This may allow an attacker to run arbitrary code through the debugger. | -| test.py:30:1:30:20 | ControlFlowNode for Attribute() | A Flask app appears to be run in debug mode. This may allow an attacker to run arbitrary code through the debugger. | -| test.py:38:1:38:18 | ControlFlowNode for runapp() | A Flask app appears to be run in debug mode. This may allow an attacker to run arbitrary code through the debugger. | -| test.py:43:1:43:35 | ControlFlowNode for Attribute() | A Flask app appears to be run in debug mode. This may allow an attacker to run arbitrary code through the debugger. | +| test.py:10:1:10:19 | After Attribute() | A Flask app appears to be run in debug mode. This may allow an attacker to run arbitrary code through the debugger. | +| test.py:11:1:11:27 | After Attribute() | A Flask app appears to be run in debug mode. This may allow an attacker to run arbitrary code through the debugger. | +| test.py:26:1:26:20 | After Attribute() | A Flask app appears to be run in debug mode. This may allow an attacker to run arbitrary code through the debugger. | +| test.py:30:1:30:20 | After Attribute() | A Flask app appears to be run in debug mode. This may allow an attacker to run arbitrary code through the debugger. | +| test.py:38:1:38:18 | After runapp() | A Flask app appears to be run in debug mode. This may allow an attacker to run arbitrary code through the debugger. | +| test.py:43:1:43:35 | After Attribute() | A Flask app appears to be run in debug mode. This may allow an attacker to run arbitrary code through the debugger. | diff --git a/python/ql/test/query-tests/Security/CWE-285-PamAuthorization/PamAuthorization.expected b/python/ql/test/query-tests/Security/CWE-285-PamAuthorization/PamAuthorization.expected index 8031d3070c94..5a88aec09229 100644 --- a/python/ql/test/query-tests/Security/CWE-285-PamAuthorization/PamAuthorization.expected +++ b/python/ql/test/query-tests/Security/CWE-285-PamAuthorization/PamAuthorization.expected @@ -1,24 +1,24 @@ edges -| pam_test.py:4:26:4:32 | ControlFlowNode for ImportMember | pam_test.py:4:26:4:32 | ControlFlowNode for request | provenance | | -| pam_test.py:4:26:4:32 | ControlFlowNode for request | pam_test.py:71:16:71:22 | ControlFlowNode for request | provenance | | -| pam_test.py:71:5:71:12 | ControlFlowNode for username | pam_test.py:74:33:74:40 | ControlFlowNode for username | provenance | | -| pam_test.py:71:16:71:22 | ControlFlowNode for request | pam_test.py:71:16:71:27 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | -| pam_test.py:71:16:71:27 | ControlFlowNode for Attribute | pam_test.py:71:16:71:47 | ControlFlowNode for Attribute() | provenance | dict.get | -| pam_test.py:71:16:71:47 | ControlFlowNode for Attribute() | pam_test.py:71:5:71:12 | ControlFlowNode for username | provenance | | -| pam_test.py:74:33:74:40 | ControlFlowNode for username | pam_test.py:74:62:74:67 | ControlFlowNode for handle | provenance | Config | -| pam_test.py:74:62:74:67 | ControlFlowNode for handle | pam_test.py:76:31:76:36 | ControlFlowNode for handle | provenance | | -| pam_test.py:76:31:76:36 | ControlFlowNode for handle | pam_test.py:76:14:76:40 | ControlFlowNode for pam_authenticate() | provenance | Config | +| pam_test.py:4:26:4:32 | After ImportMember | pam_test.py:4:26:4:32 | request | provenance | | +| pam_test.py:4:26:4:32 | request | pam_test.py:71:16:71:22 | request | provenance | | +| pam_test.py:71:5:71:12 | username | pam_test.py:74:33:74:40 | username | provenance | | +| pam_test.py:71:16:71:22 | request | pam_test.py:71:16:71:27 | After Attribute | provenance | AdditionalTaintStep | +| pam_test.py:71:16:71:27 | After Attribute | pam_test.py:71:16:71:47 | After Attribute() | provenance | dict.get | +| pam_test.py:71:16:71:47 | After Attribute() | pam_test.py:71:5:71:12 | username | provenance | | +| pam_test.py:74:33:74:40 | username | pam_test.py:74:62:74:67 | handle | provenance | Config | +| pam_test.py:74:62:74:67 | handle | pam_test.py:76:31:76:36 | handle | provenance | | +| pam_test.py:76:31:76:36 | handle | pam_test.py:76:14:76:40 | After pam_authenticate() | provenance | Config | nodes -| pam_test.py:4:26:4:32 | ControlFlowNode for ImportMember | semmle.label | ControlFlowNode for ImportMember | -| pam_test.py:4:26:4:32 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| pam_test.py:71:5:71:12 | ControlFlowNode for username | semmle.label | ControlFlowNode for username | -| pam_test.py:71:16:71:22 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| pam_test.py:71:16:71:27 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| pam_test.py:71:16:71:47 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| pam_test.py:74:33:74:40 | ControlFlowNode for username | semmle.label | ControlFlowNode for username | -| pam_test.py:74:62:74:67 | ControlFlowNode for handle | semmle.label | ControlFlowNode for handle | -| pam_test.py:76:14:76:40 | ControlFlowNode for pam_authenticate() | semmle.label | ControlFlowNode for pam_authenticate() | -| pam_test.py:76:31:76:36 | ControlFlowNode for handle | semmle.label | ControlFlowNode for handle | +| pam_test.py:4:26:4:32 | After ImportMember | semmle.label | After ImportMember | +| pam_test.py:4:26:4:32 | request | semmle.label | request | +| pam_test.py:71:5:71:12 | username | semmle.label | username | +| pam_test.py:71:16:71:22 | request | semmle.label | request | +| pam_test.py:71:16:71:27 | After Attribute | semmle.label | After Attribute | +| pam_test.py:71:16:71:47 | After Attribute() | semmle.label | After Attribute() | +| pam_test.py:74:33:74:40 | username | semmle.label | username | +| pam_test.py:74:62:74:67 | handle | semmle.label | handle | +| pam_test.py:76:14:76:40 | After pam_authenticate() | semmle.label | After pam_authenticate() | +| pam_test.py:76:31:76:36 | handle | semmle.label | handle | subpaths #select -| pam_test.py:76:14:76:40 | ControlFlowNode for pam_authenticate() | pam_test.py:4:26:4:32 | ControlFlowNode for ImportMember | pam_test.py:76:14:76:40 | ControlFlowNode for pam_authenticate() | This PAM authentication depends on a $@, and 'pam_acct_mgmt' is not called afterwards. | pam_test.py:4:26:4:32 | ControlFlowNode for ImportMember | user-provided value | +| pam_test.py:76:14:76:40 | After pam_authenticate() | pam_test.py:4:26:4:32 | After ImportMember | pam_test.py:76:14:76:40 | After pam_authenticate() | This PAM authentication depends on a $@, and 'pam_acct_mgmt' is not called afterwards. | pam_test.py:4:26:4:32 | After ImportMember | user-provided value | diff --git a/python/ql/test/query-tests/Security/CWE-295-MissingHostKeyValidation/MissingHostKeyValidation.expected b/python/ql/test/query-tests/Security/CWE-295-MissingHostKeyValidation/MissingHostKeyValidation.expected index d7245c5e6024..0831e10c019d 100644 --- a/python/ql/test/query-tests/Security/CWE-295-MissingHostKeyValidation/MissingHostKeyValidation.expected +++ b/python/ql/test/query-tests/Security/CWE-295-MissingHostKeyValidation/MissingHostKeyValidation.expected @@ -1,5 +1,5 @@ -| paramiko_host_key.py:5:1:5:49 | ControlFlowNode for Attribute() | Setting missing host key policy to AutoAddPolicy may be unsafe. | -| paramiko_host_key.py:7:1:7:49 | ControlFlowNode for Attribute() | Setting missing host key policy to WarningPolicy may be unsafe. | -| paramiko_host_key.py:11:1:11:51 | ControlFlowNode for Attribute() | Setting missing host key policy to AutoAddPolicy may be unsafe. | -| paramiko_host_key.py:13:1:13:51 | ControlFlowNode for Attribute() | Setting missing host key policy to WarningPolicy may be unsafe. | -| paramiko_host_key.py:20:1:20:58 | ControlFlowNode for Attribute() | Setting missing host key policy to AutoAddPolicy may be unsafe. | +| paramiko_host_key.py:5:1:5:49 | After Attribute() | Setting missing host key policy to AutoAddPolicy may be unsafe. | +| paramiko_host_key.py:7:1:7:49 | After Attribute() | Setting missing host key policy to WarningPolicy may be unsafe. | +| paramiko_host_key.py:11:1:11:51 | After Attribute() | Setting missing host key policy to AutoAddPolicy may be unsafe. | +| paramiko_host_key.py:13:1:13:51 | After Attribute() | Setting missing host key policy to WarningPolicy may be unsafe. | +| paramiko_host_key.py:20:1:20:58 | After Attribute() | Setting missing host key policy to AutoAddPolicy may be unsafe. | diff --git a/python/ql/test/query-tests/Security/CWE-295-RequestWithoutValidation/RequestWithoutValidation.expected b/python/ql/test/query-tests/Security/CWE-295-RequestWithoutValidation/RequestWithoutValidation.expected index c4c3ad6801f7..1d7047665271 100644 --- a/python/ql/test/query-tests/Security/CWE-295-RequestWithoutValidation/RequestWithoutValidation.expected +++ b/python/ql/test/query-tests/Security/CWE-295-RequestWithoutValidation/RequestWithoutValidation.expected @@ -1,6 +1,6 @@ -| make_request.py:5:1:5:48 | ControlFlowNode for Attribute() | This request may run without certificate validation because $@. | make_request.py:5:43:5:47 | ControlFlowNode for False | it is disabled | make_request.py:5:43:5:47 | ControlFlowNode for False | this value | -| make_request.py:7:1:7:49 | ControlFlowNode for Attribute() | This request may run without certificate validation because $@. | make_request.py:7:44:7:48 | ControlFlowNode for False | it is disabled | make_request.py:7:44:7:48 | ControlFlowNode for False | this value | -| make_request.py:12:1:12:39 | ControlFlowNode for put() | This request may run without certificate validation because $@. | make_request.py:12:34:12:38 | ControlFlowNode for False | it is disabled | make_request.py:12:34:12:38 | ControlFlowNode for False | this value | -| make_request.py:28:5:28:46 | ControlFlowNode for patch() | This request may run without certificate validation because $@ by $@. | make_request.py:28:40:28:45 | ControlFlowNode for verify | it is disabled | make_request.py:30:6:30:10 | ControlFlowNode for False | this value | -| make_request.py:34:1:34:45 | ControlFlowNode for Attribute() | This request may run without certificate validation because $@. | make_request.py:34:44:34:44 | ControlFlowNode for IntegerLiteral | it is disabled | make_request.py:34:44:34:44 | ControlFlowNode for IntegerLiteral | this value | -| make_request.py:41:1:41:26 | ControlFlowNode for Attribute() | This request may run without certificate validation because $@. | make_request.py:41:21:41:25 | ControlFlowNode for False | it is disabled | make_request.py:41:21:41:25 | ControlFlowNode for False | this value | +| make_request.py:5:1:5:48 | After Attribute() | This request may run without certificate validation because $@. | make_request.py:5:43:5:47 | False | it is disabled | make_request.py:5:43:5:47 | False | this value | +| make_request.py:7:1:7:49 | After Attribute() | This request may run without certificate validation because $@ by $@. | make_request.py:7:44:7:48 | False | it is disabled | make_request.py:5:43:5:47 | False | this value | +| make_request.py:12:1:12:39 | After put() | This request may run without certificate validation because $@ by $@. | make_request.py:12:34:12:38 | False | it is disabled | make_request.py:5:43:5:47 | False | this value | +| make_request.py:28:5:28:46 | After patch() | This request may run without certificate validation because $@ by $@. | make_request.py:28:40:28:45 | verify | it is disabled | make_request.py:5:43:5:47 | False | this value | +| make_request.py:34:1:34:45 | After Attribute() | This request may run without certificate validation because $@. | make_request.py:34:44:34:44 | IntegerLiteral | it is disabled | make_request.py:34:44:34:44 | IntegerLiteral | this value | +| make_request.py:41:1:41:26 | After Attribute() | This request may run without certificate validation because $@ by $@. | make_request.py:41:21:41:25 | False | it is disabled | make_request.py:5:43:5:47 | False | this value | diff --git a/python/ql/test/query-tests/Security/CWE-312-CleartextLogging/CleartextLogging.expected b/python/ql/test/query-tests/Security/CWE-312-CleartextLogging/CleartextLogging.expected index 47f27dbc5f27..37bc9a326d4c 100644 --- a/python/ql/test/query-tests/Security/CWE-312-CleartextLogging/CleartextLogging.expected +++ b/python/ql/test/query-tests/Security/CWE-312-CleartextLogging/CleartextLogging.expected @@ -1,94 +1,100 @@ -#select -| test.py:20:48:20:55 | ControlFlowNode for password | test.py:19:16:19:29 | ControlFlowNode for get_password() | test.py:20:48:20:55 | ControlFlowNode for password | This expression logs $@ as clear text. | test.py:19:16:19:29 | ControlFlowNode for get_password() | sensitive data (password) | -| test.py:22:58:22:65 | ControlFlowNode for password | test.py:19:16:19:29 | ControlFlowNode for get_password() | test.py:22:58:22:65 | ControlFlowNode for password | This expression logs $@ as clear text. | test.py:19:16:19:29 | ControlFlowNode for get_password() | sensitive data (password) | -| test.py:23:58:23:65 | ControlFlowNode for password | test.py:19:16:19:29 | ControlFlowNode for get_password() | test.py:23:58:23:65 | ControlFlowNode for password | This expression logs $@ as clear text. | test.py:19:16:19:29 | ControlFlowNode for get_password() | sensitive data (password) | -| test.py:27:40:27:47 | ControlFlowNode for password | test.py:19:16:19:29 | ControlFlowNode for get_password() | test.py:27:40:27:47 | ControlFlowNode for password | This expression logs $@ as clear text. | test.py:19:16:19:29 | ControlFlowNode for get_password() | sensitive data (password) | -| test.py:30:58:30:65 | ControlFlowNode for password | test.py:19:16:19:29 | ControlFlowNode for get_password() | test.py:30:58:30:65 | ControlFlowNode for password | This expression logs $@ as clear text. | test.py:19:16:19:29 | ControlFlowNode for get_password() | sensitive data (password) | -| test.py:37:11:37:24 | ControlFlowNode for get_password() | test.py:37:11:37:24 | ControlFlowNode for get_password() | test.py:37:11:37:24 | ControlFlowNode for get_password() | This expression logs $@ as clear text. | test.py:37:11:37:24 | ControlFlowNode for get_password() | sensitive data (password) | -| test.py:39:22:39:35 | ControlFlowNode for get_password() | test.py:39:22:39:35 | ControlFlowNode for get_password() | test.py:39:22:39:35 | ControlFlowNode for get_password() | This expression logs $@ as clear text. | test.py:39:22:39:35 | ControlFlowNode for get_password() | sensitive data (password) | -| test.py:40:22:40:35 | ControlFlowNode for get_password() | test.py:40:22:40:35 | ControlFlowNode for get_password() | test.py:40:22:40:35 | ControlFlowNode for get_password() | This expression logs $@ as clear text. | test.py:40:22:40:35 | ControlFlowNode for get_password() | sensitive data (password) | -| test.py:45:11:45:11 | ControlFlowNode for x | test.py:44:9:44:25 | ControlFlowNode for Attribute() | test.py:45:11:45:11 | ControlFlowNode for x | This expression logs $@ as clear text. | test.py:44:9:44:25 | ControlFlowNode for Attribute() | sensitive data (password) | -| test.py:49:15:49:36 | ControlFlowNode for social_security_number | test.py:48:14:48:35 | ControlFlowNode for social_security_number | test.py:49:15:49:36 | ControlFlowNode for social_security_number | This expression logs $@ as clear text. | test.py:48:14:48:35 | ControlFlowNode for social_security_number | sensitive data (private) | -| test.py:50:15:50:17 | ControlFlowNode for ssn | test.py:48:38:48:40 | ControlFlowNode for ssn | test.py:50:15:50:17 | ControlFlowNode for ssn | This expression logs $@ as clear text. | test.py:48:38:48:40 | ControlFlowNode for ssn | sensitive data (private) | -| test.py:52:15:52:24 | ControlFlowNode for passportNo | test.py:48:54:48:63 | ControlFlowNode for passportNo | test.py:52:15:52:24 | ControlFlowNode for passportNo | This expression logs $@ as clear text. | test.py:48:54:48:63 | ControlFlowNode for passportNo | sensitive data (private) | -| test.py:55:15:55:23 | ControlFlowNode for post_code | test.py:54:14:54:22 | ControlFlowNode for post_code | test.py:55:15:55:23 | ControlFlowNode for post_code | This expression logs $@ as clear text. | test.py:54:14:54:22 | ControlFlowNode for post_code | sensitive data (private) | -| test.py:56:15:56:21 | ControlFlowNode for zipCode | test.py:54:25:54:31 | ControlFlowNode for zipCode | test.py:56:15:56:21 | ControlFlowNode for zipCode | This expression logs $@ as clear text. | test.py:54:25:54:31 | ControlFlowNode for zipCode | sensitive data (private) | -| test.py:57:15:57:26 | ControlFlowNode for home_address | test.py:54:34:54:45 | ControlFlowNode for home_address | test.py:57:15:57:26 | ControlFlowNode for home_address | This expression logs $@ as clear text. | test.py:54:34:54:45 | ControlFlowNode for home_address | sensitive data (private) | -| test.py:60:15:60:27 | ControlFlowNode for user_latitude | test.py:59:14:59:26 | ControlFlowNode for user_latitude | test.py:60:15:60:27 | ControlFlowNode for user_latitude | This expression logs $@ as clear text. | test.py:59:14:59:26 | ControlFlowNode for user_latitude | sensitive data (private) | -| test.py:61:15:61:28 | ControlFlowNode for user_longitude | test.py:59:29:59:42 | ControlFlowNode for user_longitude | test.py:61:15:61:28 | ControlFlowNode for user_longitude | This expression logs $@ as clear text. | test.py:59:29:59:42 | ControlFlowNode for user_longitude | sensitive data (private) | -| test.py:64:15:64:27 | ControlFlowNode for mobile_number | test.py:63:14:63:26 | ControlFlowNode for mobile_number | test.py:64:15:64:27 | ControlFlowNode for mobile_number | This expression logs $@ as clear text. | test.py:63:14:63:26 | ControlFlowNode for mobile_number | sensitive data (private) | -| test.py:65:15:65:21 | ControlFlowNode for phoneNo | test.py:63:29:63:35 | ControlFlowNode for phoneNo | test.py:65:15:65:21 | ControlFlowNode for phoneNo | This expression logs $@ as clear text. | test.py:63:29:63:35 | ControlFlowNode for phoneNo | sensitive data (private) | -| test.py:68:15:68:24 | ControlFlowNode for creditcard | test.py:67:14:67:23 | ControlFlowNode for creditcard | test.py:68:15:68:24 | ControlFlowNode for creditcard | This expression logs $@ as clear text. | test.py:67:14:67:23 | ControlFlowNode for creditcard | sensitive data (private) | -| test.py:69:15:69:24 | ControlFlowNode for debit_card | test.py:67:26:67:35 | ControlFlowNode for debit_card | test.py:69:15:69:24 | ControlFlowNode for debit_card | This expression logs $@ as clear text. | test.py:67:26:67:35 | ControlFlowNode for debit_card | sensitive data (private) | -| test.py:70:15:70:25 | ControlFlowNode for bank_number | test.py:67:38:67:48 | ControlFlowNode for bank_number | test.py:70:15:70:25 | ControlFlowNode for bank_number | This expression logs $@ as clear text. | test.py:67:38:67:48 | ControlFlowNode for bank_number | sensitive data (private) | -| test.py:73:15:73:17 | ControlFlowNode for ccn | test.py:67:76:67:78 | ControlFlowNode for ccn | test.py:73:15:73:17 | ControlFlowNode for ccn | This expression logs $@ as clear text. | test.py:67:76:67:78 | ControlFlowNode for ccn | sensitive data (private) | -| test.py:74:15:74:22 | ControlFlowNode for user_ccn | test.py:67:81:67:88 | ControlFlowNode for user_ccn | test.py:74:15:74:22 | ControlFlowNode for user_ccn | This expression logs $@ as clear text. | test.py:67:81:67:88 | ControlFlowNode for user_ccn | sensitive data (private) | edges -| test.py:19:5:19:12 | ControlFlowNode for password | test.py:20:48:20:55 | ControlFlowNode for password | provenance | | -| test.py:19:5:19:12 | ControlFlowNode for password | test.py:22:58:22:65 | ControlFlowNode for password | provenance | | -| test.py:19:5:19:12 | ControlFlowNode for password | test.py:23:58:23:65 | ControlFlowNode for password | provenance | | -| test.py:19:5:19:12 | ControlFlowNode for password | test.py:27:40:27:47 | ControlFlowNode for password | provenance | | -| test.py:19:5:19:12 | ControlFlowNode for password | test.py:30:58:30:65 | ControlFlowNode for password | provenance | | -| test.py:19:16:19:29 | ControlFlowNode for get_password() | test.py:19:5:19:12 | ControlFlowNode for password | provenance | | -| test.py:44:5:44:5 | ControlFlowNode for x | test.py:45:11:45:11 | ControlFlowNode for x | provenance | | -| test.py:44:9:44:25 | ControlFlowNode for Attribute() | test.py:44:5:44:5 | ControlFlowNode for x | provenance | | -| test.py:48:14:48:35 | ControlFlowNode for social_security_number | test.py:49:15:49:36 | ControlFlowNode for social_security_number | provenance | | -| test.py:48:38:48:40 | ControlFlowNode for ssn | test.py:50:15:50:17 | ControlFlowNode for ssn | provenance | | -| test.py:48:54:48:63 | ControlFlowNode for passportNo | test.py:52:15:52:24 | ControlFlowNode for passportNo | provenance | | -| test.py:54:14:54:22 | ControlFlowNode for post_code | test.py:55:15:55:23 | ControlFlowNode for post_code | provenance | | -| test.py:54:25:54:31 | ControlFlowNode for zipCode | test.py:56:15:56:21 | ControlFlowNode for zipCode | provenance | | -| test.py:54:34:54:45 | ControlFlowNode for home_address | test.py:57:15:57:26 | ControlFlowNode for home_address | provenance | | -| test.py:59:14:59:26 | ControlFlowNode for user_latitude | test.py:60:15:60:27 | ControlFlowNode for user_latitude | provenance | | -| test.py:59:29:59:42 | ControlFlowNode for user_longitude | test.py:61:15:61:28 | ControlFlowNode for user_longitude | provenance | | -| test.py:63:14:63:26 | ControlFlowNode for mobile_number | test.py:64:15:64:27 | ControlFlowNode for mobile_number | provenance | | -| test.py:63:29:63:35 | ControlFlowNode for phoneNo | test.py:65:15:65:21 | ControlFlowNode for phoneNo | provenance | | -| test.py:67:14:67:23 | ControlFlowNode for creditcard | test.py:68:15:68:24 | ControlFlowNode for creditcard | provenance | | -| test.py:67:26:67:35 | ControlFlowNode for debit_card | test.py:69:15:69:24 | ControlFlowNode for debit_card | provenance | | -| test.py:67:38:67:48 | ControlFlowNode for bank_number | test.py:70:15:70:25 | ControlFlowNode for bank_number | provenance | | -| test.py:67:76:67:78 | ControlFlowNode for ccn | test.py:73:15:73:17 | ControlFlowNode for ccn | provenance | | -| test.py:67:81:67:88 | ControlFlowNode for user_ccn | test.py:74:15:74:22 | ControlFlowNode for user_ccn | provenance | | +| test.py:19:5:19:12 | password | test.py:20:48:20:55 | password | provenance | | +| test.py:19:5:19:12 | password | test.py:22:58:22:65 | password | provenance | | +| test.py:19:5:19:12 | password | test.py:23:58:23:65 | password | provenance | | +| test.py:19:5:19:12 | password | test.py:27:40:27:47 | password | provenance | | +| test.py:19:5:19:12 | password | test.py:30:58:30:65 | password | provenance | | +| test.py:19:16:19:29 | After get_password() | test.py:19:5:19:12 | password | provenance | | +| test.py:44:5:44:5 | x | test.py:45:11:45:11 | x | provenance | | +| test.py:44:9:44:25 | After Attribute() | test.py:44:5:44:5 | x | provenance | | +| test.py:48:14:48:35 | social_security_number | test.py:49:15:49:36 | social_security_number | provenance | | +| test.py:48:38:48:40 | ssn | test.py:50:15:50:17 | ssn | provenance | | +| test.py:48:54:48:63 | passportNo | test.py:52:15:52:24 | passportNo | provenance | | +| test.py:54:14:54:22 | post_code | test.py:55:15:55:23 | post_code | provenance | | +| test.py:54:25:54:31 | zipCode | test.py:56:15:56:21 | zipCode | provenance | | +| test.py:54:34:54:45 | home_address | test.py:57:15:57:26 | home_address | provenance | | +| test.py:59:14:59:26 | user_latitude | test.py:60:15:60:27 | user_latitude | provenance | | +| test.py:59:29:59:42 | user_longitude | test.py:61:15:61:28 | user_longitude | provenance | | +| test.py:63:14:63:26 | mobile_number | test.py:64:15:64:27 | mobile_number | provenance | | +| test.py:63:29:63:35 | phoneNo | test.py:65:15:65:21 | phoneNo | provenance | | +| test.py:67:14:67:23 | creditcard | test.py:68:15:68:24 | creditcard | provenance | | +| test.py:67:26:67:35 | debit_card | test.py:69:15:69:24 | debit_card | provenance | | +| test.py:67:38:67:48 | bank_number | test.py:70:15:70:25 | bank_number | provenance | | +| test.py:67:76:67:78 | ccn | test.py:73:15:73:17 | ccn | provenance | | +| test.py:67:81:67:88 | user_ccn | test.py:74:15:74:22 | user_ccn | provenance | | +| test.py:101:5:101:10 | config | test.py:105:11:105:31 | After Subscript | provenance | | +| test.py:103:21:103:37 | After Attribute | test.py:101:5:101:10 | config | provenance | | nodes -| test.py:19:5:19:12 | ControlFlowNode for password | semmle.label | ControlFlowNode for password | -| test.py:19:16:19:29 | ControlFlowNode for get_password() | semmle.label | ControlFlowNode for get_password() | -| test.py:20:48:20:55 | ControlFlowNode for password | semmle.label | ControlFlowNode for password | -| test.py:22:58:22:65 | ControlFlowNode for password | semmle.label | ControlFlowNode for password | -| test.py:23:58:23:65 | ControlFlowNode for password | semmle.label | ControlFlowNode for password | -| test.py:27:40:27:47 | ControlFlowNode for password | semmle.label | ControlFlowNode for password | -| test.py:30:58:30:65 | ControlFlowNode for password | semmle.label | ControlFlowNode for password | -| test.py:37:11:37:24 | ControlFlowNode for get_password() | semmle.label | ControlFlowNode for get_password() | -| test.py:39:22:39:35 | ControlFlowNode for get_password() | semmle.label | ControlFlowNode for get_password() | -| test.py:40:22:40:35 | ControlFlowNode for get_password() | semmle.label | ControlFlowNode for get_password() | -| test.py:44:5:44:5 | ControlFlowNode for x | semmle.label | ControlFlowNode for x | -| test.py:44:9:44:25 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| test.py:45:11:45:11 | ControlFlowNode for x | semmle.label | ControlFlowNode for x | -| test.py:48:14:48:35 | ControlFlowNode for social_security_number | semmle.label | ControlFlowNode for social_security_number | -| test.py:48:38:48:40 | ControlFlowNode for ssn | semmle.label | ControlFlowNode for ssn | -| test.py:48:54:48:63 | ControlFlowNode for passportNo | semmle.label | ControlFlowNode for passportNo | -| test.py:49:15:49:36 | ControlFlowNode for social_security_number | semmle.label | ControlFlowNode for social_security_number | -| test.py:50:15:50:17 | ControlFlowNode for ssn | semmle.label | ControlFlowNode for ssn | -| test.py:52:15:52:24 | ControlFlowNode for passportNo | semmle.label | ControlFlowNode for passportNo | -| test.py:54:14:54:22 | ControlFlowNode for post_code | semmle.label | ControlFlowNode for post_code | -| test.py:54:25:54:31 | ControlFlowNode for zipCode | semmle.label | ControlFlowNode for zipCode | -| test.py:54:34:54:45 | ControlFlowNode for home_address | semmle.label | ControlFlowNode for home_address | -| test.py:55:15:55:23 | ControlFlowNode for post_code | semmle.label | ControlFlowNode for post_code | -| test.py:56:15:56:21 | ControlFlowNode for zipCode | semmle.label | ControlFlowNode for zipCode | -| test.py:57:15:57:26 | ControlFlowNode for home_address | semmle.label | ControlFlowNode for home_address | -| test.py:59:14:59:26 | ControlFlowNode for user_latitude | semmle.label | ControlFlowNode for user_latitude | -| test.py:59:29:59:42 | ControlFlowNode for user_longitude | semmle.label | ControlFlowNode for user_longitude | -| test.py:60:15:60:27 | ControlFlowNode for user_latitude | semmle.label | ControlFlowNode for user_latitude | -| test.py:61:15:61:28 | ControlFlowNode for user_longitude | semmle.label | ControlFlowNode for user_longitude | -| test.py:63:14:63:26 | ControlFlowNode for mobile_number | semmle.label | ControlFlowNode for mobile_number | -| test.py:63:29:63:35 | ControlFlowNode for phoneNo | semmle.label | ControlFlowNode for phoneNo | -| test.py:64:15:64:27 | ControlFlowNode for mobile_number | semmle.label | ControlFlowNode for mobile_number | -| test.py:65:15:65:21 | ControlFlowNode for phoneNo | semmle.label | ControlFlowNode for phoneNo | -| test.py:67:14:67:23 | ControlFlowNode for creditcard | semmle.label | ControlFlowNode for creditcard | -| test.py:67:26:67:35 | ControlFlowNode for debit_card | semmle.label | ControlFlowNode for debit_card | -| test.py:67:38:67:48 | ControlFlowNode for bank_number | semmle.label | ControlFlowNode for bank_number | -| test.py:67:76:67:78 | ControlFlowNode for ccn | semmle.label | ControlFlowNode for ccn | -| test.py:67:81:67:88 | ControlFlowNode for user_ccn | semmle.label | ControlFlowNode for user_ccn | -| test.py:68:15:68:24 | ControlFlowNode for creditcard | semmle.label | ControlFlowNode for creditcard | -| test.py:69:15:69:24 | ControlFlowNode for debit_card | semmle.label | ControlFlowNode for debit_card | -| test.py:70:15:70:25 | ControlFlowNode for bank_number | semmle.label | ControlFlowNode for bank_number | -| test.py:73:15:73:17 | ControlFlowNode for ccn | semmle.label | ControlFlowNode for ccn | -| test.py:74:15:74:22 | ControlFlowNode for user_ccn | semmle.label | ControlFlowNode for user_ccn | +| test.py:19:5:19:12 | password | semmle.label | password | +| test.py:19:16:19:29 | After get_password() | semmle.label | After get_password() | +| test.py:20:48:20:55 | password | semmle.label | password | +| test.py:22:58:22:65 | password | semmle.label | password | +| test.py:23:58:23:65 | password | semmle.label | password | +| test.py:27:40:27:47 | password | semmle.label | password | +| test.py:30:58:30:65 | password | semmle.label | password | +| test.py:37:11:37:24 | After get_password() | semmle.label | After get_password() | +| test.py:39:22:39:35 | After get_password() | semmle.label | After get_password() | +| test.py:40:22:40:35 | After get_password() | semmle.label | After get_password() | +| test.py:44:5:44:5 | x | semmle.label | x | +| test.py:44:9:44:25 | After Attribute() | semmle.label | After Attribute() | +| test.py:45:11:45:11 | x | semmle.label | x | +| test.py:48:14:48:35 | social_security_number | semmle.label | social_security_number | +| test.py:48:38:48:40 | ssn | semmle.label | ssn | +| test.py:48:54:48:63 | passportNo | semmle.label | passportNo | +| test.py:49:15:49:36 | social_security_number | semmle.label | social_security_number | +| test.py:50:15:50:17 | ssn | semmle.label | ssn | +| test.py:52:15:52:24 | passportNo | semmle.label | passportNo | +| test.py:54:14:54:22 | post_code | semmle.label | post_code | +| test.py:54:25:54:31 | zipCode | semmle.label | zipCode | +| test.py:54:34:54:45 | home_address | semmle.label | home_address | +| test.py:55:15:55:23 | post_code | semmle.label | post_code | +| test.py:56:15:56:21 | zipCode | semmle.label | zipCode | +| test.py:57:15:57:26 | home_address | semmle.label | home_address | +| test.py:59:14:59:26 | user_latitude | semmle.label | user_latitude | +| test.py:59:29:59:42 | user_longitude | semmle.label | user_longitude | +| test.py:60:15:60:27 | user_latitude | semmle.label | user_latitude | +| test.py:61:15:61:28 | user_longitude | semmle.label | user_longitude | +| test.py:63:14:63:26 | mobile_number | semmle.label | mobile_number | +| test.py:63:29:63:35 | phoneNo | semmle.label | phoneNo | +| test.py:64:15:64:27 | mobile_number | semmle.label | mobile_number | +| test.py:65:15:65:21 | phoneNo | semmle.label | phoneNo | +| test.py:67:14:67:23 | creditcard | semmle.label | creditcard | +| test.py:67:26:67:35 | debit_card | semmle.label | debit_card | +| test.py:67:38:67:48 | bank_number | semmle.label | bank_number | +| test.py:67:76:67:78 | ccn | semmle.label | ccn | +| test.py:67:81:67:88 | user_ccn | semmle.label | user_ccn | +| test.py:68:15:68:24 | creditcard | semmle.label | creditcard | +| test.py:69:15:69:24 | debit_card | semmle.label | debit_card | +| test.py:70:15:70:25 | bank_number | semmle.label | bank_number | +| test.py:73:15:73:17 | ccn | semmle.label | ccn | +| test.py:74:15:74:22 | user_ccn | semmle.label | user_ccn | +| test.py:101:5:101:10 | config | semmle.label | config | +| test.py:103:21:103:37 | After Attribute | semmle.label | After Attribute | +| test.py:105:11:105:31 | After Subscript | semmle.label | After Subscript | subpaths +#select +| test.py:20:48:20:55 | password | test.py:19:16:19:29 | After get_password() | test.py:20:48:20:55 | password | This expression logs $@ as clear text. | test.py:19:16:19:29 | After get_password() | sensitive data (password) | +| test.py:22:58:22:65 | password | test.py:19:16:19:29 | After get_password() | test.py:22:58:22:65 | password | This expression logs $@ as clear text. | test.py:19:16:19:29 | After get_password() | sensitive data (password) | +| test.py:23:58:23:65 | password | test.py:19:16:19:29 | After get_password() | test.py:23:58:23:65 | password | This expression logs $@ as clear text. | test.py:19:16:19:29 | After get_password() | sensitive data (password) | +| test.py:27:40:27:47 | password | test.py:19:16:19:29 | After get_password() | test.py:27:40:27:47 | password | This expression logs $@ as clear text. | test.py:19:16:19:29 | After get_password() | sensitive data (password) | +| test.py:30:58:30:65 | password | test.py:19:16:19:29 | After get_password() | test.py:30:58:30:65 | password | This expression logs $@ as clear text. | test.py:19:16:19:29 | After get_password() | sensitive data (password) | +| test.py:37:11:37:24 | After get_password() | test.py:37:11:37:24 | After get_password() | test.py:37:11:37:24 | After get_password() | This expression logs $@ as clear text. | test.py:37:11:37:24 | After get_password() | sensitive data (password) | +| test.py:39:22:39:35 | After get_password() | test.py:39:22:39:35 | After get_password() | test.py:39:22:39:35 | After get_password() | This expression logs $@ as clear text. | test.py:39:22:39:35 | After get_password() | sensitive data (password) | +| test.py:40:22:40:35 | After get_password() | test.py:40:22:40:35 | After get_password() | test.py:40:22:40:35 | After get_password() | This expression logs $@ as clear text. | test.py:40:22:40:35 | After get_password() | sensitive data (password) | +| test.py:45:11:45:11 | x | test.py:44:9:44:25 | After Attribute() | test.py:45:11:45:11 | x | This expression logs $@ as clear text. | test.py:44:9:44:25 | After Attribute() | sensitive data (password) | +| test.py:49:15:49:36 | social_security_number | test.py:48:14:48:35 | social_security_number | test.py:49:15:49:36 | social_security_number | This expression logs $@ as clear text. | test.py:48:14:48:35 | social_security_number | sensitive data (private) | +| test.py:50:15:50:17 | ssn | test.py:48:38:48:40 | ssn | test.py:50:15:50:17 | ssn | This expression logs $@ as clear text. | test.py:48:38:48:40 | ssn | sensitive data (private) | +| test.py:52:15:52:24 | passportNo | test.py:48:54:48:63 | passportNo | test.py:52:15:52:24 | passportNo | This expression logs $@ as clear text. | test.py:48:54:48:63 | passportNo | sensitive data (private) | +| test.py:55:15:55:23 | post_code | test.py:54:14:54:22 | post_code | test.py:55:15:55:23 | post_code | This expression logs $@ as clear text. | test.py:54:14:54:22 | post_code | sensitive data (private) | +| test.py:56:15:56:21 | zipCode | test.py:54:25:54:31 | zipCode | test.py:56:15:56:21 | zipCode | This expression logs $@ as clear text. | test.py:54:25:54:31 | zipCode | sensitive data (private) | +| test.py:57:15:57:26 | home_address | test.py:54:34:54:45 | home_address | test.py:57:15:57:26 | home_address | This expression logs $@ as clear text. | test.py:54:34:54:45 | home_address | sensitive data (private) | +| test.py:60:15:60:27 | user_latitude | test.py:59:14:59:26 | user_latitude | test.py:60:15:60:27 | user_latitude | This expression logs $@ as clear text. | test.py:59:14:59:26 | user_latitude | sensitive data (private) | +| test.py:61:15:61:28 | user_longitude | test.py:59:29:59:42 | user_longitude | test.py:61:15:61:28 | user_longitude | This expression logs $@ as clear text. | test.py:59:29:59:42 | user_longitude | sensitive data (private) | +| test.py:64:15:64:27 | mobile_number | test.py:63:14:63:26 | mobile_number | test.py:64:15:64:27 | mobile_number | This expression logs $@ as clear text. | test.py:63:14:63:26 | mobile_number | sensitive data (private) | +| test.py:65:15:65:21 | phoneNo | test.py:63:29:63:35 | phoneNo | test.py:65:15:65:21 | phoneNo | This expression logs $@ as clear text. | test.py:63:29:63:35 | phoneNo | sensitive data (private) | +| test.py:68:15:68:24 | creditcard | test.py:67:14:67:23 | creditcard | test.py:68:15:68:24 | creditcard | This expression logs $@ as clear text. | test.py:67:14:67:23 | creditcard | sensitive data (private) | +| test.py:69:15:69:24 | debit_card | test.py:67:26:67:35 | debit_card | test.py:69:15:69:24 | debit_card | This expression logs $@ as clear text. | test.py:67:26:67:35 | debit_card | sensitive data (private) | +| test.py:70:15:70:25 | bank_number | test.py:67:38:67:48 | bank_number | test.py:70:15:70:25 | bank_number | This expression logs $@ as clear text. | test.py:67:38:67:48 | bank_number | sensitive data (private) | +| test.py:73:15:73:17 | ccn | test.py:67:76:67:78 | ccn | test.py:73:15:73:17 | ccn | This expression logs $@ as clear text. | test.py:67:76:67:78 | ccn | sensitive data (private) | +| test.py:74:15:74:22 | user_ccn | test.py:67:81:67:88 | user_ccn | test.py:74:15:74:22 | user_ccn | This expression logs $@ as clear text. | test.py:67:81:67:88 | user_ccn | sensitive data (private) | +| test.py:105:11:105:31 | After Subscript | test.py:103:21:103:37 | After Attribute | test.py:105:11:105:31 | After Subscript | This expression logs $@ as clear text. | test.py:103:21:103:37 | After Attribute | sensitive data (password) | diff --git a/python/ql/test/query-tests/Security/CWE-312-CleartextStorage-py3/CleartextStorage.expected b/python/ql/test/query-tests/Security/CWE-312-CleartextStorage-py3/CleartextStorage.expected index 66c192b89e03..3fe85502c7cf 100644 --- a/python/ql/test/query-tests/Security/CWE-312-CleartextStorage-py3/CleartextStorage.expected +++ b/python/ql/test/query-tests/Security/CWE-312-CleartextStorage-py3/CleartextStorage.expected @@ -1,16 +1,16 @@ -#select -| test.py:12:21:12:28 | ControlFlowNode for password | test.py:9:16:9:29 | ControlFlowNode for get_password() | test.py:12:21:12:28 | ControlFlowNode for password | This expression stores $@ as clear text. | test.py:9:16:9:29 | ControlFlowNode for get_password() | sensitive data (password) | -| test.py:13:22:13:45 | ControlFlowNode for Attribute() | test.py:9:16:9:29 | ControlFlowNode for get_password() | test.py:13:22:13:45 | ControlFlowNode for Attribute() | This expression stores $@ as clear text. | test.py:9:16:9:29 | ControlFlowNode for get_password() | sensitive data (password) | -| test.py:15:26:15:33 | ControlFlowNode for password | test.py:9:16:9:29 | ControlFlowNode for get_password() | test.py:15:26:15:33 | ControlFlowNode for password | This expression stores $@ as clear text. | test.py:9:16:9:29 | ControlFlowNode for get_password() | sensitive data (password) | edges -| test.py:9:5:9:12 | ControlFlowNode for password | test.py:12:21:12:28 | ControlFlowNode for password | provenance | | -| test.py:9:5:9:12 | ControlFlowNode for password | test.py:13:22:13:45 | ControlFlowNode for Attribute() | provenance | | -| test.py:9:5:9:12 | ControlFlowNode for password | test.py:15:26:15:33 | ControlFlowNode for password | provenance | | -| test.py:9:16:9:29 | ControlFlowNode for get_password() | test.py:9:5:9:12 | ControlFlowNode for password | provenance | | +| test.py:9:5:9:12 | password | test.py:12:21:12:28 | password | provenance | | +| test.py:9:5:9:12 | password | test.py:13:22:13:45 | After Attribute() | provenance | | +| test.py:9:5:9:12 | password | test.py:15:26:15:33 | password | provenance | | +| test.py:9:16:9:29 | After get_password() | test.py:9:5:9:12 | password | provenance | | nodes -| test.py:9:5:9:12 | ControlFlowNode for password | semmle.label | ControlFlowNode for password | -| test.py:9:16:9:29 | ControlFlowNode for get_password() | semmle.label | ControlFlowNode for get_password() | -| test.py:12:21:12:28 | ControlFlowNode for password | semmle.label | ControlFlowNode for password | -| test.py:13:22:13:45 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| test.py:15:26:15:33 | ControlFlowNode for password | semmle.label | ControlFlowNode for password | +| test.py:9:5:9:12 | password | semmle.label | password | +| test.py:9:16:9:29 | After get_password() | semmle.label | After get_password() | +| test.py:12:21:12:28 | password | semmle.label | password | +| test.py:13:22:13:45 | After Attribute() | semmle.label | After Attribute() | +| test.py:15:26:15:33 | password | semmle.label | password | subpaths +#select +| test.py:12:21:12:28 | password | test.py:9:16:9:29 | After get_password() | test.py:12:21:12:28 | password | This expression stores $@ as clear text. | test.py:9:16:9:29 | After get_password() | sensitive data (password) | +| test.py:13:22:13:45 | After Attribute() | test.py:9:16:9:29 | After get_password() | test.py:13:22:13:45 | After Attribute() | This expression stores $@ as clear text. | test.py:9:16:9:29 | After get_password() | sensitive data (password) | +| test.py:15:26:15:33 | password | test.py:9:16:9:29 | After get_password() | test.py:15:26:15:33 | password | This expression stores $@ as clear text. | test.py:9:16:9:29 | After get_password() | sensitive data (password) | diff --git a/python/ql/test/query-tests/Security/CWE-312-CleartextStorage/CleartextStorage.expected b/python/ql/test/query-tests/Security/CWE-312-CleartextStorage/CleartextStorage.expected index ed748c70df3e..bb94931bf173 100644 --- a/python/ql/test/query-tests/Security/CWE-312-CleartextStorage/CleartextStorage.expected +++ b/python/ql/test/query-tests/Security/CWE-312-CleartextStorage/CleartextStorage.expected @@ -1,31 +1,27 @@ -#select -| password_in_cookie.py:9:33:9:40 | ControlFlowNode for password | password_in_cookie.py:7:16:7:43 | ControlFlowNode for Attribute() | password_in_cookie.py:9:33:9:40 | ControlFlowNode for password | This expression stores $@ as clear text. | password_in_cookie.py:7:16:7:43 | ControlFlowNode for Attribute() | sensitive data (password) | -| password_in_cookie.py:16:33:16:40 | ControlFlowNode for password | password_in_cookie.py:14:16:14:43 | ControlFlowNode for Attribute() | password_in_cookie.py:16:33:16:40 | ControlFlowNode for password | This expression stores $@ as clear text. | password_in_cookie.py:14:16:14:43 | ControlFlowNode for Attribute() | sensitive data (password) | -| test.py:17:20:17:27 | ControlFlowNode for password | test.py:15:16:15:29 | ControlFlowNode for get_password() | test.py:17:20:17:27 | ControlFlowNode for password | This expression stores $@ as clear text. | test.py:15:16:15:29 | ControlFlowNode for get_password() | sensitive data (password) | -| test.py:19:25:19:29 | ControlFlowNode for lines | test.py:15:16:15:29 | ControlFlowNode for get_password() | test.py:19:25:19:29 | ControlFlowNode for lines | This expression stores $@ as clear text. | test.py:15:16:15:29 | ControlFlowNode for get_password() | sensitive data (password) | edges -| password_in_cookie.py:7:5:7:12 | ControlFlowNode for password | password_in_cookie.py:9:33:9:40 | ControlFlowNode for password | provenance | | -| password_in_cookie.py:7:16:7:43 | ControlFlowNode for Attribute() | password_in_cookie.py:7:5:7:12 | ControlFlowNode for password | provenance | | -| password_in_cookie.py:14:5:14:12 | ControlFlowNode for password | password_in_cookie.py:16:33:16:40 | ControlFlowNode for password | provenance | | -| password_in_cookie.py:14:16:14:43 | ControlFlowNode for Attribute() | password_in_cookie.py:14:5:14:12 | ControlFlowNode for password | provenance | | -| test.py:15:5:15:12 | ControlFlowNode for password | test.py:17:20:17:27 | ControlFlowNode for password | provenance | | -| test.py:15:5:15:12 | ControlFlowNode for password | test.py:18:18:18:32 | ControlFlowNode for BinaryExpr | provenance | | -| test.py:15:16:15:29 | ControlFlowNode for get_password() | test.py:15:5:15:12 | ControlFlowNode for password | provenance | | -| test.py:18:9:18:13 | ControlFlowNode for lines [List element] | test.py:19:25:19:29 | ControlFlowNode for lines | provenance | | -| test.py:18:17:18:33 | ControlFlowNode for List [List element] | test.py:18:9:18:13 | ControlFlowNode for lines [List element] | provenance | | -| test.py:18:18:18:32 | ControlFlowNode for BinaryExpr | test.py:18:17:18:33 | ControlFlowNode for List [List element] | provenance | | +| password_in_cookie.py:7:5:7:12 | password | password_in_cookie.py:9:33:9:40 | password | provenance | | +| password_in_cookie.py:7:16:7:43 | After Attribute() | password_in_cookie.py:7:5:7:12 | password | provenance | | +| password_in_cookie.py:14:5:14:12 | password | password_in_cookie.py:16:33:16:40 | password | provenance | | +| password_in_cookie.py:14:16:14:43 | After Attribute() | password_in_cookie.py:14:5:14:12 | password | provenance | | +| test.py:15:5:15:12 | password | test.py:17:20:17:27 | password | provenance | | +| test.py:15:5:15:12 | password | test.py:18:9:18:13 | lines | provenance | | +| test.py:15:16:15:29 | After get_password() | test.py:15:5:15:12 | password | provenance | | +| test.py:18:9:18:13 | lines | test.py:19:25:19:29 | lines | provenance | | nodes -| password_in_cookie.py:7:5:7:12 | ControlFlowNode for password | semmle.label | ControlFlowNode for password | -| password_in_cookie.py:7:16:7:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| password_in_cookie.py:9:33:9:40 | ControlFlowNode for password | semmle.label | ControlFlowNode for password | -| password_in_cookie.py:14:5:14:12 | ControlFlowNode for password | semmle.label | ControlFlowNode for password | -| password_in_cookie.py:14:16:14:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| password_in_cookie.py:16:33:16:40 | ControlFlowNode for password | semmle.label | ControlFlowNode for password | -| test.py:15:5:15:12 | ControlFlowNode for password | semmle.label | ControlFlowNode for password | -| test.py:15:16:15:29 | ControlFlowNode for get_password() | semmle.label | ControlFlowNode for get_password() | -| test.py:17:20:17:27 | ControlFlowNode for password | semmle.label | ControlFlowNode for password | -| test.py:18:9:18:13 | ControlFlowNode for lines [List element] | semmle.label | ControlFlowNode for lines [List element] | -| test.py:18:17:18:33 | ControlFlowNode for List [List element] | semmle.label | ControlFlowNode for List [List element] | -| test.py:18:18:18:32 | ControlFlowNode for BinaryExpr | semmle.label | ControlFlowNode for BinaryExpr | -| test.py:19:25:19:29 | ControlFlowNode for lines | semmle.label | ControlFlowNode for lines | +| password_in_cookie.py:7:5:7:12 | password | semmle.label | password | +| password_in_cookie.py:7:16:7:43 | After Attribute() | semmle.label | After Attribute() | +| password_in_cookie.py:9:33:9:40 | password | semmle.label | password | +| password_in_cookie.py:14:5:14:12 | password | semmle.label | password | +| password_in_cookie.py:14:16:14:43 | After Attribute() | semmle.label | After Attribute() | +| password_in_cookie.py:16:33:16:40 | password | semmle.label | password | +| test.py:15:5:15:12 | password | semmle.label | password | +| test.py:15:16:15:29 | After get_password() | semmle.label | After get_password() | +| test.py:17:20:17:27 | password | semmle.label | password | +| test.py:18:9:18:13 | lines | semmle.label | lines | +| test.py:19:25:19:29 | lines | semmle.label | lines | subpaths +#select +| password_in_cookie.py:9:33:9:40 | password | password_in_cookie.py:7:16:7:43 | After Attribute() | password_in_cookie.py:9:33:9:40 | password | This expression stores $@ as clear text. | password_in_cookie.py:7:16:7:43 | After Attribute() | sensitive data (password) | +| password_in_cookie.py:16:33:16:40 | password | password_in_cookie.py:14:16:14:43 | After Attribute() | password_in_cookie.py:16:33:16:40 | password | This expression stores $@ as clear text. | password_in_cookie.py:14:16:14:43 | After Attribute() | sensitive data (password) | +| test.py:17:20:17:27 | password | test.py:15:16:15:29 | After get_password() | test.py:17:20:17:27 | password | This expression stores $@ as clear text. | test.py:15:16:15:29 | After get_password() | sensitive data (password) | +| test.py:19:25:19:29 | lines | test.py:15:16:15:29 | After get_password() | test.py:19:25:19:29 | lines | This expression stores $@ as clear text. | test.py:15:16:15:29 | After get_password() | sensitive data (password) | diff --git a/python/ql/test/query-tests/Security/CWE-326-WeakCryptoKey/WeakCryptoKey.expected b/python/ql/test/query-tests/Security/CWE-326-WeakCryptoKey/WeakCryptoKey.expected index ea1f924045ba..7d801fbd94e6 100644 --- a/python/ql/test/query-tests/Security/CWE-326-WeakCryptoKey/WeakCryptoKey.expected +++ b/python/ql/test/query-tests/Security/CWE-326-WeakCryptoKey/WeakCryptoKey.expected @@ -1,9 +1,9 @@ -| weak_crypto.py:68:1:68:21 | ControlFlowNode for dsa_gen_key() | Creation of an DSA key uses $@ bits, which is below 2048 and considered breakable. | weak_crypto.py:16:12:16:15 | ControlFlowNode for IntegerLiteral | 1024 | -| weak_crypto.py:69:1:69:19 | ControlFlowNode for ec_gen_key() | Creation of an ECC key uses $@ bits, which is below 256 and considered breakable. | weak_crypto.py:22:11:22:22 | ControlFlowNode for Attribute | 224 | -| weak_crypto.py:70:1:70:28 | ControlFlowNode for rsa_gen_key() | Creation of an RSA key uses $@ bits, which is below 2048 and considered breakable. | weak_crypto.py:12:12:12:15 | ControlFlowNode for IntegerLiteral | 1024 | -| weak_crypto.py:72:1:72:30 | ControlFlowNode for dsa_gen_key() | Creation of an DSA key uses $@ bits, which is below 2048 and considered breakable. | weak_crypto.py:16:12:16:15 | ControlFlowNode for IntegerLiteral | 1024 | -| weak_crypto.py:73:1:73:25 | ControlFlowNode for ec_gen_key() | Creation of an ECC key uses $@ bits, which is below 256 and considered breakable. | weak_crypto.py:22:11:22:22 | ControlFlowNode for Attribute | 224 | -| weak_crypto.py:74:1:74:37 | ControlFlowNode for rsa_gen_key() | Creation of an RSA key uses $@ bits, which is below 2048 and considered breakable. | weak_crypto.py:12:12:12:15 | ControlFlowNode for IntegerLiteral | 1024 | -| weak_crypto.py:76:1:76:22 | ControlFlowNode for Attribute() | Creation of an DSA key uses $@ bits, which is below 2048 and considered breakable. | weak_crypto.py:16:12:16:15 | ControlFlowNode for IntegerLiteral | 1024 | -| weak_crypto.py:77:1:77:22 | ControlFlowNode for Attribute() | Creation of an RSA key uses $@ bits, which is below 2048 and considered breakable. | weak_crypto.py:12:12:12:15 | ControlFlowNode for IntegerLiteral | 1024 | -| weak_crypto.py:84:12:84:29 | ControlFlowNode for Attribute() | Creation of an RSA key uses $@ bits, which is below 2048 and considered breakable. | weak_crypto.py:12:12:12:15 | ControlFlowNode for IntegerLiteral | 1024 | +| weak_crypto.py:68:1:68:21 | After dsa_gen_key() | Creation of an DSA key uses $@ bits, which is below 2048 and considered breakable. | weak_crypto.py:16:12:16:15 | IntegerLiteral | 1024 | +| weak_crypto.py:69:1:69:19 | After ec_gen_key() | Creation of an ECC key uses $@ bits, which is below 256 and considered breakable. | weak_crypto.py:22:11:22:22 | After Attribute | 224 | +| weak_crypto.py:70:1:70:28 | After rsa_gen_key() | Creation of an RSA key uses $@ bits, which is below 2048 and considered breakable. | weak_crypto.py:12:12:12:15 | IntegerLiteral | 1024 | +| weak_crypto.py:72:1:72:30 | After dsa_gen_key() | Creation of an DSA key uses $@ bits, which is below 2048 and considered breakable. | weak_crypto.py:16:12:16:15 | IntegerLiteral | 1024 | +| weak_crypto.py:73:1:73:25 | After ec_gen_key() | Creation of an ECC key uses $@ bits, which is below 256 and considered breakable. | weak_crypto.py:22:11:22:22 | After Attribute | 224 | +| weak_crypto.py:74:1:74:37 | After rsa_gen_key() | Creation of an RSA key uses $@ bits, which is below 2048 and considered breakable. | weak_crypto.py:12:12:12:15 | IntegerLiteral | 1024 | +| weak_crypto.py:76:1:76:22 | After Attribute() | Creation of an DSA key uses $@ bits, which is below 2048 and considered breakable. | weak_crypto.py:16:12:16:15 | IntegerLiteral | 1024 | +| weak_crypto.py:77:1:77:22 | After Attribute() | Creation of an RSA key uses $@ bits, which is below 2048 and considered breakable. | weak_crypto.py:12:12:12:15 | IntegerLiteral | 1024 | +| weak_crypto.py:84:12:84:29 | After Attribute() | Creation of an RSA key uses $@ bits, which is below 2048 and considered breakable. | weak_crypto.py:12:12:12:15 | IntegerLiteral | 1024 | diff --git a/python/ql/test/query-tests/Security/CWE-327-BrokenCryptoAlgorithm/BrokenCryptoAlgorithm.expected b/python/ql/test/query-tests/Security/CWE-327-BrokenCryptoAlgorithm/BrokenCryptoAlgorithm.expected index 43c6eeb0f774..671b8a80f2be 100644 --- a/python/ql/test/query-tests/Security/CWE-327-BrokenCryptoAlgorithm/BrokenCryptoAlgorithm.expected +++ b/python/ql/test/query-tests/Security/CWE-327-BrokenCryptoAlgorithm/BrokenCryptoAlgorithm.expected @@ -1,4 +1,4 @@ -| test_cryptodome.py:11:13:11:42 | ControlFlowNode for Attribute() | $@ is broken or weak, and should not be used. | test_cryptodome.py:10:10:10:22 | ControlFlowNode for Attribute() | The cryptographic algorithm ARC4 | -| test_cryptodome.py:16:13:16:42 | ControlFlowNode for Attribute() | $@ is broken or weak, and should not be used. | test_cryptodome.py:15:10:15:35 | ControlFlowNode for Attribute() | The block mode ECB | -| test_cryptography.py:13:13:13:44 | ControlFlowNode for Attribute() | $@ is broken or weak, and should not be used. | test_cryptography.py:12:13:12:30 | ControlFlowNode for Attribute() | The cryptographic algorithm ARC4 | -| test_cryptography.py:22:13:22:58 | ControlFlowNode for Attribute() | $@ is broken or weak, and should not be used. | test_cryptography.py:21:13:21:30 | ControlFlowNode for Attribute() | The block mode ECB | +| test_cryptodome.py:11:13:11:42 | After Attribute() | $@ is broken or weak, and should not be used. | test_cryptodome.py:10:10:10:22 | After Attribute() | The cryptographic algorithm ARC4 | +| test_cryptodome.py:16:13:16:42 | After Attribute() | $@ is broken or weak, and should not be used. | test_cryptodome.py:15:10:15:35 | After Attribute() | The block mode ECB | +| test_cryptography.py:13:13:13:44 | After Attribute() | $@ is broken or weak, and should not be used. | test_cryptography.py:12:13:12:30 | After Attribute() | The cryptographic algorithm ARC4 | +| test_cryptography.py:22:13:22:58 | After Attribute() | $@ is broken or weak, and should not be used. | test_cryptography.py:21:13:21:30 | After Attribute() | The block mode ECB | diff --git a/python/ql/test/query-tests/Security/CWE-327-InsecureDefaultProtocol/InsecureDefaultProtocol.expected b/python/ql/test/query-tests/Security/CWE-327-InsecureDefaultProtocol/InsecureDefaultProtocol.expected index 5b98a946a1fc..f2a1637d2807 100644 --- a/python/ql/test/query-tests/Security/CWE-327-InsecureDefaultProtocol/InsecureDefaultProtocol.expected +++ b/python/ql/test/query-tests/Security/CWE-327-InsecureDefaultProtocol/InsecureDefaultProtocol.expected @@ -1 +1 @@ -| InsecureProtocol.py:7:1:7:17 | ControlFlowNode for Attribute() | Call to deprecated method ssl.wrap_socket does not specify a protocol, which may result in an insecure default being used. | +| InsecureProtocol.py:7:1:7:17 | After Attribute() | Call to deprecated method ssl.wrap_socket does not specify a protocol, which may result in an insecure default being used. | diff --git a/python/ql/test/query-tests/Security/CWE-327-InsecureProtocol/InsecureProtocol.expected b/python/ql/test/query-tests/Security/CWE-327-InsecureProtocol/InsecureProtocol.expected index 491a23823642..c94b4966a0c4 100644 --- a/python/ql/test/query-tests/Security/CWE-327-InsecureProtocol/InsecureProtocol.expected +++ b/python/ql/test/query-tests/Security/CWE-327-InsecureProtocol/InsecureProtocol.expected @@ -1,45 +1,45 @@ -| InsecureProtocol.py:6:1:6:47 | ControlFlowNode for Attribute() | Insecure SSL/TLS protocol version SSLv2 specified by $@. | InsecureProtocol.py:6:1:6:47 | ControlFlowNode for Attribute() | call to ssl.wrap_socket | -| InsecureProtocol.py:7:1:7:47 | ControlFlowNode for Attribute() | Insecure SSL/TLS protocol version SSLv3 specified by $@. | InsecureProtocol.py:7:1:7:47 | ControlFlowNode for Attribute() | call to ssl.wrap_socket | -| InsecureProtocol.py:8:1:8:47 | ControlFlowNode for Attribute() | Insecure SSL/TLS protocol version TLSv1 specified by $@. | InsecureProtocol.py:8:1:8:47 | ControlFlowNode for Attribute() | call to ssl.wrap_socket | -| InsecureProtocol.py:10:1:10:39 | ControlFlowNode for SSLContext() | Insecure SSL/TLS protocol version SSLv2 specified by $@. | InsecureProtocol.py:10:1:10:39 | ControlFlowNode for SSLContext() | call to SSLContext | -| InsecureProtocol.py:11:1:11:39 | ControlFlowNode for SSLContext() | Insecure SSL/TLS protocol version SSLv3 specified by $@. | InsecureProtocol.py:11:1:11:39 | ControlFlowNode for SSLContext() | call to SSLContext | -| InsecureProtocol.py:12:1:12:39 | ControlFlowNode for SSLContext() | Insecure SSL/TLS protocol version TLSv1 specified by $@. | InsecureProtocol.py:12:1:12:39 | ControlFlowNode for SSLContext() | call to SSLContext | -| InsecureProtocol.py:14:1:14:29 | ControlFlowNode for Attribute() | Insecure SSL/TLS protocol version SSLv2 specified by $@. | InsecureProtocol.py:14:1:14:29 | ControlFlowNode for Attribute() | call to SSL.Context | -| InsecureProtocol.py:15:1:15:29 | ControlFlowNode for Attribute() | Insecure SSL/TLS protocol version SSLv3 specified by $@. | InsecureProtocol.py:15:1:15:29 | ControlFlowNode for Attribute() | call to SSL.Context | -| InsecureProtocol.py:16:1:16:29 | ControlFlowNode for Attribute() | Insecure SSL/TLS protocol version TLSv1 specified by $@. | InsecureProtocol.py:16:1:16:29 | ControlFlowNode for Attribute() | call to SSL.Context | -| InsecureProtocol.py:19:1:19:19 | ControlFlowNode for Attribute() | Insecure SSL/TLS protocol version SSLv2 specified by $@. | InsecureProtocol.py:19:1:19:19 | ControlFlowNode for Attribute() | call to SSL.Context | -| InsecureProtocol.py:23:1:23:43 | ControlFlowNode for Attribute() | Insecure SSL/TLS protocol version SSLv2 specified by $@. | InsecureProtocol.py:23:1:23:43 | ControlFlowNode for Attribute() | call to ssl.wrap_socket | -| InsecureProtocol.py:24:1:24:35 | ControlFlowNode for SSLContext() | Insecure SSL/TLS protocol version SSLv2 specified by $@. | InsecureProtocol.py:24:1:24:35 | ControlFlowNode for SSLContext() | call to SSLContext | -| import_all_one_file.py:25:14:25:45 | ControlFlowNode for copy_completely_insecure_context | Insecure SSL/TLS protocol version TLSv1 allowed by $@. | import_all_one_file.py:9:36:9:67 | ControlFlowNode for Attribute() | call to ssl.SSLContext | -| import_all_one_file.py:25:14:25:45 | ControlFlowNode for copy_completely_insecure_context | Insecure SSL/TLS protocol version TLSv1_1 allowed by $@. | import_all_one_file.py:9:36:9:67 | ControlFlowNode for Attribute() | call to ssl.SSLContext | -| import_all_one_file.py:29:14:29:39 | ControlFlowNode for copy_also_insecure_context | Insecure SSL/TLS protocol version TLSv1_1 allowed by $@. | import_all_one_file.py:12:30:12:61 | ControlFlowNode for Attribute() | call to ssl.SSLContext | -| import_use.py:13:14:13:40 | ControlFlowNode for completely_insecure_context | Insecure SSL/TLS protocol version TLSv1 allowed by $@. | import_def.py:7:31:7:62 | ControlFlowNode for Attribute() | call to ssl.SSLContext | -| import_use.py:13:14:13:40 | ControlFlowNode for completely_insecure_context | Insecure SSL/TLS protocol version TLSv1_1 allowed by $@. | import_def.py:7:31:7:62 | ControlFlowNode for Attribute() | call to ssl.SSLContext | -| import_use.py:17:14:17:34 | ControlFlowNode for also_insecure_context | Insecure SSL/TLS protocol version TLSv1_1 allowed by $@. | import_def.py:10:25:10:56 | ControlFlowNode for Attribute() | call to ssl.SSLContext | -| pyOpenSSL_fluent.py:8:27:8:33 | ControlFlowNode for context | Insecure SSL/TLS protocol version SSLv2 allowed by $@. | pyOpenSSL_fluent.py:6:15:6:44 | ControlFlowNode for Attribute() | call to SSL.Context | -| pyOpenSSL_fluent.py:8:27:8:33 | ControlFlowNode for context | Insecure SSL/TLS protocol version SSLv3 allowed by $@. | pyOpenSSL_fluent.py:6:15:6:44 | ControlFlowNode for Attribute() | call to SSL.Context | -| pyOpenSSL_fluent.py:8:27:8:33 | ControlFlowNode for context | Insecure SSL/TLS protocol version TLSv1 allowed by $@. | pyOpenSSL_fluent.py:6:15:6:44 | ControlFlowNode for Attribute() | call to SSL.Context | -| pyOpenSSL_fluent.py:8:27:8:33 | ControlFlowNode for context | Insecure SSL/TLS protocol version TLSv1_1 allowed by $@. | pyOpenSSL_fluent.py:6:15:6:44 | ControlFlowNode for Attribute() | call to SSL.Context | -| pyOpenSSL_fluent.py:18:27:18:33 | ControlFlowNode for context | Insecure SSL/TLS protocol version SSLv2 allowed by $@. | pyOpenSSL_fluent.py:15:15:15:44 | ControlFlowNode for Attribute() | call to SSL.Context | -| pyOpenSSL_fluent.py:18:27:18:33 | ControlFlowNode for context | Insecure SSL/TLS protocol version SSLv3 allowed by $@. | pyOpenSSL_fluent.py:15:15:15:44 | ControlFlowNode for Attribute() | call to SSL.Context | -| pyOpenSSL_fluent.py:18:27:18:33 | ControlFlowNode for context | Insecure SSL/TLS protocol version TLSv1_1 allowed by $@. | pyOpenSSL_fluent.py:15:15:15:44 | ControlFlowNode for Attribute() | call to SSL.Context | -| ssl_fluent.py:9:14:9:20 | ControlFlowNode for context | Insecure SSL/TLS protocol version TLSv1 allowed by $@. | ssl_fluent.py:6:15:6:46 | ControlFlowNode for Attribute() | call to ssl.SSLContext | -| ssl_fluent.py:9:14:9:20 | ControlFlowNode for context | Insecure SSL/TLS protocol version TLSv1_1 allowed by $@. | ssl_fluent.py:6:15:6:46 | ControlFlowNode for Attribute() | call to ssl.SSLContext | -| ssl_fluent.py:19:14:19:20 | ControlFlowNode for context | Insecure SSL/TLS protocol version TLSv1_1 allowed by $@. | ssl_fluent.py:15:15:15:46 | ControlFlowNode for Attribute() | call to ssl.SSLContext | -| ssl_fluent.py:28:14:28:20 | ControlFlowNode for context | Insecure SSL/TLS protocol version TLSv1_1 allowed by $@. | ssl_fluent.py:24:15:24:53 | ControlFlowNode for Attribute() | call to ssl.SSLContext | -| ssl_fluent.py:37:14:37:20 | ControlFlowNode for context | Insecure SSL/TLS protocol version TLSv1_1 allowed by $@. | ssl_fluent.py:33:15:33:53 | ControlFlowNode for Attribute() | call to ssl.SSLContext | -| ssl_fluent.py:57:14:57:20 | ControlFlowNode for context | Insecure SSL/TLS protocol version TLSv1 allowed by $@. | ssl_fluent.py:54:15:54:49 | ControlFlowNode for Attribute() | call to ssl.SSLContext | -| ssl_fluent.py:57:14:57:20 | ControlFlowNode for context | Insecure SSL/TLS protocol version TLSv1_1 allowed by $@. | ssl_fluent.py:54:15:54:49 | ControlFlowNode for Attribute() | call to ssl.SSLContext | -| ssl_fluent.py:71:14:71:20 | ControlFlowNode for context | Insecure SSL/TLS protocol version TLSv1 allowed by $@. | ssl_fluent.py:62:12:62:43 | ControlFlowNode for Attribute() | call to ssl.SSLContext | -| ssl_fluent.py:71:14:71:20 | ControlFlowNode for context | Insecure SSL/TLS protocol version TLSv1 allowed by $@. | ssl_fluent.py:101:15:101:46 | ControlFlowNode for Attribute() | call to ssl.SSLContext | -| ssl_fluent.py:71:14:71:20 | ControlFlowNode for context | Insecure SSL/TLS protocol version TLSv1_1 allowed by $@. | ssl_fluent.py:62:12:62:43 | ControlFlowNode for Attribute() | call to ssl.SSLContext | -| ssl_fluent.py:71:14:71:20 | ControlFlowNode for context | Insecure SSL/TLS protocol version TLSv1_1 allowed by $@. | ssl_fluent.py:65:15:65:46 | ControlFlowNode for Attribute() | call to ssl.SSLContext | -| ssl_fluent.py:71:14:71:20 | ControlFlowNode for context | Insecure SSL/TLS protocol version TLSv1_1 allowed by $@. | ssl_fluent.py:101:15:101:46 | ControlFlowNode for Attribute() | call to ssl.SSLContext | -| ssl_fluent.py:71:14:71:20 | ControlFlowNode for context | Insecure SSL/TLS protocol version TLSv1_1 allowed by $@. | ssl_fluent.py:115:15:115:46 | ControlFlowNode for Attribute() | call to ssl.SSLContext | -| ssl_fluent.py:77:14:77:20 | ControlFlowNode for context | Insecure SSL/TLS protocol version TLSv1 allowed by $@. | ssl_fluent.py:62:12:62:43 | ControlFlowNode for Attribute() | call to ssl.SSLContext | -| ssl_fluent.py:77:14:77:20 | ControlFlowNode for context | Insecure SSL/TLS protocol version TLSv1_1 allowed by $@. | ssl_fluent.py:62:12:62:43 | ControlFlowNode for Attribute() | call to ssl.SSLContext | -| ssl_fluent.py:97:14:97:20 | ControlFlowNode for context | Insecure SSL/TLS protocol version TLSv1_1 allowed by $@. | ssl_fluent.py:65:15:65:46 | ControlFlowNode for Attribute() | call to ssl.SSLContext | -| ssl_fluent.py:146:14:146:20 | ControlFlowNode for context | Insecure SSL/TLS protocol version TLSv1_1 allowed by $@. | ssl_fluent.py:142:15:142:46 | ControlFlowNode for Attribute() | call to ssl.SSLContext | -| ssl_fluent.py:165:14:165:20 | ControlFlowNode for context | Insecure SSL/TLS protocol version SSLv3 allowed by $@. | ssl_fluent.py:161:15:161:65 | ControlFlowNode for Attribute() | call to ssl.create_default_context | -| ssl_fluent.py:165:14:165:20 | ControlFlowNode for context | Insecure SSL/TLS protocol version TLSv1 allowed by $@. | ssl_fluent.py:161:15:161:65 | ControlFlowNode for Attribute() | call to ssl.create_default_context | -| ssl_fluent.py:165:14:165:20 | ControlFlowNode for context | Insecure SSL/TLS protocol version TLSv1_1 allowed by $@. | ssl_fluent.py:161:15:161:65 | ControlFlowNode for Attribute() | call to ssl.create_default_context | +| InsecureProtocol.py:6:1:6:47 | After Attribute() | Insecure SSL/TLS protocol version SSLv2 specified by $@. | InsecureProtocol.py:6:1:6:47 | After Attribute() | call to ssl.wrap_socket | +| InsecureProtocol.py:7:1:7:47 | After Attribute() | Insecure SSL/TLS protocol version SSLv3 specified by $@. | InsecureProtocol.py:7:1:7:47 | After Attribute() | call to ssl.wrap_socket | +| InsecureProtocol.py:8:1:8:47 | After Attribute() | Insecure SSL/TLS protocol version TLSv1 specified by $@. | InsecureProtocol.py:8:1:8:47 | After Attribute() | call to ssl.wrap_socket | +| InsecureProtocol.py:10:1:10:39 | After SSLContext() | Insecure SSL/TLS protocol version SSLv2 specified by $@. | InsecureProtocol.py:10:1:10:39 | After SSLContext() | call to SSLContext | +| InsecureProtocol.py:11:1:11:39 | After SSLContext() | Insecure SSL/TLS protocol version SSLv3 specified by $@. | InsecureProtocol.py:11:1:11:39 | After SSLContext() | call to SSLContext | +| InsecureProtocol.py:12:1:12:39 | After SSLContext() | Insecure SSL/TLS protocol version TLSv1 specified by $@. | InsecureProtocol.py:12:1:12:39 | After SSLContext() | call to SSLContext | +| InsecureProtocol.py:14:1:14:29 | After Attribute() | Insecure SSL/TLS protocol version SSLv2 specified by $@. | InsecureProtocol.py:14:1:14:29 | After Attribute() | call to SSL.Context | +| InsecureProtocol.py:15:1:15:29 | After Attribute() | Insecure SSL/TLS protocol version SSLv3 specified by $@. | InsecureProtocol.py:15:1:15:29 | After Attribute() | call to SSL.Context | +| InsecureProtocol.py:16:1:16:29 | After Attribute() | Insecure SSL/TLS protocol version TLSv1 specified by $@. | InsecureProtocol.py:16:1:16:29 | After Attribute() | call to SSL.Context | +| InsecureProtocol.py:19:1:19:19 | After Attribute() | Insecure SSL/TLS protocol version SSLv2 specified by $@. | InsecureProtocol.py:19:1:19:19 | After Attribute() | call to SSL.Context | +| InsecureProtocol.py:23:1:23:43 | After Attribute() | Insecure SSL/TLS protocol version SSLv2 specified by $@. | InsecureProtocol.py:23:1:23:43 | After Attribute() | call to ssl.wrap_socket | +| InsecureProtocol.py:24:1:24:35 | After SSLContext() | Insecure SSL/TLS protocol version SSLv2 specified by $@. | InsecureProtocol.py:24:1:24:35 | After SSLContext() | call to SSLContext | +| import_all_one_file.py:25:14:25:45 | copy_completely_insecure_context | Insecure SSL/TLS protocol version TLSv1 allowed by $@. | import_all_one_file.py:9:36:9:67 | After Attribute() | call to ssl.SSLContext | +| import_all_one_file.py:25:14:25:45 | copy_completely_insecure_context | Insecure SSL/TLS protocol version TLSv1_1 allowed by $@. | import_all_one_file.py:9:36:9:67 | After Attribute() | call to ssl.SSLContext | +| import_all_one_file.py:29:14:29:39 | copy_also_insecure_context | Insecure SSL/TLS protocol version TLSv1_1 allowed by $@. | import_all_one_file.py:12:30:12:61 | After Attribute() | call to ssl.SSLContext | +| import_use.py:13:14:13:40 | completely_insecure_context | Insecure SSL/TLS protocol version TLSv1 allowed by $@. | import_def.py:7:31:7:62 | After Attribute() | call to ssl.SSLContext | +| import_use.py:13:14:13:40 | completely_insecure_context | Insecure SSL/TLS protocol version TLSv1_1 allowed by $@. | import_def.py:7:31:7:62 | After Attribute() | call to ssl.SSLContext | +| import_use.py:17:14:17:34 | also_insecure_context | Insecure SSL/TLS protocol version TLSv1_1 allowed by $@. | import_def.py:10:25:10:56 | After Attribute() | call to ssl.SSLContext | +| pyOpenSSL_fluent.py:8:27:8:33 | context | Insecure SSL/TLS protocol version SSLv2 allowed by $@. | pyOpenSSL_fluent.py:6:15:6:44 | After Attribute() | call to SSL.Context | +| pyOpenSSL_fluent.py:8:27:8:33 | context | Insecure SSL/TLS protocol version SSLv3 allowed by $@. | pyOpenSSL_fluent.py:6:15:6:44 | After Attribute() | call to SSL.Context | +| pyOpenSSL_fluent.py:8:27:8:33 | context | Insecure SSL/TLS protocol version TLSv1 allowed by $@. | pyOpenSSL_fluent.py:6:15:6:44 | After Attribute() | call to SSL.Context | +| pyOpenSSL_fluent.py:8:27:8:33 | context | Insecure SSL/TLS protocol version TLSv1_1 allowed by $@. | pyOpenSSL_fluent.py:6:15:6:44 | After Attribute() | call to SSL.Context | +| pyOpenSSL_fluent.py:18:27:18:33 | context | Insecure SSL/TLS protocol version SSLv2 allowed by $@. | pyOpenSSL_fluent.py:15:15:15:44 | After Attribute() | call to SSL.Context | +| pyOpenSSL_fluent.py:18:27:18:33 | context | Insecure SSL/TLS protocol version SSLv3 allowed by $@. | pyOpenSSL_fluent.py:15:15:15:44 | After Attribute() | call to SSL.Context | +| pyOpenSSL_fluent.py:18:27:18:33 | context | Insecure SSL/TLS protocol version TLSv1_1 allowed by $@. | pyOpenSSL_fluent.py:15:15:15:44 | After Attribute() | call to SSL.Context | +| ssl_fluent.py:9:14:9:20 | context | Insecure SSL/TLS protocol version TLSv1 allowed by $@. | ssl_fluent.py:6:15:6:46 | After Attribute() | call to ssl.SSLContext | +| ssl_fluent.py:9:14:9:20 | context | Insecure SSL/TLS protocol version TLSv1_1 allowed by $@. | ssl_fluent.py:6:15:6:46 | After Attribute() | call to ssl.SSLContext | +| ssl_fluent.py:19:14:19:20 | context | Insecure SSL/TLS protocol version TLSv1_1 allowed by $@. | ssl_fluent.py:15:15:15:46 | After Attribute() | call to ssl.SSLContext | +| ssl_fluent.py:28:14:28:20 | context | Insecure SSL/TLS protocol version TLSv1_1 allowed by $@. | ssl_fluent.py:24:15:24:53 | After Attribute() | call to ssl.SSLContext | +| ssl_fluent.py:37:14:37:20 | context | Insecure SSL/TLS protocol version TLSv1_1 allowed by $@. | ssl_fluent.py:33:15:33:53 | After Attribute() | call to ssl.SSLContext | +| ssl_fluent.py:57:14:57:20 | context | Insecure SSL/TLS protocol version TLSv1 allowed by $@. | ssl_fluent.py:54:15:54:49 | After Attribute() | call to ssl.SSLContext | +| ssl_fluent.py:57:14:57:20 | context | Insecure SSL/TLS protocol version TLSv1_1 allowed by $@. | ssl_fluent.py:54:15:54:49 | After Attribute() | call to ssl.SSLContext | +| ssl_fluent.py:71:14:71:20 | context | Insecure SSL/TLS protocol version TLSv1 allowed by $@. | ssl_fluent.py:62:12:62:43 | After Attribute() | call to ssl.SSLContext | +| ssl_fluent.py:71:14:71:20 | context | Insecure SSL/TLS protocol version TLSv1 allowed by $@. | ssl_fluent.py:101:15:101:46 | After Attribute() | call to ssl.SSLContext | +| ssl_fluent.py:71:14:71:20 | context | Insecure SSL/TLS protocol version TLSv1_1 allowed by $@. | ssl_fluent.py:62:12:62:43 | After Attribute() | call to ssl.SSLContext | +| ssl_fluent.py:71:14:71:20 | context | Insecure SSL/TLS protocol version TLSv1_1 allowed by $@. | ssl_fluent.py:65:15:65:46 | After Attribute() | call to ssl.SSLContext | +| ssl_fluent.py:71:14:71:20 | context | Insecure SSL/TLS protocol version TLSv1_1 allowed by $@. | ssl_fluent.py:101:15:101:46 | After Attribute() | call to ssl.SSLContext | +| ssl_fluent.py:71:14:71:20 | context | Insecure SSL/TLS protocol version TLSv1_1 allowed by $@. | ssl_fluent.py:115:15:115:46 | After Attribute() | call to ssl.SSLContext | +| ssl_fluent.py:77:14:77:20 | context | Insecure SSL/TLS protocol version TLSv1 allowed by $@. | ssl_fluent.py:62:12:62:43 | After Attribute() | call to ssl.SSLContext | +| ssl_fluent.py:77:14:77:20 | context | Insecure SSL/TLS protocol version TLSv1_1 allowed by $@. | ssl_fluent.py:62:12:62:43 | After Attribute() | call to ssl.SSLContext | +| ssl_fluent.py:97:14:97:20 | context | Insecure SSL/TLS protocol version TLSv1_1 allowed by $@. | ssl_fluent.py:65:15:65:46 | After Attribute() | call to ssl.SSLContext | +| ssl_fluent.py:146:14:146:20 | context | Insecure SSL/TLS protocol version TLSv1_1 allowed by $@. | ssl_fluent.py:142:15:142:46 | After Attribute() | call to ssl.SSLContext | +| ssl_fluent.py:165:14:165:20 | context | Insecure SSL/TLS protocol version SSLv3 allowed by $@. | ssl_fluent.py:161:15:161:65 | After Attribute() | call to ssl.create_default_context | +| ssl_fluent.py:165:14:165:20 | context | Insecure SSL/TLS protocol version TLSv1 allowed by $@. | ssl_fluent.py:161:15:161:65 | After Attribute() | call to ssl.create_default_context | +| ssl_fluent.py:165:14:165:20 | context | Insecure SSL/TLS protocol version TLSv1_1 allowed by $@. | ssl_fluent.py:161:15:161:65 | After Attribute() | call to ssl.create_default_context | diff --git a/python/ql/test/query-tests/Security/CWE-327-WeakSensitiveDataHashing/WeakSensitiveDataHashing.expected b/python/ql/test/query-tests/Security/CWE-327-WeakSensitiveDataHashing/WeakSensitiveDataHashing.expected index ae081dd1aa05..3de1b3a595df 100644 --- a/python/ql/test/query-tests/Security/CWE-327-WeakSensitiveDataHashing/WeakSensitiveDataHashing.expected +++ b/python/ql/test/query-tests/Security/CWE-327-WeakSensitiveDataHashing/WeakSensitiveDataHashing.expected @@ -1,76 +1,76 @@ -#select -| test_cryptodome.py:8:19:8:27 | ControlFlowNode for dangerous | test_cryptodome.py:2:37:2:51 | ControlFlowNode for ImportMember | test_cryptodome.py:8:19:8:27 | ControlFlowNode for dangerous | $@ is used in a hashing algorithm (MD5) that is insecure. | test_cryptodome.py:2:37:2:51 | ControlFlowNode for ImportMember | Sensitive data (certificate) | -| test_cryptodome.py:8:19:8:27 | ControlFlowNode for dangerous | test_cryptodome.py:6:17:6:33 | ControlFlowNode for get_certificate() | test_cryptodome.py:8:19:8:27 | ControlFlowNode for dangerous | $@ is used in a hashing algorithm (MD5) that is insecure. | test_cryptodome.py:6:17:6:33 | ControlFlowNode for get_certificate() | Sensitive data (certificate) | -| test_cryptodome.py:15:19:15:27 | ControlFlowNode for dangerous | test_cryptodome.py:2:23:2:34 | ControlFlowNode for ImportMember | test_cryptodome.py:15:19:15:27 | ControlFlowNode for dangerous | $@ is used in a hashing algorithm (MD5) that is insecure for password hashing, since it is not a computationally expensive hash function. | test_cryptodome.py:2:23:2:34 | ControlFlowNode for ImportMember | Sensitive data (password) | -| test_cryptodome.py:15:19:15:27 | ControlFlowNode for dangerous | test_cryptodome.py:13:17:13:30 | ControlFlowNode for get_password() | test_cryptodome.py:15:19:15:27 | ControlFlowNode for dangerous | $@ is used in a hashing algorithm (MD5) that is insecure for password hashing, since it is not a computationally expensive hash function. | test_cryptodome.py:13:17:13:30 | ControlFlowNode for get_password() | Sensitive data (password) | -| test_cryptodome.py:24:19:24:27 | ControlFlowNode for dangerous | test_cryptodome.py:2:23:2:34 | ControlFlowNode for ImportMember | test_cryptodome.py:24:19:24:27 | ControlFlowNode for dangerous | $@ is used in a hashing algorithm (SHA256) that is insecure for password hashing, since it is not a computationally expensive hash function. | test_cryptodome.py:2:23:2:34 | ControlFlowNode for ImportMember | Sensitive data (password) | -| test_cryptodome.py:24:19:24:27 | ControlFlowNode for dangerous | test_cryptodome.py:20:17:20:30 | ControlFlowNode for get_password() | test_cryptodome.py:24:19:24:27 | ControlFlowNode for dangerous | $@ is used in a hashing algorithm (SHA256) that is insecure for password hashing, since it is not a computationally expensive hash function. | test_cryptodome.py:20:17:20:30 | ControlFlowNode for get_password() | Sensitive data (password) | -| test_cryptography.py:9:19:9:27 | ControlFlowNode for dangerous | test_cryptography.py:3:37:3:51 | ControlFlowNode for ImportMember | test_cryptography.py:9:19:9:27 | ControlFlowNode for dangerous | $@ is used in a hashing algorithm (MD5) that is insecure. | test_cryptography.py:3:37:3:51 | ControlFlowNode for ImportMember | Sensitive data (certificate) | -| test_cryptography.py:9:19:9:27 | ControlFlowNode for dangerous | test_cryptography.py:7:17:7:33 | ControlFlowNode for get_certificate() | test_cryptography.py:9:19:9:27 | ControlFlowNode for dangerous | $@ is used in a hashing algorithm (MD5) that is insecure. | test_cryptography.py:7:17:7:33 | ControlFlowNode for get_certificate() | Sensitive data (certificate) | -| test_cryptography.py:17:19:17:27 | ControlFlowNode for dangerous | test_cryptography.py:3:23:3:34 | ControlFlowNode for ImportMember | test_cryptography.py:17:19:17:27 | ControlFlowNode for dangerous | $@ is used in a hashing algorithm (MD5) that is insecure for password hashing, since it is not a computationally expensive hash function. | test_cryptography.py:3:23:3:34 | ControlFlowNode for ImportMember | Sensitive data (password) | -| test_cryptography.py:17:19:17:27 | ControlFlowNode for dangerous | test_cryptography.py:15:17:15:30 | ControlFlowNode for get_password() | test_cryptography.py:17:19:17:27 | ControlFlowNode for dangerous | $@ is used in a hashing algorithm (MD5) that is insecure for password hashing, since it is not a computationally expensive hash function. | test_cryptography.py:15:17:15:30 | ControlFlowNode for get_password() | Sensitive data (password) | -| test_cryptography.py:27:19:27:27 | ControlFlowNode for dangerous | test_cryptography.py:3:23:3:34 | ControlFlowNode for ImportMember | test_cryptography.py:27:19:27:27 | ControlFlowNode for dangerous | $@ is used in a hashing algorithm (SHA256) that is insecure for password hashing, since it is not a computationally expensive hash function. | test_cryptography.py:3:23:3:34 | ControlFlowNode for ImportMember | Sensitive data (password) | -| test_cryptography.py:27:19:27:27 | ControlFlowNode for dangerous | test_cryptography.py:23:17:23:30 | ControlFlowNode for get_password() | test_cryptography.py:27:19:27:27 | ControlFlowNode for dangerous | $@ is used in a hashing algorithm (SHA256) that is insecure for password hashing, since it is not a computationally expensive hash function. | test_cryptography.py:23:17:23:30 | ControlFlowNode for get_password() | Sensitive data (password) | edges -| test_cryptodome.py:2:23:2:34 | ControlFlowNode for ImportMember | test_cryptodome.py:2:23:2:34 | ControlFlowNode for get_password | provenance | | -| test_cryptodome.py:2:23:2:34 | ControlFlowNode for get_password | test_cryptodome.py:13:17:13:28 | ControlFlowNode for get_password | provenance | | -| test_cryptodome.py:2:23:2:34 | ControlFlowNode for get_password | test_cryptodome.py:20:17:20:28 | ControlFlowNode for get_password | provenance | | -| test_cryptodome.py:2:37:2:51 | ControlFlowNode for ImportMember | test_cryptodome.py:2:37:2:51 | ControlFlowNode for get_certificate | provenance | | -| test_cryptodome.py:2:37:2:51 | ControlFlowNode for get_certificate | test_cryptodome.py:6:17:6:31 | ControlFlowNode for get_certificate | provenance | | -| test_cryptodome.py:6:5:6:13 | ControlFlowNode for dangerous | test_cryptodome.py:8:19:8:27 | ControlFlowNode for dangerous | provenance | | -| test_cryptodome.py:6:17:6:31 | ControlFlowNode for get_certificate | test_cryptodome.py:6:17:6:33 | ControlFlowNode for get_certificate() | provenance | Config | -| test_cryptodome.py:6:17:6:33 | ControlFlowNode for get_certificate() | test_cryptodome.py:6:5:6:13 | ControlFlowNode for dangerous | provenance | | -| test_cryptodome.py:13:5:13:13 | ControlFlowNode for dangerous | test_cryptodome.py:15:19:15:27 | ControlFlowNode for dangerous | provenance | | -| test_cryptodome.py:13:17:13:28 | ControlFlowNode for get_password | test_cryptodome.py:13:17:13:30 | ControlFlowNode for get_password() | provenance | Config | -| test_cryptodome.py:13:17:13:30 | ControlFlowNode for get_password() | test_cryptodome.py:13:5:13:13 | ControlFlowNode for dangerous | provenance | | -| test_cryptodome.py:20:5:20:13 | ControlFlowNode for dangerous | test_cryptodome.py:24:19:24:27 | ControlFlowNode for dangerous | provenance | | -| test_cryptodome.py:20:17:20:28 | ControlFlowNode for get_password | test_cryptodome.py:20:17:20:30 | ControlFlowNode for get_password() | provenance | Config | -| test_cryptodome.py:20:17:20:30 | ControlFlowNode for get_password() | test_cryptodome.py:20:5:20:13 | ControlFlowNode for dangerous | provenance | | -| test_cryptography.py:3:23:3:34 | ControlFlowNode for ImportMember | test_cryptography.py:3:23:3:34 | ControlFlowNode for get_password | provenance | | -| test_cryptography.py:3:23:3:34 | ControlFlowNode for get_password | test_cryptography.py:15:17:15:28 | ControlFlowNode for get_password | provenance | | -| test_cryptography.py:3:23:3:34 | ControlFlowNode for get_password | test_cryptography.py:23:17:23:28 | ControlFlowNode for get_password | provenance | | -| test_cryptography.py:3:37:3:51 | ControlFlowNode for ImportMember | test_cryptography.py:3:37:3:51 | ControlFlowNode for get_certificate | provenance | | -| test_cryptography.py:3:37:3:51 | ControlFlowNode for get_certificate | test_cryptography.py:7:17:7:31 | ControlFlowNode for get_certificate | provenance | | -| test_cryptography.py:7:5:7:13 | ControlFlowNode for dangerous | test_cryptography.py:9:19:9:27 | ControlFlowNode for dangerous | provenance | | -| test_cryptography.py:7:17:7:31 | ControlFlowNode for get_certificate | test_cryptography.py:7:17:7:33 | ControlFlowNode for get_certificate() | provenance | Config | -| test_cryptography.py:7:17:7:33 | ControlFlowNode for get_certificate() | test_cryptography.py:7:5:7:13 | ControlFlowNode for dangerous | provenance | | -| test_cryptography.py:15:5:15:13 | ControlFlowNode for dangerous | test_cryptography.py:17:19:17:27 | ControlFlowNode for dangerous | provenance | | -| test_cryptography.py:15:17:15:28 | ControlFlowNode for get_password | test_cryptography.py:15:17:15:30 | ControlFlowNode for get_password() | provenance | Config | -| test_cryptography.py:15:17:15:30 | ControlFlowNode for get_password() | test_cryptography.py:15:5:15:13 | ControlFlowNode for dangerous | provenance | | -| test_cryptography.py:23:5:23:13 | ControlFlowNode for dangerous | test_cryptography.py:27:19:27:27 | ControlFlowNode for dangerous | provenance | | -| test_cryptography.py:23:17:23:28 | ControlFlowNode for get_password | test_cryptography.py:23:17:23:30 | ControlFlowNode for get_password() | provenance | Config | -| test_cryptography.py:23:17:23:30 | ControlFlowNode for get_password() | test_cryptography.py:23:5:23:13 | ControlFlowNode for dangerous | provenance | | +| test_cryptodome.py:2:23:2:34 | After ImportMember | test_cryptodome.py:2:23:2:34 | get_password | provenance | | +| test_cryptodome.py:2:23:2:34 | get_password | test_cryptodome.py:13:17:13:28 | get_password | provenance | | +| test_cryptodome.py:2:23:2:34 | get_password | test_cryptodome.py:20:17:20:28 | get_password | provenance | | +| test_cryptodome.py:2:37:2:51 | After ImportMember | test_cryptodome.py:2:37:2:51 | get_certificate | provenance | | +| test_cryptodome.py:2:37:2:51 | get_certificate | test_cryptodome.py:6:17:6:31 | get_certificate | provenance | | +| test_cryptodome.py:6:5:6:13 | dangerous | test_cryptodome.py:8:19:8:27 | dangerous | provenance | | +| test_cryptodome.py:6:17:6:31 | get_certificate | test_cryptodome.py:6:17:6:33 | After get_certificate() | provenance | Config | +| test_cryptodome.py:6:17:6:33 | After get_certificate() | test_cryptodome.py:6:5:6:13 | dangerous | provenance | | +| test_cryptodome.py:13:5:13:13 | dangerous | test_cryptodome.py:15:19:15:27 | dangerous | provenance | | +| test_cryptodome.py:13:17:13:28 | get_password | test_cryptodome.py:13:17:13:30 | After get_password() | provenance | Config | +| test_cryptodome.py:13:17:13:30 | After get_password() | test_cryptodome.py:13:5:13:13 | dangerous | provenance | | +| test_cryptodome.py:20:5:20:13 | dangerous | test_cryptodome.py:24:19:24:27 | dangerous | provenance | | +| test_cryptodome.py:20:17:20:28 | get_password | test_cryptodome.py:20:17:20:30 | After get_password() | provenance | Config | +| test_cryptodome.py:20:17:20:30 | After get_password() | test_cryptodome.py:20:5:20:13 | dangerous | provenance | | +| test_cryptography.py:3:23:3:34 | After ImportMember | test_cryptography.py:3:23:3:34 | get_password | provenance | | +| test_cryptography.py:3:23:3:34 | get_password | test_cryptography.py:15:17:15:28 | get_password | provenance | | +| test_cryptography.py:3:23:3:34 | get_password | test_cryptography.py:23:17:23:28 | get_password | provenance | | +| test_cryptography.py:3:37:3:51 | After ImportMember | test_cryptography.py:3:37:3:51 | get_certificate | provenance | | +| test_cryptography.py:3:37:3:51 | get_certificate | test_cryptography.py:7:17:7:31 | get_certificate | provenance | | +| test_cryptography.py:7:5:7:13 | dangerous | test_cryptography.py:9:19:9:27 | dangerous | provenance | | +| test_cryptography.py:7:17:7:31 | get_certificate | test_cryptography.py:7:17:7:33 | After get_certificate() | provenance | Config | +| test_cryptography.py:7:17:7:33 | After get_certificate() | test_cryptography.py:7:5:7:13 | dangerous | provenance | | +| test_cryptography.py:15:5:15:13 | dangerous | test_cryptography.py:17:19:17:27 | dangerous | provenance | | +| test_cryptography.py:15:17:15:28 | get_password | test_cryptography.py:15:17:15:30 | After get_password() | provenance | Config | +| test_cryptography.py:15:17:15:30 | After get_password() | test_cryptography.py:15:5:15:13 | dangerous | provenance | | +| test_cryptography.py:23:5:23:13 | dangerous | test_cryptography.py:27:19:27:27 | dangerous | provenance | | +| test_cryptography.py:23:17:23:28 | get_password | test_cryptography.py:23:17:23:30 | After get_password() | provenance | Config | +| test_cryptography.py:23:17:23:30 | After get_password() | test_cryptography.py:23:5:23:13 | dangerous | provenance | | nodes -| test_cryptodome.py:2:23:2:34 | ControlFlowNode for ImportMember | semmle.label | ControlFlowNode for ImportMember | -| test_cryptodome.py:2:23:2:34 | ControlFlowNode for get_password | semmle.label | ControlFlowNode for get_password | -| test_cryptodome.py:2:37:2:51 | ControlFlowNode for ImportMember | semmle.label | ControlFlowNode for ImportMember | -| test_cryptodome.py:2:37:2:51 | ControlFlowNode for get_certificate | semmle.label | ControlFlowNode for get_certificate | -| test_cryptodome.py:6:5:6:13 | ControlFlowNode for dangerous | semmle.label | ControlFlowNode for dangerous | -| test_cryptodome.py:6:17:6:31 | ControlFlowNode for get_certificate | semmle.label | ControlFlowNode for get_certificate | -| test_cryptodome.py:6:17:6:33 | ControlFlowNode for get_certificate() | semmle.label | ControlFlowNode for get_certificate() | -| test_cryptodome.py:8:19:8:27 | ControlFlowNode for dangerous | semmle.label | ControlFlowNode for dangerous | -| test_cryptodome.py:13:5:13:13 | ControlFlowNode for dangerous | semmle.label | ControlFlowNode for dangerous | -| test_cryptodome.py:13:17:13:28 | ControlFlowNode for get_password | semmle.label | ControlFlowNode for get_password | -| test_cryptodome.py:13:17:13:30 | ControlFlowNode for get_password() | semmle.label | ControlFlowNode for get_password() | -| test_cryptodome.py:15:19:15:27 | ControlFlowNode for dangerous | semmle.label | ControlFlowNode for dangerous | -| test_cryptodome.py:20:5:20:13 | ControlFlowNode for dangerous | semmle.label | ControlFlowNode for dangerous | -| test_cryptodome.py:20:17:20:28 | ControlFlowNode for get_password | semmle.label | ControlFlowNode for get_password | -| test_cryptodome.py:20:17:20:30 | ControlFlowNode for get_password() | semmle.label | ControlFlowNode for get_password() | -| test_cryptodome.py:24:19:24:27 | ControlFlowNode for dangerous | semmle.label | ControlFlowNode for dangerous | -| test_cryptography.py:3:23:3:34 | ControlFlowNode for ImportMember | semmle.label | ControlFlowNode for ImportMember | -| test_cryptography.py:3:23:3:34 | ControlFlowNode for get_password | semmle.label | ControlFlowNode for get_password | -| test_cryptography.py:3:37:3:51 | ControlFlowNode for ImportMember | semmle.label | ControlFlowNode for ImportMember | -| test_cryptography.py:3:37:3:51 | ControlFlowNode for get_certificate | semmle.label | ControlFlowNode for get_certificate | -| test_cryptography.py:7:5:7:13 | ControlFlowNode for dangerous | semmle.label | ControlFlowNode for dangerous | -| test_cryptography.py:7:17:7:31 | ControlFlowNode for get_certificate | semmle.label | ControlFlowNode for get_certificate | -| test_cryptography.py:7:17:7:33 | ControlFlowNode for get_certificate() | semmle.label | ControlFlowNode for get_certificate() | -| test_cryptography.py:9:19:9:27 | ControlFlowNode for dangerous | semmle.label | ControlFlowNode for dangerous | -| test_cryptography.py:15:5:15:13 | ControlFlowNode for dangerous | semmle.label | ControlFlowNode for dangerous | -| test_cryptography.py:15:17:15:28 | ControlFlowNode for get_password | semmle.label | ControlFlowNode for get_password | -| test_cryptography.py:15:17:15:30 | ControlFlowNode for get_password() | semmle.label | ControlFlowNode for get_password() | -| test_cryptography.py:17:19:17:27 | ControlFlowNode for dangerous | semmle.label | ControlFlowNode for dangerous | -| test_cryptography.py:23:5:23:13 | ControlFlowNode for dangerous | semmle.label | ControlFlowNode for dangerous | -| test_cryptography.py:23:17:23:28 | ControlFlowNode for get_password | semmle.label | ControlFlowNode for get_password | -| test_cryptography.py:23:17:23:30 | ControlFlowNode for get_password() | semmle.label | ControlFlowNode for get_password() | -| test_cryptography.py:27:19:27:27 | ControlFlowNode for dangerous | semmle.label | ControlFlowNode for dangerous | +| test_cryptodome.py:2:23:2:34 | After ImportMember | semmle.label | After ImportMember | +| test_cryptodome.py:2:23:2:34 | get_password | semmle.label | get_password | +| test_cryptodome.py:2:37:2:51 | After ImportMember | semmle.label | After ImportMember | +| test_cryptodome.py:2:37:2:51 | get_certificate | semmle.label | get_certificate | +| test_cryptodome.py:6:5:6:13 | dangerous | semmle.label | dangerous | +| test_cryptodome.py:6:17:6:31 | get_certificate | semmle.label | get_certificate | +| test_cryptodome.py:6:17:6:33 | After get_certificate() | semmle.label | After get_certificate() | +| test_cryptodome.py:8:19:8:27 | dangerous | semmle.label | dangerous | +| test_cryptodome.py:13:5:13:13 | dangerous | semmle.label | dangerous | +| test_cryptodome.py:13:17:13:28 | get_password | semmle.label | get_password | +| test_cryptodome.py:13:17:13:30 | After get_password() | semmle.label | After get_password() | +| test_cryptodome.py:15:19:15:27 | dangerous | semmle.label | dangerous | +| test_cryptodome.py:20:5:20:13 | dangerous | semmle.label | dangerous | +| test_cryptodome.py:20:17:20:28 | get_password | semmle.label | get_password | +| test_cryptodome.py:20:17:20:30 | After get_password() | semmle.label | After get_password() | +| test_cryptodome.py:24:19:24:27 | dangerous | semmle.label | dangerous | +| test_cryptography.py:3:23:3:34 | After ImportMember | semmle.label | After ImportMember | +| test_cryptography.py:3:23:3:34 | get_password | semmle.label | get_password | +| test_cryptography.py:3:37:3:51 | After ImportMember | semmle.label | After ImportMember | +| test_cryptography.py:3:37:3:51 | get_certificate | semmle.label | get_certificate | +| test_cryptography.py:7:5:7:13 | dangerous | semmle.label | dangerous | +| test_cryptography.py:7:17:7:31 | get_certificate | semmle.label | get_certificate | +| test_cryptography.py:7:17:7:33 | After get_certificate() | semmle.label | After get_certificate() | +| test_cryptography.py:9:19:9:27 | dangerous | semmle.label | dangerous | +| test_cryptography.py:15:5:15:13 | dangerous | semmle.label | dangerous | +| test_cryptography.py:15:17:15:28 | get_password | semmle.label | get_password | +| test_cryptography.py:15:17:15:30 | After get_password() | semmle.label | After get_password() | +| test_cryptography.py:17:19:17:27 | dangerous | semmle.label | dangerous | +| test_cryptography.py:23:5:23:13 | dangerous | semmle.label | dangerous | +| test_cryptography.py:23:17:23:28 | get_password | semmle.label | get_password | +| test_cryptography.py:23:17:23:30 | After get_password() | semmle.label | After get_password() | +| test_cryptography.py:27:19:27:27 | dangerous | semmle.label | dangerous | subpaths +#select +| test_cryptodome.py:8:19:8:27 | dangerous | test_cryptodome.py:2:37:2:51 | After ImportMember | test_cryptodome.py:8:19:8:27 | dangerous | $@ is used in a hashing algorithm (MD5) that is insecure. | test_cryptodome.py:2:37:2:51 | After ImportMember | Sensitive data (certificate) | +| test_cryptodome.py:8:19:8:27 | dangerous | test_cryptodome.py:6:17:6:33 | After get_certificate() | test_cryptodome.py:8:19:8:27 | dangerous | $@ is used in a hashing algorithm (MD5) that is insecure. | test_cryptodome.py:6:17:6:33 | After get_certificate() | Sensitive data (certificate) | +| test_cryptodome.py:15:19:15:27 | dangerous | test_cryptodome.py:2:23:2:34 | After ImportMember | test_cryptodome.py:15:19:15:27 | dangerous | $@ is used in a hashing algorithm (MD5) that is insecure for password hashing, since it is not a computationally expensive hash function. | test_cryptodome.py:2:23:2:34 | After ImportMember | Sensitive data (password) | +| test_cryptodome.py:15:19:15:27 | dangerous | test_cryptodome.py:13:17:13:30 | After get_password() | test_cryptodome.py:15:19:15:27 | dangerous | $@ is used in a hashing algorithm (MD5) that is insecure for password hashing, since it is not a computationally expensive hash function. | test_cryptodome.py:13:17:13:30 | After get_password() | Sensitive data (password) | +| test_cryptodome.py:24:19:24:27 | dangerous | test_cryptodome.py:2:23:2:34 | After ImportMember | test_cryptodome.py:24:19:24:27 | dangerous | $@ is used in a hashing algorithm (SHA256) that is insecure for password hashing, since it is not a computationally expensive hash function. | test_cryptodome.py:2:23:2:34 | After ImportMember | Sensitive data (password) | +| test_cryptodome.py:24:19:24:27 | dangerous | test_cryptodome.py:20:17:20:30 | After get_password() | test_cryptodome.py:24:19:24:27 | dangerous | $@ is used in a hashing algorithm (SHA256) that is insecure for password hashing, since it is not a computationally expensive hash function. | test_cryptodome.py:20:17:20:30 | After get_password() | Sensitive data (password) | +| test_cryptography.py:9:19:9:27 | dangerous | test_cryptography.py:3:37:3:51 | After ImportMember | test_cryptography.py:9:19:9:27 | dangerous | $@ is used in a hashing algorithm (MD5) that is insecure. | test_cryptography.py:3:37:3:51 | After ImportMember | Sensitive data (certificate) | +| test_cryptography.py:9:19:9:27 | dangerous | test_cryptography.py:7:17:7:33 | After get_certificate() | test_cryptography.py:9:19:9:27 | dangerous | $@ is used in a hashing algorithm (MD5) that is insecure. | test_cryptography.py:7:17:7:33 | After get_certificate() | Sensitive data (certificate) | +| test_cryptography.py:17:19:17:27 | dangerous | test_cryptography.py:3:23:3:34 | After ImportMember | test_cryptography.py:17:19:17:27 | dangerous | $@ is used in a hashing algorithm (MD5) that is insecure for password hashing, since it is not a computationally expensive hash function. | test_cryptography.py:3:23:3:34 | After ImportMember | Sensitive data (password) | +| test_cryptography.py:17:19:17:27 | dangerous | test_cryptography.py:15:17:15:30 | After get_password() | test_cryptography.py:17:19:17:27 | dangerous | $@ is used in a hashing algorithm (MD5) that is insecure for password hashing, since it is not a computationally expensive hash function. | test_cryptography.py:15:17:15:30 | After get_password() | Sensitive data (password) | +| test_cryptography.py:27:19:27:27 | dangerous | test_cryptography.py:3:23:3:34 | After ImportMember | test_cryptography.py:27:19:27:27 | dangerous | $@ is used in a hashing algorithm (SHA256) that is insecure for password hashing, since it is not a computationally expensive hash function. | test_cryptography.py:3:23:3:34 | After ImportMember | Sensitive data (password) | +| test_cryptography.py:27:19:27:27 | dangerous | test_cryptography.py:23:17:23:30 | After get_password() | test_cryptography.py:27:19:27:27 | dangerous | $@ is used in a hashing algorithm (SHA256) that is insecure for password hashing, since it is not a computationally expensive hash function. | test_cryptography.py:23:17:23:30 | After get_password() | Sensitive data (password) | diff --git a/python/ql/test/query-tests/Security/CWE-502-UnsafeDeserialization/UnsafeDeserialization.expected b/python/ql/test/query-tests/Security/CWE-502-UnsafeDeserialization/UnsafeDeserialization.expected index 309ef858d3b4..99bc58a4c3bd 100644 --- a/python/ql/test/query-tests/Security/CWE-502-UnsafeDeserialization/UnsafeDeserialization.expected +++ b/python/ql/test/query-tests/Security/CWE-502-UnsafeDeserialization/UnsafeDeserialization.expected @@ -1,30 +1,30 @@ -#select -| unsafe_deserialization.py:15:18:15:24 | ControlFlowNode for payload | unsafe_deserialization.py:8:26:8:32 | ControlFlowNode for ImportMember | unsafe_deserialization.py:15:18:15:24 | ControlFlowNode for payload | Unsafe deserialization depends on a $@. | unsafe_deserialization.py:8:26:8:32 | ControlFlowNode for ImportMember | user-provided value | -| unsafe_deserialization.py:16:15:16:21 | ControlFlowNode for payload | unsafe_deserialization.py:8:26:8:32 | ControlFlowNode for ImportMember | unsafe_deserialization.py:16:15:16:21 | ControlFlowNode for payload | Unsafe deserialization depends on a $@. | unsafe_deserialization.py:8:26:8:32 | ControlFlowNode for ImportMember | user-provided value | -| unsafe_deserialization.py:18:19:18:25 | ControlFlowNode for payload | unsafe_deserialization.py:8:26:8:32 | ControlFlowNode for ImportMember | unsafe_deserialization.py:18:19:18:25 | ControlFlowNode for payload | Unsafe deserialization depends on a $@. | unsafe_deserialization.py:8:26:8:32 | ControlFlowNode for ImportMember | user-provided value | -| unsafe_deserialization.py:21:16:21:22 | ControlFlowNode for payload | unsafe_deserialization.py:8:26:8:32 | ControlFlowNode for ImportMember | unsafe_deserialization.py:21:16:21:22 | ControlFlowNode for payload | Unsafe deserialization depends on a $@. | unsafe_deserialization.py:8:26:8:32 | ControlFlowNode for ImportMember | user-provided value | -| unsafe_deserialization.py:24:24:24:30 | ControlFlowNode for payload | unsafe_deserialization.py:8:26:8:32 | ControlFlowNode for ImportMember | unsafe_deserialization.py:24:24:24:30 | ControlFlowNode for payload | Unsafe deserialization depends on a $@. | unsafe_deserialization.py:8:26:8:32 | ControlFlowNode for ImportMember | user-provided value | edges -| unsafe_deserialization.py:8:26:8:32 | ControlFlowNode for ImportMember | unsafe_deserialization.py:8:26:8:32 | ControlFlowNode for request | provenance | | -| unsafe_deserialization.py:8:26:8:32 | ControlFlowNode for request | unsafe_deserialization.py:14:15:14:21 | ControlFlowNode for request | provenance | | -| unsafe_deserialization.py:14:5:14:11 | ControlFlowNode for payload | unsafe_deserialization.py:15:18:15:24 | ControlFlowNode for payload | provenance | | -| unsafe_deserialization.py:14:5:14:11 | ControlFlowNode for payload | unsafe_deserialization.py:16:15:16:21 | ControlFlowNode for payload | provenance | | -| unsafe_deserialization.py:14:5:14:11 | ControlFlowNode for payload | unsafe_deserialization.py:18:19:18:25 | ControlFlowNode for payload | provenance | | -| unsafe_deserialization.py:14:5:14:11 | ControlFlowNode for payload | unsafe_deserialization.py:21:16:21:22 | ControlFlowNode for payload | provenance | | -| unsafe_deserialization.py:14:5:14:11 | ControlFlowNode for payload | unsafe_deserialization.py:24:24:24:30 | ControlFlowNode for payload | provenance | | -| unsafe_deserialization.py:14:15:14:21 | ControlFlowNode for request | unsafe_deserialization.py:14:15:14:26 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | -| unsafe_deserialization.py:14:15:14:26 | ControlFlowNode for Attribute | unsafe_deserialization.py:14:15:14:41 | ControlFlowNode for Attribute() | provenance | dict.get | -| unsafe_deserialization.py:14:15:14:41 | ControlFlowNode for Attribute() | unsafe_deserialization.py:14:5:14:11 | ControlFlowNode for payload | provenance | | +| unsafe_deserialization.py:8:26:8:32 | After ImportMember | unsafe_deserialization.py:8:26:8:32 | request | provenance | | +| unsafe_deserialization.py:8:26:8:32 | request | unsafe_deserialization.py:14:15:14:21 | request | provenance | | +| unsafe_deserialization.py:14:5:14:11 | payload | unsafe_deserialization.py:15:18:15:24 | payload | provenance | | +| unsafe_deserialization.py:14:5:14:11 | payload | unsafe_deserialization.py:16:15:16:21 | payload | provenance | | +| unsafe_deserialization.py:14:5:14:11 | payload | unsafe_deserialization.py:18:19:18:25 | payload | provenance | | +| unsafe_deserialization.py:14:5:14:11 | payload | unsafe_deserialization.py:21:16:21:22 | payload | provenance | | +| unsafe_deserialization.py:14:5:14:11 | payload | unsafe_deserialization.py:24:24:24:30 | payload | provenance | | +| unsafe_deserialization.py:14:15:14:21 | request | unsafe_deserialization.py:14:15:14:26 | After Attribute | provenance | AdditionalTaintStep | +| unsafe_deserialization.py:14:15:14:26 | After Attribute | unsafe_deserialization.py:14:15:14:41 | After Attribute() | provenance | dict.get | +| unsafe_deserialization.py:14:15:14:41 | After Attribute() | unsafe_deserialization.py:14:5:14:11 | payload | provenance | | nodes -| unsafe_deserialization.py:8:26:8:32 | ControlFlowNode for ImportMember | semmle.label | ControlFlowNode for ImportMember | -| unsafe_deserialization.py:8:26:8:32 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| unsafe_deserialization.py:14:5:14:11 | ControlFlowNode for payload | semmle.label | ControlFlowNode for payload | -| unsafe_deserialization.py:14:15:14:21 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| unsafe_deserialization.py:14:15:14:26 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| unsafe_deserialization.py:14:15:14:41 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| 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 | -| unsafe_deserialization.py:24:24:24:30 | ControlFlowNode for payload | semmle.label | ControlFlowNode for payload | +| unsafe_deserialization.py:8:26:8:32 | After ImportMember | semmle.label | After ImportMember | +| unsafe_deserialization.py:8:26:8:32 | request | semmle.label | request | +| unsafe_deserialization.py:14:5:14:11 | payload | semmle.label | payload | +| unsafe_deserialization.py:14:15:14:21 | request | semmle.label | request | +| unsafe_deserialization.py:14:15:14:26 | After Attribute | semmle.label | After Attribute | +| unsafe_deserialization.py:14:15:14:41 | After Attribute() | semmle.label | After Attribute() | +| unsafe_deserialization.py:15:18:15:24 | payload | semmle.label | payload | +| unsafe_deserialization.py:16:15:16:21 | payload | semmle.label | payload | +| unsafe_deserialization.py:18:19:18:25 | payload | semmle.label | payload | +| unsafe_deserialization.py:21:16:21:22 | payload | semmle.label | payload | +| unsafe_deserialization.py:24:24:24:30 | payload | semmle.label | payload | subpaths +#select +| unsafe_deserialization.py:15:18:15:24 | payload | unsafe_deserialization.py:8:26:8:32 | After ImportMember | unsafe_deserialization.py:15:18:15:24 | payload | Unsafe deserialization depends on a $@. | unsafe_deserialization.py:8:26:8:32 | After ImportMember | user-provided value | +| unsafe_deserialization.py:16:15:16:21 | payload | unsafe_deserialization.py:8:26:8:32 | After ImportMember | unsafe_deserialization.py:16:15:16:21 | payload | Unsafe deserialization depends on a $@. | unsafe_deserialization.py:8:26:8:32 | After ImportMember | user-provided value | +| unsafe_deserialization.py:18:19:18:25 | payload | unsafe_deserialization.py:8:26:8:32 | After ImportMember | unsafe_deserialization.py:18:19:18:25 | payload | Unsafe deserialization depends on a $@. | unsafe_deserialization.py:8:26:8:32 | After ImportMember | user-provided value | +| unsafe_deserialization.py:21:16:21:22 | payload | unsafe_deserialization.py:8:26:8:32 | After ImportMember | unsafe_deserialization.py:21:16:21:22 | payload | Unsafe deserialization depends on a $@. | unsafe_deserialization.py:8:26:8:32 | After ImportMember | user-provided value | +| unsafe_deserialization.py:24:24:24:30 | payload | unsafe_deserialization.py:8:26:8:32 | After ImportMember | unsafe_deserialization.py:24:24:24:30 | payload | Unsafe deserialization depends on a $@. | unsafe_deserialization.py:8:26:8:32 | After ImportMember | user-provided value | diff --git a/python/ql/test/query-tests/Security/CWE-601-UrlRedirect/UrlRedirect.expected b/python/ql/test/query-tests/Security/CWE-601-UrlRedirect/UrlRedirect.expected index 3e43c112e2a3..eaf7465d0de3 100644 --- a/python/ql/test/query-tests/Security/CWE-601-UrlRedirect/UrlRedirect.expected +++ b/python/ql/test/query-tests/Security/CWE-601-UrlRedirect/UrlRedirect.expected @@ -1,153 +1,153 @@ -#select -| test.py:8:21:8:26 | ControlFlowNode for target | test.py:1:26:1:32 | ControlFlowNode for ImportMember | test.py:8:21:8:26 | ControlFlowNode for target | Untrusted URL redirection depends on a $@. | test.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value | -| test.py:32:21:32:24 | ControlFlowNode for safe | test.py:1:26:1:32 | ControlFlowNode for ImportMember | test.py:32:21:32:24 | ControlFlowNode for safe | Untrusted URL redirection depends on a $@. | test.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value | -| test.py:39:21:39:24 | ControlFlowNode for safe | test.py:1:26:1:32 | ControlFlowNode for ImportMember | test.py:39:21:39:24 | ControlFlowNode for safe | Untrusted URL redirection depends on a $@. | test.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value | -| test.py:46:21:46:24 | ControlFlowNode for safe | test.py:1:26:1:32 | ControlFlowNode for ImportMember | test.py:46:21:46:24 | ControlFlowNode for safe | Untrusted URL redirection depends on a $@. | test.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value | -| test.py:62:21:62:26 | ControlFlowNode for unsafe | test.py:1:26:1:32 | ControlFlowNode for ImportMember | test.py:62:21:62:26 | ControlFlowNode for unsafe | Untrusted URL redirection depends on a $@. | test.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value | -| test.py:69:21:69:26 | ControlFlowNode for unsafe | test.py:1:26:1:32 | ControlFlowNode for ImportMember | test.py:69:21:69:26 | ControlFlowNode for unsafe | Untrusted URL redirection depends on a $@. | test.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value | -| test.py:76:21:76:26 | ControlFlowNode for unsafe | test.py:1:26:1:32 | ControlFlowNode for ImportMember | test.py:76:21:76:26 | ControlFlowNode for unsafe | Untrusted URL redirection depends on a $@. | test.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value | -| test.py:83:21:83:26 | ControlFlowNode for unsafe | test.py:1:26:1:32 | ControlFlowNode for ImportMember | test.py:83:21:83:26 | ControlFlowNode for unsafe | Untrusted URL redirection depends on a $@. | test.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value | -| test.py:93:18:93:26 | ControlFlowNode for untrusted | test.py:1:26:1:32 | ControlFlowNode for ImportMember | test.py:93:18:93:26 | ControlFlowNode for untrusted | Untrusted URL redirection depends on a $@. | test.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value | -| test.py:114:25:114:33 | ControlFlowNode for untrusted | test.py:1:26:1:32 | ControlFlowNode for ImportMember | test.py:114:25:114:33 | ControlFlowNode for untrusted | Untrusted URL redirection depends on a $@. | test.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value | -| test.py:140:25:140:33 | ControlFlowNode for untrusted | test.py:1:26:1:32 | ControlFlowNode for ImportMember | test.py:140:25:140:33 | ControlFlowNode for untrusted | Untrusted URL redirection depends on a $@. | test.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value | -| test.py:148:25:148:33 | ControlFlowNode for untrusted | test.py:1:26:1:32 | ControlFlowNode for ImportMember | test.py:148:25:148:33 | ControlFlowNode for untrusted | Untrusted URL redirection depends on a $@. | test.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value | edges -| test.py:1:26:1:32 | ControlFlowNode for ImportMember | test.py:1:26:1:32 | ControlFlowNode for request | provenance | | -| test.py:1:26:1:32 | ControlFlowNode for request | test.py:7:14:7:20 | ControlFlowNode for request | provenance | | -| test.py:1:26:1:32 | ControlFlowNode for request | test.py:30:17:30:23 | ControlFlowNode for request | provenance | | -| test.py:1:26:1:32 | ControlFlowNode for request | test.py:37:17:37:23 | ControlFlowNode for request | provenance | | -| test.py:1:26:1:32 | ControlFlowNode for request | test.py:44:17:44:23 | ControlFlowNode for request | provenance | | -| test.py:1:26:1:32 | ControlFlowNode for request | test.py:60:17:60:23 | ControlFlowNode for request | provenance | | -| test.py:1:26:1:32 | ControlFlowNode for request | test.py:67:17:67:23 | ControlFlowNode for request | provenance | | -| test.py:1:26:1:32 | ControlFlowNode for request | test.py:74:17:74:23 | ControlFlowNode for request | provenance | | -| test.py:1:26:1:32 | ControlFlowNode for request | test.py:81:17:81:23 | ControlFlowNode for request | provenance | | -| test.py:1:26:1:32 | ControlFlowNode for request | test.py:90:17:90:23 | ControlFlowNode for request | provenance | | -| test.py:1:26:1:32 | ControlFlowNode for request | test.py:111:17:111:23 | ControlFlowNode for request | provenance | | -| test.py:1:26:1:32 | ControlFlowNode for request | test.py:137:17:137:23 | ControlFlowNode for request | provenance | | -| test.py:1:26:1:32 | ControlFlowNode for request | test.py:145:17:145:23 | ControlFlowNode for request | provenance | | -| test.py:7:5:7:10 | ControlFlowNode for target | test.py:8:21:8:26 | ControlFlowNode for target | provenance | | -| test.py:7:14:7:20 | ControlFlowNode for request | test.py:7:14:7:25 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | -| test.py:7:14:7:25 | ControlFlowNode for Attribute | test.py:7:14:7:43 | ControlFlowNode for Attribute() | provenance | dict.get | -| test.py:7:14:7:43 | ControlFlowNode for Attribute() | test.py:7:5:7:10 | ControlFlowNode for target | provenance | | -| test.py:30:5:30:13 | ControlFlowNode for untrusted | test.py:31:5:31:8 | ControlFlowNode for safe | provenance | | -| test.py:30:17:30:23 | ControlFlowNode for request | test.py:30:17:30:28 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | -| test.py:30:17:30:28 | ControlFlowNode for Attribute | test.py:30:17:30:46 | ControlFlowNode for Attribute() | provenance | dict.get | -| test.py:30:17:30:46 | ControlFlowNode for Attribute() | test.py:30:5:30:13 | ControlFlowNode for untrusted | provenance | | -| test.py:31:5:31:8 | ControlFlowNode for safe | test.py:32:21:32:24 | ControlFlowNode for safe | provenance | | -| test.py:37:5:37:13 | ControlFlowNode for untrusted | test.py:38:5:38:8 | ControlFlowNode for safe | provenance | | -| test.py:37:17:37:23 | ControlFlowNode for request | test.py:37:17:37:28 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | -| test.py:37:17:37:28 | ControlFlowNode for Attribute | test.py:37:17:37:46 | ControlFlowNode for Attribute() | provenance | dict.get | -| test.py:37:17:37:46 | ControlFlowNode for Attribute() | test.py:37:5:37:13 | ControlFlowNode for untrusted | provenance | | -| test.py:38:5:38:8 | ControlFlowNode for safe | test.py:39:21:39:24 | ControlFlowNode for safe | provenance | | -| test.py:44:5:44:13 | ControlFlowNode for untrusted | test.py:45:5:45:8 | ControlFlowNode for safe | provenance | | -| test.py:44:17:44:23 | ControlFlowNode for request | test.py:44:17:44:28 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | -| test.py:44:17:44:28 | ControlFlowNode for Attribute | test.py:44:17:44:46 | ControlFlowNode for Attribute() | provenance | dict.get | -| test.py:44:17:44:46 | ControlFlowNode for Attribute() | test.py:44:5:44:13 | ControlFlowNode for untrusted | provenance | | -| test.py:45:5:45:8 | ControlFlowNode for safe | test.py:46:21:46:24 | ControlFlowNode for safe | provenance | | -| test.py:60:5:60:13 | ControlFlowNode for untrusted | test.py:61:5:61:10 | ControlFlowNode for unsafe | provenance | | -| test.py:60:17:60:23 | ControlFlowNode for request | test.py:60:17:60:28 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | -| test.py:60:17:60:28 | ControlFlowNode for Attribute | test.py:60:17:60:46 | ControlFlowNode for Attribute() | provenance | dict.get | -| test.py:60:17:60:46 | ControlFlowNode for Attribute() | test.py:60:5:60:13 | ControlFlowNode for untrusted | provenance | | -| test.py:61:5:61:10 | ControlFlowNode for unsafe | test.py:62:21:62:26 | ControlFlowNode for unsafe | provenance | | -| test.py:67:5:67:13 | ControlFlowNode for untrusted | test.py:68:5:68:10 | ControlFlowNode for unsafe | provenance | | -| test.py:67:17:67:23 | ControlFlowNode for request | test.py:67:17:67:28 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | -| test.py:67:17:67:28 | ControlFlowNode for Attribute | test.py:67:17:67:46 | ControlFlowNode for Attribute() | provenance | dict.get | -| test.py:67:17:67:46 | ControlFlowNode for Attribute() | test.py:67:5:67:13 | ControlFlowNode for untrusted | provenance | | -| test.py:68:5:68:10 | ControlFlowNode for unsafe | test.py:69:21:69:26 | ControlFlowNode for unsafe | provenance | | -| test.py:74:5:74:13 | ControlFlowNode for untrusted | test.py:75:5:75:10 | ControlFlowNode for unsafe | provenance | | -| test.py:74:17:74:23 | ControlFlowNode for request | test.py:74:17:74:28 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | -| test.py:74:17:74:28 | ControlFlowNode for Attribute | test.py:74:17:74:46 | ControlFlowNode for Attribute() | provenance | dict.get | -| test.py:74:17:74:46 | ControlFlowNode for Attribute() | test.py:74:5:74:13 | ControlFlowNode for untrusted | provenance | | -| test.py:75:5:75:10 | ControlFlowNode for unsafe | test.py:76:21:76:26 | ControlFlowNode for unsafe | provenance | | -| test.py:81:5:81:13 | ControlFlowNode for untrusted | test.py:82:5:82:10 | ControlFlowNode for unsafe | provenance | | -| test.py:81:17:81:23 | ControlFlowNode for request | test.py:81:17:81:28 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | -| test.py:81:17:81:28 | ControlFlowNode for Attribute | test.py:81:17:81:46 | ControlFlowNode for Attribute() | provenance | dict.get | -| test.py:81:17:81:46 | ControlFlowNode for Attribute() | test.py:81:5:81:13 | ControlFlowNode for untrusted | provenance | | -| test.py:82:5:82:10 | ControlFlowNode for unsafe | test.py:83:21:83:26 | ControlFlowNode for unsafe | provenance | | -| test.py:90:5:90:13 | ControlFlowNode for untrusted | test.py:93:18:93:26 | ControlFlowNode for untrusted | provenance | | -| test.py:90:17:90:23 | ControlFlowNode for request | test.py:90:17:90:28 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | -| test.py:90:17:90:28 | ControlFlowNode for Attribute | test.py:90:17:90:46 | ControlFlowNode for Attribute() | provenance | dict.get | -| test.py:90:17:90:46 | ControlFlowNode for Attribute() | test.py:90:5:90:13 | ControlFlowNode for untrusted | provenance | | -| test.py:111:5:111:13 | ControlFlowNode for untrusted | test.py:114:25:114:33 | ControlFlowNode for untrusted | provenance | | -| test.py:111:17:111:23 | ControlFlowNode for request | test.py:111:17:111:28 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | -| test.py:111:17:111:28 | ControlFlowNode for Attribute | test.py:111:17:111:46 | ControlFlowNode for Attribute() | provenance | dict.get | -| test.py:111:17:111:46 | ControlFlowNode for Attribute() | test.py:111:5:111:13 | ControlFlowNode for untrusted | provenance | | -| test.py:137:5:137:13 | ControlFlowNode for untrusted | test.py:140:25:140:33 | ControlFlowNode for untrusted | provenance | | -| test.py:137:17:137:23 | ControlFlowNode for request | test.py:137:17:137:28 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | -| test.py:137:17:137:28 | ControlFlowNode for Attribute | test.py:137:17:137:46 | ControlFlowNode for Attribute() | provenance | dict.get | -| test.py:137:17:137:46 | ControlFlowNode for Attribute() | test.py:137:5:137:13 | ControlFlowNode for untrusted | provenance | | -| test.py:145:5:145:13 | ControlFlowNode for untrusted | test.py:148:25:148:33 | ControlFlowNode for untrusted | provenance | | -| test.py:145:17:145:23 | ControlFlowNode for request | test.py:145:17:145:28 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | -| test.py:145:17:145:28 | ControlFlowNode for Attribute | test.py:145:17:145:46 | ControlFlowNode for Attribute() | provenance | dict.get | -| test.py:145:17:145:46 | ControlFlowNode for Attribute() | test.py:145:5:145:13 | ControlFlowNode for untrusted | provenance | | +| test.py:1:26:1:32 | After ImportMember | test.py:1:26:1:32 | request | provenance | | +| test.py:1:26:1:32 | request | test.py:7:14:7:20 | request | provenance | | +| test.py:1:26:1:32 | request | test.py:30:17:30:23 | request | provenance | | +| test.py:1:26:1:32 | request | test.py:37:17:37:23 | request | provenance | | +| test.py:1:26:1:32 | request | test.py:44:17:44:23 | request | provenance | | +| test.py:1:26:1:32 | request | test.py:60:17:60:23 | request | provenance | | +| test.py:1:26:1:32 | request | test.py:67:17:67:23 | request | provenance | | +| test.py:1:26:1:32 | request | test.py:74:17:74:23 | request | provenance | | +| test.py:1:26:1:32 | request | test.py:81:17:81:23 | request | provenance | | +| test.py:1:26:1:32 | request | test.py:90:17:90:23 | request | provenance | | +| test.py:1:26:1:32 | request | test.py:111:17:111:23 | request | provenance | | +| test.py:1:26:1:32 | request | test.py:137:17:137:23 | request | provenance | | +| test.py:1:26:1:32 | request | test.py:145:17:145:23 | request | provenance | | +| test.py:7:5:7:10 | target | test.py:8:21:8:26 | target | provenance | | +| test.py:7:14:7:20 | request | test.py:7:14:7:25 | After Attribute | provenance | AdditionalTaintStep | +| test.py:7:14:7:25 | After Attribute | test.py:7:14:7:43 | After Attribute() | provenance | dict.get | +| test.py:7:14:7:43 | After Attribute() | test.py:7:5:7:10 | target | provenance | | +| test.py:30:5:30:13 | untrusted | test.py:31:5:31:8 | safe | provenance | | +| test.py:30:17:30:23 | request | test.py:30:17:30:28 | After Attribute | provenance | AdditionalTaintStep | +| test.py:30:17:30:28 | After Attribute | test.py:30:17:30:46 | After Attribute() | provenance | dict.get | +| test.py:30:17:30:46 | After Attribute() | test.py:30:5:30:13 | untrusted | provenance | | +| test.py:31:5:31:8 | safe | test.py:32:21:32:24 | safe | provenance | | +| test.py:37:5:37:13 | untrusted | test.py:38:5:38:8 | safe | provenance | | +| test.py:37:17:37:23 | request | test.py:37:17:37:28 | After Attribute | provenance | AdditionalTaintStep | +| test.py:37:17:37:28 | After Attribute | test.py:37:17:37:46 | After Attribute() | provenance | dict.get | +| test.py:37:17:37:46 | After Attribute() | test.py:37:5:37:13 | untrusted | provenance | | +| test.py:38:5:38:8 | safe | test.py:39:21:39:24 | safe | provenance | | +| test.py:44:5:44:13 | untrusted | test.py:45:5:45:8 | safe | provenance | | +| test.py:44:17:44:23 | request | test.py:44:17:44:28 | After Attribute | provenance | AdditionalTaintStep | +| test.py:44:17:44:28 | After Attribute | test.py:44:17:44:46 | After Attribute() | provenance | dict.get | +| test.py:44:17:44:46 | After Attribute() | test.py:44:5:44:13 | untrusted | provenance | | +| test.py:45:5:45:8 | safe | test.py:46:21:46:24 | safe | provenance | | +| test.py:60:5:60:13 | untrusted | test.py:61:5:61:10 | unsafe | provenance | | +| test.py:60:17:60:23 | request | test.py:60:17:60:28 | After Attribute | provenance | AdditionalTaintStep | +| test.py:60:17:60:28 | After Attribute | test.py:60:17:60:46 | After Attribute() | provenance | dict.get | +| test.py:60:17:60:46 | After Attribute() | test.py:60:5:60:13 | untrusted | provenance | | +| test.py:61:5:61:10 | unsafe | test.py:62:21:62:26 | unsafe | provenance | | +| test.py:67:5:67:13 | untrusted | test.py:68:5:68:10 | unsafe | provenance | | +| test.py:67:17:67:23 | request | test.py:67:17:67:28 | After Attribute | provenance | AdditionalTaintStep | +| test.py:67:17:67:28 | After Attribute | test.py:67:17:67:46 | After Attribute() | provenance | dict.get | +| test.py:67:17:67:46 | After Attribute() | test.py:67:5:67:13 | untrusted | provenance | | +| test.py:68:5:68:10 | unsafe | test.py:69:21:69:26 | unsafe | provenance | | +| test.py:74:5:74:13 | untrusted | test.py:75:5:75:10 | unsafe | provenance | | +| test.py:74:17:74:23 | request | test.py:74:17:74:28 | After Attribute | provenance | AdditionalTaintStep | +| test.py:74:17:74:28 | After Attribute | test.py:74:17:74:46 | After Attribute() | provenance | dict.get | +| test.py:74:17:74:46 | After Attribute() | test.py:74:5:74:13 | untrusted | provenance | | +| test.py:75:5:75:10 | unsafe | test.py:76:21:76:26 | unsafe | provenance | | +| test.py:81:5:81:13 | untrusted | test.py:82:5:82:10 | unsafe | provenance | | +| test.py:81:17:81:23 | request | test.py:81:17:81:28 | After Attribute | provenance | AdditionalTaintStep | +| test.py:81:17:81:28 | After Attribute | test.py:81:17:81:46 | After Attribute() | provenance | dict.get | +| test.py:81:17:81:46 | After Attribute() | test.py:81:5:81:13 | untrusted | provenance | | +| test.py:82:5:82:10 | unsafe | test.py:83:21:83:26 | unsafe | provenance | | +| test.py:90:5:90:13 | untrusted | test.py:93:18:93:26 | untrusted | provenance | | +| test.py:90:17:90:23 | request | test.py:90:17:90:28 | After Attribute | provenance | AdditionalTaintStep | +| test.py:90:17:90:28 | After Attribute | test.py:90:17:90:46 | After Attribute() | provenance | dict.get | +| test.py:90:17:90:46 | After Attribute() | test.py:90:5:90:13 | untrusted | provenance | | +| test.py:111:5:111:13 | untrusted | test.py:114:25:114:33 | untrusted | provenance | | +| test.py:111:17:111:23 | request | test.py:111:17:111:28 | After Attribute | provenance | AdditionalTaintStep | +| test.py:111:17:111:28 | After Attribute | test.py:111:17:111:46 | After Attribute() | provenance | dict.get | +| test.py:111:17:111:46 | After Attribute() | test.py:111:5:111:13 | untrusted | provenance | | +| test.py:137:5:137:13 | untrusted | test.py:140:25:140:33 | untrusted | provenance | | +| test.py:137:17:137:23 | request | test.py:137:17:137:28 | After Attribute | provenance | AdditionalTaintStep | +| test.py:137:17:137:28 | After Attribute | test.py:137:17:137:46 | After Attribute() | provenance | dict.get | +| test.py:137:17:137:46 | After Attribute() | test.py:137:5:137:13 | untrusted | provenance | | +| test.py:145:5:145:13 | untrusted | test.py:148:25:148:33 | untrusted | provenance | | +| test.py:145:17:145:23 | request | test.py:145:17:145:28 | After Attribute | provenance | AdditionalTaintStep | +| test.py:145:17:145:28 | After Attribute | test.py:145:17:145:46 | After Attribute() | provenance | dict.get | +| test.py:145:17:145:46 | After Attribute() | test.py:145:5:145:13 | untrusted | provenance | | nodes -| test.py:1:26:1:32 | ControlFlowNode for ImportMember | semmle.label | ControlFlowNode for ImportMember | -| test.py:1:26:1:32 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| test.py:7:5:7:10 | ControlFlowNode for target | semmle.label | ControlFlowNode for target | -| test.py:7:14:7:20 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| test.py:7:14:7:25 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| test.py:7:14:7:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| test.py:8:21:8:26 | ControlFlowNode for target | semmle.label | ControlFlowNode for target | -| test.py:30:5:30:13 | ControlFlowNode for untrusted | semmle.label | ControlFlowNode for untrusted | -| test.py:30:17:30:23 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| test.py:30:17:30:28 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| test.py:30:17:30:46 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| test.py:31:5:31:8 | ControlFlowNode for safe | semmle.label | ControlFlowNode for safe | -| test.py:32:21:32:24 | ControlFlowNode for safe | semmle.label | ControlFlowNode for safe | -| test.py:37:5:37:13 | ControlFlowNode for untrusted | semmle.label | ControlFlowNode for untrusted | -| test.py:37:17:37:23 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| test.py:37:17:37:28 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| test.py:37:17:37:46 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| test.py:38:5:38:8 | ControlFlowNode for safe | semmle.label | ControlFlowNode for safe | -| test.py:39:21:39:24 | ControlFlowNode for safe | semmle.label | ControlFlowNode for safe | -| test.py:44:5:44:13 | ControlFlowNode for untrusted | semmle.label | ControlFlowNode for untrusted | -| test.py:44:17:44:23 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| test.py:44:17:44:28 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| test.py:44:17:44:46 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| test.py:45:5:45:8 | ControlFlowNode for safe | semmle.label | ControlFlowNode for safe | -| test.py:46:21:46:24 | ControlFlowNode for safe | semmle.label | ControlFlowNode for safe | -| test.py:60:5:60:13 | ControlFlowNode for untrusted | semmle.label | ControlFlowNode for untrusted | -| test.py:60:17:60:23 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| test.py:60:17:60:28 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| test.py:60:17:60:46 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| test.py:61:5:61:10 | ControlFlowNode for unsafe | semmle.label | ControlFlowNode for unsafe | -| test.py:62:21:62:26 | ControlFlowNode for unsafe | semmle.label | ControlFlowNode for unsafe | -| test.py:67:5:67:13 | ControlFlowNode for untrusted | semmle.label | ControlFlowNode for untrusted | -| test.py:67:17:67:23 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| test.py:67:17:67:28 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| test.py:67:17:67:46 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| test.py:68:5:68:10 | ControlFlowNode for unsafe | semmle.label | ControlFlowNode for unsafe | -| test.py:69:21:69:26 | ControlFlowNode for unsafe | semmle.label | ControlFlowNode for unsafe | -| test.py:74:5:74:13 | ControlFlowNode for untrusted | semmle.label | ControlFlowNode for untrusted | -| test.py:74:17:74:23 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| test.py:74:17:74:28 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| test.py:74:17:74:46 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| test.py:75:5:75:10 | ControlFlowNode for unsafe | semmle.label | ControlFlowNode for unsafe | -| test.py:76:21:76:26 | ControlFlowNode for unsafe | semmle.label | ControlFlowNode for unsafe | -| test.py:81:5:81:13 | ControlFlowNode for untrusted | semmle.label | ControlFlowNode for untrusted | -| test.py:81:17:81:23 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| test.py:81:17:81:28 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| test.py:81:17:81:46 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| test.py:82:5:82:10 | ControlFlowNode for unsafe | semmle.label | ControlFlowNode for unsafe | -| test.py:83:21:83:26 | ControlFlowNode for unsafe | semmle.label | ControlFlowNode for unsafe | -| test.py:90:5:90:13 | ControlFlowNode for untrusted | semmle.label | ControlFlowNode for untrusted | -| test.py:90:17:90:23 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| test.py:90:17:90:28 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| test.py:90:17:90:46 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| test.py:93:18:93:26 | ControlFlowNode for untrusted | semmle.label | ControlFlowNode for untrusted | -| test.py:111:5:111:13 | ControlFlowNode for untrusted | semmle.label | ControlFlowNode for untrusted | -| test.py:111:17:111:23 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| test.py:111:17:111:28 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| test.py:111:17:111:46 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| test.py:114:25:114:33 | ControlFlowNode for untrusted | semmle.label | ControlFlowNode for untrusted | -| test.py:137:5:137:13 | ControlFlowNode for untrusted | semmle.label | ControlFlowNode for untrusted | -| test.py:137:17:137:23 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| test.py:137:17:137:28 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| test.py:137:17:137:46 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| test.py:140:25:140:33 | ControlFlowNode for untrusted | semmle.label | ControlFlowNode for untrusted | -| test.py:145:5:145:13 | ControlFlowNode for untrusted | semmle.label | ControlFlowNode for untrusted | -| test.py:145:17:145:23 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| test.py:145:17:145:28 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| test.py:145:17:145:46 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| test.py:148:25:148:33 | ControlFlowNode for untrusted | semmle.label | ControlFlowNode for untrusted | +| test.py:1:26:1:32 | After ImportMember | semmle.label | After ImportMember | +| test.py:1:26:1:32 | request | semmle.label | request | +| test.py:7:5:7:10 | target | semmle.label | target | +| test.py:7:14:7:20 | request | semmle.label | request | +| test.py:7:14:7:25 | After Attribute | semmle.label | After Attribute | +| test.py:7:14:7:43 | After Attribute() | semmle.label | After Attribute() | +| test.py:8:21:8:26 | target | semmle.label | target | +| test.py:30:5:30:13 | untrusted | semmle.label | untrusted | +| test.py:30:17:30:23 | request | semmle.label | request | +| test.py:30:17:30:28 | After Attribute | semmle.label | After Attribute | +| test.py:30:17:30:46 | After Attribute() | semmle.label | After Attribute() | +| test.py:31:5:31:8 | safe | semmle.label | safe | +| test.py:32:21:32:24 | safe | semmle.label | safe | +| test.py:37:5:37:13 | untrusted | semmle.label | untrusted | +| test.py:37:17:37:23 | request | semmle.label | request | +| test.py:37:17:37:28 | After Attribute | semmle.label | After Attribute | +| test.py:37:17:37:46 | After Attribute() | semmle.label | After Attribute() | +| test.py:38:5:38:8 | safe | semmle.label | safe | +| test.py:39:21:39:24 | safe | semmle.label | safe | +| test.py:44:5:44:13 | untrusted | semmle.label | untrusted | +| test.py:44:17:44:23 | request | semmle.label | request | +| test.py:44:17:44:28 | After Attribute | semmle.label | After Attribute | +| test.py:44:17:44:46 | After Attribute() | semmle.label | After Attribute() | +| test.py:45:5:45:8 | safe | semmle.label | safe | +| test.py:46:21:46:24 | safe | semmle.label | safe | +| test.py:60:5:60:13 | untrusted | semmle.label | untrusted | +| test.py:60:17:60:23 | request | semmle.label | request | +| test.py:60:17:60:28 | After Attribute | semmle.label | After Attribute | +| test.py:60:17:60:46 | After Attribute() | semmle.label | After Attribute() | +| test.py:61:5:61:10 | unsafe | semmle.label | unsafe | +| test.py:62:21:62:26 | unsafe | semmle.label | unsafe | +| test.py:67:5:67:13 | untrusted | semmle.label | untrusted | +| test.py:67:17:67:23 | request | semmle.label | request | +| test.py:67:17:67:28 | After Attribute | semmle.label | After Attribute | +| test.py:67:17:67:46 | After Attribute() | semmle.label | After Attribute() | +| test.py:68:5:68:10 | unsafe | semmle.label | unsafe | +| test.py:69:21:69:26 | unsafe | semmle.label | unsafe | +| test.py:74:5:74:13 | untrusted | semmle.label | untrusted | +| test.py:74:17:74:23 | request | semmle.label | request | +| test.py:74:17:74:28 | After Attribute | semmle.label | After Attribute | +| test.py:74:17:74:46 | After Attribute() | semmle.label | After Attribute() | +| test.py:75:5:75:10 | unsafe | semmle.label | unsafe | +| test.py:76:21:76:26 | unsafe | semmle.label | unsafe | +| test.py:81:5:81:13 | untrusted | semmle.label | untrusted | +| test.py:81:17:81:23 | request | semmle.label | request | +| test.py:81:17:81:28 | After Attribute | semmle.label | After Attribute | +| test.py:81:17:81:46 | After Attribute() | semmle.label | After Attribute() | +| test.py:82:5:82:10 | unsafe | semmle.label | unsafe | +| test.py:83:21:83:26 | unsafe | semmle.label | unsafe | +| test.py:90:5:90:13 | untrusted | semmle.label | untrusted | +| test.py:90:17:90:23 | request | semmle.label | request | +| test.py:90:17:90:28 | After Attribute | semmle.label | After Attribute | +| test.py:90:17:90:46 | After Attribute() | semmle.label | After Attribute() | +| test.py:93:18:93:26 | untrusted | semmle.label | untrusted | +| test.py:111:5:111:13 | untrusted | semmle.label | untrusted | +| test.py:111:17:111:23 | request | semmle.label | request | +| test.py:111:17:111:28 | After Attribute | semmle.label | After Attribute | +| test.py:111:17:111:46 | After Attribute() | semmle.label | After Attribute() | +| test.py:114:25:114:33 | untrusted | semmle.label | untrusted | +| test.py:137:5:137:13 | untrusted | semmle.label | untrusted | +| test.py:137:17:137:23 | request | semmle.label | request | +| test.py:137:17:137:28 | After Attribute | semmle.label | After Attribute | +| test.py:137:17:137:46 | After Attribute() | semmle.label | After Attribute() | +| test.py:140:25:140:33 | untrusted | semmle.label | untrusted | +| test.py:145:5:145:13 | untrusted | semmle.label | untrusted | +| test.py:145:17:145:23 | request | semmle.label | request | +| test.py:145:17:145:28 | After Attribute | semmle.label | After Attribute | +| test.py:145:17:145:46 | After Attribute() | semmle.label | After Attribute() | +| test.py:148:25:148:33 | untrusted | semmle.label | untrusted | subpaths +#select +| test.py:8:21:8:26 | target | test.py:1:26:1:32 | After ImportMember | test.py:8:21:8:26 | target | Untrusted URL redirection depends on a $@. | test.py:1:26:1:32 | After ImportMember | user-provided value | +| test.py:32:21:32:24 | safe | test.py:1:26:1:32 | After ImportMember | test.py:32:21:32:24 | safe | Untrusted URL redirection depends on a $@. | test.py:1:26:1:32 | After ImportMember | user-provided value | +| test.py:39:21:39:24 | safe | test.py:1:26:1:32 | After ImportMember | test.py:39:21:39:24 | safe | Untrusted URL redirection depends on a $@. | test.py:1:26:1:32 | After ImportMember | user-provided value | +| test.py:46:21:46:24 | safe | test.py:1:26:1:32 | After ImportMember | test.py:46:21:46:24 | safe | Untrusted URL redirection depends on a $@. | test.py:1:26:1:32 | After ImportMember | user-provided value | +| test.py:62:21:62:26 | unsafe | test.py:1:26:1:32 | After ImportMember | test.py:62:21:62:26 | unsafe | Untrusted URL redirection depends on a $@. | test.py:1:26:1:32 | After ImportMember | user-provided value | +| test.py:69:21:69:26 | unsafe | test.py:1:26:1:32 | After ImportMember | test.py:69:21:69:26 | unsafe | Untrusted URL redirection depends on a $@. | test.py:1:26:1:32 | After ImportMember | user-provided value | +| test.py:76:21:76:26 | unsafe | test.py:1:26:1:32 | After ImportMember | test.py:76:21:76:26 | unsafe | Untrusted URL redirection depends on a $@. | test.py:1:26:1:32 | After ImportMember | user-provided value | +| test.py:83:21:83:26 | unsafe | test.py:1:26:1:32 | After ImportMember | test.py:83:21:83:26 | unsafe | Untrusted URL redirection depends on a $@. | test.py:1:26:1:32 | After ImportMember | user-provided value | +| test.py:93:18:93:26 | untrusted | test.py:1:26:1:32 | After ImportMember | test.py:93:18:93:26 | untrusted | Untrusted URL redirection depends on a $@. | test.py:1:26:1:32 | After ImportMember | user-provided value | +| test.py:114:25:114:33 | untrusted | test.py:1:26:1:32 | After ImportMember | test.py:114:25:114:33 | untrusted | Untrusted URL redirection depends on a $@. | test.py:1:26:1:32 | After ImportMember | user-provided value | +| test.py:140:25:140:33 | untrusted | test.py:1:26:1:32 | After ImportMember | test.py:140:25:140:33 | untrusted | Untrusted URL redirection depends on a $@. | test.py:1:26:1:32 | After ImportMember | user-provided value | +| test.py:148:25:148:33 | untrusted | test.py:1:26:1:32 | After ImportMember | test.py:148:25:148:33 | untrusted | Untrusted URL redirection depends on a $@. | test.py:1:26:1:32 | After ImportMember | user-provided value | diff --git a/python/ql/test/query-tests/Security/CWE-611-Xxe/Xxe.expected b/python/ql/test/query-tests/Security/CWE-611-Xxe/Xxe.expected index b33d39f50718..ef545683e239 100644 --- a/python/ql/test/query-tests/Security/CWE-611-Xxe/Xxe.expected +++ b/python/ql/test/query-tests/Security/CWE-611-Xxe/Xxe.expected @@ -1,21 +1,21 @@ edges -| test.py:1:26:1:32 | ControlFlowNode for ImportMember | test.py:1:26:1:32 | ControlFlowNode for request | provenance | | -| test.py:1:26:1:32 | ControlFlowNode for request | test.py:9:19:9:25 | ControlFlowNode for request | provenance | | -| test.py:1:26:1:32 | ControlFlowNode for request | test.py:20:19:20:25 | ControlFlowNode for request | provenance | | -| test.py:9:5:9:15 | ControlFlowNode for xml_content | test.py:10:34:10:44 | ControlFlowNode for xml_content | provenance | | -| test.py:9:19:9:25 | ControlFlowNode for request | test.py:9:5:9:15 | ControlFlowNode for xml_content | provenance | AdditionalTaintStep | -| test.py:20:5:20:15 | ControlFlowNode for xml_content | test.py:31:34:31:44 | ControlFlowNode for xml_content | provenance | | -| test.py:20:19:20:25 | ControlFlowNode for request | test.py:20:5:20:15 | ControlFlowNode for xml_content | provenance | AdditionalTaintStep | +| test.py:1:26:1:32 | After ImportMember | test.py:1:26:1:32 | request | provenance | | +| test.py:1:26:1:32 | request | test.py:9:19:9:25 | request | provenance | | +| test.py:1:26:1:32 | request | test.py:20:19:20:25 | request | provenance | | +| test.py:9:5:9:15 | xml_content | test.py:10:34:10:44 | xml_content | provenance | | +| test.py:9:19:9:25 | request | test.py:9:5:9:15 | xml_content | provenance | AdditionalTaintStep | +| test.py:20:5:20:15 | xml_content | test.py:31:34:31:44 | xml_content | provenance | | +| test.py:20:19:20:25 | request | test.py:20:5:20:15 | xml_content | provenance | AdditionalTaintStep | nodes -| test.py:1:26:1:32 | ControlFlowNode for ImportMember | semmle.label | ControlFlowNode for ImportMember | -| test.py:1:26:1:32 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| test.py:9:5:9:15 | ControlFlowNode for xml_content | semmle.label | ControlFlowNode for xml_content | -| test.py:9:19:9:25 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| test.py:10:34:10:44 | ControlFlowNode for xml_content | semmle.label | ControlFlowNode for xml_content | -| test.py:20:5:20:15 | ControlFlowNode for xml_content | semmle.label | ControlFlowNode for xml_content | -| test.py:20:19:20:25 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| test.py:31:34:31:44 | ControlFlowNode for xml_content | semmle.label | ControlFlowNode for xml_content | +| test.py:1:26:1:32 | After ImportMember | semmle.label | After ImportMember | +| test.py:1:26:1:32 | request | semmle.label | request | +| test.py:9:5:9:15 | xml_content | semmle.label | xml_content | +| test.py:9:19:9:25 | request | semmle.label | request | +| test.py:10:34:10:44 | xml_content | semmle.label | xml_content | +| test.py:20:5:20:15 | xml_content | semmle.label | xml_content | +| test.py:20:19:20:25 | request | semmle.label | request | +| test.py:31:34:31:44 | xml_content | semmle.label | xml_content | subpaths #select -| test.py:10:34:10:44 | ControlFlowNode for xml_content | test.py:1:26:1:32 | ControlFlowNode for ImportMember | test.py:10:34:10:44 | ControlFlowNode for xml_content | XML parsing depends on a $@ without guarding against external entity expansion. | test.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value | -| test.py:31:34:31:44 | ControlFlowNode for xml_content | test.py:1:26:1:32 | ControlFlowNode for ImportMember | test.py:31:34:31:44 | ControlFlowNode for xml_content | XML parsing depends on a $@ without guarding against external entity expansion. | test.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value | +| test.py:10:34:10:44 | xml_content | test.py:1:26:1:32 | After ImportMember | test.py:10:34:10:44 | xml_content | XML parsing depends on a $@ without guarding against external entity expansion. | test.py:1:26:1:32 | After ImportMember | user-provided value | +| test.py:31:34:31:44 | xml_content | test.py:1:26:1:32 | After ImportMember | test.py:31:34:31:44 | xml_content | XML parsing depends on a $@ without guarding against external entity expansion. | test.py:1:26:1:32 | After ImportMember | user-provided value | diff --git a/python/ql/test/query-tests/Security/CWE-614-InsecureCookie/InsecureCookie.expected b/python/ql/test/query-tests/Security/CWE-614-InsecureCookie/InsecureCookie.expected index 3b07bc6d9ebb..d6701c0e5548 100644 --- a/python/ql/test/query-tests/Security/CWE-614-InsecureCookie/InsecureCookie.expected +++ b/python/ql/test/query-tests/Security/CWE-614-InsecureCookie/InsecureCookie.expected @@ -1,3 +1,3 @@ -| test.py:8:5:8:40 | ControlFlowNode for Attribute() | Cookie is added to response without the 'secure' flag being set. | -| test.py:10:5:10:57 | ControlFlowNode for Attribute() | Cookie is added to response without the 'secure' flag being set. | -| test.py:11:5:11:60 | ControlFlowNode for Attribute() | Cookie is added to response without the 'secure' flag being set. | +| test.py:8:5:8:40 | After Attribute() | Cookie is added to response without the 'secure' flag being set. | +| test.py:10:5:10:57 | After Attribute() | Cookie is added to response without the 'secure' flag being set. | +| test.py:11:5:11:60 | After Attribute() | Cookie is added to response without the 'secure' flag being set. | diff --git a/python/ql/test/query-tests/Security/CWE-643-XPathInjection/XpathInjection.expected b/python/ql/test/query-tests/Security/CWE-643-XPathInjection/XpathInjection.expected index 4b1a2c40f7cf..b84dc762fcd1 100644 --- a/python/ql/test/query-tests/Security/CWE-643-XPathInjection/XpathInjection.expected +++ b/python/ql/test/query-tests/Security/CWE-643-XPathInjection/XpathInjection.expected @@ -1,68 +1,68 @@ edges -| xpathBad.py:9:7:9:13 | ControlFlowNode for request | xpathBad.py:10:5:10:9 | ControlFlowNode for value | provenance | AdditionalTaintStep | -| xpathBad.py:10:5:10:9 | ControlFlowNode for value | xpathBad.py:13:20:13:43 | ControlFlowNode for BinaryExpr | provenance | | -| xpathFlow.py:2:26:2:32 | ControlFlowNode for ImportMember | xpathFlow.py:2:26:2:32 | ControlFlowNode for request | provenance | | -| xpathFlow.py:2:26:2:32 | ControlFlowNode for request | xpathFlow.py:11:18:11:24 | ControlFlowNode for request | provenance | | -| xpathFlow.py:2:26:2:32 | ControlFlowNode for request | xpathFlow.py:20:18:20:24 | ControlFlowNode for request | provenance | | -| xpathFlow.py:2:26:2:32 | ControlFlowNode for request | xpathFlow.py:30:18:30:24 | ControlFlowNode for request | provenance | | -| xpathFlow.py:2:26:2:32 | ControlFlowNode for request | xpathFlow.py:39:18:39:24 | ControlFlowNode for request | provenance | | -| xpathFlow.py:2:26:2:32 | ControlFlowNode for request | xpathFlow.py:47:18:47:24 | ControlFlowNode for request | provenance | | -| xpathFlow.py:11:5:11:14 | ControlFlowNode for xpathQuery | xpathFlow.py:14:20:14:29 | ControlFlowNode for xpathQuery | provenance | | -| xpathFlow.py:11:18:11:24 | ControlFlowNode for request | xpathFlow.py:11:18:11:29 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | -| xpathFlow.py:11:18:11:29 | ControlFlowNode for Attribute | xpathFlow.py:11:18:11:44 | ControlFlowNode for Attribute() | provenance | dict.get | -| xpathFlow.py:11:18:11:44 | ControlFlowNode for Attribute() | xpathFlow.py:11:5:11:14 | ControlFlowNode for xpathQuery | provenance | | -| xpathFlow.py:20:5:20:14 | ControlFlowNode for xpathQuery | xpathFlow.py:23:29:23:38 | ControlFlowNode for xpathQuery | provenance | | -| xpathFlow.py:20:18:20:24 | ControlFlowNode for request | xpathFlow.py:20:18:20:29 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | -| xpathFlow.py:20:18:20:29 | ControlFlowNode for Attribute | xpathFlow.py:20:18:20:44 | ControlFlowNode for Attribute() | provenance | dict.get | -| xpathFlow.py:20:18:20:44 | ControlFlowNode for Attribute() | xpathFlow.py:20:5:20:14 | ControlFlowNode for xpathQuery | provenance | | -| xpathFlow.py:30:5:30:14 | ControlFlowNode for xpathQuery | xpathFlow.py:32:29:32:38 | ControlFlowNode for xpathQuery | provenance | | -| xpathFlow.py:30:18:30:24 | ControlFlowNode for request | xpathFlow.py:30:18:30:29 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | -| xpathFlow.py:30:18:30:29 | ControlFlowNode for Attribute | xpathFlow.py:30:18:30:44 | ControlFlowNode for Attribute() | provenance | dict.get | -| xpathFlow.py:30:18:30:44 | ControlFlowNode for Attribute() | xpathFlow.py:30:5:30:14 | ControlFlowNode for xpathQuery | provenance | | -| xpathFlow.py:39:5:39:14 | ControlFlowNode for xpathQuery | xpathFlow.py:41:31:41:40 | ControlFlowNode for xpathQuery | provenance | | -| xpathFlow.py:39:18:39:24 | ControlFlowNode for request | xpathFlow.py:39:18:39:29 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | -| xpathFlow.py:39:18:39:29 | ControlFlowNode for Attribute | xpathFlow.py:39:18:39:44 | ControlFlowNode for Attribute() | provenance | dict.get | -| xpathFlow.py:39:18:39:44 | ControlFlowNode for Attribute() | xpathFlow.py:39:5:39:14 | ControlFlowNode for xpathQuery | provenance | | -| xpathFlow.py:47:5:47:14 | ControlFlowNode for xpathQuery | xpathFlow.py:49:29:49:38 | ControlFlowNode for xpathQuery | provenance | | -| xpathFlow.py:47:18:47:24 | ControlFlowNode for request | xpathFlow.py:47:18:47:29 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | -| xpathFlow.py:47:18:47:29 | ControlFlowNode for Attribute | xpathFlow.py:47:18:47:44 | ControlFlowNode for Attribute() | provenance | dict.get | -| xpathFlow.py:47:18:47:44 | ControlFlowNode for Attribute() | xpathFlow.py:47:5:47:14 | ControlFlowNode for xpathQuery | provenance | | +| xpathBad.py:9:7:9:13 | request | xpathBad.py:10:5:10:9 | value | provenance | AdditionalTaintStep | +| xpathBad.py:10:5:10:9 | value | xpathBad.py:13:20:13:43 | After BinaryExpr | provenance | | +| xpathFlow.py:2:26:2:32 | After ImportMember | xpathFlow.py:2:26:2:32 | request | provenance | | +| xpathFlow.py:2:26:2:32 | request | xpathFlow.py:11:18:11:24 | request | provenance | | +| xpathFlow.py:2:26:2:32 | request | xpathFlow.py:20:18:20:24 | request | provenance | | +| xpathFlow.py:2:26:2:32 | request | xpathFlow.py:30:18:30:24 | request | provenance | | +| xpathFlow.py:2:26:2:32 | request | xpathFlow.py:39:18:39:24 | request | provenance | | +| xpathFlow.py:2:26:2:32 | request | xpathFlow.py:47:18:47:24 | request | provenance | | +| xpathFlow.py:11:5:11:14 | xpathQuery | xpathFlow.py:14:20:14:29 | xpathQuery | provenance | | +| xpathFlow.py:11:18:11:24 | request | xpathFlow.py:11:18:11:29 | After Attribute | provenance | AdditionalTaintStep | +| xpathFlow.py:11:18:11:29 | After Attribute | xpathFlow.py:11:18:11:44 | After Attribute() | provenance | dict.get | +| xpathFlow.py:11:18:11:44 | After Attribute() | xpathFlow.py:11:5:11:14 | xpathQuery | provenance | | +| xpathFlow.py:20:5:20:14 | xpathQuery | xpathFlow.py:23:29:23:38 | xpathQuery | provenance | | +| xpathFlow.py:20:18:20:24 | request | xpathFlow.py:20:18:20:29 | After Attribute | provenance | AdditionalTaintStep | +| xpathFlow.py:20:18:20:29 | After Attribute | xpathFlow.py:20:18:20:44 | After Attribute() | provenance | dict.get | +| xpathFlow.py:20:18:20:44 | After Attribute() | xpathFlow.py:20:5:20:14 | xpathQuery | provenance | | +| xpathFlow.py:30:5:30:14 | xpathQuery | xpathFlow.py:32:29:32:38 | xpathQuery | provenance | | +| xpathFlow.py:30:18:30:24 | request | xpathFlow.py:30:18:30:29 | After Attribute | provenance | AdditionalTaintStep | +| xpathFlow.py:30:18:30:29 | After Attribute | xpathFlow.py:30:18:30:44 | After Attribute() | provenance | dict.get | +| xpathFlow.py:30:18:30:44 | After Attribute() | xpathFlow.py:30:5:30:14 | xpathQuery | provenance | | +| xpathFlow.py:39:5:39:14 | xpathQuery | xpathFlow.py:41:31:41:40 | xpathQuery | provenance | | +| xpathFlow.py:39:18:39:24 | request | xpathFlow.py:39:18:39:29 | After Attribute | provenance | AdditionalTaintStep | +| xpathFlow.py:39:18:39:29 | After Attribute | xpathFlow.py:39:18:39:44 | After Attribute() | provenance | dict.get | +| xpathFlow.py:39:18:39:44 | After Attribute() | xpathFlow.py:39:5:39:14 | xpathQuery | provenance | | +| xpathFlow.py:47:5:47:14 | xpathQuery | xpathFlow.py:49:29:49:38 | xpathQuery | provenance | | +| xpathFlow.py:47:18:47:24 | request | xpathFlow.py:47:18:47:29 | After Attribute | provenance | AdditionalTaintStep | +| xpathFlow.py:47:18:47:29 | After Attribute | xpathFlow.py:47:18:47:44 | After Attribute() | provenance | dict.get | +| xpathFlow.py:47:18:47:44 | After Attribute() | xpathFlow.py:47:5:47:14 | xpathQuery | provenance | | nodes -| xpathBad.py:9:7:9:13 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| xpathBad.py:10:5:10:9 | ControlFlowNode for value | semmle.label | ControlFlowNode for value | -| xpathBad.py:13:20:13:43 | ControlFlowNode for BinaryExpr | semmle.label | ControlFlowNode for BinaryExpr | -| xpathFlow.py:2:26:2:32 | ControlFlowNode for ImportMember | semmle.label | ControlFlowNode for ImportMember | -| xpathFlow.py:2:26:2:32 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| xpathFlow.py:11:5:11:14 | ControlFlowNode for xpathQuery | semmle.label | ControlFlowNode for xpathQuery | -| xpathFlow.py:11:18:11:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| xpathFlow.py:11:18:11:29 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| xpathFlow.py:11:18:11:44 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| xpathFlow.py:14:20:14:29 | ControlFlowNode for xpathQuery | semmle.label | ControlFlowNode for xpathQuery | -| xpathFlow.py:20:5:20:14 | ControlFlowNode for xpathQuery | semmle.label | ControlFlowNode for xpathQuery | -| xpathFlow.py:20:18:20:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| xpathFlow.py:20:18:20:29 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| xpathFlow.py:20:18:20:44 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| xpathFlow.py:23:29:23:38 | ControlFlowNode for xpathQuery | semmle.label | ControlFlowNode for xpathQuery | -| xpathFlow.py:30:5:30:14 | ControlFlowNode for xpathQuery | semmle.label | ControlFlowNode for xpathQuery | -| xpathFlow.py:30:18:30:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| xpathFlow.py:30:18:30:29 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| xpathFlow.py:30:18:30:44 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| xpathFlow.py:32:29:32:38 | ControlFlowNode for xpathQuery | semmle.label | ControlFlowNode for xpathQuery | -| xpathFlow.py:39:5:39:14 | ControlFlowNode for xpathQuery | semmle.label | ControlFlowNode for xpathQuery | -| xpathFlow.py:39:18:39:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| xpathFlow.py:39:18:39:29 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| xpathFlow.py:39:18:39:44 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| xpathFlow.py:41:31:41:40 | ControlFlowNode for xpathQuery | semmle.label | ControlFlowNode for xpathQuery | -| xpathFlow.py:47:5:47:14 | ControlFlowNode for xpathQuery | semmle.label | ControlFlowNode for xpathQuery | -| xpathFlow.py:47:18:47:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| xpathFlow.py:47:18:47:29 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| xpathFlow.py:47:18:47:44 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| xpathFlow.py:49:29:49:38 | ControlFlowNode for xpathQuery | semmle.label | ControlFlowNode for xpathQuery | +| xpathBad.py:9:7:9:13 | request | semmle.label | request | +| xpathBad.py:10:5:10:9 | value | semmle.label | value | +| xpathBad.py:13:20:13:43 | After BinaryExpr | semmle.label | After BinaryExpr | +| xpathFlow.py:2:26:2:32 | After ImportMember | semmle.label | After ImportMember | +| xpathFlow.py:2:26:2:32 | request | semmle.label | request | +| xpathFlow.py:11:5:11:14 | xpathQuery | semmle.label | xpathQuery | +| xpathFlow.py:11:18:11:24 | request | semmle.label | request | +| xpathFlow.py:11:18:11:29 | After Attribute | semmle.label | After Attribute | +| xpathFlow.py:11:18:11:44 | After Attribute() | semmle.label | After Attribute() | +| xpathFlow.py:14:20:14:29 | xpathQuery | semmle.label | xpathQuery | +| xpathFlow.py:20:5:20:14 | xpathQuery | semmle.label | xpathQuery | +| xpathFlow.py:20:18:20:24 | request | semmle.label | request | +| xpathFlow.py:20:18:20:29 | After Attribute | semmle.label | After Attribute | +| xpathFlow.py:20:18:20:44 | After Attribute() | semmle.label | After Attribute() | +| xpathFlow.py:23:29:23:38 | xpathQuery | semmle.label | xpathQuery | +| xpathFlow.py:30:5:30:14 | xpathQuery | semmle.label | xpathQuery | +| xpathFlow.py:30:18:30:24 | request | semmle.label | request | +| xpathFlow.py:30:18:30:29 | After Attribute | semmle.label | After Attribute | +| xpathFlow.py:30:18:30:44 | After Attribute() | semmle.label | After Attribute() | +| xpathFlow.py:32:29:32:38 | xpathQuery | semmle.label | xpathQuery | +| xpathFlow.py:39:5:39:14 | xpathQuery | semmle.label | xpathQuery | +| xpathFlow.py:39:18:39:24 | request | semmle.label | request | +| xpathFlow.py:39:18:39:29 | After Attribute | semmle.label | After Attribute | +| xpathFlow.py:39:18:39:44 | After Attribute() | semmle.label | After Attribute() | +| xpathFlow.py:41:31:41:40 | xpathQuery | semmle.label | xpathQuery | +| xpathFlow.py:47:5:47:14 | xpathQuery | semmle.label | xpathQuery | +| xpathFlow.py:47:18:47:24 | request | semmle.label | request | +| xpathFlow.py:47:18:47:29 | After Attribute | semmle.label | After Attribute | +| xpathFlow.py:47:18:47:44 | After Attribute() | semmle.label | After Attribute() | +| xpathFlow.py:49:29:49:38 | xpathQuery | semmle.label | xpathQuery | subpaths #select -| xpathBad.py:13:20:13:43 | ControlFlowNode for BinaryExpr | xpathBad.py:9:7:9:13 | ControlFlowNode for request | xpathBad.py:13:20:13:43 | ControlFlowNode for BinaryExpr | XPath expression depends on a $@. | xpathBad.py:9:7:9:13 | ControlFlowNode for request | user-provided value | -| xpathFlow.py:14:20:14:29 | ControlFlowNode for xpathQuery | xpathFlow.py:2:26:2:32 | ControlFlowNode for ImportMember | xpathFlow.py:14:20:14:29 | ControlFlowNode for xpathQuery | XPath expression depends on a $@. | xpathFlow.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value | -| xpathFlow.py:23:29:23:38 | ControlFlowNode for xpathQuery | xpathFlow.py:2:26:2:32 | ControlFlowNode for ImportMember | xpathFlow.py:23:29:23:38 | ControlFlowNode for xpathQuery | XPath expression depends on a $@. | xpathFlow.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value | -| xpathFlow.py:32:29:32:38 | ControlFlowNode for xpathQuery | xpathFlow.py:2:26:2:32 | ControlFlowNode for ImportMember | xpathFlow.py:32:29:32:38 | ControlFlowNode for xpathQuery | XPath expression depends on a $@. | xpathFlow.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value | -| xpathFlow.py:41:31:41:40 | ControlFlowNode for xpathQuery | xpathFlow.py:2:26:2:32 | ControlFlowNode for ImportMember | xpathFlow.py:41:31:41:40 | ControlFlowNode for xpathQuery | XPath expression depends on a $@. | xpathFlow.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value | -| xpathFlow.py:49:29:49:38 | ControlFlowNode for xpathQuery | xpathFlow.py:2:26:2:32 | ControlFlowNode for ImportMember | xpathFlow.py:49:29:49:38 | ControlFlowNode for xpathQuery | XPath expression depends on a $@. | xpathFlow.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value | +| xpathBad.py:13:20:13:43 | After BinaryExpr | xpathBad.py:9:7:9:13 | request | xpathBad.py:13:20:13:43 | After BinaryExpr | XPath expression depends on a $@. | xpathBad.py:9:7:9:13 | request | user-provided value | +| xpathFlow.py:14:20:14:29 | xpathQuery | xpathFlow.py:2:26:2:32 | After ImportMember | xpathFlow.py:14:20:14:29 | xpathQuery | XPath expression depends on a $@. | xpathFlow.py:2:26:2:32 | After ImportMember | user-provided value | +| xpathFlow.py:23:29:23:38 | xpathQuery | xpathFlow.py:2:26:2:32 | After ImportMember | xpathFlow.py:23:29:23:38 | xpathQuery | XPath expression depends on a $@. | xpathFlow.py:2:26:2:32 | After ImportMember | user-provided value | +| xpathFlow.py:32:29:32:38 | xpathQuery | xpathFlow.py:2:26:2:32 | After ImportMember | xpathFlow.py:32:29:32:38 | xpathQuery | XPath expression depends on a $@. | xpathFlow.py:2:26:2:32 | After ImportMember | user-provided value | +| xpathFlow.py:41:31:41:40 | xpathQuery | xpathFlow.py:2:26:2:32 | After ImportMember | xpathFlow.py:41:31:41:40 | xpathQuery | XPath expression depends on a $@. | xpathFlow.py:2:26:2:32 | After ImportMember | user-provided value | +| xpathFlow.py:49:29:49:38 | xpathQuery | xpathFlow.py:2:26:2:32 | After ImportMember | xpathFlow.py:49:29:49:38 | xpathQuery | XPath expression depends on a $@. | xpathFlow.py:2:26:2:32 | After ImportMember | user-provided value | diff --git a/python/ql/test/query-tests/Security/CWE-730-PolynomialReDoS/PolynomialReDoS.expected b/python/ql/test/query-tests/Security/CWE-730-PolynomialReDoS/PolynomialReDoS.expected index 22fcfd05fa19..8ae5073c5446 100644 --- a/python/ql/test/query-tests/Security/CWE-730-PolynomialReDoS/PolynomialReDoS.expected +++ b/python/ql/test/query-tests/Security/CWE-730-PolynomialReDoS/PolynomialReDoS.expected @@ -1,34 +1,34 @@ -#select -| test.py:8:30:8:33 | ControlFlowNode for text | test.py:2:26:2:32 | ControlFlowNode for ImportMember | test.py:8:30:8:33 | ControlFlowNode for text | This $@ that depends on a $@ may run slow on strings with many repetitions of ' '. | test.py:8:19:8:21 | \\s+ | regular expression | test.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value | -| test.py:9:32:9:35 | ControlFlowNode for text | test.py:2:26:2:32 | ControlFlowNode for ImportMember | test.py:9:32:9:35 | ControlFlowNode for text | This $@ that depends on a $@ may run slow on strings starting with '0.9' and with many repetitions of '99'. | test.py:9:25:9:27 | \\d+ | regular expression | test.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value | -| test.py:12:17:12:20 | ControlFlowNode for text | test.py:2:26:2:32 | ControlFlowNode for ImportMember | test.py:12:17:12:20 | ControlFlowNode for text | This $@ that depends on a $@ may run slow on strings with many repetitions of ' '. | test.py:11:29:11:31 | \\s+ | regular expression | test.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value | -| test.py:16:24:16:30 | ControlFlowNode for my_text | test.py:2:26:2:32 | ControlFlowNode for ImportMember | test.py:16:24:16:30 | ControlFlowNode for my_text | This $@ that depends on a $@ may run slow on strings with many repetitions of ' '. | test.py:18:21:18:23 | \\s+ | regular expression | test.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value | -| test.py:21:18:21:21 | ControlFlowNode for text | test.py:2:26:2:32 | ControlFlowNode for ImportMember | test.py:21:18:21:21 | ControlFlowNode for text | This $@ that depends on a $@ may run slow on strings starting with 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC' and with many repetitions of 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC'. | test.py:20:271:20:272 | .* | regular expression | test.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value | edges -| test.py:2:26:2:32 | ControlFlowNode for ImportMember | test.py:2:26:2:32 | ControlFlowNode for request | provenance | | -| test.py:2:26:2:32 | ControlFlowNode for request | test.py:7:12:7:18 | ControlFlowNode for request | provenance | | -| test.py:7:5:7:8 | ControlFlowNode for text | test.py:8:30:8:33 | ControlFlowNode for text | provenance | | -| test.py:7:5:7:8 | ControlFlowNode for text | test.py:9:32:9:35 | ControlFlowNode for text | provenance | | -| test.py:7:5:7:8 | ControlFlowNode for text | test.py:12:17:12:20 | ControlFlowNode for text | provenance | | -| test.py:7:5:7:8 | ControlFlowNode for text | test.py:18:28:18:31 | ControlFlowNode for text | provenance | | -| test.py:7:5:7:8 | ControlFlowNode for text | test.py:21:18:21:21 | ControlFlowNode for text | provenance | | -| test.py:7:12:7:18 | ControlFlowNode for request | test.py:7:12:7:23 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep | -| test.py:7:12:7:23 | ControlFlowNode for Attribute | test.py:7:12:7:35 | ControlFlowNode for Attribute() | provenance | dict.get | -| test.py:7:12:7:35 | ControlFlowNode for Attribute() | test.py:7:5:7:8 | ControlFlowNode for text | provenance | | -| test.py:14:33:14:39 | ControlFlowNode for my_text | test.py:16:24:16:30 | ControlFlowNode for my_text | provenance | | -| test.py:18:28:18:31 | ControlFlowNode for text | test.py:14:33:14:39 | ControlFlowNode for my_text | provenance | | +| test.py:2:26:2:32 | After ImportMember | test.py:2:26:2:32 | request | provenance | | +| test.py:2:26:2:32 | request | test.py:7:12:7:18 | request | provenance | | +| test.py:7:5:7:8 | text | test.py:8:30:8:33 | text | provenance | | +| test.py:7:5:7:8 | text | test.py:9:32:9:35 | text | provenance | | +| test.py:7:5:7:8 | text | test.py:12:17:12:20 | text | provenance | | +| test.py:7:5:7:8 | text | test.py:18:28:18:31 | text | provenance | | +| test.py:7:5:7:8 | text | test.py:21:18:21:21 | text | provenance | | +| test.py:7:12:7:18 | request | test.py:7:12:7:23 | After Attribute | provenance | AdditionalTaintStep | +| test.py:7:12:7:23 | After Attribute | test.py:7:12:7:35 | After Attribute() | provenance | dict.get | +| test.py:7:12:7:35 | After Attribute() | test.py:7:5:7:8 | text | provenance | | +| test.py:14:33:14:39 | my_text | test.py:16:24:16:30 | my_text | provenance | | +| test.py:18:28:18:31 | text | test.py:14:33:14:39 | my_text | provenance | | nodes -| test.py:2:26:2:32 | ControlFlowNode for ImportMember | semmle.label | ControlFlowNode for ImportMember | -| test.py:2:26:2:32 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| test.py:7:5:7:8 | ControlFlowNode for text | semmle.label | ControlFlowNode for text | -| test.py:7:12:7:18 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| test.py:7:12:7:23 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| test.py:7:12:7:35 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| test.py:8:30:8:33 | ControlFlowNode for text | semmle.label | ControlFlowNode for text | -| test.py:9:32:9:35 | ControlFlowNode for text | semmle.label | ControlFlowNode for text | -| test.py:12:17:12:20 | ControlFlowNode for text | semmle.label | ControlFlowNode for text | -| test.py:14:33:14:39 | ControlFlowNode for my_text | semmle.label | ControlFlowNode for my_text | -| test.py:16:24:16:30 | ControlFlowNode for my_text | semmle.label | ControlFlowNode for my_text | -| test.py:18:28:18:31 | ControlFlowNode for text | semmle.label | ControlFlowNode for text | -| test.py:21:18:21:21 | ControlFlowNode for text | semmle.label | ControlFlowNode for text | +| test.py:2:26:2:32 | After ImportMember | semmle.label | After ImportMember | +| test.py:2:26:2:32 | request | semmle.label | request | +| test.py:7:5:7:8 | text | semmle.label | text | +| test.py:7:12:7:18 | request | semmle.label | request | +| test.py:7:12:7:23 | After Attribute | semmle.label | After Attribute | +| test.py:7:12:7:35 | After Attribute() | semmle.label | After Attribute() | +| test.py:8:30:8:33 | text | semmle.label | text | +| test.py:9:32:9:35 | text | semmle.label | text | +| test.py:12:17:12:20 | text | semmle.label | text | +| test.py:14:33:14:39 | my_text | semmle.label | my_text | +| test.py:16:24:16:30 | my_text | semmle.label | my_text | +| test.py:18:28:18:31 | text | semmle.label | text | +| test.py:21:18:21:21 | text | semmle.label | text | subpaths +#select +| test.py:8:30:8:33 | text | test.py:2:26:2:32 | After ImportMember | test.py:8:30:8:33 | text | This $@ that depends on a $@ may run slow on strings with many repetitions of ' '. | test.py:8:19:8:21 | \\s+ | regular expression | test.py:2:26:2:32 | After ImportMember | user-provided value | +| test.py:9:32:9:35 | text | test.py:2:26:2:32 | After ImportMember | test.py:9:32:9:35 | text | This $@ that depends on a $@ may run slow on strings starting with '0.9' and with many repetitions of '99'. | test.py:9:25:9:27 | \\d+ | regular expression | test.py:2:26:2:32 | After ImportMember | user-provided value | +| test.py:12:17:12:20 | text | test.py:2:26:2:32 | After ImportMember | test.py:12:17:12:20 | text | This $@ that depends on a $@ may run slow on strings with many repetitions of ' '. | test.py:11:29:11:31 | \\s+ | regular expression | test.py:2:26:2:32 | After ImportMember | user-provided value | +| test.py:16:24:16:30 | my_text | test.py:2:26:2:32 | After ImportMember | test.py:16:24:16:30 | my_text | This $@ that depends on a $@ may run slow on strings with many repetitions of ' '. | test.py:18:21:18:23 | \\s+ | regular expression | test.py:2:26:2:32 | After ImportMember | user-provided value | +| test.py:21:18:21:21 | text | test.py:2:26:2:32 | After ImportMember | test.py:21:18:21:21 | text | This $@ that depends on a $@ may run slow on strings starting with 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC' and with many repetitions of 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC'. | test.py:20:271:20:272 | .* | regular expression | test.py:2:26:2:32 | After ImportMember | user-provided value | diff --git a/python/ql/test/query-tests/Security/CWE-730-RegexInjection/RegexInjection.expected b/python/ql/test/query-tests/Security/CWE-730-RegexInjection/RegexInjection.expected index 16d29401f785..35d64072459a 100644 --- a/python/ql/test/query-tests/Security/CWE-730-RegexInjection/RegexInjection.expected +++ b/python/ql/test/query-tests/Security/CWE-730-RegexInjection/RegexInjection.expected @@ -1,28 +1,28 @@ edges -| re_bad.py:1:19:1:25 | ControlFlowNode for ImportMember | re_bad.py:1:19:1:25 | ControlFlowNode for request | provenance | | -| re_bad.py:1:19:1:25 | ControlFlowNode for request | re_bad.py:13:22:13:28 | ControlFlowNode for request | provenance | | -| re_bad.py:1:19:1:25 | ControlFlowNode for request | re_bad.py:24:22:24:28 | ControlFlowNode for request | provenance | | -| re_bad.py:1:19:1:25 | ControlFlowNode for request | re_bad.py:36:22:36:28 | ControlFlowNode for request | provenance | | -| re_bad.py:13:5:13:18 | ControlFlowNode for unsafe_pattern | re_bad.py:14:15:14:28 | ControlFlowNode for unsafe_pattern | provenance | | -| re_bad.py:13:22:13:28 | ControlFlowNode for request | re_bad.py:13:5:13:18 | ControlFlowNode for unsafe_pattern | provenance | AdditionalTaintStep | -| re_bad.py:24:5:24:18 | ControlFlowNode for unsafe_pattern | re_bad.py:25:35:25:48 | ControlFlowNode for unsafe_pattern | provenance | | -| re_bad.py:24:22:24:28 | ControlFlowNode for request | re_bad.py:24:5:24:18 | ControlFlowNode for unsafe_pattern | provenance | AdditionalTaintStep | -| re_bad.py:36:5:36:18 | ControlFlowNode for unsafe_pattern | re_bad.py:37:16:37:29 | ControlFlowNode for unsafe_pattern | provenance | | -| re_bad.py:36:22:36:28 | ControlFlowNode for request | re_bad.py:36:5:36:18 | ControlFlowNode for unsafe_pattern | provenance | AdditionalTaintStep | +| re_bad.py:1:19:1:25 | After ImportMember | re_bad.py:1:19:1:25 | request | provenance | | +| re_bad.py:1:19:1:25 | request | re_bad.py:13:22:13:28 | request | provenance | | +| re_bad.py:1:19:1:25 | request | re_bad.py:24:22:24:28 | request | provenance | | +| re_bad.py:1:19:1:25 | request | re_bad.py:36:22:36:28 | request | provenance | | +| re_bad.py:13:5:13:18 | unsafe_pattern | re_bad.py:14:15:14:28 | unsafe_pattern | provenance | | +| re_bad.py:13:22:13:28 | request | re_bad.py:13:5:13:18 | unsafe_pattern | provenance | AdditionalTaintStep | +| re_bad.py:24:5:24:18 | unsafe_pattern | re_bad.py:25:35:25:48 | unsafe_pattern | provenance | | +| re_bad.py:24:22:24:28 | request | re_bad.py:24:5:24:18 | unsafe_pattern | provenance | AdditionalTaintStep | +| re_bad.py:36:5:36:18 | unsafe_pattern | re_bad.py:37:16:37:29 | unsafe_pattern | provenance | | +| re_bad.py:36:22:36:28 | request | re_bad.py:36:5:36:18 | unsafe_pattern | provenance | AdditionalTaintStep | nodes -| re_bad.py:1:19:1:25 | ControlFlowNode for ImportMember | semmle.label | ControlFlowNode for ImportMember | -| re_bad.py:1:19:1:25 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| re_bad.py:13:5:13:18 | ControlFlowNode for unsafe_pattern | semmle.label | ControlFlowNode for unsafe_pattern | -| re_bad.py:13:22:13:28 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| re_bad.py:14:15:14:28 | ControlFlowNode for unsafe_pattern | semmle.label | ControlFlowNode for unsafe_pattern | -| re_bad.py:24:5:24:18 | ControlFlowNode for unsafe_pattern | semmle.label | ControlFlowNode for unsafe_pattern | -| re_bad.py:24:22:24:28 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| re_bad.py:25:35:25:48 | ControlFlowNode for unsafe_pattern | semmle.label | ControlFlowNode for unsafe_pattern | -| re_bad.py:36:5:36:18 | ControlFlowNode for unsafe_pattern | semmle.label | ControlFlowNode for unsafe_pattern | -| re_bad.py:36:22:36:28 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| re_bad.py:37:16:37:29 | ControlFlowNode for unsafe_pattern | semmle.label | ControlFlowNode for unsafe_pattern | +| re_bad.py:1:19:1:25 | After ImportMember | semmle.label | After ImportMember | +| re_bad.py:1:19:1:25 | request | semmle.label | request | +| re_bad.py:13:5:13:18 | unsafe_pattern | semmle.label | unsafe_pattern | +| re_bad.py:13:22:13:28 | request | semmle.label | request | +| re_bad.py:14:15:14:28 | unsafe_pattern | semmle.label | unsafe_pattern | +| re_bad.py:24:5:24:18 | unsafe_pattern | semmle.label | unsafe_pattern | +| re_bad.py:24:22:24:28 | request | semmle.label | request | +| re_bad.py:25:35:25:48 | unsafe_pattern | semmle.label | unsafe_pattern | +| re_bad.py:36:5:36:18 | unsafe_pattern | semmle.label | unsafe_pattern | +| re_bad.py:36:22:36:28 | request | semmle.label | request | +| re_bad.py:37:16:37:29 | unsafe_pattern | semmle.label | unsafe_pattern | subpaths #select -| re_bad.py:14:15:14:28 | ControlFlowNode for unsafe_pattern | re_bad.py:1:19:1:25 | ControlFlowNode for ImportMember | re_bad.py:14:15:14:28 | ControlFlowNode for unsafe_pattern | This regular expression depends on a $@ and is executed by $@. | re_bad.py:1:19:1:25 | ControlFlowNode for ImportMember | user-provided value | re_bad.py:14:5:14:33 | ControlFlowNode for Attribute() | re.search | -| re_bad.py:25:35:25:48 | ControlFlowNode for unsafe_pattern | re_bad.py:1:19:1:25 | ControlFlowNode for ImportMember | re_bad.py:25:35:25:48 | ControlFlowNode for unsafe_pattern | This regular expression depends on a $@ and is executed by $@. | re_bad.py:1:19:1:25 | ControlFlowNode for ImportMember | user-provided value | re_bad.py:26:5:26:31 | ControlFlowNode for Attribute() | re.search | -| re_bad.py:37:16:37:29 | ControlFlowNode for unsafe_pattern | re_bad.py:1:19:1:25 | ControlFlowNode for ImportMember | re_bad.py:37:16:37:29 | ControlFlowNode for unsafe_pattern | This regular expression depends on a $@ and is executed by $@. | re_bad.py:1:19:1:25 | ControlFlowNode for ImportMember | user-provided value | re_bad.py:37:5:37:41 | ControlFlowNode for Attribute() | re.search | +| re_bad.py:14:15:14:28 | unsafe_pattern | re_bad.py:1:19:1:25 | After ImportMember | re_bad.py:14:15:14:28 | unsafe_pattern | This regular expression depends on a $@ and is executed by $@. | re_bad.py:1:19:1:25 | After ImportMember | user-provided value | re_bad.py:14:5:14:33 | After Attribute() | re.search | +| re_bad.py:25:35:25:48 | unsafe_pattern | re_bad.py:1:19:1:25 | After ImportMember | re_bad.py:25:35:25:48 | unsafe_pattern | This regular expression depends on a $@ and is executed by $@. | re_bad.py:1:19:1:25 | After ImportMember | user-provided value | re_bad.py:26:5:26:31 | After Attribute() | re.search | +| re_bad.py:37:16:37:29 | unsafe_pattern | re_bad.py:1:19:1:25 | After ImportMember | re_bad.py:37:16:37:29 | unsafe_pattern | This regular expression depends on a $@ and is executed by $@. | re_bad.py:1:19:1:25 | After ImportMember | user-provided value | re_bad.py:37:5:37:41 | After Attribute() | re.search | diff --git a/python/ql/test/query-tests/Security/CWE-732-WeakFilePermissions/WeakFilePermissions.expected b/python/ql/test/query-tests/Security/CWE-732-WeakFilePermissions/WeakFilePermissions.expected index 762d2599c2d8..ae7ab9971c1d 100644 --- a/python/ql/test/query-tests/Security/CWE-732-WeakFilePermissions/WeakFilePermissions.expected +++ b/python/ql/test/query-tests/Security/CWE-732-WeakFilePermissions/WeakFilePermissions.expected @@ -1,6 +1,6 @@ -| test.py:7:1:7:19 | ControlFlowNode for Attribute() | Overly permissive mask in chmod sets file to world writable. | -| test.py:8:1:8:20 | ControlFlowNode for Attribute() | Overly permissive mask in chmod sets file to world writable. | -| test.py:9:1:9:21 | ControlFlowNode for Attribute() | Overly permissive mask in chmod sets file to world writable. | -| test.py:11:1:11:21 | ControlFlowNode for Attribute() | Overly permissive mask in chmod sets file to group readable. | -| test.py:14:1:14:19 | ControlFlowNode for Attribute() | Overly permissive mask in chmod sets file to group writable. | -| test.py:16:1:16:25 | ControlFlowNode for Attribute() | Overly permissive mask in open sets file to world readable. | +| test.py:7:1:7:19 | After Attribute() | Overly permissive mask in chmod sets file to world writable. | +| test.py:8:1:8:20 | After Attribute() | Overly permissive mask in chmod sets file to world writable. | +| test.py:9:1:9:21 | After Attribute() | Overly permissive mask in chmod sets file to world writable. | +| test.py:11:1:11:21 | After Attribute() | Overly permissive mask in chmod sets file to group readable. | +| test.py:14:1:14:19 | After Attribute() | Overly permissive mask in chmod sets file to group writable. | +| test.py:16:1:16:25 | After Attribute() | Overly permissive mask in open sets file to world readable. | diff --git a/python/ql/test/query-tests/Security/CWE-798-HardcodedCredentials/HardcodedCredentials.expected b/python/ql/test/query-tests/Security/CWE-798-HardcodedCredentials/HardcodedCredentials.expected index 7fe70dd495b2..968d1b246e92 100644 --- a/python/ql/test/query-tests/Security/CWE-798-HardcodedCredentials/HardcodedCredentials.expected +++ b/python/ql/test/query-tests/Security/CWE-798-HardcodedCredentials/HardcodedCredentials.expected @@ -1,16 +1,16 @@ edges -| test.py:5:1:5:8 | ControlFlowNode for USERNAME | test.py:14:18:14:25 | ControlFlowNode for USERNAME | provenance | | -| test.py:5:12:5:24 | ControlFlowNode for StringLiteral | test.py:5:1:5:8 | ControlFlowNode for USERNAME | provenance | | -| test.py:6:1:6:8 | ControlFlowNode for PASSWORD | test.py:15:18:15:25 | ControlFlowNode for PASSWORD | provenance | | -| test.py:6:12:6:25 | ControlFlowNode for StringLiteral | test.py:6:1:6:8 | ControlFlowNode for PASSWORD | provenance | | +| test.py:5:1:5:8 | USERNAME | test.py:14:18:14:25 | USERNAME | provenance | | +| test.py:5:12:5:24 | StringLiteral | test.py:5:1:5:8 | USERNAME | provenance | | +| test.py:6:1:6:8 | PASSWORD | test.py:15:18:15:25 | PASSWORD | provenance | | +| test.py:6:12:6:25 | StringLiteral | test.py:6:1:6:8 | PASSWORD | provenance | | nodes -| test.py:5:1:5:8 | ControlFlowNode for USERNAME | semmle.label | ControlFlowNode for USERNAME | -| test.py:5:12:5:24 | ControlFlowNode for StringLiteral | semmle.label | ControlFlowNode for StringLiteral | -| test.py:6:1:6:8 | ControlFlowNode for PASSWORD | semmle.label | ControlFlowNode for PASSWORD | -| test.py:6:12:6:25 | ControlFlowNode for StringLiteral | semmle.label | ControlFlowNode for StringLiteral | -| test.py:14:18:14:25 | ControlFlowNode for USERNAME | semmle.label | ControlFlowNode for USERNAME | -| test.py:15:18:15:25 | ControlFlowNode for PASSWORD | semmle.label | ControlFlowNode for PASSWORD | +| test.py:5:1:5:8 | USERNAME | semmle.label | USERNAME | +| test.py:5:12:5:24 | StringLiteral | semmle.label | StringLiteral | +| test.py:6:1:6:8 | PASSWORD | semmle.label | PASSWORD | +| test.py:6:12:6:25 | StringLiteral | semmle.label | StringLiteral | +| test.py:14:18:14:25 | USERNAME | semmle.label | USERNAME | +| test.py:15:18:15:25 | PASSWORD | semmle.label | PASSWORD | subpaths #select -| test.py:5:12:5:24 | ControlFlowNode for StringLiteral | test.py:5:12:5:24 | ControlFlowNode for StringLiteral | test.py:14:18:14:25 | ControlFlowNode for USERNAME | This hardcoded value is $@. | test.py:14:18:14:25 | ControlFlowNode for USERNAME | used as credentials | -| test.py:6:12:6:25 | ControlFlowNode for StringLiteral | test.py:6:12:6:25 | ControlFlowNode for StringLiteral | test.py:15:18:15:25 | ControlFlowNode for PASSWORD | This hardcoded value is $@. | test.py:15:18:15:25 | ControlFlowNode for PASSWORD | used as credentials | +| test.py:5:12:5:24 | StringLiteral | test.py:5:12:5:24 | StringLiteral | test.py:14:18:14:25 | USERNAME | This hardcoded value is $@. | test.py:14:18:14:25 | USERNAME | used as credentials | +| test.py:6:12:6:25 | StringLiteral | test.py:6:12:6:25 | StringLiteral | test.py:15:18:15:25 | PASSWORD | This hardcoded value is $@. | test.py:15:18:15:25 | PASSWORD | used as credentials | diff --git a/python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/FullServerSideRequestForgery.expected b/python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/FullServerSideRequestForgery.expected index 7434eca6978b..e84845da7b2b 100644 --- a/python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/FullServerSideRequestForgery.expected +++ b/python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/FullServerSideRequestForgery.expected @@ -1,153 +1,153 @@ #select -| full_partial_test.py:11:5:11:28 | ControlFlowNode for Attribute() | full_partial_test.py:1:19:1:25 | ControlFlowNode for ImportMember | full_partial_test.py:11:18:11:27 | ControlFlowNode for user_input | The full URL of this request depends on a $@. | full_partial_test.py:1:19:1:25 | ControlFlowNode for ImportMember | user-provided value | -| full_partial_test.py:15:5:15:21 | ControlFlowNode for Attribute() | full_partial_test.py:1:19:1:25 | ControlFlowNode for ImportMember | full_partial_test.py:15:18:15:20 | ControlFlowNode for url | The full URL of this request depends on a $@. | full_partial_test.py:1:19:1:25 | ControlFlowNode for ImportMember | user-provided value | -| full_partial_test.py:22:5:22:21 | ControlFlowNode for Attribute() | full_partial_test.py:1:19:1:25 | ControlFlowNode for ImportMember | full_partial_test.py:22:18:22:20 | ControlFlowNode for url | The full URL of this request depends on a $@. | full_partial_test.py:1:19:1:25 | ControlFlowNode for ImportMember | user-provided value | -| full_partial_test.py:27:5:27:21 | ControlFlowNode for Attribute() | full_partial_test.py:1:19:1:25 | ControlFlowNode for ImportMember | full_partial_test.py:27:18:27:20 | ControlFlowNode for url | The full URL of this request depends on a $@. | full_partial_test.py:1:19:1:25 | ControlFlowNode for ImportMember | user-provided value | -| full_partial_test.py:47:5:47:21 | ControlFlowNode for Attribute() | full_partial_test.py:1:19:1:25 | ControlFlowNode for ImportMember | full_partial_test.py:47:18:47:20 | ControlFlowNode for url | The full URL of this request depends on a $@. | full_partial_test.py:1:19:1:25 | ControlFlowNode for ImportMember | user-provided value | -| full_partial_test.py:51:5:51:21 | ControlFlowNode for Attribute() | full_partial_test.py:1:19:1:25 | ControlFlowNode for ImportMember | full_partial_test.py:51:18:51:20 | ControlFlowNode for url | The full URL of this request depends on a $@. | full_partial_test.py:1:19:1:25 | ControlFlowNode for ImportMember | user-provided value | -| full_partial_test.py:55:5:55:21 | ControlFlowNode for Attribute() | full_partial_test.py:1:19:1:25 | ControlFlowNode for ImportMember | full_partial_test.py:55:18:55:20 | ControlFlowNode for url | The full URL of this request depends on a $@. | full_partial_test.py:1:19:1:25 | ControlFlowNode for ImportMember | user-provided value | -| full_partial_test.py:59:5:59:21 | ControlFlowNode for Attribute() | full_partial_test.py:1:19:1:25 | ControlFlowNode for ImportMember | full_partial_test.py:59:18:59:20 | ControlFlowNode for url | The full URL of this request depends on a $@. | full_partial_test.py:1:19:1:25 | ControlFlowNode for ImportMember | user-provided value | -| full_partial_test.py:63:5:63:21 | ControlFlowNode for Attribute() | full_partial_test.py:1:19:1:25 | ControlFlowNode for ImportMember | full_partial_test.py:63:18:63:20 | ControlFlowNode for url | The full URL of this request depends on a $@. | full_partial_test.py:1:19:1:25 | ControlFlowNode for ImportMember | user-provided value | -| full_partial_test.py:72:5:72:21 | ControlFlowNode for Attribute() | full_partial_test.py:1:19:1:25 | ControlFlowNode for ImportMember | full_partial_test.py:72:18:72:20 | ControlFlowNode for url | The full URL of this request depends on a $@. | full_partial_test.py:1:19:1:25 | ControlFlowNode for ImportMember | user-provided value | -| full_partial_test.py:76:5:76:21 | ControlFlowNode for Attribute() | full_partial_test.py:1:19:1:25 | ControlFlowNode for ImportMember | full_partial_test.py:76:18:76:20 | ControlFlowNode for url | The full URL of this request depends on a $@. | full_partial_test.py:1:19:1:25 | ControlFlowNode for ImportMember | user-provided value | -| full_partial_test.py:89:5:89:21 | ControlFlowNode for Attribute() | full_partial_test.py:1:19:1:25 | ControlFlowNode for ImportMember | full_partial_test.py:89:18:89:20 | ControlFlowNode for url | The full URL of this request depends on a $@. | full_partial_test.py:1:19:1:25 | ControlFlowNode for ImportMember | user-provided value | -| full_partial_test.py:93:5:93:21 | ControlFlowNode for Attribute() | full_partial_test.py:1:19:1:25 | ControlFlowNode for ImportMember | full_partial_test.py:93:18:93:20 | ControlFlowNode for url | The full URL of this request depends on a $@. | full_partial_test.py:1:19:1:25 | ControlFlowNode for ImportMember | user-provided value | -| full_partial_test.py:97:5:97:21 | ControlFlowNode for Attribute() | full_partial_test.py:1:19:1:25 | ControlFlowNode for ImportMember | full_partial_test.py:97:18:97:20 | ControlFlowNode for url | The full URL of this request depends on a $@. | full_partial_test.py:1:19:1:25 | ControlFlowNode for ImportMember | user-provided value | -| test_azure_client.py:16:5:16:59 | ControlFlowNode for SecretClient() | test_azure_client.py:6:19:6:25 | ControlFlowNode for ImportMember | test_azure_client.py:16:28:16:35 | ControlFlowNode for full_url | The full URL of this request depends on a $@. | test_azure_client.py:6:19:6:25 | ControlFlowNode for ImportMember | user-provided value | -| test_azure_client.py:18:5:18:43 | ControlFlowNode for Attribute() | test_azure_client.py:6:19:6:25 | ControlFlowNode for ImportMember | test_azure_client.py:18:35:18:42 | ControlFlowNode for full_url | The full URL of this request depends on a $@. | test_azure_client.py:6:19:6:25 | ControlFlowNode for ImportMember | user-provided value | -| test_azure_client.py:20:5:20:35 | ControlFlowNode for KeyClient() | test_azure_client.py:6:19:6:25 | ControlFlowNode for ImportMember | test_azure_client.py:20:15:20:22 | ControlFlowNode for full_url | The full URL of this request depends on a $@. | test_azure_client.py:6:19:6:25 | ControlFlowNode for ImportMember | user-provided value | -| test_azure_client.py:22:5:22:85 | ControlFlowNode for Attribute() | test_azure_client.py:6:19:6:25 | ControlFlowNode for ImportMember | test_azure_client.py:22:54:22:61 | ControlFlowNode for full_url | The full URL of this request depends on a $@. | test_azure_client.py:6:19:6:25 | ControlFlowNode for ImportMember | user-provided value | -| test_azure_client.py:25:5:25:104 | ControlFlowNode for download_blob_from_url() | test_azure_client.py:6:19:6:25 | ControlFlowNode for ImportMember | test_azure_client.py:25:37:25:44 | ControlFlowNode for full_url | The full URL of this request depends on a $@. | test_azure_client.py:6:19:6:25 | ControlFlowNode for ImportMember | user-provided value | -| test_http_client.py:15:5:15:36 | ControlFlowNode for Attribute() | test_http_client.py:1:19:1:25 | ControlFlowNode for ImportMember | test_http_client.py:13:27:13:37 | ControlFlowNode for unsafe_host | The full URL of this request depends on a $@. | test_http_client.py:1:19:1:25 | ControlFlowNode for ImportMember | user-provided value | -| test_http_client.py:15:5:15:36 | ControlFlowNode for Attribute() | test_http_client.py:1:19:1:25 | ControlFlowNode for ImportMember | test_http_client.py:15:25:15:35 | ControlFlowNode for unsafe_path | The full URL of this request depends on a $@. | test_http_client.py:1:19:1:25 | ControlFlowNode for ImportMember | user-provided value | -| test_http_client.py:21:5:21:36 | ControlFlowNode for Attribute() | test_http_client.py:1:19:1:25 | ControlFlowNode for ImportMember | test_http_client.py:19:27:19:37 | ControlFlowNode for unsafe_host | The full URL of this request depends on a $@. | test_http_client.py:1:19:1:25 | ControlFlowNode for ImportMember | user-provided value | -| test_http_client.py:21:5:21:36 | ControlFlowNode for Attribute() | test_http_client.py:1:19:1:25 | ControlFlowNode for ImportMember | test_http_client.py:21:25:21:35 | ControlFlowNode for unsafe_path | The full URL of this request depends on a $@. | test_http_client.py:1:19:1:25 | ControlFlowNode for ImportMember | user-provided value | -| test_path_validation.py:21:9:21:63 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:21:32:21:39 | ControlFlowNode for full_url | The full URL of this request depends on a $@. | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | user-provided value | -| test_path_validation.py:37:9:37:60 | ControlFlowNode for KeyClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:37:29:37:36 | ControlFlowNode for full_url | The full URL of this request depends on a $@. | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | user-provided value | -| test_path_validation.py:53:9:53:47 | ControlFlowNode for Attribute() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:53:39:53:46 | ControlFlowNode for full_url | The full URL of this request depends on a $@. | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | user-provided value | -| test_path_validation.py:64:9:64:58 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:64:32:64:34 | ControlFlowNode for url | The full URL of this request depends on a $@. | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | user-provided value | -| test_path_validation.py:71:9:71:58 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:71:32:71:34 | ControlFlowNode for url | The full URL of this request depends on a $@. | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | user-provided value | -| test_path_validation.py:74:9:74:58 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:74:32:74:34 | ControlFlowNode for url | The full URL of this request depends on a $@. | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | user-provided value | -| test_path_validation.py:79:9:79:58 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:79:32:79:34 | ControlFlowNode for url | The full URL of this request depends on a $@. | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | user-provided value | -| test_path_validation.py:87:9:87:58 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:87:32:87:34 | ControlFlowNode for url | The full URL of this request depends on a $@. | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | user-provided value | -| test_path_validation.py:90:9:90:58 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:90:32:90:34 | ControlFlowNode for url | The full URL of this request depends on a $@. | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | user-provided value | -| test_path_validation.py:95:9:95:58 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:95:32:95:34 | ControlFlowNode for url | The full URL of this request depends on a $@. | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | user-provided value | -| test_path_validation.py:102:9:102:58 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:102:32:102:34 | ControlFlowNode for url | The full URL of this request depends on a $@. | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | user-provided value | -| test_path_validation.py:107:9:107:58 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:107:32:107:34 | ControlFlowNode for url | The full URL of this request depends on a $@. | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | user-provided value | -| test_path_validation.py:110:9:110:58 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:110:32:110:34 | ControlFlowNode for url | The full URL of this request depends on a $@. | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | user-provided value | -| test_path_validation.py:115:9:115:58 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:115:32:115:34 | ControlFlowNode for url | The full URL of this request depends on a $@. | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | user-provided value | -| test_path_validation.py:122:9:122:58 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:122:32:122:34 | ControlFlowNode for url | The full URL of this request depends on a $@. | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | user-provided value | -| test_path_validation.py:125:9:125:58 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:125:32:125:34 | ControlFlowNode for url | The full URL of this request depends on a $@. | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | user-provided value | -| test_path_validation.py:132:9:132:58 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:132:32:132:34 | ControlFlowNode for url | The full URL of this request depends on a $@. | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | user-provided value | -| test_requests.py:9:5:9:28 | ControlFlowNode for Attribute() | test_requests.py:1:19:1:25 | ControlFlowNode for ImportMember | test_requests.py:9:18:9:27 | ControlFlowNode for user_input | The full URL of this request depends on a $@. | test_requests.py:1:19:1:25 | ControlFlowNode for ImportMember | user-provided value | -| test_requests.py:17:5:17:27 | ControlFlowNode for Attribute() | test_requests.py:1:19:1:25 | ControlFlowNode for ImportMember | test_requests.py:17:17:17:26 | ControlFlowNode for user_input | The full URL of this request depends on a $@. | test_requests.py:1:19:1:25 | ControlFlowNode for ImportMember | user-provided value | -| test_requests.py:22:5:22:44 | ControlFlowNode for Attribute() | test_requests.py:1:19:1:25 | ControlFlowNode for ImportMember | test_requests.py:22:34:22:43 | ControlFlowNode for user_input | The full URL of this request depends on a $@. | test_requests.py:1:19:1:25 | ControlFlowNode for ImportMember | user-provided value | +| full_partial_test.py:11:5:11:28 | After Attribute() | full_partial_test.py:1:19:1:25 | After ImportMember | full_partial_test.py:11:18:11:27 | user_input | The full URL of this request depends on a $@. | full_partial_test.py:1:19:1:25 | After ImportMember | user-provided value | +| full_partial_test.py:15:5:15:21 | After Attribute() | full_partial_test.py:1:19:1:25 | After ImportMember | full_partial_test.py:15:18:15:20 | url | The full URL of this request depends on a $@. | full_partial_test.py:1:19:1:25 | After ImportMember | user-provided value | +| full_partial_test.py:22:5:22:21 | After Attribute() | full_partial_test.py:1:19:1:25 | After ImportMember | full_partial_test.py:22:18:22:20 | url | The full URL of this request depends on a $@. | full_partial_test.py:1:19:1:25 | After ImportMember | user-provided value | +| full_partial_test.py:27:5:27:21 | After Attribute() | full_partial_test.py:1:19:1:25 | After ImportMember | full_partial_test.py:27:18:27:20 | url | The full URL of this request depends on a $@. | full_partial_test.py:1:19:1:25 | After ImportMember | user-provided value | +| full_partial_test.py:47:5:47:21 | After Attribute() | full_partial_test.py:1:19:1:25 | After ImportMember | full_partial_test.py:47:18:47:20 | url | The full URL of this request depends on a $@. | full_partial_test.py:1:19:1:25 | After ImportMember | user-provided value | +| full_partial_test.py:51:5:51:21 | After Attribute() | full_partial_test.py:1:19:1:25 | After ImportMember | full_partial_test.py:51:18:51:20 | url | The full URL of this request depends on a $@. | full_partial_test.py:1:19:1:25 | After ImportMember | user-provided value | +| full_partial_test.py:55:5:55:21 | After Attribute() | full_partial_test.py:1:19:1:25 | After ImportMember | full_partial_test.py:55:18:55:20 | url | The full URL of this request depends on a $@. | full_partial_test.py:1:19:1:25 | After ImportMember | user-provided value | +| full_partial_test.py:59:5:59:21 | After Attribute() | full_partial_test.py:1:19:1:25 | After ImportMember | full_partial_test.py:59:18:59:20 | url | The full URL of this request depends on a $@. | full_partial_test.py:1:19:1:25 | After ImportMember | user-provided value | +| full_partial_test.py:63:5:63:21 | After Attribute() | full_partial_test.py:1:19:1:25 | After ImportMember | full_partial_test.py:63:18:63:20 | url | The full URL of this request depends on a $@. | full_partial_test.py:1:19:1:25 | After ImportMember | user-provided value | +| full_partial_test.py:72:5:72:21 | After Attribute() | full_partial_test.py:1:19:1:25 | After ImportMember | full_partial_test.py:72:18:72:20 | url | The full URL of this request depends on a $@. | full_partial_test.py:1:19:1:25 | After ImportMember | user-provided value | +| full_partial_test.py:76:5:76:21 | After Attribute() | full_partial_test.py:1:19:1:25 | After ImportMember | full_partial_test.py:76:18:76:20 | url | The full URL of this request depends on a $@. | full_partial_test.py:1:19:1:25 | After ImportMember | user-provided value | +| full_partial_test.py:89:5:89:21 | After Attribute() | full_partial_test.py:1:19:1:25 | After ImportMember | full_partial_test.py:89:18:89:20 | url | The full URL of this request depends on a $@. | full_partial_test.py:1:19:1:25 | After ImportMember | user-provided value | +| full_partial_test.py:93:5:93:21 | After Attribute() | full_partial_test.py:1:19:1:25 | After ImportMember | full_partial_test.py:93:18:93:20 | url | The full URL of this request depends on a $@. | full_partial_test.py:1:19:1:25 | After ImportMember | user-provided value | +| full_partial_test.py:97:5:97:21 | After Attribute() | full_partial_test.py:1:19:1:25 | After ImportMember | full_partial_test.py:97:18:97:20 | url | The full URL of this request depends on a $@. | full_partial_test.py:1:19:1:25 | After ImportMember | user-provided value | +| test_azure_client.py:16:5:16:59 | After SecretClient() | test_azure_client.py:6:19:6:25 | After ImportMember | test_azure_client.py:16:28:16:35 | full_url | The full URL of this request depends on a $@. | test_azure_client.py:6:19:6:25 | After ImportMember | user-provided value | +| test_azure_client.py:18:5:18:43 | After Attribute() | test_azure_client.py:6:19:6:25 | After ImportMember | test_azure_client.py:18:35:18:42 | full_url | The full URL of this request depends on a $@. | test_azure_client.py:6:19:6:25 | After ImportMember | user-provided value | +| test_azure_client.py:20:5:20:35 | After KeyClient() | test_azure_client.py:6:19:6:25 | After ImportMember | test_azure_client.py:20:15:20:22 | full_url | The full URL of this request depends on a $@. | test_azure_client.py:6:19:6:25 | After ImportMember | user-provided value | +| test_azure_client.py:22:5:22:85 | After Attribute() | test_azure_client.py:6:19:6:25 | After ImportMember | test_azure_client.py:22:54:22:61 | full_url | The full URL of this request depends on a $@. | test_azure_client.py:6:19:6:25 | After ImportMember | user-provided value | +| test_azure_client.py:25:5:25:104 | After download_blob_from_url() | test_azure_client.py:6:19:6:25 | After ImportMember | test_azure_client.py:25:37:25:44 | full_url | The full URL of this request depends on a $@. | test_azure_client.py:6:19:6:25 | After ImportMember | user-provided value | +| test_http_client.py:15:5:15:36 | After Attribute() | test_http_client.py:1:19:1:25 | After ImportMember | test_http_client.py:13:27:13:37 | unsafe_host | The full URL of this request depends on a $@. | test_http_client.py:1:19:1:25 | After ImportMember | user-provided value | +| test_http_client.py:15:5:15:36 | After Attribute() | test_http_client.py:1:19:1:25 | After ImportMember | test_http_client.py:15:25:15:35 | unsafe_path | The full URL of this request depends on a $@. | test_http_client.py:1:19:1:25 | After ImportMember | user-provided value | +| test_http_client.py:21:5:21:36 | After Attribute() | test_http_client.py:1:19:1:25 | After ImportMember | test_http_client.py:19:27:19:37 | unsafe_host | The full URL of this request depends on a $@. | test_http_client.py:1:19:1:25 | After ImportMember | user-provided value | +| test_http_client.py:21:5:21:36 | After Attribute() | test_http_client.py:1:19:1:25 | After ImportMember | test_http_client.py:21:25:21:35 | unsafe_path | The full URL of this request depends on a $@. | test_http_client.py:1:19:1:25 | After ImportMember | user-provided value | +| test_path_validation.py:21:9:21:63 | After SecretClient() | test_path_validation.py:5:19:5:25 | After ImportMember | test_path_validation.py:21:32:21:39 | full_url | The full URL of this request depends on a $@. | test_path_validation.py:5:19:5:25 | After ImportMember | user-provided value | +| test_path_validation.py:37:9:37:60 | After KeyClient() | test_path_validation.py:5:19:5:25 | After ImportMember | test_path_validation.py:37:29:37:36 | full_url | The full URL of this request depends on a $@. | test_path_validation.py:5:19:5:25 | After ImportMember | user-provided value | +| test_path_validation.py:53:9:53:47 | After Attribute() | test_path_validation.py:5:19:5:25 | After ImportMember | test_path_validation.py:53:39:53:46 | full_url | The full URL of this request depends on a $@. | test_path_validation.py:5:19:5:25 | After ImportMember | user-provided value | +| test_path_validation.py:64:9:64:58 | After SecretClient() | test_path_validation.py:5:19:5:25 | After ImportMember | test_path_validation.py:64:32:64:34 | url | The full URL of this request depends on a $@. | test_path_validation.py:5:19:5:25 | After ImportMember | user-provided value | +| test_path_validation.py:71:9:71:58 | After SecretClient() | test_path_validation.py:5:19:5:25 | After ImportMember | test_path_validation.py:71:32:71:34 | url | The full URL of this request depends on a $@. | test_path_validation.py:5:19:5:25 | After ImportMember | user-provided value | +| test_path_validation.py:74:9:74:58 | After SecretClient() | test_path_validation.py:5:19:5:25 | After ImportMember | test_path_validation.py:74:32:74:34 | url | The full URL of this request depends on a $@. | test_path_validation.py:5:19:5:25 | After ImportMember | user-provided value | +| test_path_validation.py:79:9:79:58 | After SecretClient() | test_path_validation.py:5:19:5:25 | After ImportMember | test_path_validation.py:79:32:79:34 | url | The full URL of this request depends on a $@. | test_path_validation.py:5:19:5:25 | After ImportMember | user-provided value | +| test_path_validation.py:87:9:87:58 | After SecretClient() | test_path_validation.py:5:19:5:25 | After ImportMember | test_path_validation.py:87:32:87:34 | url | The full URL of this request depends on a $@. | test_path_validation.py:5:19:5:25 | After ImportMember | user-provided value | +| test_path_validation.py:90:9:90:58 | After SecretClient() | test_path_validation.py:5:19:5:25 | After ImportMember | test_path_validation.py:90:32:90:34 | url | The full URL of this request depends on a $@. | test_path_validation.py:5:19:5:25 | After ImportMember | user-provided value | +| test_path_validation.py:95:9:95:58 | After SecretClient() | test_path_validation.py:5:19:5:25 | After ImportMember | test_path_validation.py:95:32:95:34 | url | The full URL of this request depends on a $@. | test_path_validation.py:5:19:5:25 | After ImportMember | user-provided value | +| test_path_validation.py:102:9:102:58 | After SecretClient() | test_path_validation.py:5:19:5:25 | After ImportMember | test_path_validation.py:102:32:102:34 | url | The full URL of this request depends on a $@. | test_path_validation.py:5:19:5:25 | After ImportMember | user-provided value | +| test_path_validation.py:107:9:107:58 | After SecretClient() | test_path_validation.py:5:19:5:25 | After ImportMember | test_path_validation.py:107:32:107:34 | url | The full URL of this request depends on a $@. | test_path_validation.py:5:19:5:25 | After ImportMember | user-provided value | +| test_path_validation.py:110:9:110:58 | After SecretClient() | test_path_validation.py:5:19:5:25 | After ImportMember | test_path_validation.py:110:32:110:34 | url | The full URL of this request depends on a $@. | test_path_validation.py:5:19:5:25 | After ImportMember | user-provided value | +| test_path_validation.py:115:9:115:58 | After SecretClient() | test_path_validation.py:5:19:5:25 | After ImportMember | test_path_validation.py:115:32:115:34 | url | The full URL of this request depends on a $@. | test_path_validation.py:5:19:5:25 | After ImportMember | user-provided value | +| test_path_validation.py:122:9:122:58 | After SecretClient() | test_path_validation.py:5:19:5:25 | After ImportMember | test_path_validation.py:122:32:122:34 | url | The full URL of this request depends on a $@. | test_path_validation.py:5:19:5:25 | After ImportMember | user-provided value | +| test_path_validation.py:125:9:125:58 | After SecretClient() | test_path_validation.py:5:19:5:25 | After ImportMember | test_path_validation.py:125:32:125:34 | url | The full URL of this request depends on a $@. | test_path_validation.py:5:19:5:25 | After ImportMember | user-provided value | +| test_path_validation.py:132:9:132:58 | After SecretClient() | test_path_validation.py:5:19:5:25 | After ImportMember | test_path_validation.py:132:32:132:34 | url | The full URL of this request depends on a $@. | test_path_validation.py:5:19:5:25 | After ImportMember | user-provided value | +| test_requests.py:9:5:9:28 | After Attribute() | test_requests.py:1:19:1:25 | After ImportMember | test_requests.py:9:18:9:27 | user_input | The full URL of this request depends on a $@. | test_requests.py:1:19:1:25 | After ImportMember | user-provided value | +| test_requests.py:17:5:17:27 | After Attribute() | test_requests.py:1:19:1:25 | After ImportMember | test_requests.py:17:17:17:26 | user_input | The full URL of this request depends on a $@. | test_requests.py:1:19:1:25 | After ImportMember | user-provided value | +| test_requests.py:22:5:22:44 | After Attribute() | test_requests.py:1:19:1:25 | After ImportMember | test_requests.py:22:34:22:43 | user_input | The full URL of this request depends on a $@. | test_requests.py:1:19:1:25 | After ImportMember | user-provided value | edges -| full_partial_test.py:1:19:1:25 | ControlFlowNode for ImportMember | full_partial_test.py:1:19:1:25 | ControlFlowNode for request | provenance | | -| full_partial_test.py:1:19:1:25 | ControlFlowNode for request | full_partial_test.py:7:18:7:24 | ControlFlowNode for request | provenance | | -| full_partial_test.py:1:19:1:25 | ControlFlowNode for request | full_partial_test.py:41:18:41:24 | ControlFlowNode for request | provenance | | -| full_partial_test.py:1:19:1:25 | ControlFlowNode for request | full_partial_test.py:66:18:66:24 | ControlFlowNode for request | provenance | | -| full_partial_test.py:1:19:1:25 | ControlFlowNode for request | full_partial_test.py:83:18:83:24 | ControlFlowNode for request | provenance | | -| full_partial_test.py:7:5:7:14 | ControlFlowNode for user_input | full_partial_test.py:11:18:11:27 | ControlFlowNode for user_input | provenance | | -| full_partial_test.py:7:5:7:14 | ControlFlowNode for user_input | full_partial_test.py:13:5:13:7 | ControlFlowNode for url | provenance | | -| full_partial_test.py:7:5:7:14 | ControlFlowNode for user_input | full_partial_test.py:20:5:20:7 | ControlFlowNode for url | provenance | | -| full_partial_test.py:7:5:7:14 | ControlFlowNode for user_input | full_partial_test.py:25:5:25:7 | ControlFlowNode for url | provenance | | -| full_partial_test.py:7:18:7:24 | ControlFlowNode for request | full_partial_test.py:7:5:7:14 | ControlFlowNode for user_input | provenance | AdditionalTaintStep | -| full_partial_test.py:13:5:13:7 | ControlFlowNode for url | full_partial_test.py:15:18:15:20 | ControlFlowNode for url | provenance | | -| full_partial_test.py:20:5:20:7 | ControlFlowNode for url | full_partial_test.py:22:18:22:20 | ControlFlowNode for url | provenance | | -| full_partial_test.py:25:5:25:7 | ControlFlowNode for url | full_partial_test.py:27:18:27:20 | ControlFlowNode for url | provenance | | -| full_partial_test.py:41:5:41:14 | ControlFlowNode for user_input | full_partial_test.py:45:5:45:7 | ControlFlowNode for url | provenance | | -| full_partial_test.py:41:5:41:14 | ControlFlowNode for user_input | full_partial_test.py:49:5:49:7 | ControlFlowNode for url | provenance | | -| full_partial_test.py:41:5:41:14 | ControlFlowNode for user_input | full_partial_test.py:53:5:53:7 | ControlFlowNode for url | provenance | | -| full_partial_test.py:41:5:41:14 | ControlFlowNode for user_input | full_partial_test.py:57:5:57:7 | ControlFlowNode for url | provenance | | -| full_partial_test.py:41:5:41:14 | ControlFlowNode for user_input | full_partial_test.py:61:5:61:7 | ControlFlowNode for url | provenance | | -| full_partial_test.py:41:18:41:24 | ControlFlowNode for request | full_partial_test.py:41:5:41:14 | ControlFlowNode for user_input | provenance | AdditionalTaintStep | -| full_partial_test.py:45:5:45:7 | ControlFlowNode for url | full_partial_test.py:47:18:47:20 | ControlFlowNode for url | provenance | | -| full_partial_test.py:49:5:49:7 | ControlFlowNode for url | full_partial_test.py:51:18:51:20 | ControlFlowNode for url | provenance | | -| full_partial_test.py:53:5:53:7 | ControlFlowNode for url | full_partial_test.py:55:18:55:20 | ControlFlowNode for url | provenance | | -| full_partial_test.py:57:5:57:7 | ControlFlowNode for url | full_partial_test.py:59:18:59:20 | ControlFlowNode for url | provenance | | -| full_partial_test.py:61:5:61:7 | ControlFlowNode for url | full_partial_test.py:63:18:63:20 | ControlFlowNode for url | provenance | | -| full_partial_test.py:66:5:66:14 | ControlFlowNode for user_input | full_partial_test.py:70:5:70:7 | ControlFlowNode for url | provenance | | -| full_partial_test.py:66:5:66:14 | ControlFlowNode for user_input | full_partial_test.py:74:5:74:7 | ControlFlowNode for url | provenance | | -| full_partial_test.py:66:18:66:24 | ControlFlowNode for request | full_partial_test.py:66:5:66:14 | ControlFlowNode for user_input | provenance | AdditionalTaintStep | -| full_partial_test.py:70:5:70:7 | ControlFlowNode for url | full_partial_test.py:72:18:72:20 | ControlFlowNode for url | provenance | | -| full_partial_test.py:74:5:74:7 | ControlFlowNode for url | full_partial_test.py:76:18:76:20 | ControlFlowNode for url | provenance | | -| full_partial_test.py:83:5:83:14 | ControlFlowNode for user_input | full_partial_test.py:87:5:87:7 | ControlFlowNode for url | provenance | | -| full_partial_test.py:83:5:83:14 | ControlFlowNode for user_input | full_partial_test.py:91:5:91:7 | ControlFlowNode for url | provenance | | -| full_partial_test.py:83:5:83:14 | ControlFlowNode for user_input | full_partial_test.py:95:5:95:7 | ControlFlowNode for url | provenance | | -| full_partial_test.py:83:18:83:24 | ControlFlowNode for request | full_partial_test.py:83:5:83:14 | ControlFlowNode for user_input | provenance | AdditionalTaintStep | -| full_partial_test.py:87:5:87:7 | ControlFlowNode for url | full_partial_test.py:89:18:89:20 | ControlFlowNode for url | provenance | | -| full_partial_test.py:91:5:91:7 | ControlFlowNode for url | full_partial_test.py:93:18:93:20 | ControlFlowNode for url | provenance | | -| full_partial_test.py:95:5:95:7 | ControlFlowNode for url | full_partial_test.py:97:18:97:20 | ControlFlowNode for url | provenance | | -| test_azure_client.py:6:19:6:25 | ControlFlowNode for ImportMember | test_azure_client.py:6:19:6:25 | ControlFlowNode for request | provenance | | -| test_azure_client.py:6:19:6:25 | ControlFlowNode for request | test_azure_client.py:9:18:9:24 | ControlFlowNode for request | provenance | | -| test_azure_client.py:6:19:6:25 | ControlFlowNode for request | test_azure_client.py:10:19:10:25 | ControlFlowNode for request | provenance | | -| test_azure_client.py:9:18:9:24 | ControlFlowNode for request | test_azure_client.py:10:5:10:15 | ControlFlowNode for user_input2 | provenance | AdditionalTaintStep | -| test_azure_client.py:10:5:10:15 | ControlFlowNode for user_input2 | test_azure_client.py:13:5:13:12 | ControlFlowNode for full_url | provenance | | -| test_azure_client.py:10:19:10:25 | ControlFlowNode for request | test_azure_client.py:10:5:10:15 | ControlFlowNode for user_input2 | provenance | AdditionalTaintStep | -| test_azure_client.py:13:5:13:12 | ControlFlowNode for full_url | test_azure_client.py:16:28:16:35 | ControlFlowNode for full_url | provenance | Sink:MaD:2 | -| test_azure_client.py:13:5:13:12 | ControlFlowNode for full_url | test_azure_client.py:18:35:18:42 | ControlFlowNode for full_url | provenance | Sink:MaD:4 | -| test_azure_client.py:13:5:13:12 | ControlFlowNode for full_url | test_azure_client.py:20:15:20:22 | ControlFlowNode for full_url | provenance | Sink:MaD:1 | -| test_azure_client.py:13:5:13:12 | ControlFlowNode for full_url | test_azure_client.py:22:54:22:61 | ControlFlowNode for full_url | provenance | Sink:MaD:3 | -| test_azure_client.py:13:5:13:12 | ControlFlowNode for full_url | test_azure_client.py:25:37:25:44 | ControlFlowNode for full_url | provenance | Sink:MaD:5 | -| test_http_client.py:1:19:1:25 | ControlFlowNode for ImportMember | test_http_client.py:1:19:1:25 | ControlFlowNode for request | provenance | | -| test_http_client.py:1:19:1:25 | ControlFlowNode for request | test_http_client.py:9:19:9:25 | ControlFlowNode for request | provenance | | -| test_http_client.py:1:19:1:25 | ControlFlowNode for request | test_http_client.py:10:19:10:25 | ControlFlowNode for request | provenance | | -| test_http_client.py:9:5:9:15 | ControlFlowNode for unsafe_host | test_http_client.py:13:27:13:37 | ControlFlowNode for unsafe_host | provenance | | -| test_http_client.py:9:5:9:15 | ControlFlowNode for unsafe_host | test_http_client.py:19:27:19:37 | ControlFlowNode for unsafe_host | provenance | | -| test_http_client.py:9:5:9:15 | ControlFlowNode for unsafe_host | test_http_client.py:28:27:28:37 | ControlFlowNode for unsafe_host | provenance | | -| test_http_client.py:9:19:9:25 | ControlFlowNode for request | test_http_client.py:9:5:9:15 | ControlFlowNode for unsafe_host | provenance | AdditionalTaintStep | -| test_http_client.py:9:19:9:25 | ControlFlowNode for request | test_http_client.py:10:5:10:15 | ControlFlowNode for unsafe_path | provenance | AdditionalTaintStep | -| test_http_client.py:10:5:10:15 | ControlFlowNode for unsafe_path | test_http_client.py:15:25:15:35 | ControlFlowNode for unsafe_path | provenance | | -| test_http_client.py:10:5:10:15 | ControlFlowNode for unsafe_path | test_http_client.py:21:25:21:35 | ControlFlowNode for unsafe_path | provenance | | -| test_http_client.py:10:5:10:15 | ControlFlowNode for unsafe_path | test_http_client.py:34:25:34:35 | ControlFlowNode for unsafe_path | provenance | | -| test_http_client.py:10:19:10:25 | ControlFlowNode for request | test_http_client.py:10:5:10:15 | ControlFlowNode for unsafe_path | provenance | AdditionalTaintStep | -| test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:5:19:5:25 | ControlFlowNode for request | provenance | | -| test_path_validation.py:5:19:5:25 | ControlFlowNode for request | test_path_validation.py:8:18:8:24 | ControlFlowNode for request | provenance | | -| test_path_validation.py:5:19:5:25 | ControlFlowNode for request | test_path_validation.py:9:19:9:25 | ControlFlowNode for request | provenance | | -| test_path_validation.py:5:19:5:25 | ControlFlowNode for request | test_path_validation.py:24:18:24:24 | ControlFlowNode for request | provenance | | -| test_path_validation.py:5:19:5:25 | ControlFlowNode for request | test_path_validation.py:25:19:25:25 | ControlFlowNode for request | provenance | | -| test_path_validation.py:5:19:5:25 | ControlFlowNode for request | test_path_validation.py:40:18:40:24 | ControlFlowNode for request | provenance | | -| test_path_validation.py:5:19:5:25 | ControlFlowNode for request | test_path_validation.py:41:19:41:25 | ControlFlowNode for request | provenance | | -| test_path_validation.py:5:19:5:25 | ControlFlowNode for request | test_path_validation.py:57:18:57:24 | ControlFlowNode for request | provenance | | -| test_path_validation.py:8:18:8:24 | ControlFlowNode for request | test_path_validation.py:9:5:9:15 | ControlFlowNode for user_input2 | provenance | AdditionalTaintStep | -| test_path_validation.py:9:5:9:15 | ControlFlowNode for user_input2 | test_path_validation.py:11:5:11:12 | ControlFlowNode for full_url | provenance | | -| test_path_validation.py:9:19:9:25 | ControlFlowNode for request | test_path_validation.py:9:5:9:15 | ControlFlowNode for user_input2 | provenance | AdditionalTaintStep | -| test_path_validation.py:11:5:11:12 | ControlFlowNode for full_url | test_path_validation.py:21:32:21:39 | ControlFlowNode for full_url | provenance | Sink:MaD:2 | -| test_path_validation.py:24:18:24:24 | ControlFlowNode for request | test_path_validation.py:25:5:25:15 | ControlFlowNode for user_input2 | provenance | AdditionalTaintStep | -| test_path_validation.py:25:5:25:15 | ControlFlowNode for user_input2 | test_path_validation.py:27:5:27:12 | ControlFlowNode for full_url | provenance | | -| test_path_validation.py:25:19:25:25 | ControlFlowNode for request | test_path_validation.py:25:5:25:15 | ControlFlowNode for user_input2 | provenance | AdditionalTaintStep | -| test_path_validation.py:27:5:27:12 | ControlFlowNode for full_url | test_path_validation.py:37:29:37:36 | ControlFlowNode for full_url | provenance | Sink:MaD:1 | -| test_path_validation.py:40:18:40:24 | ControlFlowNode for request | test_path_validation.py:41:5:41:15 | ControlFlowNode for user_input2 | provenance | AdditionalTaintStep | -| test_path_validation.py:41:5:41:15 | ControlFlowNode for user_input2 | test_path_validation.py:43:5:43:12 | ControlFlowNode for full_url | provenance | | -| test_path_validation.py:41:19:41:25 | ControlFlowNode for request | test_path_validation.py:41:5:41:15 | ControlFlowNode for user_input2 | provenance | AdditionalTaintStep | -| test_path_validation.py:43:5:43:12 | ControlFlowNode for full_url | test_path_validation.py:53:39:53:46 | ControlFlowNode for full_url | provenance | Sink:MaD:4 | -| test_path_validation.py:57:5:57:14 | ControlFlowNode for user_input | test_path_validation.py:61:5:61:7 | ControlFlowNode for url | provenance | | -| test_path_validation.py:57:18:57:24 | ControlFlowNode for request | test_path_validation.py:57:5:57:14 | ControlFlowNode for user_input | provenance | AdditionalTaintStep | -| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:64:32:64:34 | ControlFlowNode for url | provenance | Sink:MaD:2 | -| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:71:32:71:34 | ControlFlowNode for url | provenance | Sink:MaD:2 | -| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:74:32:74:34 | ControlFlowNode for url | provenance | Sink:MaD:2 | -| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:79:32:79:34 | ControlFlowNode for url | provenance | Sink:MaD:2 | -| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:87:32:87:34 | ControlFlowNode for url | provenance | Sink:MaD:2 | -| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:90:32:90:34 | ControlFlowNode for url | provenance | Sink:MaD:2 | -| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:95:32:95:34 | ControlFlowNode for url | provenance | Sink:MaD:2 | -| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:102:32:102:34 | ControlFlowNode for url | provenance | Sink:MaD:2 | -| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:107:32:107:34 | ControlFlowNode for url | provenance | Sink:MaD:2 | -| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:110:32:110:34 | ControlFlowNode for url | provenance | Sink:MaD:2 | -| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:115:32:115:34 | ControlFlowNode for url | provenance | Sink:MaD:2 | -| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:122:32:122:34 | ControlFlowNode for url | provenance | Sink:MaD:2 | -| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:125:32:125:34 | ControlFlowNode for url | provenance | Sink:MaD:2 | -| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:132:32:132:34 | ControlFlowNode for url | provenance | Sink:MaD:2 | -| test_requests.py:1:19:1:25 | ControlFlowNode for ImportMember | test_requests.py:1:19:1:25 | ControlFlowNode for request | provenance | | -| test_requests.py:1:19:1:25 | ControlFlowNode for request | test_requests.py:7:18:7:24 | ControlFlowNode for request | provenance | | -| test_requests.py:1:19:1:25 | ControlFlowNode for request | test_requests.py:14:18:14:24 | ControlFlowNode for request | provenance | | -| test_requests.py:1:19:1:25 | ControlFlowNode for request | test_requests.py:20:18:20:24 | ControlFlowNode for request | provenance | | -| test_requests.py:7:5:7:14 | ControlFlowNode for user_input | test_requests.py:9:18:9:27 | ControlFlowNode for user_input | provenance | | -| test_requests.py:7:18:7:24 | ControlFlowNode for request | test_requests.py:7:5:7:14 | ControlFlowNode for user_input | provenance | AdditionalTaintStep | -| test_requests.py:14:5:14:14 | ControlFlowNode for user_input | test_requests.py:17:17:17:26 | ControlFlowNode for user_input | provenance | | -| test_requests.py:14:18:14:24 | ControlFlowNode for request | test_requests.py:14:5:14:14 | ControlFlowNode for user_input | provenance | AdditionalTaintStep | -| test_requests.py:20:5:20:14 | ControlFlowNode for user_input | test_requests.py:22:34:22:43 | ControlFlowNode for user_input | provenance | | -| test_requests.py:20:18:20:24 | ControlFlowNode for request | test_requests.py:20:5:20:14 | ControlFlowNode for user_input | provenance | AdditionalTaintStep | +| full_partial_test.py:1:19:1:25 | After ImportMember | full_partial_test.py:1:19:1:25 | request | provenance | | +| full_partial_test.py:1:19:1:25 | request | full_partial_test.py:7:18:7:24 | request | provenance | | +| full_partial_test.py:1:19:1:25 | request | full_partial_test.py:41:18:41:24 | request | provenance | | +| full_partial_test.py:1:19:1:25 | request | full_partial_test.py:66:18:66:24 | request | provenance | | +| full_partial_test.py:1:19:1:25 | request | full_partial_test.py:83:18:83:24 | request | provenance | | +| full_partial_test.py:7:5:7:14 | user_input | full_partial_test.py:11:18:11:27 | user_input | provenance | | +| full_partial_test.py:7:5:7:14 | user_input | full_partial_test.py:13:5:13:7 | url | provenance | | +| full_partial_test.py:7:5:7:14 | user_input | full_partial_test.py:20:5:20:7 | url | provenance | | +| full_partial_test.py:7:5:7:14 | user_input | full_partial_test.py:25:5:25:7 | url | provenance | | +| full_partial_test.py:7:18:7:24 | request | full_partial_test.py:7:5:7:14 | user_input | provenance | AdditionalTaintStep | +| full_partial_test.py:13:5:13:7 | url | full_partial_test.py:15:18:15:20 | url | provenance | | +| full_partial_test.py:20:5:20:7 | url | full_partial_test.py:22:18:22:20 | url | provenance | | +| full_partial_test.py:25:5:25:7 | url | full_partial_test.py:27:18:27:20 | url | provenance | | +| full_partial_test.py:41:5:41:14 | user_input | full_partial_test.py:45:5:45:7 | url | provenance | | +| full_partial_test.py:41:5:41:14 | user_input | full_partial_test.py:49:5:49:7 | url | provenance | | +| full_partial_test.py:41:5:41:14 | user_input | full_partial_test.py:53:5:53:7 | url | provenance | | +| full_partial_test.py:41:5:41:14 | user_input | full_partial_test.py:57:5:57:7 | url | provenance | | +| full_partial_test.py:41:5:41:14 | user_input | full_partial_test.py:61:5:61:7 | url | provenance | | +| full_partial_test.py:41:18:41:24 | request | full_partial_test.py:41:5:41:14 | user_input | provenance | AdditionalTaintStep | +| full_partial_test.py:45:5:45:7 | url | full_partial_test.py:47:18:47:20 | url | provenance | | +| full_partial_test.py:49:5:49:7 | url | full_partial_test.py:51:18:51:20 | url | provenance | | +| full_partial_test.py:53:5:53:7 | url | full_partial_test.py:55:18:55:20 | url | provenance | | +| full_partial_test.py:57:5:57:7 | url | full_partial_test.py:59:18:59:20 | url | provenance | | +| full_partial_test.py:61:5:61:7 | url | full_partial_test.py:63:18:63:20 | url | provenance | | +| full_partial_test.py:66:5:66:14 | user_input | full_partial_test.py:70:5:70:7 | url | provenance | | +| full_partial_test.py:66:5:66:14 | user_input | full_partial_test.py:74:5:74:7 | url | provenance | | +| full_partial_test.py:66:18:66:24 | request | full_partial_test.py:66:5:66:14 | user_input | provenance | AdditionalTaintStep | +| full_partial_test.py:70:5:70:7 | url | full_partial_test.py:72:18:72:20 | url | provenance | | +| full_partial_test.py:74:5:74:7 | url | full_partial_test.py:76:18:76:20 | url | provenance | | +| full_partial_test.py:83:5:83:14 | user_input | full_partial_test.py:87:5:87:7 | url | provenance | | +| full_partial_test.py:83:5:83:14 | user_input | full_partial_test.py:91:5:91:7 | url | provenance | | +| full_partial_test.py:83:5:83:14 | user_input | full_partial_test.py:95:5:95:7 | url | provenance | | +| full_partial_test.py:83:18:83:24 | request | full_partial_test.py:83:5:83:14 | user_input | provenance | AdditionalTaintStep | +| full_partial_test.py:87:5:87:7 | url | full_partial_test.py:89:18:89:20 | url | provenance | | +| full_partial_test.py:91:5:91:7 | url | full_partial_test.py:93:18:93:20 | url | provenance | | +| full_partial_test.py:95:5:95:7 | url | full_partial_test.py:97:18:97:20 | url | provenance | | +| test_azure_client.py:6:19:6:25 | After ImportMember | test_azure_client.py:6:19:6:25 | request | provenance | | +| test_azure_client.py:6:19:6:25 | request | test_azure_client.py:9:18:9:24 | request | provenance | | +| test_azure_client.py:6:19:6:25 | request | test_azure_client.py:10:19:10:25 | request | provenance | | +| test_azure_client.py:9:18:9:24 | request | test_azure_client.py:10:5:10:15 | user_input2 | provenance | AdditionalTaintStep | +| test_azure_client.py:10:5:10:15 | user_input2 | test_azure_client.py:13:5:13:12 | full_url | provenance | | +| test_azure_client.py:10:19:10:25 | request | test_azure_client.py:10:5:10:15 | user_input2 | provenance | AdditionalTaintStep | +| test_azure_client.py:13:5:13:12 | full_url | test_azure_client.py:16:28:16:35 | full_url | provenance | Sink:MaD:2 | +| test_azure_client.py:13:5:13:12 | full_url | test_azure_client.py:18:35:18:42 | full_url | provenance | Sink:MaD:4 | +| test_azure_client.py:13:5:13:12 | full_url | test_azure_client.py:20:15:20:22 | full_url | provenance | Sink:MaD:1 | +| test_azure_client.py:13:5:13:12 | full_url | test_azure_client.py:22:54:22:61 | full_url | provenance | Sink:MaD:3 | +| test_azure_client.py:13:5:13:12 | full_url | test_azure_client.py:25:37:25:44 | full_url | provenance | Sink:MaD:5 | +| test_http_client.py:1:19:1:25 | After ImportMember | test_http_client.py:1:19:1:25 | request | provenance | | +| test_http_client.py:1:19:1:25 | request | test_http_client.py:9:19:9:25 | request | provenance | | +| test_http_client.py:1:19:1:25 | request | test_http_client.py:10:19:10:25 | request | provenance | | +| test_http_client.py:9:5:9:15 | unsafe_host | test_http_client.py:13:27:13:37 | unsafe_host | provenance | | +| test_http_client.py:9:5:9:15 | unsafe_host | test_http_client.py:19:27:19:37 | unsafe_host | provenance | | +| test_http_client.py:9:5:9:15 | unsafe_host | test_http_client.py:28:27:28:37 | unsafe_host | provenance | | +| test_http_client.py:9:19:9:25 | request | test_http_client.py:9:5:9:15 | unsafe_host | provenance | AdditionalTaintStep | +| test_http_client.py:9:19:9:25 | request | test_http_client.py:10:5:10:15 | unsafe_path | provenance | AdditionalTaintStep | +| test_http_client.py:10:5:10:15 | unsafe_path | test_http_client.py:15:25:15:35 | unsafe_path | provenance | | +| test_http_client.py:10:5:10:15 | unsafe_path | test_http_client.py:21:25:21:35 | unsafe_path | provenance | | +| test_http_client.py:10:5:10:15 | unsafe_path | test_http_client.py:34:25:34:35 | unsafe_path | provenance | | +| test_http_client.py:10:19:10:25 | request | test_http_client.py:10:5:10:15 | unsafe_path | provenance | AdditionalTaintStep | +| test_path_validation.py:5:19:5:25 | After ImportMember | test_path_validation.py:5:19:5:25 | request | provenance | | +| test_path_validation.py:5:19:5:25 | request | test_path_validation.py:8:18:8:24 | request | provenance | | +| test_path_validation.py:5:19:5:25 | request | test_path_validation.py:9:19:9:25 | request | provenance | | +| test_path_validation.py:5:19:5:25 | request | test_path_validation.py:24:18:24:24 | request | provenance | | +| test_path_validation.py:5:19:5:25 | request | test_path_validation.py:25:19:25:25 | request | provenance | | +| test_path_validation.py:5:19:5:25 | request | test_path_validation.py:40:18:40:24 | request | provenance | | +| test_path_validation.py:5:19:5:25 | request | test_path_validation.py:41:19:41:25 | request | provenance | | +| test_path_validation.py:5:19:5:25 | request | test_path_validation.py:57:18:57:24 | request | provenance | | +| test_path_validation.py:8:18:8:24 | request | test_path_validation.py:9:5:9:15 | user_input2 | provenance | AdditionalTaintStep | +| test_path_validation.py:9:5:9:15 | user_input2 | test_path_validation.py:11:5:11:12 | full_url | provenance | | +| test_path_validation.py:9:19:9:25 | request | test_path_validation.py:9:5:9:15 | user_input2 | provenance | AdditionalTaintStep | +| test_path_validation.py:11:5:11:12 | full_url | test_path_validation.py:21:32:21:39 | full_url | provenance | Sink:MaD:2 | +| test_path_validation.py:24:18:24:24 | request | test_path_validation.py:25:5:25:15 | user_input2 | provenance | AdditionalTaintStep | +| test_path_validation.py:25:5:25:15 | user_input2 | test_path_validation.py:27:5:27:12 | full_url | provenance | | +| test_path_validation.py:25:19:25:25 | request | test_path_validation.py:25:5:25:15 | user_input2 | provenance | AdditionalTaintStep | +| test_path_validation.py:27:5:27:12 | full_url | test_path_validation.py:37:29:37:36 | full_url | provenance | Sink:MaD:1 | +| test_path_validation.py:40:18:40:24 | request | test_path_validation.py:41:5:41:15 | user_input2 | provenance | AdditionalTaintStep | +| test_path_validation.py:41:5:41:15 | user_input2 | test_path_validation.py:43:5:43:12 | full_url | provenance | | +| test_path_validation.py:41:19:41:25 | request | test_path_validation.py:41:5:41:15 | user_input2 | provenance | AdditionalTaintStep | +| test_path_validation.py:43:5:43:12 | full_url | test_path_validation.py:53:39:53:46 | full_url | provenance | Sink:MaD:4 | +| test_path_validation.py:57:5:57:14 | user_input | test_path_validation.py:61:5:61:7 | url | provenance | | +| test_path_validation.py:57:18:57:24 | request | test_path_validation.py:57:5:57:14 | user_input | provenance | AdditionalTaintStep | +| test_path_validation.py:61:5:61:7 | url | test_path_validation.py:64:32:64:34 | url | provenance | Sink:MaD:2 | +| test_path_validation.py:61:5:61:7 | url | test_path_validation.py:71:32:71:34 | url | provenance | Sink:MaD:2 | +| test_path_validation.py:61:5:61:7 | url | test_path_validation.py:74:32:74:34 | url | provenance | Sink:MaD:2 | +| test_path_validation.py:61:5:61:7 | url | test_path_validation.py:79:32:79:34 | url | provenance | Sink:MaD:2 | +| test_path_validation.py:61:5:61:7 | url | test_path_validation.py:87:32:87:34 | url | provenance | Sink:MaD:2 | +| test_path_validation.py:61:5:61:7 | url | test_path_validation.py:90:32:90:34 | url | provenance | Sink:MaD:2 | +| test_path_validation.py:61:5:61:7 | url | test_path_validation.py:95:32:95:34 | url | provenance | Sink:MaD:2 | +| test_path_validation.py:61:5:61:7 | url | test_path_validation.py:102:32:102:34 | url | provenance | Sink:MaD:2 | +| test_path_validation.py:61:5:61:7 | url | test_path_validation.py:107:32:107:34 | url | provenance | Sink:MaD:2 | +| test_path_validation.py:61:5:61:7 | url | test_path_validation.py:110:32:110:34 | url | provenance | Sink:MaD:2 | +| test_path_validation.py:61:5:61:7 | url | test_path_validation.py:115:32:115:34 | url | provenance | Sink:MaD:2 | +| test_path_validation.py:61:5:61:7 | url | test_path_validation.py:122:32:122:34 | url | provenance | Sink:MaD:2 | +| test_path_validation.py:61:5:61:7 | url | test_path_validation.py:125:32:125:34 | url | provenance | Sink:MaD:2 | +| test_path_validation.py:61:5:61:7 | url | test_path_validation.py:132:32:132:34 | url | provenance | Sink:MaD:2 | +| test_requests.py:1:19:1:25 | After ImportMember | test_requests.py:1:19:1:25 | request | provenance | | +| test_requests.py:1:19:1:25 | request | test_requests.py:7:18:7:24 | request | provenance | | +| test_requests.py:1:19:1:25 | request | test_requests.py:14:18:14:24 | request | provenance | | +| test_requests.py:1:19:1:25 | request | test_requests.py:20:18:20:24 | request | provenance | | +| test_requests.py:7:5:7:14 | user_input | test_requests.py:9:18:9:27 | user_input | provenance | | +| test_requests.py:7:18:7:24 | request | test_requests.py:7:5:7:14 | user_input | provenance | AdditionalTaintStep | +| test_requests.py:14:5:14:14 | user_input | test_requests.py:17:17:17:26 | user_input | provenance | | +| test_requests.py:14:18:14:24 | request | test_requests.py:14:5:14:14 | user_input | provenance | AdditionalTaintStep | +| test_requests.py:20:5:20:14 | user_input | test_requests.py:22:34:22:43 | user_input | provenance | | +| test_requests.py:20:18:20:24 | request | test_requests.py:20:5:20:14 | user_input | provenance | AdditionalTaintStep | models | 1 | Sink: azure.keyvault.keys.KeyClient!; Call.Argument[0,vault_url:]; request-forgery | | 2 | Sink: azure.keyvault.secrets.SecretClient!; Call.Argument[0,vault_url:]; request-forgery | @@ -155,109 +155,109 @@ models | 4 | Sink: azure.storage.fileshare.ShareFileClient!; Member[from_file_url].Argument[0,file_url:]; request-forgery | | 5 | Sink: azure; Member[storage].Member[blob].Member[download_blob_from_url].Argument[0,blob_url:]; request-forgery | nodes -| full_partial_test.py:1:19:1:25 | ControlFlowNode for ImportMember | semmle.label | ControlFlowNode for ImportMember | -| full_partial_test.py:1:19:1:25 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| full_partial_test.py:7:5:7:14 | ControlFlowNode for user_input | semmle.label | ControlFlowNode for user_input | -| full_partial_test.py:7:18:7:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| full_partial_test.py:11:18:11:27 | ControlFlowNode for user_input | semmle.label | ControlFlowNode for user_input | -| full_partial_test.py:13:5:13:7 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:15:18:15:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:20:5:20:7 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:22:18:22:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:25:5:25:7 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:27:18:27:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:41:5:41:14 | ControlFlowNode for user_input | semmle.label | ControlFlowNode for user_input | -| full_partial_test.py:41:18:41:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| full_partial_test.py:45:5:45:7 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:47:18:47:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:49:5:49:7 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:51:18:51:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:53:5:53:7 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:55:18:55:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:57:5:57:7 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:59:18:59:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:61:5:61:7 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:63:18:63:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:66:5:66:14 | ControlFlowNode for user_input | semmle.label | ControlFlowNode for user_input | -| full_partial_test.py:66:18:66:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| full_partial_test.py:70:5:70:7 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:72:18:72:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:74:5:74:7 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:76:18:76:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:83:5:83:14 | ControlFlowNode for user_input | semmle.label | ControlFlowNode for user_input | -| full_partial_test.py:83:18:83:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| full_partial_test.py:87:5:87:7 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:89:18:89:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:91:5:91:7 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:93:18:93:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:95:5:95:7 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:97:18:97:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_azure_client.py:6:19:6:25 | ControlFlowNode for ImportMember | semmle.label | ControlFlowNode for ImportMember | -| test_azure_client.py:6:19:6:25 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| test_azure_client.py:9:18:9:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| test_azure_client.py:10:5:10:15 | ControlFlowNode for user_input2 | semmle.label | ControlFlowNode for user_input2 | -| test_azure_client.py:10:19:10:25 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| test_azure_client.py:13:5:13:12 | ControlFlowNode for full_url | semmle.label | ControlFlowNode for full_url | -| test_azure_client.py:16:28:16:35 | ControlFlowNode for full_url | semmle.label | ControlFlowNode for full_url | -| test_azure_client.py:18:35:18:42 | ControlFlowNode for full_url | semmle.label | ControlFlowNode for full_url | -| test_azure_client.py:20:15:20:22 | ControlFlowNode for full_url | semmle.label | ControlFlowNode for full_url | -| test_azure_client.py:22:54:22:61 | ControlFlowNode for full_url | semmle.label | ControlFlowNode for full_url | -| test_azure_client.py:25:37:25:44 | ControlFlowNode for full_url | semmle.label | ControlFlowNode for full_url | -| test_http_client.py:1:19:1:25 | ControlFlowNode for ImportMember | semmle.label | ControlFlowNode for ImportMember | -| test_http_client.py:1:19:1:25 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| test_http_client.py:9:5:9:15 | ControlFlowNode for unsafe_host | semmle.label | ControlFlowNode for unsafe_host | -| test_http_client.py:9:19:9:25 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| test_http_client.py:10:5:10:15 | ControlFlowNode for unsafe_path | semmle.label | ControlFlowNode for unsafe_path | -| test_http_client.py:10:19:10:25 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| test_http_client.py:13:27:13:37 | ControlFlowNode for unsafe_host | semmle.label | ControlFlowNode for unsafe_host | -| test_http_client.py:15:25:15:35 | ControlFlowNode for unsafe_path | semmle.label | ControlFlowNode for unsafe_path | -| test_http_client.py:19:27:19:37 | ControlFlowNode for unsafe_host | semmle.label | ControlFlowNode for unsafe_host | -| test_http_client.py:21:25:21:35 | ControlFlowNode for unsafe_path | semmle.label | ControlFlowNode for unsafe_path | -| test_http_client.py:28:27:28:37 | ControlFlowNode for unsafe_host | semmle.label | ControlFlowNode for unsafe_host | -| test_http_client.py:34:25:34:35 | ControlFlowNode for unsafe_path | semmle.label | ControlFlowNode for unsafe_path | -| test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | semmle.label | ControlFlowNode for ImportMember | -| test_path_validation.py:5:19:5:25 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| test_path_validation.py:8:18:8:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| test_path_validation.py:9:5:9:15 | ControlFlowNode for user_input2 | semmle.label | ControlFlowNode for user_input2 | -| test_path_validation.py:9:19:9:25 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| test_path_validation.py:11:5:11:12 | ControlFlowNode for full_url | semmle.label | ControlFlowNode for full_url | -| test_path_validation.py:21:32:21:39 | ControlFlowNode for full_url | semmle.label | ControlFlowNode for full_url | -| test_path_validation.py:24:18:24:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| test_path_validation.py:25:5:25:15 | ControlFlowNode for user_input2 | semmle.label | ControlFlowNode for user_input2 | -| test_path_validation.py:25:19:25:25 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| test_path_validation.py:27:5:27:12 | ControlFlowNode for full_url | semmle.label | ControlFlowNode for full_url | -| test_path_validation.py:37:29:37:36 | ControlFlowNode for full_url | semmle.label | ControlFlowNode for full_url | -| test_path_validation.py:40:18:40:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| test_path_validation.py:41:5:41:15 | ControlFlowNode for user_input2 | semmle.label | ControlFlowNode for user_input2 | -| test_path_validation.py:41:19:41:25 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| test_path_validation.py:43:5:43:12 | ControlFlowNode for full_url | semmle.label | ControlFlowNode for full_url | -| test_path_validation.py:53:39:53:46 | ControlFlowNode for full_url | semmle.label | ControlFlowNode for full_url | -| test_path_validation.py:57:5:57:14 | ControlFlowNode for user_input | semmle.label | ControlFlowNode for user_input | -| test_path_validation.py:57:18:57:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:64:32:64:34 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:71:32:71:34 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:74:32:74:34 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:79:32:79:34 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:87:32:87:34 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:90:32:90:34 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:95:32:95:34 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:102:32:102:34 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:107:32:107:34 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:110:32:110:34 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:115:32:115:34 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:122:32:122:34 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:125:32:125:34 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:132:32:132:34 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_requests.py:1:19:1:25 | ControlFlowNode for ImportMember | semmle.label | ControlFlowNode for ImportMember | -| test_requests.py:1:19:1:25 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| test_requests.py:7:5:7:14 | ControlFlowNode for user_input | semmle.label | ControlFlowNode for user_input | -| test_requests.py:7:18:7:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| test_requests.py:9:18:9:27 | ControlFlowNode for user_input | semmle.label | ControlFlowNode for user_input | -| test_requests.py:14:5:14:14 | ControlFlowNode for user_input | semmle.label | ControlFlowNode for user_input | -| test_requests.py:14:18:14:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| test_requests.py:17:17:17:26 | ControlFlowNode for user_input | semmle.label | ControlFlowNode for user_input | -| test_requests.py:20:5:20:14 | ControlFlowNode for user_input | semmle.label | ControlFlowNode for user_input | -| test_requests.py:20:18:20:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| test_requests.py:22:34:22:43 | ControlFlowNode for user_input | semmle.label | ControlFlowNode for user_input | +| full_partial_test.py:1:19:1:25 | After ImportMember | semmle.label | After ImportMember | +| full_partial_test.py:1:19:1:25 | request | semmle.label | request | +| full_partial_test.py:7:5:7:14 | user_input | semmle.label | user_input | +| full_partial_test.py:7:18:7:24 | request | semmle.label | request | +| full_partial_test.py:11:18:11:27 | user_input | semmle.label | user_input | +| full_partial_test.py:13:5:13:7 | url | semmle.label | url | +| full_partial_test.py:15:18:15:20 | url | semmle.label | url | +| full_partial_test.py:20:5:20:7 | url | semmle.label | url | +| full_partial_test.py:22:18:22:20 | url | semmle.label | url | +| full_partial_test.py:25:5:25:7 | url | semmle.label | url | +| full_partial_test.py:27:18:27:20 | url | semmle.label | url | +| full_partial_test.py:41:5:41:14 | user_input | semmle.label | user_input | +| full_partial_test.py:41:18:41:24 | request | semmle.label | request | +| full_partial_test.py:45:5:45:7 | url | semmle.label | url | +| full_partial_test.py:47:18:47:20 | url | semmle.label | url | +| full_partial_test.py:49:5:49:7 | url | semmle.label | url | +| full_partial_test.py:51:18:51:20 | url | semmle.label | url | +| full_partial_test.py:53:5:53:7 | url | semmle.label | url | +| full_partial_test.py:55:18:55:20 | url | semmle.label | url | +| full_partial_test.py:57:5:57:7 | url | semmle.label | url | +| full_partial_test.py:59:18:59:20 | url | semmle.label | url | +| full_partial_test.py:61:5:61:7 | url | semmle.label | url | +| full_partial_test.py:63:18:63:20 | url | semmle.label | url | +| full_partial_test.py:66:5:66:14 | user_input | semmle.label | user_input | +| full_partial_test.py:66:18:66:24 | request | semmle.label | request | +| full_partial_test.py:70:5:70:7 | url | semmle.label | url | +| full_partial_test.py:72:18:72:20 | url | semmle.label | url | +| full_partial_test.py:74:5:74:7 | url | semmle.label | url | +| full_partial_test.py:76:18:76:20 | url | semmle.label | url | +| full_partial_test.py:83:5:83:14 | user_input | semmle.label | user_input | +| full_partial_test.py:83:18:83:24 | request | semmle.label | request | +| full_partial_test.py:87:5:87:7 | url | semmle.label | url | +| full_partial_test.py:89:18:89:20 | url | semmle.label | url | +| full_partial_test.py:91:5:91:7 | url | semmle.label | url | +| full_partial_test.py:93:18:93:20 | url | semmle.label | url | +| full_partial_test.py:95:5:95:7 | url | semmle.label | url | +| full_partial_test.py:97:18:97:20 | url | semmle.label | url | +| test_azure_client.py:6:19:6:25 | After ImportMember | semmle.label | After ImportMember | +| test_azure_client.py:6:19:6:25 | request | semmle.label | request | +| test_azure_client.py:9:18:9:24 | request | semmle.label | request | +| test_azure_client.py:10:5:10:15 | user_input2 | semmle.label | user_input2 | +| test_azure_client.py:10:19:10:25 | request | semmle.label | request | +| test_azure_client.py:13:5:13:12 | full_url | semmle.label | full_url | +| test_azure_client.py:16:28:16:35 | full_url | semmle.label | full_url | +| test_azure_client.py:18:35:18:42 | full_url | semmle.label | full_url | +| test_azure_client.py:20:15:20:22 | full_url | semmle.label | full_url | +| test_azure_client.py:22:54:22:61 | full_url | semmle.label | full_url | +| test_azure_client.py:25:37:25:44 | full_url | semmle.label | full_url | +| test_http_client.py:1:19:1:25 | After ImportMember | semmle.label | After ImportMember | +| test_http_client.py:1:19:1:25 | request | semmle.label | request | +| test_http_client.py:9:5:9:15 | unsafe_host | semmle.label | unsafe_host | +| test_http_client.py:9:19:9:25 | request | semmle.label | request | +| test_http_client.py:10:5:10:15 | unsafe_path | semmle.label | unsafe_path | +| test_http_client.py:10:19:10:25 | request | semmle.label | request | +| test_http_client.py:13:27:13:37 | unsafe_host | semmle.label | unsafe_host | +| test_http_client.py:15:25:15:35 | unsafe_path | semmle.label | unsafe_path | +| test_http_client.py:19:27:19:37 | unsafe_host | semmle.label | unsafe_host | +| test_http_client.py:21:25:21:35 | unsafe_path | semmle.label | unsafe_path | +| test_http_client.py:28:27:28:37 | unsafe_host | semmle.label | unsafe_host | +| test_http_client.py:34:25:34:35 | unsafe_path | semmle.label | unsafe_path | +| test_path_validation.py:5:19:5:25 | After ImportMember | semmle.label | After ImportMember | +| test_path_validation.py:5:19:5:25 | request | semmle.label | request | +| test_path_validation.py:8:18:8:24 | request | semmle.label | request | +| test_path_validation.py:9:5:9:15 | user_input2 | semmle.label | user_input2 | +| test_path_validation.py:9:19:9:25 | request | semmle.label | request | +| test_path_validation.py:11:5:11:12 | full_url | semmle.label | full_url | +| test_path_validation.py:21:32:21:39 | full_url | semmle.label | full_url | +| test_path_validation.py:24:18:24:24 | request | semmle.label | request | +| test_path_validation.py:25:5:25:15 | user_input2 | semmle.label | user_input2 | +| test_path_validation.py:25:19:25:25 | request | semmle.label | request | +| test_path_validation.py:27:5:27:12 | full_url | semmle.label | full_url | +| test_path_validation.py:37:29:37:36 | full_url | semmle.label | full_url | +| test_path_validation.py:40:18:40:24 | request | semmle.label | request | +| test_path_validation.py:41:5:41:15 | user_input2 | semmle.label | user_input2 | +| test_path_validation.py:41:19:41:25 | request | semmle.label | request | +| test_path_validation.py:43:5:43:12 | full_url | semmle.label | full_url | +| test_path_validation.py:53:39:53:46 | full_url | semmle.label | full_url | +| test_path_validation.py:57:5:57:14 | user_input | semmle.label | user_input | +| test_path_validation.py:57:18:57:24 | request | semmle.label | request | +| test_path_validation.py:61:5:61:7 | url | semmle.label | url | +| test_path_validation.py:64:32:64:34 | url | semmle.label | url | +| test_path_validation.py:71:32:71:34 | url | semmle.label | url | +| test_path_validation.py:74:32:74:34 | url | semmle.label | url | +| test_path_validation.py:79:32:79:34 | url | semmle.label | url | +| test_path_validation.py:87:32:87:34 | url | semmle.label | url | +| test_path_validation.py:90:32:90:34 | url | semmle.label | url | +| test_path_validation.py:95:32:95:34 | url | semmle.label | url | +| test_path_validation.py:102:32:102:34 | url | semmle.label | url | +| test_path_validation.py:107:32:107:34 | url | semmle.label | url | +| test_path_validation.py:110:32:110:34 | url | semmle.label | url | +| test_path_validation.py:115:32:115:34 | url | semmle.label | url | +| test_path_validation.py:122:32:122:34 | url | semmle.label | url | +| test_path_validation.py:125:32:125:34 | url | semmle.label | url | +| test_path_validation.py:132:32:132:34 | url | semmle.label | url | +| test_requests.py:1:19:1:25 | After ImportMember | semmle.label | After ImportMember | +| test_requests.py:1:19:1:25 | request | semmle.label | request | +| test_requests.py:7:5:7:14 | user_input | semmle.label | user_input | +| test_requests.py:7:18:7:24 | request | semmle.label | request | +| test_requests.py:9:18:9:27 | user_input | semmle.label | user_input | +| test_requests.py:14:5:14:14 | user_input | semmle.label | user_input | +| test_requests.py:14:18:14:24 | request | semmle.label | request | +| test_requests.py:17:17:17:26 | user_input | semmle.label | user_input | +| test_requests.py:20:5:20:14 | user_input | semmle.label | user_input | +| test_requests.py:20:18:20:24 | request | semmle.label | request | +| test_requests.py:22:34:22:43 | user_input | semmle.label | user_input | subpaths diff --git a/python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/PartialServerSideRequestForgery.expected b/python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/PartialServerSideRequestForgery.expected index a8d907793129..c6f2fe014113 100644 --- a/python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/PartialServerSideRequestForgery.expected +++ b/python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/PartialServerSideRequestForgery.expected @@ -1,241 +1,236 @@ #select -| full_partial_test.py:80:5:80:21 | ControlFlowNode for Attribute() | full_partial_test.py:1:19:1:25 | ControlFlowNode for ImportMember | full_partial_test.py:80:18:80:20 | ControlFlowNode for url | Part of the URL of this request depends on a $@. | full_partial_test.py:1:19:1:25 | ControlFlowNode for ImportMember | user-provided value | -| full_partial_test.py:105:5:105:21 | ControlFlowNode for Attribute() | full_partial_test.py:1:19:1:25 | ControlFlowNode for ImportMember | full_partial_test.py:105:18:105:20 | ControlFlowNode for url | Part of the URL of this request depends on a $@. | full_partial_test.py:1:19:1:25 | ControlFlowNode for ImportMember | user-provided value | -| full_partial_test.py:112:5:112:21 | ControlFlowNode for Attribute() | full_partial_test.py:1:19:1:25 | ControlFlowNode for ImportMember | full_partial_test.py:112:18:112:20 | ControlFlowNode for url | Part of the URL of this request depends on a $@. | full_partial_test.py:1:19:1:25 | ControlFlowNode for ImportMember | user-provided value | -| full_partial_test.py:119:5:119:21 | ControlFlowNode for Attribute() | full_partial_test.py:1:19:1:25 | ControlFlowNode for ImportMember | full_partial_test.py:119:18:119:20 | ControlFlowNode for url | Part of the URL of this request depends on a $@. | full_partial_test.py:1:19:1:25 | ControlFlowNode for ImportMember | user-provided value | -| full_partial_test.py:126:5:126:21 | ControlFlowNode for Attribute() | full_partial_test.py:1:19:1:25 | ControlFlowNode for ImportMember | full_partial_test.py:126:18:126:20 | ControlFlowNode for url | Part of the URL of this request depends on a $@. | full_partial_test.py:1:19:1:25 | ControlFlowNode for ImportMember | user-provided value | -| full_partial_test.py:136:5:136:21 | ControlFlowNode for Attribute() | full_partial_test.py:1:19:1:25 | ControlFlowNode for ImportMember | full_partial_test.py:136:18:136:20 | ControlFlowNode for url | Part of the URL of this request depends on a $@. | full_partial_test.py:1:19:1:25 | ControlFlowNode for ImportMember | user-provided value | -| full_partial_test.py:143:5:143:21 | ControlFlowNode for Attribute() | full_partial_test.py:1:19:1:25 | ControlFlowNode for ImportMember | full_partial_test.py:143:18:143:20 | ControlFlowNode for url | Part of the URL of this request depends on a $@. | full_partial_test.py:1:19:1:25 | ControlFlowNode for ImportMember | user-provided value | -| test_azure_client.py:15:5:15:54 | ControlFlowNode for SecretClient() | test_azure_client.py:6:19:6:25 | ControlFlowNode for ImportMember | test_azure_client.py:15:28:15:30 | ControlFlowNode for url | Part of the URL of this request depends on a $@. | test_azure_client.py:6:19:6:25 | ControlFlowNode for ImportMember | user-provided value | -| test_azure_client.py:17:5:17:38 | ControlFlowNode for Attribute() | test_azure_client.py:6:19:6:25 | ControlFlowNode for ImportMember | test_azure_client.py:17:35:17:37 | ControlFlowNode for url | Part of the URL of this request depends on a $@. | test_azure_client.py:6:19:6:25 | ControlFlowNode for ImportMember | user-provided value | -| test_azure_client.py:19:5:19:30 | ControlFlowNode for KeyClient() | test_azure_client.py:6:19:6:25 | ControlFlowNode for ImportMember | test_azure_client.py:19:15:19:17 | ControlFlowNode for url | Part of the URL of this request depends on a $@. | test_azure_client.py:6:19:6:25 | ControlFlowNode for ImportMember | user-provided value | -| test_azure_client.py:21:5:21:80 | ControlFlowNode for Attribute() | test_azure_client.py:6:19:6:25 | ControlFlowNode for ImportMember | test_azure_client.py:21:54:21:56 | ControlFlowNode for url | Part of the URL of this request depends on a $@. | test_azure_client.py:6:19:6:25 | ControlFlowNode for ImportMember | user-provided value | -| test_azure_client.py:24:5:24:100 | ControlFlowNode for download_blob_from_url() | test_azure_client.py:6:19:6:25 | ControlFlowNode for ImportMember | test_azure_client.py:24:37:24:39 | ControlFlowNode for url | Part of the URL of this request depends on a $@. | test_azure_client.py:6:19:6:25 | ControlFlowNode for ImportMember | user-provided value | -| test_http_client.py:25:5:25:31 | ControlFlowNode for Attribute() | test_http_client.py:1:19:1:25 | ControlFlowNode for ImportMember | test_http_client.py:19:27:19:37 | ControlFlowNode for unsafe_host | Part of the URL of this request depends on a $@. | test_http_client.py:1:19:1:25 | ControlFlowNode for ImportMember | user-provided value | -| test_http_client.py:30:5:30:31 | ControlFlowNode for Attribute() | test_http_client.py:1:19:1:25 | ControlFlowNode for ImportMember | test_http_client.py:28:27:28:37 | ControlFlowNode for unsafe_host | Part of the URL of this request depends on a $@. | test_http_client.py:1:19:1:25 | ControlFlowNode for ImportMember | user-provided value | -| test_http_client.py:34:5:34:36 | ControlFlowNode for Attribute() | test_http_client.py:1:19:1:25 | ControlFlowNode for ImportMember | test_http_client.py:34:25:34:35 | ControlFlowNode for unsafe_path | Part of the URL of this request depends on a $@. | test_http_client.py:1:19:1:25 | ControlFlowNode for ImportMember | user-provided value | -| test_http_client.py:39:5:39:29 | ControlFlowNode for Attribute() | test_http_client.py:1:19:1:25 | ControlFlowNode for ImportMember | test_http_client.py:39:25:39:28 | ControlFlowNode for path | Part of the URL of this request depends on a $@. | test_http_client.py:1:19:1:25 | ControlFlowNode for ImportMember | user-provided value | -| test_http_client.py:44:5:44:29 | ControlFlowNode for Attribute() | test_http_client.py:1:19:1:25 | ControlFlowNode for ImportMember | test_http_client.py:44:25:44:28 | ControlFlowNode for path | Part of the URL of this request depends on a $@. | test_http_client.py:1:19:1:25 | ControlFlowNode for ImportMember | user-provided value | -| test_path_validation.py:14:9:14:58 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:14:32:14:34 | ControlFlowNode for url | Part of the URL of this request depends on a $@. | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | user-provided value | -| test_path_validation.py:16:9:16:58 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:16:32:16:34 | ControlFlowNode for url | Part of the URL of this request depends on a $@. | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | user-provided value | -| test_path_validation.py:19:9:19:63 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:19:32:19:39 | ControlFlowNode for full_url | Part of the URL of this request depends on a $@. | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | user-provided value | -| test_path_validation.py:30:9:30:55 | ControlFlowNode for KeyClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:30:29:30:31 | ControlFlowNode for url | Part of the URL of this request depends on a $@. | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | user-provided value | -| test_path_validation.py:32:9:32:55 | ControlFlowNode for KeyClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:32:29:32:31 | ControlFlowNode for url | Part of the URL of this request depends on a $@. | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | user-provided value | -| test_path_validation.py:35:9:35:60 | ControlFlowNode for KeyClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:35:29:35:36 | ControlFlowNode for full_url | Part of the URL of this request depends on a $@. | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | user-provided value | -| test_path_validation.py:46:9:46:42 | ControlFlowNode for Attribute() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:46:39:46:41 | ControlFlowNode for url | Part of the URL of this request depends on a $@. | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | user-provided value | -| test_path_validation.py:48:9:48:42 | ControlFlowNode for Attribute() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:48:39:48:41 | ControlFlowNode for url | Part of the URL of this request depends on a $@. | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | user-provided value | -| test_path_validation.py:51:9:51:47 | ControlFlowNode for Attribute() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:51:39:51:46 | ControlFlowNode for full_url | Part of the URL of this request depends on a $@. | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | user-provided value | -| test_path_validation.py:66:9:66:58 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:66:32:66:34 | ControlFlowNode for url | Part of the URL of this request depends on a $@. | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | user-provided value | -| test_path_validation.py:69:9:69:58 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:69:32:69:34 | ControlFlowNode for url | Part of the URL of this request depends on a $@. | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | user-provided value | -| test_path_validation.py:76:9:76:58 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:76:32:76:34 | ControlFlowNode for url | Part of the URL of this request depends on a $@. | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | user-provided value | -| test_path_validation.py:81:9:81:58 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:81:32:81:34 | ControlFlowNode for url | Part of the URL of this request depends on a $@. | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | user-provided value | -| test_path_validation.py:85:9:85:58 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:85:32:85:34 | ControlFlowNode for url | Part of the URL of this request depends on a $@. | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | user-provided value | -| test_path_validation.py:92:9:92:58 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:92:32:92:34 | ControlFlowNode for url | Part of the URL of this request depends on a $@. | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | user-provided value | -| test_path_validation.py:97:9:97:58 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:97:32:97:34 | ControlFlowNode for url | Part of the URL of this request depends on a $@. | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | user-provided value | -| test_path_validation.py:100:9:100:58 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:100:32:100:34 | ControlFlowNode for url | Part of the URL of this request depends on a $@. | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | user-provided value | -| test_path_validation.py:105:9:105:58 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:105:32:105:34 | ControlFlowNode for url | Part of the URL of this request depends on a $@. | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | user-provided value | -| test_path_validation.py:112:9:112:58 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:112:32:112:34 | ControlFlowNode for url | Part of the URL of this request depends on a $@. | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | user-provided value | -| test_path_validation.py:117:9:117:58 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:117:32:117:34 | ControlFlowNode for url | Part of the URL of this request depends on a $@. | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | user-provided value | -| test_path_validation.py:120:9:120:58 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:120:32:120:34 | ControlFlowNode for url | Part of the URL of this request depends on a $@. | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | user-provided value | -| test_path_validation.py:127:9:127:58 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:127:32:127:34 | ControlFlowNode for url | Part of the URL of this request depends on a $@. | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | user-provided value | -| test_path_validation.py:130:9:130:58 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:130:32:130:34 | ControlFlowNode for url | Part of the URL of this request depends on a $@. | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | user-provided value | +| full_partial_test.py:80:5:80:21 | After Attribute() | full_partial_test.py:1:19:1:25 | After ImportMember | full_partial_test.py:80:18:80:20 | url | Part of the URL of this request depends on a $@. | full_partial_test.py:1:19:1:25 | After ImportMember | user-provided value | +| full_partial_test.py:105:5:105:21 | After Attribute() | full_partial_test.py:1:19:1:25 | After ImportMember | full_partial_test.py:105:18:105:20 | url | Part of the URL of this request depends on a $@. | full_partial_test.py:1:19:1:25 | After ImportMember | user-provided value | +| full_partial_test.py:112:5:112:21 | After Attribute() | full_partial_test.py:1:19:1:25 | After ImportMember | full_partial_test.py:112:18:112:20 | url | Part of the URL of this request depends on a $@. | full_partial_test.py:1:19:1:25 | After ImportMember | user-provided value | +| full_partial_test.py:119:5:119:21 | After Attribute() | full_partial_test.py:1:19:1:25 | After ImportMember | full_partial_test.py:119:18:119:20 | url | Part of the URL of this request depends on a $@. | full_partial_test.py:1:19:1:25 | After ImportMember | user-provided value | +| full_partial_test.py:126:5:126:21 | After Attribute() | full_partial_test.py:1:19:1:25 | After ImportMember | full_partial_test.py:126:18:126:20 | url | Part of the URL of this request depends on a $@. | full_partial_test.py:1:19:1:25 | After ImportMember | user-provided value | +| full_partial_test.py:136:5:136:21 | After Attribute() | full_partial_test.py:1:19:1:25 | After ImportMember | full_partial_test.py:136:18:136:20 | url | Part of the URL of this request depends on a $@. | full_partial_test.py:1:19:1:25 | After ImportMember | user-provided value | +| full_partial_test.py:143:5:143:21 | After Attribute() | full_partial_test.py:1:19:1:25 | After ImportMember | full_partial_test.py:143:18:143:20 | url | Part of the URL of this request depends on a $@. | full_partial_test.py:1:19:1:25 | After ImportMember | user-provided value | +| test_azure_client.py:15:5:15:54 | After SecretClient() | test_azure_client.py:6:19:6:25 | After ImportMember | test_azure_client.py:15:28:15:30 | url | Part of the URL of this request depends on a $@. | test_azure_client.py:6:19:6:25 | After ImportMember | user-provided value | +| test_azure_client.py:17:5:17:38 | After Attribute() | test_azure_client.py:6:19:6:25 | After ImportMember | test_azure_client.py:17:35:17:37 | url | Part of the URL of this request depends on a $@. | test_azure_client.py:6:19:6:25 | After ImportMember | user-provided value | +| test_azure_client.py:19:5:19:30 | After KeyClient() | test_azure_client.py:6:19:6:25 | After ImportMember | test_azure_client.py:19:15:19:17 | url | Part of the URL of this request depends on a $@. | test_azure_client.py:6:19:6:25 | After ImportMember | user-provided value | +| test_azure_client.py:21:5:21:80 | After Attribute() | test_azure_client.py:6:19:6:25 | After ImportMember | test_azure_client.py:21:54:21:56 | url | Part of the URL of this request depends on a $@. | test_azure_client.py:6:19:6:25 | After ImportMember | user-provided value | +| test_azure_client.py:24:5:24:100 | After download_blob_from_url() | test_azure_client.py:6:19:6:25 | After ImportMember | test_azure_client.py:24:37:24:39 | url | Part of the URL of this request depends on a $@. | test_azure_client.py:6:19:6:25 | After ImportMember | user-provided value | +| test_http_client.py:25:5:25:31 | After Attribute() | test_http_client.py:1:19:1:25 | After ImportMember | test_http_client.py:19:27:19:37 | unsafe_host | Part of the URL of this request depends on a $@. | test_http_client.py:1:19:1:25 | After ImportMember | user-provided value | +| test_http_client.py:30:5:30:31 | After Attribute() | test_http_client.py:1:19:1:25 | After ImportMember | test_http_client.py:28:27:28:37 | unsafe_host | Part of the URL of this request depends on a $@. | test_http_client.py:1:19:1:25 | After ImportMember | user-provided value | +| test_http_client.py:34:5:34:36 | After Attribute() | test_http_client.py:1:19:1:25 | After ImportMember | test_http_client.py:34:25:34:35 | unsafe_path | Part of the URL of this request depends on a $@. | test_http_client.py:1:19:1:25 | After ImportMember | user-provided value | +| test_http_client.py:39:5:39:29 | After Attribute() | test_http_client.py:1:19:1:25 | After ImportMember | test_http_client.py:39:25:39:28 | path | Part of the URL of this request depends on a $@. | test_http_client.py:1:19:1:25 | After ImportMember | user-provided value | +| test_http_client.py:44:5:44:29 | After Attribute() | test_http_client.py:1:19:1:25 | After ImportMember | test_http_client.py:44:25:44:28 | path | Part of the URL of this request depends on a $@. | test_http_client.py:1:19:1:25 | After ImportMember | user-provided value | +| test_path_validation.py:14:9:14:58 | After SecretClient() | test_path_validation.py:5:19:5:25 | After ImportMember | test_path_validation.py:14:32:14:34 | url | Part of the URL of this request depends on a $@. | test_path_validation.py:5:19:5:25 | After ImportMember | user-provided value | +| test_path_validation.py:16:9:16:58 | After SecretClient() | test_path_validation.py:5:19:5:25 | After ImportMember | test_path_validation.py:16:32:16:34 | url | Part of the URL of this request depends on a $@. | test_path_validation.py:5:19:5:25 | After ImportMember | user-provided value | +| test_path_validation.py:19:9:19:63 | After SecretClient() | test_path_validation.py:5:19:5:25 | After ImportMember | test_path_validation.py:19:32:19:39 | full_url | Part of the URL of this request depends on a $@. | test_path_validation.py:5:19:5:25 | After ImportMember | user-provided value | +| test_path_validation.py:30:9:30:55 | After KeyClient() | test_path_validation.py:5:19:5:25 | After ImportMember | test_path_validation.py:30:29:30:31 | url | Part of the URL of this request depends on a $@. | test_path_validation.py:5:19:5:25 | After ImportMember | user-provided value | +| test_path_validation.py:32:9:32:55 | After KeyClient() | test_path_validation.py:5:19:5:25 | After ImportMember | test_path_validation.py:32:29:32:31 | url | Part of the URL of this request depends on a $@. | test_path_validation.py:5:19:5:25 | After ImportMember | user-provided value | +| test_path_validation.py:35:9:35:60 | After KeyClient() | test_path_validation.py:5:19:5:25 | After ImportMember | test_path_validation.py:35:29:35:36 | full_url | Part of the URL of this request depends on a $@. | test_path_validation.py:5:19:5:25 | After ImportMember | user-provided value | +| test_path_validation.py:46:9:46:42 | After Attribute() | test_path_validation.py:5:19:5:25 | After ImportMember | test_path_validation.py:46:39:46:41 | url | Part of the URL of this request depends on a $@. | test_path_validation.py:5:19:5:25 | After ImportMember | user-provided value | +| test_path_validation.py:48:9:48:42 | After Attribute() | test_path_validation.py:5:19:5:25 | After ImportMember | test_path_validation.py:48:39:48:41 | url | Part of the URL of this request depends on a $@. | test_path_validation.py:5:19:5:25 | After ImportMember | user-provided value | +| test_path_validation.py:51:9:51:47 | After Attribute() | test_path_validation.py:5:19:5:25 | After ImportMember | test_path_validation.py:51:39:51:46 | full_url | Part of the URL of this request depends on a $@. | test_path_validation.py:5:19:5:25 | After ImportMember | user-provided value | +| test_path_validation.py:66:9:66:58 | After SecretClient() | test_path_validation.py:5:19:5:25 | After ImportMember | test_path_validation.py:66:32:66:34 | url | Part of the URL of this request depends on a $@. | test_path_validation.py:5:19:5:25 | After ImportMember | user-provided value | +| test_path_validation.py:69:9:69:58 | After SecretClient() | test_path_validation.py:5:19:5:25 | After ImportMember | test_path_validation.py:69:32:69:34 | url | Part of the URL of this request depends on a $@. | test_path_validation.py:5:19:5:25 | After ImportMember | user-provided value | +| test_path_validation.py:76:9:76:58 | After SecretClient() | test_path_validation.py:5:19:5:25 | After ImportMember | test_path_validation.py:76:32:76:34 | url | Part of the URL of this request depends on a $@. | test_path_validation.py:5:19:5:25 | After ImportMember | user-provided value | +| test_path_validation.py:81:9:81:58 | After SecretClient() | test_path_validation.py:5:19:5:25 | After ImportMember | test_path_validation.py:81:32:81:34 | url | Part of the URL of this request depends on a $@. | test_path_validation.py:5:19:5:25 | After ImportMember | user-provided value | +| test_path_validation.py:85:9:85:58 | After SecretClient() | test_path_validation.py:5:19:5:25 | After ImportMember | test_path_validation.py:85:32:85:34 | url | Part of the URL of this request depends on a $@. | test_path_validation.py:5:19:5:25 | After ImportMember | user-provided value | +| test_path_validation.py:92:9:92:58 | After SecretClient() | test_path_validation.py:5:19:5:25 | After ImportMember | test_path_validation.py:92:32:92:34 | url | Part of the URL of this request depends on a $@. | test_path_validation.py:5:19:5:25 | After ImportMember | user-provided value | +| test_path_validation.py:97:9:97:58 | After SecretClient() | test_path_validation.py:5:19:5:25 | After ImportMember | test_path_validation.py:97:32:97:34 | url | Part of the URL of this request depends on a $@. | test_path_validation.py:5:19:5:25 | After ImportMember | user-provided value | +| test_path_validation.py:100:9:100:58 | After SecretClient() | test_path_validation.py:5:19:5:25 | After ImportMember | test_path_validation.py:100:32:100:34 | url | Part of the URL of this request depends on a $@. | test_path_validation.py:5:19:5:25 | After ImportMember | user-provided value | +| test_path_validation.py:105:9:105:58 | After SecretClient() | test_path_validation.py:5:19:5:25 | After ImportMember | test_path_validation.py:105:32:105:34 | url | Part of the URL of this request depends on a $@. | test_path_validation.py:5:19:5:25 | After ImportMember | user-provided value | +| test_path_validation.py:112:9:112:58 | After SecretClient() | test_path_validation.py:5:19:5:25 | After ImportMember | test_path_validation.py:112:32:112:34 | url | Part of the URL of this request depends on a $@. | test_path_validation.py:5:19:5:25 | After ImportMember | user-provided value | +| test_path_validation.py:117:9:117:58 | After SecretClient() | test_path_validation.py:5:19:5:25 | After ImportMember | test_path_validation.py:117:32:117:34 | url | Part of the URL of this request depends on a $@. | test_path_validation.py:5:19:5:25 | After ImportMember | user-provided value | +| test_path_validation.py:120:9:120:58 | After SecretClient() | test_path_validation.py:5:19:5:25 | After ImportMember | test_path_validation.py:120:32:120:34 | url | Part of the URL of this request depends on a $@. | test_path_validation.py:5:19:5:25 | After ImportMember | user-provided value | +| test_path_validation.py:127:9:127:58 | After SecretClient() | test_path_validation.py:5:19:5:25 | After ImportMember | test_path_validation.py:127:32:127:34 | url | Part of the URL of this request depends on a $@. | test_path_validation.py:5:19:5:25 | After ImportMember | user-provided value | +| test_path_validation.py:130:9:130:58 | After SecretClient() | test_path_validation.py:5:19:5:25 | After ImportMember | test_path_validation.py:130:32:130:34 | url | Part of the URL of this request depends on a $@. | test_path_validation.py:5:19:5:25 | After ImportMember | user-provided value | edges -| full_partial_test.py:1:19:1:25 | ControlFlowNode for ImportMember | full_partial_test.py:1:19:1:25 | ControlFlowNode for request | provenance | | -| full_partial_test.py:1:19:1:25 | ControlFlowNode for request | full_partial_test.py:7:18:7:24 | ControlFlowNode for request | provenance | | -| full_partial_test.py:1:19:1:25 | ControlFlowNode for request | full_partial_test.py:8:17:8:23 | ControlFlowNode for request | provenance | | -| full_partial_test.py:1:19:1:25 | ControlFlowNode for request | full_partial_test.py:41:18:41:24 | ControlFlowNode for request | provenance | | -| full_partial_test.py:1:19:1:25 | ControlFlowNode for request | full_partial_test.py:42:17:42:23 | ControlFlowNode for request | provenance | | -| full_partial_test.py:1:19:1:25 | ControlFlowNode for request | full_partial_test.py:66:18:66:24 | ControlFlowNode for request | provenance | | -| full_partial_test.py:1:19:1:25 | ControlFlowNode for request | full_partial_test.py:67:17:67:23 | ControlFlowNode for request | provenance | | -| full_partial_test.py:1:19:1:25 | ControlFlowNode for request | full_partial_test.py:83:18:83:24 | ControlFlowNode for request | provenance | | -| full_partial_test.py:1:19:1:25 | ControlFlowNode for request | full_partial_test.py:84:17:84:23 | ControlFlowNode for request | provenance | | -| full_partial_test.py:1:19:1:25 | ControlFlowNode for request | full_partial_test.py:101:18:101:24 | ControlFlowNode for request | provenance | | -| full_partial_test.py:1:19:1:25 | ControlFlowNode for request | full_partial_test.py:108:18:108:24 | ControlFlowNode for request | provenance | | -| full_partial_test.py:1:19:1:25 | ControlFlowNode for request | full_partial_test.py:115:18:115:24 | ControlFlowNode for request | provenance | | -| full_partial_test.py:1:19:1:25 | ControlFlowNode for request | full_partial_test.py:122:18:122:24 | ControlFlowNode for request | provenance | | -| full_partial_test.py:1:19:1:25 | ControlFlowNode for request | full_partial_test.py:129:18:129:24 | ControlFlowNode for request | provenance | | -| full_partial_test.py:1:19:1:25 | ControlFlowNode for request | full_partial_test.py:139:18:139:24 | ControlFlowNode for request | provenance | | -| full_partial_test.py:7:5:7:14 | ControlFlowNode for user_input | full_partial_test.py:11:18:11:27 | ControlFlowNode for user_input | provenance | | -| full_partial_test.py:7:5:7:14 | ControlFlowNode for user_input | full_partial_test.py:13:5:13:7 | ControlFlowNode for url | provenance | | -| full_partial_test.py:7:5:7:14 | ControlFlowNode for user_input | full_partial_test.py:20:5:20:7 | ControlFlowNode for url | provenance | | -| full_partial_test.py:7:5:7:14 | ControlFlowNode for user_input | full_partial_test.py:25:5:25:7 | ControlFlowNode for url | provenance | | -| full_partial_test.py:7:18:7:24 | ControlFlowNode for request | full_partial_test.py:7:5:7:14 | ControlFlowNode for user_input | provenance | AdditionalTaintStep | -| full_partial_test.py:7:18:7:24 | ControlFlowNode for request | full_partial_test.py:8:5:8:13 | ControlFlowNode for query_val | provenance | AdditionalTaintStep | -| full_partial_test.py:8:5:8:13 | ControlFlowNode for query_val | full_partial_test.py:25:5:25:7 | ControlFlowNode for url | provenance | | -| full_partial_test.py:8:17:8:23 | ControlFlowNode for request | full_partial_test.py:8:5:8:13 | ControlFlowNode for query_val | provenance | AdditionalTaintStep | -| full_partial_test.py:13:5:13:7 | ControlFlowNode for url | full_partial_test.py:15:18:15:20 | ControlFlowNode for url | provenance | | -| full_partial_test.py:20:5:20:7 | ControlFlowNode for url | full_partial_test.py:22:18:22:20 | ControlFlowNode for url | provenance | | -| full_partial_test.py:25:5:25:7 | ControlFlowNode for url | full_partial_test.py:27:18:27:20 | ControlFlowNode for url | provenance | | -| full_partial_test.py:41:5:41:14 | ControlFlowNode for user_input | full_partial_test.py:45:5:45:7 | ControlFlowNode for url | provenance | | -| full_partial_test.py:41:5:41:14 | ControlFlowNode for user_input | full_partial_test.py:49:5:49:7 | ControlFlowNode for url | provenance | | -| full_partial_test.py:41:5:41:14 | ControlFlowNode for user_input | full_partial_test.py:53:5:53:7 | ControlFlowNode for url | provenance | | -| full_partial_test.py:41:5:41:14 | ControlFlowNode for user_input | full_partial_test.py:57:5:57:7 | ControlFlowNode for url | provenance | | -| full_partial_test.py:41:5:41:14 | ControlFlowNode for user_input | full_partial_test.py:61:5:61:7 | ControlFlowNode for url | provenance | | -| full_partial_test.py:41:18:41:24 | ControlFlowNode for request | full_partial_test.py:41:5:41:14 | ControlFlowNode for user_input | provenance | AdditionalTaintStep | -| full_partial_test.py:41:18:41:24 | ControlFlowNode for request | full_partial_test.py:42:5:42:13 | ControlFlowNode for query_val | provenance | AdditionalTaintStep | -| full_partial_test.py:42:5:42:13 | ControlFlowNode for query_val | full_partial_test.py:53:5:53:7 | ControlFlowNode for url | provenance | | -| full_partial_test.py:42:17:42:23 | ControlFlowNode for request | full_partial_test.py:42:5:42:13 | ControlFlowNode for query_val | provenance | AdditionalTaintStep | -| full_partial_test.py:45:5:45:7 | ControlFlowNode for url | full_partial_test.py:47:18:47:20 | ControlFlowNode for url | provenance | | -| full_partial_test.py:49:5:49:7 | ControlFlowNode for url | full_partial_test.py:51:18:51:20 | ControlFlowNode for url | provenance | | -| full_partial_test.py:53:5:53:7 | ControlFlowNode for url | full_partial_test.py:55:18:55:20 | ControlFlowNode for url | provenance | | -| full_partial_test.py:57:5:57:7 | ControlFlowNode for url | full_partial_test.py:59:18:59:20 | ControlFlowNode for url | provenance | | -| full_partial_test.py:61:5:61:7 | ControlFlowNode for url | full_partial_test.py:63:18:63:20 | ControlFlowNode for url | provenance | | -| full_partial_test.py:66:5:66:14 | ControlFlowNode for user_input | full_partial_test.py:70:5:70:7 | ControlFlowNode for url | provenance | | -| full_partial_test.py:66:5:66:14 | ControlFlowNode for user_input | full_partial_test.py:74:5:74:7 | ControlFlowNode for url | provenance | | -| full_partial_test.py:66:5:66:14 | ControlFlowNode for user_input | full_partial_test.py:78:38:78:47 | ControlFlowNode for user_input | provenance | | -| full_partial_test.py:66:18:66:24 | ControlFlowNode for request | full_partial_test.py:66:5:66:14 | ControlFlowNode for user_input | provenance | AdditionalTaintStep | -| full_partial_test.py:66:18:66:24 | ControlFlowNode for request | full_partial_test.py:67:5:67:13 | ControlFlowNode for query_val | provenance | AdditionalTaintStep | -| full_partial_test.py:67:5:67:13 | ControlFlowNode for query_val | full_partial_test.py:78:50:78:58 | ControlFlowNode for query_val | provenance | | -| full_partial_test.py:67:17:67:23 | ControlFlowNode for request | full_partial_test.py:67:5:67:13 | ControlFlowNode for query_val | provenance | AdditionalTaintStep | -| full_partial_test.py:70:5:70:7 | ControlFlowNode for url | full_partial_test.py:72:18:72:20 | ControlFlowNode for url | provenance | | -| full_partial_test.py:74:5:74:7 | ControlFlowNode for url | full_partial_test.py:76:18:76:20 | ControlFlowNode for url | provenance | | -| full_partial_test.py:78:5:78:7 | ControlFlowNode for url | full_partial_test.py:80:18:80:20 | ControlFlowNode for url | provenance | | -| full_partial_test.py:78:11:78:59 | ControlFlowNode for BinaryExpr | full_partial_test.py:78:5:78:7 | ControlFlowNode for url | provenance | | -| full_partial_test.py:78:38:78:47 | ControlFlowNode for user_input | full_partial_test.py:78:38:78:58 | ControlFlowNode for Tuple [Tuple element at index 0] | provenance | | -| full_partial_test.py:78:38:78:58 | ControlFlowNode for Tuple [Tuple element at index 0] | full_partial_test.py:78:11:78:59 | ControlFlowNode for BinaryExpr | provenance | | -| full_partial_test.py:78:38:78:58 | ControlFlowNode for Tuple [Tuple element at index 1] | full_partial_test.py:78:11:78:59 | ControlFlowNode for BinaryExpr | provenance | | -| full_partial_test.py:78:50:78:58 | ControlFlowNode for query_val | full_partial_test.py:78:38:78:58 | ControlFlowNode for Tuple [Tuple element at index 1] | provenance | | -| full_partial_test.py:83:5:83:14 | ControlFlowNode for user_input | full_partial_test.py:87:5:87:7 | ControlFlowNode for url | provenance | | -| full_partial_test.py:83:5:83:14 | ControlFlowNode for user_input | full_partial_test.py:91:5:91:7 | ControlFlowNode for url | provenance | | -| full_partial_test.py:83:5:83:14 | ControlFlowNode for user_input | full_partial_test.py:95:5:95:7 | ControlFlowNode for url | provenance | | -| full_partial_test.py:83:18:83:24 | ControlFlowNode for request | full_partial_test.py:83:5:83:14 | ControlFlowNode for user_input | provenance | AdditionalTaintStep | -| full_partial_test.py:83:18:83:24 | ControlFlowNode for request | full_partial_test.py:84:5:84:13 | ControlFlowNode for query_val | provenance | AdditionalTaintStep | -| full_partial_test.py:84:5:84:13 | ControlFlowNode for query_val | full_partial_test.py:95:5:95:7 | ControlFlowNode for url | provenance | | -| full_partial_test.py:84:17:84:23 | ControlFlowNode for request | full_partial_test.py:84:5:84:13 | ControlFlowNode for query_val | provenance | AdditionalTaintStep | -| full_partial_test.py:87:5:87:7 | ControlFlowNode for url | full_partial_test.py:89:18:89:20 | ControlFlowNode for url | provenance | | -| full_partial_test.py:91:5:91:7 | ControlFlowNode for url | full_partial_test.py:93:18:93:20 | ControlFlowNode for url | provenance | | -| full_partial_test.py:95:5:95:7 | ControlFlowNode for url | full_partial_test.py:97:18:97:20 | ControlFlowNode for url | provenance | | -| full_partial_test.py:101:5:101:14 | ControlFlowNode for user_input | full_partial_test.py:103:5:103:7 | ControlFlowNode for url | provenance | | -| full_partial_test.py:101:18:101:24 | ControlFlowNode for request | full_partial_test.py:101:5:101:14 | ControlFlowNode for user_input | provenance | AdditionalTaintStep | -| full_partial_test.py:103:5:103:7 | ControlFlowNode for url | full_partial_test.py:105:18:105:20 | ControlFlowNode for url | provenance | | -| full_partial_test.py:108:5:108:14 | ControlFlowNode for user_input | full_partial_test.py:110:5:110:7 | ControlFlowNode for url | provenance | | -| full_partial_test.py:108:18:108:24 | ControlFlowNode for request | full_partial_test.py:108:5:108:14 | ControlFlowNode for user_input | provenance | AdditionalTaintStep | -| full_partial_test.py:110:5:110:7 | ControlFlowNode for url | full_partial_test.py:112:18:112:20 | ControlFlowNode for url | provenance | | -| full_partial_test.py:115:5:115:14 | ControlFlowNode for user_input | full_partial_test.py:117:5:117:7 | ControlFlowNode for url | provenance | | -| full_partial_test.py:115:18:115:24 | ControlFlowNode for request | full_partial_test.py:115:5:115:14 | ControlFlowNode for user_input | provenance | AdditionalTaintStep | -| full_partial_test.py:117:5:117:7 | ControlFlowNode for url | full_partial_test.py:119:18:119:20 | ControlFlowNode for url | provenance | | -| full_partial_test.py:122:5:122:14 | ControlFlowNode for user_input | full_partial_test.py:124:5:124:7 | ControlFlowNode for url | provenance | | -| full_partial_test.py:122:18:122:24 | ControlFlowNode for request | full_partial_test.py:122:5:122:14 | ControlFlowNode for user_input | provenance | AdditionalTaintStep | -| full_partial_test.py:124:5:124:7 | ControlFlowNode for url | full_partial_test.py:126:18:126:20 | ControlFlowNode for url | provenance | | -| full_partial_test.py:129:5:129:14 | ControlFlowNode for user_input | full_partial_test.py:134:5:134:7 | ControlFlowNode for url | provenance | | -| full_partial_test.py:129:18:129:24 | ControlFlowNode for request | full_partial_test.py:129:5:129:14 | ControlFlowNode for user_input | provenance | AdditionalTaintStep | -| full_partial_test.py:134:5:134:7 | ControlFlowNode for url | full_partial_test.py:136:18:136:20 | ControlFlowNode for url | provenance | | -| full_partial_test.py:139:5:139:14 | ControlFlowNode for user_input | full_partial_test.py:141:5:141:7 | ControlFlowNode for url | provenance | | -| full_partial_test.py:139:18:139:24 | ControlFlowNode for request | full_partial_test.py:139:5:139:14 | ControlFlowNode for user_input | provenance | AdditionalTaintStep | -| full_partial_test.py:141:5:141:7 | ControlFlowNode for url | full_partial_test.py:143:18:143:20 | ControlFlowNode for url | provenance | | -| test_azure_client.py:6:19:6:25 | ControlFlowNode for ImportMember | test_azure_client.py:6:19:6:25 | ControlFlowNode for request | provenance | | -| test_azure_client.py:6:19:6:25 | ControlFlowNode for request | test_azure_client.py:9:18:9:24 | ControlFlowNode for request | provenance | | -| test_azure_client.py:6:19:6:25 | ControlFlowNode for request | test_azure_client.py:10:19:10:25 | ControlFlowNode for request | provenance | | -| test_azure_client.py:9:5:9:14 | ControlFlowNode for user_input | test_azure_client.py:12:5:12:7 | ControlFlowNode for url | provenance | | -| test_azure_client.py:9:18:9:24 | ControlFlowNode for request | test_azure_client.py:9:5:9:14 | ControlFlowNode for user_input | provenance | AdditionalTaintStep | -| test_azure_client.py:9:18:9:24 | ControlFlowNode for request | test_azure_client.py:10:5:10:15 | ControlFlowNode for user_input2 | provenance | AdditionalTaintStep | -| test_azure_client.py:10:5:10:15 | ControlFlowNode for user_input2 | test_azure_client.py:13:5:13:12 | ControlFlowNode for full_url | provenance | | -| test_azure_client.py:10:19:10:25 | ControlFlowNode for request | test_azure_client.py:10:5:10:15 | ControlFlowNode for user_input2 | provenance | AdditionalTaintStep | -| test_azure_client.py:12:5:12:7 | ControlFlowNode for url | test_azure_client.py:15:28:15:30 | ControlFlowNode for url | provenance | Sink:MaD:2 | -| test_azure_client.py:12:5:12:7 | ControlFlowNode for url | test_azure_client.py:17:35:17:37 | ControlFlowNode for url | provenance | Sink:MaD:4 | -| test_azure_client.py:12:5:12:7 | ControlFlowNode for url | test_azure_client.py:19:15:19:17 | ControlFlowNode for url | provenance | Sink:MaD:1 | -| test_azure_client.py:12:5:12:7 | ControlFlowNode for url | test_azure_client.py:21:54:21:56 | ControlFlowNode for url | provenance | Sink:MaD:3 | -| test_azure_client.py:12:5:12:7 | ControlFlowNode for url | test_azure_client.py:24:37:24:39 | ControlFlowNode for url | provenance | Sink:MaD:5 | -| test_azure_client.py:13:5:13:12 | ControlFlowNode for full_url | test_azure_client.py:16:28:16:35 | ControlFlowNode for full_url | provenance | Sink:MaD:2 | -| test_azure_client.py:13:5:13:12 | ControlFlowNode for full_url | test_azure_client.py:18:35:18:42 | ControlFlowNode for full_url | provenance | Sink:MaD:4 | -| test_azure_client.py:13:5:13:12 | ControlFlowNode for full_url | test_azure_client.py:20:15:20:22 | ControlFlowNode for full_url | provenance | Sink:MaD:1 | -| test_azure_client.py:13:5:13:12 | ControlFlowNode for full_url | test_azure_client.py:22:54:22:61 | ControlFlowNode for full_url | provenance | Sink:MaD:3 | -| test_azure_client.py:13:5:13:12 | ControlFlowNode for full_url | test_azure_client.py:25:37:25:44 | ControlFlowNode for full_url | provenance | Sink:MaD:5 | -| test_http_client.py:1:19:1:25 | ControlFlowNode for ImportMember | test_http_client.py:1:19:1:25 | ControlFlowNode for request | provenance | | -| test_http_client.py:1:19:1:25 | ControlFlowNode for request | test_http_client.py:9:19:9:25 | ControlFlowNode for request | provenance | | -| test_http_client.py:1:19:1:25 | ControlFlowNode for request | test_http_client.py:10:19:10:25 | ControlFlowNode for request | provenance | | -| test_http_client.py:1:19:1:25 | ControlFlowNode for request | test_http_client.py:11:18:11:24 | ControlFlowNode for request | provenance | | -| test_http_client.py:9:5:9:15 | ControlFlowNode for unsafe_host | test_http_client.py:13:27:13:37 | ControlFlowNode for unsafe_host | provenance | | -| test_http_client.py:9:5:9:15 | ControlFlowNode for unsafe_host | test_http_client.py:19:27:19:37 | ControlFlowNode for unsafe_host | provenance | | -| test_http_client.py:9:5:9:15 | ControlFlowNode for unsafe_host | test_http_client.py:28:27:28:37 | ControlFlowNode for unsafe_host | provenance | | -| test_http_client.py:9:19:9:25 | ControlFlowNode for request | test_http_client.py:9:5:9:15 | ControlFlowNode for unsafe_host | provenance | AdditionalTaintStep | -| test_http_client.py:9:19:9:25 | ControlFlowNode for request | test_http_client.py:10:5:10:15 | ControlFlowNode for unsafe_path | provenance | AdditionalTaintStep | -| test_http_client.py:9:19:9:25 | ControlFlowNode for request | test_http_client.py:11:5:11:14 | ControlFlowNode for user_input | provenance | AdditionalTaintStep | -| test_http_client.py:10:5:10:15 | ControlFlowNode for unsafe_path | test_http_client.py:15:25:15:35 | ControlFlowNode for unsafe_path | provenance | | -| test_http_client.py:10:5:10:15 | ControlFlowNode for unsafe_path | test_http_client.py:21:25:21:35 | ControlFlowNode for unsafe_path | provenance | | -| test_http_client.py:10:5:10:15 | ControlFlowNode for unsafe_path | test_http_client.py:34:25:34:35 | ControlFlowNode for unsafe_path | provenance | | -| test_http_client.py:10:19:10:25 | ControlFlowNode for request | test_http_client.py:10:5:10:15 | ControlFlowNode for unsafe_path | provenance | AdditionalTaintStep | -| test_http_client.py:10:19:10:25 | ControlFlowNode for request | test_http_client.py:11:5:11:14 | ControlFlowNode for user_input | provenance | AdditionalTaintStep | -| test_http_client.py:11:5:11:14 | ControlFlowNode for user_input | test_http_client.py:36:5:36:8 | ControlFlowNode for path | provenance | | -| test_http_client.py:11:5:11:14 | ControlFlowNode for user_input | test_http_client.py:41:5:41:8 | ControlFlowNode for path | provenance | | -| test_http_client.py:11:18:11:24 | ControlFlowNode for request | test_http_client.py:11:5:11:14 | ControlFlowNode for user_input | provenance | AdditionalTaintStep | -| test_http_client.py:36:5:36:8 | ControlFlowNode for path | test_http_client.py:39:25:39:28 | ControlFlowNode for path | provenance | | -| test_http_client.py:41:5:41:8 | ControlFlowNode for path | test_http_client.py:44:25:44:28 | ControlFlowNode for path | provenance | | -| test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:5:19:5:25 | ControlFlowNode for request | provenance | | -| test_path_validation.py:5:19:5:25 | ControlFlowNode for request | test_path_validation.py:8:18:8:24 | ControlFlowNode for request | provenance | | -| test_path_validation.py:5:19:5:25 | ControlFlowNode for request | test_path_validation.py:9:19:9:25 | ControlFlowNode for request | provenance | | -| test_path_validation.py:5:19:5:25 | ControlFlowNode for request | test_path_validation.py:24:18:24:24 | ControlFlowNode for request | provenance | | -| test_path_validation.py:5:19:5:25 | ControlFlowNode for request | test_path_validation.py:25:19:25:25 | ControlFlowNode for request | provenance | | -| test_path_validation.py:5:19:5:25 | ControlFlowNode for request | test_path_validation.py:40:18:40:24 | ControlFlowNode for request | provenance | | -| test_path_validation.py:5:19:5:25 | ControlFlowNode for request | test_path_validation.py:41:19:41:25 | ControlFlowNode for request | provenance | | -| test_path_validation.py:5:19:5:25 | ControlFlowNode for request | test_path_validation.py:57:18:57:24 | ControlFlowNode for request | provenance | | -| test_path_validation.py:8:5:8:14 | ControlFlowNode for user_input | test_path_validation.py:10:5:10:7 | ControlFlowNode for url | provenance | | -| test_path_validation.py:8:18:8:24 | ControlFlowNode for request | test_path_validation.py:8:5:8:14 | ControlFlowNode for user_input | provenance | AdditionalTaintStep | -| test_path_validation.py:8:18:8:24 | ControlFlowNode for request | test_path_validation.py:9:5:9:15 | ControlFlowNode for user_input2 | provenance | AdditionalTaintStep | -| test_path_validation.py:9:5:9:15 | ControlFlowNode for user_input2 | test_path_validation.py:11:5:11:12 | ControlFlowNode for full_url | provenance | | -| test_path_validation.py:9:19:9:25 | ControlFlowNode for request | test_path_validation.py:9:5:9:15 | ControlFlowNode for user_input2 | provenance | AdditionalTaintStep | -| test_path_validation.py:10:5:10:7 | ControlFlowNode for url | test_path_validation.py:14:32:14:34 | ControlFlowNode for url | provenance | Sink:MaD:2 | -| test_path_validation.py:10:5:10:7 | ControlFlowNode for url | test_path_validation.py:16:32:16:34 | ControlFlowNode for url | provenance | Sink:MaD:2 | -| test_path_validation.py:11:5:11:12 | ControlFlowNode for full_url | test_path_validation.py:19:32:19:39 | ControlFlowNode for full_url | provenance | Sink:MaD:2 | -| test_path_validation.py:11:5:11:12 | ControlFlowNode for full_url | test_path_validation.py:21:32:21:39 | ControlFlowNode for full_url | provenance | Sink:MaD:2 | -| test_path_validation.py:24:5:24:14 | ControlFlowNode for user_input | test_path_validation.py:26:5:26:7 | ControlFlowNode for url | provenance | | -| test_path_validation.py:24:18:24:24 | ControlFlowNode for request | test_path_validation.py:24:5:24:14 | ControlFlowNode for user_input | provenance | AdditionalTaintStep | -| test_path_validation.py:24:18:24:24 | ControlFlowNode for request | test_path_validation.py:25:5:25:15 | ControlFlowNode for user_input2 | provenance | AdditionalTaintStep | -| test_path_validation.py:25:5:25:15 | ControlFlowNode for user_input2 | test_path_validation.py:27:5:27:12 | ControlFlowNode for full_url | provenance | | -| test_path_validation.py:25:19:25:25 | ControlFlowNode for request | test_path_validation.py:25:5:25:15 | ControlFlowNode for user_input2 | provenance | AdditionalTaintStep | -| test_path_validation.py:26:5:26:7 | ControlFlowNode for url | test_path_validation.py:30:29:30:31 | ControlFlowNode for url | provenance | Sink:MaD:1 | -| test_path_validation.py:26:5:26:7 | ControlFlowNode for url | test_path_validation.py:32:29:32:31 | ControlFlowNode for url | provenance | Sink:MaD:1 | -| test_path_validation.py:27:5:27:12 | ControlFlowNode for full_url | test_path_validation.py:35:29:35:36 | ControlFlowNode for full_url | provenance | Sink:MaD:1 | -| test_path_validation.py:27:5:27:12 | ControlFlowNode for full_url | test_path_validation.py:37:29:37:36 | ControlFlowNode for full_url | provenance | Sink:MaD:1 | -| test_path_validation.py:40:5:40:14 | ControlFlowNode for user_input | test_path_validation.py:42:5:42:7 | ControlFlowNode for url | provenance | | -| test_path_validation.py:40:18:40:24 | ControlFlowNode for request | test_path_validation.py:40:5:40:14 | ControlFlowNode for user_input | provenance | AdditionalTaintStep | -| test_path_validation.py:40:18:40:24 | ControlFlowNode for request | test_path_validation.py:41:5:41:15 | ControlFlowNode for user_input2 | provenance | AdditionalTaintStep | -| test_path_validation.py:41:5:41:15 | ControlFlowNode for user_input2 | test_path_validation.py:43:5:43:12 | ControlFlowNode for full_url | provenance | | -| test_path_validation.py:41:19:41:25 | ControlFlowNode for request | test_path_validation.py:41:5:41:15 | ControlFlowNode for user_input2 | provenance | AdditionalTaintStep | -| test_path_validation.py:42:5:42:7 | ControlFlowNode for url | test_path_validation.py:46:39:46:41 | ControlFlowNode for url | provenance | Sink:MaD:4 | -| test_path_validation.py:42:5:42:7 | ControlFlowNode for url | test_path_validation.py:48:39:48:41 | ControlFlowNode for url | provenance | Sink:MaD:4 | -| test_path_validation.py:43:5:43:12 | ControlFlowNode for full_url | test_path_validation.py:51:39:51:46 | ControlFlowNode for full_url | provenance | Sink:MaD:4 | -| test_path_validation.py:43:5:43:12 | ControlFlowNode for full_url | test_path_validation.py:53:39:53:46 | ControlFlowNode for full_url | provenance | Sink:MaD:4 | -| test_path_validation.py:57:5:57:14 | ControlFlowNode for user_input | test_path_validation.py:61:5:61:7 | ControlFlowNode for url | provenance | | -| test_path_validation.py:57:18:57:24 | ControlFlowNode for request | test_path_validation.py:57:5:57:14 | ControlFlowNode for user_input | provenance | AdditionalTaintStep | -| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:64:32:64:34 | ControlFlowNode for url | provenance | Sink:MaD:2 | -| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:66:32:66:34 | ControlFlowNode for url | provenance | Sink:MaD:2 | -| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:69:32:69:34 | ControlFlowNode for url | provenance | Sink:MaD:2 | -| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:71:32:71:34 | ControlFlowNode for url | provenance | Sink:MaD:2 | -| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:74:32:74:34 | ControlFlowNode for url | provenance | Sink:MaD:2 | -| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:76:32:76:34 | ControlFlowNode for url | provenance | Sink:MaD:2 | -| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:79:32:79:34 | ControlFlowNode for url | provenance | Sink:MaD:2 | -| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:81:32:81:34 | ControlFlowNode for url | provenance | Sink:MaD:2 | -| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:85:32:85:34 | ControlFlowNode for url | provenance | Sink:MaD:2 | -| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:87:32:87:34 | ControlFlowNode for url | provenance | Sink:MaD:2 | -| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:90:32:90:34 | ControlFlowNode for url | provenance | Sink:MaD:2 | -| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:92:32:92:34 | ControlFlowNode for url | provenance | Sink:MaD:2 | -| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:95:32:95:34 | ControlFlowNode for url | provenance | Sink:MaD:2 | -| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:97:32:97:34 | ControlFlowNode for url | provenance | Sink:MaD:2 | -| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:100:32:100:34 | ControlFlowNode for url | provenance | Sink:MaD:2 | -| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:102:32:102:34 | ControlFlowNode for url | provenance | Sink:MaD:2 | -| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:105:32:105:34 | ControlFlowNode for url | provenance | Sink:MaD:2 | -| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:107:32:107:34 | ControlFlowNode for url | provenance | Sink:MaD:2 | -| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:110:32:110:34 | ControlFlowNode for url | provenance | Sink:MaD:2 | -| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:112:32:112:34 | ControlFlowNode for url | provenance | Sink:MaD:2 | -| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:115:32:115:34 | ControlFlowNode for url | provenance | Sink:MaD:2 | -| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:117:32:117:34 | ControlFlowNode for url | provenance | Sink:MaD:2 | -| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:120:32:120:34 | ControlFlowNode for url | provenance | Sink:MaD:2 | -| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:122:32:122:34 | ControlFlowNode for url | provenance | Sink:MaD:2 | -| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:125:32:125:34 | ControlFlowNode for url | provenance | Sink:MaD:2 | -| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:127:32:127:34 | ControlFlowNode for url | provenance | Sink:MaD:2 | -| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:130:32:130:34 | ControlFlowNode for url | provenance | Sink:MaD:2 | -| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:132:32:132:34 | ControlFlowNode for url | provenance | Sink:MaD:2 | -| test_requests.py:1:19:1:25 | ControlFlowNode for ImportMember | test_requests.py:1:19:1:25 | ControlFlowNode for request | provenance | | -| test_requests.py:1:19:1:25 | ControlFlowNode for request | test_requests.py:7:18:7:24 | ControlFlowNode for request | provenance | | -| test_requests.py:1:19:1:25 | ControlFlowNode for request | test_requests.py:14:18:14:24 | ControlFlowNode for request | provenance | | -| test_requests.py:1:19:1:25 | ControlFlowNode for request | test_requests.py:20:18:20:24 | ControlFlowNode for request | provenance | | -| test_requests.py:7:5:7:14 | ControlFlowNode for user_input | test_requests.py:9:18:9:27 | ControlFlowNode for user_input | provenance | | -| test_requests.py:7:18:7:24 | ControlFlowNode for request | test_requests.py:7:5:7:14 | ControlFlowNode for user_input | provenance | AdditionalTaintStep | -| test_requests.py:14:5:14:14 | ControlFlowNode for user_input | test_requests.py:17:17:17:26 | ControlFlowNode for user_input | provenance | | -| test_requests.py:14:18:14:24 | ControlFlowNode for request | test_requests.py:14:5:14:14 | ControlFlowNode for user_input | provenance | AdditionalTaintStep | -| test_requests.py:20:5:20:14 | ControlFlowNode for user_input | test_requests.py:22:34:22:43 | ControlFlowNode for user_input | provenance | | -| test_requests.py:20:18:20:24 | ControlFlowNode for request | test_requests.py:20:5:20:14 | ControlFlowNode for user_input | provenance | AdditionalTaintStep | +| full_partial_test.py:1:19:1:25 | After ImportMember | full_partial_test.py:1:19:1:25 | request | provenance | | +| full_partial_test.py:1:19:1:25 | request | full_partial_test.py:7:18:7:24 | request | provenance | | +| full_partial_test.py:1:19:1:25 | request | full_partial_test.py:8:17:8:23 | request | provenance | | +| full_partial_test.py:1:19:1:25 | request | full_partial_test.py:41:18:41:24 | request | provenance | | +| full_partial_test.py:1:19:1:25 | request | full_partial_test.py:42:17:42:23 | request | provenance | | +| full_partial_test.py:1:19:1:25 | request | full_partial_test.py:66:18:66:24 | request | provenance | | +| full_partial_test.py:1:19:1:25 | request | full_partial_test.py:67:17:67:23 | request | provenance | | +| full_partial_test.py:1:19:1:25 | request | full_partial_test.py:83:18:83:24 | request | provenance | | +| full_partial_test.py:1:19:1:25 | request | full_partial_test.py:84:17:84:23 | request | provenance | | +| full_partial_test.py:1:19:1:25 | request | full_partial_test.py:101:18:101:24 | request | provenance | | +| full_partial_test.py:1:19:1:25 | request | full_partial_test.py:108:18:108:24 | request | provenance | | +| full_partial_test.py:1:19:1:25 | request | full_partial_test.py:115:18:115:24 | request | provenance | | +| full_partial_test.py:1:19:1:25 | request | full_partial_test.py:122:18:122:24 | request | provenance | | +| full_partial_test.py:1:19:1:25 | request | full_partial_test.py:129:18:129:24 | request | provenance | | +| full_partial_test.py:1:19:1:25 | request | full_partial_test.py:139:18:139:24 | request | provenance | | +| full_partial_test.py:7:5:7:14 | user_input | full_partial_test.py:11:18:11:27 | user_input | provenance | | +| full_partial_test.py:7:5:7:14 | user_input | full_partial_test.py:13:5:13:7 | url | provenance | | +| full_partial_test.py:7:5:7:14 | user_input | full_partial_test.py:20:5:20:7 | url | provenance | | +| full_partial_test.py:7:5:7:14 | user_input | full_partial_test.py:25:5:25:7 | url | provenance | | +| full_partial_test.py:7:18:7:24 | request | full_partial_test.py:7:5:7:14 | user_input | provenance | AdditionalTaintStep | +| full_partial_test.py:7:18:7:24 | request | full_partial_test.py:8:5:8:13 | query_val | provenance | AdditionalTaintStep | +| full_partial_test.py:8:5:8:13 | query_val | full_partial_test.py:25:5:25:7 | url | provenance | | +| full_partial_test.py:8:17:8:23 | request | full_partial_test.py:8:5:8:13 | query_val | provenance | AdditionalTaintStep | +| full_partial_test.py:13:5:13:7 | url | full_partial_test.py:15:18:15:20 | url | provenance | | +| full_partial_test.py:20:5:20:7 | url | full_partial_test.py:22:18:22:20 | url | provenance | | +| full_partial_test.py:25:5:25:7 | url | full_partial_test.py:27:18:27:20 | url | provenance | | +| full_partial_test.py:41:5:41:14 | user_input | full_partial_test.py:45:5:45:7 | url | provenance | | +| full_partial_test.py:41:5:41:14 | user_input | full_partial_test.py:49:5:49:7 | url | provenance | | +| full_partial_test.py:41:5:41:14 | user_input | full_partial_test.py:53:5:53:7 | url | provenance | | +| full_partial_test.py:41:5:41:14 | user_input | full_partial_test.py:57:5:57:7 | url | provenance | | +| full_partial_test.py:41:5:41:14 | user_input | full_partial_test.py:61:5:61:7 | url | provenance | | +| full_partial_test.py:41:18:41:24 | request | full_partial_test.py:41:5:41:14 | user_input | provenance | AdditionalTaintStep | +| full_partial_test.py:41:18:41:24 | request | full_partial_test.py:42:5:42:13 | query_val | provenance | AdditionalTaintStep | +| full_partial_test.py:42:5:42:13 | query_val | full_partial_test.py:53:5:53:7 | url | provenance | | +| full_partial_test.py:42:17:42:23 | request | full_partial_test.py:42:5:42:13 | query_val | provenance | AdditionalTaintStep | +| full_partial_test.py:45:5:45:7 | url | full_partial_test.py:47:18:47:20 | url | provenance | | +| full_partial_test.py:49:5:49:7 | url | full_partial_test.py:51:18:51:20 | url | provenance | | +| full_partial_test.py:53:5:53:7 | url | full_partial_test.py:55:18:55:20 | url | provenance | | +| full_partial_test.py:57:5:57:7 | url | full_partial_test.py:59:18:59:20 | url | provenance | | +| full_partial_test.py:61:5:61:7 | url | full_partial_test.py:63:18:63:20 | url | provenance | | +| full_partial_test.py:66:5:66:14 | user_input | full_partial_test.py:70:5:70:7 | url | provenance | | +| full_partial_test.py:66:5:66:14 | user_input | full_partial_test.py:74:5:74:7 | url | provenance | | +| full_partial_test.py:66:5:66:14 | user_input | full_partial_test.py:78:5:78:7 | url | provenance | | +| full_partial_test.py:66:18:66:24 | request | full_partial_test.py:66:5:66:14 | user_input | provenance | AdditionalTaintStep | +| full_partial_test.py:66:18:66:24 | request | full_partial_test.py:67:5:67:13 | query_val | provenance | AdditionalTaintStep | +| full_partial_test.py:67:5:67:13 | query_val | full_partial_test.py:78:5:78:7 | url | provenance | | +| full_partial_test.py:67:17:67:23 | request | full_partial_test.py:67:5:67:13 | query_val | provenance | AdditionalTaintStep | +| full_partial_test.py:70:5:70:7 | url | full_partial_test.py:72:18:72:20 | url | provenance | | +| full_partial_test.py:74:5:74:7 | url | full_partial_test.py:76:18:76:20 | url | provenance | | +| full_partial_test.py:78:5:78:7 | url | full_partial_test.py:80:18:80:20 | url | provenance | | +| full_partial_test.py:83:5:83:14 | user_input | full_partial_test.py:87:5:87:7 | url | provenance | | +| full_partial_test.py:83:5:83:14 | user_input | full_partial_test.py:91:5:91:7 | url | provenance | | +| full_partial_test.py:83:5:83:14 | user_input | full_partial_test.py:95:5:95:7 | url | provenance | | +| full_partial_test.py:83:18:83:24 | request | full_partial_test.py:83:5:83:14 | user_input | provenance | AdditionalTaintStep | +| full_partial_test.py:83:18:83:24 | request | full_partial_test.py:84:5:84:13 | query_val | provenance | AdditionalTaintStep | +| full_partial_test.py:84:5:84:13 | query_val | full_partial_test.py:95:5:95:7 | url | provenance | | +| full_partial_test.py:84:17:84:23 | request | full_partial_test.py:84:5:84:13 | query_val | provenance | AdditionalTaintStep | +| full_partial_test.py:87:5:87:7 | url | full_partial_test.py:89:18:89:20 | url | provenance | | +| full_partial_test.py:91:5:91:7 | url | full_partial_test.py:93:18:93:20 | url | provenance | | +| full_partial_test.py:95:5:95:7 | url | full_partial_test.py:97:18:97:20 | url | provenance | | +| full_partial_test.py:101:5:101:14 | user_input | full_partial_test.py:103:5:103:7 | url | provenance | | +| full_partial_test.py:101:18:101:24 | request | full_partial_test.py:101:5:101:14 | user_input | provenance | AdditionalTaintStep | +| full_partial_test.py:103:5:103:7 | url | full_partial_test.py:105:18:105:20 | url | provenance | | +| full_partial_test.py:108:5:108:14 | user_input | full_partial_test.py:110:5:110:7 | url | provenance | | +| full_partial_test.py:108:18:108:24 | request | full_partial_test.py:108:5:108:14 | user_input | provenance | AdditionalTaintStep | +| full_partial_test.py:110:5:110:7 | url | full_partial_test.py:112:18:112:20 | url | provenance | | +| full_partial_test.py:115:5:115:14 | user_input | full_partial_test.py:117:5:117:7 | url | provenance | | +| full_partial_test.py:115:18:115:24 | request | full_partial_test.py:115:5:115:14 | user_input | provenance | AdditionalTaintStep | +| full_partial_test.py:117:5:117:7 | url | full_partial_test.py:119:18:119:20 | url | provenance | | +| full_partial_test.py:122:5:122:14 | user_input | full_partial_test.py:124:5:124:7 | url | provenance | | +| full_partial_test.py:122:18:122:24 | request | full_partial_test.py:122:5:122:14 | user_input | provenance | AdditionalTaintStep | +| full_partial_test.py:124:5:124:7 | url | full_partial_test.py:126:18:126:20 | url | provenance | | +| full_partial_test.py:129:5:129:14 | user_input | full_partial_test.py:134:5:134:7 | url | provenance | | +| full_partial_test.py:129:18:129:24 | request | full_partial_test.py:129:5:129:14 | user_input | provenance | AdditionalTaintStep | +| full_partial_test.py:134:5:134:7 | url | full_partial_test.py:136:18:136:20 | url | provenance | | +| full_partial_test.py:139:5:139:14 | user_input | full_partial_test.py:141:5:141:7 | url | provenance | | +| full_partial_test.py:139:18:139:24 | request | full_partial_test.py:139:5:139:14 | user_input | provenance | AdditionalTaintStep | +| full_partial_test.py:141:5:141:7 | url | full_partial_test.py:143:18:143:20 | url | provenance | | +| test_azure_client.py:6:19:6:25 | After ImportMember | test_azure_client.py:6:19:6:25 | request | provenance | | +| test_azure_client.py:6:19:6:25 | request | test_azure_client.py:9:18:9:24 | request | provenance | | +| test_azure_client.py:6:19:6:25 | request | test_azure_client.py:10:19:10:25 | request | provenance | | +| test_azure_client.py:9:5:9:14 | user_input | test_azure_client.py:12:5:12:7 | url | provenance | | +| test_azure_client.py:9:18:9:24 | request | test_azure_client.py:9:5:9:14 | user_input | provenance | AdditionalTaintStep | +| test_azure_client.py:9:18:9:24 | request | test_azure_client.py:10:5:10:15 | user_input2 | provenance | AdditionalTaintStep | +| test_azure_client.py:10:5:10:15 | user_input2 | test_azure_client.py:13:5:13:12 | full_url | provenance | | +| test_azure_client.py:10:19:10:25 | request | test_azure_client.py:10:5:10:15 | user_input2 | provenance | AdditionalTaintStep | +| test_azure_client.py:12:5:12:7 | url | test_azure_client.py:15:28:15:30 | url | provenance | Sink:MaD:2 | +| test_azure_client.py:12:5:12:7 | url | test_azure_client.py:17:35:17:37 | url | provenance | Sink:MaD:4 | +| test_azure_client.py:12:5:12:7 | url | test_azure_client.py:19:15:19:17 | url | provenance | Sink:MaD:1 | +| test_azure_client.py:12:5:12:7 | url | test_azure_client.py:21:54:21:56 | url | provenance | Sink:MaD:3 | +| test_azure_client.py:12:5:12:7 | url | test_azure_client.py:24:37:24:39 | url | provenance | Sink:MaD:5 | +| test_azure_client.py:13:5:13:12 | full_url | test_azure_client.py:16:28:16:35 | full_url | provenance | Sink:MaD:2 | +| test_azure_client.py:13:5:13:12 | full_url | test_azure_client.py:18:35:18:42 | full_url | provenance | Sink:MaD:4 | +| test_azure_client.py:13:5:13:12 | full_url | test_azure_client.py:20:15:20:22 | full_url | provenance | Sink:MaD:1 | +| test_azure_client.py:13:5:13:12 | full_url | test_azure_client.py:22:54:22:61 | full_url | provenance | Sink:MaD:3 | +| test_azure_client.py:13:5:13:12 | full_url | test_azure_client.py:25:37:25:44 | full_url | provenance | Sink:MaD:5 | +| test_http_client.py:1:19:1:25 | After ImportMember | test_http_client.py:1:19:1:25 | request | provenance | | +| test_http_client.py:1:19:1:25 | request | test_http_client.py:9:19:9:25 | request | provenance | | +| test_http_client.py:1:19:1:25 | request | test_http_client.py:10:19:10:25 | request | provenance | | +| test_http_client.py:1:19:1:25 | request | test_http_client.py:11:18:11:24 | request | provenance | | +| test_http_client.py:9:5:9:15 | unsafe_host | test_http_client.py:13:27:13:37 | unsafe_host | provenance | | +| test_http_client.py:9:5:9:15 | unsafe_host | test_http_client.py:19:27:19:37 | unsafe_host | provenance | | +| test_http_client.py:9:5:9:15 | unsafe_host | test_http_client.py:28:27:28:37 | unsafe_host | provenance | | +| test_http_client.py:9:19:9:25 | request | test_http_client.py:9:5:9:15 | unsafe_host | provenance | AdditionalTaintStep | +| test_http_client.py:9:19:9:25 | request | test_http_client.py:10:5:10:15 | unsafe_path | provenance | AdditionalTaintStep | +| test_http_client.py:9:19:9:25 | request | test_http_client.py:11:5:11:14 | user_input | provenance | AdditionalTaintStep | +| test_http_client.py:10:5:10:15 | unsafe_path | test_http_client.py:15:25:15:35 | unsafe_path | provenance | | +| test_http_client.py:10:5:10:15 | unsafe_path | test_http_client.py:21:25:21:35 | unsafe_path | provenance | | +| test_http_client.py:10:5:10:15 | unsafe_path | test_http_client.py:34:25:34:35 | unsafe_path | provenance | | +| test_http_client.py:10:19:10:25 | request | test_http_client.py:10:5:10:15 | unsafe_path | provenance | AdditionalTaintStep | +| test_http_client.py:10:19:10:25 | request | test_http_client.py:11:5:11:14 | user_input | provenance | AdditionalTaintStep | +| test_http_client.py:11:5:11:14 | user_input | test_http_client.py:36:5:36:8 | path | provenance | | +| test_http_client.py:11:5:11:14 | user_input | test_http_client.py:41:5:41:8 | path | provenance | | +| test_http_client.py:11:18:11:24 | request | test_http_client.py:11:5:11:14 | user_input | provenance | AdditionalTaintStep | +| test_http_client.py:36:5:36:8 | path | test_http_client.py:39:25:39:28 | path | provenance | | +| test_http_client.py:41:5:41:8 | path | test_http_client.py:44:25:44:28 | path | provenance | | +| test_path_validation.py:5:19:5:25 | After ImportMember | test_path_validation.py:5:19:5:25 | request | provenance | | +| test_path_validation.py:5:19:5:25 | request | test_path_validation.py:8:18:8:24 | request | provenance | | +| test_path_validation.py:5:19:5:25 | request | test_path_validation.py:9:19:9:25 | request | provenance | | +| test_path_validation.py:5:19:5:25 | request | test_path_validation.py:24:18:24:24 | request | provenance | | +| test_path_validation.py:5:19:5:25 | request | test_path_validation.py:25:19:25:25 | request | provenance | | +| test_path_validation.py:5:19:5:25 | request | test_path_validation.py:40:18:40:24 | request | provenance | | +| test_path_validation.py:5:19:5:25 | request | test_path_validation.py:41:19:41:25 | request | provenance | | +| test_path_validation.py:5:19:5:25 | request | test_path_validation.py:57:18:57:24 | request | provenance | | +| test_path_validation.py:8:5:8:14 | user_input | test_path_validation.py:10:5:10:7 | url | provenance | | +| test_path_validation.py:8:18:8:24 | request | test_path_validation.py:8:5:8:14 | user_input | provenance | AdditionalTaintStep | +| test_path_validation.py:8:18:8:24 | request | test_path_validation.py:9:5:9:15 | user_input2 | provenance | AdditionalTaintStep | +| test_path_validation.py:9:5:9:15 | user_input2 | test_path_validation.py:11:5:11:12 | full_url | provenance | | +| test_path_validation.py:9:19:9:25 | request | test_path_validation.py:9:5:9:15 | user_input2 | provenance | AdditionalTaintStep | +| test_path_validation.py:10:5:10:7 | url | test_path_validation.py:14:32:14:34 | url | provenance | Sink:MaD:2 | +| test_path_validation.py:10:5:10:7 | url | test_path_validation.py:16:32:16:34 | url | provenance | Sink:MaD:2 | +| test_path_validation.py:11:5:11:12 | full_url | test_path_validation.py:19:32:19:39 | full_url | provenance | Sink:MaD:2 | +| test_path_validation.py:11:5:11:12 | full_url | test_path_validation.py:21:32:21:39 | full_url | provenance | Sink:MaD:2 | +| test_path_validation.py:24:5:24:14 | user_input | test_path_validation.py:26:5:26:7 | url | provenance | | +| test_path_validation.py:24:18:24:24 | request | test_path_validation.py:24:5:24:14 | user_input | provenance | AdditionalTaintStep | +| test_path_validation.py:24:18:24:24 | request | test_path_validation.py:25:5:25:15 | user_input2 | provenance | AdditionalTaintStep | +| test_path_validation.py:25:5:25:15 | user_input2 | test_path_validation.py:27:5:27:12 | full_url | provenance | | +| test_path_validation.py:25:19:25:25 | request | test_path_validation.py:25:5:25:15 | user_input2 | provenance | AdditionalTaintStep | +| test_path_validation.py:26:5:26:7 | url | test_path_validation.py:30:29:30:31 | url | provenance | Sink:MaD:1 | +| test_path_validation.py:26:5:26:7 | url | test_path_validation.py:32:29:32:31 | url | provenance | Sink:MaD:1 | +| test_path_validation.py:27:5:27:12 | full_url | test_path_validation.py:35:29:35:36 | full_url | provenance | Sink:MaD:1 | +| test_path_validation.py:27:5:27:12 | full_url | test_path_validation.py:37:29:37:36 | full_url | provenance | Sink:MaD:1 | +| test_path_validation.py:40:5:40:14 | user_input | test_path_validation.py:42:5:42:7 | url | provenance | | +| test_path_validation.py:40:18:40:24 | request | test_path_validation.py:40:5:40:14 | user_input | provenance | AdditionalTaintStep | +| test_path_validation.py:40:18:40:24 | request | test_path_validation.py:41:5:41:15 | user_input2 | provenance | AdditionalTaintStep | +| test_path_validation.py:41:5:41:15 | user_input2 | test_path_validation.py:43:5:43:12 | full_url | provenance | | +| test_path_validation.py:41:19:41:25 | request | test_path_validation.py:41:5:41:15 | user_input2 | provenance | AdditionalTaintStep | +| test_path_validation.py:42:5:42:7 | url | test_path_validation.py:46:39:46:41 | url | provenance | Sink:MaD:4 | +| test_path_validation.py:42:5:42:7 | url | test_path_validation.py:48:39:48:41 | url | provenance | Sink:MaD:4 | +| test_path_validation.py:43:5:43:12 | full_url | test_path_validation.py:51:39:51:46 | full_url | provenance | Sink:MaD:4 | +| test_path_validation.py:43:5:43:12 | full_url | test_path_validation.py:53:39:53:46 | full_url | provenance | Sink:MaD:4 | +| test_path_validation.py:57:5:57:14 | user_input | test_path_validation.py:61:5:61:7 | url | provenance | | +| test_path_validation.py:57:18:57:24 | request | test_path_validation.py:57:5:57:14 | user_input | provenance | AdditionalTaintStep | +| test_path_validation.py:61:5:61:7 | url | test_path_validation.py:64:32:64:34 | url | provenance | Sink:MaD:2 | +| test_path_validation.py:61:5:61:7 | url | test_path_validation.py:66:32:66:34 | url | provenance | Sink:MaD:2 | +| test_path_validation.py:61:5:61:7 | url | test_path_validation.py:69:32:69:34 | url | provenance | Sink:MaD:2 | +| test_path_validation.py:61:5:61:7 | url | test_path_validation.py:71:32:71:34 | url | provenance | Sink:MaD:2 | +| test_path_validation.py:61:5:61:7 | url | test_path_validation.py:74:32:74:34 | url | provenance | Sink:MaD:2 | +| test_path_validation.py:61:5:61:7 | url | test_path_validation.py:76:32:76:34 | url | provenance | Sink:MaD:2 | +| test_path_validation.py:61:5:61:7 | url | test_path_validation.py:79:32:79:34 | url | provenance | Sink:MaD:2 | +| test_path_validation.py:61:5:61:7 | url | test_path_validation.py:81:32:81:34 | url | provenance | Sink:MaD:2 | +| test_path_validation.py:61:5:61:7 | url | test_path_validation.py:85:32:85:34 | url | provenance | Sink:MaD:2 | +| test_path_validation.py:61:5:61:7 | url | test_path_validation.py:87:32:87:34 | url | provenance | Sink:MaD:2 | +| test_path_validation.py:61:5:61:7 | url | test_path_validation.py:90:32:90:34 | url | provenance | Sink:MaD:2 | +| test_path_validation.py:61:5:61:7 | url | test_path_validation.py:92:32:92:34 | url | provenance | Sink:MaD:2 | +| test_path_validation.py:61:5:61:7 | url | test_path_validation.py:95:32:95:34 | url | provenance | Sink:MaD:2 | +| test_path_validation.py:61:5:61:7 | url | test_path_validation.py:97:32:97:34 | url | provenance | Sink:MaD:2 | +| test_path_validation.py:61:5:61:7 | url | test_path_validation.py:100:32:100:34 | url | provenance | Sink:MaD:2 | +| test_path_validation.py:61:5:61:7 | url | test_path_validation.py:102:32:102:34 | url | provenance | Sink:MaD:2 | +| test_path_validation.py:61:5:61:7 | url | test_path_validation.py:105:32:105:34 | url | provenance | Sink:MaD:2 | +| test_path_validation.py:61:5:61:7 | url | test_path_validation.py:107:32:107:34 | url | provenance | Sink:MaD:2 | +| test_path_validation.py:61:5:61:7 | url | test_path_validation.py:110:32:110:34 | url | provenance | Sink:MaD:2 | +| test_path_validation.py:61:5:61:7 | url | test_path_validation.py:112:32:112:34 | url | provenance | Sink:MaD:2 | +| test_path_validation.py:61:5:61:7 | url | test_path_validation.py:115:32:115:34 | url | provenance | Sink:MaD:2 | +| test_path_validation.py:61:5:61:7 | url | test_path_validation.py:117:32:117:34 | url | provenance | Sink:MaD:2 | +| test_path_validation.py:61:5:61:7 | url | test_path_validation.py:120:32:120:34 | url | provenance | Sink:MaD:2 | +| test_path_validation.py:61:5:61:7 | url | test_path_validation.py:122:32:122:34 | url | provenance | Sink:MaD:2 | +| test_path_validation.py:61:5:61:7 | url | test_path_validation.py:125:32:125:34 | url | provenance | Sink:MaD:2 | +| test_path_validation.py:61:5:61:7 | url | test_path_validation.py:127:32:127:34 | url | provenance | Sink:MaD:2 | +| test_path_validation.py:61:5:61:7 | url | test_path_validation.py:130:32:130:34 | url | provenance | Sink:MaD:2 | +| test_path_validation.py:61:5:61:7 | url | test_path_validation.py:132:32:132:34 | url | provenance | Sink:MaD:2 | +| test_requests.py:1:19:1:25 | After ImportMember | test_requests.py:1:19:1:25 | request | provenance | | +| test_requests.py:1:19:1:25 | request | test_requests.py:7:18:7:24 | request | provenance | | +| test_requests.py:1:19:1:25 | request | test_requests.py:14:18:14:24 | request | provenance | | +| test_requests.py:1:19:1:25 | request | test_requests.py:20:18:20:24 | request | provenance | | +| test_requests.py:7:5:7:14 | user_input | test_requests.py:9:18:9:27 | user_input | provenance | | +| test_requests.py:7:18:7:24 | request | test_requests.py:7:5:7:14 | user_input | provenance | AdditionalTaintStep | +| test_requests.py:14:5:14:14 | user_input | test_requests.py:17:17:17:26 | user_input | provenance | | +| test_requests.py:14:18:14:24 | request | test_requests.py:14:5:14:14 | user_input | provenance | AdditionalTaintStep | +| test_requests.py:20:5:20:14 | user_input | test_requests.py:22:34:22:43 | user_input | provenance | | +| test_requests.py:20:18:20:24 | request | test_requests.py:20:5:20:14 | user_input | provenance | AdditionalTaintStep | models | 1 | Sink: azure.keyvault.keys.KeyClient!; Call.Argument[0,vault_url:]; request-forgery | | 2 | Sink: azure.keyvault.secrets.SecretClient!; Call.Argument[0,vault_url:]; request-forgery | @@ -243,190 +238,185 @@ models | 4 | Sink: azure.storage.fileshare.ShareFileClient!; Member[from_file_url].Argument[0,file_url:]; request-forgery | | 5 | Sink: azure; Member[storage].Member[blob].Member[download_blob_from_url].Argument[0,blob_url:]; request-forgery | nodes -| full_partial_test.py:1:19:1:25 | ControlFlowNode for ImportMember | semmle.label | ControlFlowNode for ImportMember | -| full_partial_test.py:1:19:1:25 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| full_partial_test.py:7:5:7:14 | ControlFlowNode for user_input | semmle.label | ControlFlowNode for user_input | -| full_partial_test.py:7:18:7:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| full_partial_test.py:8:5:8:13 | ControlFlowNode for query_val | semmle.label | ControlFlowNode for query_val | -| full_partial_test.py:8:17:8:23 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| full_partial_test.py:11:18:11:27 | ControlFlowNode for user_input | semmle.label | ControlFlowNode for user_input | -| full_partial_test.py:13:5:13:7 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:15:18:15:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:20:5:20:7 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:22:18:22:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:25:5:25:7 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:27:18:27:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:41:5:41:14 | ControlFlowNode for user_input | semmle.label | ControlFlowNode for user_input | -| full_partial_test.py:41:18:41:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| full_partial_test.py:42:5:42:13 | ControlFlowNode for query_val | semmle.label | ControlFlowNode for query_val | -| full_partial_test.py:42:17:42:23 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| full_partial_test.py:45:5:45:7 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:47:18:47:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:49:5:49:7 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:51:18:51:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:53:5:53:7 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:55:18:55:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:57:5:57:7 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:59:18:59:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:61:5:61:7 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:63:18:63:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:66:5:66:14 | ControlFlowNode for user_input | semmle.label | ControlFlowNode for user_input | -| full_partial_test.py:66:18:66:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| full_partial_test.py:67:5:67:13 | ControlFlowNode for query_val | semmle.label | ControlFlowNode for query_val | -| full_partial_test.py:67:17:67:23 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| full_partial_test.py:70:5:70:7 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:72:18:72:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:74:5:74:7 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:76:18:76:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:78:5:78:7 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:78:11:78:59 | ControlFlowNode for BinaryExpr | semmle.label | ControlFlowNode for BinaryExpr | -| full_partial_test.py:78:38:78:47 | ControlFlowNode for user_input | semmle.label | ControlFlowNode for user_input | -| full_partial_test.py:78:38:78:58 | ControlFlowNode for Tuple [Tuple element at index 0] | semmle.label | ControlFlowNode for Tuple [Tuple element at index 0] | -| full_partial_test.py:78:38:78:58 | ControlFlowNode for Tuple [Tuple element at index 1] | semmle.label | ControlFlowNode for Tuple [Tuple element at index 1] | -| full_partial_test.py:78:50:78:58 | ControlFlowNode for query_val | semmle.label | ControlFlowNode for query_val | -| full_partial_test.py:80:18:80:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:83:5:83:14 | ControlFlowNode for user_input | semmle.label | ControlFlowNode for user_input | -| full_partial_test.py:83:18:83:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| full_partial_test.py:84:5:84:13 | ControlFlowNode for query_val | semmle.label | ControlFlowNode for query_val | -| full_partial_test.py:84:17:84:23 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| full_partial_test.py:87:5:87:7 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:89:18:89:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:91:5:91:7 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:93:18:93:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:95:5:95:7 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:97:18:97:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:101:5:101:14 | ControlFlowNode for user_input | semmle.label | ControlFlowNode for user_input | -| full_partial_test.py:101:18:101:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| full_partial_test.py:103:5:103:7 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:105:18:105:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:108:5:108:14 | ControlFlowNode for user_input | semmle.label | ControlFlowNode for user_input | -| full_partial_test.py:108:18:108:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| full_partial_test.py:110:5:110:7 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:112:18:112:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:115:5:115:14 | ControlFlowNode for user_input | semmle.label | ControlFlowNode for user_input | -| full_partial_test.py:115:18:115:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| full_partial_test.py:117:5:117:7 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:119:18:119:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:122:5:122:14 | ControlFlowNode for user_input | semmle.label | ControlFlowNode for user_input | -| full_partial_test.py:122:18:122:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| full_partial_test.py:124:5:124:7 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:126:18:126:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:129:5:129:14 | ControlFlowNode for user_input | semmle.label | ControlFlowNode for user_input | -| full_partial_test.py:129:18:129:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| full_partial_test.py:134:5:134:7 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:136:18:136:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:139:5:139:14 | ControlFlowNode for user_input | semmle.label | ControlFlowNode for user_input | -| full_partial_test.py:139:18:139:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| full_partial_test.py:141:5:141:7 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:143:18:143:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_azure_client.py:6:19:6:25 | ControlFlowNode for ImportMember | semmle.label | ControlFlowNode for ImportMember | -| test_azure_client.py:6:19:6:25 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| test_azure_client.py:9:5:9:14 | ControlFlowNode for user_input | semmle.label | ControlFlowNode for user_input | -| test_azure_client.py:9:18:9:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| test_azure_client.py:10:5:10:15 | ControlFlowNode for user_input2 | semmle.label | ControlFlowNode for user_input2 | -| test_azure_client.py:10:19:10:25 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| test_azure_client.py:12:5:12:7 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_azure_client.py:13:5:13:12 | ControlFlowNode for full_url | semmle.label | ControlFlowNode for full_url | -| test_azure_client.py:15:28:15:30 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_azure_client.py:16:28:16:35 | ControlFlowNode for full_url | semmle.label | ControlFlowNode for full_url | -| test_azure_client.py:17:35:17:37 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_azure_client.py:18:35:18:42 | ControlFlowNode for full_url | semmle.label | ControlFlowNode for full_url | -| test_azure_client.py:19:15:19:17 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_azure_client.py:20:15:20:22 | ControlFlowNode for full_url | semmle.label | ControlFlowNode for full_url | -| test_azure_client.py:21:54:21:56 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_azure_client.py:22:54:22:61 | ControlFlowNode for full_url | semmle.label | ControlFlowNode for full_url | -| test_azure_client.py:24:37:24:39 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_azure_client.py:25:37:25:44 | ControlFlowNode for full_url | semmle.label | ControlFlowNode for full_url | -| test_http_client.py:1:19:1:25 | ControlFlowNode for ImportMember | semmle.label | ControlFlowNode for ImportMember | -| test_http_client.py:1:19:1:25 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| test_http_client.py:9:5:9:15 | ControlFlowNode for unsafe_host | semmle.label | ControlFlowNode for unsafe_host | -| test_http_client.py:9:19:9:25 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| test_http_client.py:10:5:10:15 | ControlFlowNode for unsafe_path | semmle.label | ControlFlowNode for unsafe_path | -| test_http_client.py:10:19:10:25 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| test_http_client.py:11:5:11:14 | ControlFlowNode for user_input | semmle.label | ControlFlowNode for user_input | -| test_http_client.py:11:18:11:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| test_http_client.py:13:27:13:37 | ControlFlowNode for unsafe_host | semmle.label | ControlFlowNode for unsafe_host | -| test_http_client.py:15:25:15:35 | ControlFlowNode for unsafe_path | semmle.label | ControlFlowNode for unsafe_path | -| test_http_client.py:19:27:19:37 | ControlFlowNode for unsafe_host | semmle.label | ControlFlowNode for unsafe_host | -| test_http_client.py:21:25:21:35 | ControlFlowNode for unsafe_path | semmle.label | ControlFlowNode for unsafe_path | -| test_http_client.py:28:27:28:37 | ControlFlowNode for unsafe_host | semmle.label | ControlFlowNode for unsafe_host | -| test_http_client.py:34:25:34:35 | ControlFlowNode for unsafe_path | semmle.label | ControlFlowNode for unsafe_path | -| test_http_client.py:36:5:36:8 | ControlFlowNode for path | semmle.label | ControlFlowNode for path | -| test_http_client.py:39:25:39:28 | ControlFlowNode for path | semmle.label | ControlFlowNode for path | -| test_http_client.py:41:5:41:8 | ControlFlowNode for path | semmle.label | ControlFlowNode for path | -| test_http_client.py:44:25:44:28 | ControlFlowNode for path | semmle.label | ControlFlowNode for path | -| test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | semmle.label | ControlFlowNode for ImportMember | -| test_path_validation.py:5:19:5:25 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| test_path_validation.py:8:5:8:14 | ControlFlowNode for user_input | semmle.label | ControlFlowNode for user_input | -| test_path_validation.py:8:18:8:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| test_path_validation.py:9:5:9:15 | ControlFlowNode for user_input2 | semmle.label | ControlFlowNode for user_input2 | -| test_path_validation.py:9:19:9:25 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| test_path_validation.py:10:5:10:7 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:11:5:11:12 | ControlFlowNode for full_url | semmle.label | ControlFlowNode for full_url | -| test_path_validation.py:14:32:14:34 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:16:32:16:34 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:19:32:19:39 | ControlFlowNode for full_url | semmle.label | ControlFlowNode for full_url | -| test_path_validation.py:21:32:21:39 | ControlFlowNode for full_url | semmle.label | ControlFlowNode for full_url | -| test_path_validation.py:24:5:24:14 | ControlFlowNode for user_input | semmle.label | ControlFlowNode for user_input | -| test_path_validation.py:24:18:24:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| test_path_validation.py:25:5:25:15 | ControlFlowNode for user_input2 | semmle.label | ControlFlowNode for user_input2 | -| test_path_validation.py:25:19:25:25 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| test_path_validation.py:26:5:26:7 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:27:5:27:12 | ControlFlowNode for full_url | semmle.label | ControlFlowNode for full_url | -| test_path_validation.py:30:29:30:31 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:32:29:32:31 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:35:29:35:36 | ControlFlowNode for full_url | semmle.label | ControlFlowNode for full_url | -| test_path_validation.py:37:29:37:36 | ControlFlowNode for full_url | semmle.label | ControlFlowNode for full_url | -| test_path_validation.py:40:5:40:14 | ControlFlowNode for user_input | semmle.label | ControlFlowNode for user_input | -| test_path_validation.py:40:18:40:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| test_path_validation.py:41:5:41:15 | ControlFlowNode for user_input2 | semmle.label | ControlFlowNode for user_input2 | -| test_path_validation.py:41:19:41:25 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| test_path_validation.py:42:5:42:7 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:43:5:43:12 | ControlFlowNode for full_url | semmle.label | ControlFlowNode for full_url | -| test_path_validation.py:46:39:46:41 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:48:39:48:41 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:51:39:51:46 | ControlFlowNode for full_url | semmle.label | ControlFlowNode for full_url | -| test_path_validation.py:53:39:53:46 | ControlFlowNode for full_url | semmle.label | ControlFlowNode for full_url | -| test_path_validation.py:57:5:57:14 | ControlFlowNode for user_input | semmle.label | ControlFlowNode for user_input | -| test_path_validation.py:57:18:57:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:64:32:64:34 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:66:32:66:34 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:69:32:69:34 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:71:32:71:34 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:74:32:74:34 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:76:32:76:34 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:79:32:79:34 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:81:32:81:34 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:85:32:85:34 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:87:32:87:34 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:90:32:90:34 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:92:32:92:34 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:95:32:95:34 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:97:32:97:34 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:100:32:100:34 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:102:32:102:34 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:105:32:105:34 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:107:32:107:34 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:110:32:110:34 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:112:32:112:34 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:115:32:115:34 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:117:32:117:34 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:120:32:120:34 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:122:32:122:34 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:125:32:125:34 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:127:32:127:34 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:130:32:130:34 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:132:32:132:34 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_requests.py:1:19:1:25 | ControlFlowNode for ImportMember | semmle.label | ControlFlowNode for ImportMember | -| test_requests.py:1:19:1:25 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| test_requests.py:7:5:7:14 | ControlFlowNode for user_input | semmle.label | ControlFlowNode for user_input | -| test_requests.py:7:18:7:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| test_requests.py:9:18:9:27 | ControlFlowNode for user_input | semmle.label | ControlFlowNode for user_input | -| test_requests.py:14:5:14:14 | ControlFlowNode for user_input | semmle.label | ControlFlowNode for user_input | -| test_requests.py:14:18:14:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| test_requests.py:17:17:17:26 | ControlFlowNode for user_input | semmle.label | ControlFlowNode for user_input | -| test_requests.py:20:5:20:14 | ControlFlowNode for user_input | semmle.label | ControlFlowNode for user_input | -| test_requests.py:20:18:20:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| test_requests.py:22:34:22:43 | ControlFlowNode for user_input | semmle.label | ControlFlowNode for user_input | +| full_partial_test.py:1:19:1:25 | After ImportMember | semmle.label | After ImportMember | +| full_partial_test.py:1:19:1:25 | request | semmle.label | request | +| full_partial_test.py:7:5:7:14 | user_input | semmle.label | user_input | +| full_partial_test.py:7:18:7:24 | request | semmle.label | request | +| full_partial_test.py:8:5:8:13 | query_val | semmle.label | query_val | +| full_partial_test.py:8:17:8:23 | request | semmle.label | request | +| full_partial_test.py:11:18:11:27 | user_input | semmle.label | user_input | +| full_partial_test.py:13:5:13:7 | url | semmle.label | url | +| full_partial_test.py:15:18:15:20 | url | semmle.label | url | +| full_partial_test.py:20:5:20:7 | url | semmle.label | url | +| full_partial_test.py:22:18:22:20 | url | semmle.label | url | +| full_partial_test.py:25:5:25:7 | url | semmle.label | url | +| full_partial_test.py:27:18:27:20 | url | semmle.label | url | +| full_partial_test.py:41:5:41:14 | user_input | semmle.label | user_input | +| full_partial_test.py:41:18:41:24 | request | semmle.label | request | +| full_partial_test.py:42:5:42:13 | query_val | semmle.label | query_val | +| full_partial_test.py:42:17:42:23 | request | semmle.label | request | +| full_partial_test.py:45:5:45:7 | url | semmle.label | url | +| full_partial_test.py:47:18:47:20 | url | semmle.label | url | +| full_partial_test.py:49:5:49:7 | url | semmle.label | url | +| full_partial_test.py:51:18:51:20 | url | semmle.label | url | +| full_partial_test.py:53:5:53:7 | url | semmle.label | url | +| full_partial_test.py:55:18:55:20 | url | semmle.label | url | +| full_partial_test.py:57:5:57:7 | url | semmle.label | url | +| full_partial_test.py:59:18:59:20 | url | semmle.label | url | +| full_partial_test.py:61:5:61:7 | url | semmle.label | url | +| full_partial_test.py:63:18:63:20 | url | semmle.label | url | +| full_partial_test.py:66:5:66:14 | user_input | semmle.label | user_input | +| full_partial_test.py:66:18:66:24 | request | semmle.label | request | +| full_partial_test.py:67:5:67:13 | query_val | semmle.label | query_val | +| full_partial_test.py:67:17:67:23 | request | semmle.label | request | +| full_partial_test.py:70:5:70:7 | url | semmle.label | url | +| full_partial_test.py:72:18:72:20 | url | semmle.label | url | +| full_partial_test.py:74:5:74:7 | url | semmle.label | url | +| full_partial_test.py:76:18:76:20 | url | semmle.label | url | +| full_partial_test.py:78:5:78:7 | url | semmle.label | url | +| full_partial_test.py:80:18:80:20 | url | semmle.label | url | +| full_partial_test.py:83:5:83:14 | user_input | semmle.label | user_input | +| full_partial_test.py:83:18:83:24 | request | semmle.label | request | +| full_partial_test.py:84:5:84:13 | query_val | semmle.label | query_val | +| full_partial_test.py:84:17:84:23 | request | semmle.label | request | +| full_partial_test.py:87:5:87:7 | url | semmle.label | url | +| full_partial_test.py:89:18:89:20 | url | semmle.label | url | +| full_partial_test.py:91:5:91:7 | url | semmle.label | url | +| full_partial_test.py:93:18:93:20 | url | semmle.label | url | +| full_partial_test.py:95:5:95:7 | url | semmle.label | url | +| full_partial_test.py:97:18:97:20 | url | semmle.label | url | +| full_partial_test.py:101:5:101:14 | user_input | semmle.label | user_input | +| full_partial_test.py:101:18:101:24 | request | semmle.label | request | +| full_partial_test.py:103:5:103:7 | url | semmle.label | url | +| full_partial_test.py:105:18:105:20 | url | semmle.label | url | +| full_partial_test.py:108:5:108:14 | user_input | semmle.label | user_input | +| full_partial_test.py:108:18:108:24 | request | semmle.label | request | +| full_partial_test.py:110:5:110:7 | url | semmle.label | url | +| full_partial_test.py:112:18:112:20 | url | semmle.label | url | +| full_partial_test.py:115:5:115:14 | user_input | semmle.label | user_input | +| full_partial_test.py:115:18:115:24 | request | semmle.label | request | +| full_partial_test.py:117:5:117:7 | url | semmle.label | url | +| full_partial_test.py:119:18:119:20 | url | semmle.label | url | +| full_partial_test.py:122:5:122:14 | user_input | semmle.label | user_input | +| full_partial_test.py:122:18:122:24 | request | semmle.label | request | +| full_partial_test.py:124:5:124:7 | url | semmle.label | url | +| full_partial_test.py:126:18:126:20 | url | semmle.label | url | +| full_partial_test.py:129:5:129:14 | user_input | semmle.label | user_input | +| full_partial_test.py:129:18:129:24 | request | semmle.label | request | +| full_partial_test.py:134:5:134:7 | url | semmle.label | url | +| full_partial_test.py:136:18:136:20 | url | semmle.label | url | +| full_partial_test.py:139:5:139:14 | user_input | semmle.label | user_input | +| full_partial_test.py:139:18:139:24 | request | semmle.label | request | +| full_partial_test.py:141:5:141:7 | url | semmle.label | url | +| full_partial_test.py:143:18:143:20 | url | semmle.label | url | +| test_azure_client.py:6:19:6:25 | After ImportMember | semmle.label | After ImportMember | +| test_azure_client.py:6:19:6:25 | request | semmle.label | request | +| test_azure_client.py:9:5:9:14 | user_input | semmle.label | user_input | +| test_azure_client.py:9:18:9:24 | request | semmle.label | request | +| test_azure_client.py:10:5:10:15 | user_input2 | semmle.label | user_input2 | +| test_azure_client.py:10:19:10:25 | request | semmle.label | request | +| test_azure_client.py:12:5:12:7 | url | semmle.label | url | +| test_azure_client.py:13:5:13:12 | full_url | semmle.label | full_url | +| test_azure_client.py:15:28:15:30 | url | semmle.label | url | +| test_azure_client.py:16:28:16:35 | full_url | semmle.label | full_url | +| test_azure_client.py:17:35:17:37 | url | semmle.label | url | +| test_azure_client.py:18:35:18:42 | full_url | semmle.label | full_url | +| test_azure_client.py:19:15:19:17 | url | semmle.label | url | +| test_azure_client.py:20:15:20:22 | full_url | semmle.label | full_url | +| test_azure_client.py:21:54:21:56 | url | semmle.label | url | +| test_azure_client.py:22:54:22:61 | full_url | semmle.label | full_url | +| test_azure_client.py:24:37:24:39 | url | semmle.label | url | +| test_azure_client.py:25:37:25:44 | full_url | semmle.label | full_url | +| test_http_client.py:1:19:1:25 | After ImportMember | semmle.label | After ImportMember | +| test_http_client.py:1:19:1:25 | request | semmle.label | request | +| test_http_client.py:9:5:9:15 | unsafe_host | semmle.label | unsafe_host | +| test_http_client.py:9:19:9:25 | request | semmle.label | request | +| test_http_client.py:10:5:10:15 | unsafe_path | semmle.label | unsafe_path | +| test_http_client.py:10:19:10:25 | request | semmle.label | request | +| test_http_client.py:11:5:11:14 | user_input | semmle.label | user_input | +| test_http_client.py:11:18:11:24 | request | semmle.label | request | +| test_http_client.py:13:27:13:37 | unsafe_host | semmle.label | unsafe_host | +| test_http_client.py:15:25:15:35 | unsafe_path | semmle.label | unsafe_path | +| test_http_client.py:19:27:19:37 | unsafe_host | semmle.label | unsafe_host | +| test_http_client.py:21:25:21:35 | unsafe_path | semmle.label | unsafe_path | +| test_http_client.py:28:27:28:37 | unsafe_host | semmle.label | unsafe_host | +| test_http_client.py:34:25:34:35 | unsafe_path | semmle.label | unsafe_path | +| test_http_client.py:36:5:36:8 | path | semmle.label | path | +| test_http_client.py:39:25:39:28 | path | semmle.label | path | +| test_http_client.py:41:5:41:8 | path | semmle.label | path | +| test_http_client.py:44:25:44:28 | path | semmle.label | path | +| test_path_validation.py:5:19:5:25 | After ImportMember | semmle.label | After ImportMember | +| test_path_validation.py:5:19:5:25 | request | semmle.label | request | +| test_path_validation.py:8:5:8:14 | user_input | semmle.label | user_input | +| test_path_validation.py:8:18:8:24 | request | semmle.label | request | +| test_path_validation.py:9:5:9:15 | user_input2 | semmle.label | user_input2 | +| test_path_validation.py:9:19:9:25 | request | semmle.label | request | +| test_path_validation.py:10:5:10:7 | url | semmle.label | url | +| test_path_validation.py:11:5:11:12 | full_url | semmle.label | full_url | +| test_path_validation.py:14:32:14:34 | url | semmle.label | url | +| test_path_validation.py:16:32:16:34 | url | semmle.label | url | +| test_path_validation.py:19:32:19:39 | full_url | semmle.label | full_url | +| test_path_validation.py:21:32:21:39 | full_url | semmle.label | full_url | +| test_path_validation.py:24:5:24:14 | user_input | semmle.label | user_input | +| test_path_validation.py:24:18:24:24 | request | semmle.label | request | +| test_path_validation.py:25:5:25:15 | user_input2 | semmle.label | user_input2 | +| test_path_validation.py:25:19:25:25 | request | semmle.label | request | +| test_path_validation.py:26:5:26:7 | url | semmle.label | url | +| test_path_validation.py:27:5:27:12 | full_url | semmle.label | full_url | +| test_path_validation.py:30:29:30:31 | url | semmle.label | url | +| test_path_validation.py:32:29:32:31 | url | semmle.label | url | +| test_path_validation.py:35:29:35:36 | full_url | semmle.label | full_url | +| test_path_validation.py:37:29:37:36 | full_url | semmle.label | full_url | +| test_path_validation.py:40:5:40:14 | user_input | semmle.label | user_input | +| test_path_validation.py:40:18:40:24 | request | semmle.label | request | +| test_path_validation.py:41:5:41:15 | user_input2 | semmle.label | user_input2 | +| test_path_validation.py:41:19:41:25 | request | semmle.label | request | +| test_path_validation.py:42:5:42:7 | url | semmle.label | url | +| test_path_validation.py:43:5:43:12 | full_url | semmle.label | full_url | +| test_path_validation.py:46:39:46:41 | url | semmle.label | url | +| test_path_validation.py:48:39:48:41 | url | semmle.label | url | +| test_path_validation.py:51:39:51:46 | full_url | semmle.label | full_url | +| test_path_validation.py:53:39:53:46 | full_url | semmle.label | full_url | +| test_path_validation.py:57:5:57:14 | user_input | semmle.label | user_input | +| test_path_validation.py:57:18:57:24 | request | semmle.label | request | +| test_path_validation.py:61:5:61:7 | url | semmle.label | url | +| test_path_validation.py:64:32:64:34 | url | semmle.label | url | +| test_path_validation.py:66:32:66:34 | url | semmle.label | url | +| test_path_validation.py:69:32:69:34 | url | semmle.label | url | +| test_path_validation.py:71:32:71:34 | url | semmle.label | url | +| test_path_validation.py:74:32:74:34 | url | semmle.label | url | +| test_path_validation.py:76:32:76:34 | url | semmle.label | url | +| test_path_validation.py:79:32:79:34 | url | semmle.label | url | +| test_path_validation.py:81:32:81:34 | url | semmle.label | url | +| test_path_validation.py:85:32:85:34 | url | semmle.label | url | +| test_path_validation.py:87:32:87:34 | url | semmle.label | url | +| test_path_validation.py:90:32:90:34 | url | semmle.label | url | +| test_path_validation.py:92:32:92:34 | url | semmle.label | url | +| test_path_validation.py:95:32:95:34 | url | semmle.label | url | +| test_path_validation.py:97:32:97:34 | url | semmle.label | url | +| test_path_validation.py:100:32:100:34 | url | semmle.label | url | +| test_path_validation.py:102:32:102:34 | url | semmle.label | url | +| test_path_validation.py:105:32:105:34 | url | semmle.label | url | +| test_path_validation.py:107:32:107:34 | url | semmle.label | url | +| test_path_validation.py:110:32:110:34 | url | semmle.label | url | +| test_path_validation.py:112:32:112:34 | url | semmle.label | url | +| test_path_validation.py:115:32:115:34 | url | semmle.label | url | +| test_path_validation.py:117:32:117:34 | url | semmle.label | url | +| test_path_validation.py:120:32:120:34 | url | semmle.label | url | +| test_path_validation.py:122:32:122:34 | url | semmle.label | url | +| test_path_validation.py:125:32:125:34 | url | semmle.label | url | +| test_path_validation.py:127:32:127:34 | url | semmle.label | url | +| test_path_validation.py:130:32:130:34 | url | semmle.label | url | +| test_path_validation.py:132:32:132:34 | url | semmle.label | url | +| test_requests.py:1:19:1:25 | After ImportMember | semmle.label | After ImportMember | +| test_requests.py:1:19:1:25 | request | semmle.label | request | +| test_requests.py:7:5:7:14 | user_input | semmle.label | user_input | +| test_requests.py:7:18:7:24 | request | semmle.label | request | +| test_requests.py:9:18:9:27 | user_input | semmle.label | user_input | +| test_requests.py:14:5:14:14 | user_input | semmle.label | user_input | +| test_requests.py:14:18:14:24 | request | semmle.label | request | +| test_requests.py:17:17:17:26 | user_input | semmle.label | user_input | +| test_requests.py:20:5:20:14 | user_input | semmle.label | user_input | +| test_requests.py:20:18:20:24 | request | semmle.label | request | +| test_requests.py:22:34:22:43 | user_input | semmle.label | user_input | subpaths diff --git a/python/ql/test/query-tests/Security/CWE-942-CorsMisconfigurationMiddleware/CorsMisconfigurationMiddleware.expected b/python/ql/test/query-tests/Security/CWE-942-CorsMisconfigurationMiddleware/CorsMisconfigurationMiddleware.expected index 520cf9ab0d2e..b74c40629e8d 100644 --- a/python/ql/test/query-tests/Security/CWE-942-CorsMisconfigurationMiddleware/CorsMisconfigurationMiddleware.expected +++ b/python/ql/test/query-tests/Security/CWE-942-CorsMisconfigurationMiddleware/CorsMisconfigurationMiddleware.expected @@ -1,2 +1,2 @@ -| fastapi.py:10:1:16:1 | ControlFlowNode for Attribute() | This CORS middleware uses a vulnerable configuration that allows arbitrary websites to make authenticated cross-site requests | -| starlette.py:8:5:8:75 | ControlFlowNode for Middleware() | This CORS middleware uses a vulnerable configuration that allows arbitrary websites to make authenticated cross-site requests | +| fastapi.py:10:1:16:1 | After Attribute() | This CORS middleware uses a vulnerable configuration that allows arbitrary websites to make authenticated cross-site requests | +| starlette.py:8:5:8:75 | After Middleware() | This CORS middleware uses a vulnerable configuration that allows arbitrary websites to make authenticated cross-site requests | diff --git a/python/ql/test/query-tests/Security/CWE-943-NoSqlInjection/NoSqlInjection.expected b/python/ql/test/query-tests/Security/CWE-943-NoSqlInjection/NoSqlInjection.expected index fad6762e0f61..ffc1de8f9b41 100644 --- a/python/ql/test/query-tests/Security/CWE-943-NoSqlInjection/NoSqlInjection.expected +++ b/python/ql/test/query-tests/Security/CWE-943-NoSqlInjection/NoSqlInjection.expected @@ -1,322 +1,269 @@ edges -| PoC/server.py:1:26:1:32 | ControlFlowNode for ImportMember | PoC/server.py:1:26:1:32 | ControlFlowNode for request | provenance | | -| PoC/server.py:1:26:1:32 | ControlFlowNode for request | PoC/server.py:26:21:26:27 | ControlFlowNode for request | provenance | | -| PoC/server.py:1:26:1:32 | ControlFlowNode for request | PoC/server.py:43:14:43:20 | ControlFlowNode for request | provenance | | -| PoC/server.py:1:26:1:32 | ControlFlowNode for request | PoC/server.py:52:14:52:20 | ControlFlowNode for request | provenance | | -| PoC/server.py:1:26:1:32 | ControlFlowNode for request | PoC/server.py:77:14:77:20 | ControlFlowNode for request | provenance | | -| PoC/server.py:1:26:1:32 | ControlFlowNode for request | PoC/server.py:98:14:98:20 | ControlFlowNode for request | provenance | | -| PoC/server.py:26:5:26:17 | ControlFlowNode for author_string | PoC/server.py:27:25:27:37 | ControlFlowNode for author_string | provenance | | -| PoC/server.py:26:21:26:27 | ControlFlowNode for request | PoC/server.py:26:5:26:17 | ControlFlowNode for author_string | provenance | AdditionalTaintStep | -| PoC/server.py:27:5:27:10 | ControlFlowNode for author | PoC/server.py:30:38:30:43 | ControlFlowNode for author | provenance | | -| PoC/server.py:27:5:27:10 | ControlFlowNode for author | PoC/server.py:31:45:31:50 | ControlFlowNode for author | provenance | | -| PoC/server.py:27:14:27:38 | ControlFlowNode for Attribute() | PoC/server.py:27:5:27:10 | ControlFlowNode for author | provenance | | -| PoC/server.py:27:25:27:37 | ControlFlowNode for author_string | PoC/server.py:27:14:27:38 | ControlFlowNode for Attribute() | provenance | Config | -| PoC/server.py:30:38:30:43 | ControlFlowNode for author | PoC/server.py:30:27:30:44 | ControlFlowNode for Dict | provenance | | -| PoC/server.py:31:45:31:50 | ControlFlowNode for author | PoC/server.py:31:34:31:51 | ControlFlowNode for Dict | provenance | | -| PoC/server.py:43:5:43:10 | ControlFlowNode for author | PoC/server.py:47:38:47:67 | ControlFlowNode for BinaryExpr | provenance | | -| PoC/server.py:43:14:43:20 | ControlFlowNode for request | PoC/server.py:43:5:43:10 | ControlFlowNode for author | provenance | AdditionalTaintStep | -| PoC/server.py:47:38:47:67 | ControlFlowNode for BinaryExpr | PoC/server.py:47:27:47:68 | ControlFlowNode for Dict | provenance | Config | -| PoC/server.py:52:5:52:10 | ControlFlowNode for author | PoC/server.py:54:17:54:70 | ControlFlowNode for BinaryExpr | provenance | | -| PoC/server.py:52:14:52:20 | ControlFlowNode for request | PoC/server.py:52:5:52:10 | ControlFlowNode for author | provenance | AdditionalTaintStep | -| PoC/server.py:53:5:53:10 | ControlFlowNode for search | PoC/server.py:61:51:61:56 | ControlFlowNode for search | provenance | | -| PoC/server.py:53:14:57:5 | ControlFlowNode for Dict | PoC/server.py:53:5:53:10 | ControlFlowNode for search | provenance | | -| PoC/server.py:54:17:54:70 | ControlFlowNode for BinaryExpr | PoC/server.py:53:14:57:5 | ControlFlowNode for Dict | provenance | Config | -| PoC/server.py:61:37:61:57 | ControlFlowNode for Dict [Dictionary element at key $function] | PoC/server.py:61:27:61:58 | ControlFlowNode for Dict | provenance | | -| PoC/server.py:61:51:61:56 | ControlFlowNode for search | PoC/server.py:61:37:61:57 | ControlFlowNode for Dict [Dictionary element at key $function] | provenance | | -| PoC/server.py:77:5:77:10 | ControlFlowNode for author | PoC/server.py:80:23:80:101 | ControlFlowNode for BinaryExpr | provenance | | -| PoC/server.py:77:14:77:20 | ControlFlowNode for request | PoC/server.py:77:5:77:10 | ControlFlowNode for author | provenance | AdditionalTaintStep | -| PoC/server.py:78:5:78:15 | ControlFlowNode for accumulator | PoC/server.py:86:37:86:47 | ControlFlowNode for accumulator | provenance | | -| PoC/server.py:78:19:83:5 | ControlFlowNode for Dict | PoC/server.py:78:5:78:15 | ControlFlowNode for accumulator | provenance | | -| PoC/server.py:80:23:80:101 | ControlFlowNode for BinaryExpr | PoC/server.py:78:19:83:5 | ControlFlowNode for Dict | provenance | Config | -| PoC/server.py:84:5:84:9 | ControlFlowNode for group [Dictionary element at key author, Dictionary element at key $accumulator] | PoC/server.py:91:41:91:45 | ControlFlowNode for group [Dictionary element at key author, Dictionary element at key $accumulator] | provenance | | -| PoC/server.py:84:5:84:9 | ControlFlowNode for group [Dictionary element at key author, Dictionary element at key $accumulator] | PoC/server.py:92:50:92:54 | ControlFlowNode for group [Dictionary element at key author, Dictionary element at key $accumulator] | provenance | | -| PoC/server.py:84:13:87:5 | ControlFlowNode for Dict [Dictionary element at key author, Dictionary element at key $accumulator] | PoC/server.py:84:5:84:9 | ControlFlowNode for group [Dictionary element at key author, Dictionary element at key $accumulator] | provenance | | -| PoC/server.py:86:19:86:49 | ControlFlowNode for Dict [Dictionary element at key $accumulator] | PoC/server.py:84:13:87:5 | ControlFlowNode for Dict [Dictionary element at key author, Dictionary element at key $accumulator] | provenance | | -| PoC/server.py:86:37:86:47 | ControlFlowNode for accumulator | PoC/server.py:86:19:86:49 | ControlFlowNode for Dict [Dictionary element at key $accumulator] | provenance | | -| PoC/server.py:91:41:91:45 | ControlFlowNode for group [Dictionary element at key author, Dictionary element at key $accumulator] | PoC/server.py:91:29:91:47 | ControlFlowNode for Dict | provenance | | -| PoC/server.py:92:50:92:54 | ControlFlowNode for group [Dictionary element at key author, Dictionary element at key $accumulator] | PoC/server.py:92:38:92:56 | ControlFlowNode for Dict | provenance | | -| PoC/server.py:98:5:98:10 | ControlFlowNode for author | PoC/server.py:99:5:99:10 | ControlFlowNode for mapper | provenance | | -| PoC/server.py:98:14:98:20 | ControlFlowNode for request | PoC/server.py:98:5:98:10 | ControlFlowNode for author | provenance | AdditionalTaintStep | -| PoC/server.py:99:5:99:10 | ControlFlowNode for mapper | PoC/server.py:102:9:102:14 | ControlFlowNode for mapper | provenance | | -| flask_mongoengine_bad.py:1:26:1:32 | ControlFlowNode for ImportMember | flask_mongoengine_bad.py:1:26:1:32 | ControlFlowNode for request | provenance | | -| flask_mongoengine_bad.py:1:26:1:32 | ControlFlowNode for request | flask_mongoengine_bad.py:19:21:19:27 | ControlFlowNode for request | provenance | | -| flask_mongoengine_bad.py:1:26:1:32 | ControlFlowNode for request | flask_mongoengine_bad.py:26:21:26:27 | ControlFlowNode for request | provenance | | -| flask_mongoengine_bad.py:19:5:19:17 | ControlFlowNode for unsafe_search | flask_mongoengine_bad.py:20:30:20:42 | ControlFlowNode for unsafe_search | provenance | | -| flask_mongoengine_bad.py:19:21:19:27 | ControlFlowNode for request | flask_mongoengine_bad.py:19:5:19:17 | ControlFlowNode for unsafe_search | provenance | AdditionalTaintStep | -| flask_mongoengine_bad.py:20:5:20:15 | ControlFlowNode for json_search | flask_mongoengine_bad.py:22:34:22:44 | ControlFlowNode for json_search | provenance | | -| flask_mongoengine_bad.py:20:19:20:43 | ControlFlowNode for Attribute() | flask_mongoengine_bad.py:20:5:20:15 | ControlFlowNode for json_search | provenance | | -| flask_mongoengine_bad.py:20:30:20:42 | ControlFlowNode for unsafe_search | flask_mongoengine_bad.py:20:19:20:43 | ControlFlowNode for Attribute() | provenance | Config | -| flask_mongoengine_bad.py:26:5:26:17 | ControlFlowNode for unsafe_search | flask_mongoengine_bad.py:27:30:27:42 | ControlFlowNode for unsafe_search | provenance | | -| flask_mongoengine_bad.py:26:21:26:27 | ControlFlowNode for request | flask_mongoengine_bad.py:26:5:26:17 | ControlFlowNode for unsafe_search | provenance | AdditionalTaintStep | -| flask_mongoengine_bad.py:27:5:27:15 | ControlFlowNode for json_search | flask_mongoengine_bad.py:30:48:30:58 | ControlFlowNode for json_search | provenance | | -| flask_mongoengine_bad.py:27:19:27:43 | ControlFlowNode for Attribute() | flask_mongoengine_bad.py:27:5:27:15 | ControlFlowNode for json_search | provenance | | -| flask_mongoengine_bad.py:27:30:27:42 | ControlFlowNode for unsafe_search | flask_mongoengine_bad.py:27:19:27:43 | ControlFlowNode for Attribute() | provenance | Config | -| flask_mongoengine_bad.py:30:48:30:58 | ControlFlowNode for json_search | flask_mongoengine_bad.py:30:39:30:59 | ControlFlowNode for Dict | provenance | | -| flask_pymongo_bad.py:1:26:1:32 | ControlFlowNode for ImportMember | flask_pymongo_bad.py:1:26:1:32 | ControlFlowNode for request | provenance | | -| flask_pymongo_bad.py:1:26:1:32 | ControlFlowNode for request | flask_pymongo_bad.py:11:21:11:27 | ControlFlowNode for request | provenance | | -| flask_pymongo_bad.py:11:5:11:17 | ControlFlowNode for unsafe_search | flask_pymongo_bad.py:12:30:12:42 | ControlFlowNode for unsafe_search | provenance | | -| flask_pymongo_bad.py:11:21:11:27 | ControlFlowNode for request | flask_pymongo_bad.py:11:5:11:17 | ControlFlowNode for unsafe_search | provenance | AdditionalTaintStep | -| flask_pymongo_bad.py:12:5:12:15 | ControlFlowNode for json_search | flask_pymongo_bad.py:14:40:14:50 | ControlFlowNode for json_search | provenance | | -| flask_pymongo_bad.py:12:19:12:43 | ControlFlowNode for Attribute() | flask_pymongo_bad.py:12:5:12:15 | ControlFlowNode for json_search | provenance | | -| flask_pymongo_bad.py:12:30:12:42 | ControlFlowNode for unsafe_search | flask_pymongo_bad.py:12:19:12:43 | ControlFlowNode for Attribute() | provenance | Config | -| flask_pymongo_bad.py:14:40:14:50 | ControlFlowNode for json_search | flask_pymongo_bad.py:14:31:14:51 | ControlFlowNode for Dict | provenance | | -| mongoengine_bad.py:1:26:1:32 | ControlFlowNode for ImportMember | mongoengine_bad.py:1:26:1:32 | ControlFlowNode for request | provenance | | -| mongoengine_bad.py:1:26:1:32 | ControlFlowNode for request | mongoengine_bad.py:18:21:18:27 | ControlFlowNode for request | provenance | | -| mongoengine_bad.py:1:26:1:32 | ControlFlowNode for request | mongoengine_bad.py:26:21:26:27 | ControlFlowNode for request | provenance | | -| mongoengine_bad.py:1:26:1:32 | ControlFlowNode for request | mongoengine_bad.py:34:21:34:27 | ControlFlowNode for request | provenance | | -| mongoengine_bad.py:1:26:1:32 | ControlFlowNode for request | mongoengine_bad.py:42:21:42:27 | ControlFlowNode for request | provenance | | -| mongoengine_bad.py:1:26:1:32 | ControlFlowNode for request | mongoengine_bad.py:50:21:50:27 | ControlFlowNode for request | provenance | | -| mongoengine_bad.py:1:26:1:32 | ControlFlowNode for request | mongoengine_bad.py:57:21:57:27 | ControlFlowNode for request | provenance | | -| mongoengine_bad.py:18:5:18:17 | ControlFlowNode for unsafe_search | mongoengine_bad.py:19:30:19:42 | ControlFlowNode for unsafe_search | provenance | | -| mongoengine_bad.py:18:21:18:27 | ControlFlowNode for request | mongoengine_bad.py:18:5:18:17 | ControlFlowNode for unsafe_search | provenance | AdditionalTaintStep | -| mongoengine_bad.py:19:5:19:15 | ControlFlowNode for json_search | mongoengine_bad.py:22:35:22:45 | ControlFlowNode for json_search | provenance | | -| mongoengine_bad.py:19:19:19:43 | ControlFlowNode for Attribute() | mongoengine_bad.py:19:5:19:15 | ControlFlowNode for json_search | provenance | | -| mongoengine_bad.py:19:30:19:42 | ControlFlowNode for unsafe_search | mongoengine_bad.py:19:19:19:43 | ControlFlowNode for Attribute() | provenance | Config | -| mongoengine_bad.py:22:35:22:45 | ControlFlowNode for json_search | mongoengine_bad.py:22:26:22:46 | ControlFlowNode for Dict | provenance | | -| mongoengine_bad.py:26:5:26:17 | ControlFlowNode for unsafe_search | mongoengine_bad.py:27:30:27:42 | ControlFlowNode for unsafe_search | provenance | | -| mongoengine_bad.py:26:21:26:27 | ControlFlowNode for request | mongoengine_bad.py:26:5:26:17 | ControlFlowNode for unsafe_search | provenance | AdditionalTaintStep | -| mongoengine_bad.py:27:5:27:15 | ControlFlowNode for json_search | mongoengine_bad.py:30:35:30:45 | ControlFlowNode for json_search | provenance | | -| mongoengine_bad.py:27:19:27:43 | ControlFlowNode for Attribute() | mongoengine_bad.py:27:5:27:15 | ControlFlowNode for json_search | provenance | | -| mongoengine_bad.py:27:30:27:42 | ControlFlowNode for unsafe_search | mongoengine_bad.py:27:19:27:43 | ControlFlowNode for Attribute() | provenance | Config | -| mongoengine_bad.py:30:35:30:45 | ControlFlowNode for json_search | mongoengine_bad.py:30:26:30:46 | ControlFlowNode for Dict | provenance | | -| mongoengine_bad.py:34:5:34:17 | ControlFlowNode for unsafe_search | mongoengine_bad.py:35:30:35:42 | ControlFlowNode for unsafe_search | provenance | | -| mongoengine_bad.py:34:21:34:27 | ControlFlowNode for request | mongoengine_bad.py:34:5:34:17 | ControlFlowNode for unsafe_search | provenance | AdditionalTaintStep | -| mongoengine_bad.py:35:5:35:15 | ControlFlowNode for json_search | mongoengine_bad.py:38:35:38:45 | ControlFlowNode for json_search | provenance | | -| mongoengine_bad.py:35:19:35:43 | ControlFlowNode for Attribute() | mongoengine_bad.py:35:5:35:15 | ControlFlowNode for json_search | provenance | | -| mongoengine_bad.py:35:30:35:42 | ControlFlowNode for unsafe_search | mongoengine_bad.py:35:19:35:43 | ControlFlowNode for Attribute() | provenance | Config | -| mongoengine_bad.py:38:35:38:45 | ControlFlowNode for json_search | mongoengine_bad.py:38:26:38:46 | ControlFlowNode for Dict | provenance | | -| mongoengine_bad.py:42:5:42:17 | ControlFlowNode for unsafe_search | mongoengine_bad.py:43:30:43:42 | ControlFlowNode for unsafe_search | provenance | | -| mongoengine_bad.py:42:21:42:27 | ControlFlowNode for request | mongoengine_bad.py:42:5:42:17 | ControlFlowNode for unsafe_search | provenance | AdditionalTaintStep | -| mongoengine_bad.py:43:5:43:15 | ControlFlowNode for json_search | mongoengine_bad.py:46:35:46:45 | ControlFlowNode for json_search | provenance | | -| mongoengine_bad.py:43:19:43:43 | ControlFlowNode for Attribute() | mongoengine_bad.py:43:5:43:15 | ControlFlowNode for json_search | provenance | | -| mongoengine_bad.py:43:30:43:42 | ControlFlowNode for unsafe_search | mongoengine_bad.py:43:19:43:43 | ControlFlowNode for Attribute() | provenance | Config | -| mongoengine_bad.py:46:35:46:45 | ControlFlowNode for json_search | mongoengine_bad.py:46:26:46:46 | ControlFlowNode for Dict | provenance | | -| mongoengine_bad.py:50:5:50:17 | ControlFlowNode for unsafe_search | mongoengine_bad.py:51:30:51:42 | ControlFlowNode for unsafe_search | provenance | | -| mongoengine_bad.py:50:21:50:27 | ControlFlowNode for request | mongoengine_bad.py:50:5:50:17 | ControlFlowNode for unsafe_search | provenance | AdditionalTaintStep | -| mongoengine_bad.py:51:5:51:15 | ControlFlowNode for json_search | mongoengine_bad.py:53:34:53:44 | ControlFlowNode for json_search | provenance | | -| mongoengine_bad.py:51:19:51:43 | ControlFlowNode for Attribute() | mongoengine_bad.py:51:5:51:15 | ControlFlowNode for json_search | provenance | | -| mongoengine_bad.py:51:30:51:42 | ControlFlowNode for unsafe_search | mongoengine_bad.py:51:19:51:43 | ControlFlowNode for Attribute() | provenance | Config | -| mongoengine_bad.py:57:5:57:17 | ControlFlowNode for unsafe_search | mongoengine_bad.py:58:30:58:42 | ControlFlowNode for unsafe_search | provenance | | -| mongoengine_bad.py:57:21:57:27 | ControlFlowNode for request | mongoengine_bad.py:57:5:57:17 | ControlFlowNode for unsafe_search | provenance | AdditionalTaintStep | -| mongoengine_bad.py:58:5:58:15 | ControlFlowNode for json_search | mongoengine_bad.py:61:38:61:48 | ControlFlowNode for json_search | provenance | | -| mongoengine_bad.py:58:19:58:43 | ControlFlowNode for Attribute() | mongoengine_bad.py:58:5:58:15 | ControlFlowNode for json_search | provenance | | -| mongoengine_bad.py:58:30:58:42 | ControlFlowNode for unsafe_search | mongoengine_bad.py:58:19:58:43 | ControlFlowNode for Attribute() | provenance | Config | -| mongoengine_bad.py:61:38:61:48 | ControlFlowNode for json_search | mongoengine_bad.py:61:29:61:49 | ControlFlowNode for Dict | provenance | | -| pymongo_test.py:1:26:1:32 | ControlFlowNode for ImportMember | pymongo_test.py:1:26:1:32 | ControlFlowNode for request | provenance | | -| pymongo_test.py:1:26:1:32 | ControlFlowNode for request | pymongo_test.py:12:21:12:27 | ControlFlowNode for request | provenance | | -| pymongo_test.py:1:26:1:32 | ControlFlowNode for request | pymongo_test.py:29:27:29:33 | ControlFlowNode for request | provenance | | -| pymongo_test.py:1:26:1:32 | ControlFlowNode for request | pymongo_test.py:39:27:39:33 | ControlFlowNode for request | provenance | | -| pymongo_test.py:1:26:1:32 | ControlFlowNode for request | pymongo_test.py:52:26:52:32 | ControlFlowNode for request | provenance | | -| pymongo_test.py:12:5:12:17 | ControlFlowNode for unsafe_search | pymongo_test.py:13:30:13:42 | ControlFlowNode for unsafe_search | provenance | | -| pymongo_test.py:12:21:12:27 | ControlFlowNode for request | pymongo_test.py:12:5:12:17 | ControlFlowNode for unsafe_search | provenance | AdditionalTaintStep | -| pymongo_test.py:13:5:13:15 | ControlFlowNode for json_search | pymongo_test.py:15:51:15:61 | ControlFlowNode for json_search | provenance | | -| pymongo_test.py:13:19:13:43 | ControlFlowNode for Attribute() | pymongo_test.py:13:5:13:15 | ControlFlowNode for json_search | provenance | | -| pymongo_test.py:13:30:13:42 | ControlFlowNode for unsafe_search | pymongo_test.py:13:19:13:43 | ControlFlowNode for Attribute() | provenance | Config | -| pymongo_test.py:15:51:15:61 | ControlFlowNode for json_search | pymongo_test.py:15:42:15:62 | ControlFlowNode for Dict | provenance | | -| pymongo_test.py:29:5:29:12 | ControlFlowNode for event_id | pymongo_test.py:33:45:33:72 | ControlFlowNode for Fstring | provenance | | -| pymongo_test.py:29:16:29:51 | ControlFlowNode for Attribute() | pymongo_test.py:29:5:29:12 | ControlFlowNode for event_id | provenance | | -| pymongo_test.py:29:27:29:33 | ControlFlowNode for request | pymongo_test.py:29:27:29:50 | ControlFlowNode for Subscript | provenance | AdditionalTaintStep | -| pymongo_test.py:29:27:29:50 | ControlFlowNode for Subscript | pymongo_test.py:29:16:29:51 | ControlFlowNode for Attribute() | provenance | Config | -| pymongo_test.py:33:45:33:72 | ControlFlowNode for Fstring | pymongo_test.py:33:34:33:73 | ControlFlowNode for Dict | provenance | | -| pymongo_test.py:33:45:33:72 | ControlFlowNode for Fstring | pymongo_test.py:33:34:33:73 | ControlFlowNode for Dict | provenance | Decoding-NoSQL | -| pymongo_test.py:39:5:39:12 | ControlFlowNode for event_id | pymongo_test.py:43:45:43:72 | ControlFlowNode for Fstring | provenance | | -| pymongo_test.py:39:16:39:51 | ControlFlowNode for Attribute() | pymongo_test.py:39:5:39:12 | ControlFlowNode for event_id | provenance | | -| pymongo_test.py:39:27:39:33 | ControlFlowNode for request | pymongo_test.py:39:27:39:50 | ControlFlowNode for Subscript | provenance | AdditionalTaintStep | -| pymongo_test.py:39:27:39:50 | ControlFlowNode for Subscript | pymongo_test.py:39:16:39:51 | ControlFlowNode for Attribute() | provenance | Config | -| pymongo_test.py:43:45:43:72 | ControlFlowNode for Fstring | pymongo_test.py:43:34:43:73 | ControlFlowNode for Dict | provenance | | -| pymongo_test.py:43:45:43:72 | ControlFlowNode for Fstring | pymongo_test.py:43:34:43:73 | ControlFlowNode for Dict | provenance | Decoding-NoSQL | -| pymongo_test.py:52:5:52:11 | ControlFlowNode for decoded | pymongo_test.py:55:17:55:23 | ControlFlowNode for decoded | provenance | | -| pymongo_test.py:52:15:52:50 | ControlFlowNode for Attribute() | pymongo_test.py:52:5:52:11 | ControlFlowNode for decoded | provenance | | -| pymongo_test.py:52:26:52:32 | ControlFlowNode for request | pymongo_test.py:52:26:52:49 | ControlFlowNode for Subscript | provenance | AdditionalTaintStep | -| pymongo_test.py:52:26:52:49 | ControlFlowNode for Subscript | pymongo_test.py:52:15:52:50 | ControlFlowNode for Attribute() | provenance | Config | -| pymongo_test.py:54:5:54:10 | ControlFlowNode for search | pymongo_test.py:59:49:59:54 | ControlFlowNode for search | provenance | | -| pymongo_test.py:54:5:54:10 | ControlFlowNode for search [Dictionary element at key body] | pymongo_test.py:59:49:59:54 | ControlFlowNode for search [Dictionary element at key body] | provenance | | -| pymongo_test.py:54:14:58:5 | ControlFlowNode for Dict | pymongo_test.py:54:5:54:10 | ControlFlowNode for search | provenance | | -| pymongo_test.py:54:14:58:5 | ControlFlowNode for Dict [Dictionary element at key body] | pymongo_test.py:54:5:54:10 | ControlFlowNode for search [Dictionary element at key body] | provenance | | -| pymongo_test.py:55:17:55:23 | ControlFlowNode for decoded | pymongo_test.py:54:14:58:5 | ControlFlowNode for Dict | provenance | | -| pymongo_test.py:55:17:55:23 | ControlFlowNode for decoded | pymongo_test.py:54:14:58:5 | ControlFlowNode for Dict | provenance | Decoding-NoSQL | -| pymongo_test.py:55:17:55:23 | ControlFlowNode for decoded | pymongo_test.py:54:14:58:5 | ControlFlowNode for Dict [Dictionary element at key body] | provenance | | -| pymongo_test.py:55:17:55:23 | ControlFlowNode for decoded | pymongo_test.py:61:49:61:55 | ControlFlowNode for decoded | provenance | | -| pymongo_test.py:55:17:55:23 | ControlFlowNode for decoded | pymongo_test.py:62:35:62:41 | ControlFlowNode for decoded | provenance | | -| pymongo_test.py:55:17:55:23 | ControlFlowNode for decoded | pymongo_test.py:63:25:63:31 | ControlFlowNode for decoded | provenance | | -| pymongo_test.py:59:35:59:55 | ControlFlowNode for Dict [Dictionary element at key $function, Dictionary element at key body] | pymongo_test.py:59:25:59:56 | ControlFlowNode for Dict | provenance | | -| pymongo_test.py:59:35:59:55 | ControlFlowNode for Dict [Dictionary element at key $function] | pymongo_test.py:59:25:59:56 | ControlFlowNode for Dict | provenance | | -| pymongo_test.py:59:49:59:54 | ControlFlowNode for search | pymongo_test.py:59:35:59:55 | ControlFlowNode for Dict [Dictionary element at key $function] | provenance | | -| pymongo_test.py:59:49:59:54 | ControlFlowNode for search [Dictionary element at key body] | pymongo_test.py:59:35:59:55 | ControlFlowNode for Dict [Dictionary element at key $function, Dictionary element at key body] | provenance | | -| pymongo_test.py:61:35:61:56 | ControlFlowNode for Dict [Dictionary element at key $function] | pymongo_test.py:61:25:61:57 | ControlFlowNode for Dict | provenance | | -| pymongo_test.py:61:49:61:55 | ControlFlowNode for decoded | pymongo_test.py:61:35:61:56 | ControlFlowNode for Dict [Dictionary element at key $function] | provenance | | -| pymongo_test.py:62:35:62:41 | ControlFlowNode for decoded | pymongo_test.py:62:25:62:42 | ControlFlowNode for Dict | provenance | | +| PoC/server.py:1:26:1:32 | After ImportMember | PoC/server.py:1:26:1:32 | request | provenance | | +| PoC/server.py:1:26:1:32 | request | PoC/server.py:26:21:26:27 | request | provenance | | +| PoC/server.py:1:26:1:32 | request | PoC/server.py:43:14:43:20 | request | provenance | | +| PoC/server.py:1:26:1:32 | request | PoC/server.py:52:14:52:20 | request | provenance | | +| PoC/server.py:1:26:1:32 | request | PoC/server.py:77:14:77:20 | request | provenance | | +| PoC/server.py:1:26:1:32 | request | PoC/server.py:98:14:98:20 | request | provenance | | +| PoC/server.py:26:5:26:17 | author_string | PoC/server.py:27:25:27:37 | author_string | provenance | | +| PoC/server.py:26:21:26:27 | request | PoC/server.py:26:5:26:17 | author_string | provenance | AdditionalTaintStep | +| PoC/server.py:27:5:27:10 | author | PoC/server.py:30:27:30:44 | After Dict | provenance | | +| PoC/server.py:27:5:27:10 | author | PoC/server.py:31:34:31:51 | After Dict | provenance | | +| PoC/server.py:27:14:27:38 | After Attribute() | PoC/server.py:27:5:27:10 | author | provenance | | +| PoC/server.py:27:25:27:37 | author_string | PoC/server.py:27:14:27:38 | After Attribute() | provenance | Config | +| PoC/server.py:43:5:43:10 | author | PoC/server.py:47:38:47:67 | After BinaryExpr | provenance | | +| PoC/server.py:43:14:43:20 | request | PoC/server.py:43:5:43:10 | author | provenance | AdditionalTaintStep | +| PoC/server.py:47:38:47:67 | After BinaryExpr | PoC/server.py:47:27:47:68 | After Dict | provenance | Config | +| PoC/server.py:52:5:52:10 | author | PoC/server.py:54:17:54:70 | After BinaryExpr | provenance | | +| PoC/server.py:52:14:52:20 | request | PoC/server.py:52:5:52:10 | author | provenance | AdditionalTaintStep | +| PoC/server.py:53:5:53:10 | search | PoC/server.py:61:27:61:58 | After Dict | provenance | | +| PoC/server.py:53:14:57:5 | After Dict | PoC/server.py:53:5:53:10 | search | provenance | | +| PoC/server.py:54:17:54:70 | After BinaryExpr | PoC/server.py:53:14:57:5 | After Dict | provenance | Config | +| PoC/server.py:77:5:77:10 | author | PoC/server.py:80:23:80:101 | After BinaryExpr | provenance | | +| PoC/server.py:77:14:77:20 | request | PoC/server.py:77:5:77:10 | author | provenance | AdditionalTaintStep | +| PoC/server.py:78:5:78:15 | accumulator | PoC/server.py:84:5:84:9 | group | provenance | | +| PoC/server.py:78:19:83:5 | After Dict | PoC/server.py:78:5:78:15 | accumulator | provenance | | +| PoC/server.py:80:23:80:101 | After BinaryExpr | PoC/server.py:78:19:83:5 | After Dict | provenance | Config | +| PoC/server.py:84:5:84:9 | group | PoC/server.py:91:29:91:47 | After Dict | provenance | | +| PoC/server.py:84:5:84:9 | group | PoC/server.py:92:38:92:56 | After Dict | provenance | | +| PoC/server.py:98:5:98:10 | author | PoC/server.py:99:5:99:10 | mapper | provenance | | +| PoC/server.py:98:14:98:20 | request | PoC/server.py:98:5:98:10 | author | provenance | AdditionalTaintStep | +| PoC/server.py:99:5:99:10 | mapper | PoC/server.py:102:9:102:14 | mapper | provenance | | +| flask_mongoengine_bad.py:1:26:1:32 | After ImportMember | flask_mongoengine_bad.py:1:26:1:32 | request | provenance | | +| flask_mongoengine_bad.py:1:26:1:32 | request | flask_mongoengine_bad.py:19:21:19:27 | request | provenance | | +| flask_mongoengine_bad.py:1:26:1:32 | request | flask_mongoengine_bad.py:26:21:26:27 | request | provenance | | +| flask_mongoengine_bad.py:19:5:19:17 | unsafe_search | flask_mongoengine_bad.py:20:30:20:42 | unsafe_search | provenance | | +| flask_mongoengine_bad.py:19:21:19:27 | request | flask_mongoengine_bad.py:19:5:19:17 | unsafe_search | provenance | AdditionalTaintStep | +| flask_mongoengine_bad.py:20:5:20:15 | json_search | flask_mongoengine_bad.py:22:34:22:44 | json_search | provenance | | +| flask_mongoengine_bad.py:20:19:20:43 | After Attribute() | flask_mongoengine_bad.py:20:5:20:15 | json_search | provenance | | +| flask_mongoengine_bad.py:20:30:20:42 | unsafe_search | flask_mongoengine_bad.py:20:19:20:43 | After Attribute() | provenance | Config | +| flask_mongoengine_bad.py:26:5:26:17 | unsafe_search | flask_mongoengine_bad.py:27:30:27:42 | unsafe_search | provenance | | +| flask_mongoengine_bad.py:26:21:26:27 | request | flask_mongoengine_bad.py:26:5:26:17 | unsafe_search | provenance | AdditionalTaintStep | +| flask_mongoengine_bad.py:27:5:27:15 | json_search | flask_mongoengine_bad.py:30:39:30:59 | After Dict | provenance | | +| flask_mongoengine_bad.py:27:19:27:43 | After Attribute() | flask_mongoengine_bad.py:27:5:27:15 | json_search | provenance | | +| flask_mongoengine_bad.py:27:30:27:42 | unsafe_search | flask_mongoengine_bad.py:27:19:27:43 | After Attribute() | provenance | Config | +| flask_pymongo_bad.py:1:26:1:32 | After ImportMember | flask_pymongo_bad.py:1:26:1:32 | request | provenance | | +| flask_pymongo_bad.py:1:26:1:32 | request | flask_pymongo_bad.py:11:21:11:27 | request | provenance | | +| flask_pymongo_bad.py:11:5:11:17 | unsafe_search | flask_pymongo_bad.py:12:30:12:42 | unsafe_search | provenance | | +| flask_pymongo_bad.py:11:21:11:27 | request | flask_pymongo_bad.py:11:5:11:17 | unsafe_search | provenance | AdditionalTaintStep | +| flask_pymongo_bad.py:12:5:12:15 | json_search | flask_pymongo_bad.py:14:31:14:51 | After Dict | provenance | | +| flask_pymongo_bad.py:12:19:12:43 | After Attribute() | flask_pymongo_bad.py:12:5:12:15 | json_search | provenance | | +| flask_pymongo_bad.py:12:30:12:42 | unsafe_search | flask_pymongo_bad.py:12:19:12:43 | After Attribute() | provenance | Config | +| mongoengine_bad.py:1:26:1:32 | After ImportMember | mongoengine_bad.py:1:26:1:32 | request | provenance | | +| mongoengine_bad.py:1:26:1:32 | request | mongoengine_bad.py:18:21:18:27 | request | provenance | | +| mongoengine_bad.py:1:26:1:32 | request | mongoengine_bad.py:26:21:26:27 | request | provenance | | +| mongoengine_bad.py:1:26:1:32 | request | mongoengine_bad.py:34:21:34:27 | request | provenance | | +| mongoengine_bad.py:1:26:1:32 | request | mongoengine_bad.py:42:21:42:27 | request | provenance | | +| mongoengine_bad.py:1:26:1:32 | request | mongoengine_bad.py:50:21:50:27 | request | provenance | | +| mongoengine_bad.py:1:26:1:32 | request | mongoengine_bad.py:57:21:57:27 | request | provenance | | +| mongoengine_bad.py:18:5:18:17 | unsafe_search | mongoengine_bad.py:19:30:19:42 | unsafe_search | provenance | | +| mongoengine_bad.py:18:21:18:27 | request | mongoengine_bad.py:18:5:18:17 | unsafe_search | provenance | AdditionalTaintStep | +| mongoengine_bad.py:19:5:19:15 | json_search | mongoengine_bad.py:22:26:22:46 | After Dict | provenance | | +| mongoengine_bad.py:19:19:19:43 | After Attribute() | mongoengine_bad.py:19:5:19:15 | json_search | provenance | | +| mongoengine_bad.py:19:30:19:42 | unsafe_search | mongoengine_bad.py:19:19:19:43 | After Attribute() | provenance | Config | +| mongoengine_bad.py:26:5:26:17 | unsafe_search | mongoengine_bad.py:27:30:27:42 | unsafe_search | provenance | | +| mongoengine_bad.py:26:21:26:27 | request | mongoengine_bad.py:26:5:26:17 | unsafe_search | provenance | AdditionalTaintStep | +| mongoengine_bad.py:27:5:27:15 | json_search | mongoengine_bad.py:30:26:30:46 | After Dict | provenance | | +| mongoengine_bad.py:27:19:27:43 | After Attribute() | mongoengine_bad.py:27:5:27:15 | json_search | provenance | | +| mongoengine_bad.py:27:30:27:42 | unsafe_search | mongoengine_bad.py:27:19:27:43 | After Attribute() | provenance | Config | +| mongoengine_bad.py:34:5:34:17 | unsafe_search | mongoengine_bad.py:35:30:35:42 | unsafe_search | provenance | | +| mongoengine_bad.py:34:21:34:27 | request | mongoengine_bad.py:34:5:34:17 | unsafe_search | provenance | AdditionalTaintStep | +| mongoengine_bad.py:35:5:35:15 | json_search | mongoengine_bad.py:38:26:38:46 | After Dict | provenance | | +| mongoengine_bad.py:35:19:35:43 | After Attribute() | mongoengine_bad.py:35:5:35:15 | json_search | provenance | | +| mongoengine_bad.py:35:30:35:42 | unsafe_search | mongoengine_bad.py:35:19:35:43 | After Attribute() | provenance | Config | +| mongoengine_bad.py:42:5:42:17 | unsafe_search | mongoengine_bad.py:43:30:43:42 | unsafe_search | provenance | | +| mongoengine_bad.py:42:21:42:27 | request | mongoengine_bad.py:42:5:42:17 | unsafe_search | provenance | AdditionalTaintStep | +| mongoengine_bad.py:43:5:43:15 | json_search | mongoengine_bad.py:46:26:46:46 | After Dict | provenance | | +| mongoengine_bad.py:43:19:43:43 | After Attribute() | mongoengine_bad.py:43:5:43:15 | json_search | provenance | | +| mongoengine_bad.py:43:30:43:42 | unsafe_search | mongoengine_bad.py:43:19:43:43 | After Attribute() | provenance | Config | +| mongoengine_bad.py:50:5:50:17 | unsafe_search | mongoengine_bad.py:51:30:51:42 | unsafe_search | provenance | | +| mongoengine_bad.py:50:21:50:27 | request | mongoengine_bad.py:50:5:50:17 | unsafe_search | provenance | AdditionalTaintStep | +| mongoengine_bad.py:51:5:51:15 | json_search | mongoengine_bad.py:53:34:53:44 | json_search | provenance | | +| mongoengine_bad.py:51:19:51:43 | After Attribute() | mongoengine_bad.py:51:5:51:15 | json_search | provenance | | +| mongoengine_bad.py:51:30:51:42 | unsafe_search | mongoengine_bad.py:51:19:51:43 | After Attribute() | provenance | Config | +| mongoengine_bad.py:57:5:57:17 | unsafe_search | mongoengine_bad.py:58:30:58:42 | unsafe_search | provenance | | +| mongoengine_bad.py:57:21:57:27 | request | mongoengine_bad.py:57:5:57:17 | unsafe_search | provenance | AdditionalTaintStep | +| mongoengine_bad.py:58:5:58:15 | json_search | mongoengine_bad.py:61:29:61:49 | After Dict | provenance | | +| mongoengine_bad.py:58:19:58:43 | After Attribute() | mongoengine_bad.py:58:5:58:15 | json_search | provenance | | +| mongoengine_bad.py:58:30:58:42 | unsafe_search | mongoengine_bad.py:58:19:58:43 | After Attribute() | provenance | Config | +| pymongo_test.py:1:26:1:32 | After ImportMember | pymongo_test.py:1:26:1:32 | request | provenance | | +| pymongo_test.py:1:26:1:32 | request | pymongo_test.py:12:21:12:27 | request | provenance | | +| pymongo_test.py:1:26:1:32 | request | pymongo_test.py:29:27:29:33 | request | provenance | | +| pymongo_test.py:1:26:1:32 | request | pymongo_test.py:39:27:39:33 | request | provenance | | +| pymongo_test.py:1:26:1:32 | request | pymongo_test.py:52:26:52:32 | request | provenance | | +| pymongo_test.py:12:5:12:17 | unsafe_search | pymongo_test.py:13:30:13:42 | unsafe_search | provenance | | +| pymongo_test.py:12:21:12:27 | request | pymongo_test.py:12:5:12:17 | unsafe_search | provenance | AdditionalTaintStep | +| pymongo_test.py:13:5:13:15 | json_search | pymongo_test.py:15:42:15:62 | After Dict | provenance | | +| pymongo_test.py:13:19:13:43 | After Attribute() | pymongo_test.py:13:5:13:15 | json_search | provenance | | +| pymongo_test.py:13:30:13:42 | unsafe_search | pymongo_test.py:13:19:13:43 | After Attribute() | provenance | Config | +| pymongo_test.py:29:5:29:12 | event_id | pymongo_test.py:33:45:33:72 | After Fstring | provenance | | +| pymongo_test.py:29:16:29:51 | After Attribute() | pymongo_test.py:29:5:29:12 | event_id | provenance | | +| pymongo_test.py:29:27:29:33 | request | pymongo_test.py:29:27:29:50 | After Subscript | provenance | AdditionalTaintStep | +| pymongo_test.py:29:27:29:50 | After Subscript | pymongo_test.py:29:16:29:51 | After Attribute() | provenance | Config | +| pymongo_test.py:33:45:33:72 | After Fstring | pymongo_test.py:33:34:33:73 | After Dict | provenance | | +| pymongo_test.py:33:45:33:72 | After Fstring | pymongo_test.py:33:34:33:73 | After Dict | provenance | Decoding-NoSQL | +| pymongo_test.py:39:5:39:12 | event_id | pymongo_test.py:43:45:43:72 | After Fstring | provenance | | +| pymongo_test.py:39:16:39:51 | After Attribute() | pymongo_test.py:39:5:39:12 | event_id | provenance | | +| pymongo_test.py:39:27:39:33 | request | pymongo_test.py:39:27:39:50 | After Subscript | provenance | AdditionalTaintStep | +| pymongo_test.py:39:27:39:50 | After Subscript | pymongo_test.py:39:16:39:51 | After Attribute() | provenance | Config | +| pymongo_test.py:43:45:43:72 | After Fstring | pymongo_test.py:43:34:43:73 | After Dict | provenance | | +| pymongo_test.py:43:45:43:72 | After Fstring | pymongo_test.py:43:34:43:73 | After Dict | provenance | Decoding-NoSQL | +| pymongo_test.py:52:5:52:11 | decoded | pymongo_test.py:55:17:55:23 | decoded | provenance | | +| pymongo_test.py:52:15:52:50 | After Attribute() | pymongo_test.py:52:5:52:11 | decoded | provenance | | +| pymongo_test.py:52:26:52:32 | request | pymongo_test.py:52:26:52:49 | After Subscript | provenance | AdditionalTaintStep | +| pymongo_test.py:52:26:52:49 | After Subscript | pymongo_test.py:52:15:52:50 | After Attribute() | provenance | Config | +| pymongo_test.py:54:5:54:10 | search | pymongo_test.py:59:25:59:56 | After Dict | provenance | | +| pymongo_test.py:54:14:58:5 | After Dict | pymongo_test.py:54:5:54:10 | search | provenance | | +| pymongo_test.py:55:17:55:23 | decoded | pymongo_test.py:54:14:58:5 | After Dict | provenance | | +| pymongo_test.py:55:17:55:23 | decoded | pymongo_test.py:54:14:58:5 | After Dict | provenance | Decoding-NoSQL | +| pymongo_test.py:55:17:55:23 | decoded | pymongo_test.py:61:25:61:57 | After Dict | provenance | | +| pymongo_test.py:55:17:55:23 | decoded | pymongo_test.py:62:25:62:42 | After Dict | provenance | | +| pymongo_test.py:55:17:55:23 | decoded | pymongo_test.py:63:25:63:31 | decoded | provenance | | nodes -| PoC/server.py:1:26:1:32 | ControlFlowNode for ImportMember | semmle.label | ControlFlowNode for ImportMember | -| PoC/server.py:1:26:1:32 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| PoC/server.py:26:5:26:17 | ControlFlowNode for author_string | semmle.label | ControlFlowNode for author_string | -| PoC/server.py:26:21:26:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| PoC/server.py:27:5:27:10 | ControlFlowNode for author | semmle.label | ControlFlowNode for author | -| PoC/server.py:27:14:27:38 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| PoC/server.py:27:25:27:37 | ControlFlowNode for author_string | semmle.label | ControlFlowNode for author_string | -| PoC/server.py:30:27:30:44 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict | -| PoC/server.py:30:38:30:43 | ControlFlowNode for author | semmle.label | ControlFlowNode for author | -| PoC/server.py:31:34:31:51 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict | -| PoC/server.py:31:45:31:50 | ControlFlowNode for author | semmle.label | ControlFlowNode for author | -| PoC/server.py:43:5:43:10 | ControlFlowNode for author | semmle.label | ControlFlowNode for author | -| PoC/server.py:43:14:43:20 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| PoC/server.py:47:27:47:68 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict | -| PoC/server.py:47:38:47:67 | ControlFlowNode for BinaryExpr | semmle.label | ControlFlowNode for BinaryExpr | -| PoC/server.py:52:5:52:10 | ControlFlowNode for author | semmle.label | ControlFlowNode for author | -| PoC/server.py:52:14:52:20 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| PoC/server.py:53:5:53:10 | ControlFlowNode for search | semmle.label | ControlFlowNode for search | -| PoC/server.py:53:14:57:5 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict | -| PoC/server.py:54:17:54:70 | ControlFlowNode for BinaryExpr | semmle.label | ControlFlowNode for BinaryExpr | -| PoC/server.py:61:27:61:58 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict | -| PoC/server.py:61:37:61:57 | ControlFlowNode for Dict [Dictionary element at key $function] | semmle.label | ControlFlowNode for Dict [Dictionary element at key $function] | -| PoC/server.py:61:51:61:56 | ControlFlowNode for search | semmle.label | ControlFlowNode for search | -| PoC/server.py:77:5:77:10 | ControlFlowNode for author | semmle.label | ControlFlowNode for author | -| PoC/server.py:77:14:77:20 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| PoC/server.py:78:5:78:15 | ControlFlowNode for accumulator | semmle.label | ControlFlowNode for accumulator | -| PoC/server.py:78:19:83:5 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict | -| PoC/server.py:80:23:80:101 | ControlFlowNode for BinaryExpr | semmle.label | ControlFlowNode for BinaryExpr | -| PoC/server.py:84:5:84:9 | ControlFlowNode for group [Dictionary element at key author, Dictionary element at key $accumulator] | semmle.label | ControlFlowNode for group [Dictionary element at key author, Dictionary element at key $accumulator] | -| PoC/server.py:84:13:87:5 | ControlFlowNode for Dict [Dictionary element at key author, Dictionary element at key $accumulator] | semmle.label | ControlFlowNode for Dict [Dictionary element at key author, Dictionary element at key $accumulator] | -| PoC/server.py:86:19:86:49 | ControlFlowNode for Dict [Dictionary element at key $accumulator] | semmle.label | ControlFlowNode for Dict [Dictionary element at key $accumulator] | -| PoC/server.py:86:37:86:47 | ControlFlowNode for accumulator | semmle.label | ControlFlowNode for accumulator | -| PoC/server.py:91:29:91:47 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict | -| PoC/server.py:91:41:91:45 | ControlFlowNode for group [Dictionary element at key author, Dictionary element at key $accumulator] | semmle.label | ControlFlowNode for group [Dictionary element at key author, Dictionary element at key $accumulator] | -| PoC/server.py:92:38:92:56 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict | -| PoC/server.py:92:50:92:54 | ControlFlowNode for group [Dictionary element at key author, Dictionary element at key $accumulator] | semmle.label | ControlFlowNode for group [Dictionary element at key author, Dictionary element at key $accumulator] | -| PoC/server.py:98:5:98:10 | ControlFlowNode for author | semmle.label | ControlFlowNode for author | -| PoC/server.py:98:14:98:20 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| PoC/server.py:99:5:99:10 | ControlFlowNode for mapper | semmle.label | ControlFlowNode for mapper | -| PoC/server.py:102:9:102:14 | ControlFlowNode for mapper | semmle.label | ControlFlowNode for mapper | -| flask_mongoengine_bad.py:1:26:1:32 | ControlFlowNode for ImportMember | semmle.label | ControlFlowNode for ImportMember | -| flask_mongoengine_bad.py:1:26:1:32 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| flask_mongoengine_bad.py:19:5:19:17 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search | -| flask_mongoengine_bad.py:19:21:19:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| flask_mongoengine_bad.py:20:5:20:15 | ControlFlowNode for json_search | semmle.label | ControlFlowNode for json_search | -| flask_mongoengine_bad.py:20:19:20:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| flask_mongoengine_bad.py:20:30:20:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search | -| flask_mongoengine_bad.py:22:34:22:44 | ControlFlowNode for json_search | semmle.label | ControlFlowNode for json_search | -| flask_mongoengine_bad.py:26:5:26:17 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search | -| flask_mongoengine_bad.py:26:21:26:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| flask_mongoengine_bad.py:27:5:27:15 | ControlFlowNode for json_search | semmle.label | ControlFlowNode for json_search | -| flask_mongoengine_bad.py:27:19:27:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| flask_mongoengine_bad.py:27:30:27:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search | -| flask_mongoengine_bad.py:30:39:30:59 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict | -| flask_mongoengine_bad.py:30:48:30:58 | ControlFlowNode for json_search | semmle.label | ControlFlowNode for json_search | -| flask_pymongo_bad.py:1:26:1:32 | ControlFlowNode for ImportMember | semmle.label | ControlFlowNode for ImportMember | -| flask_pymongo_bad.py:1:26:1:32 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| flask_pymongo_bad.py:11:5:11:17 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search | -| flask_pymongo_bad.py:11:21:11:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| flask_pymongo_bad.py:12:5:12:15 | ControlFlowNode for json_search | semmle.label | ControlFlowNode for json_search | -| flask_pymongo_bad.py:12:19:12:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| flask_pymongo_bad.py:12:30:12:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search | -| flask_pymongo_bad.py:14:31:14:51 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict | -| flask_pymongo_bad.py:14:40:14:50 | ControlFlowNode for json_search | semmle.label | ControlFlowNode for json_search | -| mongoengine_bad.py:1:26:1:32 | ControlFlowNode for ImportMember | semmle.label | ControlFlowNode for ImportMember | -| mongoengine_bad.py:1:26:1:32 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| mongoengine_bad.py:18:5:18:17 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search | -| mongoengine_bad.py:18:21:18:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| mongoengine_bad.py:19:5:19:15 | ControlFlowNode for json_search | semmle.label | ControlFlowNode for json_search | -| mongoengine_bad.py:19:19:19:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| mongoengine_bad.py:19:30:19:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search | -| mongoengine_bad.py:22:26:22:46 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict | -| mongoengine_bad.py:22:35:22:45 | ControlFlowNode for json_search | semmle.label | ControlFlowNode for json_search | -| mongoengine_bad.py:26:5:26:17 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search | -| mongoengine_bad.py:26:21:26:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| mongoengine_bad.py:27:5:27:15 | ControlFlowNode for json_search | semmle.label | ControlFlowNode for json_search | -| mongoengine_bad.py:27:19:27:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| mongoengine_bad.py:27:30:27:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search | -| mongoengine_bad.py:30:26:30:46 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict | -| mongoengine_bad.py:30:35:30:45 | ControlFlowNode for json_search | semmle.label | ControlFlowNode for json_search | -| mongoengine_bad.py:34:5:34:17 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search | -| mongoengine_bad.py:34:21:34:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| mongoengine_bad.py:35:5:35:15 | ControlFlowNode for json_search | semmle.label | ControlFlowNode for json_search | -| mongoengine_bad.py:35:19:35:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| mongoengine_bad.py:35:30:35:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search | -| mongoengine_bad.py:38:26:38:46 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict | -| mongoengine_bad.py:38:35:38:45 | ControlFlowNode for json_search | semmle.label | ControlFlowNode for json_search | -| mongoengine_bad.py:42:5:42:17 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search | -| mongoengine_bad.py:42:21:42:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| mongoengine_bad.py:43:5:43:15 | ControlFlowNode for json_search | semmle.label | ControlFlowNode for json_search | -| mongoengine_bad.py:43:19:43:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| mongoengine_bad.py:43:30:43:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search | -| mongoengine_bad.py:46:26:46:46 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict | -| mongoengine_bad.py:46:35:46:45 | ControlFlowNode for json_search | semmle.label | ControlFlowNode for json_search | -| mongoengine_bad.py:50:5:50:17 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search | -| mongoengine_bad.py:50:21:50:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| mongoengine_bad.py:51:5:51:15 | ControlFlowNode for json_search | semmle.label | ControlFlowNode for json_search | -| mongoengine_bad.py:51:19:51:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| mongoengine_bad.py:51:30:51:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search | -| mongoengine_bad.py:53:34:53:44 | ControlFlowNode for json_search | semmle.label | ControlFlowNode for json_search | -| mongoengine_bad.py:57:5:57:17 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search | -| mongoengine_bad.py:57:21:57:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| mongoengine_bad.py:58:5:58:15 | ControlFlowNode for json_search | semmle.label | ControlFlowNode for json_search | -| mongoengine_bad.py:58:19:58:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| mongoengine_bad.py:58:30:58:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search | -| mongoengine_bad.py:61:29:61:49 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict | -| mongoengine_bad.py:61:38:61:48 | ControlFlowNode for json_search | semmle.label | ControlFlowNode for json_search | -| pymongo_test.py:1:26:1:32 | ControlFlowNode for ImportMember | semmle.label | ControlFlowNode for ImportMember | -| pymongo_test.py:1:26:1:32 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| pymongo_test.py:12:5:12:17 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search | -| pymongo_test.py:12:21:12:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| pymongo_test.py:13:5:13:15 | ControlFlowNode for json_search | semmle.label | ControlFlowNode for json_search | -| pymongo_test.py:13:19:13:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| pymongo_test.py:13:30:13:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search | -| pymongo_test.py:15:42:15:62 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict | -| pymongo_test.py:15:51:15:61 | ControlFlowNode for json_search | semmle.label | ControlFlowNode for json_search | -| pymongo_test.py:29:5:29:12 | ControlFlowNode for event_id | semmle.label | ControlFlowNode for event_id | -| pymongo_test.py:29:16:29:51 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| pymongo_test.py:29:27:29:33 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| pymongo_test.py:29:27:29:50 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript | -| pymongo_test.py:33:34:33:73 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict | -| pymongo_test.py:33:45:33:72 | ControlFlowNode for Fstring | semmle.label | ControlFlowNode for Fstring | -| pymongo_test.py:39:5:39:12 | ControlFlowNode for event_id | semmle.label | ControlFlowNode for event_id | -| pymongo_test.py:39:16:39:51 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| pymongo_test.py:39:27:39:33 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| pymongo_test.py:39:27:39:50 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript | -| pymongo_test.py:43:34:43:73 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict | -| pymongo_test.py:43:45:43:72 | ControlFlowNode for Fstring | semmle.label | ControlFlowNode for Fstring | -| pymongo_test.py:52:5:52:11 | ControlFlowNode for decoded | semmle.label | ControlFlowNode for decoded | -| pymongo_test.py:52:15:52:50 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| pymongo_test.py:52:26:52:32 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| pymongo_test.py:52:26:52:49 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript | -| pymongo_test.py:54:5:54:10 | ControlFlowNode for search | semmle.label | ControlFlowNode for search | -| pymongo_test.py:54:5:54:10 | ControlFlowNode for search [Dictionary element at key body] | semmle.label | ControlFlowNode for search [Dictionary element at key body] | -| pymongo_test.py:54:14:58:5 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict | -| pymongo_test.py:54:14:58:5 | ControlFlowNode for Dict [Dictionary element at key body] | semmle.label | ControlFlowNode for Dict [Dictionary element at key body] | -| pymongo_test.py:55:17:55:23 | ControlFlowNode for decoded | semmle.label | ControlFlowNode for decoded | -| pymongo_test.py:59:25:59:56 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict | -| pymongo_test.py:59:35:59:55 | ControlFlowNode for Dict [Dictionary element at key $function, Dictionary element at key body] | semmle.label | ControlFlowNode for Dict [Dictionary element at key $function, Dictionary element at key body] | -| pymongo_test.py:59:35:59:55 | ControlFlowNode for Dict [Dictionary element at key $function] | semmle.label | ControlFlowNode for Dict [Dictionary element at key $function] | -| pymongo_test.py:59:49:59:54 | ControlFlowNode for search | semmle.label | ControlFlowNode for search | -| pymongo_test.py:59:49:59:54 | ControlFlowNode for search [Dictionary element at key body] | semmle.label | ControlFlowNode for search [Dictionary element at key body] | -| pymongo_test.py:61:25:61:57 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict | -| pymongo_test.py:61:35:61:56 | ControlFlowNode for Dict [Dictionary element at key $function] | semmle.label | ControlFlowNode for Dict [Dictionary element at key $function] | -| pymongo_test.py:61:49:61:55 | ControlFlowNode for decoded | semmle.label | ControlFlowNode for decoded | -| pymongo_test.py:62:25:62:42 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict | -| pymongo_test.py:62:35:62:41 | ControlFlowNode for decoded | semmle.label | ControlFlowNode for decoded | -| pymongo_test.py:63:25:63:31 | ControlFlowNode for decoded | semmle.label | ControlFlowNode for decoded | +| PoC/server.py:1:26:1:32 | After ImportMember | semmle.label | After ImportMember | +| PoC/server.py:1:26:1:32 | request | semmle.label | request | +| PoC/server.py:26:5:26:17 | author_string | semmle.label | author_string | +| PoC/server.py:26:21:26:27 | request | semmle.label | request | +| PoC/server.py:27:5:27:10 | author | semmle.label | author | +| PoC/server.py:27:14:27:38 | After Attribute() | semmle.label | After Attribute() | +| PoC/server.py:27:25:27:37 | author_string | semmle.label | author_string | +| PoC/server.py:30:27:30:44 | After Dict | semmle.label | After Dict | +| PoC/server.py:31:34:31:51 | After Dict | semmle.label | After Dict | +| PoC/server.py:43:5:43:10 | author | semmle.label | author | +| PoC/server.py:43:14:43:20 | request | semmle.label | request | +| PoC/server.py:47:27:47:68 | After Dict | semmle.label | After Dict | +| PoC/server.py:47:38:47:67 | After BinaryExpr | semmle.label | After BinaryExpr | +| PoC/server.py:52:5:52:10 | author | semmle.label | author | +| PoC/server.py:52:14:52:20 | request | semmle.label | request | +| PoC/server.py:53:5:53:10 | search | semmle.label | search | +| PoC/server.py:53:14:57:5 | After Dict | semmle.label | After Dict | +| PoC/server.py:54:17:54:70 | After BinaryExpr | semmle.label | After BinaryExpr | +| PoC/server.py:61:27:61:58 | After Dict | semmle.label | After Dict | +| PoC/server.py:77:5:77:10 | author | semmle.label | author | +| PoC/server.py:77:14:77:20 | request | semmle.label | request | +| PoC/server.py:78:5:78:15 | accumulator | semmle.label | accumulator | +| PoC/server.py:78:19:83:5 | After Dict | semmle.label | After Dict | +| PoC/server.py:80:23:80:101 | After BinaryExpr | semmle.label | After BinaryExpr | +| PoC/server.py:84:5:84:9 | group | semmle.label | group | +| PoC/server.py:91:29:91:47 | After Dict | semmle.label | After Dict | +| PoC/server.py:92:38:92:56 | After Dict | semmle.label | After Dict | +| PoC/server.py:98:5:98:10 | author | semmle.label | author | +| PoC/server.py:98:14:98:20 | request | semmle.label | request | +| PoC/server.py:99:5:99:10 | mapper | semmle.label | mapper | +| PoC/server.py:102:9:102:14 | mapper | semmle.label | mapper | +| flask_mongoengine_bad.py:1:26:1:32 | After ImportMember | semmle.label | After ImportMember | +| flask_mongoengine_bad.py:1:26:1:32 | request | semmle.label | request | +| flask_mongoengine_bad.py:19:5:19:17 | unsafe_search | semmle.label | unsafe_search | +| flask_mongoengine_bad.py:19:21:19:27 | request | semmle.label | request | +| flask_mongoengine_bad.py:20:5:20:15 | json_search | semmle.label | json_search | +| flask_mongoengine_bad.py:20:19:20:43 | After Attribute() | semmle.label | After Attribute() | +| flask_mongoengine_bad.py:20:30:20:42 | unsafe_search | semmle.label | unsafe_search | +| flask_mongoengine_bad.py:22:34:22:44 | json_search | semmle.label | json_search | +| flask_mongoengine_bad.py:26:5:26:17 | unsafe_search | semmle.label | unsafe_search | +| flask_mongoengine_bad.py:26:21:26:27 | request | semmle.label | request | +| flask_mongoengine_bad.py:27:5:27:15 | json_search | semmle.label | json_search | +| flask_mongoengine_bad.py:27:19:27:43 | After Attribute() | semmle.label | After Attribute() | +| flask_mongoengine_bad.py:27:30:27:42 | unsafe_search | semmle.label | unsafe_search | +| flask_mongoengine_bad.py:30:39:30:59 | After Dict | semmle.label | After Dict | +| flask_pymongo_bad.py:1:26:1:32 | After ImportMember | semmle.label | After ImportMember | +| flask_pymongo_bad.py:1:26:1:32 | request | semmle.label | request | +| flask_pymongo_bad.py:11:5:11:17 | unsafe_search | semmle.label | unsafe_search | +| flask_pymongo_bad.py:11:21:11:27 | request | semmle.label | request | +| flask_pymongo_bad.py:12:5:12:15 | json_search | semmle.label | json_search | +| flask_pymongo_bad.py:12:19:12:43 | After Attribute() | semmle.label | After Attribute() | +| flask_pymongo_bad.py:12:30:12:42 | unsafe_search | semmle.label | unsafe_search | +| flask_pymongo_bad.py:14:31:14:51 | After Dict | semmle.label | After Dict | +| mongoengine_bad.py:1:26:1:32 | After ImportMember | semmle.label | After ImportMember | +| mongoengine_bad.py:1:26:1:32 | request | semmle.label | request | +| mongoengine_bad.py:18:5:18:17 | unsafe_search | semmle.label | unsafe_search | +| mongoengine_bad.py:18:21:18:27 | request | semmle.label | request | +| mongoengine_bad.py:19:5:19:15 | json_search | semmle.label | json_search | +| mongoengine_bad.py:19:19:19:43 | After Attribute() | semmle.label | After Attribute() | +| mongoengine_bad.py:19:30:19:42 | unsafe_search | semmle.label | unsafe_search | +| mongoengine_bad.py:22:26:22:46 | After Dict | semmle.label | After Dict | +| mongoengine_bad.py:26:5:26:17 | unsafe_search | semmle.label | unsafe_search | +| mongoengine_bad.py:26:21:26:27 | request | semmle.label | request | +| mongoengine_bad.py:27:5:27:15 | json_search | semmle.label | json_search | +| mongoengine_bad.py:27:19:27:43 | After Attribute() | semmle.label | After Attribute() | +| mongoengine_bad.py:27:30:27:42 | unsafe_search | semmle.label | unsafe_search | +| mongoengine_bad.py:30:26:30:46 | After Dict | semmle.label | After Dict | +| mongoengine_bad.py:34:5:34:17 | unsafe_search | semmle.label | unsafe_search | +| mongoengine_bad.py:34:21:34:27 | request | semmle.label | request | +| mongoengine_bad.py:35:5:35:15 | json_search | semmle.label | json_search | +| mongoengine_bad.py:35:19:35:43 | After Attribute() | semmle.label | After Attribute() | +| mongoengine_bad.py:35:30:35:42 | unsafe_search | semmle.label | unsafe_search | +| mongoengine_bad.py:38:26:38:46 | After Dict | semmle.label | After Dict | +| mongoengine_bad.py:42:5:42:17 | unsafe_search | semmle.label | unsafe_search | +| mongoengine_bad.py:42:21:42:27 | request | semmle.label | request | +| mongoengine_bad.py:43:5:43:15 | json_search | semmle.label | json_search | +| mongoengine_bad.py:43:19:43:43 | After Attribute() | semmle.label | After Attribute() | +| mongoengine_bad.py:43:30:43:42 | unsafe_search | semmle.label | unsafe_search | +| mongoengine_bad.py:46:26:46:46 | After Dict | semmle.label | After Dict | +| mongoengine_bad.py:50:5:50:17 | unsafe_search | semmle.label | unsafe_search | +| mongoengine_bad.py:50:21:50:27 | request | semmle.label | request | +| mongoengine_bad.py:51:5:51:15 | json_search | semmle.label | json_search | +| mongoengine_bad.py:51:19:51:43 | After Attribute() | semmle.label | After Attribute() | +| mongoengine_bad.py:51:30:51:42 | unsafe_search | semmle.label | unsafe_search | +| mongoengine_bad.py:53:34:53:44 | json_search | semmle.label | json_search | +| mongoengine_bad.py:57:5:57:17 | unsafe_search | semmle.label | unsafe_search | +| mongoengine_bad.py:57:21:57:27 | request | semmle.label | request | +| mongoengine_bad.py:58:5:58:15 | json_search | semmle.label | json_search | +| mongoengine_bad.py:58:19:58:43 | After Attribute() | semmle.label | After Attribute() | +| mongoengine_bad.py:58:30:58:42 | unsafe_search | semmle.label | unsafe_search | +| mongoengine_bad.py:61:29:61:49 | After Dict | semmle.label | After Dict | +| pymongo_test.py:1:26:1:32 | After ImportMember | semmle.label | After ImportMember | +| pymongo_test.py:1:26:1:32 | request | semmle.label | request | +| pymongo_test.py:12:5:12:17 | unsafe_search | semmle.label | unsafe_search | +| pymongo_test.py:12:21:12:27 | request | semmle.label | request | +| pymongo_test.py:13:5:13:15 | json_search | semmle.label | json_search | +| pymongo_test.py:13:19:13:43 | After Attribute() | semmle.label | After Attribute() | +| pymongo_test.py:13:30:13:42 | unsafe_search | semmle.label | unsafe_search | +| pymongo_test.py:15:42:15:62 | After Dict | semmle.label | After Dict | +| pymongo_test.py:29:5:29:12 | event_id | semmle.label | event_id | +| pymongo_test.py:29:16:29:51 | After Attribute() | semmle.label | After Attribute() | +| pymongo_test.py:29:27:29:33 | request | semmle.label | request | +| pymongo_test.py:29:27:29:50 | After Subscript | semmle.label | After Subscript | +| pymongo_test.py:33:34:33:73 | After Dict | semmle.label | After Dict | +| pymongo_test.py:33:45:33:72 | After Fstring | semmle.label | After Fstring | +| pymongo_test.py:39:5:39:12 | event_id | semmle.label | event_id | +| pymongo_test.py:39:16:39:51 | After Attribute() | semmle.label | After Attribute() | +| pymongo_test.py:39:27:39:33 | request | semmle.label | request | +| pymongo_test.py:39:27:39:50 | After Subscript | semmle.label | After Subscript | +| pymongo_test.py:43:34:43:73 | After Dict | semmle.label | After Dict | +| pymongo_test.py:43:45:43:72 | After Fstring | semmle.label | After Fstring | +| pymongo_test.py:52:5:52:11 | decoded | semmle.label | decoded | +| pymongo_test.py:52:15:52:50 | After Attribute() | semmle.label | After Attribute() | +| pymongo_test.py:52:26:52:32 | request | semmle.label | request | +| pymongo_test.py:52:26:52:49 | After Subscript | semmle.label | After Subscript | +| pymongo_test.py:54:5:54:10 | search | semmle.label | search | +| pymongo_test.py:54:14:58:5 | After Dict | semmle.label | After Dict | +| pymongo_test.py:55:17:55:23 | decoded | semmle.label | decoded | +| pymongo_test.py:59:25:59:56 | After Dict | semmle.label | After Dict | +| pymongo_test.py:61:25:61:57 | After Dict | semmle.label | After Dict | +| pymongo_test.py:62:25:62:42 | After Dict | semmle.label | After Dict | +| pymongo_test.py:63:25:63:31 | decoded | semmle.label | decoded | subpaths #select -| PoC/server.py:30:27:30:44 | ControlFlowNode for Dict | PoC/server.py:1:26:1:32 | ControlFlowNode for ImportMember | PoC/server.py:30:27:30:44 | ControlFlowNode for Dict | This NoSQL query contains an unsanitized $@. | PoC/server.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value | -| PoC/server.py:31:34:31:51 | ControlFlowNode for Dict | PoC/server.py:1:26:1:32 | ControlFlowNode for ImportMember | PoC/server.py:31:34:31:51 | ControlFlowNode for Dict | This NoSQL query contains an unsanitized $@. | PoC/server.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value | -| PoC/server.py:47:27:47:68 | ControlFlowNode for Dict | PoC/server.py:1:26:1:32 | ControlFlowNode for ImportMember | PoC/server.py:47:27:47:68 | ControlFlowNode for Dict | This NoSQL query contains an unsanitized $@. | PoC/server.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value | -| PoC/server.py:61:27:61:58 | ControlFlowNode for Dict | PoC/server.py:1:26:1:32 | ControlFlowNode for ImportMember | PoC/server.py:61:27:61:58 | ControlFlowNode for Dict | This NoSQL query contains an unsanitized $@. | PoC/server.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value | -| PoC/server.py:91:29:91:47 | ControlFlowNode for Dict | PoC/server.py:1:26:1:32 | ControlFlowNode for ImportMember | PoC/server.py:91:29:91:47 | ControlFlowNode for Dict | This NoSQL query contains an unsanitized $@. | PoC/server.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value | -| PoC/server.py:92:38:92:56 | ControlFlowNode for Dict | PoC/server.py:1:26:1:32 | ControlFlowNode for ImportMember | PoC/server.py:92:38:92:56 | ControlFlowNode for Dict | This NoSQL query contains an unsanitized $@. | PoC/server.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value | -| PoC/server.py:102:9:102:14 | ControlFlowNode for mapper | PoC/server.py:1:26:1:32 | ControlFlowNode for ImportMember | PoC/server.py:102:9:102:14 | ControlFlowNode for mapper | This NoSQL query contains an unsanitized $@. | PoC/server.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value | -| flask_mongoengine_bad.py:22:34:22:44 | ControlFlowNode for json_search | flask_mongoengine_bad.py:1:26:1:32 | ControlFlowNode for ImportMember | flask_mongoengine_bad.py:22:34:22:44 | ControlFlowNode for json_search | This NoSQL query contains an unsanitized $@. | flask_mongoengine_bad.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value | -| flask_mongoengine_bad.py:30:39:30:59 | ControlFlowNode for Dict | flask_mongoengine_bad.py:1:26:1:32 | ControlFlowNode for ImportMember | flask_mongoengine_bad.py:30:39:30:59 | ControlFlowNode for Dict | This NoSQL query contains an unsanitized $@. | flask_mongoengine_bad.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value | -| flask_pymongo_bad.py:14:31:14:51 | ControlFlowNode for Dict | flask_pymongo_bad.py:1:26:1:32 | ControlFlowNode for ImportMember | flask_pymongo_bad.py:14:31:14:51 | ControlFlowNode for Dict | This NoSQL query contains an unsanitized $@. | flask_pymongo_bad.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value | -| mongoengine_bad.py:22:26:22:46 | ControlFlowNode for Dict | mongoengine_bad.py:1:26:1:32 | ControlFlowNode for ImportMember | mongoengine_bad.py:22:26:22:46 | ControlFlowNode for Dict | This NoSQL query contains an unsanitized $@. | mongoengine_bad.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value | -| mongoengine_bad.py:30:26:30:46 | ControlFlowNode for Dict | mongoengine_bad.py:1:26:1:32 | ControlFlowNode for ImportMember | mongoengine_bad.py:30:26:30:46 | ControlFlowNode for Dict | This NoSQL query contains an unsanitized $@. | mongoengine_bad.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value | -| mongoengine_bad.py:38:26:38:46 | ControlFlowNode for Dict | mongoengine_bad.py:1:26:1:32 | ControlFlowNode for ImportMember | mongoengine_bad.py:38:26:38:46 | ControlFlowNode for Dict | This NoSQL query contains an unsanitized $@. | mongoengine_bad.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value | -| mongoengine_bad.py:46:26:46:46 | ControlFlowNode for Dict | mongoengine_bad.py:1:26:1:32 | ControlFlowNode for ImportMember | mongoengine_bad.py:46:26:46:46 | ControlFlowNode for Dict | This NoSQL query contains an unsanitized $@. | mongoengine_bad.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value | -| mongoengine_bad.py:53:34:53:44 | ControlFlowNode for json_search | mongoengine_bad.py:1:26:1:32 | ControlFlowNode for ImportMember | mongoengine_bad.py:53:34:53:44 | ControlFlowNode for json_search | This NoSQL query contains an unsanitized $@. | mongoengine_bad.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value | -| mongoengine_bad.py:61:29:61:49 | ControlFlowNode for Dict | mongoengine_bad.py:1:26:1:32 | ControlFlowNode for ImportMember | mongoengine_bad.py:61:29:61:49 | ControlFlowNode for Dict | This NoSQL query contains an unsanitized $@. | mongoengine_bad.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value | -| pymongo_test.py:15:42:15:62 | ControlFlowNode for Dict | pymongo_test.py:1:26:1:32 | ControlFlowNode for ImportMember | pymongo_test.py:15:42:15:62 | ControlFlowNode for Dict | This NoSQL query contains an unsanitized $@. | pymongo_test.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value | -| pymongo_test.py:33:34:33:73 | ControlFlowNode for Dict | pymongo_test.py:1:26:1:32 | ControlFlowNode for ImportMember | pymongo_test.py:33:34:33:73 | ControlFlowNode for Dict | This NoSQL query contains an unsanitized $@. | pymongo_test.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value | -| pymongo_test.py:43:34:43:73 | ControlFlowNode for Dict | pymongo_test.py:1:26:1:32 | ControlFlowNode for ImportMember | pymongo_test.py:43:34:43:73 | ControlFlowNode for Dict | This NoSQL query contains an unsanitized $@. | pymongo_test.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value | -| pymongo_test.py:59:25:59:56 | ControlFlowNode for Dict | pymongo_test.py:1:26:1:32 | ControlFlowNode for ImportMember | pymongo_test.py:59:25:59:56 | ControlFlowNode for Dict | This NoSQL query contains an unsanitized $@. | pymongo_test.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value | -| pymongo_test.py:61:25:61:57 | ControlFlowNode for Dict | pymongo_test.py:1:26:1:32 | ControlFlowNode for ImportMember | pymongo_test.py:61:25:61:57 | ControlFlowNode for Dict | This NoSQL query contains an unsanitized $@. | pymongo_test.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value | -| pymongo_test.py:62:25:62:42 | ControlFlowNode for Dict | pymongo_test.py:1:26:1:32 | ControlFlowNode for ImportMember | pymongo_test.py:62:25:62:42 | ControlFlowNode for Dict | This NoSQL query contains an unsanitized $@. | pymongo_test.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value | -| pymongo_test.py:63:25:63:31 | ControlFlowNode for decoded | pymongo_test.py:1:26:1:32 | ControlFlowNode for ImportMember | pymongo_test.py:63:25:63:31 | ControlFlowNode for decoded | This NoSQL query contains an unsanitized $@. | pymongo_test.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value | +| PoC/server.py:30:27:30:44 | After Dict | PoC/server.py:1:26:1:32 | After ImportMember | PoC/server.py:30:27:30:44 | After Dict | This NoSQL query contains an unsanitized $@. | PoC/server.py:1:26:1:32 | After ImportMember | user-provided value | +| PoC/server.py:31:34:31:51 | After Dict | PoC/server.py:1:26:1:32 | After ImportMember | PoC/server.py:31:34:31:51 | After Dict | This NoSQL query contains an unsanitized $@. | PoC/server.py:1:26:1:32 | After ImportMember | user-provided value | +| PoC/server.py:47:27:47:68 | After Dict | PoC/server.py:1:26:1:32 | After ImportMember | PoC/server.py:47:27:47:68 | After Dict | This NoSQL query contains an unsanitized $@. | PoC/server.py:1:26:1:32 | After ImportMember | user-provided value | +| PoC/server.py:61:27:61:58 | After Dict | PoC/server.py:1:26:1:32 | After ImportMember | PoC/server.py:61:27:61:58 | After Dict | This NoSQL query contains an unsanitized $@. | PoC/server.py:1:26:1:32 | After ImportMember | user-provided value | +| PoC/server.py:91:29:91:47 | After Dict | PoC/server.py:1:26:1:32 | After ImportMember | PoC/server.py:91:29:91:47 | After Dict | This NoSQL query contains an unsanitized $@. | PoC/server.py:1:26:1:32 | After ImportMember | user-provided value | +| PoC/server.py:92:38:92:56 | After Dict | PoC/server.py:1:26:1:32 | After ImportMember | PoC/server.py:92:38:92:56 | After Dict | This NoSQL query contains an unsanitized $@. | PoC/server.py:1:26:1:32 | After ImportMember | user-provided value | +| PoC/server.py:102:9:102:14 | mapper | PoC/server.py:1:26:1:32 | After ImportMember | PoC/server.py:102:9:102:14 | mapper | This NoSQL query contains an unsanitized $@. | PoC/server.py:1:26:1:32 | After ImportMember | user-provided value | +| flask_mongoengine_bad.py:22:34:22:44 | json_search | flask_mongoengine_bad.py:1:26:1:32 | After ImportMember | flask_mongoengine_bad.py:22:34:22:44 | json_search | This NoSQL query contains an unsanitized $@. | flask_mongoengine_bad.py:1:26:1:32 | After ImportMember | user-provided value | +| flask_mongoengine_bad.py:30:39:30:59 | After Dict | flask_mongoengine_bad.py:1:26:1:32 | After ImportMember | flask_mongoengine_bad.py:30:39:30:59 | After Dict | This NoSQL query contains an unsanitized $@. | flask_mongoengine_bad.py:1:26:1:32 | After ImportMember | user-provided value | +| flask_pymongo_bad.py:14:31:14:51 | After Dict | flask_pymongo_bad.py:1:26:1:32 | After ImportMember | flask_pymongo_bad.py:14:31:14:51 | After Dict | This NoSQL query contains an unsanitized $@. | flask_pymongo_bad.py:1:26:1:32 | After ImportMember | user-provided value | +| mongoengine_bad.py:22:26:22:46 | After Dict | mongoengine_bad.py:1:26:1:32 | After ImportMember | mongoengine_bad.py:22:26:22:46 | After Dict | This NoSQL query contains an unsanitized $@. | mongoengine_bad.py:1:26:1:32 | After ImportMember | user-provided value | +| mongoengine_bad.py:30:26:30:46 | After Dict | mongoengine_bad.py:1:26:1:32 | After ImportMember | mongoengine_bad.py:30:26:30:46 | After Dict | This NoSQL query contains an unsanitized $@. | mongoengine_bad.py:1:26:1:32 | After ImportMember | user-provided value | +| mongoengine_bad.py:38:26:38:46 | After Dict | mongoengine_bad.py:1:26:1:32 | After ImportMember | mongoengine_bad.py:38:26:38:46 | After Dict | This NoSQL query contains an unsanitized $@. | mongoengine_bad.py:1:26:1:32 | After ImportMember | user-provided value | +| mongoengine_bad.py:46:26:46:46 | After Dict | mongoengine_bad.py:1:26:1:32 | After ImportMember | mongoengine_bad.py:46:26:46:46 | After Dict | This NoSQL query contains an unsanitized $@. | mongoengine_bad.py:1:26:1:32 | After ImportMember | user-provided value | +| mongoengine_bad.py:53:34:53:44 | json_search | mongoengine_bad.py:1:26:1:32 | After ImportMember | mongoengine_bad.py:53:34:53:44 | json_search | This NoSQL query contains an unsanitized $@. | mongoengine_bad.py:1:26:1:32 | After ImportMember | user-provided value | +| mongoengine_bad.py:61:29:61:49 | After Dict | mongoengine_bad.py:1:26:1:32 | After ImportMember | mongoengine_bad.py:61:29:61:49 | After Dict | This NoSQL query contains an unsanitized $@. | mongoengine_bad.py:1:26:1:32 | After ImportMember | user-provided value | +| pymongo_test.py:15:42:15:62 | After Dict | pymongo_test.py:1:26:1:32 | After ImportMember | pymongo_test.py:15:42:15:62 | After Dict | This NoSQL query contains an unsanitized $@. | pymongo_test.py:1:26:1:32 | After ImportMember | user-provided value | +| pymongo_test.py:33:34:33:73 | After Dict | pymongo_test.py:1:26:1:32 | After ImportMember | pymongo_test.py:33:34:33:73 | After Dict | This NoSQL query contains an unsanitized $@. | pymongo_test.py:1:26:1:32 | After ImportMember | user-provided value | +| pymongo_test.py:43:34:43:73 | After Dict | pymongo_test.py:1:26:1:32 | After ImportMember | pymongo_test.py:43:34:43:73 | After Dict | This NoSQL query contains an unsanitized $@. | pymongo_test.py:1:26:1:32 | After ImportMember | user-provided value | +| pymongo_test.py:59:25:59:56 | After Dict | pymongo_test.py:1:26:1:32 | After ImportMember | pymongo_test.py:59:25:59:56 | After Dict | This NoSQL query contains an unsanitized $@. | pymongo_test.py:1:26:1:32 | After ImportMember | user-provided value | +| pymongo_test.py:61:25:61:57 | After Dict | pymongo_test.py:1:26:1:32 | After ImportMember | pymongo_test.py:61:25:61:57 | After Dict | This NoSQL query contains an unsanitized $@. | pymongo_test.py:1:26:1:32 | After ImportMember | user-provided value | +| pymongo_test.py:62:25:62:42 | After Dict | pymongo_test.py:1:26:1:32 | After ImportMember | pymongo_test.py:62:25:62:42 | After Dict | This NoSQL query contains an unsanitized $@. | pymongo_test.py:1:26:1:32 | After ImportMember | user-provided value | +| pymongo_test.py:63:25:63:31 | decoded | pymongo_test.py:1:26:1:32 | After ImportMember | pymongo_test.py:63:25:63:31 | decoded | This NoSQL query contains an unsanitized $@. | pymongo_test.py:1:26:1:32 | After ImportMember | user-provided value | diff --git a/python/ql/test/query-tests/Statements/exit/UseOfExit.expected b/python/ql/test/query-tests/Statements/exit/UseOfExit.expected index 76984527df61..31c1bffaa150 100644 --- a/python/ql/test/query-tests/Statements/exit/UseOfExit.expected +++ b/python/ql/test/query-tests/Statements/exit/UseOfExit.expected @@ -1 +1 @@ -| test.py:7:9:7:15 | ControlFlowNode for exit() | The 'exit' site.Quitter object may not exist if the 'site' module is not loaded or is modified. | +| test.py:7:9:7:15 | After exit() | The 'exit' site.Quitter object may not exist if the 'site' module is not loaded or is modified. | diff --git a/shared/controlflow/codeql/controlflow/ControlFlowGraph.qll b/shared/controlflow/codeql/controlflow/ControlFlowGraph.qll index 71d22c416ea8..cca4de4df0a3 100644 --- a/shared/controlflow/codeql/controlflow/ControlFlowGraph.qll +++ b/shared/controlflow/codeql/controlflow/ControlFlowGraph.qll @@ -224,6 +224,31 @@ signature module AstSig { */ default AstNode getTryElse(TryStmt try) { none() } + /** + * Gets the `else` block of this `while` loop statement, if any. + * + * Only some languages (e.g. Python) support `while-else` constructs. + */ + default AstNode getWhileElse(WhileStmt loop) { none() } + + /** + * Gets the `else` block of this `foreach` loop statement, if any. + * + * Only some languages (e.g. Python) support `for-else` constructs. + */ + default AstNode getForeachElse(ForeachStmt loop) { none() } + + /** + * Gets the type expression of this catch clause, if any. + * + * In Python, the catch type is a runtime-evaluated expression + * (e.g. `except SomeException:` where `SomeException` is an + * arbitrary expression). For languages where the catch type is + * statically resolved, this defaults to `none()` and no CFG node + * is created. + */ + default Expr getCatchType(CatchClause catch) { none() } + /** A catch clause in a try statement. */ class CatchClause extends AstNode { /** Gets the variable declared by this catch clause. */ @@ -1577,20 +1602,33 @@ module Make0 Ast> { n1.isAfterValue(cond, any(BooleanSuccessor b | b.getValue() = while)) and n2.isBefore(loopstmt.getBody()) or - n1.isAfterValue(cond, any(BooleanSuccessor b | b.getValue() = while.booleanNot())) and - n2.isAfter(loopstmt) + n1.isAfterFalse(cond) and + ( + n2.isBefore(getWhileElse(loopstmt)) + or + not exists(getWhileElse(loopstmt)) and n2.isAfter(loopstmt) + ) or n1.isAfter(loopstmt.getBody()) and n2.isAdditional(loopstmt, loopHeaderTag()) ) or + exists(WhileStmt whilestmt | + n1.isAfter(getWhileElse(whilestmt)) and + n2.isAfter(whilestmt) + ) + or exists(ForeachStmt foreachstmt | n1.isBefore(foreachstmt) and n2.isBefore(foreachstmt.getCollection()) or n1.isAfterValue(foreachstmt.getCollection(), any(EmptinessSuccessor t | t.getValue() = true)) and - n2.isAfter(foreachstmt) + ( + n2.isBefore(getForeachElse(foreachstmt)) + or + not exists(getForeachElse(foreachstmt)) and n2.isAfter(foreachstmt) + ) or n1.isAfterValue(foreachstmt.getCollection(), any(EmptinessSuccessor t | t.getValue() = false)) and @@ -1603,10 +1641,17 @@ module Make0 Ast> { n2.isAdditional(foreachstmt, loopHeaderTag()) or n1.isAdditional(foreachstmt, loopHeaderTag()) and - n2.isAfter(foreachstmt) + ( + n2.isBefore(getForeachElse(foreachstmt)) + or + not exists(getForeachElse(foreachstmt)) and n2.isAfter(foreachstmt) + ) or n1.isAdditional(foreachstmt, loopHeaderTag()) and n2.isBefore(foreachstmt.getVariable()) + or + n1.isAfter(getForeachElse(foreachstmt)) and + n2.isAfter(foreachstmt) ) or exists(ForStmt forstmt, PreControlFlowNode condentry | @@ -1698,6 +1743,16 @@ module Make0 Ast> { exists(CatchClause catchclause | exists(MatchingSuccessor t | n1.isBefore(catchclause) and + ( + n2.isBefore(getCatchType(catchclause)) + or + not exists(getCatchType(catchclause)) and n2.isAfterValue(catchclause, t) + ) and + if Input1::catchAll(catchclause) then t.getValue() = true else any() + ) + or + exists(MatchingSuccessor t | + n1.isAfter(getCatchType(catchclause)) and n2.isAfterValue(catchclause, t) and if Input1::catchAll(catchclause) then t.getValue() = true else any() )