diff --git a/MODULE.bazel b/MODULE.bazel index 9b326127ce7..5ace37479cb 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -28,7 +28,7 @@ bazel_dep(name = "rules_kotlin", version = "2.2.0-codeql.1") bazel_dep(name = "gazelle", version = "0.40.0") bazel_dep(name = "rules_dotnet", version = "0.21.5-codeql.1") bazel_dep(name = "googletest", version = "1.14.0.bcr.1") -bazel_dep(name = "rules_rust", version = "0.66.0") +bazel_dep(name = "rules_rust", version = "0.68.1.codeql.1") bazel_dep(name = "zstd", version = "1.5.5.bcr.1") bazel_dep(name = "buildifier_prebuilt", version = "6.4.0", dev_dependency = True) @@ -41,7 +41,7 @@ RUST_EDITION = "2024" # a nightly toolchain is required to enable experimental_use_cc_common_link, which we require internally # we prefer to run the same version as internally, even if experimental_use_cc_common_link is not really # required in this repo -RUST_VERSION = "nightly/2025-08-01" +RUST_VERSION = "nightly/2026-01-22" rust = use_extension("@rules_rust//rust:extensions.bzl", "rust") rust.toolchain( @@ -53,26 +53,26 @@ rust.toolchain( ], # generated by buildutils-internal/scripts/fill-rust-sha256s.py (internal repo) sha256s = { - "2025-08-01/rustc-nightly-x86_64-unknown-linux-gnu.tar.xz": "9bbeaf5d3fc7247d31463a9083aa251c995cc50662c8219e7a2254d76a72a9a4", - "2025-08-01/rustc-nightly-x86_64-apple-darwin.tar.xz": "c9ea539a8eff0d5d162701f99f9e1aabe14dd0dfb420d62362817a5d09219de7", - "2025-08-01/rustc-nightly-aarch64-apple-darwin.tar.xz": "ae83feebbc39cfd982e4ecc8297731fe79c185173aee138467b334c5404b3773", - "2025-08-01/rustc-nightly-x86_64-pc-windows-msvc.tar.xz": "9f170c30d802a349be60cf52ec46260802093cb1013ad667fc0d528b7b10152f", - "2025-08-01/clippy-nightly-x86_64-unknown-linux-gnu.tar.xz": "9ae5f3cd8f557c4f6df522597c69d14398cf604cfaed2b83e767c4b77a7eaaf6", - "2025-08-01/clippy-nightly-x86_64-apple-darwin.tar.xz": "983cb9ee0b6b968188e04ab2d33743d54764b2681ce565e1b3f2b9135c696a3e", - "2025-08-01/clippy-nightly-aarch64-apple-darwin.tar.xz": "ed2219dbc49d088225e1b7c5c4390fa295066e071fddaa2714018f6bb39ddbf0", - "2025-08-01/clippy-nightly-x86_64-pc-windows-msvc.tar.xz": "911f40ab5cbdd686f40e00965271fe47c4805513a308ed01f30eafb25b448a50", - "2025-08-01/cargo-nightly-x86_64-unknown-linux-gnu.tar.xz": "106463c284e48e4904c717471eeec2be5cc83a9d2cae8d6e948b52438cad2e69", - "2025-08-01/cargo-nightly-x86_64-apple-darwin.tar.xz": "6ad35c40efc41a8c531ea43235058347b6902d98a9693bf0aed7fc16d5590cef", - "2025-08-01/cargo-nightly-aarch64-apple-darwin.tar.xz": "dd28c365e9d298abc3154c797720ad36a0058f131265c9978b4c8e4e37012c8a", - "2025-08-01/cargo-nightly-x86_64-pc-windows-msvc.tar.xz": "7b431286e12d6b3834b038f078389a00cac73f351e8c3152b2504a3c06420b3b", - "2025-08-01/llvm-tools-nightly-x86_64-unknown-linux-gnu.tar.xz": "e342e305d7927cc288d386983b2bc253cfad3776b113386e903d0b302648ef47", - "2025-08-01/llvm-tools-nightly-x86_64-apple-darwin.tar.xz": "e44dd3506524d85c37b3a54bcc91d01378fd2c590b2db5c5974d12f05c1b84d1", - "2025-08-01/llvm-tools-nightly-aarch64-apple-darwin.tar.xz": "0c1b5f46dd81be4a9227b10283a0fcaa39c14fea7e81aea6fd6d9887ff6cdc41", - "2025-08-01/llvm-tools-nightly-x86_64-pc-windows-msvc.tar.xz": "423e5fd11406adccbc31b8456ceb7375ce055cdf45e90d2c3babeb2d7f58383f", - "2025-08-01/rust-std-nightly-x86_64-unknown-linux-gnu.tar.xz": "3c0ceb46a252647a1d4c7116d9ccae684fa5e42aaf3296419febd2c962c3b41d", - "2025-08-01/rust-std-nightly-x86_64-apple-darwin.tar.xz": "3be416003cab10f767390a753d1d16ae4d26c7421c03c98992cf1943e5b0efe8", - "2025-08-01/rust-std-nightly-aarch64-apple-darwin.tar.xz": "4046ac0ef951cb056b5028a399124f60999fa37792eab69d008d8d7965f389b4", - "2025-08-01/rust-std-nightly-x86_64-pc-windows-msvc.tar.xz": "191ed9d8603c3a4fe5a7bbbc2feb72049078dae2df3d3b7d5dedf3abbf823e6e", + "2026-01-22/rustc-nightly-x86_64-unknown-linux-gnu.tar.xz": "88db619323cc1321630d124efa51ed02fabc5e020f08cfa0eda2c0ac1afbe69a", + "2026-01-22/rustc-nightly-x86_64-apple-darwin.tar.xz": "08484da3fa38db56f93629aeabdc0ae9ff8ed9704c0792d35259cbc849b3f54c", + "2026-01-22/rustc-nightly-aarch64-apple-darwin.tar.xz": "a39c0b21b7058e364ea1bd43144e42e4bf1efade036b2e82455f2afce194ee81", + "2026-01-22/rustc-nightly-x86_64-pc-windows-msvc.tar.xz": "d00248ee9850dbb6932b2578e32ff74fc7c429854c1aa071066ca31b65385a3b", + "2026-01-22/clippy-nightly-x86_64-unknown-linux-gnu.tar.xz": "70656a0ce994ffff16d5a35a7b170a0acd41e9bb54a589c96ed45bf97b094a4d", + "2026-01-22/clippy-nightly-x86_64-apple-darwin.tar.xz": "fe242519fa961522734733009705aec3c2d9a20cc57291f2aa614e5e6262c88f", + "2026-01-22/clippy-nightly-aarch64-apple-darwin.tar.xz": "38bb226363ec97c9722edf966cd58774a683e19fd2ff2a6030094445d51e06f9", + "2026-01-22/clippy-nightly-x86_64-pc-windows-msvc.tar.xz": "6da9b4470beea67abfebf046f141eee0d2a8db7c7a9e4e2294478734fd477228", + "2026-01-22/cargo-nightly-x86_64-unknown-linux-gnu.tar.xz": "99004e9d10c43a01499642f53bb3184d41137a95d65bfb217098840a9e79e892", + "2026-01-22/cargo-nightly-x86_64-apple-darwin.tar.xz": "6e021394cf8d8400ac6cfdfcef24e4d74f988e91eb8028b36de3a64ce3502990", + "2026-01-22/cargo-nightly-aarch64-apple-darwin.tar.xz": "4b2494cb69ab64132cddbc411a38ea9f1105e54d6f986e43168d54f79510c673", + "2026-01-22/cargo-nightly-x86_64-pc-windows-msvc.tar.xz": "c36613cf57407212d10d37b76e49a60ff42336e953cdff9e177283f530a83fc1", + "2026-01-22/llvm-tools-nightly-x86_64-unknown-linux-gnu.tar.xz": "0b123c5027dbd833aae6845ffe9bd07d309bf798746a7176aadaea68fbcbd05d", + "2026-01-22/llvm-tools-nightly-x86_64-apple-darwin.tar.xz": "a47864491ad5619158c950ab7570fb6e487d5117338585c27334d45824b406d8", + "2026-01-22/llvm-tools-nightly-aarch64-apple-darwin.tar.xz": "db9bc826d6e2e7e914505d50157682e516ceb90357e83d77abddc32c2d962f41", + "2026-01-22/llvm-tools-nightly-x86_64-pc-windows-msvc.tar.xz": "ffaa406932b2fe62e01dad61cf4ed34860a5d2a6f9306ca340d79e630d930039", + "2026-01-22/rust-std-nightly-x86_64-unknown-linux-gnu.tar.xz": "e9c0d5e06e18a4b509391b3088f29293e310cdc8ccc865be8fa3f09733326925", + "2026-01-22/rust-std-nightly-x86_64-apple-darwin.tar.xz": "25d75995cee679a4828ca9fe48c5a31a67c3b0846018440ef912e5a6208f53f6", + "2026-01-22/rust-std-nightly-aarch64-apple-darwin.tar.xz": "e4132bf3f2eed4684c86756a02315bcf481c23e675e3e25630fc604c9cb4594c", + "2026-01-22/rust-std-nightly-x86_64-pc-windows-msvc.tar.xz": "961bb535ef95ae8a5fa4e224cb94aff190f155c45a9bcf7a53e184b024aa41b1", }, versions = [RUST_VERSION], ) diff --git a/cpp/ql/lib/change-notes/2026-02-14-must-flow-fix.md b/cpp/ql/lib/change-notes/2026-02-14-must-flow-fix.md new file mode 100644 index 00000000000..fc838f51c06 --- /dev/null +++ b/cpp/ql/lib/change-notes/2026-02-14-must-flow-fix.md @@ -0,0 +1,4 @@ +--- +category: fix +--- +* The `allowInterproceduralFlow` predicate of must-flow data flow configurations now correctly handles direct recursion. diff --git a/cpp/ql/lib/change-notes/2026-02-14-must-flow.md b/cpp/ql/lib/change-notes/2026-02-14-must-flow.md new file mode 100644 index 00000000000..3d1afaa6344 --- /dev/null +++ b/cpp/ql/lib/change-notes/2026-02-14-must-flow.md @@ -0,0 +1,4 @@ +--- +category: breaking +--- +* `MustFlow`, the inter-procedural must-flow data flow analysis library, has been re-worked to use parameterized modules. Like in the case of data flow and taint tracking, instead of extending the `MustFlowConfiguration` class, the user should now implement a module with the `MustFlow::ConfigSig` signature, and instantiate the `MustFlow::Global` parameterized module with the implemented module. diff --git a/cpp/ql/lib/semmle/code/cpp/internal/Overlay.qll b/cpp/ql/lib/semmle/code/cpp/internal/Overlay.qll index 7e98177f323..3dea144bbf6 100644 --- a/cpp/ql/lib/semmle/code/cpp/internal/Overlay.qll +++ b/cpp/ql/lib/semmle/code/cpp/internal/Overlay.qll @@ -34,6 +34,38 @@ private string getSingleLocationFilePath(@element e) { macroinvocations(e, _, loc, _) or preprocdirects(e, _, loc) + or + diagnostics(e, _, _, _, _, loc) + or + usings(e, _, loc, _) + or + static_asserts(e, _, _, loc, _) + or + derivations(e, _, _, _, loc) + or + frienddecls(e, _, _, loc) + or + comments(e, _, loc) + or + exprs(e, _, loc) + or + stmts(e, _, loc) + or + initialisers(e, _, _, loc) + or + attributes(e, _, _, _, loc) + or + attribute_args(e, _, _, _, loc) + or + namequalifiers(e, _, _, loc) + or + enumconstants(e, _, _, _, _, loc) + or + type_mentions(e, _, loc, _) + or + lambda_capture(e, _, _, _, _, _, loc) + or + concept_templates(e, _, loc) | result = getLocationFilePath(loc) ) diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/MustFlow.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/MustFlow.qll index b085440f6bc..2b61190fb71 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/MustFlow.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/MustFlow.qll @@ -8,81 +8,143 @@ private import cpp private import semmle.code.cpp.ir.IR /** - * A configuration of a data flow analysis that performs must-flow analysis. This is different - * from `DataFlow.qll` which performs may-flow analysis (i.e., it finds paths where the source _may_ - * flow to the sink). - * - * Like in `DataFlow.qll`, each use of the `MustFlow.qll` library must define its own unique extension - * of this abstract class. To create a configuration, extend this class with a subclass whose - * characteristic predicate is a unique singleton string and override `isSource`, `isSink` (and - * `isAdditionalFlowStep` if additional steps are required). + * Provides an inter-procedural must-flow data flow analysis. */ -abstract class MustFlowConfiguration extends string { - bindingset[this] - MustFlowConfiguration() { any() } - +module MustFlow { /** - * Holds if `source` is a relevant data flow source. + * An input configuration of a data flow analysis that performs must-flow analysis. This is different + * from `DataFlow.qll` which performs may-flow analysis (i.e., it finds paths where the source _may_ + * flow to the sink). */ - abstract predicate isSource(Instruction source); + signature module ConfigSig { + /** + * Holds if `source` is a relevant data flow source. + */ + predicate isSource(Instruction source); - /** - * Holds if `sink` is a relevant data flow sink. - */ - abstract predicate isSink(Operand sink); + /** + * Holds if `sink` is a relevant data flow sink. + */ + predicate isSink(Operand sink); - /** - * Holds if data flow through `instr` is prohibited. - */ - predicate isBarrier(Instruction instr) { none() } + /** + * Holds if data flow through `instr` is prohibited. + */ + default predicate isBarrier(Instruction instr) { none() } - /** - * Holds if the additional flow step from `node1` to `node2` must be taken - * into account in the analysis. - */ - predicate isAdditionalFlowStep(Operand node1, Instruction node2) { none() } + /** + * Holds if the additional flow step from `node1` to `node2` must be taken + * into account in the analysis. + */ + default predicate isAdditionalFlowStep(Operand node1, Instruction node2) { none() } - /** Holds if this configuration allows flow from arguments to parameters. */ - predicate allowInterproceduralFlow() { any() } - - /** - * Holds if data must flow from `source` to `sink` for this configuration. - * - * The corresponding paths are generated from the end-points and the graph - * included in the module `PathGraph`. - */ - final predicate hasFlowPath(MustFlowPathNode source, MustFlowPathSink sink) { - this.isSource(source.getInstruction()) and - source.getASuccessor*() = sink + /** Holds if this configuration allows flow from arguments to parameters. */ + default predicate allowInterproceduralFlow() { any() } } -} -/** Holds if `node` flows from a source. */ -pragma[nomagic] -private predicate flowsFromSource(Instruction node, MustFlowConfiguration config) { - not config.isBarrier(node) and - ( - config.isSource(node) - or - exists(Instruction mid | - step(mid, node, config) and - flowsFromSource(mid, pragma[only_bind_into](config)) - ) - ) -} + /** + * Constructs a global must-flow computation. + */ + module Global { + import Config -/** Holds if `node` flows to a sink. */ -pragma[nomagic] -private predicate flowsToSink(Instruction node, MustFlowConfiguration config) { - flowsFromSource(node, pragma[only_bind_into](config)) and - ( - config.isSink(node.getAUse()) - or - exists(Instruction mid | - step(node, mid, config) and - flowsToSink(mid, pragma[only_bind_into](config)) - ) - ) + /** + * Holds if data must flow from `source` to `sink`. + * + * The corresponding paths are generated from the end-points and the graph + * included in the module `PathGraph`. + */ + predicate flowPath(PathNode source, PathSink sink) { + isSource(source.getInstruction()) and + source.getASuccessor*() = sink + } + + /** Holds if `node` flows from a source. */ + pragma[nomagic] + private predicate flowsFromSource(Instruction node) { + not isBarrier(node) and + ( + isSource(node) + or + exists(Instruction mid | + step(mid, node) and + flowsFromSource(mid) + ) + ) + } + + /** Holds if `node` flows to a sink. */ + pragma[nomagic] + private predicate flowsToSink(Instruction node) { + flowsFromSource(node) and + ( + isSink(node.getAUse()) + or + exists(Instruction mid | + step(node, mid) and + flowsToSink(mid) + ) + ) + } + + /** Holds if `nodeFrom` flows to `nodeTo`. */ + private predicate step(Instruction nodeFrom, Instruction nodeTo) { + Cached::localStep(nodeFrom, nodeTo) + or + allowInterproceduralFlow() and + Cached::flowThroughCallable(nodeFrom, nodeTo) + or + isAdditionalFlowStep(nodeFrom.getAUse(), nodeTo) + } + + private newtype TLocalPathNode = + MkLocalPathNode(Instruction n) { + flowsToSink(n) and + ( + isSource(n) + or + exists(PathNode mid | step(mid.getInstruction(), n)) + ) + } + + /** A `Node` that is in a path from a source to a sink. */ + class PathNode extends TLocalPathNode { + Instruction n; + + PathNode() { this = MkLocalPathNode(n) } + + /** Gets the underlying node. */ + Instruction getInstruction() { result = n } + + /** Gets a textual representation of this node. */ + string toString() { result = n.getAst().toString() } + + /** Gets the location of this element. */ + Location getLocation() { result = n.getLocation() } + + /** Gets a successor node, if any. */ + PathNode getASuccessor() { step(this.getInstruction(), result.getInstruction()) } + } + + private class PathSink extends PathNode { + PathSink() { isSink(this.getInstruction().getAUse()) } + } + + /** + * Provides the query predicates needed to include a graph in a path-problem query. + */ + module PathGraph { + private predicate reach(PathNode n) { n instanceof PathSink or reach(n.getASuccessor()) } + + /** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */ + query predicate edges(PathNode a, PathNode b) { a.getASuccessor() = b and reach(b) } + + /** Holds if `n` is a node in the graph of data flow path explanations. */ + query predicate nodes(PathNode n, string key, string val) { + reach(n) and key = "semmle.label" and val = n.toString() + } + } + } } cached @@ -102,7 +164,7 @@ private module Cached { not f.isVirtual() and call.getPositionalArgument(n) = instr and f = call.getStaticCallTarget() and - getEnclosingNonVirtualFunctionInitializeParameter(init, f) and + isEnclosingNonVirtualFunctionInitializeParameter(init, f) and init.getParameter().getIndex() = pragma[only_bind_into](pragma[only_bind_out](n)) } @@ -111,7 +173,7 @@ private module Cached { * corresponding initialization instruction that receives the value of `instr` in `f`. */ pragma[noinline] - private predicate getPositionalArgumentInitParam( + private predicate isPositionalArgumentInitParam( CallInstruction call, Instruction instr, InitializeParameterInstruction init, Function f ) { exists(int n | @@ -126,18 +188,18 @@ private module Cached { * `instr` in `f`. */ pragma[noinline] - private predicate getThisArgumentInitParam( + private predicate isThisArgumentInitParam( CallInstruction call, Instruction instr, InitializeParameterInstruction init, Function f ) { not f.isVirtual() and call.getStaticCallTarget() = f and - getEnclosingNonVirtualFunctionInitializeParameter(init, f) and + isEnclosingNonVirtualFunctionInitializeParameter(init, f) and call.getThisArgument() = instr and init.getIRVariable() instanceof IRThisVariable } /** Holds if `f` is the enclosing non-virtual function of `init`. */ - private predicate getEnclosingNonVirtualFunctionInitializeParameter( + private predicate isEnclosingNonVirtualFunctionInitializeParameter( InitializeParameterInstruction init, Function f ) { not f.isVirtual() and @@ -145,7 +207,7 @@ private module Cached { } /** Holds if `f` is the enclosing non-virtual function of `init`. */ - private predicate getEnclosingNonVirtualFunctionInitializeIndirection( + private predicate isEnclosingNonVirtualFunctionInitializeIndirection( InitializeIndirectionInstruction init, Function f ) { not f.isVirtual() and @@ -153,15 +215,16 @@ private module Cached { } /** - * Holds if `instr` is an argument (or argument indirection) to a call, and - * `succ` is the corresponding initialization instruction in the call target. + * Holds if `argument` is an argument (or argument indirection) to a call, and + * `parameter` is the corresponding initialization instruction in the call target. */ - private predicate flowThroughCallable(Instruction argument, Instruction parameter) { + cached + predicate flowThroughCallable(Instruction argument, Instruction parameter) { // Flow from an argument to a parameter exists(CallInstruction call, InitializeParameterInstruction init | init = parameter | - getPositionalArgumentInitParam(call, argument, init, call.getStaticCallTarget()) + isPositionalArgumentInitParam(call, argument, init, call.getStaticCallTarget()) or - getThisArgumentInitParam(call, argument, init, call.getStaticCallTarget()) + isThisArgumentInitParam(call, argument, init, call.getStaticCallTarget()) ) or // Flow from argument indirection to parameter indirection @@ -170,7 +233,7 @@ private module Cached { | init = parameter and read.getPrimaryInstruction() = call and - getEnclosingNonVirtualFunctionInitializeIndirection(init, call.getStaticCallTarget()) + isEnclosingNonVirtualFunctionInitializeIndirection(init, call.getStaticCallTarget()) | exists(int n | read.getSideEffectOperand().getAnyDef() = argument and @@ -205,92 +268,10 @@ private module Cached { } cached - predicate step(Instruction nodeFrom, Instruction nodeTo) { + predicate localStep(Instruction nodeFrom, Instruction nodeTo) { exists(Operand mid | instructionToOperandStep(nodeFrom, mid) and operandToInstructionStep(mid, nodeTo) ) - or - flowThroughCallable(nodeFrom, nodeTo) - } -} - -/** - * Gets the enclosing callable of `n`. Unlike `n.getEnclosingCallable()`, this - * predicate ensures that joins go from `n` to the result instead of the other - * way around. - */ -pragma[inline] -private IRFunction getEnclosingCallable(Instruction n) { - pragma[only_bind_into](result) = pragma[only_bind_out](n).getEnclosingIRFunction() -} - -/** Holds if `nodeFrom` flows to `nodeTo`. */ -private predicate step(Instruction nodeFrom, Instruction nodeTo, MustFlowConfiguration config) { - exists(config) and - Cached::step(pragma[only_bind_into](nodeFrom), pragma[only_bind_into](nodeTo)) and - ( - config.allowInterproceduralFlow() - or - getEnclosingCallable(nodeFrom) = getEnclosingCallable(nodeTo) - ) - or - config.isAdditionalFlowStep(nodeFrom.getAUse(), nodeTo) -} - -private newtype TLocalPathNode = - MkLocalPathNode(Instruction n, MustFlowConfiguration config) { - flowsToSink(n, config) and - ( - config.isSource(n) - or - exists(MustFlowPathNode mid | step(mid.getInstruction(), n, config)) - ) - } - -/** A `Node` that is in a path from a source to a sink. */ -class MustFlowPathNode extends TLocalPathNode { - Instruction n; - - MustFlowPathNode() { this = MkLocalPathNode(n, _) } - - /** Gets the underlying node. */ - Instruction getInstruction() { result = n } - - /** Gets a textual representation of this node. */ - string toString() { result = n.getAst().toString() } - - /** Gets the location of this element. */ - Location getLocation() { result = n.getLocation() } - - /** Gets a successor node, if any. */ - MustFlowPathNode getASuccessor() { - step(this.getInstruction(), result.getInstruction(), this.getConfiguration()) - } - - /** Gets the associated configuration. */ - MustFlowConfiguration getConfiguration() { this = MkLocalPathNode(_, result) } -} - -private class MustFlowPathSink extends MustFlowPathNode { - MustFlowPathSink() { this.getConfiguration().isSink(this.getInstruction().getAUse()) } -} - -/** - * Provides the query predicates needed to include a graph in a path-problem query. - */ -module PathGraph { - private predicate reach(MustFlowPathNode n) { - n instanceof MustFlowPathSink or reach(n.getASuccessor()) - } - - /** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */ - query predicate edges(MustFlowPathNode a, MustFlowPathNode b) { - a.getASuccessor() = b and reach(b) - } - - /** Holds if `n` is a node in the graph of data flow path explanations. */ - query predicate nodes(MustFlowPathNode n, string key, string val) { - reach(n) and key = "semmle.label" and val = n.toString() } } diff --git a/cpp/ql/src/Likely Bugs/Memory Management/ReturnStackAllocatedMemory.ql b/cpp/ql/src/Likely Bugs/Memory Management/ReturnStackAllocatedMemory.ql index b8788910332..efd136bcd2d 100644 --- a/cpp/ql/src/Likely Bugs/Memory Management/ReturnStackAllocatedMemory.ql +++ b/cpp/ql/src/Likely Bugs/Memory Management/ReturnStackAllocatedMemory.ql @@ -16,17 +16,15 @@ import cpp import semmle.code.cpp.ir.IR import semmle.code.cpp.ir.dataflow.MustFlow -import PathGraph +import ReturnStackAllocatedMemory::PathGraph /** Holds if `f` has a name that we interpret as evidence of intentionally returning the value of the stack pointer. */ predicate intentionallyReturnsStackPointer(Function f) { f.getName().toLowerCase().matches(["%stack%", "%sp%"]) } -class ReturnStackAllocatedMemoryConfig extends MustFlowConfiguration { - ReturnStackAllocatedMemoryConfig() { this = "ReturnStackAllocatedMemoryConfig" } - - override predicate isSource(Instruction source) { +module ReturnStackAllocatedMemoryConfig implements MustFlow::ConfigSig { + predicate isSource(Instruction source) { exists(Function func | // Rule out FPs caused by extraction errors. not func.hasErrors() and @@ -50,7 +48,7 @@ class ReturnStackAllocatedMemoryConfig extends MustFlowConfiguration { ) } - override predicate isSink(Operand sink) { + predicate isSink(Operand sink) { // Holds if `sink` is a node that represents the `StoreInstruction` that is subsequently used in // a `ReturnValueInstruction`. // We use the `StoreInstruction` instead of the instruction that defines the @@ -72,7 +70,7 @@ class ReturnStackAllocatedMemoryConfig extends MustFlowConfiguration { // int* px = id(&x); // } // ``` - override predicate allowInterproceduralFlow() { none() } + predicate allowInterproceduralFlow() { none() } /** * This configuration intentionally conflates addresses of fields and their object, and pointer offsets @@ -87,20 +85,22 @@ class ReturnStackAllocatedMemoryConfig extends MustFlowConfiguration { * } * ``` */ - override predicate isAdditionalFlowStep(Operand node1, Instruction node2) { + predicate isAdditionalFlowStep(Operand node1, Instruction node2) { node2.(FieldAddressInstruction).getObjectAddressOperand() = node1 or node2.(PointerOffsetInstruction).getLeftOperand() = node1 } - override predicate isBarrier(Instruction n) { n.getResultType() instanceof ErroneousType } + predicate isBarrier(Instruction n) { n.getResultType() instanceof ErroneousType } } +module ReturnStackAllocatedMemory = MustFlow::Global; + from - MustFlowPathNode source, MustFlowPathNode sink, Instruction instr, - ReturnStackAllocatedMemoryConfig conf + ReturnStackAllocatedMemory::PathNode source, ReturnStackAllocatedMemory::PathNode sink, + Instruction instr where - conf.hasFlowPath(pragma[only_bind_into](source), pragma[only_bind_into](sink)) and + ReturnStackAllocatedMemory::flowPath(pragma[only_bind_into](source), pragma[only_bind_into](sink)) and source.getInstruction() = instr select sink.getInstruction(), source, sink, "May return stack-allocated memory from $@.", instr.getAst(), instr.getAst().toString() diff --git a/cpp/ql/src/Likely Bugs/Memory Management/UninitializedLocal.ql b/cpp/ql/src/Likely Bugs/Memory Management/UninitializedLocal.ql index 763a142f1b9..1697ad31810 100644 --- a/cpp/ql/src/Likely Bugs/Memory Management/UninitializedLocal.ql +++ b/cpp/ql/src/Likely Bugs/Memory Management/UninitializedLocal.ql @@ -15,7 +15,7 @@ import cpp import semmle.code.cpp.ir.IR import semmle.code.cpp.ir.dataflow.MustFlow -import PathGraph +import UninitializedLocal::PathGraph /** * Auxiliary predicate: Types that don't require initialization @@ -70,25 +70,26 @@ predicate isSinkImpl(Instruction sink, VariableAccess va) { ) } -class MustFlow extends MustFlowConfiguration { - MustFlow() { this = "MustFlow" } - - override predicate isSource(Instruction source) { +module UninitializedLocalConfig implements MustFlow::ConfigSig { + predicate isSource(Instruction source) { source instanceof UninitializedInstruction and exists(Type t | t = source.getResultType() | not allocatedType(t)) } - override predicate isSink(Operand sink) { isSinkImpl(sink.getDef(), _) } + predicate isSink(Operand sink) { isSinkImpl(sink.getDef(), _) } - override predicate allowInterproceduralFlow() { none() } + predicate allowInterproceduralFlow() { none() } - override predicate isBarrier(Instruction instr) { instr instanceof ChiInstruction } + predicate isBarrier(Instruction instr) { instr instanceof ChiInstruction } } +module UninitializedLocal = MustFlow::Global; + from - VariableAccess va, LocalVariable v, MustFlow conf, MustFlowPathNode source, MustFlowPathNode sink + VariableAccess va, LocalVariable v, UninitializedLocal::PathNode source, + UninitializedLocal::PathNode sink where - conf.hasFlowPath(source, sink) and + UninitializedLocal::flowPath(source, sink) and isSinkImpl(sink.getInstruction(), va) and v = va.getTarget() select va, source, sink, "The variable $@ may not be initialized at this access.", v, v.getName() diff --git a/cpp/ql/src/Likely Bugs/OO/UnsafeUseOfThis.ql b/cpp/ql/src/Likely Bugs/OO/UnsafeUseOfThis.ql index bb62cfc1755..63b56d470e2 100644 --- a/cpp/ql/src/Likely Bugs/OO/UnsafeUseOfThis.ql +++ b/cpp/ql/src/Likely Bugs/OO/UnsafeUseOfThis.ql @@ -17,16 +17,16 @@ import cpp import semmle.code.cpp.ir.IR import semmle.code.cpp.ir.dataflow.MustFlow -import PathGraph +import UnsafeUseOfThis::PathGraph -class UnsafeUseOfThisConfig extends MustFlowConfiguration { - UnsafeUseOfThisConfig() { this = "UnsafeUseOfThisConfig" } +module UnsafeUseOfThisConfig implements MustFlow::ConfigSig { + predicate isSource(Instruction source) { isSource(source, _, _) } - override predicate isSource(Instruction source) { isSource(source, _, _) } - - override predicate isSink(Operand sink) { isSink(sink, _) } + predicate isSink(Operand sink) { isSink(sink, _) } } +module UnsafeUseOfThis = MustFlow::Global; + /** Holds if `sink` is a `this` pointer used by the call instruction `call`. */ predicate isSink(Operand sink, CallInstruction call) { exists(PureVirtualFunction func | @@ -66,19 +66,17 @@ predicate isSource(InitializeParameterInstruction source, string msg, Class c) { * - `msg` is a string describing whether `source` is from a constructor or destructor. */ predicate flows( - MustFlowPathNode source, string msg, Class sourceClass, MustFlowPathNode sink, + UnsafeUseOfThis::PathNode source, string msg, Class sourceClass, UnsafeUseOfThis::PathNode sink, CallInstruction call ) { - exists(UnsafeUseOfThisConfig conf | - conf.hasFlowPath(source, sink) and - isSource(source.getInstruction(), msg, sourceClass) and - isSink(sink.getInstruction().getAUse(), call) - ) + UnsafeUseOfThis::flowPath(source, sink) and + isSource(source.getInstruction(), msg, sourceClass) and + isSink(sink.getInstruction().getAUse(), call) } from - MustFlowPathNode source, MustFlowPathNode sink, CallInstruction call, string msg, - Class sourceClass + UnsafeUseOfThis::PathNode source, UnsafeUseOfThis::PathNode sink, CallInstruction call, + string msg, Class sourceClass where flows(source, msg, sourceClass, sink, call) and // Only raise an alert if there is no override of the pure virtual function in any base class. diff --git a/cpp/ql/test/query-tests/Likely Bugs/Memory Management/ReturnStackAllocatedMemory/test.cpp b/cpp/ql/test/query-tests/Likely Bugs/Memory Management/ReturnStackAllocatedMemory/test.cpp index abc21aa74d8..07e3520fa81 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Memory Management/ReturnStackAllocatedMemory/test.cpp +++ b/cpp/ql/test/query-tests/Likely Bugs/Memory Management/ReturnStackAllocatedMemory/test.cpp @@ -250,3 +250,8 @@ void* test_strndupa(const char* s, size_t size) { return s2; // BAD } +int* f_rec(int *p) { + int x; + int* px = f_rec(&x); // GOOD + return p; +} diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Event.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Event.cs index bbd90989617..c93df9ccc4f 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Event.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Event.cs @@ -11,6 +11,10 @@ namespace Semmle.Extraction.CSharp.Entities private Event(Context cx, IEventSymbol init) : base(cx, init) { } + protected override IEventSymbol BodyDeclaringSymbol => Symbol.PartialImplementationPart ?? Symbol; + + public override Microsoft.CodeAnalysis.Location? ReportingLocation => BodyDeclaringSymbol.Locations.BestOrDefault(); + public override void WriteId(EscapingTextWriter trapFile) { trapFile.WriteSubId(ContainingType!); @@ -27,13 +31,13 @@ namespace Semmle.Extraction.CSharp.Entities var type = Type.Create(Context, Symbol.Type); trapFile.events(this, Symbol.GetName(), ContainingType!, type.TypeRef, Create(Context, Symbol.OriginalDefinition)); - var adder = Symbol.AddMethod; - var remover = Symbol.RemoveMethod; + var adder = BodyDeclaringSymbol.AddMethod; + var remover = BodyDeclaringSymbol.RemoveMethod; - if (!(adder is null)) + if (adder is not null) Method.Create(Context, adder); - if (!(remover is null)) + if (remover is not null) Method.Create(Context, remover); PopulateModifiers(trapFile); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/EventAccessor.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/EventAccessor.cs index 254e7c76956..3e8ab9431be 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/EventAccessor.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/EventAccessor.cs @@ -13,6 +13,10 @@ namespace Semmle.Extraction.CSharp.Entities this.@event = @event; } + public override bool NeedsPopulation => + base.NeedsPopulation && + !Symbol.IsPartialDefinition; // Accessors always have an implementing declaration as well. + /// /// Gets the event symbol associated with accessor `symbol`, or `null` /// if there is no associated symbol. diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Factory.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Factory.cs index 0da8de1e5d5..ed8dae3738f 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Factory.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Factory.cs @@ -160,6 +160,9 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions case SyntaxKind.ThisExpression: return This.CreateExplicit(info); + case SyntaxKind.FieldExpression: + return PropertyFieldAccess.Create(info); + case SyntaxKind.AddressOfExpression: return Unary.Create(info.SetKind(ExprKind.ADDRESS_OF)); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/PropertyFieldAccess.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/PropertyFieldAccess.cs new file mode 100644 index 00000000000..a9d2afa84c9 --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/PropertyFieldAccess.cs @@ -0,0 +1,28 @@ +using System.IO; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Semmle.Extraction.Kinds; + +namespace Semmle.Extraction.CSharp.Entities.Expressions +{ + internal class PropertyFieldAccess : Expression + { + private PropertyFieldAccess(ExpressionNodeInfo info) : base(info.SetKind(ExprKind.FIELD_ACCESS)) { } + + public static Expression Create(ExpressionNodeInfo info) => new PropertyFieldAccess(info).TryPopulate(); + + protected override void PopulateExpression(TextWriter trapFile) + { + var symbolInfo = Context.GetSymbolInfo(Syntax); + if (symbolInfo.Symbol is IFieldSymbol field) + { + var target = PropertyField.Create(Context, field); + trapFile.expr_access(this, target); + if (!field.IsStatic) + { + This.CreateImplicit(Context, field.ContainingType, Location, this, -1); + } + } + } + } +} diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Field.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Field.cs index 9a010aad376..329115f11c7 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Field.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Field.cs @@ -10,7 +10,7 @@ namespace Semmle.Extraction.CSharp.Entities { internal class Field : CachedSymbol, IExpressionParentEntity { - private Field(Context cx, IFieldSymbol init) + protected Field(Context cx, IFieldSymbol init) : base(cx, init) { type = new Lazy(() => Entities.Type.Create(cx, Symbol.Type)); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PropertyField.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PropertyField.cs new file mode 100644 index 00000000000..9e9b1f41fff --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PropertyField.cs @@ -0,0 +1,53 @@ +using System.IO; +using Microsoft.CodeAnalysis; +using Semmle.Extraction.CSharp.Util; +using Semmle.Extraction.Kinds; + +namespace Semmle.Extraction.CSharp.Entities +{ + /// + /// Represents the autogenerated backing field `field` for a property. + /// It is only created for properties that use the `field` keyword in their getter or setter, and + /// is not created for auto-properties. + /// + internal class PropertyField : Field + { + protected PropertyField(Context cx, IFieldSymbol init) + : base(cx, init) + { + } + + public static new PropertyField Create(Context cx, IFieldSymbol field) => PropertyFieldFactory.Instance.CreateEntity(cx, (field, field.AssociatedSymbol), field); + + public override bool NeedsPopulation => true; + + public override void Populate(TextWriter trapFile) + { + PopulateNullability(trapFile, Symbol.GetAnnotatedType()); + + var unboundFieldKey = PropertyField.Create(Context, Symbol.OriginalDefinition); + var name = Symbol.AssociatedSymbol is not null ? $"{Symbol.AssociatedSymbol.GetName()}.field" : Symbol.Name; + trapFile.fields(this, VariableKind.None, name, ContainingType!, Type.TypeRef, unboundFieldKey); + trapFile.compiler_generated(this); + + PopulateModifiers(trapFile); + + if (Context.OnlyScaffold) + { + return; + } + + if (Context.ExtractLocation(Symbol)) + { + WriteLocationsToTrap(trapFile.field_location, this, Locations); + } + } + + private class PropertyFieldFactory : CachedEntityFactory + { + public static PropertyFieldFactory Instance { get; } = new PropertyFieldFactory(); + + public override PropertyField Create(Context cx, IFieldSymbol init) => new PropertyField(cx, init); + } + } +} diff --git a/csharp/ql/integration-tests/posix/conftest.py b/csharp/ql/integration-tests/posix/conftest.py new file mode 100644 index 00000000000..543bc046c98 --- /dev/null +++ b/csharp/ql/integration-tests/posix/conftest.py @@ -0,0 +1,19 @@ +import runs_on + + +def _supports_mono_nuget(): + """ + Helper function to determine if the current platform supports Mono and nuget. + + Returns True if running on Linux or on macOS x86_64 (excluding macos-15 and macos-26). + macOS ARM runners (macos-15 and macos-26) are excluded due to issues with Mono and nuget. + """ + return ( + runs_on.linux + or ( + runs_on.macos + and runs_on.x86_64 + and not runs_on.macos_15 + and not runs_on.macos_26 + ) + ) diff --git a/csharp/ql/integration-tests/posix/standalone_dependencies_no_framework/test.py b/csharp/ql/integration-tests/posix/standalone_dependencies_no_framework/test.py index d1c1745d69b..725ded1899c 100644 --- a/csharp/ql/integration-tests/posix/standalone_dependencies_no_framework/test.py +++ b/csharp/ql/integration-tests/posix/standalone_dependencies_no_framework/test.py @@ -1,13 +1,9 @@ -import runs_on import pytest import os +from ..conftest import _supports_mono_nuget -# Skipping the test on the ARM runners and macos-15, as we're running into trouble with Mono and nuget. -@pytest.mark.only_if( - runs_on.linux - or (runs_on.macos and runs_on.x86_64 and not runs_on.macos_15) -) +@pytest.mark.only_if(_supports_mono_nuget()) def test(codeql, csharp): os.environ["CODEQL_EXTRACTOR_CSHARP_BUILDLESS_DOTNET_FRAMEWORK_REFERENCES"] = ( "/non-existent-path" diff --git a/csharp/ql/integration-tests/posix/standalone_dependencies_nuget with_space/test.py b/csharp/ql/integration-tests/posix/standalone_dependencies_nuget with_space/test.py index 6d2058c684c..662178aa3c0 100644 --- a/csharp/ql/integration-tests/posix/standalone_dependencies_nuget with_space/test.py +++ b/csharp/ql/integration-tests/posix/standalone_dependencies_nuget with_space/test.py @@ -1,13 +1,9 @@ import os -import runs_on import pytest +from ..conftest import _supports_mono_nuget -# Skipping the test on the ARM runners and macos-15, as we're running into trouble with Mono and nuget. -@pytest.mark.only_if( - runs_on.linux - or (runs_on.macos and runs_on.x86_64 and not runs_on.macos_15) -) +@pytest.mark.only_if(_supports_mono_nuget()) def test(codeql, csharp): # making sure we're not doing any fallback restore: os.environ["CODEQL_EXTRACTOR_CSHARP_BUILDLESS_NUGET_FEEDS_CHECK_FALLBACK_TIMEOUT"] = "1" diff --git a/csharp/ql/integration-tests/posix/standalone_dependencies_nuget/test.py b/csharp/ql/integration-tests/posix/standalone_dependencies_nuget/test.py index 7f88196097f..d8e8c8055ad 100644 --- a/csharp/ql/integration-tests/posix/standalone_dependencies_nuget/test.py +++ b/csharp/ql/integration-tests/posix/standalone_dependencies_nuget/test.py @@ -1,11 +1,7 @@ -import runs_on import pytest +from ..conftest import _supports_mono_nuget -# Skipping the test on the ARM runners and macos-15, as we're running into trouble with Mono and nuget. -@pytest.mark.only_if( - runs_on.linux - or (runs_on.macos and runs_on.x86_64 and not runs_on.macos_15) -) +@pytest.mark.only_if(_supports_mono_nuget()) def test(codeql, csharp): codeql.database.create(build_mode="none") diff --git a/csharp/ql/integration-tests/posix/standalone_dependencies_nuget_no_sources/test.py b/csharp/ql/integration-tests/posix/standalone_dependencies_nuget_no_sources/test.py index 185fb5201f9..ccd8f61a384 100644 --- a/csharp/ql/integration-tests/posix/standalone_dependencies_nuget_no_sources/test.py +++ b/csharp/ql/integration-tests/posix/standalone_dependencies_nuget_no_sources/test.py @@ -1,11 +1,7 @@ -import runs_on import pytest +from ..conftest import _supports_mono_nuget -# Skipping the test on the ARM runners, as we're running into trouble with Mono and nuget. -@pytest.mark.only_if( - runs_on.linux - or (runs_on.macos and runs_on.x86_64 and not runs_on.macos_15) -) +@pytest.mark.only_if(_supports_mono_nuget()) def test(codeql, csharp): codeql.database.create(source_root="proj", build_mode="none") diff --git a/csharp/ql/lib/change-notes/2026-02-12-field-keyword.md b/csharp/ql/lib/change-notes/2026-02-12-field-keyword.md new file mode 100644 index 00000000000..7ca6548b27f --- /dev/null +++ b/csharp/ql/lib/change-notes/2026-02-12-field-keyword.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* C# 14: Added support for the `field` keyword in properties. diff --git a/csharp/ql/lib/change-notes/2026-02-16-partial-events.md b/csharp/ql/lib/change-notes/2026-02-16-partial-events.md new file mode 100644 index 00000000000..3bbc1ae829a --- /dev/null +++ b/csharp/ql/lib/change-notes/2026-02-16-partial-events.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* C# 14: Added support for partial events. diff --git a/csharp/ql/test/library-tests/dataflow/fields/D.cs b/csharp/ql/test/library-tests/dataflow/fields/D.cs index 7f07cf5ca0b..45dfbffc801 100644 --- a/csharp/ql/test/library-tests/dataflow/fields/D.cs +++ b/csharp/ql/test/library-tests/dataflow/fields/D.cs @@ -89,3 +89,65 @@ public partial class DPartial static T Source(object source) => throw null; } + +public class DFieldProps +{ + object FieldProp0 + { + get { return field; } + set { field = value; } + } = Source(0); + + object FieldProp1 + { + get { return field; } + set { field = value; } + } + + object FieldProp2 + { + get { return field; } + set + { + var x = value; + field = x; + } + } + + static object StaticFieldProp + { + get { return field; } + set { field = value; } + } + + private void M() + { + var d0 = new DFieldProps(); + Sink(d0.FieldProp0); // $ hasValueFlow=0 + Sink(d0.FieldProp1); // no flow + Sink(d0.FieldProp2); // no flow + + var d1 = new DFieldProps(); + var o1 = Source(1); + d1.FieldProp1 = o1; + Sink(d1.FieldProp0); // $ hasValueFlow=0 + Sink(d1.FieldProp1); // $ hasValueFlow=1 + Sink(d1.FieldProp2); // no flow + + var d2 = new DFieldProps(); + var o2 = Source(2); + d2.FieldProp2 = o2; + Sink(d2.FieldProp0); // $ hasValueFlow=0 + Sink(d2.FieldProp1); // no flow + Sink(d2.FieldProp2); // $ hasValueFlow=2 + + var o3 = Source(3); + DFieldProps.StaticFieldProp = o3; + Sink(DFieldProps.StaticFieldProp); // $ hasValueFlow=3 + } + + public static void Sink(object o) { } + + static T Source(object source) => throw null; + +} diff --git a/csharp/ql/test/library-tests/dataflow/fields/FieldFlow.expected b/csharp/ql/test/library-tests/dataflow/fields/FieldFlow.expected index 4e469e11887..44789d1f847 100644 --- a/csharp/ql/test/library-tests/dataflow/fields/FieldFlow.expected +++ b/csharp/ql/test/library-tests/dataflow/fields/FieldFlow.expected @@ -532,6 +532,118 @@ edges | D.cs:84:14:84:14 | access to local variable d : DPartial [field _backingField] : Object | D.cs:60:9:60:11 | this : DPartial [field _backingField] : Object | provenance | | | D.cs:84:14:84:14 | access to local variable d : DPartial [field _backingField] : Object | D.cs:84:14:84:27 | access to property PartialProp1 | provenance | | | D.cs:84:14:84:14 | access to local variable d : DPartial [field _backingField] : Object | D.cs:84:14:84:27 | access to property PartialProp1 | provenance | | +| D.cs:93:14:93:24 | [post] this access : DFieldProps [field FieldProp0.field] : Object | D.cs:125:18:125:34 | object creation of type DFieldProps : DFieldProps [field FieldProp0.field] : Object | provenance | | +| D.cs:93:14:93:24 | [post] this access : DFieldProps [field FieldProp0.field] : Object | D.cs:125:18:125:34 | object creation of type DFieldProps : DFieldProps [field FieldProp0.field] : Object | provenance | | +| D.cs:93:14:93:24 | [post] this access : DFieldProps [field FieldProp0.field] : Object | D.cs:130:18:130:34 | object creation of type DFieldProps : DFieldProps [field FieldProp0.field] : Object | provenance | | +| D.cs:93:14:93:24 | [post] this access : DFieldProps [field FieldProp0.field] : Object | D.cs:130:18:130:34 | object creation of type DFieldProps : DFieldProps [field FieldProp0.field] : Object | provenance | | +| D.cs:93:14:93:24 | [post] this access : DFieldProps [field FieldProp0.field] : Object | D.cs:137:18:137:34 | object creation of type DFieldProps : DFieldProps [field FieldProp0.field] : Object | provenance | | +| D.cs:93:14:93:24 | [post] this access : DFieldProps [field FieldProp0.field] : Object | D.cs:137:18:137:34 | object creation of type DFieldProps : DFieldProps [field FieldProp0.field] : Object | provenance | | +| D.cs:95:12:95:21 | [post] this access : DFieldProps [field FieldProp0.field] : Object | D.cs:93:14:93:24 | [post] this access : DFieldProps [field FieldProp0.field] : Object | provenance | | +| D.cs:95:12:95:21 | [post] this access : DFieldProps [field FieldProp0.field] : Object | D.cs:93:14:93:24 | [post] this access : DFieldProps [field FieldProp0.field] : Object | provenance | | +| D.cs:97:9:97:11 | this : DFieldProps [field FieldProp0.field] : Object | D.cs:97:22:97:26 | this access : DFieldProps [field FieldProp0.field] : Object | provenance | | +| D.cs:97:9:97:11 | this : DFieldProps [field FieldProp0.field] : Object | D.cs:97:22:97:26 | this access : DFieldProps [field FieldProp0.field] : Object | provenance | | +| D.cs:97:22:97:26 | this access : DFieldProps [field FieldProp0.field] : Object | D.cs:97:22:97:26 | access to field FieldProp0.field : Object | provenance | | +| D.cs:97:22:97:26 | this access : DFieldProps [field FieldProp0.field] : Object | D.cs:97:22:97:26 | access to field FieldProp0.field : Object | provenance | | +| D.cs:98:9:98:11 | value : Object | D.cs:98:23:98:27 | access to parameter value : Object | provenance | | +| D.cs:98:9:98:11 | value : Object | D.cs:98:23:98:27 | access to parameter value : Object | provenance | | +| D.cs:98:15:98:19 | [post] this access : DFieldProps [field FieldProp0.field] : Object | D.cs:98:9:98:11 | this [Return] : DFieldProps [field FieldProp0.field] : Object | provenance | | +| D.cs:98:15:98:19 | [post] this access : DFieldProps [field FieldProp0.field] : Object | D.cs:98:9:98:11 | this [Return] : DFieldProps [field FieldProp0.field] : Object | provenance | | +| D.cs:98:23:98:27 | access to parameter value : Object | D.cs:98:15:98:19 | [post] this access : DFieldProps [field FieldProp0.field] : Object | provenance | | +| D.cs:98:23:98:27 | access to parameter value : Object | D.cs:98:15:98:19 | [post] this access : DFieldProps [field FieldProp0.field] : Object | provenance | | +| D.cs:99:9:99:25 | call to method Source : Object | D.cs:95:12:95:21 | [post] this access : DFieldProps [field FieldProp0.field] : Object | provenance | | +| D.cs:99:9:99:25 | call to method Source : Object | D.cs:95:12:95:21 | [post] this access : DFieldProps [field FieldProp0.field] : Object | provenance | | +| D.cs:99:9:99:25 | call to method Source : Object | D.cs:98:9:98:11 | value : Object | provenance | | +| D.cs:99:9:99:25 | call to method Source : Object | D.cs:98:9:98:11 | value : Object | provenance | | +| D.cs:103:9:103:11 | this : DFieldProps [field FieldProp1.field] : Object | D.cs:103:22:103:26 | this access : DFieldProps [field FieldProp1.field] : Object | provenance | | +| D.cs:103:9:103:11 | this : DFieldProps [field FieldProp1.field] : Object | D.cs:103:22:103:26 | this access : DFieldProps [field FieldProp1.field] : Object | provenance | | +| D.cs:103:22:103:26 | this access : DFieldProps [field FieldProp1.field] : Object | D.cs:103:22:103:26 | access to field FieldProp1.field : Object | provenance | | +| D.cs:103:22:103:26 | this access : DFieldProps [field FieldProp1.field] : Object | D.cs:103:22:103:26 | access to field FieldProp1.field : Object | provenance | | +| D.cs:104:9:104:11 | value : Object | D.cs:104:23:104:27 | access to parameter value : Object | provenance | | +| D.cs:104:9:104:11 | value : Object | D.cs:104:23:104:27 | access to parameter value : Object | provenance | | +| D.cs:104:15:104:19 | [post] this access : DFieldProps [field FieldProp1.field] : Object | D.cs:104:9:104:11 | this [Return] : DFieldProps [field FieldProp1.field] : Object | provenance | | +| D.cs:104:15:104:19 | [post] this access : DFieldProps [field FieldProp1.field] : Object | D.cs:104:9:104:11 | this [Return] : DFieldProps [field FieldProp1.field] : Object | provenance | | +| D.cs:104:23:104:27 | access to parameter value : Object | D.cs:104:15:104:19 | [post] this access : DFieldProps [field FieldProp1.field] : Object | provenance | | +| D.cs:104:23:104:27 | access to parameter value : Object | D.cs:104:15:104:19 | [post] this access : DFieldProps [field FieldProp1.field] : Object | provenance | | +| D.cs:109:9:109:11 | this : DFieldProps [field FieldProp2.field] : Object | D.cs:109:22:109:26 | this access : DFieldProps [field FieldProp2.field] : Object | provenance | | +| D.cs:109:9:109:11 | this : DFieldProps [field FieldProp2.field] : Object | D.cs:109:22:109:26 | this access : DFieldProps [field FieldProp2.field] : Object | provenance | | +| D.cs:109:22:109:26 | this access : DFieldProps [field FieldProp2.field] : Object | D.cs:109:22:109:26 | access to field FieldProp2.field : Object | provenance | | +| D.cs:109:22:109:26 | this access : DFieldProps [field FieldProp2.field] : Object | D.cs:109:22:109:26 | access to field FieldProp2.field : Object | provenance | | +| D.cs:110:9:110:11 | value : Object | D.cs:112:17:112:17 | access to local variable x : Object | provenance | | +| D.cs:110:9:110:11 | value : Object | D.cs:112:17:112:17 | access to local variable x : Object | provenance | | +| D.cs:112:17:112:17 | access to local variable x : Object | D.cs:113:21:113:21 | access to local variable x : Object | provenance | | +| D.cs:112:17:112:17 | access to local variable x : Object | D.cs:113:21:113:21 | access to local variable x : Object | provenance | | +| D.cs:113:13:113:17 | [post] this access : DFieldProps [field FieldProp2.field] : Object | D.cs:110:9:110:11 | this [Return] : DFieldProps [field FieldProp2.field] : Object | provenance | | +| D.cs:113:13:113:17 | [post] this access : DFieldProps [field FieldProp2.field] : Object | D.cs:110:9:110:11 | this [Return] : DFieldProps [field FieldProp2.field] : Object | provenance | | +| D.cs:113:21:113:21 | access to local variable x : Object | D.cs:113:13:113:17 | [post] this access : DFieldProps [field FieldProp2.field] : Object | provenance | | +| D.cs:113:21:113:21 | access to local variable x : Object | D.cs:113:13:113:17 | [post] this access : DFieldProps [field FieldProp2.field] : Object | provenance | | +| D.cs:119:22:119:26 | access to field StaticFieldProp.field : Object | D.cs:146:14:146:40 | access to property StaticFieldProp | provenance | | +| D.cs:119:22:119:26 | access to field StaticFieldProp.field : Object | D.cs:146:14:146:40 | access to property StaticFieldProp | provenance | | +| D.cs:120:9:120:11 | value : Object | D.cs:120:23:120:27 | access to parameter value : Object | provenance | | +| D.cs:120:9:120:11 | value : Object | D.cs:120:23:120:27 | access to parameter value : Object | provenance | | +| D.cs:120:23:120:27 | access to parameter value : Object | D.cs:119:22:119:26 | access to field StaticFieldProp.field : Object | provenance | | +| D.cs:120:23:120:27 | access to parameter value : Object | D.cs:119:22:119:26 | access to field StaticFieldProp.field : Object | provenance | | +| D.cs:125:13:125:14 | access to local variable d0 : DFieldProps [field FieldProp0.field] : Object | D.cs:126:14:126:15 | access to local variable d0 : DFieldProps [field FieldProp0.field] : Object | provenance | | +| D.cs:125:13:125:14 | access to local variable d0 : DFieldProps [field FieldProp0.field] : Object | D.cs:126:14:126:15 | access to local variable d0 : DFieldProps [field FieldProp0.field] : Object | provenance | | +| D.cs:125:18:125:34 | object creation of type DFieldProps : DFieldProps [field FieldProp0.field] : Object | D.cs:125:13:125:14 | access to local variable d0 : DFieldProps [field FieldProp0.field] : Object | provenance | | +| D.cs:125:18:125:34 | object creation of type DFieldProps : DFieldProps [field FieldProp0.field] : Object | D.cs:125:13:125:14 | access to local variable d0 : DFieldProps [field FieldProp0.field] : Object | provenance | | +| D.cs:126:14:126:15 | access to local variable d0 : DFieldProps [field FieldProp0.field] : Object | D.cs:97:9:97:11 | this : DFieldProps [field FieldProp0.field] : Object | provenance | | +| D.cs:126:14:126:15 | access to local variable d0 : DFieldProps [field FieldProp0.field] : Object | D.cs:97:9:97:11 | this : DFieldProps [field FieldProp0.field] : Object | provenance | | +| D.cs:126:14:126:15 | access to local variable d0 : DFieldProps [field FieldProp0.field] : Object | D.cs:126:14:126:26 | access to property FieldProp0 | provenance | | +| D.cs:126:14:126:15 | access to local variable d0 : DFieldProps [field FieldProp0.field] : Object | D.cs:126:14:126:26 | access to property FieldProp0 | provenance | | +| D.cs:130:13:130:14 | access to local variable d1 : DFieldProps [field FieldProp0.field] : Object | D.cs:133:14:133:15 | access to local variable d1 : DFieldProps [field FieldProp0.field] : Object | provenance | | +| D.cs:130:13:130:14 | access to local variable d1 : DFieldProps [field FieldProp0.field] : Object | D.cs:133:14:133:15 | access to local variable d1 : DFieldProps [field FieldProp0.field] : Object | provenance | | +| D.cs:130:18:130:34 | object creation of type DFieldProps : DFieldProps [field FieldProp0.field] : Object | D.cs:130:13:130:14 | access to local variable d1 : DFieldProps [field FieldProp0.field] : Object | provenance | | +| D.cs:130:18:130:34 | object creation of type DFieldProps : DFieldProps [field FieldProp0.field] : Object | D.cs:130:13:130:14 | access to local variable d1 : DFieldProps [field FieldProp0.field] : Object | provenance | | +| D.cs:131:13:131:14 | access to local variable o1 : Object | D.cs:132:25:132:26 | access to local variable o1 : Object | provenance | | +| D.cs:131:13:131:14 | access to local variable o1 : Object | D.cs:132:25:132:26 | access to local variable o1 : Object | provenance | | +| D.cs:131:18:131:34 | call to method Source : Object | D.cs:131:13:131:14 | access to local variable o1 : Object | provenance | | +| D.cs:131:18:131:34 | call to method Source : Object | D.cs:131:13:131:14 | access to local variable o1 : Object | provenance | | +| D.cs:132:9:132:10 | [post] access to local variable d1 : DFieldProps [field FieldProp1.field] : Object | D.cs:134:14:134:15 | access to local variable d1 : DFieldProps [field FieldProp1.field] : Object | provenance | | +| D.cs:132:9:132:10 | [post] access to local variable d1 : DFieldProps [field FieldProp1.field] : Object | D.cs:134:14:134:15 | access to local variable d1 : DFieldProps [field FieldProp1.field] : Object | provenance | | +| D.cs:132:25:132:26 | access to local variable o1 : Object | D.cs:104:9:104:11 | value : Object | provenance | | +| D.cs:132:25:132:26 | access to local variable o1 : Object | D.cs:104:9:104:11 | value : Object | provenance | | +| D.cs:132:25:132:26 | access to local variable o1 : Object | D.cs:132:9:132:10 | [post] access to local variable d1 : DFieldProps [field FieldProp1.field] : Object | provenance | | +| D.cs:132:25:132:26 | access to local variable o1 : Object | D.cs:132:9:132:10 | [post] access to local variable d1 : DFieldProps [field FieldProp1.field] : Object | provenance | | +| D.cs:133:14:133:15 | access to local variable d1 : DFieldProps [field FieldProp0.field] : Object | D.cs:97:9:97:11 | this : DFieldProps [field FieldProp0.field] : Object | provenance | | +| D.cs:133:14:133:15 | access to local variable d1 : DFieldProps [field FieldProp0.field] : Object | D.cs:97:9:97:11 | this : DFieldProps [field FieldProp0.field] : Object | provenance | | +| D.cs:133:14:133:15 | access to local variable d1 : DFieldProps [field FieldProp0.field] : Object | D.cs:133:14:133:26 | access to property FieldProp0 | provenance | | +| D.cs:133:14:133:15 | access to local variable d1 : DFieldProps [field FieldProp0.field] : Object | D.cs:133:14:133:26 | access to property FieldProp0 | provenance | | +| D.cs:134:14:134:15 | access to local variable d1 : DFieldProps [field FieldProp1.field] : Object | D.cs:103:9:103:11 | this : DFieldProps [field FieldProp1.field] : Object | provenance | | +| D.cs:134:14:134:15 | access to local variable d1 : DFieldProps [field FieldProp1.field] : Object | D.cs:103:9:103:11 | this : DFieldProps [field FieldProp1.field] : Object | provenance | | +| D.cs:134:14:134:15 | access to local variable d1 : DFieldProps [field FieldProp1.field] : Object | D.cs:134:14:134:26 | access to property FieldProp1 | provenance | | +| D.cs:134:14:134:15 | access to local variable d1 : DFieldProps [field FieldProp1.field] : Object | D.cs:134:14:134:26 | access to property FieldProp1 | provenance | | +| D.cs:137:13:137:14 | access to local variable d2 : DFieldProps [field FieldProp0.field] : Object | D.cs:140:14:140:15 | access to local variable d2 : DFieldProps [field FieldProp0.field] : Object | provenance | | +| D.cs:137:13:137:14 | access to local variable d2 : DFieldProps [field FieldProp0.field] : Object | D.cs:140:14:140:15 | access to local variable d2 : DFieldProps [field FieldProp0.field] : Object | provenance | | +| D.cs:137:18:137:34 | object creation of type DFieldProps : DFieldProps [field FieldProp0.field] : Object | D.cs:137:13:137:14 | access to local variable d2 : DFieldProps [field FieldProp0.field] : Object | provenance | | +| D.cs:137:18:137:34 | object creation of type DFieldProps : DFieldProps [field FieldProp0.field] : Object | D.cs:137:13:137:14 | access to local variable d2 : DFieldProps [field FieldProp0.field] : Object | provenance | | +| D.cs:138:13:138:14 | access to local variable o2 : Object | D.cs:139:25:139:26 | access to local variable o2 : Object | provenance | | +| D.cs:138:13:138:14 | access to local variable o2 : Object | D.cs:139:25:139:26 | access to local variable o2 : Object | provenance | | +| D.cs:138:18:138:34 | call to method Source : Object | D.cs:138:13:138:14 | access to local variable o2 : Object | provenance | | +| D.cs:138:18:138:34 | call to method Source : Object | D.cs:138:13:138:14 | access to local variable o2 : Object | provenance | | +| D.cs:139:9:139:10 | [post] access to local variable d2 : DFieldProps [field FieldProp2.field] : Object | D.cs:142:14:142:15 | access to local variable d2 : DFieldProps [field FieldProp2.field] : Object | provenance | | +| D.cs:139:9:139:10 | [post] access to local variable d2 : DFieldProps [field FieldProp2.field] : Object | D.cs:142:14:142:15 | access to local variable d2 : DFieldProps [field FieldProp2.field] : Object | provenance | | +| D.cs:139:25:139:26 | access to local variable o2 : Object | D.cs:110:9:110:11 | value : Object | provenance | | +| D.cs:139:25:139:26 | access to local variable o2 : Object | D.cs:110:9:110:11 | value : Object | provenance | | +| D.cs:139:25:139:26 | access to local variable o2 : Object | D.cs:139:9:139:10 | [post] access to local variable d2 : DFieldProps [field FieldProp2.field] : Object | provenance | | +| D.cs:139:25:139:26 | access to local variable o2 : Object | D.cs:139:9:139:10 | [post] access to local variable d2 : DFieldProps [field FieldProp2.field] : Object | provenance | | +| D.cs:140:14:140:15 | access to local variable d2 : DFieldProps [field FieldProp0.field] : Object | D.cs:97:9:97:11 | this : DFieldProps [field FieldProp0.field] : Object | provenance | | +| D.cs:140:14:140:15 | access to local variable d2 : DFieldProps [field FieldProp0.field] : Object | D.cs:97:9:97:11 | this : DFieldProps [field FieldProp0.field] : Object | provenance | | +| D.cs:140:14:140:15 | access to local variable d2 : DFieldProps [field FieldProp0.field] : Object | D.cs:140:14:140:26 | access to property FieldProp0 | provenance | | +| D.cs:140:14:140:15 | access to local variable d2 : DFieldProps [field FieldProp0.field] : Object | D.cs:140:14:140:26 | access to property FieldProp0 | provenance | | +| D.cs:142:14:142:15 | access to local variable d2 : DFieldProps [field FieldProp2.field] : Object | D.cs:109:9:109:11 | this : DFieldProps [field FieldProp2.field] : Object | provenance | | +| D.cs:142:14:142:15 | access to local variable d2 : DFieldProps [field FieldProp2.field] : Object | D.cs:109:9:109:11 | this : DFieldProps [field FieldProp2.field] : Object | provenance | | +| D.cs:142:14:142:15 | access to local variable d2 : DFieldProps [field FieldProp2.field] : Object | D.cs:142:14:142:26 | access to property FieldProp2 | provenance | | +| D.cs:142:14:142:15 | access to local variable d2 : DFieldProps [field FieldProp2.field] : Object | D.cs:142:14:142:26 | access to property FieldProp2 | provenance | | +| D.cs:144:13:144:14 | access to local variable o3 : Object | D.cs:145:9:145:35 | access to property StaticFieldProp : Object | provenance | | +| D.cs:144:13:144:14 | access to local variable o3 : Object | D.cs:145:9:145:35 | access to property StaticFieldProp : Object | provenance | | +| D.cs:144:13:144:14 | access to local variable o3 : Object | D.cs:145:39:145:40 | access to local variable o3 : Object | provenance | | +| D.cs:144:13:144:14 | access to local variable o3 : Object | D.cs:145:39:145:40 | access to local variable o3 : Object | provenance | | +| D.cs:144:18:144:34 | call to method Source : Object | D.cs:144:13:144:14 | access to local variable o3 : Object | provenance | | +| D.cs:144:18:144:34 | call to method Source : Object | D.cs:144:13:144:14 | access to local variable o3 : Object | provenance | | +| D.cs:145:9:145:35 | access to property StaticFieldProp : Object | D.cs:146:14:146:40 | access to property StaticFieldProp | provenance | | +| D.cs:145:9:145:35 | access to property StaticFieldProp : Object | D.cs:146:14:146:40 | access to property StaticFieldProp | provenance | | +| D.cs:145:39:145:40 | access to local variable o3 : Object | D.cs:120:9:120:11 | value : Object | provenance | | +| D.cs:145:39:145:40 | access to local variable o3 : Object | D.cs:120:9:120:11 | value : Object | provenance | | | E.cs:8:29:8:29 | o : Object | E.cs:11:21:11:21 | access to parameter o : Object | provenance | | | E.cs:8:29:8:29 | o : Object | E.cs:11:21:11:21 | access to parameter o : Object | provenance | | | E.cs:11:9:11:11 | [post] access to local variable ret : S [field Field] : Object | E.cs:12:16:12:18 | access to local variable ret : S [field Field] : Object | provenance | | @@ -1807,6 +1919,120 @@ nodes | D.cs:84:14:84:14 | access to local variable d : DPartial [field _backingField] : Object | semmle.label | access to local variable d : DPartial [field _backingField] : Object | | D.cs:84:14:84:27 | access to property PartialProp1 | semmle.label | access to property PartialProp1 | | D.cs:84:14:84:27 | access to property PartialProp1 | semmle.label | access to property PartialProp1 | +| D.cs:93:14:93:24 | [post] this access : DFieldProps [field FieldProp0.field] : Object | semmle.label | [post] this access : DFieldProps [field FieldProp0.field] : Object | +| D.cs:93:14:93:24 | [post] this access : DFieldProps [field FieldProp0.field] : Object | semmle.label | [post] this access : DFieldProps [field FieldProp0.field] : Object | +| D.cs:95:12:95:21 | [post] this access : DFieldProps [field FieldProp0.field] : Object | semmle.label | [post] this access : DFieldProps [field FieldProp0.field] : Object | +| D.cs:95:12:95:21 | [post] this access : DFieldProps [field FieldProp0.field] : Object | semmle.label | [post] this access : DFieldProps [field FieldProp0.field] : Object | +| D.cs:97:9:97:11 | this : DFieldProps [field FieldProp0.field] : Object | semmle.label | this : DFieldProps [field FieldProp0.field] : Object | +| D.cs:97:9:97:11 | this : DFieldProps [field FieldProp0.field] : Object | semmle.label | this : DFieldProps [field FieldProp0.field] : Object | +| D.cs:97:22:97:26 | access to field FieldProp0.field : Object | semmle.label | access to field FieldProp0.field : Object | +| D.cs:97:22:97:26 | access to field FieldProp0.field : Object | semmle.label | access to field FieldProp0.field : Object | +| D.cs:97:22:97:26 | this access : DFieldProps [field FieldProp0.field] : Object | semmle.label | this access : DFieldProps [field FieldProp0.field] : Object | +| D.cs:97:22:97:26 | this access : DFieldProps [field FieldProp0.field] : Object | semmle.label | this access : DFieldProps [field FieldProp0.field] : Object | +| D.cs:98:9:98:11 | this [Return] : DFieldProps [field FieldProp0.field] : Object | semmle.label | this [Return] : DFieldProps [field FieldProp0.field] : Object | +| D.cs:98:9:98:11 | this [Return] : DFieldProps [field FieldProp0.field] : Object | semmle.label | this [Return] : DFieldProps [field FieldProp0.field] : Object | +| D.cs:98:9:98:11 | value : Object | semmle.label | value : Object | +| D.cs:98:9:98:11 | value : Object | semmle.label | value : Object | +| D.cs:98:15:98:19 | [post] this access : DFieldProps [field FieldProp0.field] : Object | semmle.label | [post] this access : DFieldProps [field FieldProp0.field] : Object | +| D.cs:98:15:98:19 | [post] this access : DFieldProps [field FieldProp0.field] : Object | semmle.label | [post] this access : DFieldProps [field FieldProp0.field] : Object | +| D.cs:98:23:98:27 | access to parameter value : Object | semmle.label | access to parameter value : Object | +| D.cs:98:23:98:27 | access to parameter value : Object | semmle.label | access to parameter value : Object | +| D.cs:99:9:99:25 | call to method Source : Object | semmle.label | call to method Source : Object | +| D.cs:99:9:99:25 | call to method Source : Object | semmle.label | call to method Source : Object | +| D.cs:103:9:103:11 | this : DFieldProps [field FieldProp1.field] : Object | semmle.label | this : DFieldProps [field FieldProp1.field] : Object | +| D.cs:103:9:103:11 | this : DFieldProps [field FieldProp1.field] : Object | semmle.label | this : DFieldProps [field FieldProp1.field] : Object | +| D.cs:103:22:103:26 | access to field FieldProp1.field : Object | semmle.label | access to field FieldProp1.field : Object | +| D.cs:103:22:103:26 | access to field FieldProp1.field : Object | semmle.label | access to field FieldProp1.field : Object | +| D.cs:103:22:103:26 | this access : DFieldProps [field FieldProp1.field] : Object | semmle.label | this access : DFieldProps [field FieldProp1.field] : Object | +| D.cs:103:22:103:26 | this access : DFieldProps [field FieldProp1.field] : Object | semmle.label | this access : DFieldProps [field FieldProp1.field] : Object | +| D.cs:104:9:104:11 | this [Return] : DFieldProps [field FieldProp1.field] : Object | semmle.label | this [Return] : DFieldProps [field FieldProp1.field] : Object | +| D.cs:104:9:104:11 | this [Return] : DFieldProps [field FieldProp1.field] : Object | semmle.label | this [Return] : DFieldProps [field FieldProp1.field] : Object | +| D.cs:104:9:104:11 | value : Object | semmle.label | value : Object | +| D.cs:104:9:104:11 | value : Object | semmle.label | value : Object | +| D.cs:104:15:104:19 | [post] this access : DFieldProps [field FieldProp1.field] : Object | semmle.label | [post] this access : DFieldProps [field FieldProp1.field] : Object | +| D.cs:104:15:104:19 | [post] this access : DFieldProps [field FieldProp1.field] : Object | semmle.label | [post] this access : DFieldProps [field FieldProp1.field] : Object | +| D.cs:104:23:104:27 | access to parameter value : Object | semmle.label | access to parameter value : Object | +| D.cs:104:23:104:27 | access to parameter value : Object | semmle.label | access to parameter value : Object | +| D.cs:109:9:109:11 | this : DFieldProps [field FieldProp2.field] : Object | semmle.label | this : DFieldProps [field FieldProp2.field] : Object | +| D.cs:109:9:109:11 | this : DFieldProps [field FieldProp2.field] : Object | semmle.label | this : DFieldProps [field FieldProp2.field] : Object | +| D.cs:109:22:109:26 | access to field FieldProp2.field : Object | semmle.label | access to field FieldProp2.field : Object | +| D.cs:109:22:109:26 | access to field FieldProp2.field : Object | semmle.label | access to field FieldProp2.field : Object | +| D.cs:109:22:109:26 | this access : DFieldProps [field FieldProp2.field] : Object | semmle.label | this access : DFieldProps [field FieldProp2.field] : Object | +| D.cs:109:22:109:26 | this access : DFieldProps [field FieldProp2.field] : Object | semmle.label | this access : DFieldProps [field FieldProp2.field] : Object | +| D.cs:110:9:110:11 | this [Return] : DFieldProps [field FieldProp2.field] : Object | semmle.label | this [Return] : DFieldProps [field FieldProp2.field] : Object | +| D.cs:110:9:110:11 | this [Return] : DFieldProps [field FieldProp2.field] : Object | semmle.label | this [Return] : DFieldProps [field FieldProp2.field] : Object | +| D.cs:110:9:110:11 | value : Object | semmle.label | value : Object | +| D.cs:110:9:110:11 | value : Object | semmle.label | value : Object | +| D.cs:112:17:112:17 | access to local variable x : Object | semmle.label | access to local variable x : Object | +| D.cs:112:17:112:17 | access to local variable x : Object | semmle.label | access to local variable x : Object | +| D.cs:113:13:113:17 | [post] this access : DFieldProps [field FieldProp2.field] : Object | semmle.label | [post] this access : DFieldProps [field FieldProp2.field] : Object | +| D.cs:113:13:113:17 | [post] this access : DFieldProps [field FieldProp2.field] : Object | semmle.label | [post] this access : DFieldProps [field FieldProp2.field] : Object | +| D.cs:113:21:113:21 | access to local variable x : Object | semmle.label | access to local variable x : Object | +| D.cs:113:21:113:21 | access to local variable x : Object | semmle.label | access to local variable x : Object | +| D.cs:119:22:119:26 | access to field StaticFieldProp.field : Object | semmle.label | access to field StaticFieldProp.field : Object | +| D.cs:119:22:119:26 | access to field StaticFieldProp.field : Object | semmle.label | access to field StaticFieldProp.field : Object | +| D.cs:120:9:120:11 | value : Object | semmle.label | value : Object | +| D.cs:120:9:120:11 | value : Object | semmle.label | value : Object | +| D.cs:120:23:120:27 | access to parameter value : Object | semmle.label | access to parameter value : Object | +| D.cs:120:23:120:27 | access to parameter value : Object | semmle.label | access to parameter value : Object | +| D.cs:125:13:125:14 | access to local variable d0 : DFieldProps [field FieldProp0.field] : Object | semmle.label | access to local variable d0 : DFieldProps [field FieldProp0.field] : Object | +| D.cs:125:13:125:14 | access to local variable d0 : DFieldProps [field FieldProp0.field] : Object | semmle.label | access to local variable d0 : DFieldProps [field FieldProp0.field] : Object | +| D.cs:125:18:125:34 | object creation of type DFieldProps : DFieldProps [field FieldProp0.field] : Object | semmle.label | object creation of type DFieldProps : DFieldProps [field FieldProp0.field] : Object | +| D.cs:125:18:125:34 | object creation of type DFieldProps : DFieldProps [field FieldProp0.field] : Object | semmle.label | object creation of type DFieldProps : DFieldProps [field FieldProp0.field] : Object | +| D.cs:126:14:126:15 | access to local variable d0 : DFieldProps [field FieldProp0.field] : Object | semmle.label | access to local variable d0 : DFieldProps [field FieldProp0.field] : Object | +| D.cs:126:14:126:15 | access to local variable d0 : DFieldProps [field FieldProp0.field] : Object | semmle.label | access to local variable d0 : DFieldProps [field FieldProp0.field] : Object | +| D.cs:126:14:126:26 | access to property FieldProp0 | semmle.label | access to property FieldProp0 | +| D.cs:126:14:126:26 | access to property FieldProp0 | semmle.label | access to property FieldProp0 | +| D.cs:130:13:130:14 | access to local variable d1 : DFieldProps [field FieldProp0.field] : Object | semmle.label | access to local variable d1 : DFieldProps [field FieldProp0.field] : Object | +| D.cs:130:13:130:14 | access to local variable d1 : DFieldProps [field FieldProp0.field] : Object | semmle.label | access to local variable d1 : DFieldProps [field FieldProp0.field] : Object | +| D.cs:130:18:130:34 | object creation of type DFieldProps : DFieldProps [field FieldProp0.field] : Object | semmle.label | object creation of type DFieldProps : DFieldProps [field FieldProp0.field] : Object | +| D.cs:130:18:130:34 | object creation of type DFieldProps : DFieldProps [field FieldProp0.field] : Object | semmle.label | object creation of type DFieldProps : DFieldProps [field FieldProp0.field] : Object | +| D.cs:131:13:131:14 | access to local variable o1 : Object | semmle.label | access to local variable o1 : Object | +| D.cs:131:13:131:14 | access to local variable o1 : Object | semmle.label | access to local variable o1 : Object | +| D.cs:131:18:131:34 | call to method Source : Object | semmle.label | call to method Source : Object | +| D.cs:131:18:131:34 | call to method Source : Object | semmle.label | call to method Source : Object | +| D.cs:132:9:132:10 | [post] access to local variable d1 : DFieldProps [field FieldProp1.field] : Object | semmle.label | [post] access to local variable d1 : DFieldProps [field FieldProp1.field] : Object | +| D.cs:132:9:132:10 | [post] access to local variable d1 : DFieldProps [field FieldProp1.field] : Object | semmle.label | [post] access to local variable d1 : DFieldProps [field FieldProp1.field] : Object | +| D.cs:132:25:132:26 | access to local variable o1 : Object | semmle.label | access to local variable o1 : Object | +| D.cs:132:25:132:26 | access to local variable o1 : Object | semmle.label | access to local variable o1 : Object | +| D.cs:133:14:133:15 | access to local variable d1 : DFieldProps [field FieldProp0.field] : Object | semmle.label | access to local variable d1 : DFieldProps [field FieldProp0.field] : Object | +| D.cs:133:14:133:15 | access to local variable d1 : DFieldProps [field FieldProp0.field] : Object | semmle.label | access to local variable d1 : DFieldProps [field FieldProp0.field] : Object | +| D.cs:133:14:133:26 | access to property FieldProp0 | semmle.label | access to property FieldProp0 | +| D.cs:133:14:133:26 | access to property FieldProp0 | semmle.label | access to property FieldProp0 | +| D.cs:134:14:134:15 | access to local variable d1 : DFieldProps [field FieldProp1.field] : Object | semmle.label | access to local variable d1 : DFieldProps [field FieldProp1.field] : Object | +| D.cs:134:14:134:15 | access to local variable d1 : DFieldProps [field FieldProp1.field] : Object | semmle.label | access to local variable d1 : DFieldProps [field FieldProp1.field] : Object | +| D.cs:134:14:134:26 | access to property FieldProp1 | semmle.label | access to property FieldProp1 | +| D.cs:134:14:134:26 | access to property FieldProp1 | semmle.label | access to property FieldProp1 | +| D.cs:137:13:137:14 | access to local variable d2 : DFieldProps [field FieldProp0.field] : Object | semmle.label | access to local variable d2 : DFieldProps [field FieldProp0.field] : Object | +| D.cs:137:13:137:14 | access to local variable d2 : DFieldProps [field FieldProp0.field] : Object | semmle.label | access to local variable d2 : DFieldProps [field FieldProp0.field] : Object | +| D.cs:137:18:137:34 | object creation of type DFieldProps : DFieldProps [field FieldProp0.field] : Object | semmle.label | object creation of type DFieldProps : DFieldProps [field FieldProp0.field] : Object | +| D.cs:137:18:137:34 | object creation of type DFieldProps : DFieldProps [field FieldProp0.field] : Object | semmle.label | object creation of type DFieldProps : DFieldProps [field FieldProp0.field] : Object | +| D.cs:138:13:138:14 | access to local variable o2 : Object | semmle.label | access to local variable o2 : Object | +| D.cs:138:13:138:14 | access to local variable o2 : Object | semmle.label | access to local variable o2 : Object | +| D.cs:138:18:138:34 | call to method Source : Object | semmle.label | call to method Source : Object | +| D.cs:138:18:138:34 | call to method Source : Object | semmle.label | call to method Source : Object | +| D.cs:139:9:139:10 | [post] access to local variable d2 : DFieldProps [field FieldProp2.field] : Object | semmle.label | [post] access to local variable d2 : DFieldProps [field FieldProp2.field] : Object | +| D.cs:139:9:139:10 | [post] access to local variable d2 : DFieldProps [field FieldProp2.field] : Object | semmle.label | [post] access to local variable d2 : DFieldProps [field FieldProp2.field] : Object | +| D.cs:139:25:139:26 | access to local variable o2 : Object | semmle.label | access to local variable o2 : Object | +| D.cs:139:25:139:26 | access to local variable o2 : Object | semmle.label | access to local variable o2 : Object | +| D.cs:140:14:140:15 | access to local variable d2 : DFieldProps [field FieldProp0.field] : Object | semmle.label | access to local variable d2 : DFieldProps [field FieldProp0.field] : Object | +| D.cs:140:14:140:15 | access to local variable d2 : DFieldProps [field FieldProp0.field] : Object | semmle.label | access to local variable d2 : DFieldProps [field FieldProp0.field] : Object | +| D.cs:140:14:140:26 | access to property FieldProp0 | semmle.label | access to property FieldProp0 | +| D.cs:140:14:140:26 | access to property FieldProp0 | semmle.label | access to property FieldProp0 | +| D.cs:142:14:142:15 | access to local variable d2 : DFieldProps [field FieldProp2.field] : Object | semmle.label | access to local variable d2 : DFieldProps [field FieldProp2.field] : Object | +| D.cs:142:14:142:15 | access to local variable d2 : DFieldProps [field FieldProp2.field] : Object | semmle.label | access to local variable d2 : DFieldProps [field FieldProp2.field] : Object | +| D.cs:142:14:142:26 | access to property FieldProp2 | semmle.label | access to property FieldProp2 | +| D.cs:142:14:142:26 | access to property FieldProp2 | semmle.label | access to property FieldProp2 | +| D.cs:144:13:144:14 | access to local variable o3 : Object | semmle.label | access to local variable o3 : Object | +| D.cs:144:13:144:14 | access to local variable o3 : Object | semmle.label | access to local variable o3 : Object | +| D.cs:144:18:144:34 | call to method Source : Object | semmle.label | call to method Source : Object | +| D.cs:144:18:144:34 | call to method Source : Object | semmle.label | call to method Source : Object | +| D.cs:145:9:145:35 | access to property StaticFieldProp : Object | semmle.label | access to property StaticFieldProp : Object | +| D.cs:145:9:145:35 | access to property StaticFieldProp : Object | semmle.label | access to property StaticFieldProp : Object | +| D.cs:145:39:145:40 | access to local variable o3 : Object | semmle.label | access to local variable o3 : Object | +| D.cs:145:39:145:40 | access to local variable o3 : Object | semmle.label | access to local variable o3 : Object | +| D.cs:146:14:146:40 | access to property StaticFieldProp | semmle.label | access to property StaticFieldProp | +| D.cs:146:14:146:40 | access to property StaticFieldProp | semmle.label | access to property StaticFieldProp | | E.cs:8:29:8:29 | o : Object | semmle.label | o : Object | | E.cs:8:29:8:29 | o : Object | semmle.label | o : Object | | E.cs:11:9:11:11 | [post] access to local variable ret : S [field Field] : Object | semmle.label | [post] access to local variable ret : S [field Field] : Object | @@ -2648,6 +2874,22 @@ subpaths | D.cs:81:26:81:26 | access to local variable o : Object | D.cs:61:9:61:11 | value : Object | D.cs:61:9:61:11 | this [Return] : DPartial [field _backingField] : Object | D.cs:81:9:81:9 | [post] access to local variable d : DPartial [field _backingField] : Object | | D.cs:84:14:84:14 | access to local variable d : DPartial [field _backingField] : Object | D.cs:60:9:60:11 | this : DPartial [field _backingField] : Object | D.cs:60:22:60:34 | access to field _backingField : Object | D.cs:84:14:84:27 | access to property PartialProp1 | | D.cs:84:14:84:14 | access to local variable d : DPartial [field _backingField] : Object | D.cs:60:9:60:11 | this : DPartial [field _backingField] : Object | D.cs:60:22:60:34 | access to field _backingField : Object | D.cs:84:14:84:27 | access to property PartialProp1 | +| D.cs:99:9:99:25 | call to method Source : Object | D.cs:98:9:98:11 | value : Object | D.cs:98:9:98:11 | this [Return] : DFieldProps [field FieldProp0.field] : Object | D.cs:95:12:95:21 | [post] this access : DFieldProps [field FieldProp0.field] : Object | +| D.cs:99:9:99:25 | call to method Source : Object | D.cs:98:9:98:11 | value : Object | D.cs:98:9:98:11 | this [Return] : DFieldProps [field FieldProp0.field] : Object | D.cs:95:12:95:21 | [post] this access : DFieldProps [field FieldProp0.field] : Object | +| D.cs:126:14:126:15 | access to local variable d0 : DFieldProps [field FieldProp0.field] : Object | D.cs:97:9:97:11 | this : DFieldProps [field FieldProp0.field] : Object | D.cs:97:22:97:26 | access to field FieldProp0.field : Object | D.cs:126:14:126:26 | access to property FieldProp0 | +| D.cs:126:14:126:15 | access to local variable d0 : DFieldProps [field FieldProp0.field] : Object | D.cs:97:9:97:11 | this : DFieldProps [field FieldProp0.field] : Object | D.cs:97:22:97:26 | access to field FieldProp0.field : Object | D.cs:126:14:126:26 | access to property FieldProp0 | +| D.cs:132:25:132:26 | access to local variable o1 : Object | D.cs:104:9:104:11 | value : Object | D.cs:104:9:104:11 | this [Return] : DFieldProps [field FieldProp1.field] : Object | D.cs:132:9:132:10 | [post] access to local variable d1 : DFieldProps [field FieldProp1.field] : Object | +| D.cs:132:25:132:26 | access to local variable o1 : Object | D.cs:104:9:104:11 | value : Object | D.cs:104:9:104:11 | this [Return] : DFieldProps [field FieldProp1.field] : Object | D.cs:132:9:132:10 | [post] access to local variable d1 : DFieldProps [field FieldProp1.field] : Object | +| D.cs:133:14:133:15 | access to local variable d1 : DFieldProps [field FieldProp0.field] : Object | D.cs:97:9:97:11 | this : DFieldProps [field FieldProp0.field] : Object | D.cs:97:22:97:26 | access to field FieldProp0.field : Object | D.cs:133:14:133:26 | access to property FieldProp0 | +| D.cs:133:14:133:15 | access to local variable d1 : DFieldProps [field FieldProp0.field] : Object | D.cs:97:9:97:11 | this : DFieldProps [field FieldProp0.field] : Object | D.cs:97:22:97:26 | access to field FieldProp0.field : Object | D.cs:133:14:133:26 | access to property FieldProp0 | +| D.cs:134:14:134:15 | access to local variable d1 : DFieldProps [field FieldProp1.field] : Object | D.cs:103:9:103:11 | this : DFieldProps [field FieldProp1.field] : Object | D.cs:103:22:103:26 | access to field FieldProp1.field : Object | D.cs:134:14:134:26 | access to property FieldProp1 | +| D.cs:134:14:134:15 | access to local variable d1 : DFieldProps [field FieldProp1.field] : Object | D.cs:103:9:103:11 | this : DFieldProps [field FieldProp1.field] : Object | D.cs:103:22:103:26 | access to field FieldProp1.field : Object | D.cs:134:14:134:26 | access to property FieldProp1 | +| D.cs:139:25:139:26 | access to local variable o2 : Object | D.cs:110:9:110:11 | value : Object | D.cs:110:9:110:11 | this [Return] : DFieldProps [field FieldProp2.field] : Object | D.cs:139:9:139:10 | [post] access to local variable d2 : DFieldProps [field FieldProp2.field] : Object | +| D.cs:139:25:139:26 | access to local variable o2 : Object | D.cs:110:9:110:11 | value : Object | D.cs:110:9:110:11 | this [Return] : DFieldProps [field FieldProp2.field] : Object | D.cs:139:9:139:10 | [post] access to local variable d2 : DFieldProps [field FieldProp2.field] : Object | +| D.cs:140:14:140:15 | access to local variable d2 : DFieldProps [field FieldProp0.field] : Object | D.cs:97:9:97:11 | this : DFieldProps [field FieldProp0.field] : Object | D.cs:97:22:97:26 | access to field FieldProp0.field : Object | D.cs:140:14:140:26 | access to property FieldProp0 | +| D.cs:140:14:140:15 | access to local variable d2 : DFieldProps [field FieldProp0.field] : Object | D.cs:97:9:97:11 | this : DFieldProps [field FieldProp0.field] : Object | D.cs:97:22:97:26 | access to field FieldProp0.field : Object | D.cs:140:14:140:26 | access to property FieldProp0 | +| D.cs:142:14:142:15 | access to local variable d2 : DFieldProps [field FieldProp2.field] : Object | D.cs:109:9:109:11 | this : DFieldProps [field FieldProp2.field] : Object | D.cs:109:22:109:26 | access to field FieldProp2.field : Object | D.cs:142:14:142:26 | access to property FieldProp2 | +| D.cs:142:14:142:15 | access to local variable d2 : DFieldProps [field FieldProp2.field] : Object | D.cs:109:9:109:11 | this : DFieldProps [field FieldProp2.field] : Object | D.cs:109:22:109:26 | access to field FieldProp2.field : Object | D.cs:142:14:142:26 | access to property FieldProp2 | | E.cs:23:25:23:25 | access to local variable o : Object | E.cs:8:29:8:29 | o : Object | E.cs:12:16:12:18 | access to local variable ret : S [field Field] : Object | E.cs:23:17:23:26 | call to method CreateS : S [field Field] : Object | | E.cs:23:25:23:25 | access to local variable o : Object | E.cs:8:29:8:29 | o : Object | E.cs:12:16:12:18 | access to local variable ret : S [field Field] : Object | E.cs:23:17:23:26 | call to method CreateS : S [field Field] : Object | | E.cs:55:29:55:33 | access to local variable taint : Object | E.cs:43:46:43:46 | o : Object | E.cs:43:36:43:36 | s [Return] : RefS [field RefField] : Object | E.cs:55:23:55:26 | [post] access to local variable refs : RefS [field RefField] : Object | @@ -2758,6 +3000,18 @@ testFailures | D.cs:47:14:47:26 | access to property ComplexProp | D.cs:43:32:43:48 | call to method Source : Object | D.cs:47:14:47:26 | access to property ComplexProp | $@ | D.cs:43:32:43:48 | call to method Source : Object | call to method Source : Object | | D.cs:84:14:84:27 | access to property PartialProp1 | D.cs:78:17:78:33 | call to method Source : Object | D.cs:84:14:84:27 | access to property PartialProp1 | $@ | D.cs:78:17:78:33 | call to method Source : Object | call to method Source : Object | | D.cs:84:14:84:27 | access to property PartialProp1 | D.cs:78:17:78:33 | call to method Source : Object | D.cs:84:14:84:27 | access to property PartialProp1 | $@ | D.cs:78:17:78:33 | call to method Source : Object | call to method Source : Object | +| D.cs:126:14:126:26 | access to property FieldProp0 | D.cs:99:9:99:25 | call to method Source : Object | D.cs:126:14:126:26 | access to property FieldProp0 | $@ | D.cs:99:9:99:25 | call to method Source : Object | call to method Source : Object | +| D.cs:126:14:126:26 | access to property FieldProp0 | D.cs:99:9:99:25 | call to method Source : Object | D.cs:126:14:126:26 | access to property FieldProp0 | $@ | D.cs:99:9:99:25 | call to method Source : Object | call to method Source : Object | +| D.cs:133:14:133:26 | access to property FieldProp0 | D.cs:99:9:99:25 | call to method Source : Object | D.cs:133:14:133:26 | access to property FieldProp0 | $@ | D.cs:99:9:99:25 | call to method Source : Object | call to method Source : Object | +| D.cs:133:14:133:26 | access to property FieldProp0 | D.cs:99:9:99:25 | call to method Source : Object | D.cs:133:14:133:26 | access to property FieldProp0 | $@ | D.cs:99:9:99:25 | call to method Source : Object | call to method Source : Object | +| D.cs:134:14:134:26 | access to property FieldProp1 | D.cs:131:18:131:34 | call to method Source : Object | D.cs:134:14:134:26 | access to property FieldProp1 | $@ | D.cs:131:18:131:34 | call to method Source : Object | call to method Source : Object | +| D.cs:134:14:134:26 | access to property FieldProp1 | D.cs:131:18:131:34 | call to method Source : Object | D.cs:134:14:134:26 | access to property FieldProp1 | $@ | D.cs:131:18:131:34 | call to method Source : Object | call to method Source : Object | +| D.cs:140:14:140:26 | access to property FieldProp0 | D.cs:99:9:99:25 | call to method Source : Object | D.cs:140:14:140:26 | access to property FieldProp0 | $@ | D.cs:99:9:99:25 | call to method Source : Object | call to method Source : Object | +| D.cs:140:14:140:26 | access to property FieldProp0 | D.cs:99:9:99:25 | call to method Source : Object | D.cs:140:14:140:26 | access to property FieldProp0 | $@ | D.cs:99:9:99:25 | call to method Source : Object | call to method Source : Object | +| D.cs:142:14:142:26 | access to property FieldProp2 | D.cs:138:18:138:34 | call to method Source : Object | D.cs:142:14:142:26 | access to property FieldProp2 | $@ | D.cs:138:18:138:34 | call to method Source : Object | call to method Source : Object | +| D.cs:142:14:142:26 | access to property FieldProp2 | D.cs:138:18:138:34 | call to method Source : Object | D.cs:142:14:142:26 | access to property FieldProp2 | $@ | D.cs:138:18:138:34 | call to method Source : Object | call to method Source : Object | +| D.cs:146:14:146:40 | access to property StaticFieldProp | D.cs:144:18:144:34 | call to method Source : Object | D.cs:146:14:146:40 | access to property StaticFieldProp | $@ | D.cs:144:18:144:34 | call to method Source : Object | call to method Source : Object | +| D.cs:146:14:146:40 | access to property StaticFieldProp | D.cs:144:18:144:34 | call to method Source : Object | D.cs:146:14:146:40 | access to property StaticFieldProp | $@ | D.cs:144:18:144:34 | call to method Source : Object | call to method Source : Object | | E.cs:24:14:24:20 | access to field Field | E.cs:22:17:22:33 | call to method Source : Object | E.cs:24:14:24:20 | access to field Field | $@ | E.cs:22:17:22:33 | call to method Source : Object | call to method Source : Object | | E.cs:24:14:24:20 | access to field Field | E.cs:22:17:22:33 | call to method Source : Object | E.cs:24:14:24:20 | access to field Field | $@ | E.cs:22:17:22:33 | call to method Source : Object | call to method Source : Object | | E.cs:57:14:57:26 | access to field RefField | E.cs:54:21:54:37 | call to method Source : Object | E.cs:57:14:57:26 | access to field RefField | $@ | E.cs:54:21:54:37 | call to method Source : Object | call to method Source : Object | diff --git a/csharp/ql/test/library-tests/dispatch/CallGraph.expected b/csharp/ql/test/library-tests/dispatch/CallGraph.expected index 4eed880f0a3..2feb959dd86 100644 --- a/csharp/ql/test/library-tests/dispatch/CallGraph.expected +++ b/csharp/ql/test/library-tests/dispatch/CallGraph.expected @@ -270,7 +270,9 @@ | ViableCallable.cs:679:17:679:20 | Run3 | ViableCallable.cs:637:21:637:21 | M | | ViableCallable.cs:679:17:679:20 | Run3 | ViableCallable.cs:646:21:646:21 | M | | ViableCallable.cs:679:17:679:20 | Run3 | ViableCallable.cs:648:21:648:21 | M | -| ViableCallable.cs:707:17:707:20 | Run1 | ViableCallable.cs:702:42:702:44 | get_Property | -| ViableCallable.cs:707:17:707:20 | Run1 | ViableCallable.cs:702:63:702:65 | set_Property | -| ViableCallable.cs:707:17:707:20 | Run1 | ViableCallable.cs:704:49:704:51 | get_Item | -| ViableCallable.cs:707:17:707:20 | Run1 | ViableCallable.cs:704:70:704:72 | set_Item | +| ViableCallable.cs:709:17:709:20 | Run1 | ViableCallable.cs:703:42:703:44 | get_Property | +| ViableCallable.cs:709:17:709:20 | Run1 | ViableCallable.cs:703:63:703:65 | set_Property | +| ViableCallable.cs:709:17:709:20 | Run1 | ViableCallable.cs:705:49:705:51 | get_Item | +| ViableCallable.cs:709:17:709:20 | Run1 | ViableCallable.cs:705:70:705:72 | set_Item | +| ViableCallable.cs:709:17:709:20 | Run1 | ViableCallable.cs:706:51:706:53 | add_Event | +| ViableCallable.cs:709:17:709:20 | Run1 | ViableCallable.cs:706:59:706:64 | remove_Event | diff --git a/csharp/ql/test/library-tests/dispatch/GetADynamicTarget.expected b/csharp/ql/test/library-tests/dispatch/GetADynamicTarget.expected index b38eed691b9..5d6b4be4f87 100644 --- a/csharp/ql/test/library-tests/dispatch/GetADynamicTarget.expected +++ b/csharp/ql/test/library-tests/dispatch/GetADynamicTarget.expected @@ -518,7 +518,9 @@ | ViableCallable.cs:683:9:683:16 | call to method M | C22+TestOverloadResolution2.M(Int32[]) | | ViableCallable.cs:687:9:687:16 | call to method M | C22+TestOverloadResolution1.M(List) | | ViableCallable.cs:687:9:687:16 | call to method M | C22+TestOverloadResolution2.M(List) | -| ViableCallable.cs:712:9:712:18 | access to property Property | C23+Partial1.set_Property(object) | -| ViableCallable.cs:715:13:715:22 | access to property Property | C23+Partial1.get_Property() | -| ViableCallable.cs:718:9:718:12 | access to indexer | C23+Partial1.set_Item(int, object) | -| ViableCallable.cs:721:13:721:16 | access to indexer | C23+Partial1.get_Item(int) | +| ViableCallable.cs:714:9:714:18 | access to property Property | C23+Partial1.set_Property(object) | +| ViableCallable.cs:717:13:717:22 | access to property Property | C23+Partial1.get_Property() | +| ViableCallable.cs:720:9:720:12 | access to indexer | C23+Partial1.set_Item(int, object) | +| ViableCallable.cs:723:13:723:16 | access to indexer | C23+Partial1.get_Item(int) | +| ViableCallable.cs:726:9:726:15 | access to event Event | C23+Partial1.add_Event(EventHandler) | +| ViableCallable.cs:729:9:729:15 | access to event Event | C23+Partial1.remove_Event(EventHandler) | diff --git a/csharp/ql/test/library-tests/dispatch/ViableCallable.cs b/csharp/ql/test/library-tests/dispatch/ViableCallable.cs index 99b4ec54a99..e904eb01a86 100644 --- a/csharp/ql/test/library-tests/dispatch/ViableCallable.cs +++ b/csharp/ql/test/library-tests/dispatch/ViableCallable.cs @@ -695,6 +695,7 @@ public class C23 public partial object Property { get; set; } public partial object this[int index] { get; set; } + public partial event EventHandler Event; } public partial class Partial1 @@ -702,6 +703,7 @@ public class C23 public partial object Property { get { return null; } set { } } public partial object this[int index] { get { return null; } set { } } + public partial event EventHandler Event { add { } remove { } } } public void Run1(Partial1 p) @@ -719,5 +721,11 @@ public class C23 // Viable callable: Partial1.get_Item(int) o = p[0]; + + // Viable callable: Partial1.add_Event + p.Event += (sender, e) => { }; + + // Viable callable: Partial1.remove_Event + p.Event -= (sender, e) => { }; } } diff --git a/csharp/ql/test/library-tests/partial/MethodIsPartial.expected b/csharp/ql/test/library-tests/partial/MethodIsPartial.expected index 4c0e905d8c5..a0f1f88fb98 100644 --- a/csharp/ql/test/library-tests/partial/MethodIsPartial.expected +++ b/csharp/ql/test/library-tests/partial/MethodIsPartial.expected @@ -1,7 +1,7 @@ -| Partial.cs:4:18:4:42 | PartialMethodWithoutBody1 | true | -| Partial.cs:5:17:5:23 | Method2 | false | -| Partial.cs:14:18:14:39 | PartialMethodWithBody1 | true | -| Partial.cs:15:17:15:23 | Method3 | false | -| Partial.cs:34:18:34:42 | PartialMethodWithoutBody2 | true | -| Partial.cs:35:17:35:23 | Method4 | false | -| Partial.cs:40:17:40:23 | Method5 | false | +| Partial.cs:6:18:6:42 | PartialMethodWithoutBody1 | true | +| Partial.cs:7:17:7:23 | Method2 | false | +| Partial.cs:18:18:18:39 | PartialMethodWithBody1 | true | +| Partial.cs:19:17:19:23 | Method3 | false | +| Partial.cs:41:18:41:42 | PartialMethodWithoutBody2 | true | +| Partial.cs:42:17:42:23 | Method4 | false | +| Partial.cs:47:17:47:23 | Method5 | false | diff --git a/csharp/ql/test/library-tests/partial/Partial.cs b/csharp/ql/test/library-tests/partial/Partial.cs index 5a3e4af2e8c..8dd757fcd24 100644 --- a/csharp/ql/test/library-tests/partial/Partial.cs +++ b/csharp/ql/test/library-tests/partial/Partial.cs @@ -1,3 +1,5 @@ +using System; + partial class TwoPartClass { partial void PartialMethodWithBody1(); @@ -7,6 +9,8 @@ partial class TwoPartClass public partial object PartialProperty1 { get; set; } // Declaring declaration. public partial object this[int index] { get; set; } + // Declaring declaration. + public partial event EventHandler PartialEvent1; } partial class TwoPartClass @@ -27,6 +31,9 @@ partial class TwoPartClass get { return _backingArray[index]; } set { _backingArray[index] = value; } } + + // Implementation declaration. + public partial event EventHandler PartialEvent1 { add { } remove { } } } partial class OnePartPartialClass @@ -44,4 +51,5 @@ class NonPartialClass get { return null; } set { } } + public event EventHandler Event; } diff --git a/csharp/ql/test/library-tests/partial/Partial1.expected b/csharp/ql/test/library-tests/partial/Partial1.expected index 55dcaabcea7..fe8f5658f48 100644 --- a/csharp/ql/test/library-tests/partial/Partial1.expected +++ b/csharp/ql/test/library-tests/partial/Partial1.expected @@ -1,14 +1,17 @@ -| Partial.cs:1:15:1:26 | TwoPartClass | -| Partial.cs:4:18:4:42 | PartialMethodWithoutBody1 | -| Partial.cs:12:15:12:26 | TwoPartClass | -| Partial.cs:14:18:14:39 | PartialMethodWithBody1 | -| Partial.cs:18:27:18:42 | PartialProperty1 | -| Partial.cs:20:9:20:11 | get_PartialProperty1 | -| Partial.cs:21:9:21:11 | set_PartialProperty1 | -| Partial.cs:25:27:25:30 | Item | -| Partial.cs:27:9:27:11 | get_Item | -| Partial.cs:28:9:28:11 | set_Item | -| Partial.cs:32:15:32:33 | OnePartPartialClass | -| Partial.cs:34:18:34:42 | PartialMethodWithoutBody2 | +| Partial.cs:3:15:3:26 | TwoPartClass | +| Partial.cs:6:18:6:42 | PartialMethodWithoutBody1 | +| Partial.cs:16:15:16:26 | TwoPartClass | +| Partial.cs:18:18:18:39 | PartialMethodWithBody1 | +| Partial.cs:22:27:22:42 | PartialProperty1 | +| Partial.cs:24:9:24:11 | get_PartialProperty1 | +| Partial.cs:25:9:25:11 | set_PartialProperty1 | +| Partial.cs:29:27:29:30 | Item | +| Partial.cs:31:9:31:11 | get_Item | +| Partial.cs:32:9:32:11 | set_Item | +| Partial.cs:36:39:36:51 | PartialEvent1 | +| Partial.cs:36:55:36:57 | add_PartialEvent1 | +| Partial.cs:36:63:36:68 | remove_PartialEvent1 | +| Partial.cs:39:15:39:33 | OnePartPartialClass | +| Partial.cs:41:18:41:42 | PartialMethodWithoutBody2 | | PartialMultipleFiles1.cs:1:22:1:41 | PartialMultipleFiles | | PartialMultipleFiles2.cs:1:22:1:41 | PartialMultipleFiles | diff --git a/csharp/ql/test/library-tests/partial/Partial2.expected b/csharp/ql/test/library-tests/partial/Partial2.expected index 87194dd3f9e..8d608c26011 100644 --- a/csharp/ql/test/library-tests/partial/Partial2.expected +++ b/csharp/ql/test/library-tests/partial/Partial2.expected @@ -1,15 +1,15 @@ -| Partial.cs:1:15:1:26 | TwoPartClass | Partial.cs:1:15:1:26 | | -| Partial.cs:1:15:1:26 | TwoPartClass | Partial.cs:4:18:4:42 | PartialMethodWithoutBody1 | -| Partial.cs:1:15:1:26 | TwoPartClass | Partial.cs:5:17:5:23 | Method2 | -| Partial.cs:1:15:1:26 | TwoPartClass | Partial.cs:14:18:14:39 | PartialMethodWithBody1 | -| Partial.cs:1:15:1:26 | TwoPartClass | Partial.cs:15:17:15:23 | Method3 | -| Partial.cs:12:15:12:26 | TwoPartClass | Partial.cs:1:15:1:26 | | -| Partial.cs:12:15:12:26 | TwoPartClass | Partial.cs:4:18:4:42 | PartialMethodWithoutBody1 | -| Partial.cs:12:15:12:26 | TwoPartClass | Partial.cs:5:17:5:23 | Method2 | -| Partial.cs:12:15:12:26 | TwoPartClass | Partial.cs:14:18:14:39 | PartialMethodWithBody1 | -| Partial.cs:12:15:12:26 | TwoPartClass | Partial.cs:15:17:15:23 | Method3 | -| Partial.cs:32:15:32:33 | OnePartPartialClass | Partial.cs:32:15:32:33 | | -| Partial.cs:32:15:32:33 | OnePartPartialClass | Partial.cs:34:18:34:42 | PartialMethodWithoutBody2 | -| Partial.cs:32:15:32:33 | OnePartPartialClass | Partial.cs:35:17:35:23 | Method4 | +| Partial.cs:3:15:3:26 | TwoPartClass | Partial.cs:3:15:3:26 | | +| Partial.cs:3:15:3:26 | TwoPartClass | Partial.cs:6:18:6:42 | PartialMethodWithoutBody1 | +| Partial.cs:3:15:3:26 | TwoPartClass | Partial.cs:7:17:7:23 | Method2 | +| Partial.cs:3:15:3:26 | TwoPartClass | Partial.cs:18:18:18:39 | PartialMethodWithBody1 | +| Partial.cs:3:15:3:26 | TwoPartClass | Partial.cs:19:17:19:23 | Method3 | +| Partial.cs:16:15:16:26 | TwoPartClass | Partial.cs:3:15:3:26 | | +| Partial.cs:16:15:16:26 | TwoPartClass | Partial.cs:6:18:6:42 | PartialMethodWithoutBody1 | +| Partial.cs:16:15:16:26 | TwoPartClass | Partial.cs:7:17:7:23 | Method2 | +| Partial.cs:16:15:16:26 | TwoPartClass | Partial.cs:18:18:18:39 | PartialMethodWithBody1 | +| Partial.cs:16:15:16:26 | TwoPartClass | Partial.cs:19:17:19:23 | Method3 | +| Partial.cs:39:15:39:33 | OnePartPartialClass | Partial.cs:39:15:39:33 | | +| Partial.cs:39:15:39:33 | OnePartPartialClass | Partial.cs:41:18:41:42 | PartialMethodWithoutBody2 | +| Partial.cs:39:15:39:33 | OnePartPartialClass | Partial.cs:42:17:42:23 | Method4 | | PartialMultipleFiles1.cs:1:22:1:41 | PartialMultipleFiles | PartialMultipleFiles1.cs:1:22:1:41 | | | PartialMultipleFiles2.cs:1:22:1:41 | PartialMultipleFiles | PartialMultipleFiles1.cs:1:22:1:41 | | diff --git a/csharp/ql/test/library-tests/partial/PartialAccessors.expected b/csharp/ql/test/library-tests/partial/PartialAccessors.expected index 2c69ed620ae..a9d70645420 100644 --- a/csharp/ql/test/library-tests/partial/PartialAccessors.expected +++ b/csharp/ql/test/library-tests/partial/PartialAccessors.expected @@ -1,8 +1,12 @@ -| Partial.cs:20:9:20:11 | get_PartialProperty1 | true | -| Partial.cs:21:9:21:11 | set_PartialProperty1 | true | -| Partial.cs:27:9:27:11 | get_Item | true | -| Partial.cs:28:9:28:11 | set_Item | true | -| Partial.cs:41:30:41:32 | get_Property | false | -| Partial.cs:41:35:41:37 | set_Property | false | -| Partial.cs:44:9:44:11 | get_Item | false | -| Partial.cs:45:9:45:11 | set_Item | false | +| Partial.cs:24:9:24:11 | get_PartialProperty1 | true | +| Partial.cs:25:9:25:11 | set_PartialProperty1 | true | +| Partial.cs:31:9:31:11 | get_Item | true | +| Partial.cs:32:9:32:11 | set_Item | true | +| Partial.cs:36:55:36:57 | add_PartialEvent1 | true | +| Partial.cs:36:63:36:68 | remove_PartialEvent1 | true | +| Partial.cs:48:30:48:32 | get_Property | false | +| Partial.cs:48:35:48:37 | set_Property | false | +| Partial.cs:51:9:51:11 | get_Item | false | +| Partial.cs:52:9:52:11 | set_Item | false | +| Partial.cs:54:31:54:35 | add_Event | false | +| Partial.cs:54:31:54:35 | remove_Event | false | diff --git a/csharp/ql/test/library-tests/partial/PartialConstructors.expected b/csharp/ql/test/library-tests/partial/PartialConstructors.expected index 01779f1b81e..69cabb244f5 100644 --- a/csharp/ql/test/library-tests/partial/PartialConstructors.expected +++ b/csharp/ql/test/library-tests/partial/PartialConstructors.expected @@ -1,4 +1,4 @@ -| Partial.cs:1:15:1:26 | TwoPartClass | Partial.cs:1:15:1:26 | {...} | -| Partial.cs:32:15:32:33 | OnePartPartialClass | Partial.cs:32:15:32:33 | {...} | -| Partial.cs:38:7:38:21 | NonPartialClass | Partial.cs:38:7:38:21 | {...} | +| Partial.cs:3:15:3:26 | TwoPartClass | Partial.cs:3:15:3:26 | {...} | +| Partial.cs:39:15:39:33 | OnePartPartialClass | Partial.cs:39:15:39:33 | {...} | +| Partial.cs:45:7:45:21 | NonPartialClass | Partial.cs:45:7:45:21 | {...} | | PartialMultipleFiles1.cs:1:22:1:41 | PartialMultipleFiles | PartialMultipleFiles1.cs:1:22:1:41 | {...} | diff --git a/csharp/ql/test/library-tests/partial/PartialEvents.expected b/csharp/ql/test/library-tests/partial/PartialEvents.expected new file mode 100644 index 00000000000..b12f8a07a9d --- /dev/null +++ b/csharp/ql/test/library-tests/partial/PartialEvents.expected @@ -0,0 +1,2 @@ +| Partial.cs:36:39:36:51 | PartialEvent1 | true | +| Partial.cs:54:31:54:35 | Event | false | diff --git a/csharp/ql/test/library-tests/partial/PartialEvents.ql b/csharp/ql/test/library-tests/partial/PartialEvents.ql new file mode 100644 index 00000000000..e9f45250266 --- /dev/null +++ b/csharp/ql/test/library-tests/partial/PartialEvents.ql @@ -0,0 +1,7 @@ +import csharp + +private boolean isPartial(Event e) { if e.isPartial() then result = true else result = false } + +from Event e +where e.fromSource() +select e, isPartial(e) diff --git a/csharp/ql/test/library-tests/partial/PartialIndexers.expected b/csharp/ql/test/library-tests/partial/PartialIndexers.expected index 151ed5aad03..be625fc4ad5 100644 --- a/csharp/ql/test/library-tests/partial/PartialIndexers.expected +++ b/csharp/ql/test/library-tests/partial/PartialIndexers.expected @@ -1,2 +1,2 @@ -| Partial.cs:25:27:25:30 | Item | true | -| Partial.cs:42:19:42:22 | Item | false | +| Partial.cs:29:27:29:30 | Item | true | +| Partial.cs:49:19:49:22 | Item | false | diff --git a/csharp/ql/test/library-tests/partial/PartialMethodBody.expected b/csharp/ql/test/library-tests/partial/PartialMethodBody.expected index b75a105bea0..a91a156cb62 100644 --- a/csharp/ql/test/library-tests/partial/PartialMethodBody.expected +++ b/csharp/ql/test/library-tests/partial/PartialMethodBody.expected @@ -1,3 +1,3 @@ -| Partial.cs:4:18:4:42 | PartialMethodWithoutBody1 | false | -| Partial.cs:14:18:14:39 | PartialMethodWithBody1 | true | -| Partial.cs:34:18:34:42 | PartialMethodWithoutBody2 | false | +| Partial.cs:6:18:6:42 | PartialMethodWithoutBody1 | false | +| Partial.cs:18:18:18:39 | PartialMethodWithBody1 | true | +| Partial.cs:41:18:41:42 | PartialMethodWithoutBody2 | false | diff --git a/csharp/ql/test/library-tests/partial/PartialProperties.expected b/csharp/ql/test/library-tests/partial/PartialProperties.expected index 8d2dfc01e74..4686bbf087a 100644 --- a/csharp/ql/test/library-tests/partial/PartialProperties.expected +++ b/csharp/ql/test/library-tests/partial/PartialProperties.expected @@ -1,2 +1,2 @@ -| Partial.cs:18:27:18:42 | PartialProperty1 | true | -| Partial.cs:41:19:41:26 | Property | false | +| Partial.cs:22:27:22:42 | PartialProperty1 | true | +| Partial.cs:48:19:48:26 | Property | false | diff --git a/csharp/ql/test/library-tests/partial/PrintAst.expected b/csharp/ql/test/library-tests/partial/PrintAst.expected index 0729946b18b..315de869fb3 100644 --- a/csharp/ql/test/library-tests/partial/PrintAst.expected +++ b/csharp/ql/test/library-tests/partial/PrintAst.expected @@ -1,94 +1,112 @@ Partial.cs: -# 1| [Class] TwoPartClass -# 4| 6: [Method] PartialMethodWithoutBody1 -# 4| -1: [TypeMention] Void -# 5| 7: [Method] Method2 +# 3| [Class] TwoPartClass +# 6| 6: [Method] PartialMethodWithoutBody1 +# 6| -1: [TypeMention] Void +# 7| 7: [Method] Method2 +# 7| -1: [TypeMention] Void +# 7| 4: [BlockStmt] {...} +# 18| 8: [Method] PartialMethodWithBody1 # 5| -1: [TypeMention] Void -# 5| 4: [BlockStmt] {...} -# 14| 8: [Method] PartialMethodWithBody1 -# 3| -1: [TypeMention] Void -# 14| 4: [BlockStmt] {...} -# 15| 9: [Method] Method3 -# 15| -1: [TypeMention] Void -# 15| 4: [BlockStmt] {...} -# 16| 10: [Field] _backingField -# 16| -1: [TypeMention] object -# 18| 11: [Property] PartialProperty1 -# 7| -1: [TypeMention] object -# 18| -1: [TypeMention] object -# 20| 3: [Getter] get_PartialProperty1 -# 20| 4: [BlockStmt] {...} -# 20| 0: [ReturnStmt] return ...; -# 20| 0: [FieldAccess] access to field _backingField -# 21| 4: [Setter] set_PartialProperty1 -#-----| 2: (Parameters) -# 21| 0: [Parameter] value -# 21| 4: [BlockStmt] {...} -# 21| 0: [ExprStmt] ...; -# 21| 0: [AssignExpr] ... = ... -# 21| 0: [FieldAccess] access to field _backingField -# 21| 1: [ParameterAccess] access to parameter value -# 23| 12: [Field] _backingArray -# 23| -1: [TypeMention] Object[] -# 23| 1: [TypeMention] object -# 25| 13: [Indexer] Item +# 18| 4: [BlockStmt] {...} +# 19| 9: [Method] Method3 +# 19| -1: [TypeMention] Void +# 19| 4: [BlockStmt] {...} +# 20| 10: [Field] _backingField +# 20| -1: [TypeMention] object +# 22| 11: [Property] PartialProperty1 # 9| -1: [TypeMention] object -# 25| -1: [TypeMention] object +# 22| -1: [TypeMention] object +# 24| 3: [Getter] get_PartialProperty1 +# 24| 4: [BlockStmt] {...} +# 24| 0: [ReturnStmt] return ...; +# 24| 0: [FieldAccess] access to field _backingField +# 25| 4: [Setter] set_PartialProperty1 +#-----| 2: (Parameters) +# 25| 0: [Parameter] value +# 25| 4: [BlockStmt] {...} +# 25| 0: [ExprStmt] ...; +# 25| 0: [AssignExpr] ... = ... +# 25| 0: [FieldAccess] access to field _backingField +# 25| 1: [ParameterAccess] access to parameter value +# 27| 12: [Field] _backingArray +# 27| -1: [TypeMention] Object[] +# 27| 1: [TypeMention] object +# 29| 13: [Indexer] Item +# 11| -1: [TypeMention] object +# 29| -1: [TypeMention] object #-----| 1: (Parameters) -# 9| 0: [Parameter] index -# 9| -1: [TypeMention] int -# 25| -1: [TypeMention] int -# 27| 3: [Getter] get_Item +# 11| 0: [Parameter] index +# 11| -1: [TypeMention] int +# 29| -1: [TypeMention] int +# 31| 3: [Getter] get_Item #-----| 2: (Parameters) -# 25| 0: [Parameter] index -# 27| 4: [BlockStmt] {...} -# 27| 0: [ReturnStmt] return ...; -# 27| 0: [ArrayAccess] access to array element -# 27| -1: [FieldAccess] access to field _backingArray -# 27| 0: [ParameterAccess] access to parameter index -# 28| 4: [Setter] set_Item +# 29| 0: [Parameter] index +# 31| 4: [BlockStmt] {...} +# 31| 0: [ReturnStmt] return ...; +# 31| 0: [ArrayAccess] access to array element +# 31| -1: [FieldAccess] access to field _backingArray +# 31| 0: [ParameterAccess] access to parameter index +# 32| 4: [Setter] set_Item #-----| 2: (Parameters) -# 25| 0: [Parameter] index -# 28| 1: [Parameter] value -# 28| 4: [BlockStmt] {...} -# 28| 0: [ExprStmt] ...; -# 28| 0: [AssignExpr] ... = ... -# 28| 0: [ArrayAccess] access to array element -# 28| -1: [FieldAccess] access to field _backingArray -# 28| 0: [ParameterAccess] access to parameter index -# 28| 1: [ParameterAccess] access to parameter value -# 32| [Class] OnePartPartialClass -# 34| 6: [Method] PartialMethodWithoutBody2 -# 34| -1: [TypeMention] Void -# 35| 7: [Method] Method4 -# 35| -1: [TypeMention] Void -# 35| 4: [BlockStmt] {...} -# 38| [Class] NonPartialClass -# 40| 6: [Method] Method5 -# 40| -1: [TypeMention] Void -# 40| 4: [BlockStmt] {...} -# 41| 7: [Property] Property -# 41| -1: [TypeMention] object -# 41| 3: [Getter] get_Property -# 41| 4: [Setter] set_Property +# 29| 0: [Parameter] index +# 32| 1: [Parameter] value +# 32| 4: [BlockStmt] {...} +# 32| 0: [ExprStmt] ...; +# 32| 0: [AssignExpr] ... = ... +# 32| 0: [ArrayAccess] access to array element +# 32| -1: [FieldAccess] access to field _backingArray +# 32| 0: [ParameterAccess] access to parameter index +# 32| 1: [ParameterAccess] access to parameter value +# 36| 14: [Event] PartialEvent1 +# 13| -1: [TypeMention] EventHandler +# 36| 3: [AddEventAccessor] add_PartialEvent1 #-----| 2: (Parameters) -# 41| 0: [Parameter] value -# 42| 8: [Indexer] Item -# 42| -1: [TypeMention] object +# 36| 0: [Parameter] value +# 36| 4: [BlockStmt] {...} +# 36| 4: [RemoveEventAccessor] remove_PartialEvent1 +#-----| 2: (Parameters) +# 36| 0: [Parameter] value +# 36| 4: [BlockStmt] {...} +# 39| [Class] OnePartPartialClass +# 41| 6: [Method] PartialMethodWithoutBody2 +# 41| -1: [TypeMention] Void +# 42| 7: [Method] Method4 +# 42| -1: [TypeMention] Void +# 42| 4: [BlockStmt] {...} +# 45| [Class] NonPartialClass +# 47| 6: [Method] Method5 +# 47| -1: [TypeMention] Void +# 47| 4: [BlockStmt] {...} +# 48| 7: [Property] Property +# 48| -1: [TypeMention] object +# 48| 3: [Getter] get_Property +# 48| 4: [Setter] set_Property +#-----| 2: (Parameters) +# 48| 0: [Parameter] value +# 49| 8: [Indexer] Item +# 49| -1: [TypeMention] object #-----| 1: (Parameters) -# 42| 0: [Parameter] index -# 42| -1: [TypeMention] int -# 44| 3: [Getter] get_Item +# 49| 0: [Parameter] index +# 49| -1: [TypeMention] int +# 51| 3: [Getter] get_Item #-----| 2: (Parameters) -# 42| 0: [Parameter] index -# 44| 4: [BlockStmt] {...} -# 44| 0: [ReturnStmt] return ...; -# 44| 0: [NullLiteral] null -# 45| 4: [Setter] set_Item +# 49| 0: [Parameter] index +# 51| 4: [BlockStmt] {...} +# 51| 0: [ReturnStmt] return ...; +# 51| 0: [NullLiteral] null +# 52| 4: [Setter] set_Item #-----| 2: (Parameters) -# 42| 0: [Parameter] index -# 45| 1: [Parameter] value -# 45| 4: [BlockStmt] {...} +# 49| 0: [Parameter] index +# 52| 1: [Parameter] value +# 52| 4: [BlockStmt] {...} +# 54| 9: [Event] Event +# 54| -1: [TypeMention] EventHandler +# 54| 3: [AddEventAccessor] add_Event +#-----| 2: (Parameters) +# 54| 0: [Parameter] value +# 54| 4: [RemoveEventAccessor] remove_Event +#-----| 2: (Parameters) +# 54| 0: [Parameter] value PartialMultipleFiles1.cs: # 1| [Class] PartialMultipleFiles PartialMultipleFiles2.cs: diff --git a/csharp/ql/test/library-tests/properties/PrintAst.expected b/csharp/ql/test/library-tests/properties/PrintAst.expected index 2df3ee3f5e8..711e417558e 100644 --- a/csharp/ql/test/library-tests/properties/PrintAst.expected +++ b/csharp/ql/test/library-tests/properties/PrintAst.expected @@ -230,3 +230,19 @@ properties.cs: #-----| 2: (Parameters) # 124| 0: [Parameter] value # 124| 4: [BlockStmt] {...} +# 128| 10: [Class] UseFieldKeyword +# 130| 6: [Property] Prop +# 130| -1: [TypeMention] object +# 132| 3: [Getter] get_Prop +# 132| 4: [BlockStmt] {...} +# 132| 0: [ReturnStmt] return ...; +# 132| 0: [FieldAccess] access to field Prop.field +# 133| 4: [Setter] set_Prop +#-----| 2: (Parameters) +# 133| 0: [Parameter] value +# 133| 4: [BlockStmt] {...} +# 133| 0: [ExprStmt] ...; +# 133| 0: [AssignExpr] ... = ... +# 133| 0: [FieldAccess] access to field Prop.field +# 133| 1: [ParameterAccess] access to parameter value +# 130| 7: [Field] Prop.field diff --git a/csharp/ql/test/library-tests/properties/Properties17.expected b/csharp/ql/test/library-tests/properties/Properties17.expected index 47b563e2676..ee817a63df9 100644 --- a/csharp/ql/test/library-tests/properties/Properties17.expected +++ b/csharp/ql/test/library-tests/properties/Properties17.expected @@ -1,3 +1,4 @@ +| Prop.field | | caption | | next | | y | diff --git a/csharp/ql/test/library-tests/properties/Properties17.ql b/csharp/ql/test/library-tests/properties/Properties17.ql index ca53f5423aa..6bd668ec118 100644 --- a/csharp/ql/test/library-tests/properties/Properties17.ql +++ b/csharp/ql/test/library-tests/properties/Properties17.ql @@ -1,5 +1,5 @@ /** - * @name Test that there are no backing fields + * @name Test that there are no backing fields except for properties that use the `field` keyword in their getter or setter. */ import csharp diff --git a/csharp/ql/test/library-tests/properties/properties.cs b/csharp/ql/test/library-tests/properties/properties.cs index 57ffa7a31a5..2f88214ec75 100644 --- a/csharp/ql/test/library-tests/properties/properties.cs +++ b/csharp/ql/test/library-tests/properties/properties.cs @@ -124,4 +124,13 @@ namespace Properties set { } } } + + class UseFieldKeyword + { + public object Prop + { + get { return field; } + set { field = value; } + } + } } diff --git a/csharp/ql/test/query-tests/API Abuse/ClassDoesNotImplementEquals/NullableTest.cs b/csharp/ql/test/query-tests/API Abuse/ClassDoesNotImplementEquals/NullableTest.cs new file mode 100644 index 00000000000..a66ffbec9a0 --- /dev/null +++ b/csharp/ql/test/query-tests/API Abuse/ClassDoesNotImplementEquals/NullableTest.cs @@ -0,0 +1,86 @@ +using System; + +#nullable enable + +namespace Test +{ + class TestClass1 : IEquatable + { + private int field1; + + public bool Equals(TestClass1? param1) + { + return param1 != null && field1 == param1.field1; + } + + public override bool Equals(object? param2) + { + return param2 is TestClass1 tc && Equals(tc); + } + + public override int GetHashCode() + { + return field1; + } + } + + class TestClass2 : IEquatable + { + private int field1; + + public bool Equals(TestClass2 param1) + { + return param1 != null && field1 == param1.field1; + } + + public override bool Equals(object? param2) + { + return param2 is TestClass2 tc && Equals(tc); + } + + public override int GetHashCode() + { + return field1; + } + } + + class TestClass3 : IEquatable + { + private int field1; + + public bool Equals(TestClass3? param1) + { + return param1 != null && field1 == param1.field1; + } + + public override bool Equals(object param2) + { + return param2 is TestClass3 tc && Equals(tc); + } + + public override int GetHashCode() + { + return field1; + } + } + + class TestClass4 : IEquatable + { + private int field1; + + public bool Equals(TestClass4 param1) + { + return param1 != null && field1 == param1.field1; + } + + public override bool Equals(object param2) + { + return param2 is TestClass4 tc && Equals(tc); + } + + public override int GetHashCode() + { + return field1; + } + } +} \ No newline at end of file diff --git a/csharp/ql/test/query-tests/API Abuse/IncorrectEqualsSignature/NullableTest.cs b/csharp/ql/test/query-tests/API Abuse/IncorrectEqualsSignature/NullableTest.cs new file mode 100644 index 00000000000..a66ffbec9a0 --- /dev/null +++ b/csharp/ql/test/query-tests/API Abuse/IncorrectEqualsSignature/NullableTest.cs @@ -0,0 +1,86 @@ +using System; + +#nullable enable + +namespace Test +{ + class TestClass1 : IEquatable + { + private int field1; + + public bool Equals(TestClass1? param1) + { + return param1 != null && field1 == param1.field1; + } + + public override bool Equals(object? param2) + { + return param2 is TestClass1 tc && Equals(tc); + } + + public override int GetHashCode() + { + return field1; + } + } + + class TestClass2 : IEquatable + { + private int field1; + + public bool Equals(TestClass2 param1) + { + return param1 != null && field1 == param1.field1; + } + + public override bool Equals(object? param2) + { + return param2 is TestClass2 tc && Equals(tc); + } + + public override int GetHashCode() + { + return field1; + } + } + + class TestClass3 : IEquatable + { + private int field1; + + public bool Equals(TestClass3? param1) + { + return param1 != null && field1 == param1.field1; + } + + public override bool Equals(object param2) + { + return param2 is TestClass3 tc && Equals(tc); + } + + public override int GetHashCode() + { + return field1; + } + } + + class TestClass4 : IEquatable + { + private int field1; + + public bool Equals(TestClass4 param1) + { + return param1 != null && field1 == param1.field1; + } + + public override bool Equals(object param2) + { + return param2 is TestClass4 tc && Equals(tc); + } + + public override int GetHashCode() + { + return field1; + } + } +} \ No newline at end of file diff --git a/docs/codeql/reusables/supported-versions-compilers.rst b/docs/codeql/reusables/supported-versions-compilers.rst index 6216bae08df..566238658f3 100644 --- a/docs/codeql/reusables/supported-versions-compilers.rst +++ b/docs/codeql/reusables/supported-versions-compilers.rst @@ -18,7 +18,7 @@ .NET 5, .NET 6, .NET 7, .NET 8, .NET 9","``.sln``, ``.slnx``, ``.csproj``, ``.cs``, ``.cshtml``, ``.xaml``" GitHub Actions,"Not applicable",Not applicable,"``.github/workflows/*.yml``, ``.github/workflows/*.yaml``, ``**/action.yml``, ``**/action.yaml``" Go (aka Golang), "Go up to 1.26", "Go 1.11 or more recent", ``.go`` - Java,"Java 7 to 25 [6]_","javac (OpenJDK and Oracle JDK), + Java,"Java 7 to 26 [6]_","javac (OpenJDK and Oracle JDK), Eclipse compiler for Java (ECJ) [7]_",``.java`` Kotlin,"Kotlin 1.8.0 to 2.3.0\ *x*","kotlinc",``.kt`` @@ -36,7 +36,7 @@ .. [3] Objective-C, Objective-C++, C++/CLI, and C++/CX are not supported. .. [4] Support for the clang-cl compiler is preliminary. .. [5] Support for the Arm Compiler (armcc) is preliminary. - .. [6] Builds that execute on Java 7 to 25 can be analyzed. The analysis understands standard language features in Java 8 to 25; "preview" and "incubator" features are not supported. Source code using Java language versions older than Java 8 are analyzed as Java 8 code. + .. [6] Builds that execute on Java 7 to 26 can be analyzed. The analysis understands standard language features in Java 8 to 26; "preview" and "incubator" features are not supported. Source code using Java language versions older than Java 8 are analyzed as Java 8 code. .. [7] ECJ is supported when the build invokes it via the Maven Compiler plugin or the Takari Lifecycle plugin. .. [8] JSX and Flow code, YAML, JSON, HTML, and XML files may also be analyzed with JavaScript files. .. [9] The extractor requires Python 3 to run. To analyze Python 2.7 you should install both versions of Python. diff --git a/java/ql/src/change-notes/2025-11-13-maven-default-java-17 b/java/ql/src/change-notes/2025-11-13-maven-default-java-17.md similarity index 100% rename from java/ql/src/change-notes/2025-11-13-maven-default-java-17 rename to java/ql/src/change-notes/2025-11-13-maven-default-java-17.md diff --git a/java/ql/src/change-notes/2026-02-17-support-java-26.md b/java/ql/src/change-notes/2026-02-17-support-java-26.md new file mode 100644 index 00000000000..db0a108f0ca --- /dev/null +++ b/java/ql/src/change-notes/2026-02-17-support-java-26.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* The Java extractor and QL libraries now support Java 26. diff --git a/misc/bazel/registry/modules/rules_rust/0.68.1.codeql.1/MODULE.bazel b/misc/bazel/registry/modules/rules_rust/0.68.1.codeql.1/MODULE.bazel new file mode 100644 index 00000000000..aedc5a8a242 --- /dev/null +++ b/misc/bazel/registry/modules/rules_rust/0.68.1.codeql.1/MODULE.bazel @@ -0,0 +1,151 @@ +"""bazelbuild/rules_rust""" + +module( + name = "rules_rust", + version = "0.68.1.codeql.1", +) + +############################################################################### +## Core +############################################################################### + +bazel_dep(name = "bazel_features", version = "1.32.0") +bazel_dep(name = "bazel_skylib", version = "1.8.2") +bazel_dep(name = "platforms", version = "1.0.0") +bazel_dep(name = "rules_cc", version = "0.2.4") +bazel_dep(name = "rules_license", version = "1.0.0") +bazel_dep(name = "rules_shell", version = "0.6.1") +bazel_dep(name = "apple_support", version = "1.24.1", repo_name = "build_bazel_apple_support") + +internal_deps = use_extension("//rust/private:internal_extensions.bzl", "i") +use_repo( + internal_deps, + "rrra", + "rrra__anyhow-1.0.71", + "rrra__camino-1.1.9", + "rrra__clap-4.3.11", + "rrra__env_logger-0.10.0", + "rrra__itertools-0.11.0", + "rrra__log-0.4.19", + "rrra__serde-1.0.171", + "rrra__serde_json-1.0.102", + "rules_rust_tinyjson", +) + +cargo_internal_deps = use_extension("//cargo/private:internal_extensions.bzl", "i") +use_repo( + cargo_internal_deps, + "rrc", + "rrc__cargo-util-schemas-0.3.1", + "rrc__cargo_toml-0.20.5", + "rrc__pathdiff-0.1.0", + "rrc__semver-1.0.25", + "rrc__toml-0.8.20", +) + +rust = use_extension("//rust:extensions.bzl", "rust") +rust.toolchain(edition = "2021") +use_repo(rust, "rust_toolchains") + +register_toolchains( + "@rust_toolchains//:all", +) + +rust_host_tools = use_extension("//rust:extensions.bzl", "rust_host_tools") +rust_host_tools.host_tools( + name = "rust_host_tools", +) +use_repo( + rust_host_tools, + "rust_host_tools", +) + +rust_test = use_extension("//test:test_extensions.bzl", "rust_test", dev_dependency = True) +use_repo( + rust_test, + "buildkite_config", + "generated_inputs_in_external_repo", + "libc", + "rtra", + "rtra__serde-1.0.228", + "rtra__serde_json-1.0.145", + "rtvsc", + "rtvsc__serde-1.0.228", + "rtvsc__serde_json-1.0.145", + "rules_rust_test_load_arbitrary_tool", + "rules_rust_toolchain_test_target_json", +) + +bazel_dep(name = "rules_python", version = "0.40.0", dev_dependency = True) +bazel_dep(name = "rules_testing", version = "0.7.0", dev_dependency = True) +bazel_dep(name = "bazel_ci_rules", version = "1.0.0", dev_dependency = True) + +############################################################################### +## Crate Universe +############################################################################### + +crate_universe_internal_deps = use_extension( + "//crate_universe/private:internal_extensions.bzl", + "cu", +) +use_repo( + crate_universe_internal_deps, + "cargo_bazel.buildifier-darwin-amd64", + "cargo_bazel.buildifier-darwin-arm64", + "cargo_bazel.buildifier-linux-amd64", + "cargo_bazel.buildifier-linux-arm64", + "cargo_bazel.buildifier-windows-amd64.exe", + "cui", + "cui__anyhow-1.0.98", + "cui__camino-1.1.9", + "cui__cargo-lock-10.1.0", + "cui__cargo-platform-0.1.9", + "cui__cargo_metadata-0.19.2", + "cui__cargo_toml-0.22.1", + "cui__cfg-expr-0.18.0", + "cui__clap-4.5.37", + "cui__crates-index-3.7.0", + "cui__glob-0.3.2", + "cui__hex-0.4.3", + "cui__indoc-2.0.6", + "cui__itertools-0.14.0", + "cui__maplit-1.0.2", + "cui__normpath-1.3.0", + "cui__once_cell-1.21.3", + "cui__pathdiff-0.2.3", + "cui__regex-1.11.1", + "cui__semver-1.0.26", + "cui__serde-1.0.219", + "cui__serde_json-1.0.140", + "cui__serde_starlark-0.1.17", + "cui__sha2-0.10.8", + "cui__spdx-0.10.8", + "cui__tempfile-3.19.1", + "cui__tera-1.20.0", + "cui__textwrap-0.16.2", + "cui__toml-0.8.21", + "cui__tracing-0.1.41", + "cui__tracing-subscriber-0.3.19", + "cui__url-2.5.4", + "cui__walkdir-2.5.0", +) + +crate_universe_internal_non_repro_deps = use_extension( + "//crate_universe/private:internal_extensions.bzl", + "cu_nr", +) +use_repo( + crate_universe_internal_non_repro_deps, + "cargo_bazel_bootstrap", +) + +crate_universe_internal_dev_deps = use_extension( + "//crate_universe/private:internal_extensions.bzl", + "cu_dev", + dev_dependency = True, +) +use_repo( + crate_universe_internal_dev_deps, + "cross_rs", + "cross_rs_host_bin", +) diff --git a/misc/bazel/registry/modules/rules_rust/0.68.1.codeql.1/patches/include_rmeta_in_stdlib.patch b/misc/bazel/registry/modules/rules_rust/0.68.1.codeql.1/patches/include_rmeta_in_stdlib.patch new file mode 100644 index 00000000000..3707cb51b63 --- /dev/null +++ b/misc/bazel/registry/modules/rules_rust/0.68.1.codeql.1/patches/include_rmeta_in_stdlib.patch @@ -0,0 +1,12 @@ +diff --git a/rust/private/repository_utils.bzl b/rust/private/repository_utils.bzl +index 05b741947..f88074af6 100644 +--- a/rust/private/repository_utils.bzl ++++ b/rust/private/repository_utils.bzl +@@ -280,6 +280,7 @@ rust_stdlib_filegroup( + srcs = glob( + [ + "lib/rustlib/{target_triple}/lib/*.rlib", ++ "lib/rustlib/{target_triple}/lib/*.rmeta", + "lib/rustlib/{target_triple}/lib/*{dylib_ext}*", + "lib/rustlib/{target_triple}/lib/*{staticlib_ext}", + "lib/rustlib/{target_triple}/lib/self-contained/**", diff --git a/misc/bazel/registry/modules/rules_rust/0.68.1.codeql.1/source.json b/misc/bazel/registry/modules/rules_rust/0.68.1.codeql.1/source.json new file mode 100644 index 00000000000..6048521ce2f --- /dev/null +++ b/misc/bazel/registry/modules/rules_rust/0.68.1.codeql.1/source.json @@ -0,0 +1,9 @@ +{ + "integrity": "sha256-yKqAbPYGZnmsI0YyQe6ArWkiZdrQRl9RERy74wuJA1I=", + "strip_prefix": "", + "url": "https://github.com/bazelbuild/rules_rust/releases/download/0.68.1/rules_rust-0.68.1.tar.gz", + "patches": { + "include_rmeta_in_stdlib.patch": "sha256-7n8XHpfkLUMEbRG6lKqdhLWydsWlRRG+Ywkxk6LvY9c=" + }, + "patch_strip": 1 +} diff --git a/misc/bazel/registry/modules/rules_rust/metadata.json b/misc/bazel/registry/modules/rules_rust/metadata.json new file mode 100644 index 00000000000..deffe6f6dfa --- /dev/null +++ b/misc/bazel/registry/modules/rules_rust/metadata.json @@ -0,0 +1,11 @@ +{ + "homepage": "https://github.com/bazelbuild/rules_rust", + "maintainers": [], + "repository": [ + "github:bazelbuild/rules_rust" + ], + "versions": [ + "0.68.1.codeql.1" + ], + "yanked_versions": {} +} diff --git a/python/ql/lib/change-notes/2026-02-09-ssrf_test_case_cleanup_and_new_ssrf_barriers.md b/python/ql/lib/change-notes/2026-02-09-ssrf_test_case_cleanup_and_new_ssrf_barriers.md new file mode 100644 index 00000000000..c3b4194e7b8 --- /dev/null +++ b/python/ql/lib/change-notes/2026-02-09-ssrf_test_case_cleanup_and_new_ssrf_barriers.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* Added new full SSRF sanitization barrier from the new AntiSSRF library. \ No newline at end of file diff --git a/python/ql/lib/semmle/python/security/dataflow/ServerSideRequestForgeryCustomizations.qll b/python/ql/lib/semmle/python/security/dataflow/ServerSideRequestForgeryCustomizations.qll index 274e7ee57ad..3fb260e425d 100644 --- a/python/ql/lib/semmle/python/security/dataflow/ServerSideRequestForgeryCustomizations.qll +++ b/python/ql/lib/semmle/python/security/dataflow/ServerSideRequestForgeryCustomizations.qll @@ -176,4 +176,36 @@ module ServerSideRequestForgery { strNode = [call.getArg(0), call.getArgByName("string")] ) } + + /** A validation of a URI using the `AntiSSRF` library, considered as a full-ssrf sanitizer. */ + private class UriValidator extends FullUrlControlSanitizer { + UriValidator() { this = DataFlow::BarrierGuard::getABarrierNode() } + } + + import semmle.python.dataflow.new.internal.DataFlowPublic + + private predicate uri_validator(DataFlow::GuardNode g, ControlFlowNode node, boolean branch) { + exists(DataFlow::CallCfgNode call, string funcs | + funcs in ["in_domain", "in_azure_keyvault_domain", "in_azure_storage_domain"] and + call = API::moduleImport("AntiSSRF").getMember("URIValidator").getMember(funcs).getACall() and + call.getArg(0).asCfgNode() = node + | + // validator call directly (e.g., if URIValidator.in_domain(...) ) + g = call.asCfgNode() and + branch = true + or + // validator used in a comparison + exists(Cmpop op, Node n, ControlFlowNode l | + n.getALocalSource() = call and g.(CompareNode).operands(n.asCfgNode(), op, l) + | + // validator == true or validator == false or validator is True or validator is False + (op instanceof Eq or op instanceof Is) and + branch = l.getNode().(BooleanLiteral).booleanValue() + or + // validator != false or validator != true or validator is not True or validator is not False + (op instanceof NotEq or op instanceof IsNot) and + branch = l.getNode().(BooleanLiteral).booleanValue().booleanNot() + ) + ) + } } 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 33970318461..7434eca6978 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,156 +1,263 @@ +#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 | 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:37:18:37:24 | ControlFlowNode for request | provenance | | -| full_partial_test.py:1:19:1:25 | ControlFlowNode for request | full_partial_test.py:57:18:57:24 | ControlFlowNode for request | provenance | | -| full_partial_test.py:1:19:1:25 | ControlFlowNode for request | full_partial_test.py:71:18:71:24 | ControlFlowNode for request | provenance | | -| full_partial_test.py:7:5:7:14 | ControlFlowNode for user_input | full_partial_test.py:10:18:10:27 | ControlFlowNode for user_input | provenance | | -| full_partial_test.py:7:5:7:14 | ControlFlowNode for user_input | full_partial_test.py:12:5:12:7 | ControlFlowNode for url | provenance | | -| full_partial_test.py:7:5:7:14 | ControlFlowNode for user_input | full_partial_test.py:18:5:18:7 | ControlFlowNode for url | provenance | | -| full_partial_test.py:7:5:7:14 | ControlFlowNode for user_input | full_partial_test.py:22:5:22:7 | ControlFlowNode for url | 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:12:5:12:7 | ControlFlowNode for url | full_partial_test.py:13:18:13:20 | ControlFlowNode for url | provenance | | -| full_partial_test.py:18:5:18:7 | ControlFlowNode for url | full_partial_test.py:19:18:19:20 | ControlFlowNode for url | provenance | | -| full_partial_test.py:22:5:22:7 | ControlFlowNode for url | full_partial_test.py:23:18:23:20 | ControlFlowNode for url | provenance | | -| full_partial_test.py:37:5:37:14 | ControlFlowNode for user_input | full_partial_test.py:41:5:41:7 | ControlFlowNode for url | provenance | | -| full_partial_test.py:37:5:37:14 | ControlFlowNode for user_input | full_partial_test.py:44:5:44:7 | ControlFlowNode for url | provenance | | -| full_partial_test.py:37:5:37:14 | ControlFlowNode for user_input | full_partial_test.py:47:5:47:7 | ControlFlowNode for url | provenance | | -| full_partial_test.py:37:5:37:14 | ControlFlowNode for user_input | full_partial_test.py:50:5:50:7 | ControlFlowNode for url | provenance | | -| full_partial_test.py:37:5:37:14 | ControlFlowNode for user_input | full_partial_test.py:53:5:53:7 | ControlFlowNode for url | provenance | | -| full_partial_test.py:37:18:37:24 | ControlFlowNode for request | full_partial_test.py:37:5:37:14 | ControlFlowNode for user_input | provenance | AdditionalTaintStep | -| full_partial_test.py:41:5:41:7 | ControlFlowNode for url | full_partial_test.py:42:18:42:20 | ControlFlowNode for url | provenance | | -| full_partial_test.py:44:5:44:7 | ControlFlowNode for url | full_partial_test.py:45:18:45:20 | ControlFlowNode for url | provenance | | -| full_partial_test.py:47:5:47:7 | ControlFlowNode for url | full_partial_test.py:48:18:48:20 | ControlFlowNode for url | provenance | | -| full_partial_test.py:50:5:50: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:54:18:54:20 | ControlFlowNode for url | provenance | | -| full_partial_test.py:57:5:57:14 | ControlFlowNode for user_input | full_partial_test.py:61:5:61:7 | ControlFlowNode for url | provenance | | -| full_partial_test.py:57:5:57:14 | ControlFlowNode for user_input | full_partial_test.py:64:5:64:7 | ControlFlowNode for url | provenance | | -| full_partial_test.py:57:18:57:24 | ControlFlowNode for request | full_partial_test.py:57:5:57:14 | ControlFlowNode for user_input | provenance | AdditionalTaintStep | -| full_partial_test.py:61:5:61:7 | ControlFlowNode for url | full_partial_test.py:62:18:62:20 | ControlFlowNode for url | provenance | | -| full_partial_test.py:64:5:64:7 | ControlFlowNode for url | full_partial_test.py:65:18:65:20 | ControlFlowNode for url | provenance | | -| full_partial_test.py:71:5:71:14 | ControlFlowNode for user_input | full_partial_test.py:75:5:75:7 | ControlFlowNode for url | provenance | | -| full_partial_test.py:71:5:71:14 | ControlFlowNode for user_input | full_partial_test.py:78:5:78:7 | ControlFlowNode for url | provenance | | -| full_partial_test.py:71:5:71:14 | ControlFlowNode for user_input | full_partial_test.py:81:5:81:7 | ControlFlowNode for url | provenance | | -| full_partial_test.py:71:18:71:24 | ControlFlowNode for request | full_partial_test.py:71:5:71:14 | ControlFlowNode for user_input | provenance | AdditionalTaintStep | -| full_partial_test.py:75:5:75: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:79:18:79:20 | ControlFlowNode for url | provenance | | -| full_partial_test.py:81:5:81:7 | ControlFlowNode for url | full_partial_test.py:82:18:82:20 | ControlFlowNode for url | provenance | | -| test_azure_client.py:7:19:7:25 | ControlFlowNode for ImportMember | test_azure_client.py:7:19:7:25 | ControlFlowNode for request | provenance | | -| test_azure_client.py:7:19:7:25 | ControlFlowNode for request | test_azure_client.py:10:18:10:24 | ControlFlowNode for request | provenance | | -| test_azure_client.py:7:19:7:25 | ControlFlowNode for request | test_azure_client.py:11:19:11:25 | ControlFlowNode for request | provenance | | -| test_azure_client.py:10:18:10:24 | ControlFlowNode for request | test_azure_client.py:11:5:11:15 | ControlFlowNode for user_input2 | provenance | AdditionalTaintStep | -| test_azure_client.py:11:5:11:15 | ControlFlowNode for user_input2 | test_azure_client.py:14:5:14:12 | ControlFlowNode for full_url | provenance | | -| test_azure_client.py:11:19:11:25 | ControlFlowNode for request | test_azure_client.py:11:5:11:15 | ControlFlowNode for user_input2 | provenance | AdditionalTaintStep | -| test_azure_client.py:14:5:14:12 | ControlFlowNode for full_url | test_azure_client.py:17:32:17:39 | ControlFlowNode for full_url | provenance | Sink:MaD:15 | -| test_azure_client.py:14:5:14:12 | ControlFlowNode for full_url | test_azure_client.py:19:39:19:46 | ControlFlowNode for full_url | provenance | Sink:MaD:38 | -| test_azure_client.py:14:5:14:12 | ControlFlowNode for full_url | test_azure_client.py:21:19:21:26 | ControlFlowNode for full_url | provenance | Sink:MaD:14 | -| test_azure_client.py:14:5:14:12 | ControlFlowNode for full_url | test_azure_client.py:23:58:23:65 | ControlFlowNode for full_url | provenance | Sink:MaD:26 | -| test_azure_client.py:14:5:14:12 | ControlFlowNode for full_url | test_azure_client.py:32:18:32:25 | ControlFlowNode for full_url | provenance | Sink:MaD:27 | -| test_http_client.py:1:26:1:32 | ControlFlowNode for ImportMember | test_http_client.py:1:26:1:32 | ControlFlowNode for request | provenance | | -| test_http_client.py:1:26:1:32 | ControlFlowNode for request | test_http_client.py:9:19:9:25 | ControlFlowNode for request | provenance | | -| test_http_client.py:1:26:1:32 | ControlFlowNode for request | test_http_client.py:10:19:10:25 | ControlFlowNode for request | provenance | | +| 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:18:27:18:37 | ControlFlowNode for unsafe_host | provenance | | -| test_http_client.py:9:5:9:15 | ControlFlowNode for unsafe_host | test_http_client.py:25:27:25: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:14:25:14:35 | ControlFlowNode for unsafe_path | provenance | | -| test_http_client.py:10:5:10:15 | ControlFlowNode for unsafe_path | test_http_client.py:19:25:19:35 | ControlFlowNode for unsafe_path | provenance | | -| test_http_client.py:10:5:10:15 | ControlFlowNode for unsafe_path | test_http_client.py:29:25:29:35 | ControlFlowNode for unsafe_path | provenance | | +| 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:6:18:6:24 | ControlFlowNode for request | provenance | | -| test_requests.py:6:5:6:14 | ControlFlowNode for user_input | test_requests.py:8:18:8:27 | ControlFlowNode for user_input | provenance | | -| test_requests.py:6:18:6:24 | ControlFlowNode for request | test_requests.py:6:5:6:14 | ControlFlowNode for user_input | provenance | AdditionalTaintStep | +| 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 | +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 | +| 3 | Sink: azure.storage.blob.ContainerClient!; Member[from_container_url].Argument[0,container_url:]; request-forgery | +| 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:10:18:10:27 | ControlFlowNode for user_input | semmle.label | ControlFlowNode for user_input | -| full_partial_test.py:12:5:12:7 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:13:18:13:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:18:5:18:7 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:19:18:19:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:22:5:22:7 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:23:18:23:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:37:5:37:14 | ControlFlowNode for user_input | semmle.label | ControlFlowNode for user_input | -| full_partial_test.py:37:18:37:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| full_partial_test.py:41:5:41:7 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:42:18:42:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:44:5:44:7 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:45:18:45:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:47:5:47:7 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:48:18:48:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:50:5:50:7 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| 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:54:18:54:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:57:5:57:14 | ControlFlowNode for user_input | semmle.label | ControlFlowNode for user_input | -| full_partial_test.py:57:18:57:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | +| 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:62:18:62:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:64:5:64:7 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:65:18:65:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:71:5:71:14 | ControlFlowNode for user_input | semmle.label | ControlFlowNode for user_input | -| full_partial_test.py:71:18:71:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| full_partial_test.py:75:5:75: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:78:5:78:7 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:79:18:79:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:81:5:81:7 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:82:18:82:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_azure_client.py:7:19:7:25 | ControlFlowNode for ImportMember | semmle.label | ControlFlowNode for ImportMember | -| test_azure_client.py:7:19:7:25 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| test_azure_client.py:10:18:10:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| test_azure_client.py:11:5:11:15 | ControlFlowNode for user_input2 | semmle.label | ControlFlowNode for user_input2 | -| test_azure_client.py:11:19:11:25 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| test_azure_client.py:14:5:14:12 | ControlFlowNode for full_url | semmle.label | ControlFlowNode for full_url | -| test_azure_client.py:17:32:17:39 | ControlFlowNode for full_url | semmle.label | ControlFlowNode for full_url | -| test_azure_client.py:19:39:19:46 | ControlFlowNode for full_url | semmle.label | ControlFlowNode for full_url | -| test_azure_client.py:21:19:21:26 | ControlFlowNode for full_url | semmle.label | ControlFlowNode for full_url | -| test_azure_client.py:23:58:23:65 | ControlFlowNode for full_url | semmle.label | ControlFlowNode for full_url | -| test_azure_client.py:32:18:32:25 | ControlFlowNode for full_url | semmle.label | ControlFlowNode for full_url | -| test_http_client.py:1:26:1:32 | ControlFlowNode for ImportMember | semmle.label | ControlFlowNode for ImportMember | -| test_http_client.py:1:26:1:32 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | +| 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:14:25:14:35 | ControlFlowNode for unsafe_path | semmle.label | ControlFlowNode for unsafe_path | -| test_http_client.py:18:27:18:37 | ControlFlowNode for unsafe_host | semmle.label | ControlFlowNode for unsafe_host | -| test_http_client.py:19:25:19:35 | ControlFlowNode for unsafe_path | semmle.label | ControlFlowNode for unsafe_path | -| test_http_client.py:25:27:25:37 | ControlFlowNode for unsafe_host | semmle.label | ControlFlowNode for unsafe_host | -| test_http_client.py:29:25:29:35 | ControlFlowNode for unsafe_path | semmle.label | ControlFlowNode for unsafe_path | +| 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:6:5:6:14 | ControlFlowNode for user_input | semmle.label | ControlFlowNode for user_input | -| test_requests.py:6:18:6:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| test_requests.py:8:18:8:27 | ControlFlowNode for user_input | semmle.label | ControlFlowNode for user_input | +| 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 | subpaths -#select -| full_partial_test.py:10:5:10:28 | ControlFlowNode for Attribute() | full_partial_test.py:1:19:1:25 | ControlFlowNode for ImportMember | full_partial_test.py:10:18:10: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:13:5:13:21 | ControlFlowNode for Attribute() | full_partial_test.py:1:19:1:25 | ControlFlowNode for ImportMember | full_partial_test.py:13:18:13: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:19:5:19:21 | ControlFlowNode for Attribute() | full_partial_test.py:1:19:1:25 | ControlFlowNode for ImportMember | full_partial_test.py:19:18:19: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:23:5:23:21 | ControlFlowNode for Attribute() | full_partial_test.py:1:19:1:25 | ControlFlowNode for ImportMember | full_partial_test.py:23:18:23: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:42:5:42:21 | ControlFlowNode for Attribute() | full_partial_test.py:1:19:1:25 | ControlFlowNode for ImportMember | full_partial_test.py:42:18:42: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:45:5:45:21 | ControlFlowNode for Attribute() | full_partial_test.py:1:19:1:25 | ControlFlowNode for ImportMember | full_partial_test.py:45:18:45: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:48:5:48:21 | ControlFlowNode for Attribute() | full_partial_test.py:1:19:1:25 | ControlFlowNode for ImportMember | full_partial_test.py:48:18:48: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:54:5:54:21 | ControlFlowNode for Attribute() | full_partial_test.py:1:19:1:25 | ControlFlowNode for ImportMember | full_partial_test.py:54:18:54: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:62:5:62:21 | ControlFlowNode for Attribute() | full_partial_test.py:1:19:1:25 | ControlFlowNode for ImportMember | full_partial_test.py:62:18:62: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:65:5:65:21 | ControlFlowNode for Attribute() | full_partial_test.py:1:19:1:25 | ControlFlowNode for ImportMember | full_partial_test.py:65:18:65: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:79:5:79:21 | ControlFlowNode for Attribute() | full_partial_test.py:1:19:1:25 | ControlFlowNode for ImportMember | full_partial_test.py:79:18:79: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:82:5:82:21 | ControlFlowNode for Attribute() | full_partial_test.py:1:19:1:25 | ControlFlowNode for ImportMember | full_partial_test.py:82:18:82: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:17:9:17:63 | ControlFlowNode for SecretClient() | test_azure_client.py:7:19:7:25 | ControlFlowNode for ImportMember | test_azure_client.py:17:32:17:39 | ControlFlowNode for full_url | The full URL of this request depends on a $@. | test_azure_client.py:7:19:7:25 | ControlFlowNode for ImportMember | user-provided value | -| test_azure_client.py:19:9:19:47 | ControlFlowNode for Attribute() | test_azure_client.py:7:19:7:25 | ControlFlowNode for ImportMember | test_azure_client.py:19:39:19:46 | ControlFlowNode for full_url | The full URL of this request depends on a $@. | test_azure_client.py:7:19:7:25 | ControlFlowNode for ImportMember | user-provided value | -| test_azure_client.py:21:9:21:39 | ControlFlowNode for KeyClient() | test_azure_client.py:7:19:7:25 | ControlFlowNode for ImportMember | test_azure_client.py:21:19:21:26 | ControlFlowNode for full_url | The full URL of this request depends on a $@. | test_azure_client.py:7:19:7:25 | ControlFlowNode for ImportMember | user-provided value | -| test_azure_client.py:23:9:23:89 | ControlFlowNode for Attribute() | test_azure_client.py:7:19:7:25 | ControlFlowNode for ImportMember | test_azure_client.py:23:58:23:65 | ControlFlowNode for full_url | The full URL of this request depends on a $@. | test_azure_client.py:7:19:7:25 | ControlFlowNode for ImportMember | user-provided value | -| test_azure_client.py:31:5:36:5 | ControlFlowNode for download_blob_from_url() | test_azure_client.py:7:19:7:25 | ControlFlowNode for ImportMember | test_azure_client.py:32:18:32:25 | ControlFlowNode for full_url | The full URL of this request depends on a $@. | test_azure_client.py:7:19:7:25 | ControlFlowNode for ImportMember | user-provided value | -| test_http_client.py:14:5:14:36 | ControlFlowNode for Attribute() | test_http_client.py:1:26:1:32 | 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:26:1:32 | ControlFlowNode for ImportMember | user-provided value | -| test_http_client.py:14:5:14:36 | ControlFlowNode for Attribute() | test_http_client.py:1:26:1:32 | ControlFlowNode for ImportMember | test_http_client.py:14:25:14:35 | ControlFlowNode for unsafe_path | The full URL of this request depends on a $@. | test_http_client.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value | -| test_http_client.py:19:5:19:36 | ControlFlowNode for Attribute() | test_http_client.py:1:26:1:32 | ControlFlowNode for ImportMember | test_http_client.py:18:27:18:37 | ControlFlowNode for unsafe_host | The full URL of this request depends on a $@. | test_http_client.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value | -| test_http_client.py:19:5:19:36 | ControlFlowNode for Attribute() | test_http_client.py:1:26:1:32 | ControlFlowNode for ImportMember | test_http_client.py:19:25:19:35 | ControlFlowNode for unsafe_path | The full URL of this request depends on a $@. | test_http_client.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value | -| test_requests.py:8:5:8:28 | ControlFlowNode for Attribute() | test_requests.py:1:19:1:25 | ControlFlowNode for ImportMember | test_requests.py:8:18:8: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 | diff --git a/python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/FullServerSideRequestForgery.qlref b/python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/FullServerSideRequestForgery.qlref index 50d53b5f47e..f0a8d1e6b15 100644 --- a/python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/FullServerSideRequestForgery.qlref +++ b/python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/FullServerSideRequestForgery.qlref @@ -1 +1,4 @@ -Security/CWE-918/FullServerSideRequestForgery.ql +query: Security/CWE-918/FullServerSideRequestForgery.ql +postprocess: +- utils/test/InlineExpectationsTestQuery.ql +- utils/test/PrettyPrintModels.ql \ No newline at end of file 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 bdcac746538..0b875607157 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,124 +1,242 @@ +#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 | 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:37:18:37:24 | ControlFlowNode for request | provenance | | -| full_partial_test.py:1:19:1:25 | ControlFlowNode for request | full_partial_test.py:38:17:38:23 | ControlFlowNode for request | provenance | | -| full_partial_test.py:1:19:1:25 | ControlFlowNode for request | full_partial_test.py:57:18:57:24 | ControlFlowNode for request | provenance | | -| full_partial_test.py:1:19:1:25 | ControlFlowNode for request | full_partial_test.py:58:17:58:23 | ControlFlowNode for request | provenance | | -| full_partial_test.py:1:19:1:25 | ControlFlowNode for request | full_partial_test.py:71:18:71:24 | ControlFlowNode for request | provenance | | -| full_partial_test.py:1:19:1:25 | ControlFlowNode for request | full_partial_test.py:72:17:72:23 | ControlFlowNode for request | provenance | | -| full_partial_test.py:1:19:1:25 | ControlFlowNode for request | full_partial_test.py:86:18:86:24 | ControlFlowNode for request | provenance | | -| full_partial_test.py:1:19:1:25 | ControlFlowNode for request | full_partial_test.py:92:18:92:24 | ControlFlowNode for request | provenance | | -| full_partial_test.py:1:19:1:25 | ControlFlowNode for request | full_partial_test.py:98:18:98:24 | ControlFlowNode for request | provenance | | -| full_partial_test.py:1:19:1:25 | ControlFlowNode for request | full_partial_test.py:104:18:104:24 | ControlFlowNode for request | provenance | | -| full_partial_test.py:1:19:1:25 | ControlFlowNode for request | full_partial_test.py:110:18:110:24 | ControlFlowNode for request | provenance | | -| full_partial_test.py:1:19:1:25 | ControlFlowNode for request | full_partial_test.py:119:18:119:24 | ControlFlowNode for request | provenance | | -| full_partial_test.py:7:5:7:14 | ControlFlowNode for user_input | full_partial_test.py:10:18:10:27 | ControlFlowNode for user_input | provenance | | -| full_partial_test.py:7:5:7:14 | ControlFlowNode for user_input | full_partial_test.py:12:5:12:7 | ControlFlowNode for url | provenance | | -| full_partial_test.py:7:5:7:14 | ControlFlowNode for user_input | full_partial_test.py:18:5:18:7 | ControlFlowNode for url | provenance | | -| full_partial_test.py:7:5:7:14 | ControlFlowNode for user_input | full_partial_test.py:22:5:22:7 | ControlFlowNode for url | 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:22:5:22:7 | ControlFlowNode for url | provenance | | +| 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:12:5:12:7 | ControlFlowNode for url | full_partial_test.py:13:18:13:20 | ControlFlowNode for url | provenance | | -| full_partial_test.py:18:5:18:7 | ControlFlowNode for url | full_partial_test.py:19:18:19:20 | ControlFlowNode for url | provenance | | -| full_partial_test.py:22:5:22:7 | ControlFlowNode for url | full_partial_test.py:23:18:23:20 | ControlFlowNode for url | provenance | | -| full_partial_test.py:37:5:37:14 | ControlFlowNode for user_input | full_partial_test.py:41:5:41:7 | ControlFlowNode for url | provenance | | -| full_partial_test.py:37:5:37:14 | ControlFlowNode for user_input | full_partial_test.py:44:5:44:7 | ControlFlowNode for url | provenance | | -| full_partial_test.py:37:5:37:14 | ControlFlowNode for user_input | full_partial_test.py:47:5:47:7 | ControlFlowNode for url | provenance | | -| full_partial_test.py:37:5:37:14 | ControlFlowNode for user_input | full_partial_test.py:50:5:50:7 | ControlFlowNode for url | provenance | | -| full_partial_test.py:37:5:37:14 | ControlFlowNode for user_input | full_partial_test.py:53:5:53:7 | ControlFlowNode for url | provenance | | -| full_partial_test.py:37:18:37:24 | ControlFlowNode for request | full_partial_test.py:37:5:37:14 | ControlFlowNode for user_input | provenance | AdditionalTaintStep | -| full_partial_test.py:37:18:37:24 | ControlFlowNode for request | full_partial_test.py:38:5:38:13 | ControlFlowNode for query_val | provenance | AdditionalTaintStep | -| full_partial_test.py:38:5:38:13 | ControlFlowNode for query_val | full_partial_test.py:47:5:47:7 | ControlFlowNode for url | provenance | | -| full_partial_test.py:38:17:38:23 | ControlFlowNode for request | full_partial_test.py:38:5:38:13 | ControlFlowNode for query_val | provenance | AdditionalTaintStep | -| full_partial_test.py:41:5:41:7 | ControlFlowNode for url | full_partial_test.py:42:18:42:20 | ControlFlowNode for url | provenance | | -| full_partial_test.py:44:5:44:7 | ControlFlowNode for url | full_partial_test.py:45:18:45:20 | ControlFlowNode for url | provenance | | -| full_partial_test.py:47:5:47:7 | ControlFlowNode for url | full_partial_test.py:48:18:48:20 | ControlFlowNode for url | provenance | | -| full_partial_test.py:50:5:50: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:54:18:54:20 | ControlFlowNode for url | provenance | | -| full_partial_test.py:57:5:57:14 | ControlFlowNode for user_input | full_partial_test.py:61:5:61:7 | ControlFlowNode for url | provenance | | -| full_partial_test.py:57:5:57:14 | ControlFlowNode for user_input | full_partial_test.py:64:5:64:7 | ControlFlowNode for url | provenance | | -| full_partial_test.py:57:5:57:14 | ControlFlowNode for user_input | full_partial_test.py:67:5:67:7 | ControlFlowNode for url | provenance | | -| full_partial_test.py:57:18:57:24 | ControlFlowNode for request | full_partial_test.py:57:5:57:14 | ControlFlowNode for user_input | provenance | AdditionalTaintStep | -| full_partial_test.py:57:18:57:24 | ControlFlowNode for request | full_partial_test.py:58:5:58:13 | ControlFlowNode for query_val | provenance | AdditionalTaintStep | -| full_partial_test.py:58:5:58:13 | ControlFlowNode for query_val | full_partial_test.py:67:5:67:7 | ControlFlowNode for url | provenance | | -| full_partial_test.py:58:17:58:23 | ControlFlowNode for request | full_partial_test.py:58:5:58:13 | ControlFlowNode for query_val | provenance | AdditionalTaintStep | -| full_partial_test.py:61:5:61:7 | ControlFlowNode for url | full_partial_test.py:62:18:62:20 | ControlFlowNode for url | provenance | | -| full_partial_test.py:64:5:64:7 | ControlFlowNode for url | full_partial_test.py:65:18:65:20 | ControlFlowNode for url | provenance | | -| full_partial_test.py:67:5:67:7 | ControlFlowNode for url | full_partial_test.py:68:18:68:20 | ControlFlowNode for url | provenance | | -| full_partial_test.py:71:5:71:14 | ControlFlowNode for user_input | full_partial_test.py:75:5:75:7 | ControlFlowNode for url | provenance | | -| full_partial_test.py:71:5:71:14 | ControlFlowNode for user_input | full_partial_test.py:78:5:78:7 | ControlFlowNode for url | provenance | | -| full_partial_test.py:71:5:71:14 | ControlFlowNode for user_input | full_partial_test.py:81:5:81:7 | ControlFlowNode for url | provenance | | -| full_partial_test.py:71:18:71:24 | ControlFlowNode for request | full_partial_test.py:71:5:71:14 | ControlFlowNode for user_input | provenance | AdditionalTaintStep | -| full_partial_test.py:71:18:71:24 | ControlFlowNode for request | full_partial_test.py:72:5:72:13 | ControlFlowNode for query_val | provenance | AdditionalTaintStep | -| full_partial_test.py:72:5:72:13 | ControlFlowNode for query_val | full_partial_test.py:81:5:81:7 | ControlFlowNode for url | provenance | | -| full_partial_test.py:72:17:72:23 | ControlFlowNode for request | full_partial_test.py:72:5:72:13 | ControlFlowNode for query_val | provenance | AdditionalTaintStep | -| full_partial_test.py:75:5:75: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:79:18:79:20 | ControlFlowNode for url | provenance | | -| full_partial_test.py:81:5:81:7 | ControlFlowNode for url | full_partial_test.py:82:18:82:20 | ControlFlowNode for url | provenance | | -| full_partial_test.py:86:5:86:14 | ControlFlowNode for user_input | full_partial_test.py:88:5:88:7 | ControlFlowNode for url | provenance | | -| full_partial_test.py:86:18:86:24 | ControlFlowNode for request | full_partial_test.py:86:5:86:14 | ControlFlowNode for user_input | provenance | AdditionalTaintStep | -| full_partial_test.py:88:5:88:7 | ControlFlowNode for url | full_partial_test.py:89:18:89:20 | ControlFlowNode for url | provenance | | -| full_partial_test.py:92:5:92:14 | ControlFlowNode for user_input | full_partial_test.py:94:5:94:7 | ControlFlowNode for url | provenance | | -| full_partial_test.py:92:18:92:24 | ControlFlowNode for request | full_partial_test.py:92:5:92:14 | ControlFlowNode for user_input | provenance | AdditionalTaintStep | -| full_partial_test.py:94:5:94:7 | ControlFlowNode for url | full_partial_test.py:95:18:95:20 | ControlFlowNode for url | provenance | | -| full_partial_test.py:98:5:98:14 | ControlFlowNode for user_input | full_partial_test.py:100:5:100:7 | ControlFlowNode for url | provenance | | -| full_partial_test.py:98:18:98:24 | ControlFlowNode for request | full_partial_test.py:98:5:98:14 | ControlFlowNode for user_input | provenance | AdditionalTaintStep | -| full_partial_test.py:100:5:100:7 | ControlFlowNode for url | full_partial_test.py:101:18:101:20 | ControlFlowNode for url | provenance | | -| full_partial_test.py:104:5:104:14 | ControlFlowNode for user_input | full_partial_test.py:106:5:106:7 | ControlFlowNode for url | provenance | | -| full_partial_test.py:104:18:104:24 | ControlFlowNode for request | full_partial_test.py:104:5:104:14 | ControlFlowNode for user_input | provenance | AdditionalTaintStep | -| full_partial_test.py:106:5:106:7 | ControlFlowNode for url | full_partial_test.py:107:18:107:20 | ControlFlowNode for url | provenance | | -| full_partial_test.py:110:5:110:14 | ControlFlowNode for user_input | full_partial_test.py:115:5:115:7 | ControlFlowNode for url | provenance | | -| full_partial_test.py:110:18:110:24 | ControlFlowNode for request | full_partial_test.py:110:5:110:14 | ControlFlowNode for user_input | provenance | AdditionalTaintStep | -| full_partial_test.py:115:5:115:7 | ControlFlowNode for url | full_partial_test.py:116:18:116:20 | ControlFlowNode for url | provenance | | -| full_partial_test.py:119:5:119:14 | ControlFlowNode for user_input | full_partial_test.py:121:5:121:7 | ControlFlowNode for url | provenance | | -| full_partial_test.py:119:18:119:24 | ControlFlowNode for request | full_partial_test.py:119:5:119:14 | ControlFlowNode for user_input | provenance | AdditionalTaintStep | -| full_partial_test.py:121:5:121:7 | ControlFlowNode for url | full_partial_test.py:122:18:122:20 | ControlFlowNode for url | provenance | | -| test_azure_client.py:7:19:7:25 | ControlFlowNode for ImportMember | test_azure_client.py:7:19:7:25 | ControlFlowNode for request | provenance | | -| test_azure_client.py:7:19:7:25 | ControlFlowNode for request | test_azure_client.py:10:18:10:24 | ControlFlowNode for request | provenance | | -| test_azure_client.py:7:19:7:25 | ControlFlowNode for request | test_azure_client.py:11:19:11:25 | ControlFlowNode for request | provenance | | -| test_azure_client.py:10:5:10:14 | ControlFlowNode for user_input | test_azure_client.py:13:5:13:7 | ControlFlowNode for url | provenance | | -| test_azure_client.py:10:18:10:24 | ControlFlowNode for request | test_azure_client.py:10:5:10:14 | ControlFlowNode for user_input | provenance | AdditionalTaintStep | -| test_azure_client.py:10:18:10:24 | ControlFlowNode for request | test_azure_client.py:11:5:11:15 | ControlFlowNode for user_input2 | provenance | AdditionalTaintStep | -| test_azure_client.py:11:5:11:15 | ControlFlowNode for user_input2 | test_azure_client.py:14:5:14:12 | ControlFlowNode for full_url | provenance | | -| test_azure_client.py:11:19:11:25 | ControlFlowNode for request | test_azure_client.py:11:5:11:15 | ControlFlowNode for user_input2 | provenance | AdditionalTaintStep | -| test_azure_client.py:13:5:13:7 | ControlFlowNode for url | test_azure_client.py:16:32:16:34 | ControlFlowNode for url | provenance | Sink:MaD:15 | -| test_azure_client.py:13:5:13:7 | ControlFlowNode for url | test_azure_client.py:18:39:18:41 | ControlFlowNode for url | provenance | Sink:MaD:38 | -| test_azure_client.py:13:5:13:7 | ControlFlowNode for url | test_azure_client.py:20:19:20:21 | ControlFlowNode for url | provenance | Sink:MaD:14 | -| test_azure_client.py:13:5:13:7 | ControlFlowNode for url | test_azure_client.py:22:58:22:60 | ControlFlowNode for url | provenance | Sink:MaD:26 | -| test_azure_client.py:13:5:13:7 | ControlFlowNode for url | test_azure_client.py:26:18:26:20 | ControlFlowNode for url | provenance | Sink:MaD:27 | -| test_azure_client.py:14:5:14:12 | ControlFlowNode for full_url | test_azure_client.py:17:32:17:39 | ControlFlowNode for full_url | provenance | Sink:MaD:15 | -| test_azure_client.py:14:5:14:12 | ControlFlowNode for full_url | test_azure_client.py:19:39:19:46 | ControlFlowNode for full_url | provenance | Sink:MaD:38 | -| test_azure_client.py:14:5:14:12 | ControlFlowNode for full_url | test_azure_client.py:21:19:21:26 | ControlFlowNode for full_url | provenance | Sink:MaD:14 | -| test_azure_client.py:14:5:14:12 | ControlFlowNode for full_url | test_azure_client.py:23:58:23:65 | ControlFlowNode for full_url | provenance | Sink:MaD:26 | -| test_azure_client.py:14:5:14:12 | ControlFlowNode for full_url | test_azure_client.py:32:18:32:25 | ControlFlowNode for full_url | provenance | Sink:MaD:27 | -| test_http_client.py:1:26:1:32 | ControlFlowNode for ImportMember | test_http_client.py:1:26:1:32 | ControlFlowNode for request | provenance | | -| test_http_client.py:1:26:1:32 | ControlFlowNode for request | test_http_client.py:9:19:9:25 | ControlFlowNode for request | provenance | | -| test_http_client.py:1:26:1:32 | ControlFlowNode for request | test_http_client.py:10:19:10:25 | ControlFlowNode for request | provenance | | -| test_http_client.py:1:26:1:32 | ControlFlowNode for request | test_http_client.py:11:18:11:24 | ControlFlowNode for request | provenance | | +| 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:18:27:18:37 | ControlFlowNode for unsafe_host | provenance | | -| test_http_client.py:9:5:9:15 | ControlFlowNode for unsafe_host | test_http_client.py:25:27:25: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:14:25:14:35 | ControlFlowNode for unsafe_path | provenance | | -| test_http_client.py:10:5:10:15 | ControlFlowNode for unsafe_path | test_http_client.py:19:25:19:35 | ControlFlowNode for unsafe_path | provenance | | -| test_http_client.py:10:5:10:15 | ControlFlowNode for unsafe_path | test_http_client.py:29:25:29:35 | ControlFlowNode for unsafe_path | provenance | | +| 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:31:5:31:8 | ControlFlowNode for path | provenance | | -| test_http_client.py:11:5:11:14 | ControlFlowNode for user_input | test_http_client.py:35:5:35:8 | ControlFlowNode for path | provenance | | +| 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:31:5:31:8 | ControlFlowNode for path | test_http_client.py:33:25:33:28 | ControlFlowNode for path | provenance | | -| test_http_client.py:35:5:35:8 | ControlFlowNode for path | test_http_client.py:37:25:37:28 | ControlFlowNode for path | provenance | | +| 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:6:18:6:24 | ControlFlowNode for request | provenance | | -| test_requests.py:6:5:6:14 | ControlFlowNode for user_input | test_requests.py:8:18:8:27 | ControlFlowNode for user_input | provenance | | -| test_requests.py:6:18:6:24 | ControlFlowNode for request | test_requests.py:6:5:6:14 | ControlFlowNode for user_input | provenance | AdditionalTaintStep | +| 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 | +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 | +| 3 | Sink: azure.storage.blob.ContainerClient!; Member[from_container_url].Argument[0,container_url:]; request-forgery | +| 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 | @@ -126,91 +244,91 @@ nodes | 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:10:18:10:27 | ControlFlowNode for user_input | semmle.label | ControlFlowNode for user_input | -| full_partial_test.py:12:5:12:7 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:13:18:13:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:18:5:18:7 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:19:18:19:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:22:5:22:7 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:23:18:23:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:37:5:37:14 | ControlFlowNode for user_input | semmle.label | ControlFlowNode for user_input | -| full_partial_test.py:37:18:37:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| full_partial_test.py:38:5:38:13 | ControlFlowNode for query_val | semmle.label | ControlFlowNode for query_val | -| full_partial_test.py:38:17:38:23 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| full_partial_test.py:41:5:41:7 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:42:18:42:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:44:5:44:7 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:45:18:45:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:47:5:47:7 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:48:18:48:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:50:5:50:7 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| 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:54:18:54:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:57:5:57:14 | ControlFlowNode for user_input | semmle.label | ControlFlowNode for user_input | -| full_partial_test.py:57:18:57:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| full_partial_test.py:58:5:58:13 | ControlFlowNode for query_val | semmle.label | ControlFlowNode for query_val | -| full_partial_test.py:58:17:58:23 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | +| 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:62:18:62:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:64:5:64:7 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:65:18:65:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:67:5:67:7 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:68:18:68:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:71:5:71:14 | ControlFlowNode for user_input | semmle.label | ControlFlowNode for user_input | -| full_partial_test.py:71:18:71:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| full_partial_test.py:72:5:72:13 | ControlFlowNode for query_val | semmle.label | ControlFlowNode for query_val | -| full_partial_test.py:72:17:72:23 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| full_partial_test.py:75:5:75: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:79:18:79:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:81:5:81:7 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:82:18:82:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:86:5:86:14 | ControlFlowNode for user_input | semmle.label | ControlFlowNode for user_input | -| full_partial_test.py:86:18:86:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| full_partial_test.py:88:5:88: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:92:5:92:14 | ControlFlowNode for user_input | semmle.label | ControlFlowNode for user_input | -| full_partial_test.py:92:18:92:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| full_partial_test.py:94:5:94:7 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:95:18:95:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:98:5:98:14 | ControlFlowNode for user_input | semmle.label | ControlFlowNode for user_input | -| full_partial_test.py:98:18:98:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| full_partial_test.py:100:5:100:7 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:101:18:101:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:104:5:104:14 | ControlFlowNode for user_input | semmle.label | ControlFlowNode for user_input | -| full_partial_test.py:104:18:104:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| full_partial_test.py:106:5:106:7 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:107:18:107:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:110:5:110:14 | ControlFlowNode for user_input | semmle.label | ControlFlowNode for user_input | -| full_partial_test.py:110:18:110:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| full_partial_test.py:115:5:115:7 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:116:18:116:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:119:5:119:14 | ControlFlowNode for user_input | semmle.label | ControlFlowNode for user_input | -| full_partial_test.py:119:18:119:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| full_partial_test.py:121:5:121:7 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| full_partial_test.py:122:18:122:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_azure_client.py:7:19:7:25 | ControlFlowNode for ImportMember | semmle.label | ControlFlowNode for ImportMember | -| test_azure_client.py:7:19:7:25 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| test_azure_client.py:10:5:10:14 | ControlFlowNode for user_input | semmle.label | ControlFlowNode for user_input | -| test_azure_client.py:10:18:10:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| test_azure_client.py:11:5:11:15 | ControlFlowNode for user_input2 | semmle.label | ControlFlowNode for user_input2 | -| test_azure_client.py:11:19:11:25 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| test_azure_client.py:13:5:13:7 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_azure_client.py:14:5:14:12 | ControlFlowNode for full_url | semmle.label | ControlFlowNode for full_url | -| test_azure_client.py:16:32:16:34 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_azure_client.py:17:32:17:39 | ControlFlowNode for full_url | semmle.label | ControlFlowNode for full_url | -| test_azure_client.py:18:39:18:41 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_azure_client.py:19:39:19:46 | ControlFlowNode for full_url | semmle.label | ControlFlowNode for full_url | -| test_azure_client.py:20:19:20:21 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_azure_client.py:21:19:21:26 | ControlFlowNode for full_url | semmle.label | ControlFlowNode for full_url | -| test_azure_client.py:22:58:22:60 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_azure_client.py:23:58:23:65 | ControlFlowNode for full_url | semmle.label | ControlFlowNode for full_url | -| test_azure_client.py:26:18:26:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_azure_client.py:32:18:32:25 | ControlFlowNode for full_url | semmle.label | ControlFlowNode for full_url | -| test_http_client.py:1:26:1:32 | ControlFlowNode for ImportMember | semmle.label | ControlFlowNode for ImportMember | -| test_http_client.py:1:26:1:32 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | +| 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 | @@ -218,36 +336,87 @@ nodes | 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:14:25:14:35 | ControlFlowNode for unsafe_path | semmle.label | ControlFlowNode for unsafe_path | -| test_http_client.py:18:27:18:37 | ControlFlowNode for unsafe_host | semmle.label | ControlFlowNode for unsafe_host | -| test_http_client.py:19:25:19:35 | ControlFlowNode for unsafe_path | semmle.label | ControlFlowNode for unsafe_path | -| test_http_client.py:25:27:25:37 | ControlFlowNode for unsafe_host | semmle.label | ControlFlowNode for unsafe_host | -| test_http_client.py:29:25:29:35 | ControlFlowNode for unsafe_path | semmle.label | ControlFlowNode for unsafe_path | -| test_http_client.py:31:5:31:8 | ControlFlowNode for path | semmle.label | ControlFlowNode for path | -| test_http_client.py:33:25:33:28 | ControlFlowNode for path | semmle.label | ControlFlowNode for path | -| test_http_client.py:35:5:35:8 | ControlFlowNode for path | semmle.label | ControlFlowNode for path | -| test_http_client.py:37:25:37:28 | ControlFlowNode for path | semmle.label | ControlFlowNode for path | +| 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:6:5:6:14 | ControlFlowNode for user_input | semmle.label | ControlFlowNode for user_input | -| test_requests.py:6:18:6:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| test_requests.py:8:18:8:27 | ControlFlowNode for user_input | semmle.label | ControlFlowNode for user_input | +| 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 | subpaths -#select -| full_partial_test.py:68:5:68:21 | ControlFlowNode for Attribute() | full_partial_test.py:1:19:1:25 | ControlFlowNode for ImportMember | full_partial_test.py:68:18:68: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: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 | 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:95:5:95:21 | ControlFlowNode for Attribute() | full_partial_test.py:1:19:1:25 | ControlFlowNode for ImportMember | full_partial_test.py:95:18:95: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:101:5:101:21 | ControlFlowNode for Attribute() | full_partial_test.py:1:19:1:25 | ControlFlowNode for ImportMember | full_partial_test.py:101:18:101: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:107:5:107:21 | ControlFlowNode for Attribute() | full_partial_test.py:1:19:1:25 | ControlFlowNode for ImportMember | full_partial_test.py:107:18:107: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:116:5:116:21 | ControlFlowNode for Attribute() | full_partial_test.py:1:19:1:25 | ControlFlowNode for ImportMember | full_partial_test.py:116:18:116: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:122:5:122:21 | ControlFlowNode for Attribute() | full_partial_test.py:1:19:1:25 | ControlFlowNode for ImportMember | full_partial_test.py:122:18:122: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:16:9:16:58 | ControlFlowNode for SecretClient() | test_azure_client.py:7:19:7:25 | ControlFlowNode for ImportMember | test_azure_client.py:16:32:16:34 | ControlFlowNode for url | Part of the URL of this request depends on a $@. | test_azure_client.py:7:19:7:25 | ControlFlowNode for ImportMember | user-provided value | -| test_azure_client.py:18:9:18:42 | ControlFlowNode for Attribute() | test_azure_client.py:7:19:7:25 | ControlFlowNode for ImportMember | test_azure_client.py:18:39:18:41 | ControlFlowNode for url | Part of the URL of this request depends on a $@. | test_azure_client.py:7:19:7:25 | ControlFlowNode for ImportMember | user-provided value | -| test_azure_client.py:20:9:20:34 | ControlFlowNode for KeyClient() | test_azure_client.py:7:19:7:25 | ControlFlowNode for ImportMember | test_azure_client.py:20:19:20:21 | ControlFlowNode for url | Part of the URL of this request depends on a $@. | test_azure_client.py:7:19:7:25 | ControlFlowNode for ImportMember | user-provided value | -| test_azure_client.py:22:9:22:84 | ControlFlowNode for Attribute() | test_azure_client.py:7:19:7:25 | ControlFlowNode for ImportMember | test_azure_client.py:22:58:22:60 | ControlFlowNode for url | Part of the URL of this request depends on a $@. | test_azure_client.py:7:19:7:25 | ControlFlowNode for ImportMember | user-provided value | -| test_azure_client.py:25:5:30:5 | ControlFlowNode for download_blob_from_url() | test_azure_client.py:7:19:7:25 | ControlFlowNode for ImportMember | test_azure_client.py:26:18:26:20 | ControlFlowNode for url | Part of the URL of this request depends on a $@. | test_azure_client.py:7:19:7:25 | ControlFlowNode for ImportMember | user-provided value | -| test_http_client.py:22:5:22:31 | ControlFlowNode for Attribute() | test_http_client.py:1:26:1:32 | ControlFlowNode for ImportMember | test_http_client.py:18:27:18:37 | ControlFlowNode for unsafe_host | Part of the URL of this request depends on a $@. | test_http_client.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value | -| test_http_client.py:26:5:26:31 | ControlFlowNode for Attribute() | test_http_client.py:1:26:1:32 | ControlFlowNode for ImportMember | test_http_client.py:25:27:25:37 | ControlFlowNode for unsafe_host | Part of the URL of this request depends on a $@. | test_http_client.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value | -| test_http_client.py:29:5:29:36 | ControlFlowNode for Attribute() | test_http_client.py:1:26:1:32 | ControlFlowNode for ImportMember | test_http_client.py:29:25:29:35 | ControlFlowNode for unsafe_path | Part of the URL of this request depends on a $@. | test_http_client.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value | -| test_http_client.py:33:5:33:29 | ControlFlowNode for Attribute() | test_http_client.py:1:26:1:32 | ControlFlowNode for ImportMember | test_http_client.py:33:25:33:28 | ControlFlowNode for path | Part of the URL of this request depends on a $@. | test_http_client.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value | -| test_http_client.py:37:5:37:29 | ControlFlowNode for Attribute() | test_http_client.py:1:26:1:32 | ControlFlowNode for ImportMember | test_http_client.py:37:25:37:28 | ControlFlowNode for path | Part of the URL of this request depends on a $@. | test_http_client.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value | diff --git a/python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/PartialServerSideRequestForgery.qlref b/python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/PartialServerSideRequestForgery.qlref index 88de9285e5e..1161c990e22 100644 --- a/python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/PartialServerSideRequestForgery.qlref +++ b/python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/PartialServerSideRequestForgery.qlref @@ -1 +1,4 @@ -Security/CWE-918/PartialServerSideRequestForgery.ql +query: Security/CWE-918/PartialServerSideRequestForgery.ql +postprocess: +- utils/test/InlineExpectationsTestQuery.ql +- utils/test/PrettyPrintModels.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/full_partial_test.py b/python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/full_partial_test.py index 95ff9d64944..7b7d067b611 100644 --- a/python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/full_partial_test.py +++ b/python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/full_partial_test.py @@ -1,4 +1,4 @@ -from flask import request +from flask import request # $ Source import requests import re @@ -7,20 +7,24 @@ def full_ssrf(): user_input = request.args['untrusted_input'] query_val = request.args['query_val'] - requests.get(user_input) # NOT OK -- user has full control + # NOT OK -- user has full control + requests.get(user_input) # $ Alert[py/full-ssrf] url = "https://" + user_input - requests.get(url) # NOT OK -- user has full control + # NOT OK -- user has full control + requests.get(url) # $ Alert[py/full-ssrf] # although the path `/foo` is added here, this can be circumvented such that the # final URL is `https://evil.com/#/foo" -- since the fragment (#) is not sent to the # server. url = "https://" + user_input + "/foo" - requests.get(url) # NOT OK -- user has full control + # NOT OK -- user has full control + requests.get(url) # $ Alert[py/full-ssrf] # this might seem like a dummy test, but it serves to check how our sanitizers work. url = "https://" + user_input + "/foo?key=" + query_val - requests.get(url) # NOT OK -- user has full control + # NOT OK -- user has full control + requests.get(url) # $ Alert[py/full-ssrf] # taint-steps are added as `fromNode -> toNode`, but when adding a sanitizer it's # currently only possible to so on either `fromNode` or `toNode` (either all edges in @@ -39,19 +43,24 @@ def full_ssrf_format(): # using .format url = "https://{}".format(user_input) - requests.get(url) # NOT OK -- user has full control + # NOT OK -- user has full control + requests.get(url) # $ Alert[py/full-ssrf] url = "https://{}/foo".format(user_input) - requests.get(url) # NOT OK -- user has full control + # NOT OK -- user has full control + requests.get(url) # $ Alert[py/full-ssrf] url = "https://{}/foo?key={}".format(user_input, query_val) - requests.get(url) # NOT OK -- user has full control + # NOT OK -- user has full control + requests.get(url) # $ Alert[py/full-ssrf] url = "https://{x}".format(x=user_input) - requests.get(url) # NOT OK -- user has full control + # NOT OK -- user has full control + requests.get(url) # $ Alert[py/full-ssrf] url = "https://{1}".format(0, user_input) - requests.get(url) # NOT OK -- user has full control + # NOT OK -- user has full control + requests.get(url) # $ Alert[py/full-ssrf] def full_ssrf_percent_format(): user_input = request.args['untrusted_input'] @@ -59,13 +68,16 @@ def full_ssrf_percent_format(): # using %-formatting url = "https://%s" % user_input - requests.get(url) # NOT OK -- user has full control + # NOT OK -- user has full control + requests.get(url) # $ Alert[py/full-ssrf] url = "https://%s/foo" % user_input - requests.get(url) # NOT OK -- user has full control + # NOT OK -- user has full control + requests.get(url) # $ Alert[py/full-ssrf] url = "https://%s/foo/key=%s" % (user_input, query_val) - requests.get(url) # NOT OK -- user has full control + # NOT OK -- user has full and partial control + requests.get(url) # $ Alert[py/partial-ssrf] $ MISSING: Alert[py/full-ssrf] def full_ssrf_f_strings(): user_input = request.args['untrusted_input'] @@ -73,38 +85,45 @@ def full_ssrf_f_strings(): # using f-strings url = f"https://{user_input}" - requests.get(url) # NOT OK -- user has full control + # NOT OK -- user has full control + requests.get(url) # $ Alert[py/full-ssrf] url = f"https://{user_input}/foo" - requests.get(url) # NOT OK -- user has full control + # NOT OK -- user has full control + requests.get(url) # $ Alert[py/full-ssrf] url = f"https://{user_input}/foo?key={query_val}" - requests.get(url) # NOT OK -- user has full control + # NOT OK -- user has full control + requests.get(url) # $ Alert[py/full-ssrf] def partial_ssrf_1(): user_input = request.args['untrusted_input'] url = "https://example.com/foo?" + user_input - requests.get(url) # NOT OK -- user controls query parameters + # NOT OK -- user controls query parameters + requests.get(url) # $ Alert[py/partial-ssrf] def partial_ssrf_2(): user_input = request.args['untrusted_input'] url = "https://example.com/" + user_input - requests.get(url) # NOT OK -- user controls path + # NOT OK -- user controls path + requests.get(url) # $ Alert[py/partial-ssrf] def partial_ssrf_3(): user_input = request.args['untrusted_input'] url = "https://example.com/" + user_input - requests.get(url) # NOT OK -- user controls path + # NOT OK -- user controls path + requests.get(url) # $ Alert[py/partial-ssrf] def partial_ssrf_4(): user_input = request.args['untrusted_input'] url = "https://example.com/foo#{}".format(user_input) - requests.get(url) # NOT OK -- user contollred fragment + # NOT OK -- user controlled fragment + requests.get(url) # $ Alert[py/partial-ssrf] def partial_ssrf_5(): user_input = request.args['untrusted_input'] @@ -113,20 +132,22 @@ def partial_ssrf_5(): # controlled url = "https://example.com/foo#%s" % user_input - requests.get(url) # NOT OK -- user contollred fragment + # NOT OK -- user controlled fragment + requests.get(url) # $ Alert[py/partial-ssrf] def partial_ssrf_6(): user_input = request.args['untrusted_input'] url = f"https://example.com/foo#{user_input}" - requests.get(url) # NOT OK -- user only controlled fragment + # NOT OK -- user only controlled fragment + requests.get(url) # $ Alert[py/partial-ssrf] def partial_ssrf_7(): user_input = request.args['untrusted_input'] if user_input.isalnum(): url = f"https://example.com/foo#{user_input}" - requests.get(url) # OK - user input can only contain alphanumerical characters + requests.get(url) # OK - user input can only contain alphanumerical characters if user_input.isalpha(): url = f"https://example.com/foo#{user_input}" @@ -154,7 +175,8 @@ def partial_ssrf_7(): if re.fullmatch(r'.*[a-zA-Z0-9]+.*', user_input): url = f"https://example.com/foo#{user_input}" - requests.get(url) # NOT OK, but NOT FOUND - user input can contain arbitrary characters + # NOT OK, but NOT FOUND - user input can contain arbitrary characters + requests.get(url) # $ MISSING: Alert[py/partial-ssrf] if re.match(r'^[a-zA-Z0-9]+$', user_input): @@ -163,7 +185,8 @@ def partial_ssrf_7(): if re.match(r'[a-zA-Z0-9]+', user_input): url = f"https://example.com/foo#{user_input}" - requests.get(url) # NOT OK, but NOT FOUND - user input can contain arbitrary character as a suffix. + # NOT OK, but NOT FOUND - user input can contain arbitrary character as a suffix. + requests.get(url) # $ MISSING: Alert[py/partial-ssrf] reg = re.compile(r'^[a-zA-Z0-9]+$') diff --git a/python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/test_azure_client.py b/python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/test_azure_client.py index d8de2092a2e..ac4ff4d365e 100644 --- a/python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/test_azure_client.py +++ b/python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/test_azure_client.py @@ -3,8 +3,7 @@ from azure.storage.fileshare import ShareFileClient from azure.keyvault.keys import KeyClient from azure.storage.blob import ContainerClient from azure.storage.blob import download_blob_from_url - -from flask import request +from flask import request # $ Source def azure_sdk_test(credential, output_path): user_input = request.args['untrusted_input'] @@ -13,24 +12,14 @@ def azure_sdk_test(credential, output_path): url = f"https://example.com/foo#{user_input}" full_url = f"https://{user_input2}" # Testing Azure sink - c = SecretClient(vault_url=url, credential=credential)# NOT OK -- user only controlled fragment - c = SecretClient(vault_url=full_url, credential=credential) # NOT OK -- user has full control - c = ShareFileClient.from_file_url(url) # NOT OK -- user only controlled fragment - c = ShareFileClient.from_file_url(full_url) # NOT OK -- user has full control - c = KeyClient(url, credential)# NOT OK -- user only controlled fragment - c = KeyClient(full_url, credential) # NOT OK -- user has full control - c = ContainerClient.from_container_url(container_url=url, credential=credential) # NOT OK -- user only controlled fragment - c = ContainerClient.from_container_url(container_url=full_url, credential=credential) # NOT OK -- user has full control + SecretClient(vault_url=url, credential=credential) # $ Alert[py/partial-ssrf] + SecretClient(vault_url=full_url, credential=credential) # $ Alert[py/full-ssrf] + ShareFileClient.from_file_url(url) # $ Alert[py/partial-ssrf] + ShareFileClient.from_file_url(full_url) # $ Alert[py/full-ssrf] + KeyClient(url, credential) # $ Alert[py/partial-ssrf] + KeyClient(full_url, credential) # $ Alert[py/full-ssrf] + ContainerClient.from_container_url(container_url=url, credential=credential) # $ Alert[py/partial-ssrf] + ContainerClient.from_container_url(container_url=full_url, credential=credential) # $ Alert[py/full-ssrf] - download_blob_from_url( - blob_url=url, # NOT OK -- user only controlled fragment - output=output_path, - credential=credential, - overwrite=True - ) - download_blob_from_url( - blob_url=full_url, # NOT OK -- user has full control - output=output_path, - credential=credential, - overwrite=True - ) + download_blob_from_url(blob_url=url, output=output_path, credential=credential, overwrite=True ) # $ Alert[py/partial-ssrf] + download_blob_from_url(blob_url=full_url, output=output_path, credential=credential, overwrite=True) # $ Alert[py/full-ssrf] diff --git a/python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/test_http_client.py b/python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/test_http_client.py index c833907d843..da812eb6c54 100644 --- a/python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/test_http_client.py +++ b/python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/test_http_client.py @@ -1,5 +1,5 @@ -from flask import Flask, request - +from flask import request # $ Source +from flask import Flask from http.client import HTTPConnection app = Flask(__name__) @@ -10,28 +10,35 @@ def ssrf_test(): unsafe_path = request.args["path"] user_input = request.args['untrusted_input'] - conn = HTTPConnection(unsafe_host) - conn.request("GET", unsafe_path) # NOT OK -- user has full control + conn = HTTPConnection(unsafe_host) # $ Sink[py/full-ssrf] + # NOT OK -- user has full control + conn.request("GET", unsafe_path) # $ Alert[py/full-ssrf] - # Full SSRF variant, where there is ALSO made a request with fixed URL on the same + # Full SSRF variant, where there is also a request with fixed URL on the same # connection later on. This should not change anything on the overall SSRF alerts. - conn = HTTPConnection(unsafe_host) - conn.request("GET", unsafe_path) # NOT OK -- user has full control + conn = HTTPConnection(unsafe_host) # $ Sink + # NOT OK -- user has full control + conn.request("GET", unsafe_path) # $ Alert[py/full-ssrf] # partial SSRF on SAME connection - conn.request("GET", "/foo") # NOT OK -- user has control of host + # NOT OK -- user has control of host + conn.request("GET", "/foo") # $ Alert[py/partial-ssrf] # the rest are partial SSRF - conn = HTTPConnection(unsafe_host) - conn.request("GET", "/foo") # NOT OK -- user controlled domain + conn = HTTPConnection(unsafe_host) # $ Sink[py/partial-ssrf] + # NOT OK -- user controlled domain + conn.request("GET", "/foo") # $ Alert[py/partial-ssrf] conn = HTTPConnection("example.com") - conn.request("GET", unsafe_path) # NOT OK -- user controlled path + # NOT OK -- user controlled path + conn.request("GET", unsafe_path) # $ Alert[py/partial-ssrf] path = "foo?" + user_input conn = HTTPConnection("example.com") - conn.request("GET", path) # NOT OK -- user controlled query parameters + # NOT OK -- user controlled query parameters + conn.request("GET", path) # $ Alert[py/partial-ssrf] path = "foo#" + user_input conn = HTTPConnection("example.com") - conn.request("GET", path) # NOT OK -- user controlled fragment + # NOT OK -- user controlled fragment + conn.request("GET", path) # $ Alert[py/partial-ssrf] \ No newline at end of file diff --git a/python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/test_path_validation.py b/python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/test_path_validation.py new file mode 100644 index 00000000000..ce5a6d33833 --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/test_path_validation.py @@ -0,0 +1,132 @@ +from azure.keyvault.secrets import SecretClient +from azure.storage.fileshare import ShareFileClient +from azure.keyvault.keys import KeyClient +from AntiSSRF import URIValidator +from flask import request # $ Source + +def urivalidator_path_in_domain_validation(credential, trusted_domain): + user_input = request.args['untrusted_input'] + user_input2 = request.args['untrusted_input2'] + url = f"https://example.com/foo#{user_input}" + full_url = f"https://{user_input2}" + + if URIValidator.in_domain(url, trusted_domain): + SecretClient(vault_url=url, credential=credential) # $ Alert[py/partial-ssrf] + else: + SecretClient(vault_url=url, credential=credential) # $ Alert[py/partial-ssrf] + + if URIValidator.in_domain(full_url, trusted_domain): + SecretClient(vault_url=full_url, credential=credential) # $ Alert[py/partial-ssrf] + else: + SecretClient(vault_url=full_url, credential=credential) # $ Alert[py/full-ssrf] + +def urivalidator_path_in_azure_keyvault_domain_validation(credential): + user_input = request.args['untrusted_input'] + user_input2 = request.args['untrusted_input2'] + url = f"https://example.com/foo#{user_input}" + full_url = f"https://{user_input2}" + + if URIValidator.in_azure_keyvault_domain(url): + KeyClient(vault_url=url, credential=credential) # $ Alert[py/partial-ssrf] + else: + KeyClient(vault_url=url, credential=credential) # $ Alert[py/partial-ssrf] + + if URIValidator.in_azure_keyvault_domain(full_url): + KeyClient(vault_url=full_url, credential=credential) # $ Alert[py/partial-ssrf] + else: + KeyClient(vault_url=full_url, credential=credential) # $ Alert[py/full-ssrf] + +def urivalidator_path_in_azure_storage_domain_validation(credential): + user_input = request.args['untrusted_input'] + user_input2 = request.args['untrusted_input2'] + url = f"https://example.com/foo#{user_input}" + full_url = f"https://{user_input2}" + + if URIValidator.in_azure_storage_domain(url): + ShareFileClient.from_file_url(url) # $ Alert[py/partial-ssrf] + else: + ShareFileClient.from_file_url(url) # $ Alert[py/partial-ssrf] + + if URIValidator.in_azure_storage_domain(full_url): + ShareFileClient.from_file_url(full_url) # $ Alert[py/partial-ssrf] + else: + ShareFileClient.from_file_url(full_url) # $ Alert[py/full-ssrf] + + +def complex_urivalidator_checks(credential, trusted_domain): + user_input = request.args['untrusted_input'] + # Focus on in_domain only here for simplicity + # It is assumed that the logic underlying path checking would apply + # similarly to other validator methods. + url = f"https://{user_input}" + + if not URIValidator.in_domain(url, trusted_domain): + SecretClient(vault_url=url, credential=credential) # $ Alert[py/full-ssrf] + else: + SecretClient(vault_url=url, credential=credential) # $ Alert[py/partial-ssrf] + + if URIValidator.in_domain(url, trusted_domain) and trusted_domain == "example.com": + SecretClient(vault_url=url, credential=credential) # $ Alert[py/partial-ssrf] + else: + SecretClient(vault_url=url, credential=credential) # $ Alert[py/full-ssrf] + + if not (URIValidator.in_domain(url, trusted_domain) and trusted_domain == "example.com"): + SecretClient(vault_url=url, credential=credential) # $ Alert[py/full-ssrf] + else: + SecretClient(vault_url=url, credential=credential) # $ Alert[py/partial-ssrf] + + if not not not URIValidator.in_domain(url, trusted_domain): + SecretClient(vault_url=url, credential=credential) # $ Alert[py/full-ssrf] + else: + SecretClient(vault_url=url, credential=credential) # $ Alert[py/partial-ssrf] + + + if URIValidator.in_domain(url, trusted_domain) == True: + SecretClient(vault_url=url, credential=credential) # $ Alert[py/partial-ssrf] + else: + SecretClient(vault_url=url, credential=credential) # $ Alert[py/full-ssrf] + + if URIValidator.in_domain(url, trusted_domain) == False: + SecretClient(vault_url=url, credential=credential) # $ Alert[py/full-ssrf] + else: + SecretClient(vault_url=url, credential=credential) # $ Alert[py/partial-ssrf] + + if URIValidator.in_domain(url, trusted_domain) != True: + SecretClient(vault_url=url, credential=credential) # $ Alert[py/full-ssrf] + else: + SecretClient(vault_url=url, credential=credential) # $ Alert[py/partial-ssrf] + + if URIValidator.in_domain(url, trusted_domain) != False: + SecretClient(vault_url=url, credential=credential) # $ Alert[py/partial-ssrf] + else: + SecretClient(vault_url=url, credential=credential) # $ Alert[py/full-ssrf] + + if URIValidator.in_domain(url, trusted_domain) is True: + SecretClient(vault_url=url, credential=credential) # $ Alert[py/partial-ssrf] + else: + SecretClient(vault_url=url, credential=credential) # $ Alert[py/full-ssrf] + + if URIValidator.in_domain(url, trusted_domain) is False: + SecretClient(vault_url=url, credential=credential) # $ Alert[py/full-ssrf] + else: + SecretClient(vault_url=url, credential=credential) # $ Alert[py/partial-ssrf] + + if URIValidator.in_domain(url, trusted_domain) is not True: + SecretClient(vault_url=url, credential=credential) # $ Alert[py/full-ssrf] + else: + SecretClient(vault_url=url, credential=credential) # $ Alert[py/partial-ssrf] + + if URIValidator.in_domain(url, trusted_domain) is not False: + SecretClient(vault_url=url, credential=credential) # $ Alert[py/partial-ssrf] + else: + SecretClient(vault_url=url, credential=credential) # $ Alert[py/full-ssrf] + + if not URIValidator.in_domain(url, trusted_domain) is True: + SecretClient(vault_url=url, credential=credential) # $ Alert[py/full-ssrf] + else: + SecretClient(vault_url=url, credential=credential) # $ Alert[py/partial-ssrf] + + if not URIValidator.in_domain(url, trusted_domain) is False: + SecretClient(vault_url=url, credential=credential) # $ Alert[py/partial-ssrf] + else: + SecretClient(vault_url=url, credential=credential) # $ Alert[py/full-ssrf] \ No newline at end of file diff --git a/python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/test_requests.py b/python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/test_requests.py index 443f5c3b81f..6489096c969 100644 --- a/python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/test_requests.py +++ b/python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/test_requests.py @@ -1,11 +1,51 @@ -from flask import request +from flask import request # $ Source[py/full-ssrf] +from AntiSSRF import AntiSSRFPolicy import requests -def ssrf_test(): +def ssrf_test1(): user_input = request.args['untrusted_input'] - - requests.get(user_input) # NOT OK -- user has full control - + # NOT OK -- user has full control + requests.get(user_input) # $ Alert[py/full-ssrf] # since `requests`` always uses complete URLs, it's not interesting to test more of # the framework directly. See `full_partial_test.py` for different ways to do SSRF. + +def ssrf_test2(): + user_input = request.args['untrusted_input'] + # NOT OK -- user has full control + session = requests.Session() + session.get(user_input) # $ Alert[py/full-ssrf] + +def ssrf_test3(): + user_input = request.args['untrusted_input'] + # NOT OK -- user has full control + requests.request('', user_input) # $ Alert[py/full-ssrf] + +def ssrf_test_with_policy1(): + user_input = request.args['untrusted_input'] + policy = AntiSSRFPolicy() + session = policy.get_antissrf_session() + # OK -- dangerous user input is filtered by AntiSSRFPolicy + session.get(user_input) + +def ssrf_test_with_policy2(): + user_input = request.args['untrusted_input'] + policy = AntiSSRFPolicy() + session = policy.get_antissrf_session() + # overwriting the HTTPAdapter to default requests adapter + # this makes the session unsafe again + session.mount("http://", requests.adapters.HTTPAdapter()) + # NOT OK -- dangerous user input is no longer filtered by AntiSSRFPolicy + # TODO: not currently a scenario we detect. + session.get(user_input) # $ MISSING: Alert[py/full-ssrf] + +def ssrf_test_with_policy3(adapter): + user_input = request.args['untrusted_input'] + policy = AntiSSRFPolicy() + session = policy.get_antissrf_session() + # overwriting the HTTPAdapter to a custom requests adapter + # this could make the session unsafe again + session.mount("http://", adapter) + # NOT OK -- dangerous user input is no longer filtered by AntiSSRFPolicy + # TODO: not currently a scenario we detect. + session.get(user_input) # $ MISSING: Alert[py/full-ssrf] \ No newline at end of file diff --git a/rust/ql/lib/codeql/rust/internal/PathResolution.qll b/rust/ql/lib/codeql/rust/internal/PathResolution.qll index 432608f6f9d..76c15485bb9 100644 --- a/rust/ql/lib/codeql/rust/internal/PathResolution.qll +++ b/rust/ql/lib/codeql/rust/internal/PathResolution.qll @@ -107,7 +107,7 @@ class SuccessorKind extends TSuccessorKind { } pragma[nomagic] -private ItemNode getAChildSuccessor(ItemNode item, string name, SuccessorKind kind) { +private ItemNode getAChildSuccessor0(ItemNode item, string name, SuccessorKind kind) { item = result.getImmediateParent() and name = result.getName() and // Associated items in `impl` and `trait` blocks are handled elsewhere @@ -116,7 +116,7 @@ private ItemNode getAChildSuccessor(ItemNode item, string name, SuccessorKind ki if result instanceof TypeParam then kind.isInternal() else - if result.isPublic() + if result.isPublic() or item instanceof SourceFile then kind.isBoth() else kind.isInternal() or @@ -130,6 +130,41 @@ private ItemNode getAChildSuccessor(ItemNode item, string name, SuccessorKind ki result = item } +pragma[nomagic] +private NamedItemNode getANamedNonModuleChildSuccessor( + ItemNode item, string name, Namespace ns, int startline, int startcolumn, int endline, + int endcolumn +) { + result.getLocation().hasLocationInfo(_, startline, startcolumn, endline, endcolumn) and + result = getAChildSuccessor0(item, name, _) and + ns = result.getNamespace() and + not result instanceof ModuleItemNode +} + +pragma[nomagic] +private ItemNode getAChildSuccessor(ItemNode item, string name, SuccessorKind kind) { + result = getAChildSuccessor0(item, name, kind) and + // In valid Rust code, there cannot be multiple children with the same name and namespace, + // but to safeguard against combinatorial explosions in invalid code, we always pick the + // last child, except for modules, where we take the union. + ( + not result instanceof NamedItemNode + or + result instanceof ModuleItemNode + or + exists(Namespace ns | + result = + max(NamedItemNode i, int startline, int startcolumn, int endline, int endcolumn | + i = + getANamedNonModuleChildSuccessor(item, name, ns, startline, startcolumn, endline, + endcolumn) + | + i order by startline, startcolumn, endline, endcolumn + ) + ) + ) +} + private module UseOption = Option; private class UseOption = UseOption::Option; @@ -288,10 +323,6 @@ abstract class ItemNode extends Locatable { cached ItemNode getASuccessor(string name, SuccessorKind kind, UseOption useOpt) { Stages::PathResolutionStage::ref() and - sourceFileEdge(this, name, result) and - kind.isBoth() and - useOpt.isNone() - or result = getAChildSuccessor(this, name, kind) and useOpt.isNone() or @@ -471,6 +502,8 @@ abstract class ItemNode extends Locatable { Location getLocation() { result = super.getLocation() } } +abstract class NamedItemNode extends ItemNode { } + abstract class TypeItemNode extends ItemNode { } /** A module or a source file. */ @@ -509,7 +542,7 @@ private class SourceFileItemNode extends ModuleLikeNode instanceof SourceFile { override string getCanonicalPath(Crate c) { none() } } -class CrateItemNode extends ItemNode instanceof Crate { +class CrateItemNode extends NamedItemNode instanceof Crate { /** * Gets the source file that defines this crate. */ @@ -565,7 +598,7 @@ class CrateItemNode extends ItemNode instanceof Crate { override string getCanonicalPath(Crate c) { c = this and result = Crate.super.getName() } } -class ExternCrateItemNode extends ItemNode instanceof ExternCrate { +class ExternCrateItemNode extends NamedItemNode instanceof ExternCrate { override string getName() { result = super.getRename().getName().getText() or @@ -573,7 +606,7 @@ class ExternCrateItemNode extends ItemNode instanceof ExternCrate { result = super.getIdentifier().getText() } - override Namespace getNamespace() { none() } + override Namespace getNamespace() { result.isType() } override Visibility getVisibility() { result = ExternCrate.super.getVisibility() } @@ -587,7 +620,7 @@ class ExternCrateItemNode extends ItemNode instanceof ExternCrate { } /** An item that can occur in a trait or an `impl` block. */ -abstract private class AssocItemNode extends ItemNode instanceof AssocItem { +abstract private class AssocItemNode extends NamedItemNode instanceof AssocItem { /** Holds if this associated item has an implementation. */ abstract predicate hasImplementation(); @@ -626,7 +659,7 @@ private class ConstItemNode extends AssocItemNode instanceof Const { override TypeParam getTypeParam(int i) { none() } } -private class TypeItemTypeItemNode extends TypeItemNode instanceof TypeItem { +private class TypeItemTypeItemNode extends NamedItemNode, TypeItemNode instanceof TypeItem { override string getName() { result = TypeItem.super.getName().getText() } override Namespace getNamespace() { result.isType() } @@ -659,7 +692,7 @@ private class TypeItemTypeItemNode extends TypeItemNode instanceof TypeItem { } /** An item that can be referenced with arguments. */ -abstract class ParameterizableItemNode extends ItemNode { +abstract class ParameterizableItemNode extends NamedItemNode { /** Gets the arity this item. */ abstract int getArity(); } @@ -911,7 +944,7 @@ private class ImplTraitTypeReprItemNodeImpl extends ImplTraitTypeReprItemNode { ItemNode resolveABoundCand() { result = resolvePathCand(this.getABoundPath()) } } -private class ModuleItemNode extends ModuleLikeNode instanceof Module { +private class ModuleItemNode extends NamedItemNode, ModuleLikeNode instanceof Module { override string getName() { result = Module.super.getName().getText() } override Namespace getNamespace() { result.isType() } @@ -929,7 +962,7 @@ private class ModuleItemNode extends ModuleLikeNode instanceof Module { ( exists(SourceFile f | fileImport(this, f) and - sourceFileEdge(f, _, child) + child = getAChildSuccessor(f, _, _) ) or this = child.getImmediateParent() @@ -1001,7 +1034,7 @@ private class StructItemNode extends TypeItemTypeItemNode, ParameterizableItemNo } } -final class TraitItemNode extends ImplOrTraitItemNode, TypeItemNode instanceof Trait { +final class TraitItemNode extends ImplOrTraitItemNode, NamedItemNode, TypeItemNode instanceof Trait { pragma[nomagic] Path getABoundPath() { result = super.getATypeBound().getTypeRepr().(PathTypeRepr).getPath() } @@ -1126,7 +1159,7 @@ private class BlockExprItemNode extends ItemNode instanceof BlockExpr { pragma[nomagic] private Path getWherePredPath(WherePred wp) { result = wp.getTypeRepr().(PathTypeRepr).getPath() } -final class TypeParamItemNode extends TypeItemNode instanceof TypeParam { +final class TypeParamItemNode extends NamedItemNode, TypeItemNode instanceof TypeParam { /** Gets a where predicate for this type parameter, if any */ pragma[nomagic] private WherePred getAWherePred() { @@ -1214,7 +1247,7 @@ final private class TypeParamItemNodeImpl extends TypeParamItemNode instanceof T ItemNode resolveABoundCand() { result = resolvePathCand(this.getABoundPathCand()) } } -abstract private class MacroItemNode extends ItemNode { +abstract private class MacroItemNode extends NamedItemNode { override Namespace getNamespace() { result.isMacro() } override TypeParam getTypeParam(int i) { none() } @@ -1256,12 +1289,6 @@ private class MacroDefItemNode extends MacroItemNode instanceof MacroDef { override Attr getAnAttr() { result = MacroDef.super.getAnAttr() } } -/** Holds if `item` has the name `name` and is a top-level item inside `f`. */ -private predicate sourceFileEdge(SourceFile f, string name, ItemNode item) { - item = f.(ItemNode).getADescendant() and - name = item.getName() -} - /** Holds if `f` is available as `mod name;` inside `folder`. */ pragma[nomagic] private predicate fileModule(SourceFile f, string name, Folder folder) { diff --git a/rust/ql/test/library-tests/path-resolution/invalid/main.rs b/rust/ql/test/library-tests/path-resolution/invalid/main.rs new file mode 100644 index 00000000000..b58fcb2d934 --- /dev/null +++ b/rust/ql/test/library-tests/path-resolution/invalid/main.rs @@ -0,0 +1,6 @@ +// The code in this file is not valid Rust code + +struct A; // A1 +struct A; // A2 + +fn f(x: A) {} // $ item=A2 (the latter occurence takes precedence) diff --git a/rust/ql/test/library-tests/path-resolution/invalid/options.yml b/rust/ql/test/library-tests/path-resolution/invalid/options.yml new file mode 100644 index 00000000000..cf148dd35f8 --- /dev/null +++ b/rust/ql/test/library-tests/path-resolution/invalid/options.yml @@ -0,0 +1 @@ +qltest_cargo_check: false diff --git a/rust/ql/test/library-tests/path-resolution/path-resolution.expected b/rust/ql/test/library-tests/path-resolution/path-resolution.expected index 153d80db4cc..e85bb7876da 100644 --- a/rust/ql/test/library-tests/path-resolution/path-resolution.expected +++ b/rust/ql/test/library-tests/path-resolution/path-resolution.expected @@ -51,6 +51,7 @@ mod | my/nested.rs:1:1:17:1 | mod nested1 | | my/nested.rs:2:5:11:5 | mod nested2 | resolvePath +| invalid/main.rs:6:9:6:9 | A | invalid/main.rs:3:11:4:9 | struct A | | main.rs:4:8:4:9 | my | main.rs:1:1:1:7 | mod my | | main.rs:4:14:4:17 | self | main.rs:1:1:1:7 | mod my | | main.rs:6:5:6:6 | my | main.rs:1:1:1:7 | mod my |