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 829aa6debef2..2eec17c78fe1 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 @@ -72,7 +73,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 @@ -88,16 +89,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/LegacyPointsTo.qll b/python/ql/lib/LegacyPointsTo.qll index ffea2d93b66c..f5ad67a3c555 100644 --- a/python/ql/lib/LegacyPointsTo.qll +++ b/python/ql/lib/LegacyPointsTo.qll @@ -213,9 +213,11 @@ class ExprWithPointsTo extends Expr { * Gets what this expression might "refer-to" in the given `context`. */ predicate refersTo(Context context, Object obj, ClassObject cls, AstNode origin) { - this.getAFlowNode() - .(ControlFlowNodeWithPointsTo) - .refersTo(context, obj, cls, origin.getAFlowNode()) + exists(ControlFlowNode this_, ControlFlowNode origin_ | + this_.getNode() = this and origin_.getNode() = origin + | + this_.(ControlFlowNodeWithPointsTo).refersTo(context, obj, cls, origin_) + ) } /** @@ -226,7 +228,11 @@ class ExprWithPointsTo extends Expr { */ pragma[nomagic] predicate refersTo(Object obj, AstNode origin) { - this.getAFlowNode().(ControlFlowNodeWithPointsTo).refersTo(obj, origin.getAFlowNode()) + exists(ControlFlowNode this_, ControlFlowNode origin_ | + this_.getNode() = this and origin_.getNode() = origin + | + this_.(ControlFlowNodeWithPointsTo).refersTo(obj, origin_) + ) } /** @@ -240,16 +246,22 @@ class ExprWithPointsTo extends Expr { * in the given `context`. */ predicate pointsTo(Context context, Value value, AstNode origin) { - this.getAFlowNode() - .(ControlFlowNodeWithPointsTo) - .pointsTo(context, value, origin.getAFlowNode()) + exists(ControlFlowNode this_, ControlFlowNode origin_ | + this_.getNode() = this and origin_.getNode() = origin + | + this_.(ControlFlowNodeWithPointsTo).pointsTo(context, value, origin_) + ) } /** * Holds if this expression might "point-to" to `value` which is from `origin`. */ predicate pointsTo(Value value, AstNode origin) { - this.getAFlowNode().(ControlFlowNodeWithPointsTo).pointsTo(value, origin.getAFlowNode()) + exists(ControlFlowNode this_, ControlFlowNode origin_ | + this_.getNode() = this and origin_.getNode() = origin + | + this_.(ControlFlowNodeWithPointsTo).pointsTo(value, origin_) + ) } /** @@ -475,7 +487,10 @@ class FunctionMetricsWithPointsTo extends FunctionMetrics { not non_coupling_method(result) and exists(Call call | call.getScope() = this | exists(FunctionObject callee | callee.getFunction() = result | - call.getAFlowNode().getFunction().(ControlFlowNodeWithPointsTo).refersTo(callee) + exists(CallNode call_ | + call_.getNode() = call and + call_.getFunction().(ControlFlowNodeWithPointsTo).refersTo(callee) + ) ) or exists(Attribute a | call.getFunc() = a | diff --git a/python/ql/lib/analysis/DefinitionTracking.qll b/python/ql/lib/analysis/DefinitionTracking.qll index 21155970375b..583a7807ff27 100644 --- a/python/ql/lib/analysis/DefinitionTracking.qll +++ b/python/ql/lib/analysis/DefinitionTracking.qll @@ -64,7 +64,7 @@ private predicate jump_to_defn(ControlFlowNode use, Definition defn) { private predicate preferred_jump_to_defn(Expr use, Definition def) { not use instanceof ClassExpr and not use instanceof FunctionExpr and - jump_to_defn(use.getAFlowNode(), def) + exists(ControlFlowNode useNode | useNode.getNode() = use | jump_to_defn(useNode, def)) } private predicate unique_jump_to_defn(Expr use, Definition def) { @@ -452,7 +452,7 @@ private predicate self_parameter_jump_to_defn_attribute( * This exists primarily for testing use `getPreferredDefinition()` instead. */ Definition getADefinition(Expr use) { - jump_to_defn(use.getAFlowNode(), result) and + exists(ControlFlowNode useNode | useNode.getNode() = use | jump_to_defn(useNode, result)) and not use instanceof Call and not use.isArtificial() and // Not the use itself diff --git a/python/ql/lib/change-notes/2026-05-26-shared-cfg-and-ssa.md b/python/ql/lib/change-notes/2026-05-26-shared-cfg-and-ssa.md new file mode 100644 index 000000000000..39bdadbbaa43 --- /dev/null +++ b/python/ql/lib/change-notes/2026-05-26-shared-cfg-and-ssa.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* The Python dataflow library is now built on the shared CFG and SSA libraries (`shared/controlflow` and `shared/ssa`), bringing Python in line with the other CodeQL languages. The legacy CFG in `semmle/python/Flow.qll` and the legacy ESSA SSA in `semmle/python/essa/*` remain available for downstream queries but are no longer used by the new dataflow library, type tracking, or API graphs. Most queries should be unaffected; a small number may produce slightly different results because of differences in CFG granularity (e.g. separate pre/post nodes per expression) and in how attribute and tuple-unpacking writes are modelled. 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/qlpack.yml b/python/ql/lib/qlpack.yml index 981ab78ff33e..c8b592b95f01 100644 --- a/python/ql/lib/qlpack.yml +++ b/python/ql/lib/qlpack.yml @@ -7,6 +7,7 @@ library: true upgrades: upgrades dependencies: codeql/concepts: ${workspace} + codeql/controlflow: ${workspace} codeql/dataflow: ${workspace} codeql/mad: ${workspace} codeql/regex: ${workspace} diff --git a/python/ql/lib/semmle/python/ApiGraphs.qll b/python/ql/lib/semmle/python/ApiGraphs.qll index efd8141efc6e..eaa31ed3d6c5 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 importing `Cfg::CallNode` from `Flow.qll` 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 13da4e899a71..32b9ce6eee7c 100644 --- a/python/ql/lib/semmle/python/AstExtended.qll +++ b/python/ql/lib/semmle/python/AstExtended.qll @@ -16,17 +16,6 @@ abstract class AstNode extends AstNode_ { /** Gets the scope that this node occurs in */ abstract Scope getScope(); - /** - * Gets a flow node corresponding directly to this node. - * NOTE: For some statements and other purely syntactic elements, - * there may not be a `ControlFlowNode` - */ - cached - ControlFlowNode getAFlowNode() { - Stages::AST::ref() and - py_flow_bb_node(result, this, _, _) - } - /** Gets the location for this AST node */ cached Location getLocation() { none() } 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 6ab9f8d8340d..9ce6f9e6680a 100644 --- a/python/ql/lib/semmle/python/Exprs.qll +++ b/python/ql/lib/semmle/python/Exprs.qll @@ -28,7 +28,9 @@ class Expr extends Expr_, AstNode { /** Whether this expression may have a side effect (as determined purely from its syntax) */ predicate hasSideEffects() { /* If an exception raised by this expression handled, count that as a side effect */ - this.getAFlowNode().getASuccessor().getNode() instanceof ExceptStmt + exists(ControlFlowNode n | n.getNode() = this | + n.getASuccessor().getNode() instanceof ExceptStmt + ) or this.getASubExpression().hasSideEffects() } @@ -68,8 +70,6 @@ class Attribute extends Attribute_ { /* syntax: Expr.name */ override Expr getASubExpression() { result = this.getObject() } - override AttrNode getAFlowNode() { result = super.getAFlowNode() } - /** Gets the name of this attribute. That is the `name` in `obj.name` */ string getName() { result = Attribute_.super.getAttr() } @@ -96,8 +96,6 @@ class Subscript extends Subscript_ { } Expr getObject() { result = Subscript_.super.getValue() } - - override SubscriptNode getAFlowNode() { result = super.getAFlowNode() } } /** A call expression, such as `func(...)` */ @@ -113,8 +111,6 @@ class Call extends Call_ { override string toString() { result = this.getFunc().toString() + "()" } - override CallNode getAFlowNode() { result = super.getAFlowNode() } - /** Gets a tuple (*) argument of this call. */ Expr getStarargs() { result = this.getAPositionalArg().(Starred).getValue() } @@ -200,8 +196,6 @@ class IfExp extends IfExp_ { override Expr getASubExpression() { result = this.getTest() or result = this.getBody() or result = this.getOrelse() } - - override IfExprNode getAFlowNode() { result = super.getAFlowNode() } } /** A starred expression, such as the `*rest` in the assignment `first, *rest = seq` */ @@ -410,8 +404,6 @@ class PlaceHolder extends PlaceHolder_ { override Expr getASubExpression() { none() } override string toString() { result = "$" + this.getId() } - - override NameNode getAFlowNode() { result = super.getAFlowNode() } } /** A tuple expression such as `( 1, 3, 5, 7, 9 )` */ @@ -478,8 +470,6 @@ class Name extends Name_ { override string toString() { result = this.getId() } - override NameNode getAFlowNode() { result = super.getAFlowNode() } - override predicate isArtificial() { /* Artificial variable names in comprehensions all start with "." */ this.getId().charAt(0) = "." @@ -585,8 +575,6 @@ abstract class NameConstant extends Name, ImmutableLiteral { override predicate isConstant() { any() } - override 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 94caf513aa98..0f84f3f367ad 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) } @@ -198,7 +198,7 @@ class ControlFlowNode extends @py_flow_node { pragma[inline] predicate strictlyDominates(ControlFlowNode other) { // This predicate is gigantic, so it must be inlined. - // About 1.4 billion tuples for OpenStack Cinder. + // About 1.4 billion tuples for OpenStack Py::Cinder. this.getBasicBlock().strictlyDominates(other.getBasicBlock()) or exists(BasicBlock b, int i, int j | this = b.getNode(i) and other = b.getNode(j) and i < j) @@ -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,82 +870,84 @@ 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 = ex.getType().getAFlowNode() + result.getNode() = ex.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() { - exists(ExceptStmt ex | + exists(Py::ExceptStmt ex | this.getBasicBlock().dominates(result.getBasicBlock()) and ex = this.getNode() and - result = ex.getName().getAFlowNode() + result.getNode() = ex.getName() ) } } /** 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 = this.getNode().(ExceptGroupStmt).getType().getAFlowNode() + 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 = this.getNode().(ExceptGroupStmt).getName().getAFlowNode() + 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() } @@ -1090,7 +1094,7 @@ class BasicBlock extends @py_flow_node { * Holds if this element is at the specified location. * The location spans column `startcolumn` of line `startline` to * column `endcolumn` of line `endline` in file `filepath`. - * For more information, see + * Py::For more information, see * [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/). */ predicate hasLocationInfo( @@ -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/Import.qll b/python/ql/lib/semmle/python/Import.qll index 2f7fae955399..d4f5109ed47c 100644 --- a/python/ql/lib/semmle/python/Import.qll +++ b/python/ql/lib/semmle/python/Import.qll @@ -162,8 +162,6 @@ class ImportMember extends ImportMember_ { string getImportedModuleName() { result = this.getModule().(ImportExpr).getImportedModuleName() + "." + this.getName() } - - override ImportMemberNode getAFlowNode() { result = super.getAFlowNode() } } /** An import statement */ diff --git a/python/ql/lib/semmle/python/SelfAttribute.qll b/python/ql/lib/semmle/python/SelfAttribute.qll index 90ef2b38401a..364e080dcdd7 100644 --- a/python/ql/lib/semmle/python/SelfAttribute.qll +++ b/python/ql/lib/semmle/python/SelfAttribute.qll @@ -46,20 +46,23 @@ class SelfAttributeRead extends SelfAttribute { } predicate guardedByHasattr() { - exists(Variable var, ControlFlowNode n | - var.getAUse() = this.getObject().getAFlowNode() and + exists(Variable var, ControlFlowNode n, ControlFlowNode this_, ControlFlowNode obj_ | + this_.getNode() = this and obj_.getNode() = this.getObject() + | + var.getAUse() = obj_ and hasattr(n, var.getAUse(), this.getName()) and - n.strictlyDominates(this.getAFlowNode()) + n.strictlyDominates(this_) ) } pragma[noinline] predicate locallyDefined() { - exists(SelfAttributeStore store | - this.getName() = store.getName() and - this.getScope() = store.getScope() + exists(SelfAttributeStore store, ControlFlowNode store_, ControlFlowNode this_ | + store_.getNode() = store and this_.getNode() = this | - store.getAFlowNode().strictlyDominates(this.getAFlowNode()) + this.getName() = store.getName() and + this.getScope() = store.getScope() and + store_.strictlyDominates(this_) ) } } 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..72f3a2e58fd7 --- /dev/null +++ b/python/ql/lib/semmle/python/controlflow/internal/AstNodeImpl.qll @@ -0,0 +1,1595 @@ +/** + * 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 `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() } + } + + /** 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) } + + Stmt getBody() { 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() + 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() } + + /** 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]" } + + 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 + } + + 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..4d5b7d4d8053 --- /dev/null +++ b/python/ql/lib/semmle/python/controlflow/internal/Cfg.qll @@ -0,0 +1,1163 @@ +/** + * 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. + * + * Entry/exit/synthetic CFG nodes have no Python AST node, so this is + * partial. + */ +private Py::AstNode toAst(CfgImpl::ControlFlowNode n) { + result = CfgImpl::astNodeToPyNode(n.getAstNode()) +} + +/** + * Holds if `n` is a CFG node representing the canonical position for an + * AST node from the dataflow library's perspective. + * + * For most expressions this is the "after"-evaluation point (post-order + * representative). For statements it is the post-order node when one + * exists. We additionally include the synthetic entry/exit nodes for the + * benefit of API consumers that ask "is this the entry node of a scope?". + * + * In conditional contexts the after-position of a boolean expression + * splits into separate `isAfterTrue` and `isAfterFalse` nodes; both are + * canonical, so a single AST expression may correspond to more than one + * `ControlFlowNode`. + */ +private predicate isCanonical(CfgImpl::ControlFlowNode n) { + n.isAfter(_) + or + n instanceof CfgImpl::ControlFlow::EntryNode + or + n instanceof CfgImpl::ControlFlow::ExitNode + or + // Annotated exit nodes (normal + abnormal) — needed so that dataflow + // consumers can ask "is this the normal-exit of a scope?" and also + // so that scope-exit synthetic uses in SsaImpl can attach here. + n instanceof CfgImpl::ControlFlow::AnnotatedExitNode +} + +/** + * Holds if `n` is genuinely the `TAfterValueNode` variant for a boolean-true + * outcome of its AST node. + * + * The shared CFG's `isAfterValue` predicate has a kind-mismatch fallback + * (see `ControlFlowGraph.qll`'s `isAfterValue` lines 870-892): when asking + * `isAfterValue(_, BooleanSuccessor true)` on, say, an emptiness-empty + * variant, it falsely returns `true` because the kinds differ and Python + * does not provide `successorValueImplies`. The same fallback also makes + * `TAfterNode` (the unsplit case) satisfy `isAfterValue(_, t)` for *every* + * `t`. + * + * The combination `isAfterTrue ∧ ¬isAfterFalse` excludes both: a genuine + * boolean-true variant satisfies `isAfterTrue` directly (newtype branch 3) + * but not `isAfterFalse` (the dual variant, same kind, no fallback). A + * non-boolean variant satisfies both via the cross-kind fallback. A + * `TAfterNode` satisfies both via branch 1. So `isAfterTrue ∧ ¬isAfterFalse` + * picks exactly the genuine boolean-true variant. + */ +private predicate isGenuineAfterTrue(ControlFlowNode n) { + n.isAfterTrue(_) and not n.isAfterFalse(_) +} + +/** + * Holds if `n` is genuinely the `TAfterValueNode` variant for the "empty" + * outcome of its AST node (e.g. `for x in xs: ...` when `xs` is empty). + * + * See `isGenuineAfterTrue` for why we cannot just use a single + * `isAfterValue` check. + */ +private predicate isGenuineAfterEmpty(ControlFlowNode n) { + exists(EmptinessSuccessor empty | + empty.getValue() = true and n.isAfterValue(n.getAstNode(), empty) + ) and + not exists(EmptinessSuccessor nonEmpty | + nonEmpty.getValue() = false and n.isAfterValue(n.getAstNode(), nonEmpty) + ) +} + +/** + * Holds if `n` is genuinely the `TAfterValueNode` variant for the "matched" + * outcome of its AST node (e.g. a `match` case-pattern that matched). + * + * See `isGenuineAfterTrue` for why we cannot just use a single + * `isAfterValue` check. + */ +private predicate isGenuineAfterMatched(ControlFlowNode n) { + exists(MatchingSuccessor matched | + matched.getValue() = true and n.isAfterValue(n.getAstNode(), matched) + ) and + not exists(MatchingSuccessor unmatched | + unmatched.getValue() = false and n.isAfterValue(n.getAstNode(), unmatched) + ) +} + +/** + * Holds if `n` is the canonical representative of its corresponding AST node + * for dataflow purposes. + * + * The shared CFG associates a single AST node with multiple `ControlFlowNode`s + * when the AST appears in a conditional context (boolean conditions split into + * `afterTrue`/`afterFalse`; for-loop iters split into `[empty]`/`[non-empty]`; + * `match`-case patterns split into `[matched]`/`[unmatched]`). These splits + * matter for control-flow analysis, but for dataflow purposes — where we + * ask "what is the value of this expression?" — a single representative + * suffices and is required to avoid double-counting calls, arguments, store + * steps, etc. + * + * The pick is structural: when an AST has a single `ControlFlowNode` (the + * normal `TAfterNode` or `TBeforeNode`-leaf case), that node is canonical. + * When an AST has a conditional split, the "positive" outcome variant + * (true / empty / matched) is canonical. The three split kinds are mutually + * exclusive per AST, so exactly one variant is selected. + */ +predicate isCanonicalAstNodeRepresentative(ControlFlowNode n) { + // Non-split AST: the unique variant is canonical. + not exists(ControlFlowNode other | other.getNode() = n.getNode() and other != n) + or + // Split AST: pick the "positive" outcome of the split. + isGenuineAfterTrue(n) + or + isGenuineAfterEmpty(n) + or + isGenuineAfterMatched(n) +} + +/** + * A control flow node. Control flow nodes have a many-to-one relation + * with syntactic nodes, although most syntactic nodes have only one + * corresponding control flow node. + * + * Edges between control flow nodes include exceptional as well as normal + * control flow. + */ +class ControlFlowNode extends CfgImpl::ControlFlowNode { + ControlFlowNode() { isCanonical(this) } + + /** 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. */ + pragma[inline] + ControlFlowNode getASuccessor() { result = nextCanonical(this) } + + /** Gets a successor for this node if the relevant condition is True. */ + ControlFlowNode getATrueSuccessor() { + super.isAfterTrue(_) and + exists(CfgImpl::ControlFlowNode other | other.isAfterFalse(super.getAstNode())) and + result = nextCanonical(this) + } + + /** Gets a successor for this node if the relevant condition is False. */ + ControlFlowNode getAFalseSuccessor() { + super.isAfterFalse(_) and + exists(CfgImpl::ControlFlowNode other | other.isAfterTrue(super.getAstNode())) and + result = nextCanonical(this) + } + + /** Gets a successor for this node if an exception is raised. */ + ControlFlowNode getAnExceptionalSuccessor() { + exists(CfgImpl::ControlFlowNode mid | + mid = super.getAnExceptionSuccessor() and + result = nextCanonicalFrom(mid) + ) + } + + /** Gets a successor for this node if no exception is raised. */ + ControlFlowNode getANormalSuccessor() { + result = this.getASuccessor() and + not result = this.getAnExceptionalSuccessor() + } + + /** 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 } + + /** Internal: raw successor predicate that does NOT skip non-canonical nodes. */ + CfgImpl::ControlFlowNode getASuccessorRaw() { result = super.getASuccessor() } +} + +/** + * 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 +} + +/** + * Gets the nearest canonical CFG node reachable from `n` via one or more + * raw CFG edges (skipping non-canonical intermediaries). + */ +private CfgImpl::ControlFlowNode nextCanonicalFrom(CfgImpl::ControlFlowNode n) { + result = n.getASuccessor() and isCanonical(result) + or + exists(CfgImpl::ControlFlowNode mid | + mid = n.getASuccessor() and + not isCanonical(mid) and + result = nextCanonicalFrom(mid) + ) +} + +/** Gets the nearest canonical CFG successor of canonical node `n`. */ +private ControlFlowNode nextCanonical(ControlFlowNode n) { result = nextCanonicalFrom(n) } + +/** + * 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, restricted to canonical nodes. */ + ControlFlowNode getNode(int n) { + result = rank[n + 1](ControlFlowNode node, int i | super.getNode(i) = node | node order by i) + } + + /** Gets a node in this basic block. */ + ControlFlowNode getANode() { result = this.getNode(_) } + + /** Gets the first canonical node in this basic block. */ + ControlFlowNode firstNode() { result = this.getNode(0) } + + /** Gets the last canonical node in this basic block. */ + ControlFlowNode getLastNode() { result = this.getNode(max(int n | exists(this.getNode(n)))) } + + /** 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(), + // getNode(int) (raw, includes non-canonical), getANode() (raw), + // strictlyDominates(), dominates(), getImmediateDominator(), + // length(), inLoop(). + // We expose canonical-only positional access via `getNode(int)` below + // (shadows the shared-lib version) and additional Python-style helpers. + /** 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 operands of an if-expression. */ + ControlFlowNode getAnOperand() { result = this.getAPredecessor() } +} + +/** 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 fefa30965cec..39e8d40fd172 100644 --- a/python/ql/lib/semmle/python/dataflow/new/BarrierGuards.qll +++ b/python/ql/lib/semmle/python/dataflow/new/BarrierGuards.qll @@ -1,36 +1,43 @@ /** 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 | - op = any(Eq eq) and branch = true - or - op = any(NotEq ne) and branch = false +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 + or + op = any(NotEq ne) and branch = false + ) | - cn.operands(const.getAFlowNode(), op, node) + cn.operands(c, op, node) or - cn.operands(node, op, const.getAFlowNode()) + cn.operands(node, op, c) ) or - exists(NameConstant const, Cmpop op | - op = any(Is is_) and branch = true - or - op = any(IsNot isn) and branch = false + exists(NameConstant const, Cmpop op, Cfg::ControlFlowNode c | + c.getNode() = const and + ( + op = any(Is is_) and branch = true + or + op = any(IsNot isn) and branch = false + ) | - cn.operands(const.getAFlowNode(), op, node) + cn.operands(c, op, node) or - cn.operands(node, op, const.getAFlowNode()) + 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 8778ae288667..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() } } @@ -228,7 +229,7 @@ private class ClassDefinitionAsAttrWrite extends AttrWrite, CfgNode { override Node getValue() { result.asCfgNode() = node.getValue() } - override Node getObject() { result.asCfgNode() = cls.getAFlowNode() } + override Node getObject() { result.asCfgNode().getNode() = cls } override ExprNode getAttributeNameExpr() { none() } @@ -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 1db6c08f5f43..872e030e0ecb 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) @@ -256,9 +257,13 @@ predicate parameterMatch(ParameterPosition ppos, ArgumentPosition apos) { */ overlay[local] predicate isStaticmethod(Function func) { - exists(NameNode id | id.getId() = "staticmethod" and id.isGlobal() | - func.getADecorator() = id.getNode() - ) + // The decorator is *syntactically* a Name "staticmethod" — we don't + // care which variable it resolves to. Even if a class redefines + // `staticmethod`, the binding hasn't happened yet at the decorator + // position, so Python's runtime semantics is "use the builtin". + // Matches legacy ESSA semantics which used `isGlobal()` (i.e. "no + // SSA def reaches this load") at the decorator's `NameNode`. + func.getADecorator().(Name).getId() = "staticmethod" } /** @@ -268,9 +273,7 @@ predicate isStaticmethod(Function func) { */ overlay[local] predicate isClassmethod(Function func) { - exists(NameNode id | id.getId() = "classmethod" and id.isGlobal() | - func.getADecorator() = id.getNode() - ) + func.getADecorator().(Name).getId() = "classmethod" or exists(Class cls | cls.getAMethod() = func and @@ -284,21 +287,19 @@ predicate isClassmethod(Function func) { /** Holds if the function `func` has a `property` decorator. */ overlay[local] -predicate hasPropertyDecorator(Function func) { - exists(NameNode id | id.getId() = "property" and id.isGlobal() | - func.getADecorator() = id.getNode() - ) -} +predicate hasPropertyDecorator(Function func) { func.getADecorator().(Name).getId() = "property" } /** * Holds if the function `func` has a `contextlib.contextmanager`. */ 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() ) @@ -314,10 +315,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() ) @@ -536,7 +537,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 ) } @@ -548,7 +549,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 ) } @@ -1034,7 +1035,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) @@ -1043,7 +1044,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 @@ -1060,7 +1061,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 @@ -1070,7 +1071,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 @@ -1082,7 +1083,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(_)] } @@ -1104,7 +1105,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 @@ -1114,7 +1115,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 ( @@ -1133,7 +1134,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 @@ -1180,7 +1181,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) @@ -1210,7 +1211,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__") @@ -1229,7 +1230,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 @@ -1254,11 +1255,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) @@ -1273,7 +1274,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() @@ -1347,7 +1348,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 ( @@ -1440,10 +1443,13 @@ 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) { + resolveCall(call, target, type) and + Cfg::isCanonicalAstNodeRepresentative(call) + } or /** A call to the generated function inside a comprehension */ TComprehensionCall(Comp c) or - TPotentialLibraryCall(CallNode call) or + TPotentialLibraryCall(Cfg::CallNode call) { Cfg::isCanonicalAstNodeRepresentative(call) } or /** A synthesized call inside a summarized callable */ TSummaryCall( FlowSummaryImpl::Public::SummarizedCallable c, FlowSummaryImpl::Private::SummaryNode receiver @@ -1463,7 +1469,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()) } @@ -1494,28 +1500,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() } @@ -1543,7 +1549,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() } @@ -1566,14 +1572,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() } @@ -1590,10 +1596,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() } } @@ -1625,7 +1631,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 } @@ -1767,12 +1773,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 } @@ -1790,7 +1796,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() @@ -1804,7 +1810,7 @@ class CapturedVariablesArgumentNodeAsArgumentNode extends ArgumentNode, class SynthCapturedVariablesArgumentPostUpdateNode extends PostUpdateNodeImpl, TSynthCapturedVariablesArgumentPostUpdateNode { - ControlFlowNode callable; + Cfg::ControlFlowNode callable; SynthCapturedVariablesArgumentPostUpdateNode() { this = TSynthCapturedVariablesArgumentPostUpdateNode(callable) @@ -1911,8 +1917,8 @@ abstract class ReturnNode extends Node { class ExtractedReturnNode extends ReturnNode, CfgNode { // See `TaintTrackingImplementation::returnFlowStep` ExtractedReturnNode() { - node = any(Return ret).getValue().getAFlowNode() or - node = any(Yield yield).getAFlowNode() + node.getNode() = any(Return ret).getValue() or + node.getNode() = any(Yield yield) } override ReturnKind getKind() { any() } @@ -1930,7 +1936,7 @@ class ExtractedReturnNode extends ReturnNode, CfgNode { class YieldNodeInContextManagerFunction extends ReturnNode, CfgNode { YieldNodeInContextManagerFunction() { hasContextmanagerDecorator(node.getScope()) and - node = any(Yield yield).getValue().getAFlowNode() + node.getNode() = any(Yield yield).getValue() } override ReturnKind getKind() { any() } 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 fffd0150008e..2ef018a912e5 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,23 @@ predicate isArgumentNode(ArgumentNode arg, DataFlowCall c, ArgumentPosition pos) // Nodes //-------- overlay[local] -predicate isExpressionNode(ControlFlowNode node) { node.getNode() instanceof Expr } +predicate isExpressionNode(Cfg::ControlFlowNode node) { + 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 +162,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 +176,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 @@ -185,8 +196,8 @@ private predicate synthDictSplatArgumentNodeStoreStep( */ predicate yieldStoreStep(Node nodeFrom, Content c, Node nodeTo) { exists(Yield yield | - nodeTo.asCfgNode() = yield.getAFlowNode() and - nodeFrom.asCfgNode() = yield.getValue().getAFlowNode() and + nodeTo.asCfgNode().getNode() = yield and + nodeFrom.asCfgNode().getNode() = yield.getValue() and // TODO: Consider if this will also need to transfer dictionary content // once dictionary comprehensions are supported. c instanceof ListElementContent @@ -289,7 +300,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 +344,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 +398,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 +413,28 @@ 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 `Cfg::isCanonicalAstNodeRepresentative` 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() and + Cfg::isCanonicalAstNodeRepresentative(nodeFrom) and + Cfg::isCanonicalAstNodeRepresentative(nodeTo) + ) } - 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() and + Cfg::isCanonicalAstNodeRepresentative(nodeTo) + ) } predicate useUseFlowStep(Node nodeFrom, Node nodeTo) { @@ -390,12 +443,14 @@ 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() and + Cfg::isCanonicalAstNodeRepresentative(nodeTo.(CfgNode).getNode()) ) or // Next use after use @@ -557,9 +612,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 +718,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() } /** @@ -872,7 +927,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 @@ -885,7 +940,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 } @@ -898,7 +953,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 ) @@ -912,7 +967,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() ) @@ -927,9 +982,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 @@ -942,8 +997,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() ) @@ -1018,7 +1073,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 @@ -1027,10 +1082,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() ) } 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 8612d4a253e0..4724a8e59129 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,12 @@ overlay[local] module; private import python +private import semmle.python.controlflow.internal.Cfg as Cfg 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 +28,21 @@ private import semmle.python.frameworks.data.ModelsAsData overlay[local] newtype TNode = /** A node corresponding to a control flow node. */ - TCfgNode(ControlFlowNode node) { - isExpressionNode(node) - or - node.getNode() instanceof Pattern + TCfgNode(Cfg::ControlFlowNode node) { + ( + isExpressionNode(node) + or + node.getNode() instanceof Pattern + ) and + Cfg::isCanonicalAstNodeRepresentative(node) } 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,36 +53,39 @@ 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) { Cfg::isCanonicalAstNodeRepresentative(call) } or /** * A synthetic node representing the value of an object after a state change. * See QLDoc for `PostUpdateNode`. */ - TSyntheticPostUpdateNode(ControlFlowNode node) { - exists(CallNode call | - node = call.getArg(_) + TSyntheticPostUpdateNode(Cfg::ControlFlowNode node) { + Cfg::isCanonicalAstNodeRepresentative(node) and + ( + exists(Cfg::CallNode call | + node = call.getArg(_) + or + node = call.getArgByName(_) + or + // `self` argument when handling class instance calls (`__call__` special method)) + node = call.getFunction() + ) or - node = call.getArgByName(_) + node = any(Cfg::AttrNode a).getObject() or - // `self` argument when handling class instance calls (`__call__` special method)) - node = call.getFunction() - ) - or - node = any(AttrNode a).getObject() - or - node = any(SubscriptNode s).getObject() - or - // self parameter when used implicitly in `super()` - exists(Class cls, Function func, ParameterDefinition def | - func = cls.getAMethod() and - not isStaticmethod(func) and - // this matches what we do in ExtractedParameterNode - def.getDefiningNode() = node and - def.getParameter() = func.getArg(0) + node = any(Cfg::SubscriptNode s).getObject() + or + // self parameter when used implicitly in `super()` + exists(Class cls, Function func, SsaImpl::ParameterDefinition def | + func = cls.getAMethod() and + not isStaticmethod(func) and + // this matches what we do in ExtractedParameterNode + def.getDefiningNode() = node and + def.getParameter() = func.getArg(0) + ) + or + // the iterable argument to the implicit comprehension function + node.getNode() = any(Comp c).getIterable() ) - 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 +121,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) { + exists(call.getArgByName(_)) and Cfg::isCanonicalAstNodeRepresentative(call) + } 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 +139,17 @@ 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 = any(Cfg::CallNode c).getFunction() and + Cfg::isCanonicalAstNodeRepresentative(callable) } 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 = any(Cfg::CallNode c).getFunction() and + Cfg::isCanonicalAstNodeRepresentative(callable) } or /** A synthetic node representing the values of variables captured by a comprehension. */ TSynthCompCapturedVariablesArgumentNode(Comp comp) { @@ -194,7 +207,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 +220,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 +237,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 +320,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 +350,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 +381,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 +393,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() @@ -485,21 +498,24 @@ class ModuleVariableNode extends Node, TModuleVariableNode { /** Gets a node that reads this variable, excluding reads that happen through `from ... import *`. */ Node getALocalRead() { - result.asCfgNode() = var.getALoad().getAFlowNode() and + result.asCfgNode().getNode() = var.getALoad() and 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 +532,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 +590,110 @@ 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 new shared CFG, such nodes appear in + * pairs of `isAfterTrue`/`isAfterFalse` annotated CFG nodes. * - * 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. + * Users typically obtain a `GuardNode` by casting from a more specific + * Cfg type: `g.(Cfg::CallNode)` for a call-based check, etc. * - * However, in the program - * ```python - * if not is_safe(path): - * return - * ``` - * the last node in the `ConditionBlock` is `not is_safe(path)`. + * This replaces the legacy (pre-shared-CFG) `GuardNode`/`flipped` + * machinery: the shared CFG carries outcome information structurally + * (via `isAfterTrue`/`isAfterFalse`), so no separate polarity field + * is required. + */ +class GuardNode extends Cfg::ControlFlowNode { + GuardNode() { + // This is the canonical (post-order) version of an AST node, and + // some `[true]`/`[false]` variant of the same AST exists. We + // include the canonical node because users identify guards by + // their AST (`g.(Cfg::CallNode)` etc.), and the outcome-tagged + // variants are accessed by `outcomeOfGuard` below. + exists(Cfg::ControlFlowNode outcome | + outcome.getNode() = this.getNode() and + (outcome.isAfterTrue(_) or outcome.isAfterFalse(_)) + ) + or + // Or: this IS one of the outcome-tagged variants, supporting + // users who want to query the split point directly. + this.isAfterTrue(_) + or + this.isAfterFalse(_) + } + + /** Holds if this guard controls block `b` upon evaluating to `branch`. */ + predicate controlsBlock(Cfg::BasicBlock b, boolean branch) { + branch in [true, false] and + exists(Cfg::ControlFlowNode outcomeNode | + outcomeOfGuard(this, outcomeNode, branch) and + outcomeNode.getBasicBlock().dominates(b) + ) + } +} + +/** + * Holds if some execution that arrives at `outcomeNode` corresponds + * to `guard` having evaluated 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 node is `g` itself with + * `isAfterTrue`/`isAfterFalse`. For wrapped guards like `not g` or + * `g == True`, the outcome is on the wrapping expression with an + * appropriate polarity transform — we follow those wrappers up the + * AST to find the outermost expression that carries an actual + * `isAfterTrue`/`isAfterFalse` outcome. */ -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, Cfg::ControlFlowNode outcomeNode, boolean branch +) { + // Base case: the guard itself splits — the outcome node is the + // first node of an outcome BB, with matching outcome label. + // (The shared CFG also marks inner expressions with outcome flags + // for analysis purposes, but only "splitting" nodes — those that + // actually start an outcome BB — are valid guards on their own.) + outcomeNode.getNode() = guard.getNode() and + outcomeNode = outcomeNode.getBasicBlock().firstNode() and + ( + outcomeNode.isAfterTrue(_) and branch = true + or + outcomeNode.isAfterFalse(_) and branch = false + ) 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.getOperand().getNode() = guard.getNode() and + notNode.getNode().getOp() instanceof Not and + outcomeOfGuard(notNode, outcomeNode, 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 + | + 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, outcomeNode, 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 +708,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 +720,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 +733,10 @@ 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 g.controlsBlock(result.asCfgNode().getBasicBlock(), branch) ) } @@ -712,7 +752,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 +788,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 +808,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 f3943f53f860..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,11 +5,24 @@ */ 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 -private import semmle.python.essa.SsaDefinitions + +/** + * 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 + exists(init.getPackage().getSubModule(var.getId())) and + var.getScope() = init +} /** * Python modules and the way imports are resolved are... complicated. Here's a crash course in how @@ -69,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. } /** @@ -92,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 @@ -143,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() ) @@ -158,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) { @@ -177,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) ) @@ -207,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) ) ) @@ -324,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 - SsaSource::init_module_submodule_defn(var.getSourceVariable(), package.getEntryNode()) 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..f931c4606034 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/MatchUnpacking.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/MatchUnpacking.qll @@ -55,6 +55,7 @@ module; private import python private import DataFlowPublic +private import semmle.python.controlflow.internal.Cfg as Cfg /** * Holds when there is flow from the subject `nodeFrom` to the (top-level) pattern `nodeTo` of a `match` statement. @@ -91,8 +92,8 @@ 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() + exists(Cfg::ControlFlowNode aliasCfg | aliasCfg.getNode() = alias | + nodeTo.(CfgNode).getNode() = aliasCfg ) ) } @@ -126,8 +127,8 @@ predicate matchLiteralFlowStep(Node nodeFrom, Node nodeTo) { predicate matchCaptureFlowStep(Node nodeFrom, Node nodeTo) { exists(MatchCapturePattern capture, Name var | capture.getVariable() = var | nodeFrom.(CfgNode).getNode().getNode() = capture and - exists(PatternCaptureDefinition pcd | pcd.getDefiningNode().getNode() = var | - nodeTo.(CfgNode).getNode() = pcd.getDefiningNode() + exists(Cfg::ControlFlowNode varCfg | varCfg.getNode() = var | + nodeTo.(CfgNode).getNode() = varCfg ) ) } 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..d9609599a583 --- /dev/null +++ b/python/ql/lib/semmle/python/dataflow/new/internal/SsaImpl.qll @@ -0,0 +1,547 @@ +/** + * 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 | + 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 62f5a76309b4..43f9a9e16fd4 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 @@ -75,7 +77,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() ) } @@ -84,7 +86,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() } /** @@ -100,15 +102,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 [ @@ -139,7 +141,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() @@ -149,7 +151,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() ) @@ -207,8 +209,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 95434b05451d..7fa1d4e573aa 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 @@ -94,8 +96,10 @@ private module SummaryTypeTrackerInput implements SummaryTypeTracker::Input { Node returnOf(Node callable, SummaryComponent return) { return = FlowSummaryImpl::Private::SummaryComponent::return() and // `result` should be the return value of a callable expression (lambda or function) referenced by `callable` - result.asCfgNode() = - callable.getALocalSource().asExpr().(CallableExpr).getInnerScope().getAReturnValueFlowNode() + exists(Return ret | + ret.getScope() = callable.getALocalSource().asExpr().(CallableExpr).getInnerScope() and + result.asCfgNode().getNode() = ret.getValue() + ) } // Relating callables to nodes @@ -160,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) ) @@ -259,7 +263,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 @@ -269,7 +273,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, content) @@ -306,13 +310,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 fbe05979328c..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/dataflow/old/Implementation.qll b/python/ql/lib/semmle/python/dataflow/old/Implementation.qll index 18020c7d9ffa..6e1314ff9e9a 100644 --- a/python/ql/lib/semmle/python/dataflow/old/Implementation.qll +++ b/python/ql/lib/semmle/python/dataflow/old/Implementation.qll @@ -448,8 +448,7 @@ class TaintTrackingImplementation extends string instanceof TaintTracking::Confi context = TNoParam() and src = TTaintTrackingNode_(retval, TNoParam(), path, kind, this) and node.asCfgNode() = call and - retval.asCfgNode() = - any(Return ret | ret.getScope() = pyfunc.getScope()).getValue().getAFlowNode() + retval.asCfgNode().getNode() = any(Return ret | ret.getScope() = pyfunc.getScope()).getValue() ) and edgeLabel = "return" } @@ -471,8 +470,7 @@ class TaintTrackingImplementation extends string instanceof TaintTracking::Confi this.callContexts(call, src, pyfunc, context, callee) and retnode = TTaintTrackingNode_(retval, callee, path, kind, this) and node.asCfgNode() = call and - retval.asCfgNode() = - any(Return ret | ret.getScope() = pyfunc.getScope()).getValue().getAFlowNode() + retval.asCfgNode().getNode() = any(Return ret | ret.getScope() = pyfunc.getScope()).getValue() ) and edgeLabel = "call" } @@ -716,8 +714,10 @@ private class EssaTaintTracking extends string instanceof TaintTracking::Configu src = TTaintTrackingNode_(srcnode, context, path, srckind, this) and path.noAttribute() | - assign.getValue().getAFlowNode() = srcnode.asCfgNode() and - depth = iterable_unpacking_descent(assign.getATarget().getAFlowNode(), defn.getDefiningNode()) and + srcnode.asCfgNode().getNode() = assign.getValue() and + exists(SequenceNode left_parent | left_parent.getNode() = assign.getATarget() | + depth = iterable_unpacking_descent(left_parent, defn.getDefiningNode()) + ) and kind = taint_at_depth(srckind, depth) ) } @@ -964,7 +964,7 @@ private TaintKind taint_at_depth(SequenceKind parent_kind, int depth) { * - with `left_defn` = `*y`, `left_parent` = `((x, *y), ...)`, result = 1 */ int iterable_unpacking_descent(SequenceNode left_parent, ControlFlowNode left_defn) { - exists(Assign a | a.getATarget().getASubExpression*().getAFlowNode() = left_parent) and + exists(Assign a | left_parent.getNode() = a.getATarget().getASubExpression*()) and left_parent.getAnElement() = left_defn and // Handle `a, *b = some_iterable` if left_defn instanceof StarredNode then result = 0 else result = 1 diff --git a/python/ql/lib/semmle/python/essa/SsaDefinitions.qll b/python/ql/lib/semmle/python/essa/SsaDefinitions.qll index 827bee34474e..44d246009d3a 100644 --- a/python/ql/lib/semmle/python/essa/SsaDefinitions.qll +++ b/python/ql/lib/semmle/python/essa/SsaDefinitions.qll @@ -56,7 +56,7 @@ module SsaSource { predicate with_definition(Variable v, ControlFlowNode defn) { exists(With with, Name var | with.getOptionalVars() = var and - var.getAFlowNode() = defn + defn.getNode() = var | var = v.getAStore() ) @@ -67,7 +67,7 @@ module SsaSource { predicate pattern_capture_definition(Variable v, ControlFlowNode defn) { exists(MatchCapturePattern capture, Name var | capture.getVariable() = var and - var.getAFlowNode() = defn + defn.getNode() = var | var = v.getAStore() ) @@ -78,7 +78,7 @@ module SsaSource { predicate pattern_alias_definition(Variable v, ControlFlowNode defn) { exists(MatchAsPattern pattern, Name var | pattern.getAlias() = var and - var.getAFlowNode() = defn + defn.getNode() = var | var = v.getAStore() ) diff --git a/python/ql/lib/semmle/python/frameworks/Bottle.qll b/python/ql/lib/semmle/python/frameworks/Bottle.qll index c03ea3df184e..9714f1967770 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 @@ -59,7 +60,7 @@ module Bottle { override Parameter getARoutedParameter() { none() } - override Function getARequestHandler() { result.getADecorator().getAFlowNode() = node } + override Function getARequestHandler() { node.getNode() = result.getADecorator() } } } @@ -73,7 +74,9 @@ module Bottle { /** A response returned by a view callable. */ class BottleReturnResponse extends Http::Server::HttpResponse::Range { BottleReturnResponse() { - this.asCfgNode() = any(View::ViewCallable vc).getAReturnValueFlowNode() + exists(View::ViewCallable vc, Return ret | + ret.getScope() = vc and this.asCfgNode().getNode() = ret.getValue() + ) } override DataFlow::Node getBody() { result = this } @@ -154,9 +157,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 ee0ed4a84dd0..37d5b3357256 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)) } @@ -2872,7 +2873,9 @@ module PrivateDjango { DataFlow::CfgNode { DjangoRedirectViewGetRedirectUrlReturn() { - node = any(GetRedirectUrlFunction f).getAReturnValueFlowNode() + exists(GetRedirectUrlFunction f, Return ret | + ret.getScope() = f and node.getNode() = ret.getValue() + ) } override DataFlow::Node getRedirectLocation() { result = this } diff --git a/python/ql/lib/semmle/python/frameworks/FastApi.qll b/python/ql/lib/semmle/python/frameworks/FastApi.qll index ed28f18a85a9..a8a35f485092 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 @@ -129,7 +130,7 @@ module FastApi { result in [this.getArg(0), this.getArgByName("path")] } - override Function getARequestHandler() { result.getADecorator().getAFlowNode() = node } + override Function getARequestHandler() { node.getNode() = result.getADecorator() } override string getFramework() { result = "FastAPI" } @@ -309,7 +310,11 @@ module FastApi { FastApiRouteSetup routeSetup; FastApiRequestHandlerReturn() { - node = routeSetup.getARequestHandler().getAReturnValueFlowNode() + exists(Function h, Return ret | + h = routeSetup.getARequestHandler() and + ret.getScope() = h and + node.getNode() = ret.getValue() + ) } override DataFlow::Node getBody() { result = this } @@ -438,7 +443,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 @@ -447,7 +452,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/Flask.qll b/python/ql/lib/semmle/python/frameworks/Flask.qll index f819e8679075..e2bb161eafe3 100644 --- a/python/ql/lib/semmle/python/frameworks/Flask.qll +++ b/python/ql/lib/semmle/python/frameworks/Flask.qll @@ -371,7 +371,7 @@ module Flask { result in [this.getArg(0), this.getArgByName("rule")] } - override Function getARequestHandler() { result.getADecorator().getAFlowNode() = node } + override Function getARequestHandler() { node.getNode() = result.getADecorator() } } /** @@ -536,7 +536,7 @@ module Flask { FlaskRouteHandlerReturn() { exists(Function routeHandler | routeHandler = any(FlaskRouteSetup rs).getARequestHandler() and - node = routeHandler.getAReturnValueFlowNode() and + exists(Return ret | ret.getScope() = routeHandler and node.getNode() = ret.getValue()) and not this instanceof Flask::Response::InstanceSource ) } diff --git a/python/ql/lib/semmle/python/frameworks/FlaskAdmin.qll b/python/ql/lib/semmle/python/frameworks/FlaskAdmin.qll index a9b90f1d9c4a..64870fd71ac4 100644 --- a/python/ql/lib/semmle/python/frameworks/FlaskAdmin.qll +++ b/python/ql/lib/semmle/python/frameworks/FlaskAdmin.qll @@ -38,7 +38,7 @@ private module FlaskAdmin { result in [this.getArg(0), this.getArgByName("url")] } - override Function getARequestHandler() { result.getADecorator().getAFlowNode() = node } + override Function getARequestHandler() { node.getNode() = result.getADecorator() } } /** @@ -71,7 +71,7 @@ private module FlaskAdmin { override Function getARequestHandler() { exists(Flask::FlaskViewClass cls | - cls.getADecorator().getAFlowNode() = node and + node.getNode() = cls.getADecorator() and result = cls.getARequestHandler() ) } 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/Pyramid.qll b/python/ql/lib/semmle/python/frameworks/Pyramid.qll index 63e19363fe86..2bd72a852536 100644 --- a/python/ql/lib/semmle/python/frameworks/Pyramid.qll +++ b/python/ql/lib/semmle/python/frameworks/Pyramid.qll @@ -166,7 +166,9 @@ module Pyramid { /** A response returned by a view callable. */ private class PyramidReturnResponse extends Http::Server::HttpResponse::Range { PyramidReturnResponse() { - this.asCfgNode() = any(View::ViewCallable vc).getAReturnValueFlowNode() and + exists(View::ViewCallable vc, Return ret | + ret.getScope() = vc and this.asCfgNode().getNode() = ret.getValue() + ) and not this = instance() } diff --git a/python/ql/lib/semmle/python/frameworks/Stdlib.qll b/python/ql/lib/semmle/python/frameworks/Stdlib.qll index 5d3b994880a1..d059c59e9af6 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 | - node = requestHandler.getAReturnValueFlowNode() + exists(WsgirefSimpleServerApplication requestHandler, Return ret | + ret.getScope() = requestHandler and node.getNode() = ret.getValue() ) } @@ -2337,9 +2338,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() ) @@ -2681,7 +2682,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 @@ -2806,7 +2807,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 @@ -5151,10 +5152,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/Twisted.qll b/python/ql/lib/semmle/python/frameworks/Twisted.qll index 60aedd8fb582..6d32bf42ef11 100644 --- a/python/ql/lib/semmle/python/frameworks/Twisted.qll +++ b/python/ql/lib/semmle/python/frameworks/Twisted.qll @@ -182,7 +182,9 @@ private module Twisted { DataFlow::CfgNode { TwistedResourceRenderMethodReturn() { - this.asCfgNode() = any(TwistedResourceRenderMethod meth).getAReturnValueFlowNode() + exists(TwistedResourceRenderMethod meth, Return ret | + ret.getScope() = meth and this.asCfgNode().getNode() = ret.getValue() + ) } override DataFlow::Node getBody() { result = this } 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/internal/CachedStages.qll b/python/ql/lib/semmle/python/internal/CachedStages.qll index 7379cc51372f..c1bc44945c8b 100644 --- a/python/ql/lib/semmle/python/internal/CachedStages.qll +++ b/python/ql/lib/semmle/python/internal/CachedStages.qll @@ -77,7 +77,7 @@ module Stages { or exists(any(AstExtended::AstNode n).getParentNode()) or - exists(any(AstExtended::AstNode n).getAFlowNode()) + exists(PyFlow::ControlFlowNode cfg, AstExtended::AstNode n | cfg.getNode() = n) or exists(any(PyFlow::BasicBlock b).getImmediateDominator()) or diff --git a/python/ql/lib/semmle/python/objects/Callables.qll b/python/ql/lib/semmle/python/objects/Callables.qll index 357779859bb8..c42393cc3c62 100644 --- a/python/ql/lib/semmle/python/objects/Callables.qll +++ b/python/ql/lib/semmle/python/objects/Callables.qll @@ -56,8 +56,9 @@ abstract class CallableObjectInternal extends ObjectInternal { /** A Python function. */ class PythonFunctionObjectInternal extends CallableObjectInternal, TPythonFunctionObject { override Function getScope() { - exists(CallableExpr expr | - this = TPythonFunctionObject(expr.getAFlowNode()) and + exists(CallableExpr expr, ControlFlowNode exprCfg | + exprCfg.getNode() = expr and + this = TPythonFunctionObject(exprCfg) and result = expr.getInnerScope() ) } @@ -160,10 +161,11 @@ class PythonFunctionObjectInternal extends CallableObjectInternal, TPythonFuncti } private BasicBlock blockReturningNone(Function func) { - exists(Return ret | + exists(Return ret, ControlFlowNode ret_ | not exists(ret.getValue()) and ret.getScope() = func and - result = ret.getAFlowNode().getBasicBlock() + ret_.getNode() = ret and + result = ret_.getBasicBlock() ) } diff --git a/python/ql/lib/semmle/python/objects/Classes.qll b/python/ql/lib/semmle/python/objects/Classes.qll index 998651a93bfd..2d30fb56ae31 100644 --- a/python/ql/lib/semmle/python/objects/Classes.qll +++ b/python/ql/lib/semmle/python/objects/Classes.qll @@ -113,8 +113,9 @@ abstract class ClassObjectInternal extends ObjectInternal { class PythonClassObjectInternal extends ClassObjectInternal, TPythonClassObject { /** Gets the scope for this Python class */ Class getScope() { - exists(ClassExpr expr | - this = TPythonClassObject(expr.getAFlowNode()) and + exists(ClassExpr expr, ControlFlowNode exprCfg | + exprCfg.getNode() = expr and + this = TPythonClassObject(exprCfg) and result = expr.getInnerScope() ) } diff --git a/python/ql/lib/semmle/python/objects/TObject.qll b/python/ql/lib/semmle/python/objects/TObject.qll index cfa8cb5aa07b..dd191467c19f 100644 --- a/python/ql/lib/semmle/python/objects/TObject.qll +++ b/python/ql/lib/semmle/python/objects/TObject.qll @@ -387,7 +387,7 @@ private PythonClassObjectInternal abcMetaClassObject() { private predicate neither_class_nor_static_method(Function f) { not exists(f.getADecorator()) or - exists(ControlFlowNode deco | deco = f.getADecorator().getAFlowNode() | + exists(ControlFlowNode deco | deco.getNode() = f.getADecorator() | exists(ObjectInternal o | PointsToInternal::pointsTo(deco, _, o, _) | o != ObjectInternal::staticMethod() and o != ObjectInternal::classMethod() diff --git a/python/ql/lib/semmle/python/pointsto/PointsTo.qll b/python/ql/lib/semmle/python/pointsto/PointsTo.qll index 8cc400c33b7b..41c6dafa46a4 100644 --- a/python/ql/lib/semmle/python/pointsto/PointsTo.qll +++ b/python/ql/lib/semmle/python/pointsto/PointsTo.qll @@ -711,7 +711,7 @@ private module InterModulePointsTo { ControlFlowNode f, PointsToContext context, ObjectInternal value, ControlFlowNode origin ) { exists(string name, ImportExpr i | - i.getAFlowNode() = f and + f.getNode() = i and i.getImportedModuleName() = name and PointsToInternal::module_imported_as(value, name) and origin = f and @@ -2118,8 +2118,9 @@ module Types { result.getBuiltin() = cls.getBuiltin().getBaseClass() and n = 0 or exists(Class pycls | pycls = cls.(PythonClassObjectInternal).getScope() | - exists(ObjectInternal base | - PointsToInternal::pointsTo(pycls.getBase(n).getAFlowNode(), _, base, _) + exists(ObjectInternal base, ControlFlowNode baseNode | + baseNode.getNode() = pycls.getBase(n) and + PointsToInternal::pointsTo(baseNode, _, base, _) | result = base and base != ObjectInternal::unknown() or @@ -2223,7 +2224,10 @@ module Types { } private ControlFlowNode decorator_call_callee(PythonClassObjectInternal cls) { - result = cls.getScope().getADecorator().getAFlowNode().(CallNode).getFunction() + exists(CallNode deco | + deco.getNode() = cls.getScope().getADecorator() and + result = deco.getFunction() + ) } private boolean has_six_add_metaclass(PythonClassObjectInternal cls) { @@ -2262,7 +2266,7 @@ module Types { } private EssaVariable metaclass_var(Class cls) { - result.getASourceUse() = cls.getMetaClass().getAFlowNode() + result.getASourceUse().getNode() = cls.getMetaClass() or major_version() = 2 and not exists(cls.getMetaClass()) 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/semmle/python/types/ClassObject.qll b/python/ql/lib/semmle/python/types/ClassObject.qll index 8607141f16f9..1ed271467ef6 100644 --- a/python/ql/lib/semmle/python/types/ClassObject.qll +++ b/python/ql/lib/semmle/python/types/ClassObject.qll @@ -181,7 +181,7 @@ class ClassObject extends Object { ) } - ControlFlowNode declaredMetaClass() { result = this.getPyClass().getMetaClass().getAFlowNode() } + ControlFlowNode declaredMetaClass() { result.getNode() = this.getPyClass().getMetaClass() } /** Has type inference failed to compute the full class hierarchy for this class for the reason given. */ predicate failedInference(string reason) { Types::failedInference(this.theClass(), reason) } @@ -195,8 +195,9 @@ class ClassObject extends Object { * It is guaranteed that getProbableSingletonInstance() returns at most one Object for each ClassObject. */ Object getProbableSingletonInstance() { - exists(ControlFlowNodeWithPointsTo use, Expr origin | - use.refersTo(result, this, origin.getAFlowNode()) + exists(ControlFlowNodeWithPointsTo use, Expr origin, ControlFlowNode origin_ | + origin_.getNode() = origin and + use.refersTo(result, this, origin_) | this.hasStaticallyUniqueInstance() and /* Ensure that original expression will be executed only one. */ diff --git a/python/ql/lib/semmle/python/types/Exceptions.qll b/python/ql/lib/semmle/python/types/Exceptions.qll index ea2f20e67aab..0b388ca184a4 100644 --- a/python/ql/lib/semmle/python/types/Exceptions.qll +++ b/python/ql/lib/semmle/python/types/Exceptions.qll @@ -427,7 +427,7 @@ class ExceptFlowNodeWithPointsTo extends ExceptFlowNode { } private ControlFlowNodeWithPointsTo element_from_tuple_objectapi(Object tuple) { - exists(Tuple t | t = tuple.getOrigin() and result = t.getAnElt().getAFlowNode()) + exists(Tuple t | t = tuple.getOrigin() and result.getNode() = t.getAnElt()) } /** diff --git a/python/ql/lib/semmle/python/types/Extensions.qll b/python/ql/lib/semmle/python/types/Extensions.qll index 3cde11977d05..5a3a442b1f80 100644 --- a/python/ql/lib/semmle/python/types/Extensions.qll +++ b/python/ql/lib/semmle/python/types/Extensions.qll @@ -36,8 +36,8 @@ class RangeIterationVariableFact extends PointsToExtension { RangeIterationVariableFact() { exists(For f, ControlFlowNode iterable | iterable.getBasicBlock().dominates(this.(ControlFlowNode).getBasicBlock()) and - f.getIter().getAFlowNode() = iterable and - f.getTarget().getAFlowNode() = this and + iterable.getNode() = f.getIter() and + this.(ControlFlowNode).getNode() = f.getTarget() and exists(ObjectInternal range | PointsTo::pointsTo(iterable, _, range, _) and range.getClass() = ObjectInternal::builtin("range") diff --git a/python/ql/lib/semmle/python/types/FunctionObject.qll b/python/ql/lib/semmle/python/types/FunctionObject.qll index 7ff0f37ca9a3..d03f08623009 100644 --- a/python/ql/lib/semmle/python/types/FunctionObject.qll +++ b/python/ql/lib/semmle/python/types/FunctionObject.qll @@ -170,7 +170,7 @@ class PyFunctionObject extends FunctionObject { predicate unconditionallyReturnsParameter(int n) { exists(SsaVariable pvar | exists(Parameter p | p = this.getFunction().getArg(n) | - p.asName().getAFlowNode() = pvar.getDefinition() + pvar.getDefinition().getNode() = p.asName() ) and exists(NameNode rval | rval = pvar.getAUse() and diff --git a/python/ql/lib/semmle/python/types/Object.qll b/python/ql/lib/semmle/python/types/Object.qll index 4c88f46dde87..0dbd7de10f5b 100644 --- a/python/ql/lib/semmle/python/types/Object.qll +++ b/python/ql/lib/semmle/python/types/Object.qll @@ -337,7 +337,7 @@ class TupleObject extends SequenceObject { or this instanceof TupleNode or - exists(Function func | func.getVararg().getAFlowNode() = this) + exists(Function func | this.(ControlFlowNode).getNode() = func.getVararg()) } } @@ -352,7 +352,9 @@ module TupleObject { } class NonEmptyTupleObject extends TupleObject { - NonEmptyTupleObject() { exists(Function func | func.getVararg().getAFlowNode() = this) } + NonEmptyTupleObject() { + exists(Function func | this.(ControlFlowNode).getNode() = func.getVararg()) + } override boolean booleanValue() { result = true } } 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..b6067257f979 100644 --- a/python/ql/lib/utils/test/dataflow/UnresolvedCalls.qll +++ b/python/ql/lib/utils/test/dataflow/UnresolvedCalls.qll @@ -1,15 +1,17 @@ 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) { + Cfg::isCanonicalAstNodeRepresentative(call) and not exists(DataFlowPrivate::DataFlowCall dfc | exists(dfc.getCallable()) and dfc.getNode() = call ) and @@ -24,7 +26,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) | 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/Classes/ClassAttributes.qll b/python/ql/src/Classes/ClassAttributes.qll index 4063bc7042ef..58f8ae5dffc9 100644 --- a/python/ql/src/Classes/ClassAttributes.qll +++ b/python/ql/src/Classes/ClassAttributes.qll @@ -48,9 +48,11 @@ class CheckClass extends ClassObject { self_dict = sub.getObject() or /* Indirect assignment via temporary variable */ - exists(SsaVariable v | - v.getAUse() = sub.getObject().getAFlowNode() and - v.getDefinition().(DefinitionNode).getValue() = self_dict.getAFlowNode() + exists(SsaVariable v, ControlFlowNode subObjCfg, ControlFlowNode selfDictCfg | + subObjCfg.getNode() = sub.getObject() and selfDictCfg.getNode() = self_dict + | + v.getAUse() = subObjCfg and + v.getDefinition().(DefinitionNode).getValue() = selfDictCfg ) ) and a.getATarget() = sub and @@ -62,9 +64,10 @@ class CheckClass extends ClassObject { pragma[nomagic] private predicate monkeyPatched(string name) { - exists(Attribute a | + exists(Attribute a, ControlFlowNode objCfg | + objCfg.getNode() = a.getObject() and a.getCtx() instanceof Store and - PointsTo::points_to(a.getObject().getAFlowNode(), _, this, _, _) and + PointsTo::points_to(objCfg, _, this, _, _) and a.getName() = name ) } @@ -84,9 +87,9 @@ class CheckClass extends ClassObject { } predicate interestingUndefined(SelfAttributeRead a) { - exists(string name | name = a.getName() | + exists(string name, ControlFlowNode aCfg | name = a.getName() and aCfg.getNode() = a | this.interestingContext(a, name) and - not this.definedInBlock(a.getAFlowNode().getBasicBlock(), name) + not this.definedInBlock(aCfg.getBasicBlock(), name) ) } @@ -109,8 +112,9 @@ class CheckClass extends ClassObject { pragma[nomagic] private predicate definitionInBlock(BasicBlock b, string name) { - exists(SelfAttributeStore sa | - sa.getAFlowNode().getBasicBlock() = b and + exists(SelfAttributeStore sa, ControlFlowNode saCfg | + saCfg.getNode() = sa and + saCfg.getBasicBlock() = b and sa.getName() = name and sa.getClass() = this.getPyClass() ) diff --git a/python/ql/src/Exceptions/CatchingBaseException.ql b/python/ql/src/Exceptions/CatchingBaseException.ql index 79174488760b..24d56f38afce 100644 --- a/python/ql/src/Exceptions/CatchingBaseException.ql +++ b/python/ql/src/Exceptions/CatchingBaseException.ql @@ -15,7 +15,9 @@ import python import semmle.python.ApiGraphs -predicate doesnt_reraise(ExceptStmt ex) { ex.getAFlowNode().getBasicBlock().reachesExit() } +predicate doesnt_reraise(ExceptStmt ex) { + exists(ControlFlowNode exCfg | exCfg.getNode() = ex | exCfg.getBasicBlock().reachesExit()) +} predicate catches_base_exception(ExceptStmt ex) { ex.getType() = API::builtin("BaseException").getAValueReachableFromSource().asExpr() 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/CallArgs.qll b/python/ql/src/Expressions/CallArgs.qll index 709915afbc61..43782a903dcb 100644 --- a/python/ql/src/Expressions/CallArgs.qll +++ b/python/ql/src/Expressions/CallArgs.qll @@ -116,7 +116,7 @@ FunctionValue get_function_or_initializer(Value func_or_cls) { predicate illegally_named_parameter_objectapi(Call call, Object func, string name) { not func.isC() and name = call.getANamedArgumentName() and - call.getAFlowNode() = get_a_call_objectapi(func) and + exists(ControlFlowNode callCfg | callCfg.getNode() = call | callCfg = get_a_call_objectapi(func)) and not get_function_or_initializer_objectapi(func).isLegalArgumentName(name) } @@ -124,7 +124,7 @@ predicate illegally_named_parameter_objectapi(Call call, Object func, string nam predicate illegally_named_parameter(Call call, Value func, string name) { not func.isBuiltin() and name = call.getANamedArgumentName() and - call.getAFlowNode() = get_a_call(func) and + exists(ControlFlowNode callCfg | callCfg.getNode() = call | callCfg = get_a_call(func)) and not get_function_or_initializer(func).isLegalArgumentName(name) } @@ -146,7 +146,9 @@ predicate too_few_args_objectapi(Call call, Object callable, int limit) { call = func.getAMethodCall().getNode() and limit = func.minParameters() - 1 or callable instanceof ClassObject and - call.getAFlowNode() = get_a_call_objectapi(callable) and + exists(ControlFlowNode callCfg | callCfg.getNode() = call | + callCfg = get_a_call_objectapi(callable) + ) and limit = func.minParameters() - 1 ) } @@ -172,7 +174,7 @@ predicate too_few_args(Call call, Value callable, int limit) { call = func.getAMethodCall().getNode() and limit = func.minParameters() - 1 or callable instanceof ClassValue and - call.getAFlowNode() = get_a_call(callable) and + exists(ControlFlowNode callCfg | callCfg.getNode() = call | callCfg = get_a_call(callable)) and limit = func.minParameters() - 1 ) } @@ -191,7 +193,9 @@ predicate too_many_args_objectapi(Call call, Object callable, int limit) { call = func.getAMethodCall().getNode() and limit = func.maxParameters() - 1 or callable instanceof ClassObject and - call.getAFlowNode() = get_a_call_objectapi(callable) and + exists(ControlFlowNode callCfg | callCfg.getNode() = call | + callCfg = get_a_call_objectapi(callable) + ) and limit = func.maxParameters() - 1 ) and positional_arg_count_for_call_objectapi(call, callable) > limit @@ -211,7 +215,7 @@ predicate too_many_args(Call call, Value callable, int limit) { call = func.getAMethodCall().getNode() and limit = func.maxParameters() - 1 or callable instanceof ClassValue and - call.getAFlowNode() = get_a_call(callable) and + exists(ControlFlowNode callCfg | callCfg.getNode() = call | callCfg = get_a_call(callable)) and limit = func.maxParameters() - 1 ) and positional_arg_count_for_call(call, callable) > limit diff --git a/python/ql/src/Expressions/DuplicateKeyInDictionaryLiteral.ql b/python/ql/src/Expressions/DuplicateKeyInDictionaryLiteral.ql index 166eae635fad..0c55a2ece587 100644 --- a/python/ql/src/Expressions/DuplicateKeyInDictionaryLiteral.ql +++ b/python/ql/src/Expressions/DuplicateKeyInDictionaryLiteral.ql @@ -36,11 +36,15 @@ where exists(string s | dict_key(d, k1, s) and dict_key(d, k2, s) and k1 != k2) and ( exists(BasicBlock b, int i1, int i2 | - k1.getAFlowNode() = b.getNode(i1) and - k2.getAFlowNode() = b.getNode(i2) and + b.getNode(i1).getNode() = k1 and + b.getNode(i2).getNode() = k2 and i1 < i2 ) or - k1.getAFlowNode().getBasicBlock().strictlyDominates(k2.getAFlowNode().getBasicBlock()) + exists(ControlFlowNode k1Cfg, ControlFlowNode k2Cfg | + k1Cfg.getNode() = k1 and k2Cfg.getNode() = k2 + | + k1Cfg.getBasicBlock().strictlyDominates(k2Cfg.getBasicBlock()) + ) ) select k1, "Dictionary key " + repr(k1) + " is subsequently $@.", k2, "overwritten" diff --git a/python/ql/src/Expressions/Formatting/AdvancedFormatting.qll b/python/ql/src/Expressions/Formatting/AdvancedFormatting.qll index d98286d85faf..a5e0379685a3 100644 --- a/python/ql/src/Expressions/Formatting/AdvancedFormatting.qll +++ b/python/ql/src/Expressions/Formatting/AdvancedFormatting.qll @@ -98,16 +98,18 @@ private predicate brace_pair(PossibleAdvancedFormatString fmt, int start, int en } private predicate advanced_format_call(Call format_expr, PossibleAdvancedFormatString fmt, int args) { - exists(CallNode call | call = format_expr.getAFlowNode() | + exists(CallNode call, ControlFlowNode fmtCfg | + call.getNode() = format_expr and fmtCfg.getNode() = fmt + | call.getFunction().(ControlFlowNodeWithPointsTo).pointsTo(Value::named("format")) and - call.getArg(0).(ControlFlowNodeWithPointsTo).pointsTo(_, fmt.getAFlowNode()) and + call.getArg(0).(ControlFlowNodeWithPointsTo).pointsTo(_, fmtCfg) and args = count(format_expr.getAnArg()) - 1 or call.getFunction() .(AttrNode) .getObject("format") .(ControlFlowNodeWithPointsTo) - .pointsTo(_, fmt.getAFlowNode()) and + .pointsTo(_, fmtCfg) and args = count(format_expr.getAnArg()) ) } diff --git a/python/ql/src/Expressions/IncorrectComparisonUsingIs.ql b/python/ql/src/Expressions/IncorrectComparisonUsingIs.ql index fa0ca14669f6..a7336c625472 100644 --- a/python/ql/src/Expressions/IncorrectComparisonUsingIs.ql +++ b/python/ql/src/Expressions/IncorrectComparisonUsingIs.ql @@ -15,7 +15,7 @@ import python /** Holds if the comparison `comp` uses `is` or `is not` (represented as `op`) to compare its `left` and `right` arguments. */ predicate comparison_using_is(Compare comp, ControlFlowNode left, Cmpop op, ControlFlowNode right) { - exists(CompareNode fcomp | fcomp = comp.getAFlowNode() | + exists(CompareNode fcomp | fcomp.getNode() = comp | fcomp.operands(left, op, right) and (op instanceof Is or op instanceof IsNot) ) diff --git a/python/ql/src/Expressions/IsComparisons.qll b/python/ql/src/Expressions/IsComparisons.qll index cb052ceca765..ee49f6c3337a 100644 --- a/python/ql/src/Expressions/IsComparisons.qll +++ b/python/ql/src/Expressions/IsComparisons.qll @@ -5,7 +5,7 @@ private import LegacyPointsTo /** Holds if the comparison `comp` uses `is` or `is not` (represented as `op`) to compare its `left` and `right` arguments. */ predicate comparison_using_is(Compare comp, ControlFlowNode left, Cmpop op, ControlFlowNode right) { - exists(CompareNode fcomp | fcomp = comp.getAFlowNode() | + exists(CompareNode fcomp | fcomp.getNode() = comp | fcomp.operands(left, op, right) and (op instanceof Is or op instanceof IsNot) ) diff --git a/python/ql/src/Expressions/TruncatedDivision.ql b/python/ql/src/Expressions/TruncatedDivision.ql index c731a21f7d26..d63ac056d3c2 100644 --- a/python/ql/src/Expressions/TruncatedDivision.ql +++ b/python/ql/src/Expressions/TruncatedDivision.ql @@ -19,7 +19,7 @@ where // Only relevant for Python 2, as all later versions implement true division major_version() = 2 and exists(BinaryExprNode bin, Value lval, Value rval | - bin = div.getAFlowNode() and + bin.getNode() = div and bin.getNode().getOp() instanceof Div and bin.getLeft().(ControlFlowNodeWithPointsTo).pointsTo(lval, left) and lval.getClass() = ClassValue::int_() 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/ExplicitReturnInInit.ql b/python/ql/src/Functions/ExplicitReturnInInit.ql index f1300afbfd0a..25fc799fafae 100644 --- a/python/ql/src/Functions/ExplicitReturnInInit.ql +++ b/python/ql/src/Functions/ExplicitReturnInInit.ql @@ -19,7 +19,9 @@ where exists(Function init | init.isInitMethod() and r.getScope() = init) and r.getValue() = rv and not rv.pointsTo(Value::none_()) and - not exists(FunctionValue f | f.getACall() = rv.getAFlowNode() | f.neverReturns()) and + not exists(FunctionValue f, ControlFlowNode rvCfg | rvCfg.getNode() = rv | + f.getACall() = rvCfg and f.neverReturns() + ) and // to avoid double reporting, don't trigger if returning result from other __init__ function not exists(Attribute meth | meth = rv.(Call).getFunc() | meth.getName() = "__init__") select r, "Explicit return in __init__ method." diff --git a/python/ql/src/Functions/ReturnValueIgnored.ql b/python/ql/src/Functions/ReturnValueIgnored.ql index 3716b989d891..83af6304cb30 100644 --- a/python/ql/src/Functions/ReturnValueIgnored.ql +++ b/python/ql/src/Functions/ReturnValueIgnored.ql @@ -69,7 +69,12 @@ where returns_meaningful_value(callee) and not wrapped_in_try_except(call) and exists(int unused | - unused = count(ExprStmt e | e.getValue().getAFlowNode() = callee.getACall()) and + unused = + count(ExprStmt e | + exists(ControlFlowNode eValCfg | eValCfg.getNode() = e.getValue() | + eValCfg = callee.getACall() + ) + ) and total = count(callee.getACall()) | percentage_used = (100.0 * (total - unused) / total).floor() 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 9d91e4f523c2..c5c4795eeccf 100644 --- a/python/ql/src/Resources/FileNotAlwaysClosedQuery.qll +++ b/python/ql/src/Resources/FileNotAlwaysClosedQuery.qll @@ -3,6 +3,7 @@ import python import semmle.python.dataflow.new.internal.DataFlowDispatch import semmle.python.ApiGraphs +private import semmle.python.controlflow.internal.Cfg as Cfg /** A CFG node where a file is opened. */ abstract class FileOpenSource extends DataFlow::CfgNode { } @@ -64,12 +65,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/Resources/FileOpen.qll b/python/ql/src/Resources/FileOpen.qll index dd952e732d42..1daecb6d0334 100644 --- a/python/ql/src/Resources/FileOpen.qll +++ b/python/ql/src/Resources/FileOpen.qll @@ -138,12 +138,12 @@ predicate function_opens_file(FunctionValue f) { f = Value::named("open") or exists(EssaVariable v, Return ret | ret.getScope() = f.getScope() | - ret.getValue().getAFlowNode() = v.getAUse() and + v.getNode() = ret.getValue().getAUse() and var_is_open(v, _) ) or exists(Return ret, FunctionValue callee | ret.getScope() = f.getScope() | - ret.getValue().getAFlowNode() = callee.getACall() and + callee.getNode() = ret.getValue().getACall() and function_opens_file(callee) ) } 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 1e7b4452a9a6..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 */ @@ -94,9 +95,9 @@ class CredentialSink extends DataFlow::Node { this.(DataFlow::ArgumentNode).argumentOf(_, pos) ) or - exists(Keyword k | k.getArg() = name and k.getValue().getAFlowNode() = this.asCfgNode()) + 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/IterableStringOrSequence.ql b/python/ql/src/Statements/IterableStringOrSequence.ql index d1c4a507f0d1..ad8b6beab290 100644 --- a/python/ql/src/Statements/IterableStringOrSequence.ql +++ b/python/ql/src/Statements/IterableStringOrSequence.ql @@ -25,7 +25,7 @@ from For loop, ControlFlowNodeWithPointsTo iter, Value str, Value seq, ControlFlowNode seq_origin, ControlFlowNode str_origin where - loop.getIter().getAFlowNode() = iter and + iter.getNode() = loop.getIter() and iter.pointsTo(str, str_origin) and iter.pointsTo(seq, seq_origin) and has_string_type(str) and diff --git a/python/ql/src/Statements/ModificationOfLocals.ql b/python/ql/src/Statements/ModificationOfLocals.ql index f32ddcf78849..29e08f80776c 100644 --- a/python/ql/src/Statements/ModificationOfLocals.ql +++ b/python/ql/src/Statements/ModificationOfLocals.ql @@ -13,24 +13,25 @@ import python private import semmle.python.ApiGraphs +private import semmle.python.controlflow.internal.Cfg as Cfg -predicate originIsLocals(ControlFlowNode n) { +predicate originIsLocals(Cfg::ControlFlowNode n) { API::builtin("locals").getReturn().getAValueReachableFromSource().asCfgNode() = 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/NestedLoopsSameVariableWithReuse.ql b/python/ql/src/Statements/NestedLoopsSameVariableWithReuse.ql index c4deb4e64277..a9c5a5fbbd98 100644 --- a/python/ql/src/Statements/NestedLoopsSameVariableWithReuse.ql +++ b/python/ql/src/Statements/NestedLoopsSameVariableWithReuse.ql @@ -15,7 +15,7 @@ import python predicate loop_variable_ssa(For f, Variable v, SsaVariable s) { - f.getTarget().getAFlowNode() = s.getDefinition() and v = s.getVariable() + s.getDefinition().getNode() = f.getTarget() and v = s.getVariable() } predicate variableUsedInNestedLoops(For inner, For outer, Variable v, Name n) { diff --git a/python/ql/src/Statements/NonIteratorInForLoop.ql b/python/ql/src/Statements/NonIteratorInForLoop.ql index f8e6e51b55ff..b0cbc71130d0 100644 --- a/python/ql/src/Statements/NonIteratorInForLoop.ql +++ b/python/ql/src/Statements/NonIteratorInForLoop.ql @@ -16,7 +16,7 @@ private import LegacyPointsTo from For loop, ControlFlowNodeWithPointsTo iter, Value v, ClassValue t, ControlFlowNode origin where - loop.getIter().getAFlowNode() = iter and + iter.getNode() = loop.getIter() and iter.pointsTo(_, v, origin) and v.getClass() = t and not t.isIterable() and diff --git a/python/ql/src/Statements/SideEffectInAssert.ql b/python/ql/src/Statements/SideEffectInAssert.ql index 7ac96030c04e..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,11 +25,13 @@ predicate func_with_side_effects(Expr e) { } predicate call_with_side_effect(Call e) { - e.getAFlowNode() = - API::moduleImport("subprocess") - .getMember(["call", "check_call", "check_output"]) - .getACall() - .asCfgNode() + exists(Cfg::ControlFlowNode eCfg | eCfg.getNode() = e | + eCfg = + API::moduleImport("subprocess") + .getMember(["call", "check_call", "check_output"]) + .getACall() + .asCfgNode() + ) } predicate probable_side_effect(Expr e) { 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/Variables/Definition.qll b/python/ql/src/Variables/Definition.qll index be8c9490788c..9bd7130957b6 100644 --- a/python/ql/src/Variables/Definition.qll +++ b/python/ql/src/Variables/Definition.qll @@ -133,7 +133,11 @@ class ListComprehensionDeclaration extends ListComp { major_version() = 2 and this.getIterationVariable(_).getId() = result.getId() and result.getScope() = this.getScope() and - this.getAFlowNode().strictlyReaches(result.getAFlowNode()) and + exists(ControlFlowNode thisCfg, ControlFlowNode resultCfg | + thisCfg.getNode() = this and resultCfg.getNode() = result + | + thisCfg.strictlyReaches(resultCfg) + ) and result.isUse() } diff --git a/python/ql/src/Variables/LeakingListComprehension.ql b/python/ql/src/Variables/LeakingListComprehension.ql index 9b98fb43a313..a9baa21661da 100644 --- a/python/ql/src/Variables/LeakingListComprehension.ql +++ b/python/ql/src/Variables/LeakingListComprehension.ql @@ -13,18 +13,21 @@ import python import Definition -from ListComprehensionDeclaration l, Name use, Name defn +from + ListComprehensionDeclaration l, Name use, Name defn, ControlFlowNode lCfg, ControlFlowNode useCfg where use = l.getALeakedVariableUse() and defn = l.getDefinition() and - l.getAFlowNode().strictlyReaches(use.getAFlowNode()) and + lCfg.getNode() = l and + useCfg.getNode() = use and + lCfg.strictlyReaches(useCfg) and /* Make sure we aren't in a loop, as the variable may be redefined */ - not use.getAFlowNode().strictlyReaches(l.getAFlowNode()) and + not useCfg.strictlyReaches(lCfg) and not l.contains(use) and not use.deletes(_) and not exists(SsaVariable v | - v.getAUse() = use.getAFlowNode() and - not v.getDefinition().strictlyDominates(l.getAFlowNode()) + v.getAUse() = useCfg and + not v.getDefinition().strictlyDominates(lCfg) ) select use, use.getId() + " may have a different value in Python 3, as the $@ will not be in scope.", defn, diff --git a/python/ql/src/Variables/Loop.qll b/python/ql/src/Variables/Loop.qll index c7749fe476bf..e7c189cac354 100644 --- a/python/ql/src/Variables/Loop.qll +++ b/python/ql/src/Variables/Loop.qll @@ -26,8 +26,11 @@ private Stmt loop_probably_defines(Variable v) { /** Holds if the variable used by `use` is probably defined in a loop */ predicate probably_defined_in_loop(Name use) { - exists(Stmt loop | loop = loop_probably_defines(use.getVariable()) | - loop.getAFlowNode().strictlyReaches(use.getAFlowNode()) + exists(Stmt loop, ControlFlowNode loopCfg, ControlFlowNode useCfg | + loop = loop_probably_defines(use.getVariable()) and + loopCfg.getNode() = loop and + useCfg.getNode() = use and + loopCfg.strictlyReaches(useCfg) ) } diff --git a/python/ql/src/Variables/MultiplyDefined.ql b/python/ql/src/Variables/MultiplyDefined.ql index 3c26ff0b1eb1..ce8b5b316c21 100644 --- a/python/ql/src/Variables/MultiplyDefined.ql +++ b/python/ql/src/Variables/MultiplyDefined.ql @@ -24,8 +24,8 @@ predicate multiply_defined(AstNode asgn1, AstNode asgn2, Variable v) { forex(Definition def, Definition redef | def.getVariable() = v and - def = asgn1.getAFlowNode() and - redef = asgn2.getAFlowNode() + def.getNode() = asgn1 and + redef.getNode() = asgn2 | def.isUnused() and def.getARedef() = redef and diff --git a/python/ql/src/Variables/SuspiciousUnusedLoopIterationVariable.ql b/python/ql/src/Variables/SuspiciousUnusedLoopIterationVariable.ql index d252742d67c2..f74fd4970ee4 100644 --- a/python/ql/src/Variables/SuspiciousUnusedLoopIterationVariable.ql +++ b/python/ql/src/Variables/SuspiciousUnusedLoopIterationVariable.ql @@ -88,7 +88,9 @@ predicate implicit_repeat(For f) { * E.g. gets `x` from `{ y for y in x }`. */ ControlFlowNode get_comp_iterable(For f) { - exists(Comp c | c.getFunction().getStmt(0) = f | c.getAFlowNode().getAPredecessor() = result) + exists(Comp c, ControlFlowNode cCfg | + c.getFunction().getStmt(0) = f and cCfg.getNode() = c and cCfg.getAPredecessor() = result + ) } from For f, Variable v, string msg diff --git a/python/ql/src/Variables/Undefined.qll b/python/ql/src/Variables/Undefined.qll index 42437a81340b..b320c2040b2d 100644 --- a/python/ql/src/Variables/Undefined.qll +++ b/python/ql/src/Variables/Undefined.qll @@ -19,9 +19,10 @@ private predicate loop_entry_variables(EssaVariable pred, EssaVariable succ) { private predicate loop_entry_edge(BasicBlock pred, BasicBlock loop) { pred = loop.getAPredecessor() and pred = loop.getImmediateDominator() and - exists(Stmt s | + exists(Stmt s, ControlFlowNode sCfg | loop_probably_executes_at_least_once(s) and - s.getAFlowNode().getBasicBlock() = loop + sCfg.getNode() = s and + sCfg.getBasicBlock() = loop ) } diff --git a/python/ql/src/Variables/UndefinedGlobal.ql b/python/ql/src/Variables/UndefinedGlobal.ql index 404ac64aa5a0..0c54b444ce30 100644 --- a/python/ql/src/Variables/UndefinedGlobal.ql +++ b/python/ql/src/Variables/UndefinedGlobal.ql @@ -27,7 +27,7 @@ predicate guarded_against_name_error(Name u) { | globals.getFunc().(Name).getId() = "globals" and guard.controls(controlled, _) and - controlled.contains(u.getAFlowNode()) + exists(ControlFlowNode uCfg | uCfg.getNode() = u | controlled.contains(uCfg)) ) } @@ -101,18 +101,18 @@ predicate undefined_use(Name u) { } private predicate first_use_in_a_block(Name use) { - exists(GlobalVariable v, BasicBlock b, int i | - i = min(int j | b.getNode(j).getNode() = v.getALoad()) and b.getNode(i) = use.getAFlowNode() + exists(GlobalVariable v, BasicBlock b, int i, ControlFlowNode useCfg | useCfg.getNode() = use | + i = min(int j | b.getNode(j).getNode() = v.getALoad()) and b.getNode(i) = useCfg ) } predicate first_undefined_use(Name use) { undefined_use(use) and - exists(GlobalVariable v | v.getALoad() = use | + exists(GlobalVariable v, ControlFlowNode useCfg | v.getALoad() = use and useCfg.getNode() = use | first_use_in_a_block(use) and not exists(ControlFlowNode other | other.getNode() = v.getALoad() and - other.getBasicBlock().strictlyDominates(use.getAFlowNode().getBasicBlock()) + other.getBasicBlock().strictlyDominates(useCfg.getBasicBlock()) ) ) } diff --git a/python/ql/src/Variables/UndefinedPlaceHolder.ql b/python/ql/src/Variables/UndefinedPlaceHolder.ql index 29f9b3a1a510..9fa0cc7eaaae 100644 --- a/python/ql/src/Variables/UndefinedPlaceHolder.ql +++ b/python/ql/src/Variables/UndefinedPlaceHolder.ql @@ -18,8 +18,8 @@ private import semmle.python.types.ImportTime /* Local variable part */ predicate initialized_as_local(PlaceHolder use) { - exists(SsaVariableWithPointsTo l, Function f | - f = use.getScope() and l.getAUse() = use.getAFlowNode() + exists(SsaVariableWithPointsTo l, Function f, ControlFlowNode useCfg | + f = use.getScope() and useCfg.getNode() = use and l.getAUse() = useCfg | l.getVariable() instanceof LocalVariable and not l.maybeUndefined() diff --git a/python/ql/src/Variables/UnusedModuleVariable.ql b/python/ql/src/Variables/UnusedModuleVariable.ql index 24d6559d6fea..0443c3388c85 100644 --- a/python/ql/src/Variables/UnusedModuleVariable.ql +++ b/python/ql/src/Variables/UnusedModuleVariable.ql @@ -54,7 +54,7 @@ predicate unused_global(Name unused, GlobalVariable v) { u.uses(v) | // That is reachable from this definition, directly - defn.strictlyReaches(u.getAFlowNode()) + exists(ControlFlowNode uCfg | uCfg.getNode() = u | defn.strictlyReaches(uCfg)) or // indirectly defn.getBasicBlock().reachesExit() and u.getScope() != unused.getScope() diff --git a/python/ql/src/analysis/CrossProjectDefinitions.qll b/python/ql/src/analysis/CrossProjectDefinitions.qll index 64b30f566f15..61e12a09ec6b 100644 --- a/python/ql/src/analysis/CrossProjectDefinitions.qll +++ b/python/ql/src/analysis/CrossProjectDefinitions.qll @@ -48,15 +48,17 @@ class Symbol extends TSymbol { AstNode find() { this = TModule(result) or - exists(Symbol s, string name | this = TMember(s, name) | + exists(Symbol s, string name, ControlFlowNode resultCfg | + this = TMember(s, name) and resultCfg.getNode() = result + | exists(ClassObject cls | s.resolvesTo() = cls and - cls.attributeRefersTo(name, _, result.getAFlowNode()) + cls.attributeRefersTo(name, _, resultCfg) ) or exists(ModuleObject m | s.resolvesTo() = m and - m.attributeRefersTo(name, _, result.getAFlowNode()) + m.attributeRefersTo(name, _, resultCfg) ) ) } diff --git a/python/ql/src/analysis/ImportFailure.ql b/python/ql/src/analysis/ImportFailure.ql index 71967e6e04f7..760a3693d6ea 100644 --- a/python/ql/src/analysis/ImportFailure.ql +++ b/python/ql/src/analysis/ImportFailure.ql @@ -80,10 +80,11 @@ class VersionGuard extends ConditionBlock { VersionGuard() { this.getLastNode() instanceof VersionTest } } -from ImportExpr ie +from ImportExpr ie, ControlFlowNode ieCfg where + ieCfg.getNode() = ie and not ie.(ExprWithPointsTo).refersTo(_) and - exists(Context c | c.appliesTo(ie.getAFlowNode())) and + exists(Context c | c.appliesTo(ieCfg)) and not ok_to_fail(ie) and - not exists(VersionGuard guard | guard.controls(ie.getAFlowNode().getBasicBlock(), _)) + not exists(VersionGuard guard | guard.controls(ieCfg.getBasicBlock(), _)) select ie, "Unable to resolve import of '" + ie.getImportedModuleName() + "'." diff --git a/python/ql/src/analysis/KeyPointsToFailure.ql b/python/ql/src/analysis/KeyPointsToFailure.ql index f07e8638f385..e42e5ac0bdd4 100644 --- a/python/ql/src/analysis/KeyPointsToFailure.ql +++ b/python/ql/src/analysis/KeyPointsToFailure.ql @@ -11,13 +11,13 @@ import python import semmle.python.pointsto.PointsTo predicate points_to_failure(Expr e) { - exists(ControlFlowNode f | f = e.getAFlowNode() | not PointsTo::pointsTo(f, _, _, _)) + exists(ControlFlowNode f | f.getNode() = e | not PointsTo::pointsTo(f, _, _, _)) } predicate key_points_to_failure(Expr e) { points_to_failure(e) and not points_to_failure(e.getASubExpression()) and - not exists(SsaVariable ssa | ssa.getAUse() = e.getAFlowNode() | + not exists(SsaVariable ssa, ControlFlowNode eCfg | eCfg.getNode() = e and ssa.getAUse() = eCfg | points_to_failure(ssa.getAnUltimateDefinition().getDefinition().getNode()) ) and not exists(Assign a | a.getATarget() = e) diff --git a/python/ql/src/analysis/PointsToFailure.ql b/python/ql/src/analysis/PointsToFailure.ql index fee1e80d2f77..8d46cbd90952 100644 --- a/python/ql/src/analysis/PointsToFailure.ql +++ b/python/ql/src/analysis/PointsToFailure.ql @@ -12,5 +12,5 @@ import python private import LegacyPointsTo from Expr e -where exists(ControlFlowNodeWithPointsTo f | f = e.getAFlowNode() | not f.refersTo(_)) +where exists(ControlFlowNodeWithPointsTo f | f.getNode() = e | not f.refersTo(_)) select e, "Expression does not 'point-to' any object." 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 c7aef20c09dd..d4cdc388b14f 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,13 +126,13 @@ 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 | a.getTarget().getAFlowNode() = this.asCfgNode()) + exists(AugAssign a | this.asCfgNode().getNode() = a.getTarget()) or // modifying function call exists(DataFlow::CallCfgNode c, DataFlow::AttrRead a | c.getFunction() = a | @@ -141,54 +142,33 @@ 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`. + * Holds if `g` validates `node` as truthy when evaluating to `branch`. * - * 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) - * ``` + * The new shared CFG's `GuardNode`/`outcomeOfGuard` already unwraps + * `not x` wrappers, so we only need the direct case: a guard `g` + * controls a block where the guarded value (also `g`) is known to + * have the matching truthiness for the taken branch. */ - 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 truthinessGuard(DataFlow::GuardNode g, Cfg::ControlFlowNode node, boolean branch) { + node = g and branch in [true, 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() and + // truthy = true branch + exists(DataFlow::GuardNode g | g.controlsBlock(this.asCfgNode().getBasicBlock(), true)) + } } /** Simple guard detecting falsey values. */ - private class MustBeFalsey extends MustBe, MustBeEmpty { - MustBeFalsey() { truthy = false } + private class MustBeFalsey extends MustBeEmpty { + MustBeFalsey() { + this = DataFlow::BarrierGuard::getABarrierNode() and + // truthy = false branch + exists(DataFlow::GuardNode g | g.controlsBlock(this.asCfgNode().getBasicBlock(), false)) + } } } diff --git a/python/ql/test/2/library-tests/comprehensions/ConsistencyCheck.ql b/python/ql/test/2/library-tests/comprehensions/ConsistencyCheck.ql index 2f5191fb5475..c1a214e40c75 100644 --- a/python/ql/test/2/library-tests/comprehensions/ConsistencyCheck.ql +++ b/python/ql/test/2/library-tests/comprehensions/ConsistencyCheck.ql @@ -5,5 +5,7 @@ import python select count(Comprehension c | - count(c.toString()) != 1 or count(c.getLocation()) != 1 or not exists(c.getAFlowNode()) + count(c.toString()) != 1 or + count(c.getLocation()) != 1 or + not exists(ControlFlowNode n | n.getNode() = c) ) 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 a3e20123fc7c..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,13 +46,15 @@ private class VersionGuardedNode extends DataFlow::Node { VersionGuardedNode() { version in [2, 3] and - exists(If parent, CompareNode c | parent.getBody().contains(this.asExpr()) | + exists(If parent, Cfg::CompareNode c, Cfg::ControlFlowNode litCfg | + parent.getBody().contains(this.asExpr()) and + litCfg.getNode() = any(IntegerLiteral lit | lit.getValue() = version) + | c.operands(API::moduleImport("sys") .getMember("version_info") .getASubscript() .asSource() - .asCfgNode(), any(Eq eq), - any(IntegerLiteral lit | lit.getValue() = version).getAFlowNode()) + .asCfgNode(), any(Eq eq), litCfg) ) } 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..f1901813e7cd 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,8 @@ 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 | +| type_annotations.py:29:5:29:14 | Attribute() | Fixed 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/InlineCallGraphTest.expected b/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.expected index b353309e852f..5d0c9750bb31 100644 --- a/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.expected +++ b/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.expected @@ -1,54 +1,54 @@ testFailures +| code/conditional_in_argument.py:18:5:18:11 | Attribute() | Fixed missing result: tt=X.bar | +| code/funky_regression.py:15:9:15:17 | Attribute() | Fixed missing result: tt=Wat.f2 | debug_callableNotUnique pointsTo_found_typeTracker_notFound -| code/class_attr_assign.py:10:9:10:27 | ControlFlowNode for Attribute() | my_func | -| code/class_attr_assign.py:11:9:11:25 | ControlFlowNode for Attribute() | my_func | -| code/class_attr_assign.py:26:9:26:25 | ControlFlowNode for Attribute() | DummyObject.method | -| 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/FindSubclass/Find.expected b/python/ql/test/experimental/library-tests/FindSubclass/Find.expected index c08e282981ca..ecf027797e8a 100644 --- a/python/ql/test/experimental/library-tests/FindSubclass/Find.expected +++ b/python/ql/test/experimental/library-tests/FindSubclass/Find.expected @@ -4,7 +4,6 @@ | flask.MethodView~Subclass | find_subclass_test | Member[C] | | flask.View~Subclass | find_subclass_test | Member[A] | | flask.View~Subclass | find_subclass_test | Member[B] | -| flask.View~Subclass | find_subclass_test | Member[ViewAliasInExcept] | | flask.View~Subclass | find_subclass_test | Member[ViewAliasInTry] | | flask.View~Subclass | find_subclass_test | Member[ViewAlias] | | flask.View~Subclass | find_subclass_test | Member[ViewAlias_no_use] | 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 97527c300db5..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,235 +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:19:20:24 | ControlFlowNode for member | TarSlipImprov.py:20:5:20:10 | [post] ControlFlowNode for result | 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:23:35:28 | ControlFlowNode for member | TarSlipImprov.py:35:9:35:14 | [post] ControlFlowNode for result | 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:13:152:20 | ControlFlowNode for Yield | provenance | | -| 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 | TarSlipImprov.py:157:18:157:40 | ControlFlowNode for py2_tarxz() | 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:18:157:40 | ControlFlowNode for py2_tarxz() | TarSlipImprov.py:157:9:157:14 | ControlFlowNode for tar_cm | 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: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:28:235:28 | ControlFlowNode for f | TarSlipImprov.py:235:13:235:19 | [post] ControlFlowNode for members | 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:19:309:24 | ControlFlowNode for member | TarSlipImprov.py:309:5:309:10 | [post] ControlFlowNode for result | 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: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: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: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 | semmle.label | ControlFlowNode for Yield | -| 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:18:157:40 | ControlFlowNode for py2_tarxz() | semmle.label | ControlFlowNode for py2_tarxz() | -| 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: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: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: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 | 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 de8721382bf3..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,206 +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:37:166:42 | ControlFlowNode for member | UnsafeUnpack.py:166:23:166:28 | [post] ControlFlowNode for result | 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: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 914d6fbbee45..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,88 +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:41:23:57 | ControlFlowNode for List | provenance | | -| Netmiko.py:18:16:18:18 | ControlFlowNode for cmd | Netmiko.py:24:48:24:50 | ControlFlowNode for cmd | 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: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 64b10ac564de..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,120 +1,120 @@ 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 | 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 | 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 | 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 | 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 | 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:5:45:15 | ControlFlowNode for xsltStrings | 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 | xsltInjection.py:46:38:46:48 | ControlFlowNode for xsltStrings | 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 | xsltInjection.py:46:17:46:49 | ControlFlowNode for Attribute() | provenance | Config | -| xsltInjection.py:46:38:46:48 | ControlFlowNode for xsltStrings | xsltInjection.py:46:17:46:49 | ControlFlowNode for Attribute() | provenance | Decoding-XML | +| 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 | semmle.label | ControlFlowNode for xsltStrings | -| 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 | semmle.label | ControlFlowNode for xsltStrings | -| 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 | 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 | +| 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 5152f7353f25..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 @@ 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 | 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 | +| 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 6acb03ce7f51..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,87 +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: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: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:23:15:37:9 | ControlFlowNode for List | provenance | Sink:MaD:9 | -| 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:23:15:37:9 | ControlFlowNode for List | 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: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 | | +| 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 | @@ -95,60 +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:26:28:26:51 | ControlFlowNode for BinaryExpr | semmle.label | ControlFlowNode for BinaryExpr | -| 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 1577182b2dcd..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 @@ 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 | 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 | +| 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 097e3580fb1d..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 @@ 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 | 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 | +| 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/PointsToSupport/UseFromDefinition.ql b/python/ql/test/library-tests/ControlFlow/PointsToSupport/UseFromDefinition.ql index 8b52244478f1..6173331a2dd1 100644 --- a/python/ql/test/library-tests/ControlFlow/PointsToSupport/UseFromDefinition.ql +++ b/python/ql/test/library-tests/ControlFlow/PointsToSupport/UseFromDefinition.ql @@ -9,7 +9,7 @@ Expr assignedValue(Name n) { from Name def, DefinitionNode d where - d = def.getAFlowNode() and + d.getNode() = def and exists(assignedValue(def)) and not d.getValue().getNode() = assignedValue(def) select def.toString(), assignedValue(def) 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..dbfb857b5360 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/bindings/dead_under_no_raise.py @@ -0,0 +1,52 @@ +# Dead bindings under the "no expressions raise" CFG abstraction. +# +# The new CFG does not currently model raise edges from arbitrary +# expressions. As a consequence, code that is only reachable through +# exception flow is (correctly) classified as dead and has no CFG node. +# Variable bindings in dead code do not need CFG nodes - SSA / dataflow +# over dead code is moot. +# +# These tests act as a regression guard: the bindings below intentionally +# have no `cfgdefines=` annotations. If raise modelling is later added, +# the BindingsTest infrastructure will surface the new CFG nodes as +# unexpected results, and this file will need to be revisited. + + +def f(obj): # $ cfgdefines=f cfgdefines=obj + try: + return len(obj) + except TypeError: + pass + + # The first try's body always returns; its except handler does not + # raise or otherwise transfer control, so under "no expressions + # raise" the only paths out of the try-statement are dead. Everything + # below is unreachable. + try: + hint = type(obj).__length_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, 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`: dead under "no expressions raise". + value = compute(key) + 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..80fa3350282f 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 | @@ -11,4 +11,3 @@ | test_boolean.py:64:10:64:52 | ControlFlowNode for BoolExpr | Basic block ordering: $@ appears before $@ | test_boolean.py:64:59:64:59 | IntegerLiteral | timestamp 6 | test_boolean.py:64:27:64:27 | IntegerLiteral | timestamp 2 | | test_boolean.py:76:10:76:51 | ControlFlowNode for BoolExpr | Basic block ordering: $@ appears before $@ | test_boolean.py:76:58:76:58 | IntegerLiteral | timestamp 6 | test_boolean.py:76:17:76:17 | IntegerLiteral | timestamp 0 | | test_boolean.py:76:10:76:51 | ControlFlowNode for BoolExpr | Basic block ordering: $@ appears before $@ | test_boolean.py:76:58:76:58 | IntegerLiteral | timestamp 6 | test_boolean.py:76:27:76:27 | IntegerLiteral | timestamp 2 | -| test_if.py:96:9:96:29 | ControlFlowNode for BoolExpr | Basic block ordering: $@ appears before $@ | test_if.py:96:36:96:36 | IntegerLiteral | timestamp 4 | test_if.py:96:15:96:15 | IntegerLiteral | timestamp 2 | 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.expected b/python/ql/test/library-tests/ControlFlow/evaluation-order/ConsecutiveTimestamps.expected index ed22c971ecbc..e8071c044213 100644 --- a/python/ql/test/library-tests/ControlFlow/evaluation-order/ConsecutiveTimestamps.expected +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/ConsecutiveTimestamps.expected @@ -7,6 +7,3 @@ | test_boolean.py:52:11:52:47 | BoolExpr | $@ in $@ has no consecutive successor (expected 3) | test_boolean.py:52:63:52:63 | IntegerLiteral | Timestamp 2 | test_boolean.py:50:1:50:25 | Function test_mixed_and_or | test_mixed_and_or | | test_boolean.py:52:27:52:31 | False | $@ in $@ has no consecutive successor (expected 2) | test_boolean.py:52:37:52:37 | IntegerLiteral | Timestamp 1 | test_boolean.py:50:1:50:25 | Function test_mixed_and_or | test_mixed_and_or | | test_boolean.py:52:78:52:79 | IntegerLiteral | $@ in $@ has no consecutive successor (expected 4) | test_boolean.py:52:85:52:85 | IntegerLiteral | Timestamp 3 | test_boolean.py:50:1:50:25 | Function test_mixed_and_or | test_mixed_and_or | -| test_if.py:95:9:95:13 | False | $@ in $@ has no consecutive successor (expected 2) | test_if.py:95:19:95:19 | IntegerLiteral | Timestamp 1 | test_if.py:93:1:93:34 | Function test_if_compound_condition | test_if_compound_condition | -| test_if.py:96:9:96:29 | BoolExpr | $@ in $@ has no consecutive successor (expected 5) | test_if.py:96:36:96:36 | IntegerLiteral | Timestamp 4 | test_if.py:93:1:93:34 | Function test_if_compound_condition | test_if_compound_condition | -| test_if.py:96:22:96:22 | y | $@ in $@ has no consecutive successor (expected 4) | test_if.py:96:28:96:28 | IntegerLiteral | Timestamp 3 | test_if.py:93:1:93:34 | Function test_if_compound_condition | test_if_compound_condition | 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..89a93f41a01b --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgBranchTimestamps.expected @@ -0,0 +1,276 @@ +| test_assert_raise.py:51:20:51:53 | After BinaryExpr() | Timestamp 3 on true/false branch is missing a dead() annotation on the false successor in $@ | test_assert_raise.py:48:1:48:25 | Function test_bare_reraise | test_bare_reraise | +| test_assert_raise.py:51:20:51:53 | After BinaryExpr() | Timestamp 3 on true/false branch is missing a dead() annotation on the true successor in $@ | test_assert_raise.py:48:1:48:25 | Function test_bare_reraise | test_bare_reraise | +| test_assert_raise.py:51:20:51:53 | After BinaryExpr() | Timestamp 4 on true/false branch is missing a dead() annotation on the false successor in $@ | test_assert_raise.py:48:1:48:25 | Function test_bare_reraise | test_bare_reraise | +| test_assert_raise.py:51:20:51:53 | After BinaryExpr() | Timestamp 4 on true/false branch is missing a dead() annotation on the true successor in $@ | test_assert_raise.py:48:1:48:25 | Function test_bare_reraise | test_bare_reraise | +| test_loops.py:10:12:10:52 | After Compare | Timestamp 4 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:8:1:8:23 | Function test_while_loop | test_while_loop | +| test_loops.py:10:12:10:52 | After Compare | Timestamp 4 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:8:1:8:23 | Function test_while_loop | test_while_loop | +| test_loops.py:10:12:10:52 | After Compare | Timestamp 10 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:8:1:8:23 | Function test_while_loop | test_while_loop | +| test_loops.py:10:12:10:52 | After Compare | Timestamp 10 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:8:1:8:23 | Function test_while_loop | test_while_loop | +| test_loops.py:10:12:10:52 | After Compare | Timestamp 16 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:8:1:8:23 | Function test_while_loop | test_while_loop | +| test_loops.py:10:12:10:52 | After Compare | Timestamp 16 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:8:1:8:23 | Function test_while_loop | test_while_loop | +| test_loops.py:10:12:10:52 | After Compare | Timestamp 22 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:8:1:8:23 | Function test_while_loop | test_while_loop | +| test_loops.py:10:12:10:52 | After Compare | Timestamp 22 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:8:1:8:23 | Function test_while_loop | test_while_loop | +| test_loops.py:19:12:19:46 | After Compare | Timestamp 4 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:17:1:17:24 | Function test_while_break | test_while_break | +| test_loops.py:19:12:19:46 | After Compare | Timestamp 4 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:17:1:17:24 | Function test_while_break | test_while_break | +| test_loops.py:19:12:19:46 | After Compare | Timestamp 13 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:17:1:17:24 | Function test_while_break | test_while_break | +| test_loops.py:19:12:19:46 | After Compare | Timestamp 13 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:17:1:17:24 | Function test_while_break | test_while_break | +| test_loops.py:19:12:19:46 | After Compare | Timestamp 22 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:17:1:17:24 | Function test_while_break | test_while_break | +| test_loops.py:19:12:19:46 | After Compare | Timestamp 22 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:17:1:17:24 | Function test_while_break | test_while_break | +| test_loops.py:19:12:19:46 | After Compare | Timestamp 25 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:17:1:17:24 | Function test_while_break | test_while_break | +| test_loops.py:19:12:19:46 | After Compare | Timestamp 25 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:17:1:17:24 | Function test_while_break | test_while_break | +| test_loops.py:20:13:20:48 | After Compare | Timestamp 7 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:17:1:17:24 | Function test_while_break | test_while_break | +| test_loops.py:20:13:20:48 | After Compare | Timestamp 7 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:17:1:17:24 | Function test_while_break | test_while_break | +| test_loops.py:20:13:20:48 | After Compare | Timestamp 16 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:17:1:17:24 | Function test_while_break | test_while_break | +| test_loops.py:20:13:20:48 | After Compare | Timestamp 16 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:17:1:17:24 | Function test_while_break | test_while_break | +| test_loops.py:20:13:20:48 | After Compare | Timestamp 25 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:17:1:17:24 | Function test_while_break | test_while_break | +| test_loops.py:20:13:20:48 | After Compare | Timestamp 25 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:17:1:17:24 | Function test_while_break | test_while_break | +| test_loops.py:31:12:31:54 | After Compare | Timestamp 5 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:28:1:28:27 | Function test_while_continue | test_while_continue | +| test_loops.py:31:12:31:54 | After Compare | Timestamp 5 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:28:1:28:27 | Function test_while_continue | test_while_continue | +| test_loops.py:31:12:31:54 | After Compare | Timestamp 17 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:28:1:28:27 | Function test_while_continue | test_while_continue | +| test_loops.py:31:12:31:54 | After Compare | Timestamp 17 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:28:1:28:27 | Function test_while_continue | test_while_continue | +| test_loops.py:31:12:31:54 | After Compare | Timestamp 26 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:28:1:28:27 | Function test_while_continue | test_while_continue | +| test_loops.py:31:12:31:54 | After Compare | Timestamp 26 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:28:1:28:27 | Function test_while_continue | test_while_continue | +| test_loops.py:31:12:31:54 | After Compare | Timestamp 38 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:28:1:28:27 | Function test_while_continue | test_while_continue | +| test_loops.py:31:12:31:54 | After Compare | Timestamp 38 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:28:1:28:27 | Function test_while_continue | test_while_continue | +| test_loops.py:33:13:33:48 | After Compare | Timestamp 2 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:28:1:28:27 | Function test_while_continue | test_while_continue | +| test_loops.py:33:13:33:48 | After Compare | Timestamp 2 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:28:1:28:27 | Function test_while_continue | test_while_continue | +| test_loops.py:33:13:33:48 | After Compare | Timestamp 11 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:28:1:28:27 | Function test_while_continue | test_while_continue | +| test_loops.py:33:13:33:48 | After Compare | Timestamp 11 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:28:1:28:27 | Function test_while_continue | test_while_continue | +| test_loops.py:33:13:33:48 | After Compare | Timestamp 14 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:28:1:28:27 | Function test_while_continue | test_while_continue | +| test_loops.py:33:13:33:48 | After Compare | Timestamp 14 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:28:1:28:27 | Function test_while_continue | test_while_continue | +| test_loops.py:33:13:33:48 | After Compare | Timestamp 23 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:28:1:28:27 | Function test_while_continue | test_while_continue | +| test_loops.py:33:13:33:48 | After Compare | Timestamp 23 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:28:1:28:27 | Function test_while_continue | test_while_continue | +| test_loops.py:33:13:33:48 | After Compare | Timestamp 32 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:28:1:28:27 | Function test_while_continue | test_while_continue | +| test_loops.py:33:13:33:48 | After Compare | Timestamp 32 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:28:1:28:27 | Function test_while_continue | test_while_continue | +| test_loops.py:33:13:33:48 | After Compare | Timestamp 35 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:28:1:28:27 | Function test_while_continue | test_while_continue | +| test_loops.py:33:13:33:48 | After Compare | Timestamp 35 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:28:1:28:27 | Function test_while_continue | test_while_continue | +| test_loops.py:43:12:43:44 | After Compare | Timestamp 4 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:41:1:41:23 | Function test_while_else | test_while_else | +| test_loops.py:43:12:43:44 | After Compare | Timestamp 4 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:41:1:41:23 | Function test_while_else | test_while_else | +| test_loops.py:43:12:43:44 | After Compare | Timestamp 10 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:41:1:41:23 | Function test_while_else | test_while_else | +| test_loops.py:43:12:43:44 | After Compare | Timestamp 10 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:41:1:41:23 | Function test_while_else | test_while_else | +| test_loops.py:43:12:43:44 | After Compare | Timestamp 16 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:41:1:41:23 | Function test_while_else | test_while_else | +| test_loops.py:43:12:43:44 | After Compare | Timestamp 16 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:41:1:41:23 | Function test_while_else | test_while_else | +| test_loops.py:53:12:53:38 | After Compare | Timestamp 4 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:51:1:51:29 | Function test_while_else_break | test_while_else_break | +| test_loops.py:53:12:53:38 | After Compare | Timestamp 4 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:51:1:51:29 | Function test_while_else_break | test_while_else_break | +| test_loops.py:53:12:53:38 | After Compare | Timestamp 13 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:51:1:51:29 | Function test_while_else_break | test_while_else_break | +| test_loops.py:53:12:53:38 | After Compare | Timestamp 13 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:51:1:51:29 | Function test_while_else_break | test_while_else_break | +| test_loops.py:54:13:54:40 | After Compare | Timestamp 7 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:51:1:51:29 | Function test_while_else_break | test_while_else_break | +| test_loops.py:54:13:54:40 | After Compare | Timestamp 7 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:51:1:51:29 | Function test_while_else_break | test_while_else_break | +| test_loops.py:54:13:54:40 | After Compare | Timestamp 16 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:51:1:51:29 | Function test_while_else_break | test_while_else_break | +| test_loops.py:54:13:54:40 | After Compare | Timestamp 16 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:51:1:51:29 | Function test_while_else_break | test_while_else_break | +| test_loops.py:65:14:65:43 | After List | Timestamp 4 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:64:1:64:21 | Function test_for_list | test_for_list | +| test_loops.py:65:14:65:43 | After List | Timestamp 4 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:64:1:64:21 | Function test_for_list | test_for_list | +| test_loops.py:65:14:65:43 | After List | Timestamp 5 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:64:1:64:21 | Function test_for_list | test_for_list | +| test_loops.py:65:14:65:43 | After List | Timestamp 5 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:64:1:64:21 | Function test_for_list | test_for_list | +| test_loops.py:65:14:65:43 | After List | Timestamp 6 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:64:1:64:21 | Function test_for_list | test_for_list | +| test_loops.py:65:14:65:43 | After List | Timestamp 6 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:64:1:64:21 | Function test_for_list | test_for_list | +| test_loops.py:65:14:65:43 | After List | Timestamp 7 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:64:1:64:21 | Function test_for_list | test_for_list | +| test_loops.py:65:14:65:43 | After List | Timestamp 7 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:64:1:64:21 | Function test_for_list | test_for_list | +| test_loops.py:66:9:66:9 | x | Timestamp 4 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:64:1:64:21 | Function test_for_list | test_for_list | +| test_loops.py:66:9:66:9 | x | Timestamp 4 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:64:1:64:21 | Function test_for_list | test_for_list | +| test_loops.py:66:9:66:9 | x | Timestamp 5 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:64:1:64:21 | Function test_for_list | test_for_list | +| test_loops.py:66:9:66:9 | x | Timestamp 5 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:64:1:64:21 | Function test_for_list | test_for_list | +| test_loops.py:66:9:66:9 | x | Timestamp 6 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:64:1:64:21 | Function test_for_list | test_for_list | +| test_loops.py:66:9:66:9 | x | Timestamp 6 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:64:1:64:21 | Function test_for_list | test_for_list | +| test_loops.py:66:9:66:9 | x | Timestamp 7 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:64:1:64:21 | Function test_for_list | test_for_list | +| test_loops.py:66:9:66:9 | x | Timestamp 7 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:64:1:64:21 | Function test_for_list | test_for_list | +| test_loops.py:73:14:73:37 | After BinaryExpr() | Timestamp 3 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:72:1:72:22 | Function test_for_range | test_for_range | +| test_loops.py:73:14:73:37 | After BinaryExpr() | Timestamp 3 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:72:1:72:22 | Function test_for_range | test_for_range | +| test_loops.py:73:14:73:37 | After BinaryExpr() | Timestamp 4 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:72:1:72:22 | Function test_for_range | test_for_range | +| test_loops.py:73:14:73:37 | After BinaryExpr() | Timestamp 4 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:72:1:72:22 | Function test_for_range | test_for_range | +| test_loops.py:73:14:73:37 | After BinaryExpr() | Timestamp 5 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:72:1:72:22 | Function test_for_range | test_for_range | +| test_loops.py:73:14:73:37 | After BinaryExpr() | Timestamp 5 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:72:1:72:22 | Function test_for_range | test_for_range | +| test_loops.py:73:14:73:37 | After BinaryExpr() | Timestamp 6 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:72:1:72:22 | Function test_for_range | test_for_range | +| test_loops.py:73:14:73:37 | After BinaryExpr() | Timestamp 6 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:72:1:72:22 | Function test_for_range | test_for_range | +| test_loops.py:74:9:74:9 | i | Timestamp 3 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:72:1:72:22 | Function test_for_range | test_for_range | +| test_loops.py:74:9:74:9 | i | Timestamp 3 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:72:1:72:22 | Function test_for_range | test_for_range | +| test_loops.py:74:9:74:9 | i | Timestamp 4 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:72:1:72:22 | Function test_for_range | test_for_range | +| test_loops.py:74:9:74:9 | i | Timestamp 4 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:72:1:72:22 | Function test_for_range | test_for_range | +| test_loops.py:74:9:74:9 | i | Timestamp 5 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:72:1:72:22 | Function test_for_range | test_for_range | +| test_loops.py:74:9:74:9 | i | Timestamp 5 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:72:1:72:22 | Function test_for_range | test_for_range | +| test_loops.py:74:9:74:9 | i | Timestamp 6 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:72:1:72:22 | Function test_for_range | test_for_range | +| test_loops.py:74:9:74:9 | i | Timestamp 6 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:72:1:72:22 | Function test_for_range | test_for_range | +| test_loops.py:81:14:81:53 | After List | Timestamp 5 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:80:1:80:22 | Function test_for_break | test_for_break | +| test_loops.py:81:14:81:53 | After List | Timestamp 5 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:80:1:80:22 | Function test_for_break | test_for_break | +| test_loops.py:81:14:81:53 | After List | Timestamp 9 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:80:1:80:22 | Function test_for_break | test_for_break | +| test_loops.py:81:14:81:53 | After List | Timestamp 9 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:80:1:80:22 | Function test_for_break | test_for_break | +| test_loops.py:81:14:81:53 | After List | Timestamp 13 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:80:1:80:22 | Function test_for_break | test_for_break | +| test_loops.py:81:14:81:53 | After List | Timestamp 13 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:80:1:80:22 | Function test_for_break | test_for_break | +| test_loops.py:81:14:81:53 | After List | Timestamp 16 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:80:1:80:22 | Function test_for_break | test_for_break | +| test_loops.py:81:14:81:53 | After List | Timestamp 16 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:80:1:80:22 | Function test_for_break | test_for_break | +| test_loops.py:82:13:82:47 | After Compare | Timestamp 8 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:80:1:80:22 | Function test_for_break | test_for_break | +| test_loops.py:82:13:82:47 | After Compare | Timestamp 8 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:80:1:80:22 | Function test_for_break | test_for_break | +| test_loops.py:82:13:82:47 | After Compare | Timestamp 12 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:80:1:80:22 | Function test_for_break | test_for_break | +| test_loops.py:82:13:82:47 | After Compare | Timestamp 12 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:80:1:80:22 | Function test_for_break | test_for_break | +| test_loops.py:82:13:82:47 | After Compare | Timestamp 16 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:80:1:80:22 | Function test_for_break | test_for_break | +| test_loops.py:82:13:82:47 | After Compare | Timestamp 16 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:80:1:80:22 | Function test_for_break | test_for_break | +| test_loops.py:84:9:84:9 | x | Timestamp 5 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:80:1:80:22 | Function test_for_break | test_for_break | +| test_loops.py:84:9:84:9 | x | Timestamp 5 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:80:1:80:22 | Function test_for_break | test_for_break | +| test_loops.py:84:9:84:9 | x | Timestamp 9 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:80:1:80:22 | Function test_for_break | test_for_break | +| test_loops.py:84:9:84:9 | x | Timestamp 9 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:80:1:80:22 | Function test_for_break | test_for_break | +| test_loops.py:84:9:84:9 | x | Timestamp 13 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:80:1:80:22 | Function test_for_break | test_for_break | +| test_loops.py:84:9:84:9 | x | Timestamp 13 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:80:1:80:22 | Function test_for_break | test_for_break | +| test_loops.py:84:9:84:9 | x | Timestamp 16 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:80:1:80:22 | Function test_for_break | test_for_break | +| test_loops.py:84:9:84:9 | x | Timestamp 16 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:80:1:80:22 | Function test_for_break | test_for_break | +| test_loops.py:92:14:92:43 | After List | Timestamp 5 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:90:1:90:25 | Function test_for_continue | test_for_continue | +| test_loops.py:92:14:92:43 | After List | Timestamp 5 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:90:1:90:25 | Function test_for_continue | test_for_continue | +| test_loops.py:92:14:92:43 | After List | Timestamp 11 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:90:1:90:25 | Function test_for_continue | test_for_continue | +| test_loops.py:92:14:92:43 | After List | Timestamp 11 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:90:1:90:25 | Function test_for_continue | test_for_continue | +| test_loops.py:92:14:92:43 | After List | Timestamp 14 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:90:1:90:25 | Function test_for_continue | test_for_continue | +| test_loops.py:92:14:92:43 | After List | Timestamp 14 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:90:1:90:25 | Function test_for_continue | test_for_continue | +| test_loops.py:92:14:92:43 | After List | Timestamp 20 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:90:1:90:25 | Function test_for_continue | test_for_continue | +| test_loops.py:92:14:92:43 | After List | Timestamp 20 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:90:1:90:25 | Function test_for_continue | test_for_continue | +| test_loops.py:93:13:93:48 | After Compare | Timestamp 5 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:90:1:90:25 | Function test_for_continue | test_for_continue | +| test_loops.py:93:13:93:48 | After Compare | Timestamp 5 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:90:1:90:25 | Function test_for_continue | test_for_continue | +| test_loops.py:93:13:93:48 | After Compare | Timestamp 8 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:90:1:90:25 | Function test_for_continue | test_for_continue | +| test_loops.py:93:13:93:48 | After Compare | Timestamp 8 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:90:1:90:25 | Function test_for_continue | test_for_continue | +| test_loops.py:93:13:93:48 | After Compare | Timestamp 11 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:90:1:90:25 | Function test_for_continue | test_for_continue | +| test_loops.py:93:13:93:48 | After Compare | Timestamp 11 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:90:1:90:25 | Function test_for_continue | test_for_continue | +| test_loops.py:93:13:93:48 | After Compare | Timestamp 14 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:90:1:90:25 | Function test_for_continue | test_for_continue | +| test_loops.py:93:13:93:48 | After Compare | Timestamp 14 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:90:1:90:25 | Function test_for_continue | test_for_continue | +| test_loops.py:93:13:93:48 | After Compare | Timestamp 17 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:90:1:90:25 | Function test_for_continue | test_for_continue | +| test_loops.py:93:13:93:48 | After Compare | Timestamp 17 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:90:1:90:25 | Function test_for_continue | test_for_continue | +| test_loops.py:93:13:93:48 | After Compare | Timestamp 20 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:90:1:90:25 | Function test_for_continue | test_for_continue | +| test_loops.py:93:13:93:48 | After Compare | Timestamp 20 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:90:1:90:25 | Function test_for_continue | test_for_continue | +| test_loops.py:95:18:95:48 | After BinaryExpr | Timestamp 5 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:90:1:90:25 | Function test_for_continue | test_for_continue | +| test_loops.py:95:18:95:48 | After BinaryExpr | Timestamp 5 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:90:1:90:25 | Function test_for_continue | test_for_continue | +| test_loops.py:95:18:95:48 | After BinaryExpr | Timestamp 11 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:90:1:90:25 | Function test_for_continue | test_for_continue | +| test_loops.py:95:18:95:48 | After BinaryExpr | Timestamp 11 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:90:1:90:25 | Function test_for_continue | test_for_continue | +| test_loops.py:95:18:95:48 | After BinaryExpr | Timestamp 14 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:90:1:90:25 | Function test_for_continue | test_for_continue | +| test_loops.py:95:18:95:48 | After BinaryExpr | Timestamp 14 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:90:1:90:25 | Function test_for_continue | test_for_continue | +| test_loops.py:95:18:95:48 | After BinaryExpr | Timestamp 20 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:90:1:90:25 | Function test_for_continue | test_for_continue | +| test_loops.py:95:18:95:48 | After BinaryExpr | Timestamp 20 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:90:1:90:25 | Function test_for_continue | test_for_continue | +| test_loops.py:102:14:102:33 | After List | Timestamp 3 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:101:1:101:21 | Function test_for_else | test_for_else | +| test_loops.py:102:14:102:33 | After List | Timestamp 3 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:101:1:101:21 | Function test_for_else | test_for_else | +| test_loops.py:102:14:102:33 | After List | Timestamp 4 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:101:1:101:21 | Function test_for_else | test_for_else | +| test_loops.py:102:14:102:33 | After List | Timestamp 4 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:101:1:101:21 | Function test_for_else | test_for_else | +| test_loops.py:102:14:102:33 | After List | Timestamp 5 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:101:1:101:21 | Function test_for_else | test_for_else | +| test_loops.py:102:14:102:33 | After List | Timestamp 5 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:101:1:101:21 | Function test_for_else | test_for_else | +| test_loops.py:103:9:103:9 | x | Timestamp 3 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:101:1:101:21 | Function test_for_else | test_for_else | +| test_loops.py:103:9:103:9 | x | Timestamp 3 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:101:1:101:21 | Function test_for_else | test_for_else | +| test_loops.py:103:9:103:9 | x | Timestamp 4 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:101:1:101:21 | Function test_for_else | test_for_else | +| test_loops.py:103:9:103:9 | x | Timestamp 4 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:101:1:101:21 | Function test_for_else | test_for_else | +| test_loops.py:103:9:103:9 | x | Timestamp 5 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:101:1:101:21 | Function test_for_else | test_for_else | +| test_loops.py:103:9:103:9 | x | Timestamp 5 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:101:1:101:21 | Function test_for_else | test_for_else | +| test_loops.py:111:14:111:43 | After List | Timestamp 4 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:110:1:110:27 | Function test_for_else_break | test_for_else_break | +| test_loops.py:111:14:111:43 | After List | Timestamp 4 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:110:1:110:27 | Function test_for_else_break | test_for_else_break | +| test_loops.py:111:14:111:43 | After List | Timestamp 8 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:110:1:110:27 | Function test_for_else_break | test_for_else_break | +| test_loops.py:111:14:111:43 | After List | Timestamp 8 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:110:1:110:27 | Function test_for_else_break | test_for_else_break | +| test_loops.py:112:13:112:38 | After Compare | Timestamp 7 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:110:1:110:27 | Function test_for_else_break | test_for_else_break | +| test_loops.py:112:13:112:38 | After Compare | Timestamp 7 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:110:1:110:27 | Function test_for_else_break | test_for_else_break | +| test_loops.py:112:13:112:38 | After Compare | Timestamp 11 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:110:1:110:27 | Function test_for_else_break | test_for_else_break | +| test_loops.py:112:13:112:38 | After Compare | Timestamp 11 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:110:1:110:27 | Function test_for_else_break | test_for_else_break | +| test_loops.py:114:9:114:9 | x | Timestamp 4 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:110:1:110:27 | Function test_for_else_break | test_for_else_break | +| test_loops.py:114:9:114:9 | x | Timestamp 4 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:110:1:110:27 | Function test_for_else_break | test_for_else_break | +| test_loops.py:114:9:114:9 | x | Timestamp 8 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:110:1:110:27 | Function test_for_else_break | test_for_else_break | +| test_loops.py:114:9:114:9 | x | Timestamp 8 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:110:1:110:27 | Function test_for_else_break | test_for_else_break | +| test_loops.py:123:14:123:33 | After List | Timestamp 21 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:122:1:122:25 | Function test_nested_loops | test_nested_loops | +| test_loops.py:123:14:123:33 | After List | Timestamp 21 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:122:1:122:25 | Function test_nested_loops | test_nested_loops | +| test_loops.py:124:18:124:47 | After List | Timestamp 3 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:122:1:122:25 | Function test_nested_loops | test_nested_loops | +| test_loops.py:124:18:124:47 | After List | Timestamp 3 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:122:1:122:25 | Function test_nested_loops | test_nested_loops | +| test_loops.py:124:18:124:47 | After List | Timestamp 6 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:122:1:122:25 | Function test_nested_loops | test_nested_loops | +| test_loops.py:124:18:124:47 | After List | Timestamp 6 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:122:1:122:25 | Function test_nested_loops | test_nested_loops | +| test_loops.py:124:18:124:47 | After List | Timestamp 9 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:122:1:122:25 | Function test_nested_loops | test_nested_loops | +| test_loops.py:124:18:124:47 | After List | Timestamp 9 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:122:1:122:25 | Function test_nested_loops | test_nested_loops | +| test_loops.py:124:18:124:47 | After List | Timestamp 12 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:122:1:122:25 | Function test_nested_loops | test_nested_loops | +| test_loops.py:124:18:124:47 | After List | Timestamp 12 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:122:1:122:25 | Function test_nested_loops | test_nested_loops | +| test_loops.py:124:18:124:47 | After List | Timestamp 15 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:122:1:122:25 | Function test_nested_loops | test_nested_loops | +| test_loops.py:124:18:124:47 | After List | Timestamp 15 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:122:1:122:25 | Function test_nested_loops | test_nested_loops | +| test_loops.py:124:18:124:47 | After List | Timestamp 18 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:122:1:122:25 | Function test_nested_loops | test_nested_loops | +| test_loops.py:124:18:124:47 | After List | Timestamp 18 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:122:1:122:25 | Function test_nested_loops | test_nested_loops | +| test_loops.py:124:18:124:47 | After List | Timestamp 21 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:122:1:122:25 | Function test_nested_loops | test_nested_loops | +| test_loops.py:124:18:124:47 | After List | Timestamp 21 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:122:1:122:25 | Function test_nested_loops | test_nested_loops | +| test_loops.py:125:14:125:65 | After BinaryExpr | Timestamp 3 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:122:1:122:25 | Function test_nested_loops | test_nested_loops | +| test_loops.py:125:14:125:65 | After BinaryExpr | Timestamp 3 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:122:1:122:25 | Function test_nested_loops | test_nested_loops | +| test_loops.py:125:14:125:65 | After BinaryExpr | Timestamp 6 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:122:1:122:25 | Function test_nested_loops | test_nested_loops | +| test_loops.py:125:14:125:65 | After BinaryExpr | Timestamp 6 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:122:1:122:25 | Function test_nested_loops | test_nested_loops | +| test_loops.py:125:14:125:65 | After BinaryExpr | Timestamp 9 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:122:1:122:25 | Function test_nested_loops | test_nested_loops | +| test_loops.py:125:14:125:65 | After BinaryExpr | Timestamp 9 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:122:1:122:25 | Function test_nested_loops | test_nested_loops | +| test_loops.py:125:14:125:65 | After BinaryExpr | Timestamp 12 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:122:1:122:25 | Function test_nested_loops | test_nested_loops | +| test_loops.py:125:14:125:65 | After BinaryExpr | Timestamp 12 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:122:1:122:25 | Function test_nested_loops | test_nested_loops | +| test_loops.py:125:14:125:65 | After BinaryExpr | Timestamp 15 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:122:1:122:25 | Function test_nested_loops | test_nested_loops | +| test_loops.py:125:14:125:65 | After BinaryExpr | Timestamp 15 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:122:1:122:25 | Function test_nested_loops | test_nested_loops | +| test_loops.py:125:14:125:65 | After BinaryExpr | Timestamp 18 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:122:1:122:25 | Function test_nested_loops | test_nested_loops | +| test_loops.py:125:14:125:65 | After BinaryExpr | Timestamp 18 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:122:1:122:25 | Function test_nested_loops | test_nested_loops | +| test_loops.py:125:14:125:65 | After BinaryExpr | Timestamp 21 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:122:1:122:25 | Function test_nested_loops | test_nested_loops | +| test_loops.py:125:14:125:65 | After BinaryExpr | Timestamp 21 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:122:1:122:25 | Function test_nested_loops | test_nested_loops | +| test_loops.py:133:11:133:14 | True | Timestamp 2 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:131:1:131:29 | Function test_while_true_break | test_while_true_break | +| test_loops.py:133:11:133:14 | True | Timestamp 2 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:131:1:131:29 | Function test_while_true_break | test_while_true_break | +| test_loops.py:133:11:133:14 | True | Timestamp 9 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:131:1:131:29 | Function test_while_true_break | test_while_true_break | +| test_loops.py:133:11:133:14 | True | Timestamp 9 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:131:1:131:29 | Function test_while_true_break | test_while_true_break | +| test_loops.py:133:11:133:14 | True | Timestamp 16 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:131:1:131:29 | Function test_while_true_break | test_while_true_break | +| test_loops.py:133:11:133:14 | True | Timestamp 16 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:131:1:131:29 | Function test_while_true_break | test_while_true_break | +| test_loops.py:133:11:133:14 | True | Timestamp 22 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:131:1:131:29 | Function test_while_true_break | test_while_true_break | +| test_loops.py:133:11:133:14 | True | Timestamp 22 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:131:1:131:29 | Function test_while_true_break | test_while_true_break | +| test_loops.py:135:13:135:48 | After Compare | Timestamp 1 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:131:1:131:29 | Function test_while_true_break | test_while_true_break | +| test_loops.py:135:13:135:48 | After Compare | Timestamp 1 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:131:1:131:29 | Function test_while_true_break | test_while_true_break | +| test_loops.py:135:13:135:48 | After Compare | Timestamp 8 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:131:1:131:29 | Function test_while_true_break | test_while_true_break | +| test_loops.py:135:13:135:48 | After Compare | Timestamp 8 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:131:1:131:29 | Function test_while_true_break | test_while_true_break | +| test_loops.py:135:13:135:48 | After Compare | Timestamp 15 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:131:1:131:29 | Function test_while_true_break | test_while_true_break | +| test_loops.py:135:13:135:48 | After Compare | Timestamp 15 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:131:1:131:29 | Function test_while_true_break | test_while_true_break | +| test_loops.py:135:13:135:48 | After Compare | Timestamp 22 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:131:1:131:29 | Function test_while_true_break | test_while_true_break | +| test_loops.py:135:13:135:48 | After Compare | Timestamp 22 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:131:1:131:29 | Function test_while_true_break | test_while_true_break | +| test_loops.py:143:21:143:83 | After BinaryExpr() | Timestamp 6 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:142:1:142:26 | Function test_for_enumerate | test_for_enumerate | +| test_loops.py:143:21:143:83 | After BinaryExpr() | Timestamp 6 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:142:1:142:26 | Function test_for_enumerate | test_for_enumerate | +| test_loops.py:143:21:143:83 | After BinaryExpr() | Timestamp 8 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:142:1:142:26 | Function test_for_enumerate | test_for_enumerate | +| test_loops.py:143:21:143:83 | After BinaryExpr() | Timestamp 8 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:142:1:142:26 | Function test_for_enumerate | test_for_enumerate | +| test_loops.py:143:21:143:83 | After BinaryExpr() | Timestamp 10 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:142:1:142:26 | Function test_for_enumerate | test_for_enumerate | +| test_loops.py:143:21:143:83 | After BinaryExpr() | Timestamp 10 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:142:1:142:26 | Function test_for_enumerate | test_for_enumerate | +| test_loops.py:143:21:143:83 | After BinaryExpr() | Timestamp 12 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:142:1:142:26 | Function test_for_enumerate | test_for_enumerate | +| test_loops.py:143:21:143:83 | After BinaryExpr() | Timestamp 12 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:142:1:142:26 | Function test_for_enumerate | test_for_enumerate | +| test_loops.py:145:9:145:11 | val | Timestamp 6 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:142:1:142:26 | Function test_for_enumerate | test_for_enumerate | +| test_loops.py:145:9:145:11 | val | Timestamp 6 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:142:1:142:26 | Function test_for_enumerate | test_for_enumerate | +| test_loops.py:145:9:145:11 | val | Timestamp 8 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:142:1:142:26 | Function test_for_enumerate | test_for_enumerate | +| test_loops.py:145:9:145:11 | val | Timestamp 8 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:142:1:142:26 | Function test_for_enumerate | test_for_enumerate | +| test_loops.py:145:9:145:11 | val | Timestamp 10 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:142:1:142:26 | Function test_for_enumerate | test_for_enumerate | +| test_loops.py:145:9:145:11 | val | Timestamp 10 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:142:1:142:26 | Function test_for_enumerate | test_for_enumerate | +| test_loops.py:145:9:145:11 | val | Timestamp 12 on true/false branch is missing a dead() annotation on the false successor in $@ | test_loops.py:142:1:142:26 | Function test_for_enumerate | test_for_enumerate | +| test_loops.py:145:9:145:11 | val | Timestamp 12 on true/false branch is missing a dead() annotation on the true successor in $@ | test_loops.py:142:1:142:26 | Function test_for_enumerate | test_for_enumerate | +| test_match.py:16:11:16:11 | x | Timestamp 2 on true/false branch is missing a dead() annotation on the false successor in $@ | test_match.py:14:1:14:26 | Function test_match_literal | test_match_literal | +| test_match.py:16:11:16:11 | x | Timestamp 2 on true/false branch is missing a dead() annotation on the true successor in $@ | test_match.py:14:1:14:26 | Function test_match_literal | test_match_literal | +| test_match.py:16:11:16:11 | x | Timestamp 3 on true/false branch is missing a dead() annotation on the false successor in $@ | test_match.py:14:1:14:26 | Function test_match_literal | test_match_literal | +| test_match.py:16:11:16:11 | x | Timestamp 3 on true/false branch is missing a dead() annotation on the true successor in $@ | test_match.py:14:1:14:26 | Function test_match_literal | test_match_literal | +| test_match.py:27:11:27:11 | x | Timestamp 2 on true/false branch is missing a dead() annotation on the false successor in $@ | test_match.py:25:1:25:38 | Function test_match_literal_fallthrough | test_match_literal_fallthrough | +| test_match.py:27:11:27:11 | x | Timestamp 2 on true/false branch is missing a dead() annotation on the true successor in $@ | test_match.py:25:1:25:38 | Function test_match_literal_fallthrough | test_match_literal_fallthrough | +| test_match.py:27:11:27:11 | x | Timestamp 3 on true/false branch is missing a dead() annotation on the false successor in $@ | test_match.py:25:1:25:38 | Function test_match_literal_fallthrough | test_match_literal_fallthrough | +| test_match.py:27:11:27:11 | x | Timestamp 3 on true/false branch is missing a dead() annotation on the true successor in $@ | test_match.py:25:1:25:38 | Function test_match_literal_fallthrough | test_match_literal_fallthrough | +| test_match.py:51:11:51:11 | x | Timestamp 2 on true/false branch is missing a dead() annotation on the false successor in $@ | test_match.py:49:1:49:26 | Function test_match_capture | test_match_capture | +| test_match.py:51:11:51:11 | x | Timestamp 2 on true/false branch is missing a dead() annotation on the true successor in $@ | test_match.py:49:1:49:26 | Function test_match_capture | test_match_capture | +| test_match.py:51:11:51:11 | x | Timestamp 3 on true/false branch is missing a dead() annotation on the false successor in $@ | test_match.py:49:1:49:26 | Function test_match_capture | test_match_capture | +| test_match.py:51:11:51:11 | x | Timestamp 3 on true/false branch is missing a dead() annotation on the true successor in $@ | test_match.py:49:1:49:26 | Function test_match_capture | test_match_capture | +| test_match.py:71:11:71:11 | x | Timestamp 2 on true/false branch is missing a dead() annotation on the false successor in $@ | test_match.py:69:1:69:24 | Function test_match_guard | test_match_guard | +| test_match.py:71:11:71:11 | x | Timestamp 2 on true/false branch is missing a dead() annotation on the true successor in $@ | test_match.py:69:1:69:24 | Function test_match_guard | test_match_guard | +| test_match.py:82:11:82:11 | x | Timestamp 2 on true/false branch is missing a dead() annotation on the false successor in $@ | test_match.py:80:1:80:32 | Function test_match_class_pattern | test_match_class_pattern | +| test_match.py:82:11:82:11 | x | Timestamp 2 on true/false branch is missing a dead() annotation on the true successor in $@ | test_match.py:80:1:80:32 | Function test_match_class_pattern | test_match_class_pattern | +| test_match.py:82:11:82:11 | x | Timestamp 3 on true/false branch is missing a dead() annotation on the false successor in $@ | test_match.py:80:1:80:32 | Function test_match_class_pattern | test_match_class_pattern | +| test_match.py:82:11:82:11 | x | Timestamp 3 on true/false branch is missing a dead() annotation on the true successor in $@ | test_match.py:80:1:80:32 | Function test_match_class_pattern | test_match_class_pattern | +| test_match.py:93:11:93:11 | x | Timestamp 4 on true/false branch is missing a dead() annotation on the false successor in $@ | test_match.py:91:1:91:27 | Function test_match_sequence | test_match_sequence | +| test_match.py:93:11:93:11 | x | Timestamp 4 on true/false branch is missing a dead() annotation on the true successor in $@ | test_match.py:91:1:91:27 | Function test_match_sequence | test_match_sequence | +| test_try.py:95:16:95:36 | After BinaryExpr() | Timestamp 3 on true/false branch is missing a dead() annotation on the false successor in $@ | test_try.py:92:1:92:41 | Function test_try_except_finally_exception | test_try_except_finally_exception | +| test_try.py:95:16:95:36 | After BinaryExpr() | Timestamp 3 on true/false branch is missing a dead() annotation on the true successor in $@ | test_try.py:92:1:92:41 | Function test_try_except_finally_exception | test_try_except_finally_exception | +| test_try.py:95:16:95:36 | After BinaryExpr() | Timestamp 4 on true/false branch is missing a dead() annotation on the false successor in $@ | test_try.py:92:1:92:41 | Function test_try_except_finally_exception | test_try_except_finally_exception | +| test_try.py:95:16:95:36 | After BinaryExpr() | Timestamp 4 on true/false branch is missing a dead() annotation on the true successor in $@ | test_try.py:92:1:92:41 | Function test_try_except_finally_exception | test_try_except_finally_exception | +| test_try.py:147:20:147:40 | After BinaryExpr() | Timestamp 4 on true/false branch is missing a dead() annotation on the false successor in $@ | test_try.py:142:1:142:30 | Function test_nested_try_except | test_nested_try_except | +| test_try.py:147:20:147:40 | After BinaryExpr() | Timestamp 4 on true/false branch is missing a dead() annotation on the true successor in $@ | test_try.py:142:1:142:30 | Function test_nested_try_except | test_nested_try_except | +| test_try.py:162:17:162:52 | After Compare | Timestamp 7 on true/false branch is missing a dead() annotation on the false successor in $@ | test_try.py:158:1:158:24 | Function test_try_in_loop | test_try_in_loop | +| test_try.py:162:17:162:52 | After Compare | Timestamp 7 on true/false branch is missing a dead() annotation on the true successor in $@ | test_try.py:158:1:158:24 | Function test_try_in_loop | test_try_in_loop | +| test_try.py:162:17:162:52 | After Compare | Timestamp 14 on true/false branch is missing a dead() annotation on the false successor in $@ | test_try.py:158:1:158:24 | Function test_try_in_loop | test_try_in_loop | +| test_try.py:162:17:162:52 | After Compare | Timestamp 14 on true/false branch is missing a dead() annotation on the true successor in $@ | test_try.py:158:1:158:24 | Function test_try_in_loop | test_try_in_loop | +| test_try.py:162:17:162:52 | After Compare | Timestamp 23 on true/false branch is missing a dead() annotation on the false successor in $@ | test_try.py:158:1:158:24 | Function test_try_in_loop | test_try_in_loop | +| test_try.py:162:17:162:52 | After Compare | Timestamp 23 on true/false branch is missing a dead() annotation on the true successor in $@ | test_try.py:158:1:158:24 | Function test_try_in_loop | test_try_in_loop | +| test_try.py:176:20:176:40 | After BinaryExpr() | Timestamp 3 on true/false branch is missing a dead() annotation on the false successor in $@ | test_try.py:172:1:172:20 | Function test_reraise | test_reraise | +| test_try.py:176:20:176:40 | After BinaryExpr() | Timestamp 3 on true/false branch is missing a dead() annotation on the true successor in $@ | test_try.py:172:1:172:20 | Function test_reraise | test_reraise | +| test_try.py:176:20:176:40 | After BinaryExpr() | Timestamp 4 on true/false branch is missing a dead() annotation on the false successor in $@ | test_try.py:172:1:172:20 | Function test_reraise | test_reraise | +| test_try.py:176:20:176:40 | After BinaryExpr() | Timestamp 4 on true/false branch is missing a dead() annotation on the true successor in $@ | test_try.py:172:1:172:20 | Function test_reraise | test_reraise | +| test_with.py:55:14:55:33 | After List | Timestamp 3 on true/false branch is missing a dead() annotation on the false successor in $@ | test_with.py:54:1:54:25 | Function test_with_in_loop | test_with_in_loop | +| test_with.py:55:14:55:33 | After List | Timestamp 3 on true/false branch is missing a dead() annotation on the true successor in $@ | test_with.py:54:1:54:25 | Function test_with_in_loop | test_with_in_loop | +| test_with.py:55:14:55:33 | After List | Timestamp 6 on true/false branch is missing a dead() annotation on the false successor in $@ | test_with.py:54:1:54:25 | Function test_with_in_loop | test_with_in_loop | +| test_with.py:55:14:55:33 | After List | Timestamp 6 on true/false branch is missing a dead() annotation on the true successor in $@ | test_with.py:54:1:54:25 | Function test_with_in_loop | test_with_in_loop | +| test_with.py:55:14:55:33 | After List | Timestamp 9 on true/false branch is missing a dead() annotation on the false successor in $@ | test_with.py:54:1:54:25 | Function test_with_in_loop | test_with_in_loop | +| test_with.py:55:14:55:33 | After List | Timestamp 9 on true/false branch is missing a dead() annotation on the true successor in $@ | test_with.py:54:1:54:25 | Function test_with_in_loop | test_with_in_loop | +| test_with.py:57:17:57:17 | i | Timestamp 3 on true/false branch is missing a dead() annotation on the false successor in $@ | test_with.py:54:1:54:25 | Function test_with_in_loop | test_with_in_loop | +| test_with.py:57:17:57:17 | i | Timestamp 3 on true/false branch is missing a dead() annotation on the true successor in $@ | test_with.py:54:1:54:25 | Function test_with_in_loop | test_with_in_loop | +| test_with.py:57:17:57:17 | i | Timestamp 6 on true/false branch is missing a dead() annotation on the false successor in $@ | test_with.py:54:1:54:25 | Function test_with_in_loop | test_with_in_loop | +| test_with.py:57:17:57:17 | i | Timestamp 6 on true/false branch is missing a dead() annotation on the true successor in $@ | test_with.py:54:1:54:25 | Function test_with_in_loop | test_with_in_loop | +| test_with.py:57:17:57:17 | i | Timestamp 9 on true/false branch is missing a dead() annotation on the false successor in $@ | test_with.py:54:1:54:25 | Function test_with_in_loop | test_with_in_loop | +| test_with.py:57:17:57:17 | i | Timestamp 9 on true/false branch is missing a dead() annotation on the true successor in $@ | test_with.py:54:1:54:25 | Function test_with_in_loop | test_with_in_loop | 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..cd591b867666 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgBranchTimestamps.ql @@ -0,0 +1,23 @@ +/** + * 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. + */ + +import python +import TimerUtils +import NewCfgImpl + +private module Utils = EvalOrderCfgUtils; + +private import Utils +private import Utils::CfgTests + +from TimerCfgNode node, int ts, string branch +where missingBranchTimestamp(node, ts, branch) +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..1ef8be08d27b 100644 --- a/python/ql/test/library-tests/ControlFlow/evaluation-order/NoBackwardFlow.expected +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/NoBackwardFlow.expected @@ -1,11 +1,10 @@ | 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 | | test_boolean.py:52:11:52:47 | ControlFlowNode for BoolExpr | Backward flow: $@ flows to $@ (max timestamp $@) | test_boolean.py:52:63:52:63 | IntegerLiteral | 2 | test_boolean.py:52:11:52:14 | ControlFlowNode for True | True | test_boolean.py:52:20:52:20 | IntegerLiteral | 0 | | test_boolean.py:64:10:64:52 | ControlFlowNode for BoolExpr | Backward flow: $@ flows to $@ (max timestamp $@) | test_boolean.py:64:59:64:59 | IntegerLiteral | 6 | test_boolean.py:64:11:64:11 | ControlFlowNode for f | f | test_boolean.py:64:17:64:17 | IntegerLiteral | 0 | | test_boolean.py:76:10:76:51 | ControlFlowNode for BoolExpr | Backward flow: $@ flows to $@ (max timestamp $@) | test_boolean.py:76:58:76:58 | IntegerLiteral | 6 | test_boolean.py:76:11:76:11 | ControlFlowNode for f | f | test_boolean.py:76:17:76:17 | IntegerLiteral | 0 | -| test_if.py:96:9:96:29 | ControlFlowNode for BoolExpr | Backward flow: $@ flows to $@ (max timestamp $@) | test_if.py:96:36:96:36 | IntegerLiteral | 4 | test_if.py:96:9:96:9 | ControlFlowNode for x | x | test_if.py:96:15:96:15 | 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..6ddfe672de75 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(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..aa03001b61bd 100644 --- a/python/ql/test/library-tests/ControlFlow/evaluation-order/StrictForward.expected +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/StrictForward.expected @@ -1,11 +1,10 @@ | 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 | | test_boolean.py:52:11:52:47 | ControlFlowNode for BoolExpr | Strict forward violation: $@ flows to $@ | test_boolean.py:52:63:52:63 | IntegerLiteral | timestamp 2 | test_boolean.py:52:20:52:20 | IntegerLiteral | timestamp 0 | | test_boolean.py:64:10:64:52 | ControlFlowNode for BoolExpr | Strict forward violation: $@ flows to $@ | test_boolean.py:64:59:64:59 | IntegerLiteral | timestamp 6 | test_boolean.py:64:17:64:17 | IntegerLiteral | timestamp 0 | | test_boolean.py:76:10:76:51 | ControlFlowNode for BoolExpr | Strict forward violation: $@ flows to $@ | test_boolean.py:76:58:76:58 | IntegerLiteral | timestamp 6 | test_boolean.py:76:17:76:17 | IntegerLiteral | timestamp 0 | -| test_if.py:96:9:96:29 | ControlFlowNode for BoolExpr | Strict forward violation: $@ flows to $@ | test_if.py:96:36:96:36 | IntegerLiteral | timestamp 4 | test_if.py:96:15:96:15 | 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/TimerUtils.qll b/python/ql/test/library-tests/ControlFlow/evaluation-order/TimerUtils.qll index 23f8f3a50a0a..46ace2e3e6b1 100644 --- a/python/ql/test/library-tests/ControlFlow/evaluation-order/TimerUtils.qll +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/TimerUtils.qll @@ -23,6 +23,13 @@ class TestFunction extends Function { string getTimerParamName() { result = this.getArgName(0) } } +/** Gets an IntegerLiteral from a timestamp expression (single int or tuple of ints). */ +private IntegerLiteral timestampLiteral(Expr timestamps) { + result = timestamps + or + result = timestamps.(Tuple).getAnElt() +} + /** * Gets an element from a timestamp subscript index. Each element is either * an `IntegerLiteral` (live), a `Call` to `dead` (dead), a `Name("never")` 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..79abb278684c 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 @@ -106,3 +106,9 @@ def test_if_pass(t): if x @ t[1]: pass z = 0 @ t[2] + + +@test + + +@test diff --git a/python/ql/test/library-tests/ControlFlow/splitting/NodeCount.ql b/python/ql/test/library-tests/ControlFlow/splitting/NodeCount.ql index c51707a65ffd..e41f73f5b884 100644 --- a/python/ql/test/library-tests/ControlFlow/splitting/NodeCount.ql +++ b/python/ql/test/library-tests/ControlFlow/splitting/NodeCount.ql @@ -8,4 +8,4 @@ where not a instanceof ExprStmt and a.getScope() = s and s instanceof Function -select a.getLocation().getStartLine(), s.getName(), a, count(a.getAFlowNode()) +select a.getLocation().getStartLine(), s.getName(), a, count(ControlFlowNode n | n.getNode() = a) 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..7d83ea98a0eb --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/store-load/StoreLoadTest.ql @@ -0,0 +1,45 @@ +/** + * 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. + * + * For subscript / attribute stores the tag fires on the Subscript / + * Attribute node itself, with `value` set to the rightmost identifier + * (the attribute name for `Attribute`, the index expression's textual + * form for `Subscript`). + */ + +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/global/Global.ql b/python/ql/test/library-tests/PointsTo/global/Global.ql index 4dc6d16d3797..9887b79fbfc7 100644 --- a/python/ql/test/library-tests/PointsTo/global/Global.ql +++ b/python/ql/test/library-tests/PointsTo/global/Global.ql @@ -3,6 +3,6 @@ private import LegacyPointsTo from ControlFlowNode f, PointsToContext ctx, Value obj, ControlFlowNode orig where - exists(ExprStmt s | s.getValue().getAFlowNode() = f) and + exists(ExprStmt s | f.getNode() = s.getValue()) and PointsTo::pointsTo(f, ctx, obj, orig) select ctx, f, obj.toString(), orig diff --git a/python/ql/test/library-tests/PointsTo/local/LocalPointsTo.ql b/python/ql/test/library-tests/PointsTo/local/LocalPointsTo.ql index c81bd0ed3deb..ecf67aa7b33e 100644 --- a/python/ql/test/library-tests/PointsTo/local/LocalPointsTo.ql +++ b/python/ql/test/library-tests/PointsTo/local/LocalPointsTo.ql @@ -4,6 +4,6 @@ import semmle.python.objects.ObjectInternal from ControlFlowNode f, ObjectInternal obj, ControlFlowNode orig where - exists(ExprStmt s | s.getValue().getAFlowNode() = f) and + exists(ExprStmt s | f.getNode() = s.getValue()) and PointsTo::pointsTo(f, _, obj, orig) select f, obj.toString(), orig 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..3b5cd963eeab --- /dev/null +++ b/python/ql/test/library-tests/dataflow-new-ssa-vs-legacy/CmpTest.expected @@ -0,0 +1,6 @@ +| 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 | e:40:25 | +| 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..2ce5c66bc4a2 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 | After 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 | After 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..046e18186c03 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 | After 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..c5794bfca970 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 | After 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 | After 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 | After 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 | After 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 | After 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 | After 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 | After 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 | After 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 | After obfuscated_id() | test.py:0:0:0:0 | ModuleVariableNode in Module test for b | +| test.py:7:5:7:20 | After 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 | After 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..dd758848448f 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 | After obfuscated_id() | +| test.py:4:10:4:10 | z | test.py:7:5:7:20 | After 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 | After obfuscated_id() | test.py:7:1:7:1 | b | +| test.py:7:5:7:20 | After 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 | After obfuscated_id() | +| test.py:7:19:7:19 | a | test.py:7:5:7:20 | After 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..4ed0993e4e0c 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 | After obfuscated_id() | test.py:7:1:7:1 | b | +| test.py:7:5:7:20 | After obfuscated_id() | test.py:7:5:7:20 | After obfuscated_id() | +| test.py:7:5:7:20 | [pre] After obfuscated_id() | test.py:7:5:7:20 | [pre] After 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..6631b2123f2b 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 | After 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..b820e3d2d7b0 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 | After obfuscated_id() | test.py:0:0:0:0 | ModuleVariableNode in Module test for b | +| test.py:7:5:7:20 | After 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..d516fa208956 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 | After obfuscated_id() | +| test.py:7:5:7:20 | [pre] After 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..d516fa208956 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 | After obfuscated_id() | +| test.py:7:5:7:20 | [pre] After 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..c8efb96e5648 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] After CrosstalkTestX() | self | +| test.py:33:8:33:23 | CrosstalkTestY() | test.py:21:5:21:23 | Function __init__ | test.py:33:8:33:23 | [pre] After 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..303a2736935d 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 | After 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 | After 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 | After ListComp | test.py:209:5:209:5 | x | diff --git a/python/ql/test/library-tests/dataflow/coverage/test.py b/python/ql/test/library-tests/dataflow/coverage/test.py index 5f13ba5a403c..0b6d6f1444ea 100644 --- a/python/ql/test/library-tests/dataflow/coverage/test.py +++ b/python/ql/test/library-tests/dataflow/coverage/test.py @@ -844,7 +844,7 @@ def return_from_inner_scope(x): return SOURCE def test_return_from_inner_scope(): - SINK(return_from_inner_scope([])) # $ flow="SOURCE, l:-3 -> return_from_inner_scope(..)" + SINK(return_from_inner_scope([])) # $ MISSING: flow="SOURCE, l:-3 -> return_from_inner_scope(..)" # Inspired by reverse read inconsistency check 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..58bcf1bb44ee 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 | After 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 | After 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 | After 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 | After .0 [empty] | +| generator.py:2:12:2:26 | Function listcomp | generator.py:2:13:2:13 | After 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..4f4eebc6fb2b 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 | After Attribute() | Unexpected result: unresolved_call=os.path.dirname(..) | +| test.py:4:33:4:59 | After Attribute() | Unexpected result: unresolved_call=os.path.dirname(..) | +| test_dict.py:4:17:4:60 | After Attribute() | Unexpected result: unresolved_call=os.path.dirname(..) | +| test_dict.py:4:33:4:59 | After 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..2e7a4109218b 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 | After ImportMember | test3.py:1:17:1:19 | foo | +| test3.py:1:17:1:19 | After 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 | After 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 | After 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 | After 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..d0551ac94771 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 | After meth() | meth() | obj1 | bar | +| test.py:6:1:6:6 | After meth() | meth() | obj1 | foo | +| test.py:6:1:6:6 | After meth() | meth() | obj2 | bar | +| test.py:6:1:6:6 | After 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 | After meth() | meth() | obj1 | foo | +| test.py:6:1:6:6 | After 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..4591f33922d7 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 | After Attribute | +| module.py:1:13:1:18 | SOURCE | test.py:111:10:111:12 | After 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 4a97116f8cd1..535c449545a1 100644 --- a/python/ql/test/library-tests/dataflow/summaries/summaries.expected +++ b/python/ql/test/library-tests/dataflow/summaries/summaries.expected @@ -1,114 +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 | summaries.py:45:6:45:20 | ControlFlowNode for Subscript | provenance | | -| 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() | summaries.py:44:1:44:12 | ControlFlowNode for tainted_list | 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 | summaries.py:44:16:44:33 | ControlFlowNode for reversed() | provenance | builtins.reversed | -| 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 | provenance | | -| 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 | 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 | After identity() | summaries.py:32:1:32:7 | tainted | provenance | | +| summaries.py:32:20:32:25 | SOURCE | summaries.py:32:11:32:26 | After 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 | After apply_lambda() | summaries.py:36:1:36:14 | tainted_lambda | provenance | | +| summaries.py:36:38:36:38 | x | summaries.py:36:41:36:45 | After BinaryExpr | provenance | | +| summaries.py:36:48:36:53 | SOURCE | summaries.py:36:18:36:54 | After 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 | After 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 | After reversed() | summaries.py:44:1:44:12 | tainted_list | provenance | | +| summaries.py:44:16:44:33 | After reversed() [List element] | summaries.py:44:1:44:12 | tainted_list [List element] | provenance | | +| summaries.py:44:25:44:32 | After List | summaries.py:44:16:44:33 | After reversed() | provenance | builtins.reversed | +| summaries.py:44:25:44:32 | After List [List element] | summaries.py:44:16:44:33 | After reversed() [List element] | provenance | builtins.reversed | +| summaries.py:44:26:44:31 | SOURCE | summaries.py:44:25:44:32 | After List | provenance | | +| summaries.py:44:26:44:31 | SOURCE | summaries.py:44:25:44:32 | After List [List element] | provenance | | +| summaries.py:45:6:45:17 | tainted_list [List element] | summaries.py:45:6:45:20 | After Subscript | provenance | | +| summaries.py:48:15:48:15 | x | summaries.py:49:12:49:18 | After 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 | After list_map() [List element] | summaries.py:51:1:51:14 | tainted_mapped [List element] | provenance | | +| summaries.py:51:38:51:45 | After List [List element] | summaries.py:48:15:48:15 | x | provenance | list_map | +| summaries.py:51:38:51:45 | After List [List element] | summaries.py:51:18:51:46 | After list_map() [List element] | provenance | list_map | +| summaries.py:51:39:51:44 | SOURCE | summaries.py:51:38:51:45 | After List [List element] | provenance | | +| summaries.py:52:6:52:19 | tainted_mapped [List element] | summaries.py:52:6:52:22 | After 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 | After list_map() [List element] | summaries.py:57:1:57:23 | tainted_mapped_explicit [List element] | provenance | | +| summaries.py:57:55:57:62 | After List [List element] | summaries.py:54:23:54:23 | x | provenance | list_map | +| summaries.py:57:55:57:62 | After List [List element] | summaries.py:57:27:57:63 | After list_map() [List element] | provenance | list_map | +| summaries.py:57:56:57:61 | SOURCE | summaries.py:57:55:57:62 | After List [List element] | provenance | | +| summaries.py:58:6:58:28 | tainted_mapped_explicit [List element] | summaries.py:58:6:58:31 | After 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 | After list_map() [List element] | summaries.py:60:1:60:22 | tainted_mapped_summary [List element] | provenance | | +| summaries.py:60:45:60:52 | After List [List element] | summaries.py:60:26:60:53 | After list_map() [List element] | provenance | list_map | +| summaries.py:60:46:60:51 | SOURCE | summaries.py:60:45:60:52 | After List [List element] | provenance | | +| summaries.py:61:6:61:27 | tainted_mapped_summary [List element] | summaries.py:61:6:61:30 | After 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 | After 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 | After 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 | After Subscript | provenance | | +| summaries.py:67:1:67:18 | tainted_resultlist | summaries.py:68:6:68:26 | After 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 | After 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 | After json_loads() [List element] | provenance | json.loads | +| summaries.py:68:6:68:23 | tainted_resultlist [List element] | summaries.py:68:6:68:26 | After 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 | semmle.label | ControlFlowNode for tainted_list | -| 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() | semmle.label | ControlFlowNode for reversed() | -| 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 | semmle.label | ControlFlowNode for List | -| 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 | After identity() | semmle.label | After 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 | After apply_lambda() | semmle.label | After apply_lambda() | +| summaries.py:36:38:36:38 | x | semmle.label | x | +| summaries.py:36:41:36:45 | After BinaryExpr | semmle.label | After 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 | After reversed() | semmle.label | After reversed() | +| summaries.py:44:16:44:33 | After reversed() [List element] | semmle.label | After reversed() [List element] | +| summaries.py:44:25:44:32 | After List | semmle.label | After List | +| summaries.py:44:25:44:32 | After List [List element] | semmle.label | After 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 | After Subscript | semmle.label | After Subscript | +| summaries.py:48:15:48:15 | x | semmle.label | x | +| summaries.py:49:12:49:18 | After BinaryExpr | semmle.label | After BinaryExpr | +| summaries.py:51:1:51:14 | tainted_mapped [List element] | semmle.label | tainted_mapped [List element] | +| summaries.py:51:18:51:46 | After list_map() [List element] | semmle.label | After list_map() [List element] | +| summaries.py:51:38:51:45 | After List [List element] | semmle.label | After 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 | After Subscript | semmle.label | After 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 | After list_map() [List element] | semmle.label | After list_map() [List element] | +| summaries.py:57:55:57:62 | After List [List element] | semmle.label | After 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 | After Subscript | semmle.label | After 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 | After list_map() [List element] | semmle.label | After list_map() [List element] | +| summaries.py:60:45:60:52 | After List [List element] | semmle.label | After 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 | After Subscript | semmle.label | After Subscript | +| summaries.py:63:1:63:12 | tainted_list [List element] | semmle.label | tainted_list [List element] | +| summaries.py:63:16:63:41 | After append_to_list() [List element] | semmle.label | After 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 | After Subscript | semmle.label | After 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 | After json_loads() [List element] | semmle.label | After 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 | After Subscript | semmle.label | After 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 | After BinaryExpr | summaries.py:36:18:36:54 | After apply_lambda() | +| summaries.py:51:38:51:45 | After List [List element] | summaries.py:48:15:48:15 | x | summaries.py:49:12:49:18 | After BinaryExpr | summaries.py:51:18:51:46 | After list_map() [List element] | +| summaries.py:57:55:57:62 | After List [List element] | summaries.py:54:23:54:23 | x | summaries.py:55:12:55:12 | x | summaries.py:57:27:57:63 | After 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 | After Subscript | summaries.py:44:26:44:31 | SOURCE | summaries.py:45:6:45:20 | After Subscript | $@ | summaries.py:44:26:44:31 | SOURCE | SOURCE | +| summaries.py:52:6:52:22 | After Subscript | summaries.py:51:39:51:44 | SOURCE | summaries.py:52:6:52:22 | After Subscript | $@ | summaries.py:51:39:51:44 | SOURCE | SOURCE | +| summaries.py:58:6:58:31 | After Subscript | summaries.py:57:56:57:61 | SOURCE | summaries.py:58:6:58:31 | After Subscript | $@ | summaries.py:57:56:57:61 | SOURCE | SOURCE | +| summaries.py:61:6:61:30 | After Subscript | summaries.py:60:46:60:51 | SOURCE | summaries.py:61:6:61:30 | After Subscript | $@ | summaries.py:60:46:60:51 | SOURCE | SOURCE | +| summaries.py:64:6:64:20 | After Subscript | summaries.py:63:35:63:40 | SOURCE | summaries.py:64:6:64:20 | After Subscript | $@ | summaries.py:63:35:63:40 | SOURCE | SOURCE | +| summaries.py:68:6:68:26 | After Subscript | summaries.py:67:33:67:38 | SOURCE | summaries.py:68:6:68:26 | After 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 67a9f576cc75..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() ) } @@ -43,7 +44,7 @@ query predicate test_taint(string arg_location, string test_res, string scope_na // TODO: Replace with `hasFlowToExpr` once that is working if TestTaintTrackingFlow::flowTo(any(DataFlow::Node n | - n.(DataFlow::CfgNode).getNode() = arg.getAFlowNode() + n.(DataFlow::CfgNode).getNode().getNode() = arg )) then has_taint = true else has_taint = false 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..f981b3e1d740 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 | After 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..30589f705c87 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 | After 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 2ebf825a19b5..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,26 +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 | | -| 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: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: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: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..bee1b8f77d48 100644 --- a/python/ql/test/library-tests/frameworks/lxml/InlineTaintTest.expected +++ b/python/ql/test/library-tests/frameworks/lxml/InlineTaintTest.expected @@ -1,3 +1,6 @@ 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:83:13:83:19 | ch.text | Fixed missing result: tainted | +| 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/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/Exceptions/general/CatchingBaseException.expected b/python/ql/test/query-tests/Exceptions/general/CatchingBaseException.expected index dbc838a90be0..59a9ed5f80b7 100644 --- a/python/ql/test/query-tests/Exceptions/general/CatchingBaseException.expected +++ b/python/ql/test/query-tests/Exceptions/general/CatchingBaseException.expected @@ -1,2 +1 @@ | exceptions_test.py:7:5:7:11 | ExceptStmt | Except block directly handles BaseException. | -| exceptions_test.py:97:5:97:25 | ExceptStmt | Except block directly handles BaseException. | diff --git a/python/ql/test/query-tests/Exceptions/general/EmptyExcept.expected b/python/ql/test/query-tests/Exceptions/general/EmptyExcept.expected index f9d9c69dd877..580fe93e2e5f 100644 --- a/python/ql/test/query-tests/Exceptions/general/EmptyExcept.expected +++ b/python/ql/test/query-tests/Exceptions/general/EmptyExcept.expected @@ -3,3 +3,9 @@ | exceptions_test.py:72:1:72:18 | ExceptStmt | 'except' clause does nothing but pass and there is no explanatory comment. | | exceptions_test.py:85:1:85:17 | ExceptStmt | 'except' clause does nothing but pass and there is no explanatory comment. | | exceptions_test.py:89:1:89:17 | ExceptStmt | 'except' clause does nothing but pass and there is no explanatory comment. | +| exceptions_test.py:144:5:144:25 | ExceptStmt | 'except' clause does nothing but pass and there is no explanatory comment. | +| exceptions_test.py:167:5:167:26 | ExceptStmt | 'except' clause does nothing but pass and there is no explanatory comment. | +| exceptions_test.py:173:5:173:22 | ExceptStmt | 'except' clause does nothing but pass and there is no explanatory comment. | +| exceptions_test.py:179:5:179:22 | ExceptStmt | 'except' clause does nothing but pass and there is no explanatory comment. | +| exceptions_test.py:185:5:185:26 | ExceptStmt | 'except' clause does nothing but pass and there is no explanatory comment. | +| exceptions_test.py:191:5:191:30 | ExceptStmt | 'except' clause does nothing but pass and there is no explanatory comment. | diff --git a/python/ql/test/query-tests/Exceptions/general/IncorrectExceptOrder.expected b/python/ql/test/query-tests/Exceptions/general/IncorrectExceptOrder.expected index 3fab57be376b..6010ed3bdedc 100644 --- a/python/ql/test/query-tests/Exceptions/general/IncorrectExceptOrder.expected +++ b/python/ql/test/query-tests/Exceptions/general/IncorrectExceptOrder.expected @@ -1 +1,3 @@ -| exceptions_test.py:64:1:64:22 | ExceptStmt | This except block handling $@ is unreachable; as $@ for the more general $@ always subsumes it. | file://:0:0:0:0 | AttributeError | AttributeError | exceptions_test.py:62:1:62:17 | ExceptStmt | this except block | file://:0:0:0:0 | Exception | Exception | +#select +testFailures +| exceptions_test.py:64:24:64:55 | Comment # $ Alert[py/unreachable-except] | Missing result: Alert[py/unreachable-except] | 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..d69df207f14e 100644 --- a/python/ql/test/query-tests/Functions/ModificationOfParameterWithDefault/ModificationOfParameterWithDefault.expected +++ b/python/ql/test/query-tests/Functions/ModificationOfParameterWithDefault/ModificationOfParameterWithDefault.expected @@ -1,140 +1,132 @@ 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:131:23:131:23 | l | test.py:135:9:135: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:131:23:131:23 | l | semmle.label | l | +| test.py:135:9:135: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: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: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/Functions/ModificationOfParameterWithDefault/test.expected b/python/ql/test/query-tests/Functions/ModificationOfParameterWithDefault/test.expected index e69de29bb2d1..db5d700378f7 100644 --- a/python/ql/test/query-tests/Functions/ModificationOfParameterWithDefault/test.expected +++ b/python/ql/test/query-tests/Functions/ModificationOfParameterWithDefault/test.expected @@ -0,0 +1,2 @@ +| test.py:128:22:128:39 | Comment # $ modification=l | Missing result: modification=l | +| test.py:140:22:140:39 | Comment # $ modification=l | Missing result: modification=l | 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 7f48feb72eb9..368e5da42c27 100644 --- a/python/ql/test/query-tests/Resources/FileNotAlwaysClosed/FileNotAlwaysClosed.expected +++ b/python/ql/test/query-tests/Resources/FileNotAlwaysClosed/FileNotAlwaysClosed.expected @@ -1,9 +1,43 @@ -| resources_test.py:4:10:4:25 | ControlFlowNode for open() | File may not be closed if $@ raises an exception. | resources_test.py:5:5:5:33 | ControlFlowNode for Attribute() | this operation | -| resources_test.py:9:10:9:25 | ControlFlowNode for open() | File is opened but is not closed. | file://:0:0:0:0 | (none) | this operation | -| resources_test.py:108:11:108:20 | ControlFlowNode for open() | File is opened but is not closed. | file://:0:0:0:0 | (none) | this operation | -| resources_test.py:112:11:112:28 | ControlFlowNode for opener_func2() | File may not be closed if $@ raises an exception. | resources_test.py:113:5:113:22 | ControlFlowNode for Attribute() | this operation | -| resources_test.py:123:11:123:24 | ControlFlowNode for opener_func2() | File is opened but is not closed. | file://:0:0:0:0 | (none) | this operation | -| resources_test.py:129:15:129:24 | ControlFlowNode for open() | File may not be closed if $@ raises an exception. | resources_test.py:130:9:130:26 | ControlFlowNode for Attribute() | this operation | -| resources_test.py:248:11:248:25 | ControlFlowNode for open() | File is opened but is not closed. | file://:0:0:0:0 | (none) | this operation | -| resources_test.py:269:10:269:27 | ControlFlowNode for Attribute() | File may not be closed if $@ raises an exception. | resources_test.py:271:5:271:19 | ControlFlowNode for Attribute() | this operation | -| resources_test.py:285:11:285:20 | ControlFlowNode for open() | File may not be closed if $@ raises an exception. | resources_test.py:287:5:287:31 | ControlFlowNode for Attribute() | this operation | +#select +| 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:20:10:20:25 | After open() | File may not be closed if $@ raises an exception. | resources_test.py:22:9:22:37 | After Attribute() | this operation | +| resources_test.py:30:14:30:29 | After open() | File may not be closed if $@ raises an exception. | resources_test.py:31:9:31:37 | After Attribute() | this operation | +| resources_test.py:39:14:39:29 | After open() | File may not be closed if $@ raises an exception. | resources_test.py:40:9:40:37 | After Attribute() | this operation | +| resources_test.py:49:14:49:29 | After open() | File may not be closed if $@ raises an exception. | resources_test.py:50:9:50:37 | After Attribute() | this operation | +| resources_test.py:58:14:58:29 | After open() | File may not be closed if $@ raises an exception. | resources_test.py:59:9:59:37 | After Attribute() | this operation | +| resources_test.py:69:11:69:26 | After open() | File may not be closed if $@ raises an exception. | resources_test.py:71:9:71:40 | After Attribute() | this operation | +| resources_test.py:69:11:69:26 | After open() | File may not be closed if $@ raises an exception. | resources_test.py:72:9:72:40 | After Attribute() | this operation | +| resources_test.py:79:11:79:26 | After open() | File may not be closed if $@ raises an exception. | resources_test.py:81:9:81:40 | After Attribute() | this operation | +| resources_test.py:79:11:79:26 | After open() | File may not be closed if $@ raises an exception. | resources_test.py:82:9:82:40 | After Attribute() | this operation | +| resources_test.py:91:11:91:26 | After open() | File may not be closed if $@ raises an exception. | resources_test.py:93:9:93:40 | After Attribute() | this operation | +| resources_test.py:91:11:91:26 | After open() | File may not be closed if $@ raises an exception. | resources_test.py:94:9:94:40 | After Attribute() | 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:141:11:141:26 | After open() | File may not be closed if $@ raises an exception. | resources_test.py:143:9:143:40 | After Attribute() | this operation | +| resources_test.py:141:11:141:26 | After open() | File may not be closed if $@ raises an exception. | resources_test.py:144:9:144:40 | After Attribute() | this operation | +| resources_test.py:182:15:182:54 | After open() | File may not be closed if $@ raises an exception. | resources_test.py:186:9:186:25 | After Attribute() | this operation | +| resources_test.py:225:11:225:26 | After open() | File may not be closed if $@ raises an exception. | resources_test.py:227:9:227:25 | After Attribute() | this operation | +| resources_test.py:237:11:237:26 | After open() | File may not be closed if $@ raises an exception. | resources_test.py:239:9:239:25 | 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:252:11:252:25 | After open() | File may not be closed if $@ raises an exception. | resources_test.py:254:9:254:23 | After Attribute() | 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:275:10:275:35 | After Attribute() | File may not be closed if $@ raises an exception. | resources_test.py:278:9:278:23 | 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 | +testFailures +| resources_test.py:20:10:20:25 | File may not be closed if $@ raises an exception. | Unexpected result: Alert | +| resources_test.py:30:14:30:29 | File may not be closed if $@ raises an exception. | Unexpected result: Alert | +| resources_test.py:39:14:39:29 | File may not be closed if $@ raises an exception. | Unexpected result: Alert | +| resources_test.py:49:14:49:29 | File may not be closed if $@ raises an exception. | Fixed missing result: Alert | +| resources_test.py:58:14:58:29 | File may not be closed if $@ raises an exception. | Unexpected result: Alert | +| resources_test.py:69:11:69:26 | File may not be closed if $@ raises an exception. | Unexpected result: Alert | +| resources_test.py:79:11:79:26 | File may not be closed if $@ raises an exception. | Unexpected result: Alert | +| resources_test.py:91:11:91:26 | File may not be closed if $@ raises an exception. | Unexpected result: Alert | +| resources_test.py:141:11:141:26 | File may not be closed if $@ raises an exception. | Fixed missing result: Alert | +| resources_test.py:182:15:182:54 | File may not be closed if $@ raises an exception. | Unexpected result: Alert | +| resources_test.py:225:11:225:26 | File may not be closed if $@ raises an exception. | Unexpected result: Alert | +| resources_test.py:237:11:237:26 | File may not be closed if $@ raises an exception. | Fixed missing result: Alert | +| resources_test.py:252:11:252:25 | File may not be closed if $@ raises an exception. | Unexpected result: Alert | +| resources_test.py:275:10:275:35 | File may not be closed if $@ raises an exception. | Unexpected result: Alert | 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 0b96b2df6508..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,63 +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:24 | ControlFlowNode for Tuple | provenance | Sink:MaD:63 | -| BindToAllInterfaces_test.py:16:1:16:10 | ControlFlowNode for ALL_LOCALS | BindToAllInterfaces_test.py:20:1:20:3 | ControlFlowNode for tup | 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:20:1:20:3 | ControlFlowNode for tup | BindToAllInterfaces_test.py:21:8:21:10 | ControlFlowNode for tup | provenance | Sink:MaD:63 | -| 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:18 | ControlFlowNode for Tuple | provenance | Sink:MaD:63 | -| 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: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:24 | ControlFlowNode for Tuple | semmle.label | ControlFlowNode for Tuple | -| BindToAllInterfaces_test.py:20:1:20:3 | ControlFlowNode for tup | semmle.label | ControlFlowNode for tup | -| 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: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 cf3a06ac7c8f..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 @@ 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 | 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 | +| 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 08a5b798f71f..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,75 +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 | 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 | 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..e31cc5af9ba4 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 | After ImportMember | flask_path_injection.py:21:32:21:38 | dirname | This path depends on a $@. | flask_path_injection.py:1:26:1:32 | After ImportMember | user-provided value | +| path_injection.py:13:14:13:47 | After Attribute() | path_injection.py:3:26:3:32 | After ImportMember | path_injection.py:13:14:13:47 | After Attribute() | This path depends on a $@. | path_injection.py:3:26:3:32 | After ImportMember | user-provided value | +| path_injection.py:21:14:21:18 | npath | path_injection.py:3:26:3:32 | After ImportMember | path_injection.py:21:14:21:18 | npath | This path depends on a $@. | path_injection.py:3:26:3:32 | After ImportMember | user-provided value | +| path_injection.py:31:14:31:18 | npath | path_injection.py:3:26:3:32 | After ImportMember | path_injection.py:31:14:31:18 | npath | This path depends on a $@. | path_injection.py:3:26:3:32 | After ImportMember | user-provided value | +| path_injection.py:48:14:48:18 | npath | path_injection.py:3:26:3:32 | After ImportMember | path_injection.py:48:14:48:18 | npath | This path depends on a $@. | path_injection.py:3:26:3:32 | After ImportMember | user-provided value | +| path_injection.py:65:14:65:18 | npath | path_injection.py:3:26:3:32 | After ImportMember | path_injection.py:65:14:65:18 | npath | This path depends on a $@. | path_injection.py:3:26:3:32 | After ImportMember | user-provided value | +| path_injection.py:87:18:87:37 | possibly_unsafe_path | path_injection.py:3:26:3:32 | After ImportMember | path_injection.py:87:18:87:37 | possibly_unsafe_path | This path depends on a $@. | path_injection.py:3:26:3:32 | After 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 | After ImportMember | path_injection.py:113:14:113:17 | path | This path depends on a $@. | path_injection.py:3:26:3:32 | After ImportMember | user-provided value | +| path_injection.py:124:14:124:17 | path | path_injection.py:3:26:3:32 | After ImportMember | path_injection.py:124:14:124:17 | path | This path depends on a $@. | path_injection.py:3:26:3:32 | After ImportMember | user-provided value | +| path_injection.py:132:14:132:22 | sanitized | path_injection.py:3:26:3:32 | After ImportMember | path_injection.py:132:14:132:22 | sanitized | This path depends on a $@. | path_injection.py:3:26:3:32 | After ImportMember | user-provided value | +| path_injection.py:142:14:142:17 | path | path_injection.py:3:26:3:32 | After ImportMember | path_injection.py:142:14:142:17 | path | This path depends on a $@. | path_injection.py:3:26:3:32 | After ImportMember | user-provided value | +| path_injection.py:152:18:152:21 | path | path_injection.py:3:26:3:32 | After ImportMember | path_injection.py:152:18:152:21 | path | This path depends on a $@. | path_injection.py:3:26:3:32 | After ImportMember | user-provided value | +| pathlib_use.py:14:5:14:5 | p | pathlib_use.py:3:26:3:32 | After ImportMember | pathlib_use.py:14:5:14:5 | p | This path depends on a $@. | pathlib_use.py:3:26:3:32 | After ImportMember | user-provided value | +| pathlib_use.py:17:5:17:6 | p2 | pathlib_use.py:3:26:3:32 | After ImportMember | pathlib_use.py:17:5:17:6 | p2 | This path depends on a $@. | pathlib_use.py:3:26:3:32 | After ImportMember | user-provided value | +| test.py:19:10:19:10 | x | test.py:3:26:3:32 | After ImportMember | test.py:19:10:19:10 | x | This path depends on a $@. | test.py:3:26:3:32 | After ImportMember | user-provided value | +| test.py:26:10:26:10 | y | test.py:3:26:3:32 | After ImportMember | test.py:26:10:26:10 | y | This path depends on a $@. | test.py:3:26:3:32 | After ImportMember | user-provided value | +| test.py:33:14:33:14 | x | test.py:3:26:3:32 | After ImportMember | test.py:33:14:33:14 | x | This path depends on a $@. | test.py:3:26:3:32 | After ImportMember | user-provided value | +| test.py:49:14:49:14 | y | test.py:3:26:3:32 | After ImportMember | test.py:49:14:49:14 | y | This path depends on a $@. | test.py:3:26:3:32 | After 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 | After 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 | After Attribute | provenance | AdditionalTaintStep | +| flask_path_injection.py:19:15:19:26 | After Attribute | flask_path_injection.py:19:15:19:45 | After Attribute() | provenance | dict.get | +| flask_path_injection.py:19:15:19:45 | After Attribute() | flask_path_injection.py:19:5:19:11 | dirname | provenance | | +| path_injection.py:3:26:3:32 | After 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 | After Attribute() | provenance | AdditionalTaintStep | +| path_injection.py:12:16:12:22 | request | path_injection.py:12:16:12:27 | After Attribute | provenance | AdditionalTaintStep | +| path_injection.py:12:16:12:27 | After Attribute | path_injection.py:12:16:12:47 | After Attribute() | provenance | dict.get | +| path_injection.py:12:16:12:47 | After 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 | After Attribute() | provenance | AdditionalTaintStep | +| path_injection.py:19:16:19:22 | request | path_injection.py:19:16:19:27 | After Attribute | provenance | AdditionalTaintStep | +| path_injection.py:19:16:19:27 | After Attribute | path_injection.py:19:16:19:47 | After Attribute() | provenance | dict.get | +| path_injection.py:19:16:19:47 | After 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 | After Attribute() | path_injection.py:20:5:20:9 | npath | provenance | | +| path_injection.py:20:30:20:63 | After Attribute() | path_injection.py:20:13:20:64 | After Attribute() | provenance | Config | +| path_injection.py:27:5:27:12 | filename | path_injection.py:28:30:28:63 | After Attribute() | provenance | AdditionalTaintStep | +| path_injection.py:27:16:27:22 | request | path_injection.py:27:16:27:27 | After Attribute | provenance | AdditionalTaintStep | +| path_injection.py:27:16:27:27 | After Attribute | path_injection.py:27:16:27:47 | After Attribute() | provenance | dict.get | +| path_injection.py:27:16:27:47 | After 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 | After Attribute() | path_injection.py:28:5:28:9 | npath | provenance | | +| path_injection.py:28:30:28:63 | After Attribute() | path_injection.py:28:13:28:64 | After Attribute() | provenance | Config | +| path_injection.py:46:5:46:12 | filename | path_injection.py:47:30:47:63 | After Attribute() | provenance | AdditionalTaintStep | +| path_injection.py:46:16:46:22 | request | path_injection.py:46:16:46:27 | After Attribute | provenance | AdditionalTaintStep | +| path_injection.py:46:16:46:27 | After Attribute | path_injection.py:46:16:46:47 | After Attribute() | provenance | dict.get | +| path_injection.py:46:16:46:47 | After 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 | After Attribute() | path_injection.py:47:5:47:9 | npath | provenance | | +| path_injection.py:47:30:47:63 | After Attribute() | path_injection.py:47:13:47:64 | After Attribute() | provenance | Config | +| path_injection.py:63:5:63:12 | filename | path_injection.py:64:29:64:62 | After Attribute() | provenance | AdditionalTaintStep | +| path_injection.py:63:16:63:22 | request | path_injection.py:63:16:63:27 | After Attribute | provenance | AdditionalTaintStep | +| path_injection.py:63:16:63:27 | After Attribute | path_injection.py:63:16:63:47 | After Attribute() | provenance | dict.get | +| path_injection.py:63:16:63:47 | After 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 | After Attribute() | path_injection.py:64:5:64:9 | npath | provenance | | +| path_injection.py:64:29:64:62 | After Attribute() | path_injection.py:64:13:64:63 | After 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 | After Attribute | provenance | AdditionalTaintStep | +| path_injection.py:84:16:84:27 | After Attribute | path_injection.py:84:16:84:47 | After Attribute() | provenance | dict.get | +| path_injection.py:84:16:84:47 | After 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 | After Attribute | provenance | AdditionalTaintStep | +| path_injection.py:107:16:107:27 | After Attribute | path_injection.py:107:16:107:47 | After Attribute() | provenance | dict.get | +| path_injection.py:107:16:107:47 | After 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 | After Attribute | provenance | AdditionalTaintStep | +| path_injection.py:118:16:118:27 | After Attribute | path_injection.py:118:16:118:47 | After Attribute() | provenance | dict.get | +| path_injection.py:118:16:118:47 | After 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 | After Attribute | provenance | AdditionalTaintStep | +| path_injection.py:129:16:129:27 | After Attribute | path_injection.py:129:16:129:47 | After Attribute() | provenance | dict.get | +| path_injection.py:129:16:129:47 | After 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 | After Attribute | provenance | AdditionalTaintStep | +| path_injection.py:138:16:138:27 | After Attribute | path_injection.py:138:16:138:47 | After Attribute() | provenance | dict.get | +| path_injection.py:138:16:138:47 | After 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 | After Attribute | provenance | AdditionalTaintStep | +| path_injection.py:149:16:149:27 | After Attribute | path_injection.py:149:16:149:47 | After Attribute() | provenance | dict.get | +| path_injection.py:149:16:149:47 | After 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 | After 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 | After Attribute | provenance | AdditionalTaintStep | +| pathlib_use.py:12:16:12:27 | After Attribute | pathlib_use.py:12:16:12:47 | After Attribute() | provenance | dict.get | +| pathlib_use.py:12:16:12:47 | After 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 | After 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 | After Attribute | provenance | AdditionalTaintStep | +| test.py:9:12:9:23 | After Attribute | test.py:9:12:9:39 | After Attribute() | provenance | dict.get | +| test.py:9:12:9:39 | After Attribute() | test.py:18:9:18:16 | After source() | provenance | | +| test.py:9:12:9:39 | After Attribute() | test.py:24:9:24:16 | After source() | provenance | | +| test.py:9:12:9:39 | After Attribute() | test.py:31:9:31:16 | After source() | provenance | | +| test.py:9:12:9:39 | After Attribute() | test.py:46:9:46:16 | After 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 | After Attribute() | provenance | Config | +| test.py:18:5:18:5 | x | test.py:19:10:19:10 | x | provenance | | +| test.py:18:9:18:16 | After 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 | After 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 | After 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 | After normalize() | provenance | Config | +| test.py:31:5:31:5 | x | test.py:33:14:33:14 | x | provenance | | +| test.py:31:9:31:16 | After 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 | After 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 | After 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 | After 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 | After ImportMember | semmle.label | After 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 | After Attribute | semmle.label | After Attribute | +| flask_path_injection.py:19:15:19:45 | After Attribute() | semmle.label | After Attribute() | +| flask_path_injection.py:21:32:21:38 | dirname | semmle.label | dirname | +| path_injection.py:3:26:3:32 | After ImportMember | semmle.label | After 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 | After Attribute | semmle.label | After Attribute | +| path_injection.py:12:16:12:47 | After Attribute() | semmle.label | After Attribute() | +| path_injection.py:13:14:13:47 | After Attribute() | semmle.label | After 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 | After Attribute | semmle.label | After Attribute | +| path_injection.py:19:16:19:47 | After Attribute() | semmle.label | After Attribute() | +| path_injection.py:20:5:20:9 | npath | semmle.label | npath | +| path_injection.py:20:13:20:64 | After Attribute() | semmle.label | After Attribute() | +| path_injection.py:20:30:20:63 | After Attribute() | semmle.label | After 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 | After Attribute | semmle.label | After Attribute | +| path_injection.py:27:16:27:47 | After Attribute() | semmle.label | After Attribute() | +| path_injection.py:28:5:28:9 | npath | semmle.label | npath | +| path_injection.py:28:13:28:64 | After Attribute() | semmle.label | After Attribute() | +| path_injection.py:28:30:28:63 | After Attribute() | semmle.label | After 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 | After Attribute | semmle.label | After Attribute | +| path_injection.py:46:16:46:47 | After Attribute() | semmle.label | After Attribute() | +| path_injection.py:47:5:47:9 | npath | semmle.label | npath | +| path_injection.py:47:13:47:64 | After Attribute() | semmle.label | After Attribute() | +| path_injection.py:47:30:47:63 | After Attribute() | semmle.label | After 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 | After Attribute | semmle.label | After Attribute | +| path_injection.py:63:16:63:47 | After Attribute() | semmle.label | After Attribute() | +| path_injection.py:64:5:64:9 | npath | semmle.label | npath | +| path_injection.py:64:13:64:63 | After Attribute() | semmle.label | After Attribute() | +| path_injection.py:64:29:64:62 | After Attribute() | semmle.label | After 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 | After Attribute | semmle.label | After Attribute | +| path_injection.py:84:16:84:47 | After Attribute() | semmle.label | After 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 | After Attribute | semmle.label | After Attribute | +| path_injection.py:107:16:107:47 | After Attribute() | semmle.label | After 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 | After Attribute | semmle.label | After Attribute | +| path_injection.py:118:16:118:47 | After Attribute() | semmle.label | After 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 | After Attribute | semmle.label | After Attribute | +| path_injection.py:129:16:129:47 | After Attribute() | semmle.label | After 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 | After Attribute | semmle.label | After Attribute | +| path_injection.py:138:16:138:47 | After Attribute() | semmle.label | After 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 | After Attribute | semmle.label | After Attribute | +| path_injection.py:149:16:149:47 | After Attribute() | semmle.label | After 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 | After ImportMember | semmle.label | After 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 | After Attribute | semmle.label | After Attribute | +| pathlib_use.py:12:16:12:47 | After Attribute() | semmle.label | After 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 | After ImportMember | semmle.label | After 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 | After Attribute | semmle.label | After Attribute | +| test.py:9:12:9:39 | After Attribute() | semmle.label | After Attribute() | +| test.py:12:15:12:15 | x | semmle.label | x | +| test.py:13:12:13:30 | After Attribute() | semmle.label | After 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 | After source() | semmle.label | After 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 | After source() | semmle.label | After source() | +| test.py:25:5:25:5 | y | semmle.label | y | +| test.py:25:9:25:20 | After normalize() | semmle.label | After 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 | After source() | semmle.label | After 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 | After source() | semmle.label | After source() | +| test.py:48:9:48:9 | y | semmle.label | y | +| test.py:48:13:48:24 | After normalize() | semmle.label | After 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 | After Attribute() | test.py:25:9:25:20 | After normalize() | +| test.py:48:23:48:23 | x | test.py:12:15:12:15 | x | test.py:13:12:13:30 | After Attribute() | test.py:48:13:48:24 | After 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 6f98ea1aae2b..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 @@ 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 | 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 | +| 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 f92107728395..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 @@ 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 | 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 | +| 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..db538752d424 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 | After 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 | After BinaryExpr | provenance | | +| command_injection.py:11:13:11:19 | request | command_injection.py:11:13:11:24 | After Attribute | provenance | AdditionalTaintStep | +| command_injection.py:11:13:11:24 | After Attribute | command_injection.py:11:13:11:41 | After Attribute() | provenance | dict.get | +| command_injection.py:11:13:11:41 | After 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 | 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 | | +| 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 | After Attribute | provenance | AdditionalTaintStep | +| command_injection.py:25:11:25:22 | After Attribute | command_injection.py:25:11:25:37 | After Attribute() | provenance | dict.get | +| command_injection.py:25:11:25:37 | After 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 | After BinaryExpr | provenance | | +| command_injection.py:31:13:31:19 | request | command_injection.py:31:13:31:24 | After Attribute | provenance | AdditionalTaintStep | +| command_injection.py:31:13:31:24 | After Attribute | command_injection.py:31:13:31:41 | After Attribute() | provenance | dict.get | +| command_injection.py:31:13:31:41 | After 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 | After Attribute | provenance | AdditionalTaintStep | +| command_injection.py:38:15:38:26 | After Attribute | command_injection.py:38:15:38:45 | After Attribute() | provenance | dict.get | +| command_injection.py:38:15:38:45 | After 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 | After Attribute | provenance | AdditionalTaintStep | +| command_injection.py:54:15:54:26 | After Attribute | command_injection.py:54:15:54:45 | After Attribute() | provenance | dict.get | +| command_injection.py:54:15:54:45 | After 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 | After BinaryExpr | provenance | | +| command_injection.py:71:12:71:18 | request | command_injection.py:71:12:71:23 | After Attribute | provenance | AdditionalTaintStep | +| command_injection.py:71:12:71:23 | After Attribute | command_injection.py:71:12:71:39 | After Attribute() | provenance | dict.get | +| command_injection.py:71:12:71:39 | After 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 | After BinaryExpr | provenance | | +| command_injection.py:78:12:78:18 | request | command_injection.py:78:12:78:23 | After Attribute | provenance | AdditionalTaintStep | +| command_injection.py:78:12:78:23 | After Attribute | command_injection.py:78:12:78:39 | After Attribute() | provenance | dict.get | +| command_injection.py:78:12:78:39 | After 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 | After ImportMember | semmle.label | After 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 | After Attribute | semmle.label | After Attribute | +| command_injection.py:11:13:11:41 | After Attribute() | semmle.label | After Attribute() | +| command_injection.py:13:15:13:27 | After BinaryExpr | semmle.label | After 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 | After Attribute | semmle.label | After Attribute | +| command_injection.py:18:13:18:41 | After Attribute() | semmle.label | After Attribute() | +| command_injection.py:20:22:20:34 | After BinaryExpr | semmle.label | After 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 | After Attribute | semmle.label | After Attribute | +| command_injection.py:25:11:25:37 | After Attribute() | semmle.label | After 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 | After Attribute | semmle.label | After Attribute | +| command_injection.py:31:13:31:41 | After Attribute() | semmle.label | After Attribute() | +| command_injection.py:33:14:33:26 | After BinaryExpr | semmle.label | After 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 | After Attribute | semmle.label | After Attribute | +| command_injection.py:38:15:38:45 | After Attribute() | semmle.label | After 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 | After Attribute | semmle.label | After Attribute | +| command_injection.py:54:15:54:45 | After Attribute() | semmle.label | After 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 | After Attribute | semmle.label | After Attribute | +| command_injection.py:71:12:71:39 | After Attribute() | semmle.label | After Attribute() | +| command_injection.py:73:19:73:30 | After BinaryExpr | semmle.label | After 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 | After Attribute | semmle.label | After Attribute | +| command_injection.py:78:12:78:39 | After Attribute() | semmle.label | After Attribute() | +| command_injection.py:80:19:80:30 | After BinaryExpr | semmle.label | After 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 | After BinaryExpr | command_injection.py:5:26:5:32 | After ImportMember | command_injection.py:13:15:13: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:22:20:34 | After BinaryExpr | command_injection.py:5:26:5:32 | After ImportMember | command_injection.py:20:22:20:34 | After BinaryExpr | This command line depends on a $@. | command_injection.py:5:26:5:32 | After ImportMember | user-provided value | +| command_injection.py:26:23:26:25 | cmd | command_injection.py:5:26:5:32 | After ImportMember | command_injection.py:26:23:26:25 | cmd | This command line depends on a $@. | command_injection.py:5:26:5:32 | After ImportMember | user-provided value | +| command_injection.py:33:14:33:26 | After BinaryExpr | command_injection.py:5:26:5:32 | After ImportMember | command_injection.py:33:14:33:26 | After BinaryExpr | This command line depends on a $@. | command_injection.py:5:26:5:32 | After ImportMember | user-provided value | +| command_injection.py:41:15:41:21 | command | command_injection.py:5:26:5:32 | After ImportMember | command_injection.py:41:15:41:21 | command | This command line depends on a $@. | command_injection.py:5:26:5:32 | After ImportMember | user-provided value | +| command_injection.py:42:15:42:21 | command | command_injection.py:5:26:5:32 | After ImportMember | command_injection.py:42:15:42:21 | command | This command line depends on a $@. | command_injection.py:5:26:5:32 | After ImportMember | user-provided value | +| command_injection.py:55:15:55:21 | command | command_injection.py:5:26:5:32 | After ImportMember | command_injection.py:55:15:55:21 | command | This command line depends on a $@. | command_injection.py:5:26:5:32 | After ImportMember | user-provided value | +| command_injection.py:56:14:56:20 | command | command_injection.py:5:26:5:32 | After ImportMember | command_injection.py:56:14:56:20 | command | This command line depends on a $@. | command_injection.py:5:26:5:32 | After ImportMember | user-provided value | +| command_injection.py:57:21:57:27 | command | command_injection.py:5:26:5:32 | After ImportMember | command_injection.py:57:21:57:27 | command | This command line depends on a $@. | command_injection.py:5:26:5:32 | After ImportMember | user-provided value | +| command_injection.py:58:27:58:33 | command | command_injection.py:5:26:5:32 | After ImportMember | command_injection.py:58:27:58:33 | command | This command line depends on a $@. | command_injection.py:5:26:5:32 | After ImportMember | user-provided value | +| command_injection.py:59:20:59:26 | command | command_injection.py:5:26:5:32 | After ImportMember | command_injection.py:59:20:59:26 | command | This command line depends on a $@. | command_injection.py:5:26:5:32 | After ImportMember | user-provided value | +| command_injection.py:73:19:73:30 | After BinaryExpr | command_injection.py:5:26:5:32 | After ImportMember | command_injection.py:73:19:73:30 | After BinaryExpr | This command line depends on a $@. | command_injection.py:5:26:5:32 | After ImportMember | user-provided value | +| command_injection.py:80:19:80:30 | After BinaryExpr | command_injection.py:5:26:5:32 | After ImportMember | command_injection.py:80:19:80:30 | 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-UnsafeShellCommandConstruction/UnsafeShellCommandConstruction.expected b/python/ql/test/query-tests/Security/CWE-078-UnsafeShellCommandConstruction/UnsafeShellCommandConstruction.expected index e53508f61a5a..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,38 +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:25:11:38 | ControlFlowNode for Attribute() | provenance | | -| src/unsafe_shell_test.py:4:22:4:25 | ControlFlowNode for name | src/unsafe_shell_test.py:14:25:14:40 | ControlFlowNode for Attribute() | 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: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:14:25:14:40 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| 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 2e6c5c33fbcd..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,32 +1,32 @@ 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 | 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 | 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 | 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 | +| 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 9ff8b1d718c1..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,54 +1,54 @@ edges -| 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 -| 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 | 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 | +| 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 fd9b5fe6bb65..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 @@ 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 | 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 | +| 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/ExceptionInfo.expected b/python/ql/test/query-tests/Security/CWE-209-StackTraceExposure/ExceptionInfo.expected index e69de29bb2d1..01e0f9784807 100644 --- a/python/ql/test/query-tests/Security/CWE-209-StackTraceExposure/ExceptionInfo.expected +++ b/python/ql/test/query-tests/Security/CWE-209-StackTraceExposure/ExceptionInfo.expected @@ -0,0 +1,17 @@ +| Exceptions.py:3:25:3:41 | Comment # $ exceptionInfo | Missing result: exceptionInfo | +| Exceptions.py:9:29:9:45 | Comment # $ exceptionInfo | Missing result: exceptionInfo | +| Stacktrace.py:6:57:6:73 | Comment # $ exceptionInfo | Missing result: exceptionInfo | +| Stacktrace.py:8:46:8:62 | Comment # $ exceptionInfo | Missing result: exceptionInfo | +| Stacktrace.py:9:39:9:55 | Comment # $ exceptionInfo | Missing result: exceptionInfo | +| Stacktrace.py:10:40:10:56 | Comment # $ exceptionInfo | Missing result: exceptionInfo | +| Stacktrace.py:11:75:11:91 | Comment # $ exceptionInfo | Missing result: exceptionInfo | +| Stacktrace.py:12:61:12:77 | Comment # $ exceptionInfo | Missing result: exceptionInfo | +| Stacktrace.py:13:41:13:57 | Comment # $ exceptionInfo | Missing result: exceptionInfo | +| Stacktrace.py:14:37:14:53 | Comment # $ exceptionInfo | Missing result: exceptionInfo | +| Stacktrace.py:15:47:15:63 | Comment # $ exceptionInfo | Missing result: exceptionInfo | +| test.py:16:40:16:56 | Comment # $ exceptionInfo | Missing result: exceptionInfo | +| test.py:23:29:23:45 | Comment # $ exceptionInfo | Missing result: exceptionInfo | +| test.py:31:29:31:45 | Comment # $ exceptionInfo | Missing result: exceptionInfo | +| test.py:40:38:40:54 | Comment # $ exceptionInfo | Missing result: exceptionInfo | +| test.py:49:39:49:55 | Comment # $ exceptionInfo | Missing result: exceptionInfo | +| test.py:65:28:65:44 | Comment # $ exceptionInfo | Missing result: exceptionInfo | 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 e0321cab12eb..e217064d1dfc 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,33 +1,4 @@ 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:24:66:40 | ControlFlowNode for 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 | 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() | #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 | 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 7cb9e0151907..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,100 +1,100 @@ 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:101:5:101:10 | ControlFlowNode for config | test.py:105:11:105:31 | ControlFlowNode for Subscript | provenance | | -| test.py:103:21:103:37 | ControlFlowNode for Attribute | test.py:101:5:101:10 | ControlFlowNode for config | 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:101:5:101:10 | ControlFlowNode for config | semmle.label | ControlFlowNode for config | -| test.py:103:21:103:37 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| test.py:105:11:105:31 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript | +| 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 | 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) | -| test.py:105:11:105:31 | ControlFlowNode for Subscript | test.py:103:21:103:37 | ControlFlowNode for Attribute | test.py:105:11:105:31 | ControlFlowNode for Subscript | This expression logs $@ as clear text. | test.py:103:21:103:37 | ControlFlowNode for Attribute | sensitive data (password) | +| 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 588cfae32ef5..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 @@ 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 | 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) | +| 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 c3c1206ce927..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,27 +1,27 @@ 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:9:18:13 | ControlFlowNode for lines | 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 | test.py:19:25:19:29 | ControlFlowNode for lines | 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 | semmle.label | ControlFlowNode for lines | -| 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 | 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) | +| 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 1027fbf4963c..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 @@ 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 | 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) | +| 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 bab1e34c912b..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 @@ 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 | 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 | +| 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 551299a64dc4..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 @@ 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 | 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 | +| 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 aa8cea07ed16..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 @@ 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 | 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 | +| 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 0b8756071573..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,236 +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:5:78: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: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:5:78:7 | ControlFlowNode for url | 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: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 | @@ -238,185 +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: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 810ece4f1074..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,269 +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:27:30:44 | ControlFlowNode for Dict | provenance | | -| PoC/server.py:27:5:27:10 | ControlFlowNode for author | PoC/server.py:31:34:31:51 | ControlFlowNode for Dict | 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: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:27:61:58 | ControlFlowNode for Dict | 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: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:84:5:84:9 | ControlFlowNode for group | 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 | PoC/server.py:91:29:91:47 | ControlFlowNode for Dict | provenance | | -| PoC/server.py:84:5:84:9 | ControlFlowNode for group | 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:39:30:59 | ControlFlowNode for Dict | 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_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:31:14:51 | ControlFlowNode for Dict | 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 | -| 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:26:22:46 | ControlFlowNode for Dict | 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: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:26:30:46 | ControlFlowNode for Dict | 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: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:26:38:46 | ControlFlowNode for Dict | 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: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:26:46:46 | ControlFlowNode for Dict | 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: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:29:61:49 | ControlFlowNode for Dict | 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 | -| 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:42:15:62 | ControlFlowNode for Dict | 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: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:25:59:56 | ControlFlowNode for Dict | 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: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:61:25:61:57 | ControlFlowNode for Dict | provenance | | -| pymongo_test.py:55:17:55:23 | ControlFlowNode for decoded | pymongo_test.py:62:25:62:42 | ControlFlowNode for Dict | provenance | | -| pymongo_test.py:55:17:55:23 | ControlFlowNode for decoded | pymongo_test.py:63:25:63:31 | ControlFlowNode for decoded | 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:31:34:31:51 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict | -| 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: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 | semmle.label | ControlFlowNode for group | -| PoC/server.py:91:29:91:47 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict | -| PoC/server.py:92:38:92:56 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict | -| 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_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 | -| 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: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: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: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: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 | -| 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: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:14:58:5 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict | -| 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:61:25:61:57 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict | -| pymongo_test.py:62:25:62:42 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict | -| 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..e69de29bb2d1 100644 --- a/python/ql/test/query-tests/Statements/exit/UseOfExit.expected +++ b/python/ql/test/query-tests/Statements/exit/UseOfExit.expected @@ -1 +0,0 @@ -| 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. | diff --git a/shared/controlflow/codeql/controlflow/ControlFlowGraph.qll b/shared/controlflow/codeql/controlflow/ControlFlowGraph.qll index fff877b9fcd9..dd71b5f98c79 100644 --- a/shared/controlflow/codeql/controlflow/ControlFlowGraph.qll +++ b/shared/controlflow/codeql/controlflow/ControlFlowGraph.qll @@ -211,6 +211,20 @@ 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() } + /** A catch clause in a try statement. */ class CatchClause extends AstNode { /** Gets the variable declared by this catch clause. */ @@ -1549,19 +1563,32 @@ module Make0 Ast> { n2.isBefore(loopstmt.getBody()) or n1.isAfterFalse(cond) and - n2.isAfter(loopstmt) + ( + 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 @@ -1574,10 +1601,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 |