From 9912aaaf1ab2a66f9d5bc28c777214bf09eb4773 Mon Sep 17 00:00:00 2001 From: "REDMOND\\brodes" Date: Tue, 30 Sep 2025 13:32:56 -0400 Subject: [PATCH 01/22] Adding azure sdk test cases and updated test expected file. --- .../FullServerSideRequestForgery.expected | 6 +++--- .../PartialServerSideRequestForgery.expected | 10 +++++----- .../test_azure_client.py | 4 ++++ 3 files changed, 12 insertions(+), 8 deletions(-) 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..ae554fa812c 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 @@ -45,7 +45,7 @@ edges | 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_azure_client.py:14:5:14:12 | ControlFlowNode for full_url | test_azure_client.py:33:18:33: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 | | @@ -110,7 +110,7 @@ nodes | 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_azure_client.py:33:18:33: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 | | test_http_client.py:9:5:9:15 | ControlFlowNode for unsafe_host | semmle.label | ControlFlowNode for unsafe_host | @@ -148,7 +148,7 @@ subpaths | 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_azure_client.py:32:5:37:5 | ControlFlowNode for download_blob_from_url() | test_azure_client.py:7:19:7:25 | ControlFlowNode for ImportMember | test_azure_client.py:33:18:33: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 | 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..bbe756e24b7 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 @@ -89,12 +89,12 @@ edges | 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:13:5:13:7 | ControlFlowNode for url | test_azure_client.py:27:18:27: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_azure_client.py:14:5:14:12 | ControlFlowNode for full_url | test_azure_client.py:33:18:33: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 | | @@ -207,8 +207,8 @@ nodes | 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_azure_client.py:27:18:27:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| test_azure_client.py:33:18:33: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 | | test_http_client.py:9:5:9:15 | ControlFlowNode for unsafe_host | semmle.label | ControlFlowNode for unsafe_host | @@ -245,7 +245,7 @@ subpaths | 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_azure_client.py:26:5:31:5 | ControlFlowNode for download_blob_from_url() | test_azure_client.py:7:19:7:25 | ControlFlowNode for ImportMember | test_azure_client.py:27:18:27: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 | 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..f78b0a64137 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 @@ -22,6 +22,7 @@ def azure_sdk_test(credential, output_path): 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 + download_blob_from_url( blob_url=url, # NOT OK -- user only controlled fragment output=output_path, @@ -34,3 +35,6 @@ def azure_sdk_test(credential, output_path): credential=credential, overwrite=True ) + + + From b8ba9052533e62f30f361db281e86e0be583a685 Mon Sep 17 00:00:00 2001 From: "REDMOND\\brodes" Date: Tue, 30 Sep 2025 13:55:31 -0400 Subject: [PATCH 02/22] Added change logs. --- .../lib/change-notes/released/2025-09-30-azure_ssrf_models | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 python/ql/lib/change-notes/released/2025-09-30-azure_ssrf_models diff --git a/python/ql/lib/change-notes/released/2025-09-30-azure_ssrf_models b/python/ql/lib/change-notes/released/2025-09-30-azure_ssrf_models new file mode 100644 index 00000000000..573d5ea109d --- /dev/null +++ b/python/ql/lib/change-notes/released/2025-09-30-azure_ssrf_models @@ -0,0 +1,5 @@ +--- +category: minorAnalysis +--- +* Added `ssrf` MaD for the azure SDK +* Added MaD `ssrf` to `Http::Client::Request` \ No newline at end of file From 46a2a249f9d7d982bdb3dc829abade9c69f82e51 Mon Sep 17 00:00:00 2001 From: Ben Rodes Date: Tue, 30 Sep 2025 14:00:16 -0400 Subject: [PATCH 03/22] Update python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/test_azure_client.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../CWE-918-ServerSideRequestForgery/test_azure_client.py | 1 - 1 file changed, 1 deletion(-) 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 f78b0a64137..5d2b04b9c9d 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 @@ -22,7 +22,6 @@ def azure_sdk_test(credential, output_path): 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 - download_blob_from_url( blob_url=url, # NOT OK -- user only controlled fragment output=output_path, From 08b72d0a868fe57d42bdac4f0c73f71e2851176f Mon Sep 17 00:00:00 2001 From: Ben Rodes Date: Tue, 30 Sep 2025 14:00:25 -0400 Subject: [PATCH 04/22] Update python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/test_azure_client.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../CWE-918-ServerSideRequestForgery/test_azure_client.py | 3 --- 1 file changed, 3 deletions(-) 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 5d2b04b9c9d..d8de2092a2e 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 @@ -34,6 +34,3 @@ def azure_sdk_test(credential, output_path): credential=credential, overwrite=True ) - - - From 7db97799c1415a70502009fa31ca9fa5084253ae Mon Sep 17 00:00:00 2001 From: "REDMOND\\brodes" Date: Tue, 30 Sep 2025 14:02:43 -0400 Subject: [PATCH 05/22] Moved change log to correct location. --- python/ql/lib/change-notes/2025-09-30-azure_ssrf_models.md | 4 ++-- .../lib/change-notes/released/2025-09-30-azure_ssrf_models | 5 ----- 2 files changed, 2 insertions(+), 7 deletions(-) delete mode 100644 python/ql/lib/change-notes/released/2025-09-30-azure_ssrf_models diff --git a/python/ql/lib/change-notes/2025-09-30-azure_ssrf_models.md b/python/ql/lib/change-notes/2025-09-30-azure_ssrf_models.md index 283b703a438..573d5ea109d 100644 --- a/python/ql/lib/change-notes/2025-09-30-azure_ssrf_models.md +++ b/python/ql/lib/change-notes/2025-09-30-azure_ssrf_models.md @@ -1,5 +1,5 @@ --- category: minorAnalysis --- -* Added request forgery sink models for the Azure SDK. -* Made it so that models-as-data sinks with the kind `request-forgery` contribute to the class `Http::Client::Request` which represents HTTP client requests. \ No newline at end of file +* Added `ssrf` MaD for the azure SDK +* Added MaD `ssrf` to `Http::Client::Request` \ No newline at end of file diff --git a/python/ql/lib/change-notes/released/2025-09-30-azure_ssrf_models b/python/ql/lib/change-notes/released/2025-09-30-azure_ssrf_models deleted file mode 100644 index 573d5ea109d..00000000000 --- a/python/ql/lib/change-notes/released/2025-09-30-azure_ssrf_models +++ /dev/null @@ -1,5 +0,0 @@ ---- -category: minorAnalysis ---- -* Added `ssrf` MaD for the azure SDK -* Added MaD `ssrf` to `Http::Client::Request` \ No newline at end of file From 265922d2e509bbd93fbbe87227eb49204a083a5f Mon Sep 17 00:00:00 2001 From: "REDMOND\\brodes" Date: Tue, 30 Sep 2025 14:07:32 -0400 Subject: [PATCH 06/22] Adding docs. --- .../lib/semmle/python/frameworks/SSRFSink.qll | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 python/ql/lib/semmle/python/frameworks/SSRFSink.qll diff --git a/python/ql/lib/semmle/python/frameworks/SSRFSink.qll b/python/ql/lib/semmle/python/frameworks/SSRFSink.qll new file mode 100644 index 00000000000..e9b7ff9e474 --- /dev/null +++ b/python/ql/lib/semmle/python/frameworks/SSRFSink.qll @@ -0,0 +1,42 @@ +/** + * Provides classes for SSRF sinks modeled using Models as Data (MaD). + */ + +private import python +private import semmle.python.Concepts +private import semmle.python.ApiGraphs +private import semmle.python.frameworks.data.ModelsAsData + +/** + * INTERNAL: Do not use. + * + * Sets up SSRF sinks as Http::Client::Request + */ +module SSRFMaDModel { + /** + * An HTTP request modeled from `ssrf` sinks, modeled using MaD. + */ + class SSRFSink extends Http::Client::Request::Range instanceof API::CallNode { + DataFlow::Node urlArg; + + SSRFSink() { + ( + this.getArg(_) = urlArg + or + this.getArgByName(_) = urlArg + ) and + urlArg = ModelOutput::getASinkNode("ssrf").asSink() + } + + override DataFlow::Node getAUrlPart() { result = urlArg } + + override string getFramework() { result = "MaD" } + + override predicate disablesCertificateValidation( + DataFlow::Node disablingNode, DataFlow::Node argumentOrigin + ) { + // NOTE: if you need to define this, you have to special case it for every possible API in MaD + none() + } + } +} From 88adb05d4b21928d26aafc8e5c3d083268ac2068 Mon Sep 17 00:00:00 2001 From: "REDMOND\\brodes" Date: Tue, 30 Sep 2025 14:09:06 -0400 Subject: [PATCH 07/22] Adjusting acryonym for SSRF for casing standards. --- python/ql/lib/semmle/python/frameworks/SSRFSink.qll | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/python/ql/lib/semmle/python/frameworks/SSRFSink.qll b/python/ql/lib/semmle/python/frameworks/SSRFSink.qll index e9b7ff9e474..aeb228daf13 100644 --- a/python/ql/lib/semmle/python/frameworks/SSRFSink.qll +++ b/python/ql/lib/semmle/python/frameworks/SSRFSink.qll @@ -12,14 +12,14 @@ private import semmle.python.frameworks.data.ModelsAsData * * Sets up SSRF sinks as Http::Client::Request */ -module SSRFMaDModel { +module SsrfMaDModel { /** * An HTTP request modeled from `ssrf` sinks, modeled using MaD. */ - class SSRFSink extends Http::Client::Request::Range instanceof API::CallNode { + class SsrfSink extends Http::Client::Request::Range instanceof API::CallNode { DataFlow::Node urlArg; - SSRFSink() { + SsrfSink() { ( this.getArg(_) = urlArg or From 27e19813bea78bcfbfca6b13354a8637529066aa Mon Sep 17 00:00:00 2001 From: "REDMOND\\brodes" Date: Mon, 2 Feb 2026 10:13:59 -0500 Subject: [PATCH 08/22] Removing an upstream change log, not needed for local fork update. --- python/ql/lib/change-notes/2025-09-30-azure_ssrf_models.md | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 python/ql/lib/change-notes/2025-09-30-azure_ssrf_models.md diff --git a/python/ql/lib/change-notes/2025-09-30-azure_ssrf_models.md b/python/ql/lib/change-notes/2025-09-30-azure_ssrf_models.md deleted file mode 100644 index 573d5ea109d..00000000000 --- a/python/ql/lib/change-notes/2025-09-30-azure_ssrf_models.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -category: minorAnalysis ---- -* Added `ssrf` MaD for the azure SDK -* Added MaD `ssrf` to `Http::Client::Request` \ No newline at end of file From 97ddab0724bc37dec318f02ff79d091423236db5 Mon Sep 17 00:00:00 2001 From: "REDMOND\\brodes" Date: Mon, 2 Feb 2026 16:09:53 -0500 Subject: [PATCH 09/22] Added support for new URIValidator in AntiSSRF library. Updated test caes to use postprocessing results. Currently results for partial ssrf still need work, it is flagging cases where the URL is fully controlled, but is sanitized. I'm not sure if this should be flagged yet. --- ...ServerSideRequestForgeryCustomizations.qll | 45 ++ .../FullServerSideRequestForgery.expected | 364 +++++++----- .../FullServerSideRequestForgery.qlref | 3 +- .../PartialServerSideRequestForgery.expected | 538 +++++++++++------- .../PartialServerSideRequestForgery.qlref | 3 +- .../full_partial_test.py | 75 ++- .../test_azure_client.py | 233 +++++++- .../test_http_client.py | 33 +- .../test_path_validation.py | 132 +++++ .../test_requests.py | 48 +- 10 files changed, 1061 insertions(+), 413 deletions(-) create mode 100644 python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/test_path_validation.py diff --git a/python/ql/lib/semmle/python/security/dataflow/ServerSideRequestForgeryCustomizations.qll b/python/ql/lib/semmle/python/security/dataflow/ServerSideRequestForgeryCustomizations.qll index 274e7ee57ad..2139ecf797d 100644 --- a/python/ql/lib/semmle/python/security/dataflow/ServerSideRequestForgeryCustomizations.qll +++ b/python/ql/lib/semmle/python/security/dataflow/ServerSideRequestForgeryCustomizations.qll @@ -176,4 +176,49 @@ module ServerSideRequestForgery { strNode = [call.getArg(0), call.getArgByName("string")] ) } + + /** A validation that a string does not contain certain characters, considered as a 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, Node n, string funcs | + funcs in ["in_domain", "in_azure_keyvault_domain", "in_azure_storage_domain"] + | + call = API::moduleImport("AntiSSRF").getMember("URIValidator").getMember(funcs).getACall() and + call.getArg(0).asCfgNode() = node and + n.getALocalSource() = call and + ( + // validator used in a comparison + exists(CompareNode cn, Cmpop op | cn = g | + ( + // validator == true or validator == false or validator is True or validator is False + (op instanceof Eq or op instanceof Is) and + exists(ControlFlowNode l, boolean bool | + l.getNode().(BooleanLiteral).booleanValue() = bool and + bool in [true, false] and + branch = bool and + cn.operands(n.asCfgNode(), op, l) + ) + or + // validator != false or validator != true or validator is not True or validator is not False + (op instanceof NotEq or op instanceof IsNot) and + exists(ControlFlowNode l, boolean bool | + l.getNode().(BooleanLiteral).booleanValue() = bool and + bool in [true, false] and + branch = bool.booleanNot() and + cn.operands(n.asCfgNode(), op, l) + ) + ) + ) + or + // validator call directly (e.g., if URIValidator.in_domain(...) ) + g = call.asCfgNode() and + branch = true + ) + ) + } } 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 ae554fa812c..19b5f7efa9d 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,260 @@ +#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:9:16:63 | ControlFlowNode for SecretClient() | test_azure_client.py:6:19:6:25 | ControlFlowNode for ImportMember | test_azure_client.py:16:32:16:39 | 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:9:18:47 | ControlFlowNode for Attribute() | test_azure_client.py:6:19:6:25 | ControlFlowNode for ImportMember | test_azure_client.py:18:39:18:46 | 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:9:20:39 | ControlFlowNode for KeyClient() | test_azure_client.py:6:19:6:25 | ControlFlowNode for ImportMember | test_azure_client.py:20:19:20:26 | 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:9:22:89 | ControlFlowNode for Attribute() | test_azure_client.py:6:19:6:25 | ControlFlowNode for ImportMember | test_azure_client.py:22:58:22:65 | 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:13:21:67 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:21:36:21:43 | 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:13:37:64 | ControlFlowNode for KeyClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:37:33:37:40 | 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:13:53:51 | ControlFlowNode for Attribute() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:53:43:53:50 | 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:13:64:62 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:64:36:64:38 | 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:13:71:62 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:71:36:71:38 | 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:13:74:62 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:74:36:74:38 | 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:13:79:62 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:79:36:79:38 | 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:13:87:62 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:87:36:87:38 | 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:13:90:62 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:90:36:90:38 | 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:13:95:62 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:95:36:95:38 | 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:13:102:62 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:102:36:102:38 | 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:13:107:62 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:107:36:107:38 | 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:13:110:62 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:110:36:110:38 | 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:13:115:62 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:115:36:115:38 | 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:13:122:62 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:122:36:122:38 | 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:13:125:62 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:125:36:125:38 | 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:13:132:62 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:132:36:132:38 | 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:16:22:55 | ControlFlowNode for Attribute() | test_requests.py:1:19:1:25 | ControlFlowNode for ImportMember | test_requests.py:22:45:22:54 | 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:33:18:33: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:32:16:39 | ControlFlowNode for full_url | provenance | Sink:MaD:15 | +| test_azure_client.py:13:5:13:12 | ControlFlowNode for full_url | test_azure_client.py:18:39:18:46 | ControlFlowNode for full_url | provenance | Sink:MaD:38 | +| test_azure_client.py:13:5:13:12 | ControlFlowNode for full_url | test_azure_client.py:20:19:20:26 | ControlFlowNode for full_url | provenance | Sink:MaD:14 | +| test_azure_client.py:13:5:13:12 | ControlFlowNode for full_url | test_azure_client.py:22:58:22:65 | ControlFlowNode for full_url | provenance | Sink:MaD:26 | +| 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:27 | +| 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:36:21:43 | ControlFlowNode for full_url | provenance | Sink:MaD:15 | +| 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:33:37:40 | ControlFlowNode for full_url | provenance | Sink:MaD:14 | +| 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:43:53:50 | ControlFlowNode for full_url | provenance | Sink:MaD:38 | +| 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:36:64:38 | ControlFlowNode for url | provenance | Sink:MaD:15 | +| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:71:36:71:38 | ControlFlowNode for url | provenance | Sink:MaD:15 | +| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:74:36:74:38 | ControlFlowNode for url | provenance | Sink:MaD:15 | +| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:79:36:79:38 | ControlFlowNode for url | provenance | Sink:MaD:15 | +| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:87:36:87:38 | ControlFlowNode for url | provenance | Sink:MaD:15 | +| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:90:36:90:38 | ControlFlowNode for url | provenance | Sink:MaD:15 | +| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:95:36:95:38 | ControlFlowNode for url | provenance | Sink:MaD:15 | +| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:102:36:102:38 | ControlFlowNode for url | provenance | Sink:MaD:15 | +| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:107:36:107:38 | ControlFlowNode for url | provenance | Sink:MaD:15 | +| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:110:36:110:38 | ControlFlowNode for url | provenance | Sink:MaD:15 | +| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:115:36:115:38 | ControlFlowNode for url | provenance | Sink:MaD:15 | +| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:122:36:122:38 | ControlFlowNode for url | provenance | Sink:MaD:15 | +| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:125:36:125:38 | ControlFlowNode for url | provenance | Sink:MaD:15 | +| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:132:36:132:38 | ControlFlowNode for url | provenance | Sink:MaD:15 | | 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:45:22:54 | 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 | 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:33:18:33: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:32:16:39 | ControlFlowNode for full_url | semmle.label | ControlFlowNode for full_url | +| test_azure_client.py:18:39:18:46 | ControlFlowNode for full_url | semmle.label | ControlFlowNode for full_url | +| test_azure_client.py:20:19:20:26 | ControlFlowNode for full_url | semmle.label | ControlFlowNode for full_url | +| test_azure_client.py:22:58:22:65 | 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:36:21:43 | 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:33:37:40 | 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:43:53:50 | 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:36:64:38 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| test_path_validation.py:71:36:71:38 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| test_path_validation.py:74:36:74:38 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| test_path_validation.py:79:36:79:38 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| test_path_validation.py:87:36:87:38 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| test_path_validation.py:90:36:90:38 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| test_path_validation.py:95:36:95:38 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| test_path_validation.py:102:36:102:38 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| test_path_validation.py:107:36:107:38 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| test_path_validation.py:110:36:110:38 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| test_path_validation.py:115:36:115:38 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| test_path_validation.py:122:36:122:38 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| test_path_validation.py:125:36:125:38 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| test_path_validation.py:132:36:132:38 | 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:45:22:54 | 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:32:5:37:5 | ControlFlowNode for download_blob_from_url() | test_azure_client.py:7:19:7:25 | ControlFlowNode for ImportMember | test_azure_client.py:33:18:33: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 | +testFailures +| test_requests.py:39:40:39:62 | Comment # $ Alert[py/full-ssrf] | Missing result: Alert[py/full-ssrf] | +| test_requests.py:49:40:49:62 | Comment # $ Alert[py/full-ssrf] | Missing result: Alert[py/full-ssrf] | 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..35a2814e7f4 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,2 @@ -Security/CWE-918/FullServerSideRequestForgery.ql +query: Security/CWE-918/FullServerSideRequestForgery.ql +postprocess: utils/test/InlineExpectationsTestQuery.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 bbe756e24b7..875d8b62b62 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,199 @@ +#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:9:15:58 | ControlFlowNode for SecretClient() | test_azure_client.py:6:19:6:25 | ControlFlowNode for ImportMember | test_azure_client.py:15:32:15:34 | 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:9:17:42 | ControlFlowNode for Attribute() | test_azure_client.py:6:19:6:25 | ControlFlowNode for ImportMember | test_azure_client.py:17:39:17:41 | 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:9:19:34 | ControlFlowNode for KeyClient() | test_azure_client.py:6:19:6:25 | ControlFlowNode for ImportMember | test_azure_client.py:19:19:19:21 | 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:9:21:84 | ControlFlowNode for Attribute() | test_azure_client.py:6:19:6:25 | ControlFlowNode for ImportMember | test_azure_client.py:21:58:21:60 | 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:13:14:62 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:14:36:14:38 | 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:13:16:62 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:16:36:16:38 | 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:30:13:30:59 | ControlFlowNode for KeyClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:30:33:30:35 | 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:13:32:59 | ControlFlowNode for KeyClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:32:33:32:35 | 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:46:13:46:46 | ControlFlowNode for Attribute() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:46:43:46:45 | 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:13:48:46 | ControlFlowNode for Attribute() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:48:43:48:45 | 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:27:18:27: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:33:18:33: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:32:15:34 | ControlFlowNode for url | provenance | Sink:MaD:15 | +| test_azure_client.py:12:5:12:7 | ControlFlowNode for url | test_azure_client.py:17:39:17:41 | ControlFlowNode for url | provenance | Sink:MaD:38 | +| test_azure_client.py:12:5:12:7 | ControlFlowNode for url | test_azure_client.py:19:19:19:21 | ControlFlowNode for url | provenance | Sink:MaD:14 | +| test_azure_client.py:12:5:12:7 | ControlFlowNode for url | test_azure_client.py:21:58:21:60 | ControlFlowNode for url | provenance | Sink:MaD:26 | +| 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:27 | +| test_azure_client.py:13:5:13:12 | ControlFlowNode for full_url | test_azure_client.py:16:32:16:39 | ControlFlowNode for full_url | provenance | Sink:MaD:15 | +| test_azure_client.py:13:5:13:12 | ControlFlowNode for full_url | test_azure_client.py:18:39:18:46 | ControlFlowNode for full_url | provenance | Sink:MaD:38 | +| test_azure_client.py:13:5:13:12 | ControlFlowNode for full_url | test_azure_client.py:20:19:20:26 | ControlFlowNode for full_url | provenance | Sink:MaD:14 | +| test_azure_client.py:13:5:13:12 | ControlFlowNode for full_url | test_azure_client.py:22:58:22:65 | ControlFlowNode for full_url | provenance | Sink:MaD:26 | +| 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:27 | +| 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:36:14:38 | ControlFlowNode for url | provenance | Sink:MaD:15 | +| test_path_validation.py:10:5:10:7 | ControlFlowNode for url | test_path_validation.py:16:36:16:38 | ControlFlowNode for url | provenance | Sink:MaD:15 | +| test_path_validation.py:11:5:11:12 | ControlFlowNode for full_url | test_path_validation.py:19:36:19:43 | ControlFlowNode for full_url | provenance | Sink:MaD:15 | +| test_path_validation.py:11:5:11:12 | ControlFlowNode for full_url | test_path_validation.py:21:36:21:43 | ControlFlowNode for full_url | provenance | Sink:MaD:15 | +| 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:33:30:35 | ControlFlowNode for url | provenance | Sink:MaD:14 | +| test_path_validation.py:26:5:26:7 | ControlFlowNode for url | test_path_validation.py:32:33:32:35 | ControlFlowNode for url | provenance | Sink:MaD:14 | +| test_path_validation.py:27:5:27:12 | ControlFlowNode for full_url | test_path_validation.py:35:33:35:40 | ControlFlowNode for full_url | provenance | Sink:MaD:14 | +| test_path_validation.py:27:5:27:12 | ControlFlowNode for full_url | test_path_validation.py:37:33:37:40 | ControlFlowNode for full_url | provenance | Sink:MaD:14 | +| 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:43:46:45 | ControlFlowNode for url | provenance | Sink:MaD:38 | +| test_path_validation.py:42:5:42:7 | ControlFlowNode for url | test_path_validation.py:48:43:48:45 | ControlFlowNode for url | provenance | Sink:MaD:38 | +| test_path_validation.py:43:5:43:12 | ControlFlowNode for full_url | test_path_validation.py:51:43:51:50 | ControlFlowNode for full_url | provenance | Sink:MaD:38 | +| test_path_validation.py:43:5:43:12 | ControlFlowNode for full_url | test_path_validation.py:53:43:53:50 | ControlFlowNode for full_url | provenance | Sink:MaD:38 | +| 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:36:64:38 | ControlFlowNode for url | provenance | Sink:MaD:15 | +| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:66:36:66:38 | ControlFlowNode for url | provenance | Sink:MaD:15 | +| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:69:36:69:38 | ControlFlowNode for url | provenance | Sink:MaD:15 | +| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:71:36:71:38 | ControlFlowNode for url | provenance | Sink:MaD:15 | +| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:74:36:74:38 | ControlFlowNode for url | provenance | Sink:MaD:15 | +| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:76:36:76:38 | ControlFlowNode for url | provenance | Sink:MaD:15 | +| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:79:36:79:38 | ControlFlowNode for url | provenance | Sink:MaD:15 | +| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:81:36:81:38 | ControlFlowNode for url | provenance | Sink:MaD:15 | | 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:45:22:54 | 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 | 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 +201,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:27:18:27:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_azure_client.py:33:18:33: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:32:15:34 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| test_azure_client.py:16:32:16:39 | ControlFlowNode for full_url | semmle.label | ControlFlowNode for full_url | +| test_azure_client.py:17:39:17:41 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| test_azure_client.py:18:39:18:46 | ControlFlowNode for full_url | semmle.label | ControlFlowNode for full_url | +| test_azure_client.py:19:19:19:21 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| test_azure_client.py:20:19:20:26 | ControlFlowNode for full_url | semmle.label | ControlFlowNode for full_url | +| test_azure_client.py:21:58:21:60 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| test_azure_client.py:22:58:22:65 | 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 +293,69 @@ 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:36:14:38 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| test_path_validation.py:16:36:16:38 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| test_path_validation.py:19:36:19:43 | ControlFlowNode for full_url | semmle.label | ControlFlowNode for full_url | +| test_path_validation.py:21:36:21:43 | 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:33:30:35 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| test_path_validation.py:32:33:32:35 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| test_path_validation.py:35:33:35:40 | ControlFlowNode for full_url | semmle.label | ControlFlowNode for full_url | +| test_path_validation.py:37:33:37:40 | 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:43:46:45 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| test_path_validation.py:48:43:48:45 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| test_path_validation.py:51:43:51:50 | ControlFlowNode for full_url | semmle.label | ControlFlowNode for full_url | +| test_path_validation.py:53:43:53:50 | 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:36:64:38 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| test_path_validation.py:66:36:66:38 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| test_path_validation.py:69:36:69:38 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| test_path_validation.py:71:36:71:38 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| test_path_validation.py:74:36:74:38 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| test_path_validation.py:76:36:76:38 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| test_path_validation.py:79:36:79:38 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| test_path_validation.py:81:36:81:38 | 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:45:22:54 | 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:26:5:31:5 | ControlFlowNode for download_blob_from_url() | test_azure_client.py:7:19:7:25 | ControlFlowNode for ImportMember | test_azure_client.py:27:18:27: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 | +testFailures +| test_requests.py:1:27:1:36 | Comment # $ Source | Missing result: Source | 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..651b07aea55 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,2 @@ -Security/CWE-918/PartialServerSideRequestForgery.ql +query: Security/CWE-918/PartialServerSideRequestForgery.ql +postprocess: utils/test/InlineExpectationsTestQuery.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..e2f4fc05026 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,26 +1,30 @@ -from flask import request +from flask import request # $ Source -import requests +import requests import re 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 contollred 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 contollred 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..28570b7ab4a 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,214 @@ 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 + c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/partial-ssrf] + c = SecretClient(vault_url=full_url, credential=credential) # $ Alert[py/full-ssrf] + c = ShareFileClient.from_file_url(url) # $ Alert[py/partial-ssrf] + c = ShareFileClient.from_file_url(full_url) # $ Alert[py/full-ssrf] + c = KeyClient(url, credential) # $ Alert[py/partial-ssrf] + c = KeyClient(full_url, credential) # $ Alert[py/full-ssrf] + c = ContainerClient.from_container_url(container_url=url, credential=credential) # $ Alert[py/partial-ssrf] + c = 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] + +# if URIValidator.in_domain(url, trusted_domain): +# # Testing Azure sink +# c = SecretClient(vault_url=url, credential=credential)# OK +# c = ShareFileClient.from_file_url(url) # OK +# c = KeyClient(url, credential)# OK +# c = ContainerClient.from_container_url(container_url=url, credential=credential) # OK + +# download_blob_from_url( +# blob_url=url, # OK +# output=output_path, +# credential=credential, +# overwrite=True +# ) +# else: +# # Testing Azure sink +# c = SecretClient(vault_url=url, credential=credential)# NOT OK -- user only controlled fragment +# c = ShareFileClient.from_file_url(url) # NOT OK -- user only controlled fragment +# c = KeyClient(url, credential)# NOT OK -- user only controlled fragment +# c = ContainerClient.from_container_url(container_url=url, credential=credential) # NOT OK -- user only controlled fragment + +# download_blob_from_url( +# blob_url=url, # NOT OK -- user only controlled fragment +# output=output_path, +# credential=credential, +# overwrite=True +# ) + + +# if URIValidator.in_domain(full_url, trusted_domain): +# # Testing Azure sink +# c = SecretClient(vault_url=full_url, credential=credential) # OK +# c = ShareFileClient.from_file_url(full_url) # OK +# c = KeyClient(full_url, credential) # OK +# c = ContainerClient.from_container_url(container_url=full_url, credential=credential) # OK + +# download_blob_from_url( +# blob_url=full_url, # OK +# output=output_path, +# credential=credential, +# overwrite=True +# ) +# else: +# # Testing Azure sink +# c = SecretClient(vault_url=full_url, credential=credential) # NOT OK -- user has full control +# c = ShareFileClient.from_file_url(full_url) # NOT OK -- user has full control +# c = KeyClient(full_url, credential) # NOT OK -- user has full control +# c = ContainerClient.from_container_url(container_url=full_url, credential=credential) # NOT OK -- user has full control + +# download_blob_from_url( +# blob_url=full_url, # NOT OK -- user has full control +# output=output_path, +# credential=credential, +# overwrite=True +# ) + + +# if URIValidator.in_azure_keyvault_domain(url): +# # Testing Azure sink +# c = SecretClient(vault_url=url, credential=credential)# OK +# c = ShareFileClient.from_file_url(url) # OK +# c = KeyClient(url, credential)# OK +# c = ContainerClient.from_container_url(container_url=url, credential=credential) # OK + +# download_blob_from_url( +# blob_url=url, # OK +# output=output_path, +# credential=credential, +# overwrite=True +# ) +# else: +# # Testing Azure sink +# c = SecretClient(vault_url=url, credential=credential)# NOT OK -- user only controlled fragment +# c = ShareFileClient.from_file_url(url) # NOT OK -- user only controlled fragment +# c = KeyClient(url, credential)# NOT OK -- user only controlled fragment +# c = ContainerClient.from_container_url(container_url=url, credential=credential) # NOT OK -- user only controlled fragment + +# download_blob_from_url( +# blob_url=url, # NOT OK -- user only controlled fragment +# output=output_path, +# credential=credential, +# overwrite=True +# ) + + +# if URIValidator.in_azure_keyvault_domain(full_url): +# # Testing Azure sink +# c = SecretClient(vault_url=full_url, credential=credential) # OK +# c = ShareFileClient.from_file_url(full_url) # OK +# c = KeyClient(full_url, credential) # OK +# c = ContainerClient.from_container_url(container_url=full_url, credential=credential) # OK + +# download_blob_from_url( +# blob_url=full_url, # OK +# output=output_path, +# credential=credential, +# overwrite=True +# ) +# else: +# # Testing Azure sink +# c = SecretClient(vault_url=full_url, credential=credential) # NOT OK -- user has full control +# c = ShareFileClient.from_file_url(full_url) # NOT OK -- user has full control +# c = KeyClient(full_url, credential) # NOT OK -- user has full control +# c = ContainerClient.from_container_url(container_url=full_url, credential=credential) # NOT OK -- user has full control + +# download_blob_from_url( +# blob_url=full_url, # NOT OK -- user has full control +# output=output_path, +# credential=credential, +# overwrite=True +# ) + +# if URIValidator.in_azure_storage_domain(url): +# # Testing Azure sink +# c = SecretClient(vault_url=url, credential=credential)# OK +# c = ShareFileClient.from_file_url(url) # OK +# c = KeyClient(url, credential)# OK +# c = ContainerClient.from_container_url(container_url=url, credential=credential) # OK + +# download_blob_from_url( +# blob_url=url, # OK +# output=output_path, +# credential=credential, +# overwrite=True +# ) +# else: +# # Testing Azure sink +# c = SecretClient(vault_url=url, credential=credential)# NOT OK -- user only controlled fragment +# c = ShareFileClient.from_file_url(url) # NOT OK -- user only controlled fragment +# c = KeyClient(url, credential)# NOT OK -- user only controlled fragment +# c = ContainerClient.from_container_url(container_url=url, credential=credential) # NOT OK -- user only controlled fragment + +# download_blob_from_url( +# blob_url=url, # NOT OK -- user only controlled fragment +# output=output_path, +# credential=credential, +# overwrite=True +# ) + + +# if URIValidator.in_azure_storage_domain(full_url): +# # Testing Azure sink +# c = SecretClient(vault_url=full_url, credential=credential) # OK +# c = ShareFileClient.from_file_url(full_url) # OK +# c = KeyClient(full_url, credential) # OK +# c = ContainerClient.from_container_url(container_url=full_url, credential=credential) # OK + +# download_blob_from_url( +# blob_url=full_url, # OK +# output=output_path, +# credential=credential, +# overwrite=True +# ) +# else: +# # Testing Azure sink +# c = SecretClient(vault_url=full_url, credential=credential) # NOT OK -- user has full control +# c = ShareFileClient.from_file_url(full_url) # NOT OK -- user has full control +# c = KeyClient(full_url, credential) # NOT OK -- user has full control +# c = ContainerClient.from_container_url(container_url=full_url, credential=credential) # NOT OK -- user has full control + +# download_blob_from_url( +# blob_url=full_url, # NOT OK -- user has full control +# output=output_path, +# credential=credential, +# overwrite=True +# ) + +# def azure_sdk_logic_sanity_test(credential, output_path, trusted_domain): +# user_input = request.args['untrusted_input'] +# full_url = f"https://{user_input}" +# if not URIValidator.in_azure_storage_domain(full_url): +# # Testing Azure sink +# c = SecretClient(vault_url=full_url, credential=credential) # NOT OK -- user has full control +# else: +# # Testing Azure sink +# c = SecretClient(vault_url=full_url, credential=credential) # OK + + + +# if not not URIValidator.in_azure_storage_domain(full_url): +# # Testing Azure sink +# c = SecretClient(vault_url=full_url, credential=credential) # OK +# else: +# # Testing Azure sink +# c = SecretClient(vault_url=full_url, credential=credential) # NOT OK -- user has full control + + +# if URIValidator.URIValidator.in_domain(full_url, trusted_domain) and trusted_domain == "example.com": +# # Testing Azure sink +# c = SecretClient(vault_url=full_url, credential=credential) # OK +# else: +# # Testing Azure sink +# c = SecretClient(vault_url=full_url, credential=credential) # NOT OK -- user has full control + +# if not (URIValidator.URIValidator.in_domain(full_url, trusted_domain) and trusted_domain == "example.com"): +# # Testing Azure sink +# c = SecretClient(vault_url=full_url, credential=credential) # NOT OK -- user has full control +# else: +# # Testing Azure sink +# c = SecretClient(vault_url=full_url, credential=credential) # OK \ No newline at end of file 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..0a238878e35 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 made 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..44c569f625d --- /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): + c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/partial-ssrf] + else: + c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/partial-ssrf] + + if URIValidator.in_domain(full_url, trusted_domain): + c = SecretClient(vault_url=full_url, credential=credential) # OK + else: + c = 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): + c = KeyClient(vault_url=url, credential=credential) # $ Alert[py/partial-ssrf] + else: + c = KeyClient(vault_url=url, credential=credential) # $ Alert[py/partial-ssrf] + + if URIValidator.in_azure_keyvault_domain(full_url): + c = KeyClient(vault_url=full_url, credential=credential) # OK + else: + c = 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): + c = ShareFileClient.from_file_url(url) # $ Alert[py/partial-ssrf] + else: + c = ShareFileClient.from_file_url(url) # $ Alert[py/partial-ssrf] + + if URIValidator.in_azure_storage_domain(full_url): + c = ShareFileClient.from_file_url(full_url) # OK + else: + c = 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 assumed the logic underlying checking paths would apply + # similarly other validator methods + url = f"https://{user_input}" + + if not URIValidator.in_domain(url, trusted_domain): + c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/full-ssrf] + else: + c = SecretClient(vault_url=url, credential=credential) # OK + + if URIValidator.in_domain(url, trusted_domain) and trusted_domain == "example.com": + c = SecretClient(vault_url=url, credential=credential) # OK + else: + c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/full-ssrf] + + if not (URIValidator.in_domain(url, trusted_domain) and trusted_domain == "example.com"): + c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/full-ssrf] + else: + c = SecretClient(vault_url=url, credential=credential) # OK + + if not not not URIValidator.in_domain(url, trusted_domain): + c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/full-ssrf] + else: + c = SecretClient(vault_url=url, credential=credential) # OK + + + if URIValidator.in_domain(url, trusted_domain) == True: + c = SecretClient(vault_url=url, credential=credential) # OK + else: + c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/full-ssrf] + + if URIValidator.in_domain(url, trusted_domain) == False: + c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/full-ssrf] + else: + c = SecretClient(vault_url=url, credential=credential) # OK + + if URIValidator.in_domain(url, trusted_domain) != True: + c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/full-ssrf] + else: + c = SecretClient(vault_url=url, credential=credential) # OK + + if URIValidator.in_domain(url, trusted_domain) != False: + c = SecretClient(vault_url=url, credential=credential) # OK + else: + c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/full-ssrf] + + if URIValidator.in_domain(url, trusted_domain) is True: + c = SecretClient(vault_url=url, credential=credential) # OK + else: + c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/full-ssrf] + + if URIValidator.in_domain(url, trusted_domain) is False: + c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/full-ssrf] + else: + c = SecretClient(vault_url=url, credential=credential) # OK + + if URIValidator.in_domain(url, trusted_domain) is not True: + c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/full-ssrf] + else: + c = SecretClient(vault_url=url, credential=credential) # OK + + if URIValidator.in_domain(url, trusted_domain) is not False: + c = SecretClient(vault_url=url, credential=credential) # OK + else: + c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/full-ssrf] + + if not URIValidator.in_domain(url, trusted_domain) is True: + c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/full-ssrf] + else: + c = SecretClient(vault_url=url, credential=credential) # OK + + if not URIValidator.in_domain(url, trusted_domain) is False: + c = SecretClient(vault_url=url, credential=credential) # OK + else: + c = 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..cfa2e6aa5a7 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,49 @@ -from flask import request +from flask import request # $ Source +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 + response = 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 + response = 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 + response = session.get(user_input) # $ 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 + response = session.get(user_input) # $ Alert[py/full-ssrf] \ No newline at end of file From 97f19d03ad7b2f9fa8873f58ce91d46dee225e2a Mon Sep 17 00:00:00 2001 From: "REDMOND\\brodes" Date: Mon, 2 Feb 2026 16:21:34 -0500 Subject: [PATCH 10/22] Updating test case expected alerts. --- .../PartialServerSideRequestForgery.expected | 57 +++++++++++++++++++ .../test_path_validation.py | 34 +++++------ 2 files changed, 74 insertions(+), 17 deletions(-) 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 875d8b62b62..0d3f49c200e 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 @@ -18,10 +18,27 @@ | 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:13:14:62 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:14:36:14:38 | 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:13:16:62 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:16:36:16:38 | 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:13:19:67 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:19:36:19:43 | 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:13:30:59 | ControlFlowNode for KeyClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:30:33:30:35 | 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:13:32:59 | ControlFlowNode for KeyClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:32:33:32:35 | 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:13:35:64 | ControlFlowNode for KeyClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:35:33:35:40 | 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:13:46:46 | ControlFlowNode for Attribute() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:46:43:46:45 | 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:13:48:46 | ControlFlowNode for Attribute() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:48:43:48:45 | 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:13:51:51 | ControlFlowNode for Attribute() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:51:43:51:50 | 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:13:66:62 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:66:36:66:38 | 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:13:69:62 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:69:36:69:38 | 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:13:76:62 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:76:36:76:38 | 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:13:81:62 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:81:36:81:38 | 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:13:85:62 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:85:36:85:38 | 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:13:92:62 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:92:36:92:38 | 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:13:97:62 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:97:36:97:38 | 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:13:100:62 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:100:36:100:38 | 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:13:105:62 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:105:36:105:38 | 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:13:112:62 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:112:36:112:38 | 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:13:117:62 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:117:36:117:38 | 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:13:120:62 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:120:36:120:38 | 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:13:127:62 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:127:36:127:38 | 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:13:130:62 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:130:36:130:38 | 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 | | @@ -184,6 +201,26 @@ edges | test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:76:36:76:38 | ControlFlowNode for url | provenance | Sink:MaD:15 | | test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:79:36:79:38 | ControlFlowNode for url | provenance | Sink:MaD:15 | | test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:81:36:81:38 | ControlFlowNode for url | provenance | Sink:MaD:15 | +| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:85:36:85:38 | ControlFlowNode for url | provenance | Sink:MaD:15 | +| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:87:36:87:38 | ControlFlowNode for url | provenance | Sink:MaD:15 | +| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:90:36:90:38 | ControlFlowNode for url | provenance | Sink:MaD:15 | +| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:92:36:92:38 | ControlFlowNode for url | provenance | Sink:MaD:15 | +| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:95:36:95:38 | ControlFlowNode for url | provenance | Sink:MaD:15 | +| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:97:36:97:38 | ControlFlowNode for url | provenance | Sink:MaD:15 | +| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:100:36:100:38 | ControlFlowNode for url | provenance | Sink:MaD:15 | +| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:102:36:102:38 | ControlFlowNode for url | provenance | Sink:MaD:15 | +| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:105:36:105:38 | ControlFlowNode for url | provenance | Sink:MaD:15 | +| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:107:36:107:38 | ControlFlowNode for url | provenance | Sink:MaD:15 | +| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:110:36:110:38 | ControlFlowNode for url | provenance | Sink:MaD:15 | +| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:112:36:112:38 | ControlFlowNode for url | provenance | Sink:MaD:15 | +| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:115:36:115:38 | ControlFlowNode for url | provenance | Sink:MaD:15 | +| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:117:36:117:38 | ControlFlowNode for url | provenance | Sink:MaD:15 | +| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:120:36:120:38 | ControlFlowNode for url | provenance | Sink:MaD:15 | +| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:122:36:122:38 | ControlFlowNode for url | provenance | Sink:MaD:15 | +| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:125:36:125:38 | ControlFlowNode for url | provenance | Sink:MaD:15 | +| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:127:36:127:38 | ControlFlowNode for url | provenance | Sink:MaD:15 | +| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:130:36:130:38 | ControlFlowNode for url | provenance | Sink:MaD:15 | +| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:132:36:132:38 | ControlFlowNode for url | provenance | Sink:MaD:15 | | test_requests.py:1:19:1:25 | ControlFlowNode for ImportMember | test_requests.py:1:19:1:25 | ControlFlowNode for request | provenance | | | test_requests.py:1:19:1:25 | ControlFlowNode for request | test_requests.py:7:18:7:24 | ControlFlowNode for request | provenance | | | test_requests.py:1:19:1:25 | ControlFlowNode for request | test_requests.py:14:18:14:24 | ControlFlowNode for request | provenance | | @@ -345,6 +382,26 @@ nodes | test_path_validation.py:76:36:76:38 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | | test_path_validation.py:79:36:79:38 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | | test_path_validation.py:81:36:81:38 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| test_path_validation.py:85:36:85:38 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| test_path_validation.py:87:36:87:38 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| test_path_validation.py:90:36:90:38 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| test_path_validation.py:92:36:92:38 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| test_path_validation.py:95:36:95:38 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| test_path_validation.py:97:36:97:38 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| test_path_validation.py:100:36:100:38 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| test_path_validation.py:102:36:102:38 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| test_path_validation.py:105:36:105:38 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| test_path_validation.py:107:36:107:38 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| test_path_validation.py:110:36:110:38 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| test_path_validation.py:112:36:112:38 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| test_path_validation.py:115:36:115:38 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| test_path_validation.py:117:36:117:38 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| test_path_validation.py:120:36:120:38 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| test_path_validation.py:122:36:122:38 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| test_path_validation.py:125:36:125:38 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| test_path_validation.py:127:36:127:38 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| test_path_validation.py:130:36:130:38 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| test_path_validation.py:132:36:132:38 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | | test_requests.py:1:19:1:25 | ControlFlowNode for ImportMember | semmle.label | ControlFlowNode for ImportMember | | test_requests.py:1:19:1:25 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | | test_requests.py:7:5:7:14 | ControlFlowNode for user_input | semmle.label | ControlFlowNode for user_input | 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 index 44c569f625d..3e6bb1f6d0c 100644 --- 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 @@ -16,7 +16,7 @@ def urivalidator_path_in_domain_validation(credential, trusted_domain): c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/partial-ssrf] if URIValidator.in_domain(full_url, trusted_domain): - c = SecretClient(vault_url=full_url, credential=credential) # OK + c = SecretClient(vault_url=full_url, credential=credential) # $ Alert[py/partial-ssrf] else: c = SecretClient(vault_url=full_url, credential=credential) # $ Alert[py/full-ssrf] @@ -32,7 +32,7 @@ def urivalidator_path_in_azure_keyvault_domain_validation(credential): c = KeyClient(vault_url=url, credential=credential) # $ Alert[py/partial-ssrf] if URIValidator.in_azure_keyvault_domain(full_url): - c = KeyClient(vault_url=full_url, credential=credential) # OK + c = KeyClient(vault_url=full_url, credential=credential) # $ Alert[py/partial-ssrf] else: c = KeyClient(vault_url=full_url, credential=credential) # $ Alert[py/full-ssrf] @@ -48,7 +48,7 @@ def urivalidator_path_in_azure_storage_domain_validation(credential): c = ShareFileClient.from_file_url(url) # $ Alert[py/partial-ssrf] if URIValidator.in_azure_storage_domain(full_url): - c = ShareFileClient.from_file_url(full_url) # OK + c = ShareFileClient.from_file_url(full_url) # $ Alert[py/partial-ssrf] else: c = ShareFileClient.from_file_url(full_url) # $ Alert[py/full-ssrf] @@ -63,70 +63,70 @@ def complex_urivalidator_checks(credential, trusted_domain): if not URIValidator.in_domain(url, trusted_domain): c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/full-ssrf] else: - c = SecretClient(vault_url=url, credential=credential) # OK + c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/partial-ssrf] if URIValidator.in_domain(url, trusted_domain) and trusted_domain == "example.com": - c = SecretClient(vault_url=url, credential=credential) # OK + c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/partial-ssrf] else: c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/full-ssrf] if not (URIValidator.in_domain(url, trusted_domain) and trusted_domain == "example.com"): c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/full-ssrf] else: - c = SecretClient(vault_url=url, credential=credential) # OK + c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/partial-ssrf] if not not not URIValidator.in_domain(url, trusted_domain): c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/full-ssrf] else: - c = SecretClient(vault_url=url, credential=credential) # OK + c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/partial-ssrf] if URIValidator.in_domain(url, trusted_domain) == True: - c = SecretClient(vault_url=url, credential=credential) # OK + c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/partial-ssrf] else: c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/full-ssrf] if URIValidator.in_domain(url, trusted_domain) == False: c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/full-ssrf] else: - c = SecretClient(vault_url=url, credential=credential) # OK + c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/partial-ssrf] if URIValidator.in_domain(url, trusted_domain) != True: c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/full-ssrf] else: - c = SecretClient(vault_url=url, credential=credential) # OK + c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/partial-ssrf] if URIValidator.in_domain(url, trusted_domain) != False: - c = SecretClient(vault_url=url, credential=credential) # OK + c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/partial-ssrf] else: c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/full-ssrf] if URIValidator.in_domain(url, trusted_domain) is True: - c = SecretClient(vault_url=url, credential=credential) # OK + c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/partial-ssrf] else: c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/full-ssrf] if URIValidator.in_domain(url, trusted_domain) is False: c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/full-ssrf] else: - c = SecretClient(vault_url=url, credential=credential) # OK + c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/partial-ssrf] if URIValidator.in_domain(url, trusted_domain) is not True: c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/full-ssrf] else: - c = SecretClient(vault_url=url, credential=credential) # OK + c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/partial-ssrf] if URIValidator.in_domain(url, trusted_domain) is not False: - c = SecretClient(vault_url=url, credential=credential) # OK + c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/partial-ssrf] else: c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/full-ssrf] if not URIValidator.in_domain(url, trusted_domain) is True: c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/full-ssrf] else: - c = SecretClient(vault_url=url, credential=credential) # OK + c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/partial-ssrf] if not URIValidator.in_domain(url, trusted_domain) is False: - c = SecretClient(vault_url=url, credential=credential) # OK + c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/partial-ssrf] else: c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/full-ssrf] \ No newline at end of file From 42f6e6a19cdba380b2b0245cfe091c894204fda9 Mon Sep 17 00:00:00 2001 From: "REDMOND\\brodes" Date: Tue, 3 Feb 2026 11:44:34 -0500 Subject: [PATCH 11/22] Fixing inefficiently passed variable in nested existential quantification. --- .../dataflow/ServerSideRequestForgeryCustomizations.qll | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/python/ql/lib/semmle/python/security/dataflow/ServerSideRequestForgeryCustomizations.qll b/python/ql/lib/semmle/python/security/dataflow/ServerSideRequestForgeryCustomizations.qll index 2139ecf797d..e75217d608f 100644 --- a/python/ql/lib/semmle/python/security/dataflow/ServerSideRequestForgeryCustomizations.qll +++ b/python/ql/lib/semmle/python/security/dataflow/ServerSideRequestForgeryCustomizations.qll @@ -185,15 +185,14 @@ module ServerSideRequestForgery { import semmle.python.dataflow.new.internal.DataFlowPublic private predicate uri_validator(DataFlow::GuardNode g, ControlFlowNode node, boolean branch) { - exists(DataFlow::CallCfgNode call, Node n, string funcs | + exists(DataFlow::CallCfgNode call, string funcs | funcs in ["in_domain", "in_azure_keyvault_domain", "in_azure_storage_domain"] | call = API::moduleImport("AntiSSRF").getMember("URIValidator").getMember(funcs).getACall() and call.getArg(0).asCfgNode() = node and - n.getALocalSource() = call and ( // validator used in a comparison - exists(CompareNode cn, Cmpop op | cn = g | + exists(CompareNode cn, Cmpop op, Node n | cn = g and n.getALocalSource() = call | ( // validator == true or validator == false or validator is True or validator is False (op instanceof Eq or op instanceof Is) and From 4f11913ee53aab76fff8457007c2bf83bce8b6ae Mon Sep 17 00:00:00 2001 From: "REDMOND\\brodes" Date: Fri, 6 Feb 2026 11:23:58 -0500 Subject: [PATCH 12/22] removing SSRFSink.qll --- .../lib/semmle/python/frameworks/SSRFSink.qll | 42 ------------------- 1 file changed, 42 deletions(-) delete mode 100644 python/ql/lib/semmle/python/frameworks/SSRFSink.qll diff --git a/python/ql/lib/semmle/python/frameworks/SSRFSink.qll b/python/ql/lib/semmle/python/frameworks/SSRFSink.qll deleted file mode 100644 index aeb228daf13..00000000000 --- a/python/ql/lib/semmle/python/frameworks/SSRFSink.qll +++ /dev/null @@ -1,42 +0,0 @@ -/** - * Provides classes for SSRF sinks modeled using Models as Data (MaD). - */ - -private import python -private import semmle.python.Concepts -private import semmle.python.ApiGraphs -private import semmle.python.frameworks.data.ModelsAsData - -/** - * INTERNAL: Do not use. - * - * Sets up SSRF sinks as Http::Client::Request - */ -module SsrfMaDModel { - /** - * An HTTP request modeled from `ssrf` sinks, modeled using MaD. - */ - class SsrfSink extends Http::Client::Request::Range instanceof API::CallNode { - DataFlow::Node urlArg; - - SsrfSink() { - ( - this.getArg(_) = urlArg - or - this.getArgByName(_) = urlArg - ) and - urlArg = ModelOutput::getASinkNode("ssrf").asSink() - } - - override DataFlow::Node getAUrlPart() { result = urlArg } - - override string getFramework() { result = "MaD" } - - override predicate disablesCertificateValidation( - DataFlow::Node disablingNode, DataFlow::Node argumentOrigin - ) { - // NOTE: if you need to define this, you have to special case it for every possible API in MaD - none() - } - } -} From f6c302b68cc107d8a361a9dd1e5dbddc88015ee2 Mon Sep 17 00:00:00 2001 From: "REDMOND\\brodes" Date: Fri, 6 Feb 2026 11:28:48 -0500 Subject: [PATCH 13/22] Removing commented out test cases. --- .../test_azure_client.py | 200 ------------------ 1 file changed, 200 deletions(-) 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 28570b7ab4a..5dbb7e1ede4 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 @@ -23,203 +23,3 @@ def azure_sdk_test(credential, output_path): 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] - -# if URIValidator.in_domain(url, trusted_domain): -# # Testing Azure sink -# c = SecretClient(vault_url=url, credential=credential)# OK -# c = ShareFileClient.from_file_url(url) # OK -# c = KeyClient(url, credential)# OK -# c = ContainerClient.from_container_url(container_url=url, credential=credential) # OK - -# download_blob_from_url( -# blob_url=url, # OK -# output=output_path, -# credential=credential, -# overwrite=True -# ) -# else: -# # Testing Azure sink -# c = SecretClient(vault_url=url, credential=credential)# NOT OK -- user only controlled fragment -# c = ShareFileClient.from_file_url(url) # NOT OK -- user only controlled fragment -# c = KeyClient(url, credential)# NOT OK -- user only controlled fragment -# c = ContainerClient.from_container_url(container_url=url, credential=credential) # NOT OK -- user only controlled fragment - -# download_blob_from_url( -# blob_url=url, # NOT OK -- user only controlled fragment -# output=output_path, -# credential=credential, -# overwrite=True -# ) - - -# if URIValidator.in_domain(full_url, trusted_domain): -# # Testing Azure sink -# c = SecretClient(vault_url=full_url, credential=credential) # OK -# c = ShareFileClient.from_file_url(full_url) # OK -# c = KeyClient(full_url, credential) # OK -# c = ContainerClient.from_container_url(container_url=full_url, credential=credential) # OK - -# download_blob_from_url( -# blob_url=full_url, # OK -# output=output_path, -# credential=credential, -# overwrite=True -# ) -# else: -# # Testing Azure sink -# c = SecretClient(vault_url=full_url, credential=credential) # NOT OK -- user has full control -# c = ShareFileClient.from_file_url(full_url) # NOT OK -- user has full control -# c = KeyClient(full_url, credential) # NOT OK -- user has full control -# c = ContainerClient.from_container_url(container_url=full_url, credential=credential) # NOT OK -- user has full control - -# download_blob_from_url( -# blob_url=full_url, # NOT OK -- user has full control -# output=output_path, -# credential=credential, -# overwrite=True -# ) - - -# if URIValidator.in_azure_keyvault_domain(url): -# # Testing Azure sink -# c = SecretClient(vault_url=url, credential=credential)# OK -# c = ShareFileClient.from_file_url(url) # OK -# c = KeyClient(url, credential)# OK -# c = ContainerClient.from_container_url(container_url=url, credential=credential) # OK - -# download_blob_from_url( -# blob_url=url, # OK -# output=output_path, -# credential=credential, -# overwrite=True -# ) -# else: -# # Testing Azure sink -# c = SecretClient(vault_url=url, credential=credential)# NOT OK -- user only controlled fragment -# c = ShareFileClient.from_file_url(url) # NOT OK -- user only controlled fragment -# c = KeyClient(url, credential)# NOT OK -- user only controlled fragment -# c = ContainerClient.from_container_url(container_url=url, credential=credential) # NOT OK -- user only controlled fragment - -# download_blob_from_url( -# blob_url=url, # NOT OK -- user only controlled fragment -# output=output_path, -# credential=credential, -# overwrite=True -# ) - - -# if URIValidator.in_azure_keyvault_domain(full_url): -# # Testing Azure sink -# c = SecretClient(vault_url=full_url, credential=credential) # OK -# c = ShareFileClient.from_file_url(full_url) # OK -# c = KeyClient(full_url, credential) # OK -# c = ContainerClient.from_container_url(container_url=full_url, credential=credential) # OK - -# download_blob_from_url( -# blob_url=full_url, # OK -# output=output_path, -# credential=credential, -# overwrite=True -# ) -# else: -# # Testing Azure sink -# c = SecretClient(vault_url=full_url, credential=credential) # NOT OK -- user has full control -# c = ShareFileClient.from_file_url(full_url) # NOT OK -- user has full control -# c = KeyClient(full_url, credential) # NOT OK -- user has full control -# c = ContainerClient.from_container_url(container_url=full_url, credential=credential) # NOT OK -- user has full control - -# download_blob_from_url( -# blob_url=full_url, # NOT OK -- user has full control -# output=output_path, -# credential=credential, -# overwrite=True -# ) - -# if URIValidator.in_azure_storage_domain(url): -# # Testing Azure sink -# c = SecretClient(vault_url=url, credential=credential)# OK -# c = ShareFileClient.from_file_url(url) # OK -# c = KeyClient(url, credential)# OK -# c = ContainerClient.from_container_url(container_url=url, credential=credential) # OK - -# download_blob_from_url( -# blob_url=url, # OK -# output=output_path, -# credential=credential, -# overwrite=True -# ) -# else: -# # Testing Azure sink -# c = SecretClient(vault_url=url, credential=credential)# NOT OK -- user only controlled fragment -# c = ShareFileClient.from_file_url(url) # NOT OK -- user only controlled fragment -# c = KeyClient(url, credential)# NOT OK -- user only controlled fragment -# c = ContainerClient.from_container_url(container_url=url, credential=credential) # NOT OK -- user only controlled fragment - -# download_blob_from_url( -# blob_url=url, # NOT OK -- user only controlled fragment -# output=output_path, -# credential=credential, -# overwrite=True -# ) - - -# if URIValidator.in_azure_storage_domain(full_url): -# # Testing Azure sink -# c = SecretClient(vault_url=full_url, credential=credential) # OK -# c = ShareFileClient.from_file_url(full_url) # OK -# c = KeyClient(full_url, credential) # OK -# c = ContainerClient.from_container_url(container_url=full_url, credential=credential) # OK - -# download_blob_from_url( -# blob_url=full_url, # OK -# output=output_path, -# credential=credential, -# overwrite=True -# ) -# else: -# # Testing Azure sink -# c = SecretClient(vault_url=full_url, credential=credential) # NOT OK -- user has full control -# c = ShareFileClient.from_file_url(full_url) # NOT OK -- user has full control -# c = KeyClient(full_url, credential) # NOT OK -- user has full control -# c = ContainerClient.from_container_url(container_url=full_url, credential=credential) # NOT OK -- user has full control - -# download_blob_from_url( -# blob_url=full_url, # NOT OK -- user has full control -# output=output_path, -# credential=credential, -# overwrite=True -# ) - -# def azure_sdk_logic_sanity_test(credential, output_path, trusted_domain): -# user_input = request.args['untrusted_input'] -# full_url = f"https://{user_input}" -# if not URIValidator.in_azure_storage_domain(full_url): -# # Testing Azure sink -# c = SecretClient(vault_url=full_url, credential=credential) # NOT OK -- user has full control -# else: -# # Testing Azure sink -# c = SecretClient(vault_url=full_url, credential=credential) # OK - - - -# if not not URIValidator.in_azure_storage_domain(full_url): -# # Testing Azure sink -# c = SecretClient(vault_url=full_url, credential=credential) # OK -# else: -# # Testing Azure sink -# c = SecretClient(vault_url=full_url, credential=credential) # NOT OK -- user has full control - - -# if URIValidator.URIValidator.in_domain(full_url, trusted_domain) and trusted_domain == "example.com": -# # Testing Azure sink -# c = SecretClient(vault_url=full_url, credential=credential) # OK -# else: -# # Testing Azure sink -# c = SecretClient(vault_url=full_url, credential=credential) # NOT OK -- user has full control - -# if not (URIValidator.URIValidator.in_domain(full_url, trusted_domain) and trusted_domain == "example.com"): -# # Testing Azure sink -# c = SecretClient(vault_url=full_url, credential=credential) # NOT OK -- user has full control -# else: -# # Testing Azure sink -# c = SecretClient(vault_url=full_url, credential=credential) # OK \ No newline at end of file From df544595525a8df1dab3030753ce673602550910 Mon Sep 17 00:00:00 2001 From: "REDMOND\\brodes" Date: Mon, 9 Feb 2026 13:19:02 -0500 Subject: [PATCH 14/22] Restore prior PR change log (accidentally removed) --- python/ql/lib/change-notes/2025-09-30-azure_ssrf_models.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 python/ql/lib/change-notes/2025-09-30-azure_ssrf_models.md diff --git a/python/ql/lib/change-notes/2025-09-30-azure_ssrf_models.md b/python/ql/lib/change-notes/2025-09-30-azure_ssrf_models.md new file mode 100644 index 00000000000..283b703a438 --- /dev/null +++ b/python/ql/lib/change-notes/2025-09-30-azure_ssrf_models.md @@ -0,0 +1,5 @@ +--- +category: minorAnalysis +--- +* Added request forgery sink models for the Azure SDK. +* Made it so that models-as-data sinks with the kind `request-forgery` contribute to the class `Http::Client::Request` which represents HTTP client requests. \ No newline at end of file From 23bab818553cd00fac1704e75567d775981150b1 Mon Sep 17 00:00:00 2001 From: "REDMOND\\brodes" Date: Mon, 9 Feb 2026 13:22:35 -0500 Subject: [PATCH 15/22] Added change log --- ...026-02-09-ssrf_test_case_cleanup_and_new_ssrf_barriers.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 python/ql/lib/change-notes/2026-02-09-ssrf_test_case_cleanup_and_new_ssrf_barriers.md 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..d4373eadfb2 --- /dev/null +++ b/python/ql/lib/change-notes/2026-02-09-ssrf_test_case_cleanup_and_new_ssrf_barriers.md @@ -0,0 +1,5 @@ +--- +category: minorAnalysis +--- +* Modified SSRF tests to use postprocessing to more easily debug results. +* Added new full SSRF sanitization barrier from the new AntiSSRF library. \ No newline at end of file From 9f8ed710e28870ccd1044c53055bcce57ce062cf Mon Sep 17 00:00:00 2001 From: Ben Rodes Date: Tue, 10 Feb 2026 11:09:25 -0500 Subject: [PATCH 16/22] Update python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/test_path_validation.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../CWE-918-ServerSideRequestForgery/test_path_validation.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 index 3e6bb1f6d0c..4560479d2b3 100644 --- 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 @@ -56,8 +56,8 @@ def urivalidator_path_in_azure_storage_domain_validation(credential): def complex_urivalidator_checks(credential, trusted_domain): user_input = request.args['untrusted_input'] # Focus on in_domain only here for simplicity - # It assumed the logic underlying checking paths would apply - # similarly other validator methods + # 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): From a91cf6b7cba78087cc011eea9cd15555c07a0c29 Mon Sep 17 00:00:00 2001 From: "REDMOND\\brodes" Date: Tue, 10 Feb 2026 11:37:11 -0500 Subject: [PATCH 17/22] Applying copilot PR suggestions. --- ...ServerSideRequestForgeryCustomizations.qll | 2 +- .../FullServerSideRequestForgery.expected | 129 +++++---- .../PartialServerSideRequestForgery.expected | 248 +++++++++--------- .../full_partial_test.py | 6 +- .../test_azure_client.py | 16 +- .../test_http_client.py | 2 +- .../test_path_validation.py | 80 +++--- .../test_requests.py | 8 +- 8 files changed, 244 insertions(+), 247 deletions(-) diff --git a/python/ql/lib/semmle/python/security/dataflow/ServerSideRequestForgeryCustomizations.qll b/python/ql/lib/semmle/python/security/dataflow/ServerSideRequestForgeryCustomizations.qll index e75217d608f..afce799d8ac 100644 --- a/python/ql/lib/semmle/python/security/dataflow/ServerSideRequestForgeryCustomizations.qll +++ b/python/ql/lib/semmle/python/security/dataflow/ServerSideRequestForgeryCustomizations.qll @@ -177,7 +177,7 @@ module ServerSideRequestForgery { ) } - /** A validation that a string does not contain certain characters, considered as a sanitizer. */ + /** 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() } } 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 19b5f7efa9d..cb46c54ca70 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 @@ -13,32 +13,32 @@ | 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:9:16:63 | ControlFlowNode for SecretClient() | test_azure_client.py:6:19:6:25 | ControlFlowNode for ImportMember | test_azure_client.py:16:32:16:39 | 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:9:18:47 | ControlFlowNode for Attribute() | test_azure_client.py:6:19:6:25 | ControlFlowNode for ImportMember | test_azure_client.py:18:39:18:46 | 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:9:20:39 | ControlFlowNode for KeyClient() | test_azure_client.py:6:19:6:25 | ControlFlowNode for ImportMember | test_azure_client.py:20:19:20:26 | 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:9:22:89 | ControlFlowNode for Attribute() | test_azure_client.py:6:19:6:25 | ControlFlowNode for ImportMember | test_azure_client.py:22:58:22:65 | 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: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:13:21:67 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:21:36:21:43 | 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:13:37:64 | ControlFlowNode for KeyClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:37:33:37:40 | 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:13:53:51 | ControlFlowNode for Attribute() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:53:43:53:50 | 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:13:64:62 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:64:36:64:38 | 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:13:71:62 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:71:36:71:38 | 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:13:74:62 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:74:36:74:38 | 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:13:79:62 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:79:36:79:38 | 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:13:87:62 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:87:36:87:38 | 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:13:90:62 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:90:36:90:38 | 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:13:95:62 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:95:36:95:38 | 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:13:102:62 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:102:36:102:38 | 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:13:107:62 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:107:36:107:38 | 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:13:110:62 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:110:36:110:38 | 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:13:115:62 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:115:36:115:38 | 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:13:122:62 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:122:36:122:38 | 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:13:125:62 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:125:36:125:38 | 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:13:132:62 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:132:36:132:38 | 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: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:16:22:55 | ControlFlowNode for Attribute() | test_requests.py:1:19:1:25 | ControlFlowNode for ImportMember | test_requests.py:22:45:22:54 | 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 | @@ -85,10 +85,10 @@ edges | 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:32:16:39 | ControlFlowNode for full_url | provenance | Sink:MaD:15 | -| test_azure_client.py:13:5:13:12 | ControlFlowNode for full_url | test_azure_client.py:18:39:18:46 | ControlFlowNode for full_url | provenance | Sink:MaD:38 | -| test_azure_client.py:13:5:13:12 | ControlFlowNode for full_url | test_azure_client.py:20:19:20:26 | ControlFlowNode for full_url | provenance | Sink:MaD:14 | -| test_azure_client.py:13:5:13:12 | ControlFlowNode for full_url | test_azure_client.py:22:58:22:65 | ControlFlowNode for full_url | provenance | Sink:MaD:26 | +| 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:15 | +| 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:38 | +| 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:14 | +| 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:26 | | 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:27 | | 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 | | @@ -113,31 +113,31 @@ edges | 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:36:21:43 | ControlFlowNode for full_url | provenance | Sink:MaD:15 | +| 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:15 | | 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:33:37:40 | ControlFlowNode for full_url | provenance | Sink:MaD:14 | +| 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:14 | | 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:43:53:50 | ControlFlowNode for full_url | provenance | Sink:MaD:38 | +| 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:38 | | 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:36:64:38 | ControlFlowNode for url | provenance | Sink:MaD:15 | -| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:71:36:71:38 | ControlFlowNode for url | provenance | Sink:MaD:15 | -| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:74:36:74:38 | ControlFlowNode for url | provenance | Sink:MaD:15 | -| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:79:36:79:38 | ControlFlowNode for url | provenance | Sink:MaD:15 | -| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:87:36:87:38 | ControlFlowNode for url | provenance | Sink:MaD:15 | -| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:90:36:90:38 | ControlFlowNode for url | provenance | Sink:MaD:15 | -| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:95:36:95:38 | ControlFlowNode for url | provenance | Sink:MaD:15 | -| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:102:36:102:38 | ControlFlowNode for url | provenance | Sink:MaD:15 | -| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:107:36:107:38 | ControlFlowNode for url | provenance | Sink:MaD:15 | -| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:110:36:110:38 | ControlFlowNode for url | provenance | Sink:MaD:15 | -| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:115:36:115:38 | ControlFlowNode for url | provenance | Sink:MaD:15 | -| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:122:36:122:38 | ControlFlowNode for url | provenance | Sink:MaD:15 | -| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:125:36:125:38 | ControlFlowNode for url | provenance | Sink:MaD:15 | -| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:132:36:132:38 | ControlFlowNode for url | provenance | Sink:MaD:15 | +| 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:15 | +| 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:15 | +| 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:15 | +| 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:15 | +| 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:15 | +| 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:15 | +| 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:15 | +| 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:15 | +| 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:15 | +| 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:15 | +| 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:15 | +| 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:15 | +| 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:15 | +| 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:15 | | test_requests.py:1:19:1:25 | ControlFlowNode for ImportMember | test_requests.py:1:19:1:25 | ControlFlowNode for request | provenance | | | test_requests.py:1:19:1:25 | ControlFlowNode for request | test_requests.py:7:18:7:24 | ControlFlowNode for request | provenance | | | test_requests.py:1:19:1:25 | ControlFlowNode for request | test_requests.py:14:18:14:24 | ControlFlowNode for request | provenance | | @@ -192,10 +192,10 @@ nodes | 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:32:16:39 | ControlFlowNode for full_url | semmle.label | ControlFlowNode for full_url | -| test_azure_client.py:18:39:18:46 | ControlFlowNode for full_url | semmle.label | ControlFlowNode for full_url | -| test_azure_client.py:20:19:20:26 | ControlFlowNode for full_url | semmle.label | ControlFlowNode for full_url | -| test_azure_client.py:22:58:22:65 | 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 | @@ -215,34 +215,34 @@ nodes | 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:36:21:43 | 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:33:37:40 | 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:43:53:50 | 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:36:64:38 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:71:36:71:38 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:74:36:74:38 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:79:36:79:38 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:87:36:87:38 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:90:36:90:38 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:95:36:95:38 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:102:36:102:38 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:107:36:107:38 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:110:36:110:38 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:115:36:115:38 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:122:36:122:38 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:125:36:125:38 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:132:36:132:38 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| test_path_validation.py:64:32:64:34 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| test_path_validation.py:71:32:71:34 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| test_path_validation.py:74:32:74:34 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| test_path_validation.py:79:32:79:34 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| test_path_validation.py:87:32:87:34 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| test_path_validation.py:90:32:90:34 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| test_path_validation.py:95:32:95:34 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| test_path_validation.py:102:32:102:34 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| test_path_validation.py:107:32:107:34 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| test_path_validation.py:110:32:110:34 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| test_path_validation.py:115:32:115:34 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| test_path_validation.py:122:32:122:34 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| test_path_validation.py:125:32:125:34 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| test_path_validation.py:132:32:132:34 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | | test_requests.py:1:19:1:25 | ControlFlowNode for ImportMember | semmle.label | ControlFlowNode for ImportMember | | test_requests.py:1:19:1:25 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | | test_requests.py:7:5:7:14 | ControlFlowNode for user_input | semmle.label | ControlFlowNode for user_input | @@ -255,6 +255,3 @@ nodes | test_requests.py:20:18:20:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | | test_requests.py:22:45:22:54 | ControlFlowNode for user_input | semmle.label | ControlFlowNode for user_input | subpaths -testFailures -| test_requests.py:39:40:39:62 | Comment # $ Alert[py/full-ssrf] | Missing result: Alert[py/full-ssrf] | -| test_requests.py:49:40:49:62 | Comment # $ Alert[py/full-ssrf] | Missing result: Alert[py/full-ssrf] | 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 0d3f49c200e..314aa99ef60 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 @@ -6,39 +6,39 @@ | 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:9:15:58 | ControlFlowNode for SecretClient() | test_azure_client.py:6:19:6:25 | ControlFlowNode for ImportMember | test_azure_client.py:15:32:15:34 | 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:9:17:42 | ControlFlowNode for Attribute() | test_azure_client.py:6:19:6:25 | ControlFlowNode for ImportMember | test_azure_client.py:17:39:17:41 | 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:9:19:34 | ControlFlowNode for KeyClient() | test_azure_client.py:6:19:6:25 | ControlFlowNode for ImportMember | test_azure_client.py:19:19:19:21 | 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:9:21:84 | ControlFlowNode for Attribute() | test_azure_client.py:6:19:6:25 | ControlFlowNode for ImportMember | test_azure_client.py:21:58:21:60 | 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: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:13:14:62 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:14:36:14:38 | 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:13:16:62 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:16:36:16:38 | 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:13:19:67 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:19:36:19:43 | 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:13:30:59 | ControlFlowNode for KeyClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:30:33:30:35 | 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:13:32:59 | ControlFlowNode for KeyClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:32:33:32:35 | 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:13:35:64 | ControlFlowNode for KeyClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:35:33:35:40 | 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:13:46:46 | ControlFlowNode for Attribute() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:46:43:46:45 | 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:13:48:46 | ControlFlowNode for Attribute() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:48:43:48:45 | 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:13:51:51 | ControlFlowNode for Attribute() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:51:43:51:50 | 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:13:66:62 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:66:36:66:38 | 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:13:69:62 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:69:36:69:38 | 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:13:76:62 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:76:36:76:38 | 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:13:81:62 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:81:36:81:38 | 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:13:85:62 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:85:36:85:38 | 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:13:92:62 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:92:36:92:38 | 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:13:97:62 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:97:36:97:38 | 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:13:100:62 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:100:36:100:38 | 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:13:105:62 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:105:36:105:38 | 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:13:112:62 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:112:36:112:38 | 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:13:117:62 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:117:36:117:38 | 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:13:120:62 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:120:36:120:38 | 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:13:127:62 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:127:36:127:38 | 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:13:130:62 | ControlFlowNode for SecretClient() | test_path_validation.py:5:19:5:25 | ControlFlowNode for ImportMember | test_path_validation.py:130:36:130:38 | 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: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 | | @@ -126,15 +126,15 @@ edges | 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:32:15:34 | ControlFlowNode for url | provenance | Sink:MaD:15 | -| test_azure_client.py:12:5:12:7 | ControlFlowNode for url | test_azure_client.py:17:39:17:41 | ControlFlowNode for url | provenance | Sink:MaD:38 | -| test_azure_client.py:12:5:12:7 | ControlFlowNode for url | test_azure_client.py:19:19:19:21 | ControlFlowNode for url | provenance | Sink:MaD:14 | -| test_azure_client.py:12:5:12:7 | ControlFlowNode for url | test_azure_client.py:21:58:21:60 | ControlFlowNode for url | provenance | Sink:MaD:26 | +| 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:15 | +| 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:38 | +| 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:14 | +| 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:26 | | 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:27 | -| test_azure_client.py:13:5:13:12 | ControlFlowNode for full_url | test_azure_client.py:16:32:16:39 | ControlFlowNode for full_url | provenance | Sink:MaD:15 | -| test_azure_client.py:13:5:13:12 | ControlFlowNode for full_url | test_azure_client.py:18:39:18:46 | ControlFlowNode for full_url | provenance | Sink:MaD:38 | -| test_azure_client.py:13:5:13:12 | ControlFlowNode for full_url | test_azure_client.py:20:19:20:26 | ControlFlowNode for full_url | provenance | Sink:MaD:14 | -| test_azure_client.py:13:5:13:12 | ControlFlowNode for full_url | test_azure_client.py:22:58:22:65 | ControlFlowNode for full_url | provenance | Sink:MaD:26 | +| 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:15 | +| 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:38 | +| 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:14 | +| 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:26 | | 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:27 | | 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 | | @@ -169,58 +169,58 @@ edges | 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:36:14:38 | ControlFlowNode for url | provenance | Sink:MaD:15 | -| test_path_validation.py:10:5:10:7 | ControlFlowNode for url | test_path_validation.py:16:36:16:38 | ControlFlowNode for url | provenance | Sink:MaD:15 | -| test_path_validation.py:11:5:11:12 | ControlFlowNode for full_url | test_path_validation.py:19:36:19:43 | ControlFlowNode for full_url | provenance | Sink:MaD:15 | -| test_path_validation.py:11:5:11:12 | ControlFlowNode for full_url | test_path_validation.py:21:36:21:43 | ControlFlowNode for full_url | provenance | Sink:MaD:15 | +| 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:15 | +| 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:15 | +| 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:15 | +| 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:15 | | 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:33:30:35 | ControlFlowNode for url | provenance | Sink:MaD:14 | -| test_path_validation.py:26:5:26:7 | ControlFlowNode for url | test_path_validation.py:32:33:32:35 | ControlFlowNode for url | provenance | Sink:MaD:14 | -| test_path_validation.py:27:5:27:12 | ControlFlowNode for full_url | test_path_validation.py:35:33:35:40 | ControlFlowNode for full_url | provenance | Sink:MaD:14 | -| test_path_validation.py:27:5:27:12 | ControlFlowNode for full_url | test_path_validation.py:37:33:37:40 | ControlFlowNode for full_url | provenance | Sink:MaD:14 | +| 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:14 | +| 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:14 | +| 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:14 | +| 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:14 | | 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:43:46:45 | ControlFlowNode for url | provenance | Sink:MaD:38 | -| test_path_validation.py:42:5:42:7 | ControlFlowNode for url | test_path_validation.py:48:43:48:45 | ControlFlowNode for url | provenance | Sink:MaD:38 | -| test_path_validation.py:43:5:43:12 | ControlFlowNode for full_url | test_path_validation.py:51:43:51:50 | ControlFlowNode for full_url | provenance | Sink:MaD:38 | -| test_path_validation.py:43:5:43:12 | ControlFlowNode for full_url | test_path_validation.py:53:43:53:50 | ControlFlowNode for full_url | provenance | Sink:MaD:38 | +| 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:38 | +| 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:38 | +| 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:38 | +| 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:38 | | 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:36:64:38 | ControlFlowNode for url | provenance | Sink:MaD:15 | -| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:66:36:66:38 | ControlFlowNode for url | provenance | Sink:MaD:15 | -| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:69:36:69:38 | ControlFlowNode for url | provenance | Sink:MaD:15 | -| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:71:36:71:38 | ControlFlowNode for url | provenance | Sink:MaD:15 | -| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:74:36:74:38 | ControlFlowNode for url | provenance | Sink:MaD:15 | -| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:76:36:76:38 | ControlFlowNode for url | provenance | Sink:MaD:15 | -| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:79:36:79:38 | ControlFlowNode for url | provenance | Sink:MaD:15 | -| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:81:36:81:38 | ControlFlowNode for url | provenance | Sink:MaD:15 | -| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:85:36:85:38 | ControlFlowNode for url | provenance | Sink:MaD:15 | -| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:87:36:87:38 | ControlFlowNode for url | provenance | Sink:MaD:15 | -| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:90:36:90:38 | ControlFlowNode for url | provenance | Sink:MaD:15 | -| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:92:36:92:38 | ControlFlowNode for url | provenance | Sink:MaD:15 | -| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:95:36:95:38 | ControlFlowNode for url | provenance | Sink:MaD:15 | -| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:97:36:97:38 | ControlFlowNode for url | provenance | Sink:MaD:15 | -| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:100:36:100:38 | ControlFlowNode for url | provenance | Sink:MaD:15 | -| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:102:36:102:38 | ControlFlowNode for url | provenance | Sink:MaD:15 | -| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:105:36:105:38 | ControlFlowNode for url | provenance | Sink:MaD:15 | -| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:107:36:107:38 | ControlFlowNode for url | provenance | Sink:MaD:15 | -| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:110:36:110:38 | ControlFlowNode for url | provenance | Sink:MaD:15 | -| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:112:36:112:38 | ControlFlowNode for url | provenance | Sink:MaD:15 | -| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:115:36:115:38 | ControlFlowNode for url | provenance | Sink:MaD:15 | -| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:117:36:117:38 | ControlFlowNode for url | provenance | Sink:MaD:15 | -| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:120:36:120:38 | ControlFlowNode for url | provenance | Sink:MaD:15 | -| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:122:36:122:38 | ControlFlowNode for url | provenance | Sink:MaD:15 | -| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:125:36:125:38 | ControlFlowNode for url | provenance | Sink:MaD:15 | -| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:127:36:127:38 | ControlFlowNode for url | provenance | Sink:MaD:15 | -| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:130:36:130:38 | ControlFlowNode for url | provenance | Sink:MaD:15 | -| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:132:36:132:38 | ControlFlowNode for url | provenance | Sink:MaD:15 | +| 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:15 | +| 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:15 | +| 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:15 | +| 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:15 | +| 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:15 | +| 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:15 | +| 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:15 | +| 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:15 | +| 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:15 | +| 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:15 | +| 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:15 | +| 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:15 | +| 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:15 | +| 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:15 | +| 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:15 | +| 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:15 | +| 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:15 | +| 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:15 | +| 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:15 | +| 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:15 | +| 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:15 | +| 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:15 | +| 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:15 | +| 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:15 | +| 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:15 | +| 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:15 | +| 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:15 | +| 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:15 | | test_requests.py:1:19:1:25 | ControlFlowNode for ImportMember | test_requests.py:1:19:1:25 | ControlFlowNode for request | provenance | | | test_requests.py:1:19:1:25 | ControlFlowNode for request | test_requests.py:7:18:7:24 | ControlFlowNode for request | provenance | | | test_requests.py:1:19:1:25 | ControlFlowNode for request | test_requests.py:14:18:14:24 | ControlFlowNode for request | provenance | | @@ -311,14 +311,14 @@ nodes | 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:32:15:34 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_azure_client.py:16:32:16:39 | ControlFlowNode for full_url | semmle.label | ControlFlowNode for full_url | -| test_azure_client.py:17:39:17:41 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_azure_client.py:18:39:18:46 | ControlFlowNode for full_url | semmle.label | ControlFlowNode for full_url | -| test_azure_client.py:19:19:19:21 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_azure_client.py:20:19:20:26 | ControlFlowNode for full_url | semmle.label | ControlFlowNode for full_url | -| test_azure_client.py:21:58:21:60 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_azure_client.py:22:58:22:65 | 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 | @@ -347,61 +347,61 @@ nodes | 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:36:14:38 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:16:36:16:38 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:19:36:19:43 | ControlFlowNode for full_url | semmle.label | ControlFlowNode for full_url | -| test_path_validation.py:21:36:21:43 | 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:33:30:35 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:32:33:32:35 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:35:33:35:40 | ControlFlowNode for full_url | semmle.label | ControlFlowNode for full_url | -| test_path_validation.py:37:33:37:40 | 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:43:46:45 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:48:43:48:45 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:51:43:51:50 | ControlFlowNode for full_url | semmle.label | ControlFlowNode for full_url | -| test_path_validation.py:53:43:53:50 | 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:36:64:38 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:66:36:66:38 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:69:36:69:38 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:71:36:71:38 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:74:36:74:38 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:76:36:76:38 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:79:36:79:38 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:81:36:81:38 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:85:36:85:38 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:87:36:87:38 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:90:36:90:38 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:92:36:92:38 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:95:36:95:38 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:97:36:97:38 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:100:36:100:38 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:102:36:102:38 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:105:36:105:38 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:107:36:107:38 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:110:36:110:38 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:112:36:112:38 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:115:36:115:38 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:117:36:117:38 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:120:36:120:38 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:122:36:122:38 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:125:36:125:38 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:127:36:127:38 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:130:36:130:38 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | -| test_path_validation.py:132:36:132:38 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| test_path_validation.py:64:32:64:34 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| test_path_validation.py:66:32:66:34 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| test_path_validation.py:69:32:69:34 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| test_path_validation.py:71:32:71:34 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| test_path_validation.py:74:32:74:34 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| test_path_validation.py:76:32:76:34 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| test_path_validation.py:79:32:79:34 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| test_path_validation.py:81:32:81:34 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| test_path_validation.py:85:32:85:34 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| test_path_validation.py:87:32:87:34 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| test_path_validation.py:90:32:90:34 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| test_path_validation.py:92:32:92:34 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| test_path_validation.py:95:32:95:34 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| test_path_validation.py:97:32:97:34 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| test_path_validation.py:100:32:100:34 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| test_path_validation.py:102:32:102:34 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| test_path_validation.py:105:32:105:34 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| test_path_validation.py:107:32:107:34 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| test_path_validation.py:110:32:110:34 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| test_path_validation.py:112:32:112:34 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| test_path_validation.py:115:32:115:34 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| test_path_validation.py:117:32:117:34 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| test_path_validation.py:120:32:120:34 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| test_path_validation.py:122:32:122:34 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| test_path_validation.py:125:32:125:34 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| test_path_validation.py:127:32:127:34 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| test_path_validation.py:130:32:130:34 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | +| test_path_validation.py:132:32:132:34 | ControlFlowNode for url | semmle.label | ControlFlowNode for url | | test_requests.py:1:19:1:25 | ControlFlowNode for ImportMember | semmle.label | ControlFlowNode for ImportMember | | test_requests.py:1:19:1:25 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | | test_requests.py:7:5:7:14 | ControlFlowNode for user_input | semmle.label | ControlFlowNode for user_input | @@ -414,5 +414,3 @@ nodes | test_requests.py:20:18:20:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | | test_requests.py:22:45:22:54 | ControlFlowNode for user_input | semmle.label | ControlFlowNode for user_input | subpaths -testFailures -| test_requests.py:1:27:1:36 | Comment # $ Source | Missing result: Source | 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 e2f4fc05026..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,6 +1,6 @@ from flask import request # $ Source -import requests +import requests import re def full_ssrf(): @@ -122,7 +122,7 @@ def partial_ssrf_4(): user_input = request.args['untrusted_input'] url = "https://example.com/foo#{}".format(user_input) - # NOT OK -- user contollred fragment + # NOT OK -- user controlled fragment requests.get(url) # $ Alert[py/partial-ssrf] def partial_ssrf_5(): @@ -132,7 +132,7 @@ def partial_ssrf_5(): # controlled url = "https://example.com/foo#%s" % user_input - # NOT OK -- user contollred fragment + # NOT OK -- user controlled fragment requests.get(url) # $ Alert[py/partial-ssrf] def partial_ssrf_6(): 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 5dbb7e1ede4..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 @@ -12,14 +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) # $ Alert[py/partial-ssrf] - c = SecretClient(vault_url=full_url, credential=credential) # $ Alert[py/full-ssrf] - c = ShareFileClient.from_file_url(url) # $ Alert[py/partial-ssrf] - c = ShareFileClient.from_file_url(full_url) # $ Alert[py/full-ssrf] - c = KeyClient(url, credential) # $ Alert[py/partial-ssrf] - c = KeyClient(full_url, credential) # $ Alert[py/full-ssrf] - c = ContainerClient.from_container_url(container_url=url, credential=credential) # $ Alert[py/partial-ssrf] - c = ContainerClient.from_container_url(container_url=full_url, credential=credential) # $ Alert[py/full-ssrf] + 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, 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 0a238878e35..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 @@ -14,7 +14,7 @@ def ssrf_test(): # 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) # $ Sink # NOT OK -- user has full control 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 index 4560479d2b3..ce5a6d33833 100644 --- 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 @@ -11,14 +11,14 @@ def urivalidator_path_in_domain_validation(credential, trusted_domain): full_url = f"https://{user_input2}" if URIValidator.in_domain(url, trusted_domain): - c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/partial-ssrf] + SecretClient(vault_url=url, credential=credential) # $ Alert[py/partial-ssrf] else: - c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/partial-ssrf] + SecretClient(vault_url=url, credential=credential) # $ Alert[py/partial-ssrf] if URIValidator.in_domain(full_url, trusted_domain): - c = SecretClient(vault_url=full_url, credential=credential) # $ Alert[py/partial-ssrf] + SecretClient(vault_url=full_url, credential=credential) # $ Alert[py/partial-ssrf] else: - c = SecretClient(vault_url=full_url, credential=credential) # $ Alert[py/full-ssrf] + 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'] @@ -27,14 +27,14 @@ def urivalidator_path_in_azure_keyvault_domain_validation(credential): full_url = f"https://{user_input2}" if URIValidator.in_azure_keyvault_domain(url): - c = KeyClient(vault_url=url, credential=credential) # $ Alert[py/partial-ssrf] + KeyClient(vault_url=url, credential=credential) # $ Alert[py/partial-ssrf] else: - c = KeyClient(vault_url=url, credential=credential) # $ Alert[py/partial-ssrf] + KeyClient(vault_url=url, credential=credential) # $ Alert[py/partial-ssrf] if URIValidator.in_azure_keyvault_domain(full_url): - c = KeyClient(vault_url=full_url, credential=credential) # $ Alert[py/partial-ssrf] + KeyClient(vault_url=full_url, credential=credential) # $ Alert[py/partial-ssrf] else: - c = KeyClient(vault_url=full_url, credential=credential) # $ Alert[py/full-ssrf] + 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'] @@ -43,14 +43,14 @@ def urivalidator_path_in_azure_storage_domain_validation(credential): full_url = f"https://{user_input2}" if URIValidator.in_azure_storage_domain(url): - c = ShareFileClient.from_file_url(url) # $ Alert[py/partial-ssrf] + ShareFileClient.from_file_url(url) # $ Alert[py/partial-ssrf] else: - c = ShareFileClient.from_file_url(url) # $ Alert[py/partial-ssrf] + ShareFileClient.from_file_url(url) # $ Alert[py/partial-ssrf] if URIValidator.in_azure_storage_domain(full_url): - c = ShareFileClient.from_file_url(full_url) # $ Alert[py/partial-ssrf] + ShareFileClient.from_file_url(full_url) # $ Alert[py/partial-ssrf] else: - c = ShareFileClient.from_file_url(full_url) # $ Alert[py/full-ssrf] + ShareFileClient.from_file_url(full_url) # $ Alert[py/full-ssrf] def complex_urivalidator_checks(credential, trusted_domain): @@ -61,72 +61,72 @@ def complex_urivalidator_checks(credential, trusted_domain): url = f"https://{user_input}" if not URIValidator.in_domain(url, trusted_domain): - c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/full-ssrf] + SecretClient(vault_url=url, credential=credential) # $ Alert[py/full-ssrf] else: - c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/partial-ssrf] + SecretClient(vault_url=url, credential=credential) # $ Alert[py/partial-ssrf] if URIValidator.in_domain(url, trusted_domain) and trusted_domain == "example.com": - c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/partial-ssrf] + SecretClient(vault_url=url, credential=credential) # $ Alert[py/partial-ssrf] else: - c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/full-ssrf] + SecretClient(vault_url=url, credential=credential) # $ Alert[py/full-ssrf] if not (URIValidator.in_domain(url, trusted_domain) and trusted_domain == "example.com"): - c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/full-ssrf] + SecretClient(vault_url=url, credential=credential) # $ Alert[py/full-ssrf] else: - c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/partial-ssrf] + SecretClient(vault_url=url, credential=credential) # $ Alert[py/partial-ssrf] if not not not URIValidator.in_domain(url, trusted_domain): - c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/full-ssrf] + SecretClient(vault_url=url, credential=credential) # $ Alert[py/full-ssrf] else: - c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/partial-ssrf] + SecretClient(vault_url=url, credential=credential) # $ Alert[py/partial-ssrf] if URIValidator.in_domain(url, trusted_domain) == True: - c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/partial-ssrf] + SecretClient(vault_url=url, credential=credential) # $ Alert[py/partial-ssrf] else: - c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/full-ssrf] + SecretClient(vault_url=url, credential=credential) # $ Alert[py/full-ssrf] if URIValidator.in_domain(url, trusted_domain) == False: - c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/full-ssrf] + SecretClient(vault_url=url, credential=credential) # $ Alert[py/full-ssrf] else: - c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/partial-ssrf] + SecretClient(vault_url=url, credential=credential) # $ Alert[py/partial-ssrf] if URIValidator.in_domain(url, trusted_domain) != True: - c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/full-ssrf] + SecretClient(vault_url=url, credential=credential) # $ Alert[py/full-ssrf] else: - c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/partial-ssrf] + SecretClient(vault_url=url, credential=credential) # $ Alert[py/partial-ssrf] if URIValidator.in_domain(url, trusted_domain) != False: - c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/partial-ssrf] + SecretClient(vault_url=url, credential=credential) # $ Alert[py/partial-ssrf] else: - c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/full-ssrf] + SecretClient(vault_url=url, credential=credential) # $ Alert[py/full-ssrf] if URIValidator.in_domain(url, trusted_domain) is True: - c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/partial-ssrf] + SecretClient(vault_url=url, credential=credential) # $ Alert[py/partial-ssrf] else: - c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/full-ssrf] + SecretClient(vault_url=url, credential=credential) # $ Alert[py/full-ssrf] if URIValidator.in_domain(url, trusted_domain) is False: - c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/full-ssrf] + SecretClient(vault_url=url, credential=credential) # $ Alert[py/full-ssrf] else: - c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/partial-ssrf] + SecretClient(vault_url=url, credential=credential) # $ Alert[py/partial-ssrf] if URIValidator.in_domain(url, trusted_domain) is not True: - c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/full-ssrf] + SecretClient(vault_url=url, credential=credential) # $ Alert[py/full-ssrf] else: - c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/partial-ssrf] + SecretClient(vault_url=url, credential=credential) # $ Alert[py/partial-ssrf] if URIValidator.in_domain(url, trusted_domain) is not False: - c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/partial-ssrf] + SecretClient(vault_url=url, credential=credential) # $ Alert[py/partial-ssrf] else: - c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/full-ssrf] + SecretClient(vault_url=url, credential=credential) # $ Alert[py/full-ssrf] if not URIValidator.in_domain(url, trusted_domain) is True: - c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/full-ssrf] + SecretClient(vault_url=url, credential=credential) # $ Alert[py/full-ssrf] else: - c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/partial-ssrf] + SecretClient(vault_url=url, credential=credential) # $ Alert[py/partial-ssrf] if not URIValidator.in_domain(url, trusted_domain) is False: - c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/partial-ssrf] + SecretClient(vault_url=url, credential=credential) # $ Alert[py/partial-ssrf] else: - c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/full-ssrf] \ No newline at end of file + 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 cfa2e6aa5a7..fa5da6cef49 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,4 +1,4 @@ -from flask import request # $ Source +from flask import request # $ Source[py/full-ssrf] from AntiSSRF import AntiSSRFPolicy import requests @@ -36,7 +36,8 @@ def ssrf_test_with_policy2(): # this makes the session unsafe again session.mount("http://", requests.adapters.HTTPAdapter()) # NOT OK -- dangerous user input is no longer filtered by AntiSSRFPolicy - response = session.get(user_input) # $ Alert[py/full-ssrf] + # 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'] @@ -46,4 +47,5 @@ def ssrf_test_with_policy3(adapter): # this could make the session unsafe again session.mount("http://", adapter) # NOT OK -- dangerous user input is no longer filtered by AntiSSRFPolicy - response = session.get(user_input) # $ Alert[py/full-ssrf] \ No newline at end of file + # TODO: not currently a scenario we detect. + session.get(user_input) # $ MISSING: Alert[py/full-ssrf] \ No newline at end of file From 4bb110beb87256fdef01f122b2bf9f8c7d254b70 Mon Sep 17 00:00:00 2001 From: "REDMOND\\brodes" Date: Tue, 10 Feb 2026 11:46:16 -0500 Subject: [PATCH 18/22] More copilot suggestions. --- .../CWE-918-ServerSideRequestForgery/test_requests.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 fa5da6cef49..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 @@ -19,14 +19,14 @@ def ssrf_test2(): def ssrf_test3(): user_input = request.args['untrusted_input'] # NOT OK -- user has full control - response = requests.request('', user_input) # $ Alert[py/full-ssrf] + 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 - response = session.get(user_input) + session.get(user_input) def ssrf_test_with_policy2(): user_input = request.args['untrusted_input'] From 9f9c353806ae05361c5bf4515036e722f89b4176 Mon Sep 17 00:00:00 2001 From: "REDMOND\\brodes" Date: Tue, 10 Feb 2026 11:47:23 -0500 Subject: [PATCH 19/22] Update expected files. Copilot suggestions broke unit test expected results (column numbers). --- .../FullServerSideRequestForgery.expected | 6 +++--- .../PartialServerSideRequestForgery.expected | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) 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 cb46c54ca70..c2fd16bfab7 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 @@ -41,7 +41,7 @@ | 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:16:22:55 | ControlFlowNode for Attribute() | test_requests.py:1:19:1:25 | ControlFlowNode for ImportMember | test_requests.py:22:45:22:54 | 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 | | @@ -146,7 +146,7 @@ edges | 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:45:22:54 | ControlFlowNode for user_input | provenance | | +| 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 | nodes | full_partial_test.py:1:19:1:25 | ControlFlowNode for ImportMember | semmle.label | ControlFlowNode for ImportMember | @@ -253,5 +253,5 @@ nodes | 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:45:22:54 | ControlFlowNode for user_input | semmle.label | ControlFlowNode for user_input | +| test_requests.py:22:34:22:43 | ControlFlowNode for user_input | semmle.label | ControlFlowNode for user_input | subpaths diff --git a/python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/PartialServerSideRequestForgery.expected b/python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/PartialServerSideRequestForgery.expected index 314aa99ef60..8cc69590b7e 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 @@ -229,7 +229,7 @@ edges | 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:45:22:54 | ControlFlowNode for user_input | provenance | | +| 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 | nodes | full_partial_test.py:1:19:1:25 | ControlFlowNode for ImportMember | semmle.label | ControlFlowNode for ImportMember | @@ -412,5 +412,5 @@ nodes | 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:45:22:54 | ControlFlowNode for user_input | semmle.label | ControlFlowNode for user_input | +| test_requests.py:22:34:22:43 | ControlFlowNode for user_input | semmle.label | ControlFlowNode for user_input | subpaths From 4d4e7a1b5c21badf976d5647c34aae8eac49908d Mon Sep 17 00:00:00 2001 From: "REDMOND\\brodes" Date: Thu, 12 Feb 2026 08:28:08 -0500 Subject: [PATCH 20/22] Pretty print for tests. --- .../FullServerSideRequestForgery.expected | 50 +++++---- .../FullServerSideRequestForgery.qlref | 4 +- .../PartialServerSideRequestForgery.expected | 106 +++++++++--------- .../PartialServerSideRequestForgery.qlref | 4 +- 4 files changed, 90 insertions(+), 74 deletions(-) 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 c2fd16bfab7..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 @@ -85,11 +85,11 @@ edges | 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:15 | -| 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:38 | -| 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:14 | -| 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:26 | -| 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:27 | +| 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 | | @@ -113,31 +113,31 @@ edges | 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:15 | +| 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:14 | +| 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:38 | +| 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:15 | -| 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:15 | -| 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:15 | -| 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:15 | -| 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:15 | -| 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:15 | -| 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:15 | -| 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:15 | -| 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:15 | -| 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:15 | -| 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:15 | -| 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:15 | -| 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:15 | -| 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:15 | +| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:64:32:64:34 | ControlFlowNode for url | provenance | Sink:MaD:2 | +| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:71:32:71:34 | ControlFlowNode for url | provenance | Sink:MaD:2 | +| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:74:32:74:34 | ControlFlowNode for url | provenance | Sink:MaD:2 | +| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:79:32:79:34 | ControlFlowNode for url | provenance | Sink:MaD:2 | +| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:87:32:87:34 | ControlFlowNode for url | provenance | Sink:MaD:2 | +| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:90:32:90:34 | ControlFlowNode for url | provenance | Sink:MaD:2 | +| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:95:32:95:34 | ControlFlowNode for url | provenance | Sink:MaD:2 | +| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:102:32:102:34 | ControlFlowNode for url | provenance | Sink:MaD:2 | +| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:107:32:107:34 | ControlFlowNode for url | provenance | Sink:MaD:2 | +| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:110:32:110:34 | ControlFlowNode for url | provenance | Sink:MaD:2 | +| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:115:32:115:34 | ControlFlowNode for url | provenance | Sink:MaD:2 | +| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:122:32:122:34 | ControlFlowNode for url | provenance | Sink:MaD:2 | +| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:125:32:125:34 | ControlFlowNode for url | provenance | Sink:MaD:2 | +| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:132:32:132:34 | ControlFlowNode for url | provenance | Sink:MaD:2 | | test_requests.py:1:19:1:25 | ControlFlowNode for ImportMember | test_requests.py:1:19:1:25 | ControlFlowNode for request | provenance | | | test_requests.py:1:19:1:25 | ControlFlowNode for request | test_requests.py:7:18:7:24 | ControlFlowNode for request | provenance | | | test_requests.py:1:19:1:25 | ControlFlowNode for request | test_requests.py:14:18:14:24 | ControlFlowNode for request | provenance | | @@ -148,6 +148,12 @@ edges | 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 | 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 35a2814e7f4..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,2 +1,4 @@ query: Security/CWE-918/FullServerSideRequestForgery.ql -postprocess: utils/test/InlineExpectationsTestQuery.ql \ No newline at end of file +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 8cc69590b7e..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 @@ -126,16 +126,16 @@ edges | 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:15 | -| 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:38 | -| 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:14 | -| 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:26 | -| 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:27 | -| 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:15 | -| 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:38 | -| 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:14 | -| 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:26 | -| 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:27 | +| 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 | | @@ -169,58 +169,58 @@ edges | 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:15 | -| 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:15 | -| 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:15 | -| 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:15 | +| 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:14 | -| 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:14 | -| 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:14 | -| 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:14 | +| 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:38 | -| 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:38 | -| 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:38 | -| 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:38 | +| 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:15 | -| 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:15 | -| 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:15 | -| 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:15 | -| 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:15 | -| 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:15 | -| 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:15 | -| 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:15 | -| 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:15 | -| 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:15 | -| 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:15 | -| 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:15 | -| 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:15 | -| 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:15 | -| 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:15 | -| 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:15 | -| 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:15 | -| 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:15 | -| 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:15 | -| 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:15 | -| 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:15 | -| 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:15 | -| 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:15 | -| 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:15 | -| 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:15 | -| 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:15 | -| 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:15 | -| 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:15 | +| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:64:32:64:34 | ControlFlowNode for url | provenance | Sink:MaD:2 | +| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:66:32:66:34 | ControlFlowNode for url | provenance | Sink:MaD:2 | +| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:69:32:69:34 | ControlFlowNode for url | provenance | Sink:MaD:2 | +| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:71:32:71:34 | ControlFlowNode for url | provenance | Sink:MaD:2 | +| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:74:32:74:34 | ControlFlowNode for url | provenance | Sink:MaD:2 | +| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:76:32:76:34 | ControlFlowNode for url | provenance | Sink:MaD:2 | +| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:79:32:79:34 | ControlFlowNode for url | provenance | Sink:MaD:2 | +| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:81:32:81:34 | ControlFlowNode for url | provenance | Sink:MaD:2 | +| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:85:32:85:34 | ControlFlowNode for url | provenance | Sink:MaD:2 | +| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:87:32:87:34 | ControlFlowNode for url | provenance | Sink:MaD:2 | +| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:90:32:90:34 | ControlFlowNode for url | provenance | Sink:MaD:2 | +| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:92:32:92:34 | ControlFlowNode for url | provenance | Sink:MaD:2 | +| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:95:32:95:34 | ControlFlowNode for url | provenance | Sink:MaD:2 | +| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:97:32:97:34 | ControlFlowNode for url | provenance | Sink:MaD:2 | +| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:100:32:100:34 | ControlFlowNode for url | provenance | Sink:MaD:2 | +| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:102:32:102:34 | ControlFlowNode for url | provenance | Sink:MaD:2 | +| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:105:32:105:34 | ControlFlowNode for url | provenance | Sink:MaD:2 | +| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:107:32:107:34 | ControlFlowNode for url | provenance | Sink:MaD:2 | +| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:110:32:110:34 | ControlFlowNode for url | provenance | Sink:MaD:2 | +| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:112:32:112:34 | ControlFlowNode for url | provenance | Sink:MaD:2 | +| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:115:32:115:34 | ControlFlowNode for url | provenance | Sink:MaD:2 | +| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:117:32:117:34 | ControlFlowNode for url | provenance | Sink:MaD:2 | +| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:120:32:120:34 | ControlFlowNode for url | provenance | Sink:MaD:2 | +| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:122:32:122:34 | ControlFlowNode for url | provenance | Sink:MaD:2 | +| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:125:32:125:34 | ControlFlowNode for url | provenance | Sink:MaD:2 | +| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:127:32:127:34 | ControlFlowNode for url | provenance | Sink:MaD:2 | +| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:130:32:130:34 | ControlFlowNode for url | provenance | Sink:MaD:2 | +| test_path_validation.py:61:5:61:7 | ControlFlowNode for url | test_path_validation.py:132:32:132:34 | ControlFlowNode for url | provenance | Sink:MaD:2 | | test_requests.py:1:19:1:25 | ControlFlowNode for ImportMember | test_requests.py:1:19:1:25 | ControlFlowNode for request | provenance | | | test_requests.py:1:19:1:25 | ControlFlowNode for request | test_requests.py:7:18:7:24 | ControlFlowNode for request | provenance | | | test_requests.py:1:19:1:25 | ControlFlowNode for request | test_requests.py:14:18:14:24 | ControlFlowNode for request | provenance | | @@ -231,6 +231,12 @@ edges | 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 | 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 651b07aea55..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,2 +1,4 @@ query: Security/CWE-918/PartialServerSideRequestForgery.ql -postprocess: utils/test/InlineExpectationsTestQuery.ql \ No newline at end of file +postprocess: +- utils/test/InlineExpectationsTestQuery.ql +- utils/test/PrettyPrintModels.ql \ No newline at end of file From ceb3b21e0f2e27f7cf2926fa235c286eea34c1e9 Mon Sep 17 00:00:00 2001 From: Ben Rodes Date: Tue, 17 Feb 2026 10:28:43 -0500 Subject: [PATCH 21/22] Update python/ql/lib/semmle/python/security/dataflow/ServerSideRequestForgeryCustomizations.qll Co-authored-by: Taus --- ...ServerSideRequestForgeryCustomizations.qll | 46 +++++++------------ 1 file changed, 17 insertions(+), 29 deletions(-) diff --git a/python/ql/lib/semmle/python/security/dataflow/ServerSideRequestForgeryCustomizations.qll b/python/ql/lib/semmle/python/security/dataflow/ServerSideRequestForgeryCustomizations.qll index afce799d8ac..3fb260e425d 100644 --- a/python/ql/lib/semmle/python/security/dataflow/ServerSideRequestForgeryCustomizations.qll +++ b/python/ql/lib/semmle/python/security/dataflow/ServerSideRequestForgeryCustomizations.qll @@ -186,37 +186,25 @@ module ServerSideRequestForgery { 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"] - | + 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 and - ( - // validator used in a comparison - exists(CompareNode cn, Cmpop op, Node n | cn = g and n.getALocalSource() = call | - ( - // validator == true or validator == false or validator is True or validator is False - (op instanceof Eq or op instanceof Is) and - exists(ControlFlowNode l, boolean bool | - l.getNode().(BooleanLiteral).booleanValue() = bool and - bool in [true, false] and - branch = bool and - cn.operands(n.asCfgNode(), op, l) - ) - or - // validator != false or validator != true or validator is not True or validator is not False - (op instanceof NotEq or op instanceof IsNot) and - exists(ControlFlowNode l, boolean bool | - l.getNode().(BooleanLiteral).booleanValue() = bool and - bool in [true, false] and - branch = bool.booleanNot() and - cn.operands(n.asCfgNode(), op, l) - ) - ) - ) + 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 call directly (e.g., if URIValidator.in_domain(...) ) - g = call.asCfgNode() and - branch = true + // 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() ) ) } From a1eaf42cbf5fd1ee9695db7c6423e48d6bd19f0c Mon Sep 17 00:00:00 2001 From: Ben Rodes Date: Tue, 17 Feb 2026 13:05:51 -0500 Subject: [PATCH 22/22] Update python/ql/lib/change-notes/2026-02-09-ssrf_test_case_cleanup_and_new_ssrf_barriers.md Co-authored-by: Owen Mansel-Chan <62447351+owen-mc@users.noreply.github.com> --- .../2026-02-09-ssrf_test_case_cleanup_and_new_ssrf_barriers.md | 1 - 1 file changed, 1 deletion(-) 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 index d4373eadfb2..c3b4194e7b8 100644 --- 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 @@ -1,5 +1,4 @@ --- category: minorAnalysis --- -* Modified SSRF tests to use postprocessing to more easily debug results. * Added new full SSRF sanitization barrier from the new AntiSSRF library. \ No newline at end of file