Date: Fri, 9 Apr 2021 21:31:45 +0200
Subject: [PATCH 037/429] Polish qhelp and examples
---
.../experimental/Security/CWE-943/NoSQLInjection.qhelp | 9 ++++-----
.../NoSQLInjection-bad.py} | 0
.../NoSQLInjection-good.py} | 0
3 files changed, 4 insertions(+), 5 deletions(-)
rename python/ql/src/experimental/Security/CWE-943/{NoSQLInjection-Bad.py => examples/NoSQLInjection-bad.py} (100%)
rename python/ql/src/experimental/Security/CWE-943/{NoSQLInjection-Good.py => examples/NoSQLInjection-good.py} (100%)
diff --git a/python/ql/src/experimental/Security/CWE-943/NoSQLInjection.qhelp b/python/ql/src/experimental/Security/CWE-943/NoSQLInjection.qhelp
index b11587901af..339fc5d9d14 100644
--- a/python/ql/src/experimental/Security/CWE-943/NoSQLInjection.qhelp
+++ b/python/ql/src/experimental/Security/CWE-943/NoSQLInjection.qhelp
@@ -9,7 +9,6 @@
This tainted NoSQL query containing a user-controlled source can then execute a malicious query in a NoSQL database such as MongoDB.
In order for the user-controlled source to taint the NoSQL query, the user-controller source must be converted into a Python object using something like json.loads or xmltodict.parse.
-
Because a user-controlled source is passed into the query, the malicious user can have complete control over the query itself.
When the tainted query is executed, the malicious user can commit malicious actions such as bypassing role restrictions or accessing and modifying restricted data in the NoSQL database.
@@ -25,13 +24,13 @@
In the example below, the user-supplied source is passed to a MongoDB function that queries the MongoDB database.
-
+
This can be fixed by using a sanitizer library like MongoSanitizer as shown in this annotated code version below.
-
+
- OWASP: NoSQL Injection
- Security Stack Exchange Discussion: Question 83231
+ OWASP: NoSQL Injection.
+ Security Stack Exchange Discussion: Question 83231.
diff --git a/python/ql/src/experimental/Security/CWE-943/NoSQLInjection-Bad.py b/python/ql/src/experimental/Security/CWE-943/examples/NoSQLInjection-bad.py
similarity index 100%
rename from python/ql/src/experimental/Security/CWE-943/NoSQLInjection-Bad.py
rename to python/ql/src/experimental/Security/CWE-943/examples/NoSQLInjection-bad.py
diff --git a/python/ql/src/experimental/Security/CWE-943/NoSQLInjection-Good.py b/python/ql/src/experimental/Security/CWE-943/examples/NoSQLInjection-good.py
similarity index 100%
rename from python/ql/src/experimental/Security/CWE-943/NoSQLInjection-Good.py
rename to python/ql/src/experimental/Security/CWE-943/examples/NoSQLInjection-good.py
From 983af32ab525b909ee6f9bf668c007f71af8c7ed Mon Sep 17 00:00:00 2001
From: jorgectf
Date: Fri, 9 Apr 2021 21:36:11 +0200
Subject: [PATCH 038/429] Polish qhelp examples
---
.../CWE-943/examples/NoSQLInjection-bad.py | 10 ++++------
.../CWE-943/examples/NoSQLInjection-good.py | 15 +++++++++++----
2 files changed, 15 insertions(+), 10 deletions(-)
diff --git a/python/ql/src/experimental/Security/CWE-943/examples/NoSQLInjection-bad.py b/python/ql/src/experimental/Security/CWE-943/examples/NoSQLInjection-bad.py
index 0b7abf0740e..f0071201969 100644
--- a/python/ql/src/experimental/Security/CWE-943/examples/NoSQLInjection-bad.py
+++ b/python/ql/src/experimental/Security/CWE-943/examples/NoSQLInjection-bad.py
@@ -2,14 +2,12 @@ from flask import Flask, request
from flask_pymongo import PyMongo
import json
-app = Flask(__name__)
-app.config["MONGO_URI"] = "mongodb://localhost:27017/testdb"
mongo = PyMongo(app)
@app.route("/")
def home_page():
- unsanitized_search = json.loads(request.args['search'])
-
- db_results = mongo.db.user.find({'name': unsanitized_search})
- return db_results[0].keys()
+ unsanitized_search = request.args['search']
+ json_search = json.loads(unsanitized_search)
+
+ result = mongo.db.user.find({'name': json_search})
diff --git a/python/ql/src/experimental/Security/CWE-943/examples/NoSQLInjection-good.py b/python/ql/src/experimental/Security/CWE-943/examples/NoSQLInjection-good.py
index 96f1db06fce..8aed7386f8e 100644
--- a/python/ql/src/experimental/Security/CWE-943/examples/NoSQLInjection-good.py
+++ b/python/ql/src/experimental/Security/CWE-943/examples/NoSQLInjection-good.py
@@ -1,8 +1,15 @@
-# Annotated version
+from flask import Flask, request
+from flask_pymongo import PyMongo
from mongosanitizer.sanitizer import sanitize
+import json
-unsanitized_search = json.loads(request.args['search'])
+mongo = PyMongo(app)
-sanitize(unsanitized_search)
-db_results = mongo.db.user.find({'name': unsanitized_search})
+@app.route("/")
+def home_page():
+ unsafe_search = request.args['search']
+ json_search = json.loads(unsafe_search)
+ safe_search = sanitize(unsanitized_search)
+
+ result = client.db.collection.find_one({'data': safe_search})
From 208b53e4d2d9d98b16ce955b2c6074489dd1c766 Mon Sep 17 00:00:00 2001
From: jorgectf
Date: Fri, 9 Apr 2021 21:36:21 +0200
Subject: [PATCH 039/429] Polish query file
---
python/ql/src/experimental/Security/CWE-943/NoSQLInjection.ql | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/python/ql/src/experimental/Security/CWE-943/NoSQLInjection.ql b/python/ql/src/experimental/Security/CWE-943/NoSQLInjection.ql
index c3310379e81..cd3909494f3 100644
--- a/python/ql/src/experimental/Security/CWE-943/NoSQLInjection.ql
+++ b/python/ql/src/experimental/Security/CWE-943/NoSQLInjection.ql
@@ -4,7 +4,7 @@
* malicious NoSQL code by the user.
* @kind path-problem
* @problem.severity error
- * @id python/nosql-injection
+ * @id py/nosql-injection
* @tags experimental
* security
* external/cwe/cwe-943
From 166385755afacd7a069db68bcbcd62421ce44a47 Mon Sep 17 00:00:00 2001
From: jorgectf
Date: Fri, 9 Apr 2021 21:49:41 +0200
Subject: [PATCH 040/429] Polish Calls naming
---
.../ql/src/experimental/semmle/python/frameworks/Stdlib.qll | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/python/ql/src/experimental/semmle/python/frameworks/Stdlib.qll b/python/ql/src/experimental/semmle/python/frameworks/Stdlib.qll
index 6ffbf80b5a5..11f1a5758d5 100644
--- a/python/ql/src/experimental/semmle/python/frameworks/Stdlib.qll
+++ b/python/ql/src/experimental/semmle/python/frameworks/Stdlib.qll
@@ -28,7 +28,7 @@ private module NoSQL {
.getMember("MongoClient")
.getReturn()
.getAMember*()
- .getMember(any(PyMongoMethods pyMongoMethods))
+ .getMember(any(PyMongoMethods pyMongoMethod))
.getACall()
}
@@ -36,7 +36,7 @@ private module NoSQL {
}
private class PyMongoFlaskMethods extends string {
- PyMongoFlaskMethods() { this in ["find_one_or_404"] or this instanceof PyMongoMethods }
+ PyMongoFlaskMethods() { this in ["find_one_or_404", any(PyMongoMethods pyMongoMethod)] }
}
private class PyMongoFlaskCall extends DataFlow::CallCfgNode, NoSQLQuery::Range {
@@ -46,7 +46,7 @@ private module NoSQL {
.getMember("PyMongo")
.getReturn()
.getAMember*()
- .getMember(any(PyMongoFlaskMethods pyMongoFlaskMethods))
+ .getMember(any(PyMongoFlaskMethods pyMongoFlaskMethod))
.getACall()
}
From 4615927eeb2efc2c537278575fe254ba7ad73153 Mon Sep 17 00:00:00 2001
From: jorgectf
Date: Fri, 9 Apr 2021 22:27:53 +0200
Subject: [PATCH 041/429] Fix flask_mongoengine Call
---
.../semmle/python/frameworks/Stdlib.qll | 21 ++++++++++++++-----
1 file changed, 16 insertions(+), 5 deletions(-)
diff --git a/python/ql/src/experimental/semmle/python/frameworks/Stdlib.qll b/python/ql/src/experimental/semmle/python/frameworks/Stdlib.qll
index 11f1a5758d5..dc13a50b8dc 100644
--- a/python/ql/src/experimental/semmle/python/frameworks/Stdlib.qll
+++ b/python/ql/src/experimental/semmle/python/frameworks/Stdlib.qll
@@ -53,14 +53,25 @@ private module NoSQL {
override DataFlow::Node getQueryNode() { result = this.getArg(0) }
}
- private class MongoEngineMethods extends string {
- MongoEngineMethods() { this in ["mongoengine", "flask_mongoengine"] }
- }
-
private class MongoEngineObjectsCall extends DataFlow::CallCfgNode, NoSQLQuery::Range {
MongoEngineObjectsCall() {
this =
- API::moduleImport(any(MongoEngineMethods mongoEngineMethod))
+ API::moduleImport("mongoengine")
+ .getMember("Document")
+ .getASubclass()
+ .getMember("objects")
+ .getACall()
+ }
+
+ override DataFlow::Node getQueryNode() { result = this.getArgByName(any(string name)) }
+ }
+
+ private class MongoEngineObjectsFlaskCall extends DataFlow::CallCfgNode, NoSQLQuery::Range {
+ MongoEngineObjectsFlaskCall() {
+ this =
+ API::moduleImport("flask_mongoengine")
+ .getMember("MongoEngine")
+ .getReturn()
.getMember("Document")
.getASubclass()
.getMember("objects")
From 5d25a27d62e07d00e00bed0e5e3f3701d9642c78 Mon Sep 17 00:00:00 2001
From: jorgectf
Date: Fri, 9 Apr 2021 22:28:03 +0200
Subject: [PATCH 042/429] Add .expected
---
.../Security/CWE-943/NoSQLInjection.expected | 71 +++++++++++++++++++
1 file changed, 71 insertions(+)
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/NoSQLInjection.expected b/python/ql/test/experimental/query-tests/Security/CWE-943/NoSQLInjection.expected
index e69de29bb2d..9135d887e31 100644
--- a/python/ql/test/experimental/query-tests/Security/CWE-943/NoSQLInjection.expected
+++ b/python/ql/test/experimental/query-tests/Security/CWE-943/NoSQLInjection.expected
@@ -0,0 +1,71 @@
+edges
+| flask_mongoengine_bad.py:24:26:24:32 | ControlFlowNode for request | flask_mongoengine_bad.py:24:26:24:37 | ControlFlowNode for Attribute |
+| flask_mongoengine_bad.py:24:26:24:37 | ControlFlowNode for Attribute | flask_mongoengine_bad.py:24:26:24:47 | ControlFlowNode for Subscript |
+| flask_mongoengine_bad.py:24:26:24:47 | ControlFlowNode for Subscript | flask_mongoengine_bad.py:25:30:25:47 | ControlFlowNode for unsanitized_search |
+| flask_mongoengine_bad.py:25:30:25:47 | ControlFlowNode for unsanitized_search | flask_mongoengine_bad.py:27:36:27:46 | ControlFlowNode for json_search |
+| flask_mongoengine_good.py:25:21:25:27 | ControlFlowNode for request | flask_mongoengine_good.py:25:21:25:32 | ControlFlowNode for Attribute |
+| flask_mongoengine_good.py:25:21:25:32 | ControlFlowNode for Attribute | flask_mongoengine_good.py:25:21:25:42 | ControlFlowNode for Subscript |
+| flask_mongoengine_good.py:25:21:25:42 | ControlFlowNode for Subscript | flask_mongoengine_good.py:26:30:26:42 | ControlFlowNode for unsafe_search |
+| flask_pymongo_bad.py:11:26:11:32 | ControlFlowNode for request | flask_pymongo_bad.py:11:26:11:37 | ControlFlowNode for Attribute |
+| flask_pymongo_bad.py:11:26:11:37 | ControlFlowNode for Attribute | flask_pymongo_bad.py:11:26:11:47 | ControlFlowNode for Subscript |
+| flask_pymongo_bad.py:11:26:11:47 | ControlFlowNode for Subscript | flask_pymongo_bad.py:12:30:12:47 | ControlFlowNode for unsanitized_search |
+| flask_pymongo_bad.py:12:30:12:47 | ControlFlowNode for unsanitized_search | flask_pymongo_bad.py:14:33:14:53 | ControlFlowNode for Dict |
+| flask_pymongo_good.py:12:21:12:27 | ControlFlowNode for request | flask_pymongo_good.py:12:21:12:32 | ControlFlowNode for Attribute |
+| flask_pymongo_good.py:12:21:12:32 | ControlFlowNode for Attribute | flask_pymongo_good.py:12:21:12:42 | ControlFlowNode for Subscript |
+| flask_pymongo_good.py:12:21:12:42 | ControlFlowNode for Subscript | flask_pymongo_good.py:13:30:13:42 | ControlFlowNode for unsafe_search |
+| mongoengine_bad.py:22:21:22:27 | ControlFlowNode for request | mongoengine_bad.py:22:21:22:32 | ControlFlowNode for Attribute |
+| mongoengine_bad.py:22:21:22:32 | ControlFlowNode for Attribute | mongoengine_bad.py:22:21:22:42 | ControlFlowNode for Subscript |
+| mongoengine_bad.py:22:21:22:42 | ControlFlowNode for Subscript | mongoengine_bad.py:23:30:23:42 | ControlFlowNode for unsafe_search |
+| mongoengine_bad.py:23:30:23:42 | ControlFlowNode for unsafe_search | mongoengine_bad.py:25:34:25:44 | ControlFlowNode for json_search |
+| mongoengine_good.py:23:21:23:27 | ControlFlowNode for request | mongoengine_good.py:23:21:23:32 | ControlFlowNode for Attribute |
+| mongoengine_good.py:23:21:23:32 | ControlFlowNode for Attribute | mongoengine_good.py:23:21:23:42 | ControlFlowNode for Subscript |
+| mongoengine_good.py:23:21:23:42 | ControlFlowNode for Subscript | mongoengine_good.py:24:30:24:42 | ControlFlowNode for unsafe_search |
+| pymongo_bad.py:11:21:11:27 | ControlFlowNode for request | pymongo_bad.py:11:21:11:32 | ControlFlowNode for Attribute |
+| pymongo_bad.py:11:21:11:32 | ControlFlowNode for Attribute | pymongo_bad.py:11:21:11:42 | ControlFlowNode for Subscript |
+| pymongo_bad.py:11:21:11:42 | ControlFlowNode for Subscript | pymongo_bad.py:12:30:12:42 | ControlFlowNode for unsafe_search |
+| pymongo_bad.py:12:30:12:42 | ControlFlowNode for unsafe_search | pymongo_bad.py:14:44:14:64 | ControlFlowNode for Dict |
+| pymongo_good.py:12:21:12:27 | ControlFlowNode for request | pymongo_good.py:12:21:12:32 | ControlFlowNode for Attribute |
+| pymongo_good.py:12:21:12:32 | ControlFlowNode for Attribute | pymongo_good.py:12:21:12:42 | ControlFlowNode for Subscript |
+| pymongo_good.py:12:21:12:42 | ControlFlowNode for Subscript | pymongo_good.py:13:30:13:42 | ControlFlowNode for unsafe_search |
+nodes
+| flask_mongoengine_bad.py:24:26:24:32 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
+| flask_mongoengine_bad.py:24:26:24:37 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
+| flask_mongoengine_bad.py:24:26:24:47 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
+| flask_mongoengine_bad.py:25:30:25:47 | ControlFlowNode for unsanitized_search | semmle.label | ControlFlowNode for unsanitized_search |
+| flask_mongoengine_bad.py:27:36:27:46 | ControlFlowNode for json_search | semmle.label | ControlFlowNode for json_search |
+| flask_mongoengine_good.py:25:21:25:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
+| flask_mongoengine_good.py:25:21:25:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
+| flask_mongoengine_good.py:25:21:25:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
+| flask_mongoengine_good.py:26:30:26:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search |
+| flask_pymongo_bad.py:11:26:11:32 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
+| flask_pymongo_bad.py:11:26:11:37 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
+| flask_pymongo_bad.py:11:26:11:47 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
+| flask_pymongo_bad.py:12:30:12:47 | ControlFlowNode for unsanitized_search | semmle.label | ControlFlowNode for unsanitized_search |
+| flask_pymongo_bad.py:14:33:14:53 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict |
+| flask_pymongo_good.py:12:21:12:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
+| flask_pymongo_good.py:12:21:12:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
+| flask_pymongo_good.py:12:21:12:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
+| flask_pymongo_good.py:13:30:13:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search |
+| mongoengine_bad.py:22:21:22:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
+| mongoengine_bad.py:22:21:22:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
+| mongoengine_bad.py:22:21:22:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
+| mongoengine_bad.py:23:30:23:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search |
+| mongoengine_bad.py:25:34:25:44 | ControlFlowNode for json_search | semmle.label | ControlFlowNode for json_search |
+| mongoengine_good.py:23:21:23:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
+| mongoengine_good.py:23:21:23:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
+| mongoengine_good.py:23:21:23:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
+| mongoengine_good.py:24:30:24:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search |
+| pymongo_bad.py:11:21:11:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
+| pymongo_bad.py:11:21:11:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
+| pymongo_bad.py:11:21:11:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
+| pymongo_bad.py:12:30:12:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search |
+| pymongo_bad.py:14:44:14:64 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict |
+| pymongo_good.py:12:21:12:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
+| pymongo_good.py:12:21:12:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
+| pymongo_good.py:12:21:12:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
+| pymongo_good.py:13:30:13:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search |
+#select
+| flask_mongoengine_bad.py:27:36:27:46 | ControlFlowNode for json_search | flask_mongoengine_bad.py:24:26:24:32 | ControlFlowNode for request | flask_mongoengine_bad.py:27:36:27:46 | ControlFlowNode for json_search | $@ NoSQL query contains an unsanitized $@ | flask_mongoengine_bad.py:27:36:27:46 | ControlFlowNode for json_search | This | flask_mongoengine_bad.py:24:26:24:32 | ControlFlowNode for request | user-provided value |
+| flask_pymongo_bad.py:14:33:14:53 | ControlFlowNode for Dict | flask_pymongo_bad.py:11:26:11:32 | ControlFlowNode for request | flask_pymongo_bad.py:14:33:14:53 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | flask_pymongo_bad.py:14:33:14:53 | ControlFlowNode for Dict | This | flask_pymongo_bad.py:11:26:11:32 | ControlFlowNode for request | user-provided value |
+| mongoengine_bad.py:25:34:25:44 | ControlFlowNode for json_search | mongoengine_bad.py:22:21:22:27 | ControlFlowNode for request | mongoengine_bad.py:25:34:25:44 | ControlFlowNode for json_search | $@ NoSQL query contains an unsanitized $@ | mongoengine_bad.py:25:34:25:44 | ControlFlowNode for json_search | This | mongoengine_bad.py:22:21:22:27 | ControlFlowNode for request | user-provided value |
+| pymongo_bad.py:14:44:14:64 | ControlFlowNode for Dict | pymongo_bad.py:11:21:11:27 | ControlFlowNode for request | pymongo_bad.py:14:44:14:64 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | pymongo_bad.py:14:44:14:64 | ControlFlowNode for Dict | This | pymongo_bad.py:11:21:11:27 | ControlFlowNode for request | user-provided value |
From a4fd70aa3d4b7dbccbbba601695dabc624012414 Mon Sep 17 00:00:00 2001
From: edvraa <80588099+edvraa@users.noreply.github.com>
Date: Wed, 14 Apr 2021 23:35:38 +0300
Subject: [PATCH 043/429] Use don't care expression
---
.../src/Security Features/CWE-502/UnsafeDeserialization.ql | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/csharp/ql/src/Security Features/CWE-502/UnsafeDeserialization.ql b/csharp/ql/src/Security Features/CWE-502/UnsafeDeserialization.ql
index 17438230099..252d2b25ddc 100644
--- a/csharp/ql/src/Security Features/CWE-502/UnsafeDeserialization.ql
+++ b/csharp/ql/src/Security Features/CWE-502/UnsafeDeserialization.ql
@@ -19,10 +19,9 @@ where
(
sink instanceof InstanceMethodSink and
not exists(
- SafeConstructorTrackingConfig safeConstructorTracking, DataFlow::PathNode safeCreation,
- DataFlow::PathNode safeTypeUsage
+ SafeConstructorTrackingConfig safeConstructorTracking, DataFlow::PathNode safeTypeUsage
|
- safeConstructorTracking.hasFlowPath(safeCreation, safeTypeUsage) and
+ safeConstructorTracking.hasFlowPath(_, safeTypeUsage) and
safeTypeUsage.getNode().asExpr().getParent() = deserializeCall
)
or
From 3a9d1f46fdb48a70aadec1da01ea2979646e6fa4 Mon Sep 17 00:00:00 2001
From: edvraa <80588099+edvraa@users.noreply.github.com>
Date: Thu, 15 Apr 2021 00:09:19 +0300
Subject: [PATCH 044/429] Hide implementation details
---
.../dataflow/UnsafeDeserialization.qll | 136 +++++++++---------
1 file changed, 68 insertions(+), 68 deletions(-)
diff --git a/csharp/ql/src/semmle/code/csharp/security/dataflow/UnsafeDeserialization.qll b/csharp/ql/src/semmle/code/csharp/security/dataflow/UnsafeDeserialization.qll
index f1486f14f77..ec16a6fc9c6 100644
--- a/csharp/ql/src/semmle/code/csharp/security/dataflow/UnsafeDeserialization.qll
+++ b/csharp/ql/src/semmle/code/csharp/security/dataflow/UnsafeDeserialization.qll
@@ -119,7 +119,7 @@ module UnsafeDeserialization {
}
/** BinaryFormatter */
- predicate isBinaryFormatterCall(MethodCall mc, Method m) {
+ private predicate isBinaryFormatterCall(MethodCall mc, Method m) {
m = mc.getTarget() and
(
m instanceof BinaryFormatterDeserializeMethod and
@@ -133,9 +133,9 @@ module UnsafeDeserialization {
)
}
- abstract class BinaryFormatterSink extends InstanceMethodSink { }
+ private abstract class BinaryFormatterSink extends InstanceMethodSink { }
- class BinaryFormatterDeserializeMethodSink extends BinaryFormatterSink {
+ private class BinaryFormatterDeserializeMethodSink extends BinaryFormatterSink {
BinaryFormatterDeserializeMethodSink() {
exists(MethodCall mc, Method m |
isBinaryFormatterCall(mc, m) and
@@ -145,15 +145,15 @@ module UnsafeDeserialization {
}
/** SoapFormatter */
- predicate isSoapFormatterCall(MethodCall mc, Method m) {
+ private predicate isSoapFormatterCall(MethodCall mc, Method m) {
m = mc.getTarget() and
m instanceof SoapFormatterDeserializeMethod and
not mc.getArgument(0).hasValue()
}
- abstract class SoapFormatterSink extends InstanceMethodSink { }
+ private abstract class SoapFormatterSink extends InstanceMethodSink { }
- class SoapFormatterDeserializeMethodSink extends SoapFormatterSink {
+ private class SoapFormatterDeserializeMethodSink extends SoapFormatterSink {
SoapFormatterDeserializeMethodSink() {
exists(MethodCall mc, Method m |
isSoapFormatterCall(mc, m) and
@@ -163,15 +163,15 @@ module UnsafeDeserialization {
}
/** ObjectStateFormatter */
- predicate isObjectStateFormatterCall(MethodCall mc, Method m) {
+ private predicate isObjectStateFormatterCall(MethodCall mc, Method m) {
m = mc.getTarget() and
m instanceof ObjectStateFormatterDeserializeMethod and
not mc.getArgument(0).hasValue()
}
- abstract class ObjectStateFormatterSink extends InstanceMethodSink { }
+ private abstract class ObjectStateFormatterSink extends InstanceMethodSink { }
- class ObjectStateFormatterDeserializeMethodSink extends ObjectStateFormatterSink {
+ private class ObjectStateFormatterDeserializeMethodSink extends ObjectStateFormatterSink {
ObjectStateFormatterDeserializeMethodSink() {
exists(MethodCall mc, Method m |
isObjectStateFormatterCall(mc, m) and
@@ -181,7 +181,7 @@ module UnsafeDeserialization {
}
/** NetDataContractSerializer */
- predicate isNetDataContractSerializerCall(MethodCall mc, Method m) {
+ private predicate isNetDataContractSerializerCall(MethodCall mc, Method m) {
m = mc.getTarget() and
(
m instanceof NetDataContractSerializerDeserializeMethod and
@@ -192,9 +192,9 @@ module UnsafeDeserialization {
)
}
- abstract class NetDataContractSerializerSink extends InstanceMethodSink { }
+ private abstract class NetDataContractSerializerSink extends InstanceMethodSink { }
- class NetDataContractSerializerDeserializeMethodSink extends NetDataContractSerializerSink {
+ private class NetDataContractSerializerDeserializeMethodSink extends NetDataContractSerializerSink {
NetDataContractSerializerDeserializeMethodSink() {
exists(MethodCall mc, Method m |
isNetDataContractSerializerCall(mc, m) and
@@ -204,15 +204,15 @@ module UnsafeDeserialization {
}
/** DataContractJsonSerializer */
- predicate isDataContractJsonSerializerCall(MethodCall mc, Method m) {
+ private predicate isDataContractJsonSerializerCall(MethodCall mc, Method m) {
m = mc.getTarget() and
m instanceof DataContractJsonSerializerReadObjectMethod and
not mc.getArgument(0).hasValue()
}
- abstract class DataContractJsonSerializerSink extends InstanceMethodSink { }
+ private abstract class DataContractJsonSerializerSink extends InstanceMethodSink { }
- class DataContractJsonSerializerDeserializeMethodSink extends DataContractJsonSerializerSink {
+ private class DataContractJsonSerializerDeserializeMethodSink extends DataContractJsonSerializerSink {
DataContractJsonSerializerDeserializeMethodSink() {
exists(MethodCall mc, Method m |
isDataContractJsonSerializerCall(mc, m) and
@@ -221,7 +221,7 @@ module UnsafeDeserialization {
}
}
- class DataContractJsonSafeConstructorTrackingConfiguration extends SafeConstructorTrackingConfig {
+ private class DataContractJsonSafeConstructorTrackingConfiguration extends SafeConstructorTrackingConfig {
DataContractJsonSafeConstructorTrackingConfiguration() {
this = "DataContractJsonSafeConstructorTrackingConfiguration"
}
@@ -242,7 +242,7 @@ module UnsafeDeserialization {
}
/** JavaScriptSerializer */
- predicate isJavaScriptSerializerCall(MethodCall mc, Method m) {
+ private predicate isJavaScriptSerializerCall(MethodCall mc, Method m) {
m = mc.getTarget() and
(
m instanceof JavaScriptSerializerClassDeserializeMethod and
@@ -253,9 +253,9 @@ module UnsafeDeserialization {
)
}
- abstract class JavaScriptSerializerSink extends InstanceMethodSink { }
+ private abstract class JavaScriptSerializerSink extends InstanceMethodSink { }
- class JavaScriptSerializerDeserializeMethodSink extends JavaScriptSerializerSink {
+ private class JavaScriptSerializerDeserializeMethodSink extends JavaScriptSerializerSink {
JavaScriptSerializerDeserializeMethodSink() {
exists(MethodCall mc, Method m |
isJavaScriptSerializerCall(mc, m) and
@@ -264,7 +264,7 @@ module UnsafeDeserialization {
}
}
- class JavaScriptSerializerSafeConstructorTrackingConfiguration extends SafeConstructorTrackingConfig {
+ private class JavaScriptSerializerSafeConstructorTrackingConfiguration extends SafeConstructorTrackingConfig {
JavaScriptSerializerSafeConstructorTrackingConfiguration() {
this = "JavaScriptSerializerSafeConstructorTrackingConfiguration"
}
@@ -284,16 +284,16 @@ module UnsafeDeserialization {
}
/** XmlObjectSerializer */
- predicate isXmlObjectSerializerCall(MethodCall mc, Method m) {
+ private predicate isXmlObjectSerializerCall(MethodCall mc, Method m) {
m = mc.getTarget() and
m instanceof XmlObjectSerializerReadObjectMethod and
not mc.getArgument(0).hasValue() and
not mc.targetIsLocalInstance()
}
- abstract class XmlObjectSerializerSink extends InstanceMethodSink { }
+ private abstract class XmlObjectSerializerSink extends InstanceMethodSink { }
- class XmlObjectSerializerDeserializeMethodSink extends XmlObjectSerializerSink {
+ private class XmlObjectSerializerDeserializeMethodSink extends XmlObjectSerializerSink {
XmlObjectSerializerDeserializeMethodSink() {
exists(MethodCall mc, Method m |
isXmlObjectSerializerCall(mc, m) and
@@ -302,7 +302,7 @@ module UnsafeDeserialization {
}
}
- class XmlObjectSerializerDerivedConstructorTrackingConfiguration extends SafeConstructorTrackingConfig {
+ private class XmlObjectSerializerDerivedConstructorTrackingConfiguration extends SafeConstructorTrackingConfig {
XmlObjectSerializerDerivedConstructorTrackingConfiguration() {
this = "XmlObjectSerializerDerivedConstructorTrackingConfiguration"
}
@@ -327,15 +327,15 @@ module UnsafeDeserialization {
}
/** XmlSerializer */
- predicate isXmlSerializerCall(MethodCall mc, Method m) {
+ private predicate isXmlSerializerCall(MethodCall mc, Method m) {
m = mc.getTarget() and
m instanceof XmlSerializerDeserializeMethod and
not mc.getArgument(0).hasValue()
}
- abstract class XmlSerializerSink extends InstanceMethodSink { }
+ private abstract class XmlSerializerSink extends InstanceMethodSink { }
- class XmlSerializerDeserializeMethodSink extends XmlSerializerSink {
+ private class XmlSerializerDeserializeMethodSink extends XmlSerializerSink {
XmlSerializerDeserializeMethodSink() {
exists(MethodCall mc, Method m |
isXmlSerializerCall(mc, m) and
@@ -344,7 +344,7 @@ module UnsafeDeserialization {
}
}
- class XmlSerializerSafeConstructorTrackingConfiguration extends SafeConstructorTrackingConfig {
+ private class XmlSerializerSafeConstructorTrackingConfiguration extends SafeConstructorTrackingConfig {
XmlSerializerSafeConstructorTrackingConfiguration() {
this = "XmlSerializerSafeConstructorTrackingConfiguration"
}
@@ -364,7 +364,7 @@ module UnsafeDeserialization {
}
/** DataContractSerializer */
- predicate isDataContractSerializerCall(MethodCall mc, Method m) {
+ private predicate isDataContractSerializerCall(MethodCall mc, Method m) {
m = mc.getTarget() and
(
m instanceof DataContractSerializerReadObjectMethod
@@ -374,9 +374,9 @@ module UnsafeDeserialization {
not mc.getArgument(0).hasValue()
}
- abstract class DataContractSerializerSink extends InstanceMethodSink { }
+ private abstract class DataContractSerializerSink extends InstanceMethodSink { }
- class DataContractSerializerDeserializeMethodSink extends DataContractSerializerSink {
+ private class DataContractSerializerDeserializeMethodSink extends DataContractSerializerSink {
DataContractSerializerDeserializeMethodSink() {
exists(MethodCall mc, Method m |
isDataContractSerializerCall(mc, m) and
@@ -385,7 +385,7 @@ module UnsafeDeserialization {
}
}
- class DataContractSerializerSafeConstructorTrackingConfiguration extends SafeConstructorTrackingConfig {
+ private class DataContractSerializerSafeConstructorTrackingConfiguration extends SafeConstructorTrackingConfig {
DataContractSerializerSafeConstructorTrackingConfiguration() {
this = "DataContractSerializerSafeConstructorTrackingConfiguration"
}
@@ -406,15 +406,15 @@ module UnsafeDeserialization {
}
/** XmlMessageFormatter */
- predicate isXmlMessageFormatterCall(MethodCall mc, Method m) {
+ private predicate isXmlMessageFormatterCall(MethodCall mc, Method m) {
m = mc.getTarget() and
m instanceof XmlMessageFormatterReadMethod and
not mc.getArgument(0).hasValue()
}
- abstract class XmlMessageFormatterSink extends InstanceMethodSink { }
+ private abstract class XmlMessageFormatterSink extends InstanceMethodSink { }
- class XmlMessageFormatterDeserializeMethodSink extends XmlMessageFormatterSink {
+ private class XmlMessageFormatterDeserializeMethodSink extends XmlMessageFormatterSink {
XmlMessageFormatterDeserializeMethodSink() {
exists(MethodCall mc, Method m |
isXmlMessageFormatterCall(mc, m) and
@@ -423,7 +423,7 @@ module UnsafeDeserialization {
}
}
- class XmlMessageFormatterSafeConstructorTrackingConfiguration extends SafeConstructorTrackingConfig {
+ private class XmlMessageFormatterSafeConstructorTrackingConfiguration extends SafeConstructorTrackingConfig {
XmlMessageFormatterSafeConstructorTrackingConfiguration() {
this = "XmlMessageFormatterSafeConstructorTrackingConfiguration"
}
@@ -444,15 +444,15 @@ module UnsafeDeserialization {
}
/** LosFormatter */
- predicate isLosFormatterCall(MethodCall mc, Method m) {
+ private predicate isLosFormatterCall(MethodCall mc, Method m) {
m = mc.getTarget() and
m instanceof LosFormatterDeserializeMethod and
not mc.getArgument(0).hasValue()
}
- abstract class LosFormatterSink extends InstanceMethodSink { }
+ private abstract class LosFormatterSink extends InstanceMethodSink { }
- class LosFormatterDeserializeMethodSink extends LosFormatterSink {
+ private class LosFormatterDeserializeMethodSink extends LosFormatterSink {
LosFormatterDeserializeMethodSink() {
exists(MethodCall mc, Method m |
isLosFormatterCall(mc, m) and
@@ -462,15 +462,15 @@ module UnsafeDeserialization {
}
/** fastJSON */
- predicate isFastJsonCall(MethodCall mc, Method m) {
+ private predicate isFastJsonCall(MethodCall mc, Method m) {
m = mc.getTarget() and
m instanceof FastJsonClassToObjectMethod and
not mc.getArgument(0).hasValue()
}
- abstract class FastJsonSink extends ConstructorOrStaticMethodSink { }
+ private abstract class FastJsonSink extends ConstructorOrStaticMethodSink { }
- class FastJsonDeserializeMethodSink extends FastJsonSink {
+ private class FastJsonDeserializeMethodSink extends FastJsonSink {
FastJsonDeserializeMethodSink() {
exists(MethodCall mc, Method m |
isFastJsonCall(mc, m) and
@@ -480,15 +480,15 @@ module UnsafeDeserialization {
}
/** Activity */
- predicate isActivityCall(MethodCall mc, Method m) {
+ private predicate isActivityCall(MethodCall mc, Method m) {
m = mc.getTarget() and
m instanceof ActivityLoadMethod and
not mc.getArgument(0).hasValue()
}
- abstract class ActivitySink extends InstanceMethodSink { }
+ private abstract class ActivitySink extends InstanceMethodSink { }
- class ActivityDeserializeMethodSink extends ActivitySink {
+ private class ActivityDeserializeMethodSink extends ActivitySink {
ActivityDeserializeMethodSink() {
exists(MethodCall mc, Method m |
isActivityCall(mc, m) and
@@ -498,15 +498,15 @@ module UnsafeDeserialization {
}
/** ResourceReader */
- predicate isResourceReaderCall(Call mc, Constructor m) {
+ private predicate isResourceReaderCall(Call mc, Constructor m) {
m = mc.getTarget() and
m instanceof ResourceReaderConstructor and
not mc.getArgument(0).hasValue()
}
- abstract class ResourceReaderSink extends ConstructorOrStaticMethodSink { }
+ private abstract class ResourceReaderSink extends ConstructorOrStaticMethodSink { }
- class ResourceReaderDeserializeMethodSink extends ResourceReaderSink {
+ private class ResourceReaderDeserializeMethodSink extends ResourceReaderSink {
ResourceReaderDeserializeMethodSink() {
exists(Call mc, Constructor m |
isResourceReaderCall(mc, m) and
@@ -516,15 +516,15 @@ module UnsafeDeserialization {
}
/** BinaryMessageFormatter */
- predicate isBinaryMessageFormatterCall(MethodCall mc, Method m) {
+ private predicate isBinaryMessageFormatterCall(MethodCall mc, Method m) {
m = mc.getTarget() and
m instanceof BinaryMessageFormatterReadMethod and
not mc.getArgument(0).hasValue()
}
- abstract class BinaryMessageFormatterSink extends InstanceMethodSink { }
+ private abstract class BinaryMessageFormatterSink extends InstanceMethodSink { }
- class BinaryMessageFormatterDeserializeMethodSink extends BinaryMessageFormatterSink {
+ private class BinaryMessageFormatterDeserializeMethodSink extends BinaryMessageFormatterSink {
BinaryMessageFormatterDeserializeMethodSink() {
exists(MethodCall mc, Method m |
isBinaryMessageFormatterCall(mc, m) and
@@ -534,7 +534,7 @@ module UnsafeDeserialization {
}
/** XamlReader */
- predicate isXamlReaderCall(MethodCall mc, Method m) {
+ private predicate isXamlReaderCall(MethodCall mc, Method m) {
m = mc.getTarget() and
(
m instanceof XamlReaderParseMethod
@@ -546,9 +546,9 @@ module UnsafeDeserialization {
not mc.getArgument(0).hasValue()
}
- abstract class XamlReaderSink extends ConstructorOrStaticMethodSink { }
+ private abstract class XamlReaderSink extends ConstructorOrStaticMethodSink { }
- class XamlReaderDeserializeMethodSink extends XamlReaderSink {
+ private class XamlReaderDeserializeMethodSink extends XamlReaderSink {
XamlReaderDeserializeMethodSink() {
exists(MethodCall mc, Method m |
isXamlReaderCall(mc, m) and
@@ -558,7 +558,7 @@ module UnsafeDeserialization {
}
/** ProxyObject */
- predicate isProxyObjectCall(MethodCall mc, Method m) {
+ private predicate isProxyObjectCall(MethodCall mc, Method m) {
m = mc.getTarget() and
(
m instanceof ProxyObjectDecodeValueMethod
@@ -568,9 +568,9 @@ module UnsafeDeserialization {
not mc.getArgument(0).hasValue()
}
- abstract class ProxyObjectSink extends InstanceMethodSink { }
+ private abstract class ProxyObjectSink extends InstanceMethodSink { }
- class ProxyObjectDeserializeMethodSink extends ProxyObjectSink {
+ private class ProxyObjectDeserializeMethodSink extends ProxyObjectSink {
ProxyObjectDeserializeMethodSink() {
exists(MethodCall mc, Method m |
isProxyObjectCall(mc, m) and
@@ -580,15 +580,15 @@ module UnsafeDeserialization {
}
/** SweetJayson */
- predicate isSweetJaysonCall(MethodCall mc, Method m) {
+ private predicate isSweetJaysonCall(MethodCall mc, Method m) {
m = mc.getTarget() and
m instanceof JaysonConverterToObjectMethod and
not mc.getArgument(0).hasValue()
}
- abstract class SweetJaysonSink extends ConstructorOrStaticMethodSink { }
+ private abstract class SweetJaysonSink extends ConstructorOrStaticMethodSink { }
- class SweetJaysonDeserializeMethodSink extends SweetJaysonSink {
+ private class SweetJaysonDeserializeMethodSink extends SweetJaysonSink {
SweetJaysonDeserializeMethodSink() {
exists(MethodCall mc, Method m |
isSweetJaysonCall(mc, m) and
@@ -598,9 +598,9 @@ module UnsafeDeserialization {
}
/** ServiceStack.Text.JsonSerializer */
- abstract class ServiceStackTextJsonSerializerSink extends ConstructorOrStaticMethodSink { }
+ private abstract class ServiceStackTextJsonSerializerSink extends ConstructorOrStaticMethodSink { }
- class ServiceStackTextJsonSerializerDeserializeMethodSink extends ServiceStackTextJsonSerializerSink {
+ private class ServiceStackTextJsonSerializerDeserializeMethodSink extends ServiceStackTextJsonSerializerSink {
ServiceStackTextJsonSerializerDeserializeMethodSink() {
exists(MethodCall mc, Method m |
m = mc.getTarget() and
@@ -619,9 +619,9 @@ module UnsafeDeserialization {
}
/** ServiceStack.Text.TypeSerializer */
- abstract class ServiceStackTextTypeSerializerSink extends ConstructorOrStaticMethodSink { }
+ private abstract class ServiceStackTextTypeSerializerSink extends ConstructorOrStaticMethodSink { }
- class ServiceStackTextTypeSerializerDeserializeMethodSink extends ServiceStackTextTypeSerializerSink {
+ private class ServiceStackTextTypeSerializerDeserializeMethodSink extends ServiceStackTextTypeSerializerSink {
ServiceStackTextTypeSerializerDeserializeMethodSink() {
exists(MethodCall mc, Method m |
m = mc.getTarget() and
@@ -640,9 +640,9 @@ module UnsafeDeserialization {
}
/** ServiceStack.Text.CsvSerializer */
- abstract class ServiceStackTextCsvSerializerSink extends ConstructorOrStaticMethodSink { }
+ private abstract class ServiceStackTextCsvSerializerSink extends ConstructorOrStaticMethodSink { }
- class ServiceStackTextCsvSerializerDeserializeMethodSink extends ServiceStackTextCsvSerializerSink {
+ private class ServiceStackTextCsvSerializerDeserializeMethodSink extends ServiceStackTextCsvSerializerSink {
ServiceStackTextCsvSerializerDeserializeMethodSink() {
exists(MethodCall mc, Method m |
m = mc.getTarget() and
@@ -661,9 +661,9 @@ module UnsafeDeserialization {
}
/** ServiceStack.Text.XmlSerializer */
- abstract class ServiceStackTextXmlSerializerSink extends ConstructorOrStaticMethodSink { }
+ private abstract class ServiceStackTextXmlSerializerSink extends ConstructorOrStaticMethodSink { }
- class ServiceStackTextXmlSerializerDeserializeMethodSink extends ServiceStackTextXmlSerializerSink {
+ private class ServiceStackTextXmlSerializerDeserializeMethodSink extends ServiceStackTextXmlSerializerSink {
ServiceStackTextXmlSerializerDeserializeMethodSink() {
exists(MethodCall mc, Method m |
m = mc.getTarget() and
From b027fddc7ed5eb1da36cc57d105239972174eff5 Mon Sep 17 00:00:00 2001
From: edvraa <80588099+edvraa@users.noreply.github.com>
Date: Thu, 15 Apr 2021 00:14:09 +0300
Subject: [PATCH 045/429] Remove redundant check
---
.../ql/src/Security Features/CWE-502/UnsafeDeserialization.ql | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/csharp/ql/src/Security Features/CWE-502/UnsafeDeserialization.ql b/csharp/ql/src/Security Features/CWE-502/UnsafeDeserialization.ql
index 252d2b25ddc..7575bd14665 100644
--- a/csharp/ql/src/Security Features/CWE-502/UnsafeDeserialization.ql
+++ b/csharp/ql/src/Security Features/CWE-502/UnsafeDeserialization.ql
@@ -25,8 +25,7 @@ where
safeTypeUsage.getNode().asExpr().getParent() = deserializeCall
)
or
- sink instanceof ConstructorOrStaticMethodSink and
- deserializeCall.getAnArgument() = sink.asExpr()
+ sink instanceof ConstructorOrStaticMethodSink
)
select deserializeCall,
"Unsafe deserializer is used. Make sure the value being deserialized comes from a trusted source."
From 1581a27d3d4218c7f3239000019a5a2e4a9b74f6 Mon Sep 17 00:00:00 2001
From: edvraa <80588099+edvraa@users.noreply.github.com>
Date: Thu, 15 Apr 2021 15:23:03 +0300
Subject: [PATCH 046/429] Simplify getTarget check
---
.../csharp/security/dataflow/UnsafeDeserialization.qll | 10 ++++------
1 file changed, 4 insertions(+), 6 deletions(-)
diff --git a/csharp/ql/src/semmle/code/csharp/security/dataflow/UnsafeDeserialization.qll b/csharp/ql/src/semmle/code/csharp/security/dataflow/UnsafeDeserialization.qll
index ec16a6fc9c6..5d6b2652fca 100644
--- a/csharp/ql/src/semmle/code/csharp/security/dataflow/UnsafeDeserialization.qll
+++ b/csharp/ql/src/semmle/code/csharp/security/dataflow/UnsafeDeserialization.qll
@@ -63,9 +63,8 @@ module UnsafeDeserialization {
override predicate isSource(DataFlow::Node source) { source instanceof Source }
override predicate isSink(DataFlow::Node sink) {
- exists(MethodCall mc, Method m |
- m = mc.getTarget() and
- m instanceof UnsafeDeserializerCallable and
+ exists(MethodCall mc |
+ mc.getTarget() instanceof UnsafeDeserializerCallable and
sink.asExpr() = mc.getQualifier()
)
}
@@ -102,9 +101,8 @@ module UnsafeDeserialization {
}
override predicate isSink(DataFlow::Node sink) {
- exists(MethodCall mc, Method m |
- m = mc.getTarget() and
- m instanceof UnsafeDeserializerCallable and
+ exists(MethodCall mc |
+ mc.getTarget() instanceof UnsafeDeserializerCallable and
sink.asExpr() = mc.getQualifier()
)
}
From 773556e5e035a7daa2baaa446f2a045fbd04915b Mon Sep 17 00:00:00 2001
From: edvraa <80588099+edvraa@users.noreply.github.com>
Date: Thu, 15 Apr 2021 15:16:38 +0300
Subject: [PATCH 047/429] Use hasFlow where path is not needed
---
.../CWE-502/UnsafeDeserialization.ql | 6 ++---
.../UnsafeDeserializationUntrustedInput.ql | 24 +++++++++----------
2 files changed, 14 insertions(+), 16 deletions(-)
diff --git a/csharp/ql/src/Security Features/CWE-502/UnsafeDeserialization.ql b/csharp/ql/src/Security Features/CWE-502/UnsafeDeserialization.ql
index 7575bd14665..3f5862795e3 100644
--- a/csharp/ql/src/Security Features/CWE-502/UnsafeDeserialization.ql
+++ b/csharp/ql/src/Security Features/CWE-502/UnsafeDeserialization.ql
@@ -19,10 +19,10 @@ where
(
sink instanceof InstanceMethodSink and
not exists(
- SafeConstructorTrackingConfig safeConstructorTracking, DataFlow::PathNode safeTypeUsage
+ SafeConstructorTrackingConfig safeConstructorTracking, DataFlow::Node safeTypeUsage
|
- safeConstructorTracking.hasFlowPath(_, safeTypeUsage) and
- safeTypeUsage.getNode().asExpr().getParent() = deserializeCall
+ safeConstructorTracking.hasFlow(_, safeTypeUsage) and
+ safeTypeUsage.asExpr().getParent() = deserializeCall
)
or
sink instanceof ConstructorOrStaticMethodSink
diff --git a/csharp/ql/src/Security Features/CWE-502/UnsafeDeserializationUntrustedInput.ql b/csharp/ql/src/Security Features/CWE-502/UnsafeDeserializationUntrustedInput.ql
index de75bf08807..ce85c424f7e 100644
--- a/csharp/ql/src/Security Features/CWE-502/UnsafeDeserializationUntrustedInput.ql
+++ b/csharp/ql/src/Security Features/CWE-502/UnsafeDeserializationUntrustedInput.ql
@@ -33,30 +33,28 @@ where
// intersect with strong types, but user controlled or weak types deserialization usages
(
exists(
- DataFlow::PathNode weakTypeCreation, DataFlow::PathNode weakTypeUsage,
+ DataFlow::Node weakTypeCreation, DataFlow::Node weakTypeUsage,
WeakTypeCreationToUsageTrackingConfig weakTypeDeserializerTracking
|
- weakTypeDeserializerTracking.hasFlowPath(weakTypeCreation, weakTypeUsage) and
- weakTypeUsage.getNode().asExpr().getParent() =
- deserializeCallArg.getNode().asExpr().getParent()
+ weakTypeDeserializerTracking.hasFlow(weakTypeCreation, weakTypeUsage) and
+ weakTypeUsage.asExpr().getParent() = deserializeCallArg.getNode().asExpr().getParent()
)
or
exists(
- TaintToObjectTypeTrackingConfig userControlledTypeTracking,
- DataFlow::PathNode taintedTypeUsage, DataFlow::PathNode userInput2
+ TaintToObjectTypeTrackingConfig userControlledTypeTracking, DataFlow::Node taintedTypeUsage,
+ DataFlow::Node userInput2
|
- userControlledTypeTracking.hasFlowPath(userInput2, taintedTypeUsage) and
- taintedTypeUsage.getNode().asExpr().getParent() =
- deserializeCallArg.getNode().asExpr().getParent()
+ userControlledTypeTracking.hasFlow(userInput2, taintedTypeUsage) and
+ taintedTypeUsage.asExpr().getParent() = deserializeCallArg.getNode().asExpr().getParent()
)
) and
// exclude deserialization flows with safe instances (i.e. JavaScriptSerializer without resolver)
not exists(
- SafeConstructorTrackingConfig safeConstructorTracking, DataFlow::PathNode safeCreation,
- DataFlow::PathNode safeTypeUsage
+ SafeConstructorTrackingConfig safeConstructorTracking, DataFlow::Node safeCreation,
+ DataFlow::Node safeTypeUsage
|
- safeConstructorTracking.hasFlowPath(safeCreation, safeTypeUsage) and
- safeTypeUsage.getNode().asExpr().getParent() = deserializeCallArg.getNode().asExpr().getParent()
+ safeConstructorTracking.hasFlow(safeCreation, safeTypeUsage) and
+ safeTypeUsage.asExpr().getParent() = deserializeCallArg.getNode().asExpr().getParent()
)
or
// no type check needed - straightforward taint -> sink
From 3aedd2c1f42c03be87db891031cbc1e7689c54c2 Mon Sep 17 00:00:00 2001
From: edvraa <80588099+edvraa@users.noreply.github.com>
Date: Thu, 15 Apr 2021 22:12:01 +0300
Subject: [PATCH 048/429] Use TaintTracking2
---
.../UnsafeDeserializationUntrustedInput.ql | 10 +--
.../dataflow/UnsafeDeserialization.qll | 7 +-
...safeDeserializationUntrustedInput.expected | 64 -------------------
3 files changed, 9 insertions(+), 72 deletions(-)
diff --git a/csharp/ql/src/Security Features/CWE-502/UnsafeDeserializationUntrustedInput.ql b/csharp/ql/src/Security Features/CWE-502/UnsafeDeserializationUntrustedInput.ql
index ce85c424f7e..4e57e256faf 100644
--- a/csharp/ql/src/Security Features/CWE-502/UnsafeDeserializationUntrustedInput.ql
+++ b/csharp/ql/src/Security Features/CWE-502/UnsafeDeserializationUntrustedInput.ql
@@ -24,12 +24,12 @@ class LocalSource extends Source {
LocalSource() { this instanceof LocalFlowSource }
}
-from
- TaintToObjectMethodTrackingConfig taintTracking, DataFlow::PathNode userInput,
- DataFlow::PathNode deserializeCallArg
+from DataFlow::PathNode userInput, DataFlow::PathNode deserializeCallArg
where
- // all flows from user input to deserialization with weak and strong type serializers
- taintTracking.hasFlowPath(userInput, deserializeCallArg) and
+ exists(TaintToObjectMethodTrackingConfig taintTracking |
+ // all flows from user input to deserialization with weak and strong type serializers
+ taintTracking.hasFlowPath(userInput, deserializeCallArg)
+ ) and
// intersect with strong types, but user controlled or weak types deserialization usages
(
exists(
diff --git a/csharp/ql/src/semmle/code/csharp/security/dataflow/UnsafeDeserialization.qll b/csharp/ql/src/semmle/code/csharp/security/dataflow/UnsafeDeserialization.qll
index 5d6b2652fca..ec7b4e52b49 100644
--- a/csharp/ql/src/semmle/code/csharp/security/dataflow/UnsafeDeserialization.qll
+++ b/csharp/ql/src/semmle/code/csharp/security/dataflow/UnsafeDeserialization.qll
@@ -7,6 +7,7 @@ import csharp
module UnsafeDeserialization {
private import semmle.code.csharp.serialization.Deserializers
+ private import semmle.code.csharp.dataflow.TaintTracking2
/**
* A data flow source for unsafe deserialization vulnerabilities.
@@ -57,7 +58,7 @@ module UnsafeDeserialization {
/**
* User input to instance type flow tracking.
*/
- class TaintToObjectTypeTrackingConfig extends TaintTracking::Configuration {
+ class TaintToObjectTypeTrackingConfig extends TaintTracking2::Configuration {
TaintToObjectTypeTrackingConfig() { this = "TaintToObjectTypeTrackingConfig" }
override predicate isSource(DataFlow::Node source) { source instanceof Source }
@@ -90,7 +91,7 @@ module UnsafeDeserialization {
/**
* Unsafe deserializer creation to usage tracking config.
*/
- class WeakTypeCreationToUsageTrackingConfig extends TaintTracking::Configuration {
+ class WeakTypeCreationToUsageTrackingConfig extends TaintTracking2::Configuration {
WeakTypeCreationToUsageTrackingConfig() { this = "DeserializerCreationToUsageTrackingConfig" }
override predicate isSource(DataFlow::Node source) {
@@ -111,7 +112,7 @@ module UnsafeDeserialization {
/**
* Safe deserializer creation to usage tracking config.
*/
- abstract class SafeConstructorTrackingConfig extends TaintTracking::Configuration {
+ abstract class SafeConstructorTrackingConfig extends TaintTracking2::Configuration {
bindingset[this]
SafeConstructorTrackingConfig() { any() }
}
diff --git a/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserializationUntrustedInput/UnsafeDeserializationUntrustedInput.expected b/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserializationUntrustedInput/UnsafeDeserializationUntrustedInput.expected
index 57d849a34b0..5ad68adabc8 100644
--- a/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserializationUntrustedInput/UnsafeDeserializationUntrustedInput.expected
+++ b/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserializationUntrustedInput/UnsafeDeserializationUntrustedInput.expected
@@ -1,142 +1,78 @@
edges
-| BinaryFormatterUntrustedInputBad.cs:10:18:10:38 | object creation of type BinaryFormatter : BinaryFormatter | BinaryFormatterUntrustedInputBad.cs:12:16:12:17 | access to local variable ds |
| BinaryFormatterUntrustedInputBad.cs:12:48:12:83 | call to method GetBytes : Byte[] | BinaryFormatterUntrustedInputBad.cs:12:31:12:84 | object creation of type MemoryStream |
| BinaryFormatterUntrustedInputBad.cs:12:71:12:77 | access to parameter textBox : TextBox | BinaryFormatterUntrustedInputBad.cs:12:71:12:82 | access to property Text : String |
| BinaryFormatterUntrustedInputBad.cs:12:71:12:82 | access to property Text : String | BinaryFormatterUntrustedInputBad.cs:12:48:12:83 | call to method GetBytes : Byte[] |
-| BinaryFormatterUntrustedInputGood.cs:9:18:9:38 | object creation of type BinaryFormatter : BinaryFormatter | BinaryFormatterUntrustedInputGood.cs:11:16:11:17 | access to local variable ds |
-| DataContractJsonSerializerUntrustedInputBad.cs:11:62:11:65 | access to parameter type : TextBox | DataContractJsonSerializerUntrustedInputBad.cs:11:62:11:70 | access to property Text : String |
-| DataContractJsonSerializerUntrustedInputBad.cs:11:62:11:70 | access to property Text : String | DataContractJsonSerializerUntrustedInputBad.cs:13:16:13:17 | access to local variable ds |
| DataContractJsonSerializerUntrustedInputBad.cs:13:47:13:79 | call to method GetBytes : Byte[] | DataContractJsonSerializerUntrustedInputBad.cs:13:30:13:80 | object creation of type MemoryStream |
| DataContractJsonSerializerUntrustedInputBad.cs:13:70:13:73 | access to parameter data : TextBox | DataContractJsonSerializerUntrustedInputBad.cs:13:70:13:78 | access to property Text : String |
| DataContractJsonSerializerUntrustedInputBad.cs:13:70:13:78 | access to property Text : String | DataContractJsonSerializerUntrustedInputBad.cs:13:47:13:79 | call to method GetBytes : Byte[] |
-| DataContractJsonSerializerUntrustedInputGood.cs:12:18:12:87 | object creation of type DataContractJsonSerializer : DataContractJsonSerializer | DataContractJsonSerializerUntrustedInputGood.cs:13:16:13:17 | access to local variable ds |
| DataContractJsonSerializerUntrustedInputGood.cs:13:47:13:79 | call to method GetBytes : Byte[] | DataContractJsonSerializerUntrustedInputGood.cs:13:30:13:80 | object creation of type MemoryStream |
| DataContractJsonSerializerUntrustedInputGood.cs:13:70:13:73 | access to parameter data : TextBox | DataContractJsonSerializerUntrustedInputGood.cs:13:70:13:78 | access to property Text : String |
| DataContractJsonSerializerUntrustedInputGood.cs:13:70:13:78 | access to property Text : String | DataContractJsonSerializerUntrustedInputGood.cs:13:47:13:79 | call to method GetBytes : Byte[] |
-| DataContractJsonSerializerUntrustedInputGood.cs:18:62:18:65 | access to parameter type : TextBox | DataContractJsonSerializerUntrustedInputGood.cs:18:62:18:70 | access to property Text : String |
-| DataContractJsonSerializerUntrustedInputGood.cs:18:62:18:70 | access to property Text : String | DataContractJsonSerializerUntrustedInputGood.cs:20:16:20:17 | access to local variable ds |
-| DataContractSerializerUntrustedInputBad.cs:11:58:11:61 | access to parameter type : TextBox | DataContractSerializerUntrustedInputBad.cs:11:58:11:66 | access to property Text : String |
-| DataContractSerializerUntrustedInputBad.cs:11:58:11:66 | access to property Text : String | DataContractSerializerUntrustedInputBad.cs:13:16:13:17 | access to local variable ds |
| DataContractSerializerUntrustedInputBad.cs:13:47:13:79 | call to method GetBytes : Byte[] | DataContractSerializerUntrustedInputBad.cs:13:30:13:80 | object creation of type MemoryStream |
| DataContractSerializerUntrustedInputBad.cs:13:70:13:73 | access to parameter data : TextBox | DataContractSerializerUntrustedInputBad.cs:13:70:13:78 | access to property Text : String |
| DataContractSerializerUntrustedInputBad.cs:13:70:13:78 | access to property Text : String | DataContractSerializerUntrustedInputBad.cs:13:47:13:79 | call to method GetBytes : Byte[] |
-| DataContractSerializerUntrustedInputGood.cs:12:18:12:79 | object creation of type DataContractSerializer : DataContractSerializer | DataContractSerializerUntrustedInputGood.cs:13:16:13:17 | access to local variable ds |
| DataContractSerializerUntrustedInputGood.cs:13:47:13:79 | call to method GetBytes : Byte[] | DataContractSerializerUntrustedInputGood.cs:13:30:13:80 | object creation of type MemoryStream |
| DataContractSerializerUntrustedInputGood.cs:13:70:13:73 | access to parameter data : TextBox | DataContractSerializerUntrustedInputGood.cs:13:70:13:78 | access to property Text : String |
| DataContractSerializerUntrustedInputGood.cs:13:70:13:78 | access to property Text : String | DataContractSerializerUntrustedInputGood.cs:13:47:13:79 | call to method GetBytes : Byte[] |
-| DataContractSerializerUntrustedInputGood.cs:18:58:18:61 | access to parameter type : TextBox | DataContractSerializerUntrustedInputGood.cs:18:58:18:66 | access to property Text : String |
-| DataContractSerializerUntrustedInputGood.cs:18:58:18:66 | access to property Text : String | DataContractSerializerUntrustedInputGood.cs:20:16:20:17 | access to local variable ds |
| ResourceReaderUntrustedInputBad.cs:11:54:11:86 | call to method GetBytes : Byte[] | ResourceReaderUntrustedInputBad.cs:11:37:11:87 | object creation of type MemoryStream |
| ResourceReaderUntrustedInputBad.cs:11:77:11:80 | access to parameter data : TextBox | ResourceReaderUntrustedInputBad.cs:11:77:11:85 | access to property Text : String |
| ResourceReaderUntrustedInputBad.cs:11:77:11:85 | access to property Text : String | ResourceReaderUntrustedInputBad.cs:11:54:11:86 | call to method GetBytes : Byte[] |
-| UnsafeDeserializationUntrustedInputBad.cs:8:35:8:84 | object creation of type JavaScriptSerializer : JavaScriptSerializer | UnsafeDeserializationUntrustedInputBad.cs:10:16:10:17 | access to local variable sr |
| UnsafeDeserializationUntrustedInputBad.cs:10:37:10:43 | access to parameter textBox : TextBox | UnsafeDeserializationUntrustedInputBad.cs:10:37:10:48 | access to property Text |
-| UnsafeDeserializationUntrustedInputGood.cs:8:35:8:84 | object creation of type JavaScriptSerializer : JavaScriptSerializer | UnsafeDeserializationUntrustedInputGood.cs:10:16:10:17 | access to local variable sr |
-| XmlObjectSerializerUntrustedInputBad.cs:11:74:11:77 | access to parameter type : TextBox | XmlObjectSerializerUntrustedInputBad.cs:11:74:11:82 | access to property Text : String |
-| XmlObjectSerializerUntrustedInputBad.cs:11:74:11:82 | access to property Text : String | XmlObjectSerializerUntrustedInputBad.cs:13:16:13:17 | access to local variable ds |
| XmlObjectSerializerUntrustedInputBad.cs:13:47:13:79 | call to method GetBytes : Byte[] | XmlObjectSerializerUntrustedInputBad.cs:13:30:13:80 | object creation of type MemoryStream |
| XmlObjectSerializerUntrustedInputBad.cs:13:70:13:73 | access to parameter data : TextBox | XmlObjectSerializerUntrustedInputBad.cs:13:70:13:78 | access to property Text : String |
| XmlObjectSerializerUntrustedInputBad.cs:13:70:13:78 | access to property Text : String | XmlObjectSerializerUntrustedInputBad.cs:13:47:13:79 | call to method GetBytes : Byte[] |
-| XmlObjectSerializerUntrustedInputGood.cs:12:34:12:92 | object creation of type DataContractSerializer : DataContractSerializer | XmlObjectSerializerUntrustedInputGood.cs:13:16:13:17 | access to local variable ds |
| XmlObjectSerializerUntrustedInputGood.cs:13:47:13:79 | call to method GetBytes : Byte[] | XmlObjectSerializerUntrustedInputGood.cs:13:30:13:80 | object creation of type MemoryStream |
| XmlObjectSerializerUntrustedInputGood.cs:13:70:13:73 | access to parameter data : TextBox | XmlObjectSerializerUntrustedInputGood.cs:13:70:13:78 | access to property Text : String |
| XmlObjectSerializerUntrustedInputGood.cs:13:70:13:78 | access to property Text : String | XmlObjectSerializerUntrustedInputGood.cs:13:47:13:79 | call to method GetBytes : Byte[] |
-| XmlObjectSerializerUntrustedInputGood.cs:18:74:18:77 | access to parameter type : TextBox | XmlObjectSerializerUntrustedInputGood.cs:18:74:18:82 | access to property Text : String |
-| XmlObjectSerializerUntrustedInputGood.cs:18:74:18:82 | access to property Text : String | XmlObjectSerializerUntrustedInputGood.cs:20:16:20:17 | access to local variable ds |
-| XmlSerializerUntrustedInputBad.cs:11:49:11:52 | access to parameter type : TextBox | XmlSerializerUntrustedInputBad.cs:11:49:11:57 | access to property Text : String |
-| XmlSerializerUntrustedInputBad.cs:11:49:11:57 | access to property Text : String | XmlSerializerUntrustedInputBad.cs:13:16:13:17 | access to local variable ds |
| XmlSerializerUntrustedInputBad.cs:13:48:13:80 | call to method GetBytes : Byte[] | XmlSerializerUntrustedInputBad.cs:13:31:13:81 | object creation of type MemoryStream |
| XmlSerializerUntrustedInputBad.cs:13:71:13:74 | access to parameter data : TextBox | XmlSerializerUntrustedInputBad.cs:13:71:13:79 | access to property Text : String |
| XmlSerializerUntrustedInputBad.cs:13:71:13:79 | access to property Text : String | XmlSerializerUntrustedInputBad.cs:13:48:13:80 | call to method GetBytes : Byte[] |
-| XmlSerializerUntrustedInputGood.cs:12:18:12:61 | object creation of type XmlSerializer : XmlSerializer | XmlSerializerUntrustedInputGood.cs:13:16:13:17 | access to local variable ds |
| XmlSerializerUntrustedInputGood.cs:13:48:13:80 | call to method GetBytes : Byte[] | XmlSerializerUntrustedInputGood.cs:13:31:13:81 | object creation of type MemoryStream |
| XmlSerializerUntrustedInputGood.cs:13:71:13:74 | access to parameter data : TextBox | XmlSerializerUntrustedInputGood.cs:13:71:13:79 | access to property Text : String |
| XmlSerializerUntrustedInputGood.cs:13:71:13:79 | access to property Text : String | XmlSerializerUntrustedInputGood.cs:13:48:13:80 | call to method GetBytes : Byte[] |
-| XmlSerializerUntrustedInputGood.cs:18:49:18:52 | access to parameter type : TextBox | XmlSerializerUntrustedInputGood.cs:18:49:18:57 | access to property Text : String |
-| XmlSerializerUntrustedInputGood.cs:18:49:18:57 | access to property Text : String | XmlSerializerUntrustedInputGood.cs:20:16:20:17 | access to local variable ds |
nodes
-| BinaryFormatterUntrustedInputBad.cs:10:18:10:38 | object creation of type BinaryFormatter : BinaryFormatter | semmle.label | object creation of type BinaryFormatter : BinaryFormatter |
-| BinaryFormatterUntrustedInputBad.cs:12:16:12:17 | access to local variable ds | semmle.label | access to local variable ds |
| BinaryFormatterUntrustedInputBad.cs:12:31:12:84 | object creation of type MemoryStream | semmle.label | object creation of type MemoryStream |
| BinaryFormatterUntrustedInputBad.cs:12:48:12:83 | call to method GetBytes : Byte[] | semmle.label | call to method GetBytes : Byte[] |
| BinaryFormatterUntrustedInputBad.cs:12:71:12:77 | access to parameter textBox : TextBox | semmle.label | access to parameter textBox : TextBox |
| BinaryFormatterUntrustedInputBad.cs:12:71:12:82 | access to property Text : String | semmle.label | access to property Text : String |
-| BinaryFormatterUntrustedInputGood.cs:9:18:9:38 | object creation of type BinaryFormatter : BinaryFormatter | semmle.label | object creation of type BinaryFormatter : BinaryFormatter |
-| BinaryFormatterUntrustedInputGood.cs:11:16:11:17 | access to local variable ds | semmle.label | access to local variable ds |
-| DataContractJsonSerializerUntrustedInputBad.cs:11:62:11:65 | access to parameter type : TextBox | semmle.label | access to parameter type : TextBox |
-| DataContractJsonSerializerUntrustedInputBad.cs:11:62:11:70 | access to property Text : String | semmle.label | access to property Text : String |
-| DataContractJsonSerializerUntrustedInputBad.cs:13:16:13:17 | access to local variable ds | semmle.label | access to local variable ds |
| DataContractJsonSerializerUntrustedInputBad.cs:13:30:13:80 | object creation of type MemoryStream | semmle.label | object creation of type MemoryStream |
| DataContractJsonSerializerUntrustedInputBad.cs:13:47:13:79 | call to method GetBytes : Byte[] | semmle.label | call to method GetBytes : Byte[] |
| DataContractJsonSerializerUntrustedInputBad.cs:13:70:13:73 | access to parameter data : TextBox | semmle.label | access to parameter data : TextBox |
| DataContractJsonSerializerUntrustedInputBad.cs:13:70:13:78 | access to property Text : String | semmle.label | access to property Text : String |
-| DataContractJsonSerializerUntrustedInputGood.cs:12:18:12:87 | object creation of type DataContractJsonSerializer : DataContractJsonSerializer | semmle.label | object creation of type DataContractJsonSerializer : DataContractJsonSerializer |
-| DataContractJsonSerializerUntrustedInputGood.cs:13:16:13:17 | access to local variable ds | semmle.label | access to local variable ds |
| DataContractJsonSerializerUntrustedInputGood.cs:13:30:13:80 | object creation of type MemoryStream | semmle.label | object creation of type MemoryStream |
| DataContractJsonSerializerUntrustedInputGood.cs:13:47:13:79 | call to method GetBytes : Byte[] | semmle.label | call to method GetBytes : Byte[] |
| DataContractJsonSerializerUntrustedInputGood.cs:13:70:13:73 | access to parameter data : TextBox | semmle.label | access to parameter data : TextBox |
| DataContractJsonSerializerUntrustedInputGood.cs:13:70:13:78 | access to property Text : String | semmle.label | access to property Text : String |
-| DataContractJsonSerializerUntrustedInputGood.cs:18:62:18:65 | access to parameter type : TextBox | semmle.label | access to parameter type : TextBox |
-| DataContractJsonSerializerUntrustedInputGood.cs:18:62:18:70 | access to property Text : String | semmle.label | access to property Text : String |
-| DataContractJsonSerializerUntrustedInputGood.cs:20:16:20:17 | access to local variable ds | semmle.label | access to local variable ds |
-| DataContractSerializerUntrustedInputBad.cs:11:58:11:61 | access to parameter type : TextBox | semmle.label | access to parameter type : TextBox |
-| DataContractSerializerUntrustedInputBad.cs:11:58:11:66 | access to property Text : String | semmle.label | access to property Text : String |
-| DataContractSerializerUntrustedInputBad.cs:13:16:13:17 | access to local variable ds | semmle.label | access to local variable ds |
| DataContractSerializerUntrustedInputBad.cs:13:30:13:80 | object creation of type MemoryStream | semmle.label | object creation of type MemoryStream |
| DataContractSerializerUntrustedInputBad.cs:13:47:13:79 | call to method GetBytes : Byte[] | semmle.label | call to method GetBytes : Byte[] |
| DataContractSerializerUntrustedInputBad.cs:13:70:13:73 | access to parameter data : TextBox | semmle.label | access to parameter data : TextBox |
| DataContractSerializerUntrustedInputBad.cs:13:70:13:78 | access to property Text : String | semmle.label | access to property Text : String |
-| DataContractSerializerUntrustedInputGood.cs:12:18:12:79 | object creation of type DataContractSerializer : DataContractSerializer | semmle.label | object creation of type DataContractSerializer : DataContractSerializer |
-| DataContractSerializerUntrustedInputGood.cs:13:16:13:17 | access to local variable ds | semmle.label | access to local variable ds |
| DataContractSerializerUntrustedInputGood.cs:13:30:13:80 | object creation of type MemoryStream | semmle.label | object creation of type MemoryStream |
| DataContractSerializerUntrustedInputGood.cs:13:47:13:79 | call to method GetBytes : Byte[] | semmle.label | call to method GetBytes : Byte[] |
| DataContractSerializerUntrustedInputGood.cs:13:70:13:73 | access to parameter data : TextBox | semmle.label | access to parameter data : TextBox |
| DataContractSerializerUntrustedInputGood.cs:13:70:13:78 | access to property Text : String | semmle.label | access to property Text : String |
-| DataContractSerializerUntrustedInputGood.cs:18:58:18:61 | access to parameter type : TextBox | semmle.label | access to parameter type : TextBox |
-| DataContractSerializerUntrustedInputGood.cs:18:58:18:66 | access to property Text : String | semmle.label | access to property Text : String |
-| DataContractSerializerUntrustedInputGood.cs:20:16:20:17 | access to local variable ds | semmle.label | access to local variable ds |
| ResourceReaderUntrustedInputBad.cs:11:37:11:87 | object creation of type MemoryStream | semmle.label | object creation of type MemoryStream |
| ResourceReaderUntrustedInputBad.cs:11:54:11:86 | call to method GetBytes : Byte[] | semmle.label | call to method GetBytes : Byte[] |
| ResourceReaderUntrustedInputBad.cs:11:77:11:80 | access to parameter data : TextBox | semmle.label | access to parameter data : TextBox |
| ResourceReaderUntrustedInputBad.cs:11:77:11:85 | access to property Text : String | semmle.label | access to property Text : String |
-| UnsafeDeserializationUntrustedInputBad.cs:8:35:8:84 | object creation of type JavaScriptSerializer : JavaScriptSerializer | semmle.label | object creation of type JavaScriptSerializer : JavaScriptSerializer |
-| UnsafeDeserializationUntrustedInputBad.cs:10:16:10:17 | access to local variable sr | semmle.label | access to local variable sr |
| UnsafeDeserializationUntrustedInputBad.cs:10:37:10:43 | access to parameter textBox : TextBox | semmle.label | access to parameter textBox : TextBox |
| UnsafeDeserializationUntrustedInputBad.cs:10:37:10:48 | access to property Text | semmle.label | access to property Text |
-| UnsafeDeserializationUntrustedInputGood.cs:8:35:8:84 | object creation of type JavaScriptSerializer : JavaScriptSerializer | semmle.label | object creation of type JavaScriptSerializer : JavaScriptSerializer |
-| UnsafeDeserializationUntrustedInputGood.cs:10:16:10:17 | access to local variable sr | semmle.label | access to local variable sr |
-| XmlObjectSerializerUntrustedInputBad.cs:11:74:11:77 | access to parameter type : TextBox | semmle.label | access to parameter type : TextBox |
-| XmlObjectSerializerUntrustedInputBad.cs:11:74:11:82 | access to property Text : String | semmle.label | access to property Text : String |
-| XmlObjectSerializerUntrustedInputBad.cs:13:16:13:17 | access to local variable ds | semmle.label | access to local variable ds |
| XmlObjectSerializerUntrustedInputBad.cs:13:30:13:80 | object creation of type MemoryStream | semmle.label | object creation of type MemoryStream |
| XmlObjectSerializerUntrustedInputBad.cs:13:47:13:79 | call to method GetBytes : Byte[] | semmle.label | call to method GetBytes : Byte[] |
| XmlObjectSerializerUntrustedInputBad.cs:13:70:13:73 | access to parameter data : TextBox | semmle.label | access to parameter data : TextBox |
| XmlObjectSerializerUntrustedInputBad.cs:13:70:13:78 | access to property Text : String | semmle.label | access to property Text : String |
-| XmlObjectSerializerUntrustedInputGood.cs:12:34:12:92 | object creation of type DataContractSerializer : DataContractSerializer | semmle.label | object creation of type DataContractSerializer : DataContractSerializer |
-| XmlObjectSerializerUntrustedInputGood.cs:13:16:13:17 | access to local variable ds | semmle.label | access to local variable ds |
| XmlObjectSerializerUntrustedInputGood.cs:13:30:13:80 | object creation of type MemoryStream | semmle.label | object creation of type MemoryStream |
| XmlObjectSerializerUntrustedInputGood.cs:13:47:13:79 | call to method GetBytes : Byte[] | semmle.label | call to method GetBytes : Byte[] |
| XmlObjectSerializerUntrustedInputGood.cs:13:70:13:73 | access to parameter data : TextBox | semmle.label | access to parameter data : TextBox |
| XmlObjectSerializerUntrustedInputGood.cs:13:70:13:78 | access to property Text : String | semmle.label | access to property Text : String |
-| XmlObjectSerializerUntrustedInputGood.cs:18:74:18:77 | access to parameter type : TextBox | semmle.label | access to parameter type : TextBox |
-| XmlObjectSerializerUntrustedInputGood.cs:18:74:18:82 | access to property Text : String | semmle.label | access to property Text : String |
-| XmlObjectSerializerUntrustedInputGood.cs:20:16:20:17 | access to local variable ds | semmle.label | access to local variable ds |
-| XmlSerializerUntrustedInputBad.cs:11:49:11:52 | access to parameter type : TextBox | semmle.label | access to parameter type : TextBox |
-| XmlSerializerUntrustedInputBad.cs:11:49:11:57 | access to property Text : String | semmle.label | access to property Text : String |
-| XmlSerializerUntrustedInputBad.cs:13:16:13:17 | access to local variable ds | semmle.label | access to local variable ds |
| XmlSerializerUntrustedInputBad.cs:13:31:13:81 | object creation of type MemoryStream | semmle.label | object creation of type MemoryStream |
| XmlSerializerUntrustedInputBad.cs:13:48:13:80 | call to method GetBytes : Byte[] | semmle.label | call to method GetBytes : Byte[] |
| XmlSerializerUntrustedInputBad.cs:13:71:13:74 | access to parameter data : TextBox | semmle.label | access to parameter data : TextBox |
| XmlSerializerUntrustedInputBad.cs:13:71:13:79 | access to property Text : String | semmle.label | access to property Text : String |
-| XmlSerializerUntrustedInputGood.cs:12:18:12:61 | object creation of type XmlSerializer : XmlSerializer | semmle.label | object creation of type XmlSerializer : XmlSerializer |
-| XmlSerializerUntrustedInputGood.cs:13:16:13:17 | access to local variable ds | semmle.label | access to local variable ds |
| XmlSerializerUntrustedInputGood.cs:13:31:13:81 | object creation of type MemoryStream | semmle.label | object creation of type MemoryStream |
| XmlSerializerUntrustedInputGood.cs:13:48:13:80 | call to method GetBytes : Byte[] | semmle.label | call to method GetBytes : Byte[] |
| XmlSerializerUntrustedInputGood.cs:13:71:13:74 | access to parameter data : TextBox | semmle.label | access to parameter data : TextBox |
| XmlSerializerUntrustedInputGood.cs:13:71:13:79 | access to property Text : String | semmle.label | access to property Text : String |
-| XmlSerializerUntrustedInputGood.cs:18:49:18:52 | access to parameter type : TextBox | semmle.label | access to parameter type : TextBox |
-| XmlSerializerUntrustedInputGood.cs:18:49:18:57 | access to property Text : String | semmle.label | access to property Text : String |
-| XmlSerializerUntrustedInputGood.cs:20:16:20:17 | access to local variable ds | semmle.label | access to local variable ds |
#select
| BinaryFormatterUntrustedInputBad.cs:12:31:12:84 | object creation of type MemoryStream | BinaryFormatterUntrustedInputBad.cs:12:71:12:77 | access to parameter textBox : TextBox | BinaryFormatterUntrustedInputBad.cs:12:31:12:84 | object creation of type MemoryStream | $@ flows to unsafe deserializer. | BinaryFormatterUntrustedInputBad.cs:12:71:12:77 | access to parameter textBox : TextBox | User-provided data |
| DataContractJsonSerializerUntrustedInputBad.cs:13:30:13:80 | object creation of type MemoryStream | DataContractJsonSerializerUntrustedInputBad.cs:13:70:13:73 | access to parameter data : TextBox | DataContractJsonSerializerUntrustedInputBad.cs:13:30:13:80 | object creation of type MemoryStream | $@ flows to unsafe deserializer. | DataContractJsonSerializerUntrustedInputBad.cs:13:70:13:73 | access to parameter data : TextBox | User-provided data |
From a412581556d0e6bfd0f3b14cb3a14fd7751edf06 Mon Sep 17 00:00:00 2001
From: edvraa <80588099+edvraa@users.noreply.github.com>
Date: Thu, 15 Apr 2021 22:32:42 +0300
Subject: [PATCH 049/429] reintroduce UnsafeDeserializer
---
.../csharp/serialization/Deserializers.qll | 79 ++++++++++---------
1 file changed, 41 insertions(+), 38 deletions(-)
diff --git a/csharp/ql/src/semmle/code/csharp/serialization/Deserializers.qll b/csharp/ql/src/semmle/code/csharp/serialization/Deserializers.qll
index bf9c74e645b..6f70c205159 100644
--- a/csharp/ql/src/semmle/code/csharp/serialization/Deserializers.qll
+++ b/csharp/ql/src/semmle/code/csharp/serialization/Deserializers.qll
@@ -5,6 +5,9 @@
import csharp
+/** An unsafe deserializer. */
+abstract class UnsafeDeserializer extends Callable { }
+
/** Unsafe deserialization calls. */
class UnsafeDeserializerCallable extends Callable {
UnsafeDeserializerCallable() {
@@ -140,7 +143,7 @@ class WeakTypeDeserializer extends Class {
* An unsafe deserializer method that calls any unsafe deserializer on any of
* the parameters.
*/
-class WrapperDeserializer extends UnsafeDeserializerCallable {
+class WrapperDeserializer extends UnsafeDeserializerCallable, UnsafeDeserializer {
WrapperDeserializer() {
exists(Call call |
call.getEnclosingCallable() = this and
@@ -157,21 +160,21 @@ class BinaryFormatterClass extends Class {
}
}
-class BinaryFormatterDeserializeMethod extends Method {
+class BinaryFormatterDeserializeMethod extends Method, UnsafeDeserializer {
BinaryFormatterDeserializeMethod() {
this.getDeclaringType() instanceof BinaryFormatterClass and
this.hasName("Deserialize")
}
}
-class BinaryFormatterUnsafeDeserializeMethod extends Method {
+class BinaryFormatterUnsafeDeserializeMethod extends Method, UnsafeDeserializer {
BinaryFormatterUnsafeDeserializeMethod() {
this.getDeclaringType() instanceof BinaryFormatterClass and
this.hasName("UnsafeDeserialize")
}
}
-class BinaryFormatterUnsafeDeserializeMethodResponseMethod extends Method {
+class BinaryFormatterUnsafeDeserializeMethodResponseMethod extends Method, UnsafeDeserializer {
BinaryFormatterUnsafeDeserializeMethodResponseMethod() {
this.getDeclaringType() instanceof BinaryFormatterClass and
this.hasName("UnsafeDeserializeMethodResponse")
@@ -185,7 +188,7 @@ class SoapFormatterClass extends Class {
}
}
-class SoapFormatterDeserializeMethod extends Method {
+class SoapFormatterDeserializeMethod extends Method, UnsafeDeserializer {
SoapFormatterDeserializeMethod() {
this.getDeclaringType() instanceof SoapFormatterClass and
this.hasName("Deserialize")
@@ -197,7 +200,7 @@ class ObjectStateFormatterClass extends Class {
ObjectStateFormatterClass() { this.hasQualifiedName("System.Web.UI.ObjectStateFormatter") }
}
-class ObjectStateFormatterDeserializeMethod extends Method {
+class ObjectStateFormatterDeserializeMethod extends Method, UnsafeDeserializer {
ObjectStateFormatterDeserializeMethod() {
this.getDeclaringType() instanceof ObjectStateFormatterClass and
this.hasName("Deserialize")
@@ -211,14 +214,14 @@ class NetDataContractSerializerClass extends Class {
}
}
-class NetDataContractSerializerDeserializeMethod extends Method {
+class NetDataContractSerializerDeserializeMethod extends Method, UnsafeDeserializer {
NetDataContractSerializerDeserializeMethod() {
this.getDeclaringType() instanceof NetDataContractSerializerClass and
this.hasName("Deserialize")
}
}
-class NetDataContractSerializerReadObjectMethod extends Method {
+class NetDataContractSerializerReadObjectMethod extends Method, UnsafeDeserializer {
NetDataContractSerializerReadObjectMethod() {
this.getDeclaringType() instanceof NetDataContractSerializerClass and
this.hasName("ReadObject")
@@ -232,7 +235,7 @@ class DataContractJsonSerializerClass extends Class {
}
}
-class DataContractJsonSerializerReadObjectMethod extends Method {
+class DataContractJsonSerializerReadObjectMethod extends Method, UnsafeDeserializer {
DataContractJsonSerializerReadObjectMethod() {
this.getDeclaringType() instanceof DataContractJsonSerializerClass and
this.hasName("ReadObject")
@@ -246,14 +249,14 @@ class JavaScriptSerializerClass extends Class {
}
}
-class JavaScriptSerializerClassDeserializeMethod extends Method {
+class JavaScriptSerializerClassDeserializeMethod extends Method, UnsafeDeserializer {
JavaScriptSerializerClassDeserializeMethod() {
this.getDeclaringType() instanceof JavaScriptSerializerClass and
this.hasName("Deserialize")
}
}
-class JavaScriptSerializerClassDeserializeObjectMethod extends Method {
+class JavaScriptSerializerClassDeserializeObjectMethod extends Method, UnsafeDeserializer {
JavaScriptSerializerClassDeserializeObjectMethod() {
this.getDeclaringType() instanceof JavaScriptSerializerClass and
this.hasName("DeserializeObject")
@@ -267,7 +270,7 @@ class XmlObjectSerializerClass extends Class {
}
}
-class XmlObjectSerializerReadObjectMethod extends Method {
+class XmlObjectSerializerReadObjectMethod extends Method, UnsafeDeserializer {
XmlObjectSerializerReadObjectMethod() {
this.getDeclaringType() instanceof XmlObjectSerializerClass and
this.hasName("ReadObject")
@@ -279,7 +282,7 @@ class XmlSerializerClass extends Class {
XmlSerializerClass() { this.hasQualifiedName("System.Xml.Serialization.XmlSerializer") }
}
-class XmlSerializerDeserializeMethod extends Method {
+class XmlSerializerDeserializeMethod extends Method, UnsafeDeserializer {
XmlSerializerDeserializeMethod() {
this.getDeclaringType() instanceof XmlSerializerClass and
this.hasName("Deserialize")
@@ -293,7 +296,7 @@ class DataContractSerializerClass extends Class {
}
}
-class DataContractSerializerReadObjectMethod extends Method {
+class DataContractSerializerReadObjectMethod extends Method, UnsafeDeserializer {
DataContractSerializerReadObjectMethod() {
this.getDeclaringType() instanceof DataContractSerializerClass and
this.hasName("ReadObject")
@@ -305,7 +308,7 @@ class XmlMessageFormatterClass extends Class {
XmlMessageFormatterClass() { this.hasQualifiedName("System.Messaging.XmlMessageFormatter") }
}
-class XmlMessageFormatterReadMethod extends Method {
+class XmlMessageFormatterReadMethod extends Method, UnsafeDeserializer {
XmlMessageFormatterReadMethod() {
this.getDeclaringType() instanceof XmlMessageFormatterClass and
this.hasName("Read")
@@ -317,7 +320,7 @@ class LosFormatterClass extends Class {
LosFormatterClass() { this.hasQualifiedName("System.Web.UI.LosFormatter") }
}
-class LosFormatterDeserializeMethod extends Method {
+class LosFormatterDeserializeMethod extends Method, UnsafeDeserializer {
LosFormatterDeserializeMethod() {
this.getDeclaringType() instanceof LosFormatterClass and
this.hasName("Deserialize")
@@ -329,7 +332,7 @@ class FastJsonClass extends Class {
FastJsonClass() { this.hasQualifiedName("fastJSON.JSON") }
}
-class FastJsonClassToObjectMethod extends Method {
+class FastJsonClassToObjectMethod extends Method, UnsafeDeserializer {
FastJsonClassToObjectMethod() {
this.getDeclaringType() instanceof FastJsonClass and
this.hasName("ToObject") and
@@ -342,7 +345,7 @@ class ActivityClass extends Class {
ActivityClass() { this.hasQualifiedName("System.Workflow.ComponentModel.Activity") }
}
-class ActivityLoadMethod extends Method {
+class ActivityLoadMethod extends Method, UnsafeDeserializer {
ActivityLoadMethod() {
this.getDeclaringType() instanceof ActivityClass and
this.hasName("Load")
@@ -354,7 +357,7 @@ class ResourceReaderClass extends Class {
ResourceReaderClass() { this.hasQualifiedName("System.Resources.ResourceReader") }
}
-class ResourceReaderConstructor extends Constructor {
+class ResourceReaderConstructor extends Constructor, UnsafeDeserializer {
ResourceReaderConstructor() {
this.getDeclaringType() instanceof ResourceReaderClass and
this.hasName("ResourceReader")
@@ -366,7 +369,7 @@ class BinaryMessageFormatterClass extends Class {
BinaryMessageFormatterClass() { this.hasQualifiedName("System.Messaging.BinaryMessageFormatter") }
}
-class BinaryMessageFormatterReadMethod extends Method {
+class BinaryMessageFormatterReadMethod extends Method, UnsafeDeserializer {
BinaryMessageFormatterReadMethod() {
this.getDeclaringType() instanceof BinaryMessageFormatterClass and
this.hasName("Read")
@@ -378,7 +381,7 @@ class XamlReaderClass extends Class {
XamlReaderClass() { this.hasQualifiedName("System.Windows.Markup.XamlReader") }
}
-class XamlReaderParseMethod extends Method {
+class XamlReaderParseMethod extends Method, UnsafeDeserializer {
XamlReaderParseMethod() {
this.getDeclaringType() instanceof XamlReaderClass and
this.hasName("Parse") and
@@ -386,7 +389,7 @@ class XamlReaderParseMethod extends Method {
}
}
-class XamlReaderLoadMethod extends Method {
+class XamlReaderLoadMethod extends Method, UnsafeDeserializer {
XamlReaderLoadMethod() {
this.getDeclaringType() instanceof XamlReaderClass and
this.hasName("Load") and
@@ -394,7 +397,7 @@ class XamlReaderLoadMethod extends Method {
}
}
-class XamlReaderLoadAsyncMethod extends Method {
+class XamlReaderLoadAsyncMethod extends Method, UnsafeDeserializer {
XamlReaderLoadAsyncMethod() {
this.getDeclaringType() instanceof XamlReaderClass and
this.hasName("LoadAsync")
@@ -406,14 +409,14 @@ class ProxyObjectClass extends Class {
ProxyObjectClass() { this.hasQualifiedName("Microsoft.Web.Design.Remote.ProxyObject") }
}
-class ProxyObjectDecodeValueMethod extends Method {
+class ProxyObjectDecodeValueMethod extends Method, UnsafeDeserializer {
ProxyObjectDecodeValueMethod() {
this.getDeclaringType() instanceof ProxyObjectClass and
this.hasName("DecodeValue")
}
}
-class ProxyObjectDecodeSerializedObjectMethod extends Method {
+class ProxyObjectDecodeSerializedObjectMethod extends Method, UnsafeDeserializer {
ProxyObjectDecodeSerializedObjectMethod() {
this.getDeclaringType() instanceof ProxyObjectClass and
this.hasName("DecodeSerializedObject")
@@ -425,7 +428,7 @@ class JaysonConverterClass extends Class {
JaysonConverterClass() { this.hasQualifiedName("Sweet.Jayson.JaysonConverter") }
}
-class JaysonConverterToObjectMethod extends Method {
+class JaysonConverterToObjectMethod extends Method, UnsafeDeserializer {
JaysonConverterToObjectMethod() {
this.getDeclaringType() instanceof JaysonConverterClass and
this.hasName("ToObject") and
@@ -440,7 +443,7 @@ class ServiceStackTextJsonSerializerClass extends Class {
}
}
-class ServiceStackTextJsonSerializerDeserializeFromStringMethod extends Method {
+class ServiceStackTextJsonSerializerDeserializeFromStringMethod extends Method, UnsafeDeserializer {
ServiceStackTextJsonSerializerDeserializeFromStringMethod() {
this.getDeclaringType() instanceof ServiceStackTextJsonSerializerClass and
this.hasName("DeserializeFromString") and
@@ -448,7 +451,7 @@ class ServiceStackTextJsonSerializerDeserializeFromStringMethod extends Method {
}
}
-class ServiceStackTextJsonSerializerDeserializeFromReaderMethod extends Method {
+class ServiceStackTextJsonSerializerDeserializeFromReaderMethod extends Method, UnsafeDeserializer {
ServiceStackTextJsonSerializerDeserializeFromReaderMethod() {
this.getDeclaringType() instanceof ServiceStackTextJsonSerializerClass and
this.hasName("DeserializeFromReader") and
@@ -456,7 +459,7 @@ class ServiceStackTextJsonSerializerDeserializeFromReaderMethod extends Method {
}
}
-class ServiceStackTextJsonSerializerDeserializeFromStreamMethod extends Method {
+class ServiceStackTextJsonSerializerDeserializeFromStreamMethod extends Method, UnsafeDeserializer {
ServiceStackTextJsonSerializerDeserializeFromStreamMethod() {
this.getDeclaringType() instanceof ServiceStackTextJsonSerializerClass and
this.hasName("DeserializeFromStream") and
@@ -471,7 +474,7 @@ class ServiceStackTextTypeSerializerClass extends Class {
}
}
-class ServiceStackTextTypeSerializerDeserializeFromStringMethod extends Method {
+class ServiceStackTextTypeSerializerDeserializeFromStringMethod extends Method, UnsafeDeserializer {
ServiceStackTextTypeSerializerDeserializeFromStringMethod() {
this.getDeclaringType() instanceof ServiceStackTextTypeSerializerClass and
this.hasName("DeserializeFromString") and
@@ -479,7 +482,7 @@ class ServiceStackTextTypeSerializerDeserializeFromStringMethod extends Method {
}
}
-class ServiceStackTextTypeSerializerDeserializeFromReaderMethod extends Method {
+class ServiceStackTextTypeSerializerDeserializeFromReaderMethod extends Method, UnsafeDeserializer {
ServiceStackTextTypeSerializerDeserializeFromReaderMethod() {
this.getDeclaringType() instanceof ServiceStackTextTypeSerializerClass and
this.hasName("DeserializeFromReader") and
@@ -487,7 +490,7 @@ class ServiceStackTextTypeSerializerDeserializeFromReaderMethod extends Method {
}
}
-class ServiceStackTextTypeSerializerDeserializeFromStreamMethod extends Method {
+class ServiceStackTextTypeSerializerDeserializeFromStreamMethod extends Method, UnsafeDeserializer {
ServiceStackTextTypeSerializerDeserializeFromStreamMethod() {
this.getDeclaringType() instanceof ServiceStackTextTypeSerializerClass and
this.hasName("DeserializeFromStream") and
@@ -500,7 +503,7 @@ class ServiceStackTextCsvSerializerClass extends Class {
ServiceStackTextCsvSerializerClass() { this.hasQualifiedName("ServiceStack.Text.CsvSerializer") }
}
-class ServiceStackTextCsvSerializerDeserializeFromStringMethod extends Method {
+class ServiceStackTextCsvSerializerDeserializeFromStringMethod extends Method, UnsafeDeserializer {
ServiceStackTextCsvSerializerDeserializeFromStringMethod() {
this.getDeclaringType() instanceof ServiceStackTextCsvSerializerClass and
this.hasName("DeserializeFromString") and
@@ -508,7 +511,7 @@ class ServiceStackTextCsvSerializerDeserializeFromStringMethod extends Method {
}
}
-class ServiceStackTextCsvSerializerDeserializeFromReaderMethod extends Method {
+class ServiceStackTextCsvSerializerDeserializeFromReaderMethod extends Method, UnsafeDeserializer {
ServiceStackTextCsvSerializerDeserializeFromReaderMethod() {
this.getDeclaringType() instanceof ServiceStackTextCsvSerializerClass and
this.hasName("DeserializeFromReader") and
@@ -516,7 +519,7 @@ class ServiceStackTextCsvSerializerDeserializeFromReaderMethod extends Method {
}
}
-class ServiceStackTextCsvSerializerDeserializeFromStreamMethod extends Method {
+class ServiceStackTextCsvSerializerDeserializeFromStreamMethod extends Method, UnsafeDeserializer {
ServiceStackTextCsvSerializerDeserializeFromStreamMethod() {
this.getDeclaringType() instanceof ServiceStackTextCsvSerializerClass and
this.hasName("DeserializeFromStream") and
@@ -529,7 +532,7 @@ class ServiceStackTextXmlSerializerClass extends Class {
ServiceStackTextXmlSerializerClass() { this.hasQualifiedName("ServiceStack.Text.XmlSerializer") }
}
-class ServiceStackTextXmlSerializerDeserializeFromStringMethod extends Method {
+class ServiceStackTextXmlSerializerDeserializeFromStringMethod extends Method, UnsafeDeserializer {
ServiceStackTextXmlSerializerDeserializeFromStringMethod() {
this.getDeclaringType() instanceof ServiceStackTextXmlSerializerClass and
this.hasName("DeserializeFromString") and
@@ -537,7 +540,7 @@ class ServiceStackTextXmlSerializerDeserializeFromStringMethod extends Method {
}
}
-class ServiceStackTextXmlSerializerDeserializeFromReaderMethod extends Method {
+class ServiceStackTextXmlSerializerDeserializeFromReaderMethod extends Method, UnsafeDeserializer {
ServiceStackTextXmlSerializerDeserializeFromReaderMethod() {
this.getDeclaringType() instanceof ServiceStackTextXmlSerializerClass and
this.hasName("DeserializeFromReader") and
@@ -545,7 +548,7 @@ class ServiceStackTextXmlSerializerDeserializeFromReaderMethod extends Method {
}
}
-class ServiceStackTextXmlSerializerDeserializeFromStreamMethod extends Method {
+class ServiceStackTextXmlSerializerDeserializeFromStreamMethod extends Method, UnsafeDeserializer {
ServiceStackTextXmlSerializerDeserializeFromStreamMethod() {
this.getDeclaringType() instanceof ServiceStackTextXmlSerializerClass and
this.hasName("DeserializeFromStream") and
From c3deb48efab9e440a051d93542899c0dc89b848c Mon Sep 17 00:00:00 2001
From: edvraa <80588099+edvraa@users.noreply.github.com>
Date: Fri, 16 Apr 2021 17:19:42 +0300
Subject: [PATCH 050/429] Charpred for InstanceMethodSink
---
.../CWE-502/UnsafeDeserialization.ql | 12 +---
.../dataflow/UnsafeDeserialization.qll | 64 ++++++++++++-------
...safeDeserializationUntrustedInput.expected | 28 --------
3 files changed, 41 insertions(+), 63 deletions(-)
diff --git a/csharp/ql/src/Security Features/CWE-502/UnsafeDeserialization.ql b/csharp/ql/src/Security Features/CWE-502/UnsafeDeserialization.ql
index 3f5862795e3..e7c3eb2b4e9 100644
--- a/csharp/ql/src/Security Features/CWE-502/UnsafeDeserialization.ql
+++ b/csharp/ql/src/Security Features/CWE-502/UnsafeDeserialization.ql
@@ -16,16 +16,6 @@ import semmle.code.csharp.security.dataflow.UnsafeDeserialization::UnsafeDeseria
from Call deserializeCall, DataFlow::Node sink
where
deserializeCall.getAnArgument() = sink.asExpr() and
- (
- sink instanceof InstanceMethodSink and
- not exists(
- SafeConstructorTrackingConfig safeConstructorTracking, DataFlow::Node safeTypeUsage
- |
- safeConstructorTracking.hasFlow(_, safeTypeUsage) and
- safeTypeUsage.asExpr().getParent() = deserializeCall
- )
- or
- sink instanceof ConstructorOrStaticMethodSink
- )
+ sink instanceof Sink
select deserializeCall,
"Unsafe deserializer is used. Make sure the value being deserialized comes from a trusted source."
diff --git a/csharp/ql/src/semmle/code/csharp/security/dataflow/UnsafeDeserialization.qll b/csharp/ql/src/semmle/code/csharp/security/dataflow/UnsafeDeserialization.qll
index ec7b4e52b49..753d2c457e4 100644
--- a/csharp/ql/src/semmle/code/csharp/security/dataflow/UnsafeDeserialization.qll
+++ b/csharp/ql/src/semmle/code/csharp/security/dataflow/UnsafeDeserialization.qll
@@ -14,15 +14,29 @@ module UnsafeDeserialization {
*/
abstract class Source extends DataFlow::Node { }
+ /**
+ * A data flow sink for unsafe deserialization vulnerabilities.
+ */
+ abstract class Sink extends DataFlow::Node { }
+
/**
* A data flow sink for unsafe deserialization vulnerabilities to an instance method.
*/
- abstract class InstanceMethodSink extends DataFlow::Node { }
+ abstract private class InstanceMethodSink extends Sink {
+ InstanceMethodSink() {
+ not exists(
+ SafeConstructorTrackingConfig safeConstructorTracking, DataFlow::Node safeTypeUsage
+ |
+ safeConstructorTracking.hasFlow(_, safeTypeUsage) and
+ safeTypeUsage.asExpr().getParent() = this.asExpr().getParent()
+ )
+ }
+ }
/**
* A data flow sink for unsafe deserialization vulnerabilities to a static method or constructor call.
*/
- abstract class ConstructorOrStaticMethodSink extends DataFlow::Node { }
+ abstract private class ConstructorOrStaticMethodSink extends Sink { }
/**
* A sanitizer for unsafe deserialization vulnerabilities.
@@ -132,7 +146,7 @@ module UnsafeDeserialization {
)
}
- private abstract class BinaryFormatterSink extends InstanceMethodSink { }
+ abstract private class BinaryFormatterSink extends InstanceMethodSink { }
private class BinaryFormatterDeserializeMethodSink extends BinaryFormatterSink {
BinaryFormatterDeserializeMethodSink() {
@@ -150,7 +164,7 @@ module UnsafeDeserialization {
not mc.getArgument(0).hasValue()
}
- private abstract class SoapFormatterSink extends InstanceMethodSink { }
+ abstract private class SoapFormatterSink extends InstanceMethodSink { }
private class SoapFormatterDeserializeMethodSink extends SoapFormatterSink {
SoapFormatterDeserializeMethodSink() {
@@ -168,7 +182,7 @@ module UnsafeDeserialization {
not mc.getArgument(0).hasValue()
}
- private abstract class ObjectStateFormatterSink extends InstanceMethodSink { }
+ abstract private class ObjectStateFormatterSink extends InstanceMethodSink { }
private class ObjectStateFormatterDeserializeMethodSink extends ObjectStateFormatterSink {
ObjectStateFormatterDeserializeMethodSink() {
@@ -191,7 +205,7 @@ module UnsafeDeserialization {
)
}
- private abstract class NetDataContractSerializerSink extends InstanceMethodSink { }
+ abstract private class NetDataContractSerializerSink extends InstanceMethodSink { }
private class NetDataContractSerializerDeserializeMethodSink extends NetDataContractSerializerSink {
NetDataContractSerializerDeserializeMethodSink() {
@@ -209,7 +223,7 @@ module UnsafeDeserialization {
not mc.getArgument(0).hasValue()
}
- private abstract class DataContractJsonSerializerSink extends InstanceMethodSink { }
+ abstract private class DataContractJsonSerializerSink extends InstanceMethodSink { }
private class DataContractJsonSerializerDeserializeMethodSink extends DataContractJsonSerializerSink {
DataContractJsonSerializerDeserializeMethodSink() {
@@ -252,7 +266,7 @@ module UnsafeDeserialization {
)
}
- private abstract class JavaScriptSerializerSink extends InstanceMethodSink { }
+ abstract private class JavaScriptSerializerSink extends InstanceMethodSink { }
private class JavaScriptSerializerDeserializeMethodSink extends JavaScriptSerializerSink {
JavaScriptSerializerDeserializeMethodSink() {
@@ -290,7 +304,7 @@ module UnsafeDeserialization {
not mc.targetIsLocalInstance()
}
- private abstract class XmlObjectSerializerSink extends InstanceMethodSink { }
+ abstract private class XmlObjectSerializerSink extends InstanceMethodSink { }
private class XmlObjectSerializerDeserializeMethodSink extends XmlObjectSerializerSink {
XmlObjectSerializerDeserializeMethodSink() {
@@ -332,7 +346,7 @@ module UnsafeDeserialization {
not mc.getArgument(0).hasValue()
}
- private abstract class XmlSerializerSink extends InstanceMethodSink { }
+ abstract private class XmlSerializerSink extends InstanceMethodSink { }
private class XmlSerializerDeserializeMethodSink extends XmlSerializerSink {
XmlSerializerDeserializeMethodSink() {
@@ -373,7 +387,7 @@ module UnsafeDeserialization {
not mc.getArgument(0).hasValue()
}
- private abstract class DataContractSerializerSink extends InstanceMethodSink { }
+ abstract private class DataContractSerializerSink extends InstanceMethodSink { }
private class DataContractSerializerDeserializeMethodSink extends DataContractSerializerSink {
DataContractSerializerDeserializeMethodSink() {
@@ -411,7 +425,7 @@ module UnsafeDeserialization {
not mc.getArgument(0).hasValue()
}
- private abstract class XmlMessageFormatterSink extends InstanceMethodSink { }
+ abstract private class XmlMessageFormatterSink extends InstanceMethodSink { }
private class XmlMessageFormatterDeserializeMethodSink extends XmlMessageFormatterSink {
XmlMessageFormatterDeserializeMethodSink() {
@@ -449,7 +463,7 @@ module UnsafeDeserialization {
not mc.getArgument(0).hasValue()
}
- private abstract class LosFormatterSink extends InstanceMethodSink { }
+ abstract private class LosFormatterSink extends InstanceMethodSink { }
private class LosFormatterDeserializeMethodSink extends LosFormatterSink {
LosFormatterDeserializeMethodSink() {
@@ -467,7 +481,7 @@ module UnsafeDeserialization {
not mc.getArgument(0).hasValue()
}
- private abstract class FastJsonSink extends ConstructorOrStaticMethodSink { }
+ abstract private class FastJsonSink extends ConstructorOrStaticMethodSink { }
private class FastJsonDeserializeMethodSink extends FastJsonSink {
FastJsonDeserializeMethodSink() {
@@ -485,7 +499,7 @@ module UnsafeDeserialization {
not mc.getArgument(0).hasValue()
}
- private abstract class ActivitySink extends InstanceMethodSink { }
+ abstract private class ActivitySink extends InstanceMethodSink { }
private class ActivityDeserializeMethodSink extends ActivitySink {
ActivityDeserializeMethodSink() {
@@ -503,7 +517,7 @@ module UnsafeDeserialization {
not mc.getArgument(0).hasValue()
}
- private abstract class ResourceReaderSink extends ConstructorOrStaticMethodSink { }
+ abstract private class ResourceReaderSink extends ConstructorOrStaticMethodSink { }
private class ResourceReaderDeserializeMethodSink extends ResourceReaderSink {
ResourceReaderDeserializeMethodSink() {
@@ -521,7 +535,7 @@ module UnsafeDeserialization {
not mc.getArgument(0).hasValue()
}
- private abstract class BinaryMessageFormatterSink extends InstanceMethodSink { }
+ abstract private class BinaryMessageFormatterSink extends InstanceMethodSink { }
private class BinaryMessageFormatterDeserializeMethodSink extends BinaryMessageFormatterSink {
BinaryMessageFormatterDeserializeMethodSink() {
@@ -545,7 +559,7 @@ module UnsafeDeserialization {
not mc.getArgument(0).hasValue()
}
- private abstract class XamlReaderSink extends ConstructorOrStaticMethodSink { }
+ abstract private class XamlReaderSink extends ConstructorOrStaticMethodSink { }
private class XamlReaderDeserializeMethodSink extends XamlReaderSink {
XamlReaderDeserializeMethodSink() {
@@ -567,7 +581,7 @@ module UnsafeDeserialization {
not mc.getArgument(0).hasValue()
}
- private abstract class ProxyObjectSink extends InstanceMethodSink { }
+ abstract private class ProxyObjectSink extends InstanceMethodSink { }
private class ProxyObjectDeserializeMethodSink extends ProxyObjectSink {
ProxyObjectDeserializeMethodSink() {
@@ -585,7 +599,7 @@ module UnsafeDeserialization {
not mc.getArgument(0).hasValue()
}
- private abstract class SweetJaysonSink extends ConstructorOrStaticMethodSink { }
+ abstract private class SweetJaysonSink extends ConstructorOrStaticMethodSink { }
private class SweetJaysonDeserializeMethodSink extends SweetJaysonSink {
SweetJaysonDeserializeMethodSink() {
@@ -597,7 +611,8 @@ module UnsafeDeserialization {
}
/** ServiceStack.Text.JsonSerializer */
- private abstract class ServiceStackTextJsonSerializerSink extends ConstructorOrStaticMethodSink { }
+ abstract private class ServiceStackTextJsonSerializerSink extends ConstructorOrStaticMethodSink {
+ }
private class ServiceStackTextJsonSerializerDeserializeMethodSink extends ServiceStackTextJsonSerializerSink {
ServiceStackTextJsonSerializerDeserializeMethodSink() {
@@ -618,7 +633,8 @@ module UnsafeDeserialization {
}
/** ServiceStack.Text.TypeSerializer */
- private abstract class ServiceStackTextTypeSerializerSink extends ConstructorOrStaticMethodSink { }
+ abstract private class ServiceStackTextTypeSerializerSink extends ConstructorOrStaticMethodSink {
+ }
private class ServiceStackTextTypeSerializerDeserializeMethodSink extends ServiceStackTextTypeSerializerSink {
ServiceStackTextTypeSerializerDeserializeMethodSink() {
@@ -639,7 +655,7 @@ module UnsafeDeserialization {
}
/** ServiceStack.Text.CsvSerializer */
- private abstract class ServiceStackTextCsvSerializerSink extends ConstructorOrStaticMethodSink { }
+ abstract private class ServiceStackTextCsvSerializerSink extends ConstructorOrStaticMethodSink { }
private class ServiceStackTextCsvSerializerDeserializeMethodSink extends ServiceStackTextCsvSerializerSink {
ServiceStackTextCsvSerializerDeserializeMethodSink() {
@@ -660,7 +676,7 @@ module UnsafeDeserialization {
}
/** ServiceStack.Text.XmlSerializer */
- private abstract class ServiceStackTextXmlSerializerSink extends ConstructorOrStaticMethodSink { }
+ abstract private class ServiceStackTextXmlSerializerSink extends ConstructorOrStaticMethodSink { }
private class ServiceStackTextXmlSerializerDeserializeMethodSink extends ServiceStackTextXmlSerializerSink {
ServiceStackTextXmlSerializerDeserializeMethodSink() {
diff --git a/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserializationUntrustedInput/UnsafeDeserializationUntrustedInput.expected b/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserializationUntrustedInput/UnsafeDeserializationUntrustedInput.expected
index 5ad68adabc8..7d36370b2e3 100644
--- a/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserializationUntrustedInput/UnsafeDeserializationUntrustedInput.expected
+++ b/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserializationUntrustedInput/UnsafeDeserializationUntrustedInput.expected
@@ -5,15 +5,9 @@ edges
| DataContractJsonSerializerUntrustedInputBad.cs:13:47:13:79 | call to method GetBytes : Byte[] | DataContractJsonSerializerUntrustedInputBad.cs:13:30:13:80 | object creation of type MemoryStream |
| DataContractJsonSerializerUntrustedInputBad.cs:13:70:13:73 | access to parameter data : TextBox | DataContractJsonSerializerUntrustedInputBad.cs:13:70:13:78 | access to property Text : String |
| DataContractJsonSerializerUntrustedInputBad.cs:13:70:13:78 | access to property Text : String | DataContractJsonSerializerUntrustedInputBad.cs:13:47:13:79 | call to method GetBytes : Byte[] |
-| DataContractJsonSerializerUntrustedInputGood.cs:13:47:13:79 | call to method GetBytes : Byte[] | DataContractJsonSerializerUntrustedInputGood.cs:13:30:13:80 | object creation of type MemoryStream |
-| DataContractJsonSerializerUntrustedInputGood.cs:13:70:13:73 | access to parameter data : TextBox | DataContractJsonSerializerUntrustedInputGood.cs:13:70:13:78 | access to property Text : String |
-| DataContractJsonSerializerUntrustedInputGood.cs:13:70:13:78 | access to property Text : String | DataContractJsonSerializerUntrustedInputGood.cs:13:47:13:79 | call to method GetBytes : Byte[] |
| DataContractSerializerUntrustedInputBad.cs:13:47:13:79 | call to method GetBytes : Byte[] | DataContractSerializerUntrustedInputBad.cs:13:30:13:80 | object creation of type MemoryStream |
| DataContractSerializerUntrustedInputBad.cs:13:70:13:73 | access to parameter data : TextBox | DataContractSerializerUntrustedInputBad.cs:13:70:13:78 | access to property Text : String |
| DataContractSerializerUntrustedInputBad.cs:13:70:13:78 | access to property Text : String | DataContractSerializerUntrustedInputBad.cs:13:47:13:79 | call to method GetBytes : Byte[] |
-| DataContractSerializerUntrustedInputGood.cs:13:47:13:79 | call to method GetBytes : Byte[] | DataContractSerializerUntrustedInputGood.cs:13:30:13:80 | object creation of type MemoryStream |
-| DataContractSerializerUntrustedInputGood.cs:13:70:13:73 | access to parameter data : TextBox | DataContractSerializerUntrustedInputGood.cs:13:70:13:78 | access to property Text : String |
-| DataContractSerializerUntrustedInputGood.cs:13:70:13:78 | access to property Text : String | DataContractSerializerUntrustedInputGood.cs:13:47:13:79 | call to method GetBytes : Byte[] |
| ResourceReaderUntrustedInputBad.cs:11:54:11:86 | call to method GetBytes : Byte[] | ResourceReaderUntrustedInputBad.cs:11:37:11:87 | object creation of type MemoryStream |
| ResourceReaderUntrustedInputBad.cs:11:77:11:80 | access to parameter data : TextBox | ResourceReaderUntrustedInputBad.cs:11:77:11:85 | access to property Text : String |
| ResourceReaderUntrustedInputBad.cs:11:77:11:85 | access to property Text : String | ResourceReaderUntrustedInputBad.cs:11:54:11:86 | call to method GetBytes : Byte[] |
@@ -21,15 +15,9 @@ edges
| XmlObjectSerializerUntrustedInputBad.cs:13:47:13:79 | call to method GetBytes : Byte[] | XmlObjectSerializerUntrustedInputBad.cs:13:30:13:80 | object creation of type MemoryStream |
| XmlObjectSerializerUntrustedInputBad.cs:13:70:13:73 | access to parameter data : TextBox | XmlObjectSerializerUntrustedInputBad.cs:13:70:13:78 | access to property Text : String |
| XmlObjectSerializerUntrustedInputBad.cs:13:70:13:78 | access to property Text : String | XmlObjectSerializerUntrustedInputBad.cs:13:47:13:79 | call to method GetBytes : Byte[] |
-| XmlObjectSerializerUntrustedInputGood.cs:13:47:13:79 | call to method GetBytes : Byte[] | XmlObjectSerializerUntrustedInputGood.cs:13:30:13:80 | object creation of type MemoryStream |
-| XmlObjectSerializerUntrustedInputGood.cs:13:70:13:73 | access to parameter data : TextBox | XmlObjectSerializerUntrustedInputGood.cs:13:70:13:78 | access to property Text : String |
-| XmlObjectSerializerUntrustedInputGood.cs:13:70:13:78 | access to property Text : String | XmlObjectSerializerUntrustedInputGood.cs:13:47:13:79 | call to method GetBytes : Byte[] |
| XmlSerializerUntrustedInputBad.cs:13:48:13:80 | call to method GetBytes : Byte[] | XmlSerializerUntrustedInputBad.cs:13:31:13:81 | object creation of type MemoryStream |
| XmlSerializerUntrustedInputBad.cs:13:71:13:74 | access to parameter data : TextBox | XmlSerializerUntrustedInputBad.cs:13:71:13:79 | access to property Text : String |
| XmlSerializerUntrustedInputBad.cs:13:71:13:79 | access to property Text : String | XmlSerializerUntrustedInputBad.cs:13:48:13:80 | call to method GetBytes : Byte[] |
-| XmlSerializerUntrustedInputGood.cs:13:48:13:80 | call to method GetBytes : Byte[] | XmlSerializerUntrustedInputGood.cs:13:31:13:81 | object creation of type MemoryStream |
-| XmlSerializerUntrustedInputGood.cs:13:71:13:74 | access to parameter data : TextBox | XmlSerializerUntrustedInputGood.cs:13:71:13:79 | access to property Text : String |
-| XmlSerializerUntrustedInputGood.cs:13:71:13:79 | access to property Text : String | XmlSerializerUntrustedInputGood.cs:13:48:13:80 | call to method GetBytes : Byte[] |
nodes
| BinaryFormatterUntrustedInputBad.cs:12:31:12:84 | object creation of type MemoryStream | semmle.label | object creation of type MemoryStream |
| BinaryFormatterUntrustedInputBad.cs:12:48:12:83 | call to method GetBytes : Byte[] | semmle.label | call to method GetBytes : Byte[] |
@@ -39,18 +27,10 @@ nodes
| DataContractJsonSerializerUntrustedInputBad.cs:13:47:13:79 | call to method GetBytes : Byte[] | semmle.label | call to method GetBytes : Byte[] |
| DataContractJsonSerializerUntrustedInputBad.cs:13:70:13:73 | access to parameter data : TextBox | semmle.label | access to parameter data : TextBox |
| DataContractJsonSerializerUntrustedInputBad.cs:13:70:13:78 | access to property Text : String | semmle.label | access to property Text : String |
-| DataContractJsonSerializerUntrustedInputGood.cs:13:30:13:80 | object creation of type MemoryStream | semmle.label | object creation of type MemoryStream |
-| DataContractJsonSerializerUntrustedInputGood.cs:13:47:13:79 | call to method GetBytes : Byte[] | semmle.label | call to method GetBytes : Byte[] |
-| DataContractJsonSerializerUntrustedInputGood.cs:13:70:13:73 | access to parameter data : TextBox | semmle.label | access to parameter data : TextBox |
-| DataContractJsonSerializerUntrustedInputGood.cs:13:70:13:78 | access to property Text : String | semmle.label | access to property Text : String |
| DataContractSerializerUntrustedInputBad.cs:13:30:13:80 | object creation of type MemoryStream | semmle.label | object creation of type MemoryStream |
| DataContractSerializerUntrustedInputBad.cs:13:47:13:79 | call to method GetBytes : Byte[] | semmle.label | call to method GetBytes : Byte[] |
| DataContractSerializerUntrustedInputBad.cs:13:70:13:73 | access to parameter data : TextBox | semmle.label | access to parameter data : TextBox |
| DataContractSerializerUntrustedInputBad.cs:13:70:13:78 | access to property Text : String | semmle.label | access to property Text : String |
-| DataContractSerializerUntrustedInputGood.cs:13:30:13:80 | object creation of type MemoryStream | semmle.label | object creation of type MemoryStream |
-| DataContractSerializerUntrustedInputGood.cs:13:47:13:79 | call to method GetBytes : Byte[] | semmle.label | call to method GetBytes : Byte[] |
-| DataContractSerializerUntrustedInputGood.cs:13:70:13:73 | access to parameter data : TextBox | semmle.label | access to parameter data : TextBox |
-| DataContractSerializerUntrustedInputGood.cs:13:70:13:78 | access to property Text : String | semmle.label | access to property Text : String |
| ResourceReaderUntrustedInputBad.cs:11:37:11:87 | object creation of type MemoryStream | semmle.label | object creation of type MemoryStream |
| ResourceReaderUntrustedInputBad.cs:11:54:11:86 | call to method GetBytes : Byte[] | semmle.label | call to method GetBytes : Byte[] |
| ResourceReaderUntrustedInputBad.cs:11:77:11:80 | access to parameter data : TextBox | semmle.label | access to parameter data : TextBox |
@@ -61,18 +41,10 @@ nodes
| XmlObjectSerializerUntrustedInputBad.cs:13:47:13:79 | call to method GetBytes : Byte[] | semmle.label | call to method GetBytes : Byte[] |
| XmlObjectSerializerUntrustedInputBad.cs:13:70:13:73 | access to parameter data : TextBox | semmle.label | access to parameter data : TextBox |
| XmlObjectSerializerUntrustedInputBad.cs:13:70:13:78 | access to property Text : String | semmle.label | access to property Text : String |
-| XmlObjectSerializerUntrustedInputGood.cs:13:30:13:80 | object creation of type MemoryStream | semmle.label | object creation of type MemoryStream |
-| XmlObjectSerializerUntrustedInputGood.cs:13:47:13:79 | call to method GetBytes : Byte[] | semmle.label | call to method GetBytes : Byte[] |
-| XmlObjectSerializerUntrustedInputGood.cs:13:70:13:73 | access to parameter data : TextBox | semmle.label | access to parameter data : TextBox |
-| XmlObjectSerializerUntrustedInputGood.cs:13:70:13:78 | access to property Text : String | semmle.label | access to property Text : String |
| XmlSerializerUntrustedInputBad.cs:13:31:13:81 | object creation of type MemoryStream | semmle.label | object creation of type MemoryStream |
| XmlSerializerUntrustedInputBad.cs:13:48:13:80 | call to method GetBytes : Byte[] | semmle.label | call to method GetBytes : Byte[] |
| XmlSerializerUntrustedInputBad.cs:13:71:13:74 | access to parameter data : TextBox | semmle.label | access to parameter data : TextBox |
| XmlSerializerUntrustedInputBad.cs:13:71:13:79 | access to property Text : String | semmle.label | access to property Text : String |
-| XmlSerializerUntrustedInputGood.cs:13:31:13:81 | object creation of type MemoryStream | semmle.label | object creation of type MemoryStream |
-| XmlSerializerUntrustedInputGood.cs:13:48:13:80 | call to method GetBytes : Byte[] | semmle.label | call to method GetBytes : Byte[] |
-| XmlSerializerUntrustedInputGood.cs:13:71:13:74 | access to parameter data : TextBox | semmle.label | access to parameter data : TextBox |
-| XmlSerializerUntrustedInputGood.cs:13:71:13:79 | access to property Text : String | semmle.label | access to property Text : String |
#select
| BinaryFormatterUntrustedInputBad.cs:12:31:12:84 | object creation of type MemoryStream | BinaryFormatterUntrustedInputBad.cs:12:71:12:77 | access to parameter textBox : TextBox | BinaryFormatterUntrustedInputBad.cs:12:31:12:84 | object creation of type MemoryStream | $@ flows to unsafe deserializer. | BinaryFormatterUntrustedInputBad.cs:12:71:12:77 | access to parameter textBox : TextBox | User-provided data |
| DataContractJsonSerializerUntrustedInputBad.cs:13:30:13:80 | object creation of type MemoryStream | DataContractJsonSerializerUntrustedInputBad.cs:13:70:13:73 | access to parameter data : TextBox | DataContractJsonSerializerUntrustedInputBad.cs:13:30:13:80 | object creation of type MemoryStream | $@ flows to unsafe deserializer. | DataContractJsonSerializerUntrustedInputBad.cs:13:70:13:73 | access to parameter data : TextBox | User-provided data |
From bbd3552392c5ab978fe8322e703b821389893878 Mon Sep 17 00:00:00 2001
From: thank_you
Date: Tue, 20 Apr 2021 08:47:37 -0400
Subject: [PATCH 051/429] Rename predicate to getQuery
---
python/ql/src/experimental/semmle/python/Concepts.qll | 4 ++--
.../src/experimental/semmle/python/frameworks/Stdlib.qll | 8 ++++----
.../semmle/python/security/injection/NoSQLInjection.qll | 4 +---
3 files changed, 7 insertions(+), 9 deletions(-)
diff --git a/python/ql/src/experimental/semmle/python/Concepts.qll b/python/ql/src/experimental/semmle/python/Concepts.qll
index ff418437f8a..fec3e5c7ea1 100644
--- a/python/ql/src/experimental/semmle/python/Concepts.qll
+++ b/python/ql/src/experimental/semmle/python/Concepts.qll
@@ -16,7 +16,7 @@ private import experimental.semmle.python.Frameworks
module NoSQLQuery {
abstract class Range extends DataFlow::Node {
- abstract DataFlow::Node getQueryNode();
+ abstract DataFlow::Node getQuery();
}
}
@@ -25,7 +25,7 @@ class NoSQLQuery extends DataFlow::Node {
NoSQLQuery() { this = range }
- DataFlow::Node getQueryNode() { result = range.getQueryNode() }
+ DataFlow::Node getQuery() { result = range.getQuery() }
}
module NoSQLSanitizer {
diff --git a/python/ql/src/experimental/semmle/python/frameworks/Stdlib.qll b/python/ql/src/experimental/semmle/python/frameworks/Stdlib.qll
index dc13a50b8dc..4ae1b2b104a 100644
--- a/python/ql/src/experimental/semmle/python/frameworks/Stdlib.qll
+++ b/python/ql/src/experimental/semmle/python/frameworks/Stdlib.qll
@@ -32,7 +32,7 @@ private module NoSQL {
.getACall()
}
- override DataFlow::Node getQueryNode() { result = this.getArg(0) }
+ override DataFlow::Node getQuery() { result = this.getArg(0) }
}
private class PyMongoFlaskMethods extends string {
@@ -50,7 +50,7 @@ private module NoSQL {
.getACall()
}
- override DataFlow::Node getQueryNode() { result = this.getArg(0) }
+ override DataFlow::Node getQuery() { result = this.getArg(0) }
}
private class MongoEngineObjectsCall extends DataFlow::CallCfgNode, NoSQLQuery::Range {
@@ -63,7 +63,7 @@ private module NoSQL {
.getACall()
}
- override DataFlow::Node getQueryNode() { result = this.getArgByName(any(string name)) }
+ override DataFlow::Node getQuery() { result = this.getArgByName(any(string name)) }
}
private class MongoEngineObjectsFlaskCall extends DataFlow::CallCfgNode, NoSQLQuery::Range {
@@ -78,7 +78,7 @@ private module NoSQL {
.getACall()
}
- override DataFlow::Node getQueryNode() { result = this.getArgByName(any(string name)) }
+ override DataFlow::Node getQuery() { result = this.getArgByName(any(string name)) }
}
private class MongoSanitizerCall extends DataFlow::CallCfgNode, NoSQLSanitizer::Range {
diff --git a/python/ql/src/experimental/semmle/python/security/injection/NoSQLInjection.qll b/python/ql/src/experimental/semmle/python/security/injection/NoSQLInjection.qll
index 2f785de4a21..27109bb3439 100644
--- a/python/ql/src/experimental/semmle/python/security/injection/NoSQLInjection.qll
+++ b/python/ql/src/experimental/semmle/python/security/injection/NoSQLInjection.qll
@@ -51,9 +51,7 @@ class FromDataDictToSink extends TaintTracking2::Configuration {
override predicate isSource(DataFlow::Node source) { source instanceof DataToDictSink }
- override predicate isSink(DataFlow::Node sink) {
- sink = any(NoSQLQuery noSQLQuery).getQueryNode()
- }
+ override predicate isSink(DataFlow::Node sink) { sink = any(NoSQLQuery noSQLQuery).getQuery() }
override predicate isSanitizer(DataFlow::Node sanitizer) {
sanitizer = any(NoSQLSanitizer noSQLSanitizer).getSanitizerNode()
From 7773c531248417e7d90c419b05971f1e36ba2792 Mon Sep 17 00:00:00 2001
From: thank_you
Date: Tue, 20 Apr 2021 08:49:08 -0400
Subject: [PATCH 052/429] Replace any(string) with _ wildcard
---
.../ql/src/experimental/semmle/python/frameworks/Stdlib.qll | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/python/ql/src/experimental/semmle/python/frameworks/Stdlib.qll b/python/ql/src/experimental/semmle/python/frameworks/Stdlib.qll
index 4ae1b2b104a..177d7a1a560 100644
--- a/python/ql/src/experimental/semmle/python/frameworks/Stdlib.qll
+++ b/python/ql/src/experimental/semmle/python/frameworks/Stdlib.qll
@@ -63,7 +63,7 @@ private module NoSQL {
.getACall()
}
- override DataFlow::Node getQuery() { result = this.getArgByName(any(string name)) }
+ override DataFlow::Node getQuery() { result = this.getArgByName(_) }
}
private class MongoEngineObjectsFlaskCall extends DataFlow::CallCfgNode, NoSQLQuery::Range {
@@ -78,7 +78,7 @@ private module NoSQL {
.getACall()
}
- override DataFlow::Node getQuery() { result = this.getArgByName(any(string name)) }
+ override DataFlow::Node getQuery() { result = this.getArgByName(_) }
}
private class MongoSanitizerCall extends DataFlow::CallCfgNode, NoSQLSanitizer::Range {
From 3ac5f7bb18aa16b4c99a55bfda7cf5c3e304eb1e Mon Sep 17 00:00:00 2001
From: edvraa <80588099+edvraa@users.noreply.github.com>
Date: Wed, 21 Apr 2021 13:27:26 +0300
Subject: [PATCH 053/429] Move RemoteSource and LocalSource to
UnsafeDeserialization.qll
---
.../CWE-502/UnsafeDeserializationUntrustedInput.ql | 10 ----------
.../csharp/security/dataflow/UnsafeDeserialization.qll | 10 ++++++++++
2 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/csharp/ql/src/Security Features/CWE-502/UnsafeDeserializationUntrustedInput.ql b/csharp/ql/src/Security Features/CWE-502/UnsafeDeserializationUntrustedInput.ql
index 4e57e256faf..44302bc2cdf 100644
--- a/csharp/ql/src/Security Features/CWE-502/UnsafeDeserializationUntrustedInput.ql
+++ b/csharp/ql/src/Security Features/CWE-502/UnsafeDeserializationUntrustedInput.ql
@@ -13,16 +13,6 @@
import csharp
import semmle.code.csharp.security.dataflow.UnsafeDeserialization::UnsafeDeserialization
import DataFlow::PathGraph
-import semmle.code.csharp.security.dataflow.flowsources.Remote
-import semmle.code.csharp.security.dataflow.flowsources.Local
-
-class RemoteSource extends Source {
- RemoteSource() { this instanceof RemoteFlowSource }
-}
-
-class LocalSource extends Source {
- LocalSource() { this instanceof LocalFlowSource }
-}
from DataFlow::PathNode userInput, DataFlow::PathNode deserializeCallArg
where
diff --git a/csharp/ql/src/semmle/code/csharp/security/dataflow/UnsafeDeserialization.qll b/csharp/ql/src/semmle/code/csharp/security/dataflow/UnsafeDeserialization.qll
index 753d2c457e4..a41bba54f09 100644
--- a/csharp/ql/src/semmle/code/csharp/security/dataflow/UnsafeDeserialization.qll
+++ b/csharp/ql/src/semmle/code/csharp/security/dataflow/UnsafeDeserialization.qll
@@ -8,6 +8,8 @@ import csharp
module UnsafeDeserialization {
private import semmle.code.csharp.serialization.Deserializers
private import semmle.code.csharp.dataflow.TaintTracking2
+ private import semmle.code.csharp.security.dataflow.flowsources.Remote
+ private import semmle.code.csharp.security.dataflow.flowsources.Local
/**
* A data flow source for unsafe deserialization vulnerabilities.
@@ -43,6 +45,14 @@ module UnsafeDeserialization {
*/
abstract class Sanitizer extends DataFlow::Node { }
+ class RemoteSource extends Source {
+ RemoteSource() { this instanceof RemoteFlowSource }
+ }
+
+ class LocalSource extends Source {
+ LocalSource() { this instanceof LocalFlowSource }
+ }
+
/**
* User input to object method call deserialization flow tracking.
*/
From 0590522e4bb3962c214a314e1300f0486373e749 Mon Sep 17 00:00:00 2001
From: edvraa <80588099+edvraa@users.noreply.github.com>
Date: Wed, 21 Apr 2021 13:29:00 +0300
Subject: [PATCH 054/429] a deserializer
---
.../ql/src/semmle/code/csharp/serialization/Deserializers.qll | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/csharp/ql/src/semmle/code/csharp/serialization/Deserializers.qll b/csharp/ql/src/semmle/code/csharp/serialization/Deserializers.qll
index 6f70c205159..ce50b10ba45 100644
--- a/csharp/ql/src/semmle/code/csharp/serialization/Deserializers.qll
+++ b/csharp/ql/src/semmle/code/csharp/serialization/Deserializers.qll
@@ -87,7 +87,7 @@ class UnsafeDeserializerCallable extends Callable {
}
}
-/** Deserializer exploitable only if user controls the expected object type. */
+/** A deserializer exploitable only if user controls the expected object type. */
class StrongTypeDeserializer extends Class {
StrongTypeDeserializer() {
this instanceof XmlSerializerClass
@@ -100,7 +100,7 @@ class StrongTypeDeserializer extends Class {
}
}
-/** Deserializer that doesn't make strong expected type check. */
+/** A deserializer that doesn't make strong expected type check. */
class WeakTypeDeserializer extends Class {
WeakTypeDeserializer() {
this instanceof BinaryFormatterClass
From 8f6411dba30ba0ae30199a298e5fb2dbbbd06ccf Mon Sep 17 00:00:00 2001
From: edvraa <80588099+edvraa@users.noreply.github.com>
Date: Wed, 21 Apr 2021 13:52:41 +0300
Subject: [PATCH 055/429] Simpify with exists
---
.../dataflow/UnsafeDeserialization.qll | 151 +++++++++++-------
1 file changed, 97 insertions(+), 54 deletions(-)
diff --git a/csharp/ql/src/semmle/code/csharp/security/dataflow/UnsafeDeserialization.qll b/csharp/ql/src/semmle/code/csharp/security/dataflow/UnsafeDeserialization.qll
index a41bba54f09..41eb322eb76 100644
--- a/csharp/ql/src/semmle/code/csharp/security/dataflow/UnsafeDeserialization.qll
+++ b/csharp/ql/src/semmle/code/csharp/security/dataflow/UnsafeDeserialization.qll
@@ -48,7 +48,7 @@ module UnsafeDeserialization {
class RemoteSource extends Source {
RemoteSource() { this instanceof RemoteFlowSource }
}
-
+
class LocalSource extends Source {
LocalSource() { this instanceof LocalFlowSource }
}
@@ -145,14 +145,14 @@ module UnsafeDeserialization {
private predicate isBinaryFormatterCall(MethodCall mc, Method m) {
m = mc.getTarget() and
(
- m instanceof BinaryFormatterDeserializeMethod and
- not mc.getArgument(0).hasValue()
- or
- m instanceof BinaryFormatterUnsafeDeserializeMethod and
- not mc.getArgument(0).hasValue()
- or
- m instanceof BinaryFormatterUnsafeDeserializeMethodResponseMethod and
- not mc.getArgument(0).hasValue()
+ not mc.getArgument(0).hasValue() and
+ (
+ m instanceof BinaryFormatterDeserializeMethod
+ or
+ m instanceof BinaryFormatterUnsafeDeserializeMethod
+ or
+ m instanceof BinaryFormatterUnsafeDeserializeMethodResponseMethod
+ )
)
}
@@ -207,10 +207,11 @@ module UnsafeDeserialization {
private predicate isNetDataContractSerializerCall(MethodCall mc, Method m) {
m = mc.getTarget() and
(
- m instanceof NetDataContractSerializerDeserializeMethod and
- not mc.getArgument(0).hasValue()
- or
- m instanceof NetDataContractSerializerReadObjectMethod and
+ (
+ m instanceof NetDataContractSerializerDeserializeMethod
+ or
+ m instanceof NetDataContractSerializerReadObjectMethod
+ ) and
not mc.getArgument(0).hasValue()
)
}
@@ -250,10 +251,15 @@ module UnsafeDeserialization {
}
override predicate isSource(DataFlow::Node source) {
- source.asExpr().(ObjectCreation).getTarget().getDeclaringType() instanceof
- DataContractJsonSerializerClass and
- source.asExpr().(ObjectCreation).getTarget().getNumberOfParameters() > 0 and
- source.asExpr().(ObjectCreation).getArgument(0) instanceof TypeofExpr
+ exists(ObjectCreation oc |
+ oc = source.asExpr() and
+ exists(Constructor c |
+ c = oc.getTarget() and
+ c.getDeclaringType() instanceof DataContractJsonSerializerClass and
+ c.getNumberOfParameters() > 0 and
+ oc.getArgument(0) instanceof TypeofExpr
+ )
+ )
}
override predicate isSink(DataFlow::Node sink) {
@@ -268,10 +274,11 @@ module UnsafeDeserialization {
private predicate isJavaScriptSerializerCall(MethodCall mc, Method m) {
m = mc.getTarget() and
(
- m instanceof JavaScriptSerializerClassDeserializeMethod and
- not mc.getArgument(0).hasValue()
- or
- m instanceof JavaScriptSerializerClassDeserializeObjectMethod and
+ (
+ m instanceof JavaScriptSerializerClassDeserializeMethod
+ or
+ m instanceof JavaScriptSerializerClassDeserializeObjectMethod
+ ) and
not mc.getArgument(0).hasValue()
)
}
@@ -293,9 +300,14 @@ module UnsafeDeserialization {
}
override predicate isSource(DataFlow::Node source) {
- source.asExpr().(ObjectCreation).getTarget().getDeclaringType() instanceof
- JavaScriptSerializerClass and
- source.asExpr().(ObjectCreation).getTarget().getNumberOfParameters() = 0
+ exists(ObjectCreation oc |
+ oc = source.asExpr() and
+ exists(Constructor c |
+ c = oc.getTarget() and
+ c.getDeclaringType() instanceof JavaScriptSerializerClass and
+ c.getNumberOfParameters() = 0
+ )
+ )
}
override predicate isSink(DataFlow::Node sink) {
@@ -331,13 +343,16 @@ module UnsafeDeserialization {
}
override predicate isSource(DataFlow::Node source) {
- source.asExpr().(ObjectCreation).getTarget().getDeclaringType().getABaseType+() instanceof
- XmlObjectSerializerClass and
- not (
- source.asExpr().(ObjectCreation).getTarget().getDeclaringType() instanceof
- DataContractSerializerClass or
- source.asExpr().(ObjectCreation).getTarget().getDeclaringType() instanceof
- NetDataContractSerializerClass
+ exists(ObjectCreation oc |
+ oc = source.asExpr() and
+ exists(ValueOrRefType declaringType |
+ declaringType = oc.getTarget().getDeclaringType() and
+ declaringType.getABaseType+() instanceof XmlObjectSerializerClass and
+ not (
+ declaringType instanceof DataContractSerializerClass or
+ declaringType instanceof NetDataContractSerializerClass
+ )
+ )
)
}
@@ -373,9 +388,15 @@ module UnsafeDeserialization {
}
override predicate isSource(DataFlow::Node source) {
- source.asExpr().(ObjectCreation).getTarget().getDeclaringType() instanceof XmlSerializerClass and
- source.asExpr().(ObjectCreation).getTarget().getNumberOfParameters() > 0 and
- source.asExpr().(ObjectCreation).getArgument(0) instanceof TypeofExpr
+ exists(ObjectCreation oc |
+ oc = source.asExpr() and
+ exists(Constructor c |
+ c = oc.getTarget() and
+ c.getDeclaringType() instanceof XmlSerializerClass and
+ c.getNumberOfParameters() > 0 and
+ oc.getArgument(0) instanceof TypeofExpr
+ )
+ )
}
override predicate isSink(DataFlow::Node sink) {
@@ -414,10 +435,15 @@ module UnsafeDeserialization {
}
override predicate isSource(DataFlow::Node source) {
- source.asExpr().(ObjectCreation).getTarget().getDeclaringType() instanceof
- DataContractSerializerClass and
- source.asExpr().(ObjectCreation).getTarget().getNumberOfParameters() > 0 and
- source.asExpr().(ObjectCreation).getArgument(0) instanceof TypeofExpr
+ exists(ObjectCreation oc |
+ oc = source.asExpr() and
+ exists(Constructor c |
+ c = oc.getTarget() and
+ c.getDeclaringType() instanceof DataContractSerializerClass and
+ c.getNumberOfParameters() > 0 and
+ oc.getArgument(0) instanceof TypeofExpr
+ )
+ )
}
override predicate isSink(DataFlow::Node sink) {
@@ -452,10 +478,15 @@ module UnsafeDeserialization {
}
override predicate isSource(DataFlow::Node source) {
- source.asExpr().(ObjectCreation).getTarget().getDeclaringType() instanceof
- XmlMessageFormatterClass and
- source.asExpr().(ObjectCreation).getTarget().getNumberOfParameters() > 0 and
- source.asExpr().(ObjectCreation).getArgument(0) instanceof TypeofExpr
+ exists(ObjectCreation oc |
+ oc = source.asExpr() and
+ exists(Constructor c |
+ c = oc.getTarget() and
+ c.getDeclaringType() instanceof XmlMessageFormatterClass and
+ c.getNumberOfParameters() > 0 and
+ oc.getArgument(0) instanceof TypeofExpr
+ )
+ )
}
override predicate isSink(DataFlow::Node sink) {
@@ -635,9 +666,12 @@ module UnsafeDeserialization {
or
m instanceof ServiceStackTextJsonSerializerDeserializeFromStreamMethod
) and
- not mc.getAnArgument().hasValue() and
- not mc.getAnArgument() instanceof TypeofExpr and
- this.asExpr() = mc.getAnArgument()
+ exists(Expr arg |
+ arg = mc.getAnArgument() and
+ not arg.hasValue() and
+ not arg instanceof TypeofExpr and
+ this.asExpr() = arg
+ )
)
}
}
@@ -657,9 +691,12 @@ module UnsafeDeserialization {
or
m instanceof ServiceStackTextTypeSerializerDeserializeFromStreamMethod
) and
- not mc.getAnArgument().hasValue() and
- not mc.getAnArgument() instanceof TypeofExpr and
- this.asExpr() = mc.getAnArgument()
+ exists(Expr arg |
+ arg = mc.getAnArgument() and
+ not arg.hasValue() and
+ not arg instanceof TypeofExpr and
+ this.asExpr() = arg
+ )
)
}
}
@@ -678,9 +715,12 @@ module UnsafeDeserialization {
or
m instanceof ServiceStackTextCsvSerializerDeserializeFromStreamMethod
) and
- not mc.getAnArgument().hasValue() and
- not mc.getAnArgument() instanceof TypeofExpr and
- this.asExpr() = mc.getAnArgument()
+ exists(Expr arg |
+ arg = mc.getAnArgument() and
+ not arg.hasValue() and
+ not arg instanceof TypeofExpr and
+ this.asExpr() = arg
+ )
)
}
}
@@ -699,9 +739,12 @@ module UnsafeDeserialization {
or
m instanceof ServiceStackTextXmlSerializerDeserializeFromStreamMethod
) and
- not mc.getAnArgument().hasValue() and
- not mc.getAnArgument() instanceof TypeofExpr and
- this.asExpr() = mc.getAnArgument()
+ exists(Expr arg |
+ arg = mc.getAnArgument() and
+ not arg.hasValue() and
+ not arg instanceof TypeofExpr and
+ this.asExpr() = arg
+ )
)
}
}
From 9cc67e426671c0fd642d747cfec2bce3d95557dc Mon Sep 17 00:00:00 2001
From: edvraa <80588099+edvraa@users.noreply.github.com>
Date: Wed, 21 Apr 2021 16:48:05 +0300
Subject: [PATCH 056/429] make private where possible
---
.../csharp/serialization/Deserializers.qll | 32 +++++++++----------
1 file changed, 16 insertions(+), 16 deletions(-)
diff --git a/csharp/ql/src/semmle/code/csharp/serialization/Deserializers.qll b/csharp/ql/src/semmle/code/csharp/serialization/Deserializers.qll
index ce50b10ba45..de1f793c1ef 100644
--- a/csharp/ql/src/semmle/code/csharp/serialization/Deserializers.qll
+++ b/csharp/ql/src/semmle/code/csharp/serialization/Deserializers.qll
@@ -143,7 +143,7 @@ class WeakTypeDeserializer extends Class {
* An unsafe deserializer method that calls any unsafe deserializer on any of
* the parameters.
*/
-class WrapperDeserializer extends UnsafeDeserializerCallable, UnsafeDeserializer {
+private class WrapperDeserializer extends UnsafeDeserializerCallable, UnsafeDeserializer {
WrapperDeserializer() {
exists(Call call |
call.getEnclosingCallable() = this and
@@ -154,7 +154,7 @@ class WrapperDeserializer extends UnsafeDeserializerCallable, UnsafeDeserializer
}
/** BinaryFormatter */
-class BinaryFormatterClass extends Class {
+private class BinaryFormatterClass extends Class {
BinaryFormatterClass() {
this.hasQualifiedName("System.Runtime.Serialization.Formatters.Binary.BinaryFormatter")
}
@@ -182,7 +182,7 @@ class BinaryFormatterUnsafeDeserializeMethodResponseMethod extends Method, Unsaf
}
/** SoapFormatter */
-class SoapFormatterClass extends Class {
+private class SoapFormatterClass extends Class {
SoapFormatterClass() {
this.hasQualifiedName("System.Runtime.Serialization.Formatters.Soap.SoapFormatter")
}
@@ -196,7 +196,7 @@ class SoapFormatterDeserializeMethod extends Method, UnsafeDeserializer {
}
/** ObjectStateFormatter */
-class ObjectStateFormatterClass extends Class {
+private class ObjectStateFormatterClass extends Class {
ObjectStateFormatterClass() { this.hasQualifiedName("System.Web.UI.ObjectStateFormatter") }
}
@@ -316,7 +316,7 @@ class XmlMessageFormatterReadMethod extends Method, UnsafeDeserializer {
}
/** LosFormatter */
-class LosFormatterClass extends Class {
+private class LosFormatterClass extends Class {
LosFormatterClass() { this.hasQualifiedName("System.Web.UI.LosFormatter") }
}
@@ -328,7 +328,7 @@ class LosFormatterDeserializeMethod extends Method, UnsafeDeserializer {
}
/** fastJSON */
-class FastJsonClass extends Class {
+private class FastJsonClass extends Class {
FastJsonClass() { this.hasQualifiedName("fastJSON.JSON") }
}
@@ -341,7 +341,7 @@ class FastJsonClassToObjectMethod extends Method, UnsafeDeserializer {
}
/** Activity */
-class ActivityClass extends Class {
+private class ActivityClass extends Class {
ActivityClass() { this.hasQualifiedName("System.Workflow.ComponentModel.Activity") }
}
@@ -353,7 +353,7 @@ class ActivityLoadMethod extends Method, UnsafeDeserializer {
}
/** ResourceReader */
-class ResourceReaderClass extends Class {
+private class ResourceReaderClass extends Class {
ResourceReaderClass() { this.hasQualifiedName("System.Resources.ResourceReader") }
}
@@ -365,7 +365,7 @@ class ResourceReaderConstructor extends Constructor, UnsafeDeserializer {
}
/** BinaryMessageFormatter */
-class BinaryMessageFormatterClass extends Class {
+private class BinaryMessageFormatterClass extends Class {
BinaryMessageFormatterClass() { this.hasQualifiedName("System.Messaging.BinaryMessageFormatter") }
}
@@ -377,7 +377,7 @@ class BinaryMessageFormatterReadMethod extends Method, UnsafeDeserializer {
}
/** XamlReader */
-class XamlReaderClass extends Class {
+private class XamlReaderClass extends Class {
XamlReaderClass() { this.hasQualifiedName("System.Windows.Markup.XamlReader") }
}
@@ -405,7 +405,7 @@ class XamlReaderLoadAsyncMethod extends Method, UnsafeDeserializer {
}
/** ProxyObject */
-class ProxyObjectClass extends Class {
+private class ProxyObjectClass extends Class {
ProxyObjectClass() { this.hasQualifiedName("Microsoft.Web.Design.Remote.ProxyObject") }
}
@@ -424,7 +424,7 @@ class ProxyObjectDecodeSerializedObjectMethod extends Method, UnsafeDeserializer
}
/** SweetJayson */
-class JaysonConverterClass extends Class {
+private class JaysonConverterClass extends Class {
JaysonConverterClass() { this.hasQualifiedName("Sweet.Jayson.JaysonConverter") }
}
@@ -437,7 +437,7 @@ class JaysonConverterToObjectMethod extends Method, UnsafeDeserializer {
}
/** ServiceStack.Text.JsonSerializer */
-class ServiceStackTextJsonSerializerClass extends Class {
+private class ServiceStackTextJsonSerializerClass extends Class {
ServiceStackTextJsonSerializerClass() {
this.hasQualifiedName("ServiceStack.Text.JsonSerializer")
}
@@ -468,7 +468,7 @@ class ServiceStackTextJsonSerializerDeserializeFromStreamMethod extends Method,
}
/** ServiceStack.Text.TypeSerializer */
-class ServiceStackTextTypeSerializerClass extends Class {
+private class ServiceStackTextTypeSerializerClass extends Class {
ServiceStackTextTypeSerializerClass() {
this.hasQualifiedName("ServiceStack.Text.TypeSerializer")
}
@@ -499,7 +499,7 @@ class ServiceStackTextTypeSerializerDeserializeFromStreamMethod extends Method,
}
/** ServiceStack.Text.CsvSerializer */
-class ServiceStackTextCsvSerializerClass extends Class {
+private class ServiceStackTextCsvSerializerClass extends Class {
ServiceStackTextCsvSerializerClass() { this.hasQualifiedName("ServiceStack.Text.CsvSerializer") }
}
@@ -528,7 +528,7 @@ class ServiceStackTextCsvSerializerDeserializeFromStreamMethod extends Method, U
}
/** ServiceStack.Text.XmlSerializer */
-class ServiceStackTextXmlSerializerClass extends Class {
+private class ServiceStackTextXmlSerializerClass extends Class {
ServiceStackTextXmlSerializerClass() { this.hasQualifiedName("ServiceStack.Text.XmlSerializer") }
}
From b6952d541ae37a655722c24be4822544629f29e1 Mon Sep 17 00:00:00 2001
From: edvraa <80588099+edvraa@users.noreply.github.com>
Date: Wed, 21 Apr 2021 16:55:34 +0300
Subject: [PATCH 057/429] get rid of getParent
---
.../CWE-502/UnsafeDeserializationUntrustedInput.ql | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/csharp/ql/src/Security Features/CWE-502/UnsafeDeserializationUntrustedInput.ql b/csharp/ql/src/Security Features/CWE-502/UnsafeDeserializationUntrustedInput.ql
index 44302bc2cdf..839f9615e26 100644
--- a/csharp/ql/src/Security Features/CWE-502/UnsafeDeserializationUntrustedInput.ql
+++ b/csharp/ql/src/Security Features/CWE-502/UnsafeDeserializationUntrustedInput.ql
@@ -24,18 +24,20 @@ where
(
exists(
DataFlow::Node weakTypeCreation, DataFlow::Node weakTypeUsage,
- WeakTypeCreationToUsageTrackingConfig weakTypeDeserializerTracking
+ WeakTypeCreationToUsageTrackingConfig weakTypeDeserializerTracking, MethodCall mc
|
weakTypeDeserializerTracking.hasFlow(weakTypeCreation, weakTypeUsage) and
- weakTypeUsage.asExpr().getParent() = deserializeCallArg.getNode().asExpr().getParent()
+ mc.getQualifier() = weakTypeUsage.asExpr() and
+ mc.getAnArgument() = deserializeCallArg.getNode().asExpr()
)
or
exists(
TaintToObjectTypeTrackingConfig userControlledTypeTracking, DataFlow::Node taintedTypeUsage,
- DataFlow::Node userInput2
+ DataFlow::Node userInput2, MethodCall mc
|
userControlledTypeTracking.hasFlow(userInput2, taintedTypeUsage) and
- taintedTypeUsage.asExpr().getParent() = deserializeCallArg.getNode().asExpr().getParent()
+ mc.getQualifier() = taintedTypeUsage.asExpr() and
+ mc.getAnArgument() = deserializeCallArg.getNode().asExpr()
)
) and
// exclude deserialization flows with safe instances (i.e. JavaScriptSerializer without resolver)
From 808444986d44490308df2505fd5e6083de92c040 Mon Sep 17 00:00:00 2001
From: edvraa <80588099+edvraa@users.noreply.github.com>
Date: Wed, 21 Apr 2021 17:06:20 +0300
Subject: [PATCH 058/429] Get rid of UnsafeDeserializerCallable
---
.../CWE-502/DeserializedDelegate.ql | 2 +-
.../dataflow/UnsafeDeserialization.qll | 4 +-
.../csharp/serialization/Deserializers.qll | 83 +------------------
3 files changed, 5 insertions(+), 84 deletions(-)
diff --git a/csharp/ql/src/Security Features/CWE-502/DeserializedDelegate.ql b/csharp/ql/src/Security Features/CWE-502/DeserializedDelegate.ql
index 75708e712dc..31d28311908 100644
--- a/csharp/ql/src/Security Features/CWE-502/DeserializedDelegate.ql
+++ b/csharp/ql/src/Security Features/CWE-502/DeserializedDelegate.ql
@@ -16,7 +16,7 @@ import semmle.code.csharp.serialization.Deserializers
from Call deserialization, Cast cast
where
- deserialization.getTarget() instanceof UnsafeDeserializerCallable and
+ deserialization.getTarget() instanceof UnsafeDeserializer and
cast.getExpr() = deserialization and
cast.getTargetType() instanceof SystemLinqExpressions::DelegateExtType
select deserialization, "Deserialization of delegate type."
diff --git a/csharp/ql/src/semmle/code/csharp/security/dataflow/UnsafeDeserialization.qll b/csharp/ql/src/semmle/code/csharp/security/dataflow/UnsafeDeserialization.qll
index 41eb322eb76..6c78f745037 100644
--- a/csharp/ql/src/semmle/code/csharp/security/dataflow/UnsafeDeserialization.qll
+++ b/csharp/ql/src/semmle/code/csharp/security/dataflow/UnsafeDeserialization.qll
@@ -89,7 +89,7 @@ module UnsafeDeserialization {
override predicate isSink(DataFlow::Node sink) {
exists(MethodCall mc |
- mc.getTarget() instanceof UnsafeDeserializerCallable and
+ mc.getTarget() instanceof UnsafeDeserializer and
sink.asExpr() = mc.getQualifier()
)
}
@@ -127,7 +127,7 @@ module UnsafeDeserialization {
override predicate isSink(DataFlow::Node sink) {
exists(MethodCall mc |
- mc.getTarget() instanceof UnsafeDeserializerCallable and
+ mc.getTarget() instanceof UnsafeDeserializer and
sink.asExpr() = mc.getQualifier()
)
}
diff --git a/csharp/ql/src/semmle/code/csharp/serialization/Deserializers.qll b/csharp/ql/src/semmle/code/csharp/serialization/Deserializers.qll
index de1f793c1ef..9dcbeda5acf 100644
--- a/csharp/ql/src/semmle/code/csharp/serialization/Deserializers.qll
+++ b/csharp/ql/src/semmle/code/csharp/serialization/Deserializers.qll
@@ -8,85 +8,6 @@ import csharp
/** An unsafe deserializer. */
abstract class UnsafeDeserializer extends Callable { }
-/** Unsafe deserialization calls. */
-class UnsafeDeserializerCallable extends Callable {
- UnsafeDeserializerCallable() {
- this instanceof BinaryFormatterDeserializeMethod
- or
- this instanceof BinaryFormatterUnsafeDeserializeMethod
- or
- this instanceof BinaryFormatterUnsafeDeserializeMethodResponseMethod
- or
- this instanceof SoapFormatterDeserializeMethod
- or
- this instanceof ObjectStateFormatterDeserializeMethod
- or
- this instanceof NetDataContractSerializerDeserializeMethod
- or
- this instanceof NetDataContractSerializerReadObjectMethod
- or
- this instanceof DataContractJsonSerializerReadObjectMethod
- or
- this instanceof JavaScriptSerializerClassDeserializeMethod
- or
- this instanceof JavaScriptSerializerClassDeserializeObjectMethod
- or
- this instanceof XmlObjectSerializerReadObjectMethod
- or
- this instanceof XmlSerializerDeserializeMethod
- or
- this instanceof DataContractSerializerReadObjectMethod
- or
- this instanceof XmlMessageFormatterReadMethod
- or
- this instanceof LosFormatterDeserializeMethod
- or
- this instanceof FastJsonClassToObjectMethod
- or
- this instanceof ActivityLoadMethod
- or
- this instanceof ResourceReaderConstructor
- or
- this instanceof BinaryMessageFormatterReadMethod
- or
- this instanceof XamlReaderParseMethod
- or
- this instanceof XamlReaderLoadMethod
- or
- this instanceof XamlReaderLoadAsyncMethod
- or
- this instanceof ProxyObjectDecodeValueMethod
- or
- this instanceof ProxyObjectDecodeSerializedObjectMethod
- or
- this instanceof JaysonConverterToObjectMethod
- or
- this instanceof ServiceStackTextJsonSerializerDeserializeFromStringMethod
- or
- this instanceof ServiceStackTextJsonSerializerDeserializeFromReaderMethod
- or
- this instanceof ServiceStackTextJsonSerializerDeserializeFromStreamMethod
- or
- this instanceof ServiceStackTextTypeSerializerDeserializeFromStringMethod
- or
- this instanceof ServiceStackTextTypeSerializerDeserializeFromReaderMethod
- or
- this instanceof ServiceStackTextTypeSerializerDeserializeFromStreamMethod
- or
- this instanceof ServiceStackTextCsvSerializerDeserializeFromStringMethod
- or
- this instanceof ServiceStackTextCsvSerializerDeserializeFromReaderMethod
- or
- this instanceof ServiceStackTextCsvSerializerDeserializeFromStreamMethod
- or
- this instanceof ServiceStackTextXmlSerializerDeserializeFromStringMethod
- or
- this instanceof ServiceStackTextXmlSerializerDeserializeFromReaderMethod
- or
- this instanceof ServiceStackTextXmlSerializerDeserializeFromStreamMethod
- }
-}
-
/** A deserializer exploitable only if user controls the expected object type. */
class StrongTypeDeserializer extends Class {
StrongTypeDeserializer() {
@@ -143,12 +64,12 @@ class WeakTypeDeserializer extends Class {
* An unsafe deserializer method that calls any unsafe deserializer on any of
* the parameters.
*/
-private class WrapperDeserializer extends UnsafeDeserializerCallable, UnsafeDeserializer {
+private class WrapperDeserializer extends UnsafeDeserializer {
WrapperDeserializer() {
exists(Call call |
call.getEnclosingCallable() = this and
call.getAnArgument() instanceof ParameterAccess and
- call.getTarget() instanceof UnsafeDeserializerCallable
+ call.getTarget() instanceof UnsafeDeserializer
)
}
}
From 9e46ef3cd9768ff7da2d0a2a4e71455ca46fad55 Mon Sep 17 00:00:00 2001
From: edvraa <80588099+edvraa@users.noreply.github.com>
Date: Wed, 21 Apr 2021 17:11:40 +0300
Subject: [PATCH 059/429] Get rid of getParent
---
.../code/csharp/security/dataflow/UnsafeDeserialization.qll | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/csharp/ql/src/semmle/code/csharp/security/dataflow/UnsafeDeserialization.qll b/csharp/ql/src/semmle/code/csharp/security/dataflow/UnsafeDeserialization.qll
index 6c78f745037..181a27d6d2d 100644
--- a/csharp/ql/src/semmle/code/csharp/security/dataflow/UnsafeDeserialization.qll
+++ b/csharp/ql/src/semmle/code/csharp/security/dataflow/UnsafeDeserialization.qll
@@ -27,10 +27,12 @@ module UnsafeDeserialization {
abstract private class InstanceMethodSink extends Sink {
InstanceMethodSink() {
not exists(
- SafeConstructorTrackingConfig safeConstructorTracking, DataFlow::Node safeTypeUsage
+ SafeConstructorTrackingConfig safeConstructorTracking, DataFlow::Node safeTypeUsage,
+ MethodCall mc
|
safeConstructorTracking.hasFlow(_, safeTypeUsage) and
- safeTypeUsage.asExpr().getParent() = this.asExpr().getParent()
+ mc.getQualifier() = safeTypeUsage.asExpr() and
+ mc.getAnArgument() = this.asExpr()
)
}
}
From a93d6a3ef66fba1562bfd89d8200db001e0ecc58 Mon Sep 17 00:00:00 2001
From: edvraa <80588099+edvraa@users.noreply.github.com>
Date: Wed, 21 Apr 2021 17:16:54 +0300
Subject: [PATCH 060/429] Remove SafeConstructorTrackingConfig
---
.../CWE-502/UnsafeDeserializationUntrustedInput.ql | 8 --------
1 file changed, 8 deletions(-)
diff --git a/csharp/ql/src/Security Features/CWE-502/UnsafeDeserializationUntrustedInput.ql b/csharp/ql/src/Security Features/CWE-502/UnsafeDeserializationUntrustedInput.ql
index 839f9615e26..2aeb41e4ceb 100644
--- a/csharp/ql/src/Security Features/CWE-502/UnsafeDeserializationUntrustedInput.ql
+++ b/csharp/ql/src/Security Features/CWE-502/UnsafeDeserializationUntrustedInput.ql
@@ -39,14 +39,6 @@ where
mc.getQualifier() = taintedTypeUsage.asExpr() and
mc.getAnArgument() = deserializeCallArg.getNode().asExpr()
)
- ) and
- // exclude deserialization flows with safe instances (i.e. JavaScriptSerializer without resolver)
- not exists(
- SafeConstructorTrackingConfig safeConstructorTracking, DataFlow::Node safeCreation,
- DataFlow::Node safeTypeUsage
- |
- safeConstructorTracking.hasFlow(safeCreation, safeTypeUsage) and
- safeTypeUsage.asExpr().getParent() = deserializeCallArg.getNode().asExpr().getParent()
)
or
// no type check needed - straightforward taint -> sink
From 57689df5aa880fb5eb5ecf621a62e726ccde5b19 Mon Sep 17 00:00:00 2001
From: edvraa <80588099+edvraa@users.noreply.github.com>
Date: Wed, 21 Apr 2021 19:29:30 +0300
Subject: [PATCH 061/429] Remove DataFlow::Node
---
.../src/Security Features/CWE-502/UnsafeDeserialization.ql | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/csharp/ql/src/Security Features/CWE-502/UnsafeDeserialization.ql b/csharp/ql/src/Security Features/CWE-502/UnsafeDeserialization.ql
index e7c3eb2b4e9..40022d40573 100644
--- a/csharp/ql/src/Security Features/CWE-502/UnsafeDeserialization.ql
+++ b/csharp/ql/src/Security Features/CWE-502/UnsafeDeserialization.ql
@@ -13,9 +13,7 @@
import csharp
import semmle.code.csharp.security.dataflow.UnsafeDeserialization::UnsafeDeserialization
-from Call deserializeCall, DataFlow::Node sink
-where
- deserializeCall.getAnArgument() = sink.asExpr() and
- sink instanceof Sink
+from Call deserializeCall, Sink sink
+where deserializeCall.getAnArgument() = sink.asExpr()
select deserializeCall,
"Unsafe deserializer is used. Make sure the value being deserialized comes from a trusted source."
From c9c9758e014f7771728d4f732020fa956a16cf8e Mon Sep 17 00:00:00 2001
From: edvraa <80588099+edvraa@users.noreply.github.com>
Date: Thu, 22 Apr 2021 12:23:46 +0300
Subject: [PATCH 062/429] Make similarly named files in tests and qhelp in sync
---
.../CWE-502/UnsafeDeserializationUntrustedInputGood.cs | 2 +-
.../UnsafeDeserializationUntrustedInputGood.cs | 6 +++---
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/csharp/ql/src/Security Features/CWE-502/UnsafeDeserializationUntrustedInputGood.cs b/csharp/ql/src/Security Features/CWE-502/UnsafeDeserializationUntrustedInputGood.cs
index d1e2935b218..d6b5b09841b 100644
--- a/csharp/ql/src/Security Features/CWE-502/UnsafeDeserializationUntrustedInputGood.cs
+++ b/csharp/ql/src/Security Features/CWE-502/UnsafeDeserializationUntrustedInputGood.cs
@@ -6,7 +6,7 @@ class Good
public static object Deserialize(TextBox textBox)
{
JavaScriptSerializer sr = new JavaScriptSerializer();
- // GOOD
+ // GOOD: no unsafe type resolver
return sr.DeserializeObject(textBox.Text);
}
}
diff --git a/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserializationUntrustedInput/UnsafeDeserializationUntrustedInputGood.cs b/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserializationUntrustedInput/UnsafeDeserializationUntrustedInputGood.cs
index 05222245f9a..d6b5b09841b 100644
--- a/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserializationUntrustedInput/UnsafeDeserializationUntrustedInputGood.cs
+++ b/csharp/ql/test/query-tests/Security Features/CWE-502/UnsafeDeserializationUntrustedInput/UnsafeDeserializationUntrustedInputGood.cs
@@ -5,8 +5,8 @@ class Good
{
public static object Deserialize(TextBox textBox)
{
- JavaScriptSerializer sr = new JavaScriptSerializer(new SimpleTypeResolver());
- // GOOD
- return sr.DeserializeObject("hardcoded");
+ JavaScriptSerializer sr = new JavaScriptSerializer();
+ // GOOD: no unsafe type resolver
+ return sr.DeserializeObject(textBox.Text);
}
}
From 62f3e8d64a4f75fc6fdf21dbeafaa66685f91e39 Mon Sep 17 00:00:00 2001
From: thank_you
Date: Mon, 26 Apr 2021 15:35:42 -0400
Subject: [PATCH 063/429] Add sanitizer for ObjectId
ObjectId is a sanitizer used to sanitize strings into valid MongoDB ids. During research we've found that this method is used.
ObjectId returns a string representing an id. If at any time ObjectId can't parse it's input (like when a tainted dict in passed in), then ObjectId will throw an error preventing the query from running.
---
.../experimental/semmle/python/frameworks/Stdlib.qll | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/python/ql/src/experimental/semmle/python/frameworks/Stdlib.qll b/python/ql/src/experimental/semmle/python/frameworks/Stdlib.qll
index 177d7a1a560..09777dd1037 100644
--- a/python/ql/src/experimental/semmle/python/frameworks/Stdlib.qll
+++ b/python/ql/src/experimental/semmle/python/frameworks/Stdlib.qll
@@ -89,4 +89,15 @@ private module NoSQL {
override DataFlow::Node getSanitizerNode() { result = this.getArg(0) }
}
+
+ private class BsonObjectIdCall extends DataFlow::CallCfgNode, NoSQLSanitizer::Range {
+ BsonObjectIdCall() {
+ this =
+ API::moduleImport(["bson", "bson.objectid", "bson.json_util"])
+ .getMember("ObjectId")
+ .getACall()
+ }
+
+ override DataFlow::Node getSanitizerNode() { result = this.getArg(0) }
+ }
}
From 18a3e4d45b233a301e959cc2e1b390a5eb16ce55 Mon Sep 17 00:00:00 2001
From: edvraa <80588099+edvraa@users.noreply.github.com>
Date: Tue, 27 Apr 2021 22:10:04 +0300
Subject: [PATCH 064/429] add comments
---
.../dataflow/UnsafeDeserialization.qll | 4 +-
.../csharp/serialization/Deserializers.qll | 37 +++++++++++++++++++
2 files changed, 39 insertions(+), 2 deletions(-)
diff --git a/csharp/ql/src/semmle/code/csharp/security/dataflow/UnsafeDeserialization.qll b/csharp/ql/src/semmle/code/csharp/security/dataflow/UnsafeDeserialization.qll
index 181a27d6d2d..407d7b22bbc 100644
--- a/csharp/ql/src/semmle/code/csharp/security/dataflow/UnsafeDeserialization.qll
+++ b/csharp/ql/src/semmle/code/csharp/security/dataflow/UnsafeDeserialization.qll
@@ -47,11 +47,11 @@ module UnsafeDeserialization {
*/
abstract class Sanitizer extends DataFlow::Node { }
- class RemoteSource extends Source {
+ private class RemoteSource extends Source {
RemoteSource() { this instanceof RemoteFlowSource }
}
- class LocalSource extends Source {
+ private class LocalSource extends Source {
LocalSource() { this instanceof LocalFlowSource }
}
diff --git a/csharp/ql/src/semmle/code/csharp/serialization/Deserializers.qll b/csharp/ql/src/semmle/code/csharp/serialization/Deserializers.qll
index 9dcbeda5acf..58b6375bc13 100644
--- a/csharp/ql/src/semmle/code/csharp/serialization/Deserializers.qll
+++ b/csharp/ql/src/semmle/code/csharp/serialization/Deserializers.qll
@@ -81,6 +81,7 @@ private class BinaryFormatterClass extends Class {
}
}
+/** `System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize` method */
class BinaryFormatterDeserializeMethod extends Method, UnsafeDeserializer {
BinaryFormatterDeserializeMethod() {
this.getDeclaringType() instanceof BinaryFormatterClass and
@@ -88,6 +89,7 @@ class BinaryFormatterDeserializeMethod extends Method, UnsafeDeserializer {
}
}
+/** `System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.UnsafeDeserialize` method */
class BinaryFormatterUnsafeDeserializeMethod extends Method, UnsafeDeserializer {
BinaryFormatterUnsafeDeserializeMethod() {
this.getDeclaringType() instanceof BinaryFormatterClass and
@@ -95,6 +97,7 @@ class BinaryFormatterUnsafeDeserializeMethod extends Method, UnsafeDeserializer
}
}
+/** `System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.UnsafeDeserializeMethodResponse` method */
class BinaryFormatterUnsafeDeserializeMethodResponseMethod extends Method, UnsafeDeserializer {
BinaryFormatterUnsafeDeserializeMethodResponseMethod() {
this.getDeclaringType() instanceof BinaryFormatterClass and
@@ -109,6 +112,7 @@ private class SoapFormatterClass extends Class {
}
}
+/** `System.Runtime.Serialization.Formatters.Soap.SoapFormatter.Deserialize` method */
class SoapFormatterDeserializeMethod extends Method, UnsafeDeserializer {
SoapFormatterDeserializeMethod() {
this.getDeclaringType() instanceof SoapFormatterClass and
@@ -121,6 +125,7 @@ private class ObjectStateFormatterClass extends Class {
ObjectStateFormatterClass() { this.hasQualifiedName("System.Web.UI.ObjectStateFormatter") }
}
+/** `System.Web.UI.ObjectStateFormatter.Deserialize` method */
class ObjectStateFormatterDeserializeMethod extends Method, UnsafeDeserializer {
ObjectStateFormatterDeserializeMethod() {
this.getDeclaringType() instanceof ObjectStateFormatterClass and
@@ -135,6 +140,7 @@ class NetDataContractSerializerClass extends Class {
}
}
+/** `System.Runtime.Serialization.NetDataContractSerializer.Deserialize` method */
class NetDataContractSerializerDeserializeMethod extends Method, UnsafeDeserializer {
NetDataContractSerializerDeserializeMethod() {
this.getDeclaringType() instanceof NetDataContractSerializerClass and
@@ -142,6 +148,7 @@ class NetDataContractSerializerDeserializeMethod extends Method, UnsafeDeseriali
}
}
+/** `System.Runtime.Serialization.NetDataContractSerializer.ReadObject` method */
class NetDataContractSerializerReadObjectMethod extends Method, UnsafeDeserializer {
NetDataContractSerializerReadObjectMethod() {
this.getDeclaringType() instanceof NetDataContractSerializerClass and
@@ -156,6 +163,7 @@ class DataContractJsonSerializerClass extends Class {
}
}
+/** `System.Runtime.Serialization.Json.DataContractJsonSerializer.ReadObject` method */
class DataContractJsonSerializerReadObjectMethod extends Method, UnsafeDeserializer {
DataContractJsonSerializerReadObjectMethod() {
this.getDeclaringType() instanceof DataContractJsonSerializerClass and
@@ -170,6 +178,7 @@ class JavaScriptSerializerClass extends Class {
}
}
+/** `System.Web.Script.Serialization.JavaScriptSerializer.Deserialize` method */
class JavaScriptSerializerClassDeserializeMethod extends Method, UnsafeDeserializer {
JavaScriptSerializerClassDeserializeMethod() {
this.getDeclaringType() instanceof JavaScriptSerializerClass and
@@ -177,6 +186,7 @@ class JavaScriptSerializerClassDeserializeMethod extends Method, UnsafeDeseriali
}
}
+/** `System.Web.Script.Serialization.JavaScriptSerializer.DeserializeObject` method */
class JavaScriptSerializerClassDeserializeObjectMethod extends Method, UnsafeDeserializer {
JavaScriptSerializerClassDeserializeObjectMethod() {
this.getDeclaringType() instanceof JavaScriptSerializerClass and
@@ -191,6 +201,7 @@ class XmlObjectSerializerClass extends Class {
}
}
+/** `System.Runtime.Serialization.XmlObjectSerializer.ReadObject` method */
class XmlObjectSerializerReadObjectMethod extends Method, UnsafeDeserializer {
XmlObjectSerializerReadObjectMethod() {
this.getDeclaringType() instanceof XmlObjectSerializerClass and
@@ -203,6 +214,7 @@ class XmlSerializerClass extends Class {
XmlSerializerClass() { this.hasQualifiedName("System.Xml.Serialization.XmlSerializer") }
}
+/** `System.Xml.Serialization.XmlSerializer.Deserialize` method */
class XmlSerializerDeserializeMethod extends Method, UnsafeDeserializer {
XmlSerializerDeserializeMethod() {
this.getDeclaringType() instanceof XmlSerializerClass and
@@ -217,6 +229,7 @@ class DataContractSerializerClass extends Class {
}
}
+/** `System.Runtime.Serialization.DataContractSerializer.ReadObject` method */
class DataContractSerializerReadObjectMethod extends Method, UnsafeDeserializer {
DataContractSerializerReadObjectMethod() {
this.getDeclaringType() instanceof DataContractSerializerClass and
@@ -229,6 +242,7 @@ class XmlMessageFormatterClass extends Class {
XmlMessageFormatterClass() { this.hasQualifiedName("System.Messaging.XmlMessageFormatter") }
}
+/** `System.Messaging.XmlMessageFormatter.Read` method */
class XmlMessageFormatterReadMethod extends Method, UnsafeDeserializer {
XmlMessageFormatterReadMethod() {
this.getDeclaringType() instanceof XmlMessageFormatterClass and
@@ -241,6 +255,7 @@ private class LosFormatterClass extends Class {
LosFormatterClass() { this.hasQualifiedName("System.Web.UI.LosFormatter") }
}
+/** `System.Web.UI.LosFormatter.Deserialize` method */
class LosFormatterDeserializeMethod extends Method, UnsafeDeserializer {
LosFormatterDeserializeMethod() {
this.getDeclaringType() instanceof LosFormatterClass and
@@ -253,6 +268,7 @@ private class FastJsonClass extends Class {
FastJsonClass() { this.hasQualifiedName("fastJSON.JSON") }
}
+/** `fastJSON.JSON.ToObject` method */
class FastJsonClassToObjectMethod extends Method, UnsafeDeserializer {
FastJsonClassToObjectMethod() {
this.getDeclaringType() instanceof FastJsonClass and
@@ -266,6 +282,7 @@ private class ActivityClass extends Class {
ActivityClass() { this.hasQualifiedName("System.Workflow.ComponentModel.Activity") }
}
+/** `System.Workflow.ComponentModel.Activity.Load` method */
class ActivityLoadMethod extends Method, UnsafeDeserializer {
ActivityLoadMethod() {
this.getDeclaringType() instanceof ActivityClass and
@@ -278,6 +295,7 @@ private class ResourceReaderClass extends Class {
ResourceReaderClass() { this.hasQualifiedName("System.Resources.ResourceReader") }
}
+/** `System.Resources.ResourceReader` constructor */
class ResourceReaderConstructor extends Constructor, UnsafeDeserializer {
ResourceReaderConstructor() {
this.getDeclaringType() instanceof ResourceReaderClass and
@@ -290,6 +308,7 @@ private class BinaryMessageFormatterClass extends Class {
BinaryMessageFormatterClass() { this.hasQualifiedName("System.Messaging.BinaryMessageFormatter") }
}
+/** `System.Messaging.BinaryMessageFormatter.Read` method */
class BinaryMessageFormatterReadMethod extends Method, UnsafeDeserializer {
BinaryMessageFormatterReadMethod() {
this.getDeclaringType() instanceof BinaryMessageFormatterClass and
@@ -302,6 +321,7 @@ private class XamlReaderClass extends Class {
XamlReaderClass() { this.hasQualifiedName("System.Windows.Markup.XamlReader") }
}
+/** `System.Windows.Markup.XamlReader.Parse` method */
class XamlReaderParseMethod extends Method, UnsafeDeserializer {
XamlReaderParseMethod() {
this.getDeclaringType() instanceof XamlReaderClass and
@@ -310,6 +330,7 @@ class XamlReaderParseMethod extends Method, UnsafeDeserializer {
}
}
+/** `System.Windows.Markup.XamlReader.Load` method */
class XamlReaderLoadMethod extends Method, UnsafeDeserializer {
XamlReaderLoadMethod() {
this.getDeclaringType() instanceof XamlReaderClass and
@@ -318,6 +339,7 @@ class XamlReaderLoadMethod extends Method, UnsafeDeserializer {
}
}
+/** `System.Windows.Markup.XamlReader.LoadAsync` method */
class XamlReaderLoadAsyncMethod extends Method, UnsafeDeserializer {
XamlReaderLoadAsyncMethod() {
this.getDeclaringType() instanceof XamlReaderClass and
@@ -330,6 +352,7 @@ private class ProxyObjectClass extends Class {
ProxyObjectClass() { this.hasQualifiedName("Microsoft.Web.Design.Remote.ProxyObject") }
}
+/** `Microsoft.Web.Design.Remote.ProxyObject.DecodeValue` method */
class ProxyObjectDecodeValueMethod extends Method, UnsafeDeserializer {
ProxyObjectDecodeValueMethod() {
this.getDeclaringType() instanceof ProxyObjectClass and
@@ -337,6 +360,7 @@ class ProxyObjectDecodeValueMethod extends Method, UnsafeDeserializer {
}
}
+/** `Microsoft.Web.Design.Remote.ProxyObject.DecodeSerializedObject` method */
class ProxyObjectDecodeSerializedObjectMethod extends Method, UnsafeDeserializer {
ProxyObjectDecodeSerializedObjectMethod() {
this.getDeclaringType() instanceof ProxyObjectClass and
@@ -349,6 +373,7 @@ private class JaysonConverterClass extends Class {
JaysonConverterClass() { this.hasQualifiedName("Sweet.Jayson.JaysonConverter") }
}
+/** `Sweet.Jayson.JaysonConverter.ToObject` method */
class JaysonConverterToObjectMethod extends Method, UnsafeDeserializer {
JaysonConverterToObjectMethod() {
this.getDeclaringType() instanceof JaysonConverterClass and
@@ -364,6 +389,7 @@ private class ServiceStackTextJsonSerializerClass extends Class {
}
}
+/** `ServiceStack.Text.JsonSerializer.DeserializeFromString` method */
class ServiceStackTextJsonSerializerDeserializeFromStringMethod extends Method, UnsafeDeserializer {
ServiceStackTextJsonSerializerDeserializeFromStringMethod() {
this.getDeclaringType() instanceof ServiceStackTextJsonSerializerClass and
@@ -372,6 +398,7 @@ class ServiceStackTextJsonSerializerDeserializeFromStringMethod extends Method,
}
}
+/** `ServiceStack.Text.JsonSerializer.DeserializeFromReader` method */
class ServiceStackTextJsonSerializerDeserializeFromReaderMethod extends Method, UnsafeDeserializer {
ServiceStackTextJsonSerializerDeserializeFromReaderMethod() {
this.getDeclaringType() instanceof ServiceStackTextJsonSerializerClass and
@@ -380,6 +407,7 @@ class ServiceStackTextJsonSerializerDeserializeFromReaderMethod extends Method,
}
}
+/** `ServiceStack.Text.JsonSerializer.DeserializeFromStream` method */
class ServiceStackTextJsonSerializerDeserializeFromStreamMethod extends Method, UnsafeDeserializer {
ServiceStackTextJsonSerializerDeserializeFromStreamMethod() {
this.getDeclaringType() instanceof ServiceStackTextJsonSerializerClass and
@@ -395,6 +423,7 @@ private class ServiceStackTextTypeSerializerClass extends Class {
}
}
+/** `ServiceStack.Text.TypeSerializer.DeserializeFromString` method */
class ServiceStackTextTypeSerializerDeserializeFromStringMethod extends Method, UnsafeDeserializer {
ServiceStackTextTypeSerializerDeserializeFromStringMethod() {
this.getDeclaringType() instanceof ServiceStackTextTypeSerializerClass and
@@ -403,6 +432,7 @@ class ServiceStackTextTypeSerializerDeserializeFromStringMethod extends Method,
}
}
+/** `ServiceStack.Text.TypeSerializer.DeserializeFromReader` method */
class ServiceStackTextTypeSerializerDeserializeFromReaderMethod extends Method, UnsafeDeserializer {
ServiceStackTextTypeSerializerDeserializeFromReaderMethod() {
this.getDeclaringType() instanceof ServiceStackTextTypeSerializerClass and
@@ -411,6 +441,7 @@ class ServiceStackTextTypeSerializerDeserializeFromReaderMethod extends Method,
}
}
+/** `ServiceStack.Text.TypeSerializer.DeserializeFromStream` method */
class ServiceStackTextTypeSerializerDeserializeFromStreamMethod extends Method, UnsafeDeserializer {
ServiceStackTextTypeSerializerDeserializeFromStreamMethod() {
this.getDeclaringType() instanceof ServiceStackTextTypeSerializerClass and
@@ -424,6 +455,7 @@ private class ServiceStackTextCsvSerializerClass extends Class {
ServiceStackTextCsvSerializerClass() { this.hasQualifiedName("ServiceStack.Text.CsvSerializer") }
}
+/** `ServiceStack.Text.CsvSerializer.DeserializeFromString` method */
class ServiceStackTextCsvSerializerDeserializeFromStringMethod extends Method, UnsafeDeserializer {
ServiceStackTextCsvSerializerDeserializeFromStringMethod() {
this.getDeclaringType() instanceof ServiceStackTextCsvSerializerClass and
@@ -432,6 +464,7 @@ class ServiceStackTextCsvSerializerDeserializeFromStringMethod extends Method, U
}
}
+/** `ServiceStack.Text.TypeSeriCsvSerializeralizer.DeserializeFromReader` method */
class ServiceStackTextCsvSerializerDeserializeFromReaderMethod extends Method, UnsafeDeserializer {
ServiceStackTextCsvSerializerDeserializeFromReaderMethod() {
this.getDeclaringType() instanceof ServiceStackTextCsvSerializerClass and
@@ -440,6 +473,7 @@ class ServiceStackTextCsvSerializerDeserializeFromReaderMethod extends Method, U
}
}
+/** `ServiceStack.Text.CsvSerializer.DeserializeFromStream` method */
class ServiceStackTextCsvSerializerDeserializeFromStreamMethod extends Method, UnsafeDeserializer {
ServiceStackTextCsvSerializerDeserializeFromStreamMethod() {
this.getDeclaringType() instanceof ServiceStackTextCsvSerializerClass and
@@ -453,6 +487,7 @@ private class ServiceStackTextXmlSerializerClass extends Class {
ServiceStackTextXmlSerializerClass() { this.hasQualifiedName("ServiceStack.Text.XmlSerializer") }
}
+/** `ServiceStack.Text.XmlSerializer.DeserializeFromString` method */
class ServiceStackTextXmlSerializerDeserializeFromStringMethod extends Method, UnsafeDeserializer {
ServiceStackTextXmlSerializerDeserializeFromStringMethod() {
this.getDeclaringType() instanceof ServiceStackTextXmlSerializerClass and
@@ -461,6 +496,7 @@ class ServiceStackTextXmlSerializerDeserializeFromStringMethod extends Method, U
}
}
+/** `ServiceStack.Text.XmlSerializer.DeserializeFromReader` method */
class ServiceStackTextXmlSerializerDeserializeFromReaderMethod extends Method, UnsafeDeserializer {
ServiceStackTextXmlSerializerDeserializeFromReaderMethod() {
this.getDeclaringType() instanceof ServiceStackTextXmlSerializerClass and
@@ -469,6 +505,7 @@ class ServiceStackTextXmlSerializerDeserializeFromReaderMethod extends Method, U
}
}
+/** `ServiceStack.Text.XmlSerializer.DeserializeFromStream` method */
class ServiceStackTextXmlSerializerDeserializeFromStreamMethod extends Method, UnsafeDeserializer {
ServiceStackTextXmlSerializerDeserializeFromStreamMethod() {
this.getDeclaringType() instanceof ServiceStackTextXmlSerializerClass and
From d85b1a2d5fc2c8bf0d79c09c9bd353958ddfaa77 Mon Sep 17 00:00:00 2001
From: thank_you
Date: Wed, 28 Apr 2021 16:54:49 -0400
Subject: [PATCH 065/429] Replace recursive getAMember*() method
---
.../ql/src/experimental/semmle/python/frameworks/Stdlib.qll | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/python/ql/src/experimental/semmle/python/frameworks/Stdlib.qll b/python/ql/src/experimental/semmle/python/frameworks/Stdlib.qll
index 09777dd1037..ab702929855 100644
--- a/python/ql/src/experimental/semmle/python/frameworks/Stdlib.qll
+++ b/python/ql/src/experimental/semmle/python/frameworks/Stdlib.qll
@@ -27,7 +27,8 @@ private module NoSQL {
API::moduleImport("pymongo")
.getMember("MongoClient")
.getReturn()
- .getAMember*()
+ .getAMember()
+ .getAMember()
.getMember(any(PyMongoMethods pyMongoMethod))
.getACall()
}
@@ -45,7 +46,8 @@ private module NoSQL {
API::moduleImport("flask_pymongo")
.getMember("PyMongo")
.getReturn()
- .getAMember*()
+ .getAMember()
+ .getAMember()
.getMember(any(PyMongoFlaskMethods pyMongoFlaskMethod))
.getACall()
}
From 56dc4d886e0b86dd69865a75ed95e4430a24fddd Mon Sep 17 00:00:00 2001
From: thank_you
Date: Tue, 4 May 2021 19:11:59 -0400
Subject: [PATCH 066/429] Add comment on BsonObjectIdCall
---
.../ql/src/experimental/semmle/python/frameworks/Stdlib.qll | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/python/ql/src/experimental/semmle/python/frameworks/Stdlib.qll b/python/ql/src/experimental/semmle/python/frameworks/Stdlib.qll
index ab702929855..20858e596c5 100644
--- a/python/ql/src/experimental/semmle/python/frameworks/Stdlib.qll
+++ b/python/ql/src/experimental/semmle/python/frameworks/Stdlib.qll
@@ -92,6 +92,10 @@ private module NoSQL {
override DataFlow::Node getSanitizerNode() { result = this.getArg(0) }
}
+ /** ObjectId returns a string representing an id.
+ * If at any time ObjectId can't parse it's input (like when a tainted dict in passed in),
+ * then ObjectId will throw an error preventing the query from running.
+ */
private class BsonObjectIdCall extends DataFlow::CallCfgNode, NoSQLSanitizer::Range {
BsonObjectIdCall() {
this =
From c4a67e522cf6711e035a8b97cc640a7289d5b673 Mon Sep 17 00:00:00 2001
From: thank_you
Date: Tue, 4 May 2021 19:29:31 -0400
Subject: [PATCH 067/429] Rewrite query to take into account MongoClient and
subscript expressions
A couple of notes with these changes:
- Added TypeTracker pattern to handle subscript expressions. We've found that pymongo supports subscripts expressions when calling databases and collections. To resolve this, we implemented the TypeTracker pattern to catch those subscripts since CodeQL Python API modeling doesn't support subscript expressions.
- After some research, we've discovered that MongoEngine and Flask-MongoEngine utilize MongoClient under-the-hood. This requires us to rewrite the query so that instead of querying these libraries with specific queries, we are instead going to query for usages of MongoClient since all of the libraries we are targeting utilizes MongoClient under-the-hood.
---
.../semmle/python/frameworks/Stdlib.qll | 107 ++++++++++++------
1 file changed, 71 insertions(+), 36 deletions(-)
diff --git a/python/ql/src/experimental/semmle/python/frameworks/Stdlib.qll b/python/ql/src/experimental/semmle/python/frameworks/Stdlib.qll
index 20858e596c5..05a8e1ac911 100644
--- a/python/ql/src/experimental/semmle/python/frameworks/Stdlib.qll
+++ b/python/ql/src/experimental/semmle/python/frameworks/Stdlib.qll
@@ -11,46 +11,80 @@ private import experimental.semmle.python.Concepts
private import semmle.python.ApiGraphs
private module NoSQL {
- private class PyMongoMethods extends string {
- // These are all find-keyword relevant PyMongo collection level operation methods
- PyMongoMethods() {
+ /** Gets a reference to a `MongoClient` DB. */
+ private API::Node mongoClientInstance() {
+ result = API::moduleImport("pymongo").getMember("MongoClient").getReturn() or
+ result =
+ API::moduleImport("flask_mongoengine")
+ .getMember("MongoEngine")
+ .getReturn()
+ .getMember("get_db")
+ .getReturn() or
+ result = API::moduleImport("mongoengine").getMember("connect").getReturn() or
+ result = API::moduleImport("flask_pymongo").getMember("PyMongo").getReturn()
+ }
+
+ /** Gets a reference to a `MongoClient` DB. */
+ private DataFlow::LocalSourceNode mongoClientDB(DataFlow::TypeTracker t) {
+ t.start() and
+ (
+ exists(SubscriptNode subscript | result.asCfgNode() = subscript |
+ subscript.getObject() = mongoClientInstance().getAUse().asCfgNode()
+ )
+ or
+ result.(DataFlow::AttrRead).getObject() = mongoClientInstance().getAUse()
+ )
+ or
+ exists(DataFlow::TypeTracker t2 | result = mongoClientDB(t2).track(t2, t))
+ }
+
+ /** Gets a reference to a `MongoClient` DB. */
+ private DataFlow::Node mongoClientDB() {
+ mongoClientDB(DataFlow::TypeTracker::end()).flowsTo(result)
+ }
+
+ /** Gets a reference to a `MongoClient` collection. */
+ private DataFlow::LocalSourceNode mongoClientCollection(DataFlow::TypeTracker t) {
+ t.start() and
+ (
+ exists(SubscriptNode subscript | result.asCfgNode() = subscript |
+ subscript.getObject() = mongoClientDB().asCfgNode()
+ )
+ or
+ result.(DataFlow::AttrRead).getObject() = mongoClientDB()
+ )
+ or
+ exists(DataFlow::TypeTracker t2 | result = mongoClientCollection(t2).track(t2, t))
+ }
+
+ /** Gets a reference to a `MongoClient` collection. */
+ private DataFlow::Node mongoClientCollection() {
+ mongoClientCollection(DataFlow::TypeTracker::end()).flowsTo(result)
+ }
+
+ /** This class represents names of find_* relevant MongoClient collection level operation methods. */
+ private class MongoClientMethodNames extends string {
+ MongoClientMethodNames() {
+ // the find_one_or_404 method is only found in the Pymongo Flask library.
this in [
"find", "find_raw_batches", "find_one", "find_one_and_delete", "find_and_modify",
- "find_one_and_replace", "find_one_and_update"
+ "find_one_and_replace", "find_one_and_update", "find_one_or_404"
]
}
}
- private class PyMongoClientCall extends DataFlow::CallCfgNode, NoSQLQuery::Range {
- PyMongoClientCall() {
- this =
- API::moduleImport("pymongo")
- .getMember("MongoClient")
- .getReturn()
- .getAMember()
- .getAMember()
- .getMember(any(PyMongoMethods pyMongoMethod))
- .getACall()
- }
-
- override DataFlow::Node getQuery() { result = this.getArg(0) }
+ /** Gets a reference to a `MongoClient` Collection method. */
+ DataFlow::Node mongoClientMethod() {
+ result.(DataFlow::AttrRead).getAttributeName() instanceof MongoClientMethodNames and
+ (
+ result.(DataFlow::AttrRead).getObject() = mongoClientCollection() or
+ result.(DataFlow::AttrRead) = mongoClientCollection()
+ )
}
- private class PyMongoFlaskMethods extends string {
- PyMongoFlaskMethods() { this in ["find_one_or_404", any(PyMongoMethods pyMongoMethod)] }
- }
-
- private class PyMongoFlaskCall extends DataFlow::CallCfgNode, NoSQLQuery::Range {
- PyMongoFlaskCall() {
- this =
- API::moduleImport("flask_pymongo")
- .getMember("PyMongo")
- .getReturn()
- .getAMember()
- .getAMember()
- .getMember(any(PyMongoFlaskMethods pyMongoFlaskMethod))
- .getACall()
- }
+ /** Gets a reference to a `MongoClient` call */
+ private class MongoClientCall extends DataFlow::CallCfgNode, NoSQLQuery::Range {
+ MongoClientCall() { this.getFunction() = mongoClientMethod() }
override DataFlow::Node getQuery() { result = this.getArg(0) }
}
@@ -92,10 +126,11 @@ private module NoSQL {
override DataFlow::Node getSanitizerNode() { result = this.getArg(0) }
}
- /** ObjectId returns a string representing an id.
- * If at any time ObjectId can't parse it's input (like when a tainted dict in passed in),
- * then ObjectId will throw an error preventing the query from running.
- */
+ /**
+ * ObjectId returns a string representing an id.
+ * If at any time ObjectId can't parse it's input (like when a tainted dict in passed in),
+ * then ObjectId will throw an error preventing the query from running.
+ */
private class BsonObjectIdCall extends DataFlow::CallCfgNode, NoSQLSanitizer::Range {
BsonObjectIdCall() {
this =
From 1d36aa6649b6ac3ed9a28e8649f893a5944478b9 Mon Sep 17 00:00:00 2001
From: thank_you
Date: Fri, 7 May 2021 14:30:50 -0400
Subject: [PATCH 068/429] Add additional querying for mongoengine Document
subclassing
After further research, it was discovered that Flask-Mongoengine has multiple ways of allowing a developer to call the Document class. One way is by directly importing the Document class from the module. Another approach is to get the Document class via a mongoengine instance.
The update to this query checks for cases where the developer gets the Document class via the MongoEngine instance.
Other misc changes include setting the various predicates to private.
---
.../semmle/python/frameworks/Stdlib.qll | 53 +++++++++++++++++--
1 file changed, 48 insertions(+), 5 deletions(-)
diff --git a/python/ql/src/experimental/semmle/python/frameworks/Stdlib.qll b/python/ql/src/experimental/semmle/python/frameworks/Stdlib.qll
index 05a8e1ac911..9339780b06c 100644
--- a/python/ql/src/experimental/semmle/python/frameworks/Stdlib.qll
+++ b/python/ql/src/experimental/semmle/python/frameworks/Stdlib.qll
@@ -20,7 +20,10 @@ private module NoSQL {
.getReturn()
.getMember("get_db")
.getReturn() or
- result = API::moduleImport("mongoengine").getMember("connect").getReturn() or
+ result =
+ API::moduleImport(["mongoengine", "mongoengine.connection"])
+ .getMember(["get_db", "connect"])
+ .getReturn() or
result = API::moduleImport("flask_pymongo").getMember("PyMongo").getReturn()
}
@@ -65,7 +68,7 @@ private module NoSQL {
/** This class represents names of find_* relevant MongoClient collection level operation methods. */
private class MongoClientMethodNames extends string {
MongoClientMethodNames() {
- // the find_one_or_404 method is only found in the Pymongo Flask library.
+ // the find_one_or_404 method is only found in the Pymongo Flask library.
this in [
"find", "find_raw_batches", "find_one", "find_one_and_delete", "find_and_modify",
"find_one_and_replace", "find_one_and_update", "find_one_or_404"
@@ -74,7 +77,7 @@ private module NoSQL {
}
/** Gets a reference to a `MongoClient` Collection method. */
- DataFlow::Node mongoClientMethod() {
+ private DataFlow::Node mongoClientMethod() {
result.(DataFlow::AttrRead).getAttributeName() instanceof MongoClientMethodNames and
(
result.(DataFlow::AttrRead).getObject() = mongoClientCollection() or
@@ -102,8 +105,8 @@ private module NoSQL {
override DataFlow::Node getQuery() { result = this.getArgByName(_) }
}
- private class MongoEngineObjectsFlaskCall extends DataFlow::CallCfgNode, NoSQLQuery::Range {
- MongoEngineObjectsFlaskCall() {
+ private class FlaskMongoEngineObjectsCall extends DataFlow::CallCfgNode, NoSQLQuery::Range {
+ FlaskMongoEngineObjectsCall() {
this =
API::moduleImport("flask_mongoengine")
.getMember("MongoEngine")
@@ -117,6 +120,46 @@ private module NoSQL {
override DataFlow::Node getQuery() { result = this.getArgByName(_) }
}
+ private DataFlow::Node flaskMongoEngineInstance() {
+ result = API::moduleImport("flask_mongoengine").getMember("MongoEngine").getReturn().getAUse()
+ }
+
+ /**
+ * A MongoEngine.Document subclass which represents a single MongoDB table.
+ */
+ private class FlaskMongoEngineDocumentClass extends ClassValue {
+ FlaskMongoEngineDocumentClass() {
+ this.getASuperType().getName() = "Document" and
+ exists(AttrNode documentClass |
+ documentClass.getName() = "Document" and
+ documentClass.getObject() = flaskMongoEngineInstance().asCfgNode() and
+ // This is super hacky. It checks to see if the class is a subclass of a flaskMongoEngineInstance.Document
+ this.getASuperType()
+ .getAReference()
+ .getNode()
+ .(ClassExpr)
+ .contains(documentClass.getNode().getObject())
+ )
+ }
+ }
+
+ private class FlaskMongoEngineDocumentSubclassInstanceCall extends DataFlow::CallCfgNode,
+ NoSQLQuery::Range {
+ FlaskMongoEngineDocumentSubclassInstanceCall() {
+ exists(
+ DataFlow::CallCfgNode objectsCall,
+ FlaskMongoEngineDocumentClass flaskMongoEngineDocumentClass
+ |
+ objectsCall.getFunction().asExpr().(Attribute).getObject().getAFlowNode() =
+ flaskMongoEngineDocumentClass.getAReference() and
+ objectsCall.asCfgNode().(CallNode).getNode().getFunc().(Attribute).getName() = "objects" and
+ this = objectsCall
+ )
+ }
+
+ override DataFlow::Node getQuery() { result = this.getArgByName(_) }
+ }
+
private class MongoSanitizerCall extends DataFlow::CallCfgNode, NoSQLSanitizer::Range {
MongoSanitizerCall() {
this =
From 7693d696cc9f1c208cbcb39c2c3bde53253a329b Mon Sep 17 00:00:00 2001
From: thank_you
Date: Fri, 7 May 2021 14:36:02 -0400
Subject: [PATCH 069/429] Add additional query tests
To ensure that this query works against numerous usages of libraries such as PyMongo, Flask PyMongo, Mongoengine, and Flask Mongoengine, I've added a variety of query tests to test against. These tests deal with scenarious such as:
- Subscript expressions
- Mongoengine instances and Document subclasses
- Mongoengine connection usage
- And more...
---
.../CWE-943/flask_mongoengine_get_db_bad.py | 31 +++++++++++++++++
.../CWE-943/flask_mongoengine_get_db_good.py | 33 +++++++++++++++++++
.../CWE-943/mongoclient_subscript_bad.py | 29 ++++++++++++++++
.../CWE-943/mongoclient_subscript_good.py | 31 +++++++++++++++++
...goengine-flask-db-document-subclass-bad.py | 29 ++++++++++++++++
...oengine-flask-db-document-subclass-good.py | 31 +++++++++++++++++
.../CWE-943/mongoengine_connect_bad.py | 29 ++++++++++++++++
.../CWE-943/mongoengine_connect_good.py | 31 +++++++++++++++++
.../mongoengine_connect_via_connection_bad.py | 30 +++++++++++++++++
...mongoengine_connect_via_connection_good.py | 32 ++++++++++++++++++
.../CWE-943/mongoengine_get_db_bad.py | 29 ++++++++++++++++
.../CWE-943/mongoengine_get_db_good.py | 31 +++++++++++++++++
.../mongoengine_get_db_via_connection_bad.py | 30 +++++++++++++++++
.../mongoengine_get_db_via_connection_good.py | 32 ++++++++++++++++++
14 files changed, 428 insertions(+)
create mode 100644 python/ql/test/experimental/query-tests/Security/CWE-943/flask_mongoengine_get_db_bad.py
create mode 100644 python/ql/test/experimental/query-tests/Security/CWE-943/flask_mongoengine_get_db_good.py
create mode 100644 python/ql/test/experimental/query-tests/Security/CWE-943/mongoclient_subscript_bad.py
create mode 100644 python/ql/test/experimental/query-tests/Security/CWE-943/mongoclient_subscript_good.py
create mode 100644 python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine-flask-db-document-subclass-bad.py
create mode 100644 python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine-flask-db-document-subclass-good.py
create mode 100644 python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_connect_bad.py
create mode 100644 python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_connect_good.py
create mode 100644 python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_connect_via_connection_bad.py
create mode 100644 python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_connect_via_connection_good.py
create mode 100644 python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_get_db_bad.py
create mode 100644 python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_get_db_good.py
create mode 100644 python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_get_db_via_connection_bad.py
create mode 100644 python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_get_db_via_connection_good.py
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/flask_mongoengine_get_db_bad.py b/python/ql/test/experimental/query-tests/Security/CWE-943/flask_mongoengine_get_db_bad.py
new file mode 100644
index 00000000000..b4013ab1950
--- /dev/null
+++ b/python/ql/test/experimental/query-tests/Security/CWE-943/flask_mongoengine_get_db_bad.py
@@ -0,0 +1,31 @@
+from flask import Flask, request
+from flask_mongoengine import MongoEngine
+import json
+
+app = Flask(__name__)
+db = MongoEngine(app)
+db.init_app(app)
+
+
+class Movie(db.Document):
+ title = db.StringField(required=True)
+ year = db.IntField()
+ rated = db.StringField()
+ director = db.StringField()
+ actors = db.ListField()
+
+
+Movie(title='aa').save()
+Movie(title='bb').save()
+
+
+@app.route("/")
+def home_page():
+ unsanitized_search = request.args['search']
+ json_search = json.loads(unsanitized_search)
+
+ retrieved_db = db.get_db()
+ result = retrieved_db["Movie"].find_one_or_404({'name': json_search})
+
+# if __name__ == "__main__":
+# app.run(debug=True)
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/flask_mongoengine_get_db_good.py b/python/ql/test/experimental/query-tests/Security/CWE-943/flask_mongoengine_get_db_good.py
new file mode 100644
index 00000000000..1cc57a2b364
--- /dev/null
+++ b/python/ql/test/experimental/query-tests/Security/CWE-943/flask_mongoengine_get_db_good.py
@@ -0,0 +1,33 @@
+from flask import Flask, request
+from flask_mongoengine import MongoEngine
+from mongosanitizer.sanitizer import sanitize
+import json
+
+app = Flask(__name__)
+db = MongoEngine(app)
+db.init_app(app)
+
+
+class Movie(db.Document):
+ title = db.StringField(required=True)
+ year = db.IntField()
+ rated = db.StringField()
+ director = db.StringField()
+ actors = db.ListField()
+
+
+Movie(title='aa').save()
+Movie(title='bb').save()
+
+
+@app.route("/")
+def home_page():
+ unsanitized_search = request.args['search']
+ json_search = json.loads(unsanitized_search)
+ safe_search = sanitize(json_search)
+
+ retrieved_db = db.get_db()
+ result = retrieved_db["Movie"].find_one_or_404({'name': safe_search})
+
+# if __name__ == "__main__":
+# app.run(debug=True)
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoclient_subscript_bad.py b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoclient_subscript_bad.py
new file mode 100644
index 00000000000..14f1177a023
--- /dev/null
+++ b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoclient_subscript_bad.py
@@ -0,0 +1,29 @@
+from flask import Flask, request
+import mongoengine as me
+import json
+
+app = Flask(__name__)
+
+
+class Movie(me.Document):
+ title = me.StringField(required=True)
+ year = me.IntField()
+ rated = me.StringField()
+ director = me.StringField()
+ actors = me.ListField()
+
+
+Movie(title='aa').save()
+Movie(title='bb').save()
+
+
+@app.route("/")
+def home_page():
+ unsafe_search = request.args['search']
+ json_search = json.loads(unsafe_search)
+
+ db = me.connect('mydb')
+ data = db['mydb']['movie'].find({'name': json_search})
+
+# if __name__ == "__main__":
+# app.run(debug=True)
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoclient_subscript_good.py b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoclient_subscript_good.py
new file mode 100644
index 00000000000..1d1aad89780
--- /dev/null
+++ b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoclient_subscript_good.py
@@ -0,0 +1,31 @@
+from flask import Flask, request
+import mongoengine as me
+from mongosanitizer.sanitizer import sanitize
+import json
+
+app = Flask(__name__)
+
+
+class Movie(me.Document):
+ title = me.StringField(required=True)
+ year = me.IntField()
+ rated = me.StringField()
+ director = me.StringField()
+ actors = me.ListField()
+
+
+Movie(title='aa').save()
+Movie(title='bb').save()
+
+
+@app.route("/")
+def home_page():
+ unsafe_search = request.args['search']
+ json_search = json.loads(unsafe_search)
+ safe_search = sanitize(json_search)
+
+ db = me.connect('mydb')
+ data = db['mydb']['movie'].find({'name': safe_search})
+
+# if __name__ == "__main__":
+# app.run(debug=True)
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine-flask-db-document-subclass-bad.py b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine-flask-db-document-subclass-bad.py
new file mode 100644
index 00000000000..e8f05bba707
--- /dev/null
+++ b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine-flask-db-document-subclass-bad.py
@@ -0,0 +1,29 @@
+from flask import Flask, request
+from flask_mongoengine import MongoEngine
+import json
+
+app = Flask(__name__)
+app.config.from_pyfile('the-config.cfg')
+db = MongoEngine(app)
+
+class Movie(db.Document):
+ title = db.StringField(required=True)
+ year = db.IntField()
+ rated = db.StringField()
+ director = db.StringField()
+ actors = db.ListField()
+
+
+Movie(title='aa').save()
+Movie(title='bb').save()
+
+
+@app.route("/")
+def home_page():
+ unsafe_search = request.args['search']
+ json_search = json.loads(unsafe_search)
+
+ data = Movie.objects(__raw__=json_search)
+
+# if __name__ == "__main__":
+# app.run(debug=True)
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine-flask-db-document-subclass-good.py b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine-flask-db-document-subclass-good.py
new file mode 100644
index 00000000000..7fd0e927155
--- /dev/null
+++ b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine-flask-db-document-subclass-good.py
@@ -0,0 +1,31 @@
+from flask import Flask, request
+from flask_mongoengine import MongoEngine
+from mongosanitizer.sanitizer import sanitize
+import json
+
+app = Flask(__name__)
+app.config.from_pyfile('the-config.cfg')
+db = MongoEngine(app)
+
+class Movie(db.Document):
+ title = db.StringField(required=True)
+ year = db.IntField()
+ rated = db.StringField()
+ director = db.StringField()
+ actors = db.ListField()
+
+
+Movie(title='aa').save()
+Movie(title='bb').save()
+
+
+@app.route("/")
+def home_page():
+ unsafe_search = request.args['search']
+ json_search = json.loads(unsafe_search)
+ safe_search = sanitize(json_search)
+
+ data = Movie.objects(__raw__=safe_search)
+
+# if __name__ == "__main__":
+# app.run(debug=True)
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_connect_bad.py b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_connect_bad.py
new file mode 100644
index 00000000000..7d50fc8bd44
--- /dev/null
+++ b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_connect_bad.py
@@ -0,0 +1,29 @@
+from flask import Flask, request
+import mongoengine as me
+import json
+
+app = Flask(__name__)
+
+
+class Movie(me.Document):
+ title = me.StringField(required=True)
+ year = me.IntField()
+ rated = me.StringField()
+ director = me.StringField()
+ actors = me.ListField()
+
+
+Movie(title='aa').save()
+Movie(title='bb').save()
+
+
+@app.route("/")
+def home_page():
+ unsafe_search = request.args['search']
+ json_search = json.loads(unsafe_search)
+
+ db = me.connect('mydb')
+ data = db.mydb.movie.find({'name': json_search})
+
+# if __name__ == "__main__":
+# app.run(debug=True)
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_connect_good.py b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_connect_good.py
new file mode 100644
index 00000000000..0dfaac547dd
--- /dev/null
+++ b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_connect_good.py
@@ -0,0 +1,31 @@
+from flask import Flask, request
+import mongoengine as me
+from mongosanitizer.sanitizer import sanitize
+import json
+
+app = Flask(__name__)
+
+
+class Movie(me.Document):
+ title = me.StringField(required=True)
+ year = me.IntField()
+ rated = me.StringField()
+ director = me.StringField()
+ actors = me.ListField()
+
+
+Movie(title='aa').save()
+Movie(title='bb').save()
+
+
+@app.route("/")
+def home_page():
+ unsafe_search = request.args['search']
+ json_search = json.loads(unsafe_search)
+ safe_search = sanitize(json_search)
+
+ db = me.connect('mydb')
+ data = db.mydb.movie.find({'name': safe_search})
+
+# if __name__ == "__main__":
+# app.run(debug=True)
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_connect_via_connection_bad.py b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_connect_via_connection_bad.py
new file mode 100644
index 00000000000..10d9e17523f
--- /dev/null
+++ b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_connect_via_connection_bad.py
@@ -0,0 +1,30 @@
+from flask import Flask, request
+import mongoengine as me
+from mongoengine.connection import get_db, connect
+import json
+
+app = Flask(__name__)
+
+
+class Movie(me.Document):
+ title = me.StringField(required=True)
+ year = me.IntField()
+ rated = me.StringField()
+ director = me.StringField()
+ actors = me.ListField()
+
+
+Movie(title='aa').save()
+Movie(title='bb').save()
+
+
+@app.route("/")
+def home_page():
+ unsafe_search = request.args['search']
+ json_search = json.loads(unsafe_search)
+
+ db = connect('mydb')
+ data = db.mydb.movie.find({'name': json_search})
+
+# if __name__ == "__main__":
+# app.run(debug=True)
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_connect_via_connection_good.py b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_connect_via_connection_good.py
new file mode 100644
index 00000000000..d00d82894de
--- /dev/null
+++ b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_connect_via_connection_good.py
@@ -0,0 +1,32 @@
+from flask import Flask, request
+import mongoengine as me
+from mongoengine.connection import get_db, connect
+from mongosanitizer.sanitizer import sanitize
+import json
+
+app = Flask(__name__)
+
+
+class Movie(me.Document):
+ title = me.StringField(required=True)
+ year = me.IntField()
+ rated = me.StringField()
+ director = me.StringField()
+ actors = me.ListField()
+
+
+Movie(title='aa').save()
+Movie(title='bb').save()
+
+
+@app.route("/")
+def home_page():
+ unsafe_search = request.args['search']
+ json_search = json.loads(unsafe_search)
+ safe_search = sanitize(json_search)
+
+ db = connect('mydb')
+ data = db.mydb.movie.find({'name': json_search})
+
+# if __name__ == "__main__":
+# app.run(debug=True)
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_get_db_bad.py b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_get_db_bad.py
new file mode 100644
index 00000000000..5722881fc3e
--- /dev/null
+++ b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_get_db_bad.py
@@ -0,0 +1,29 @@
+from flask import Flask, request
+import mongoengine as me
+import json
+
+app = Flask(__name__)
+
+
+class Movie(me.Document):
+ title = me.StringField(required=True)
+ year = me.IntField()
+ rated = me.StringField()
+ director = me.StringField()
+ actors = me.ListField()
+
+
+Movie(title='aa').save()
+Movie(title='bb').save()
+
+
+@app.route("/")
+def home_page():
+ unsafe_search = request.args['search']
+ json_search = json.loads(unsafe_search)
+
+ db = me.get_db()
+ data = db.movie.find({'name': json_search})
+
+# if __name__ == "__main__":
+# app.run(debug=True)
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_get_db_good.py b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_get_db_good.py
new file mode 100644
index 00000000000..7c4aad77f8f
--- /dev/null
+++ b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_get_db_good.py
@@ -0,0 +1,31 @@
+from flask import Flask, request
+import mongoengine as me
+from mongosanitizer.sanitizer import sanitize
+import json
+
+app = Flask(__name__)
+
+
+class Movie(me.Document):
+ title = me.StringField(required=True)
+ year = me.IntField()
+ rated = me.StringField()
+ director = me.StringField()
+ actors = me.ListField()
+
+
+Movie(title='aa').save()
+Movie(title='bb').save()
+
+
+@app.route("/")
+def home_page():
+ unsafe_search = request.args['search']
+ json_search = json.loads(unsafe_search)
+ safe_search = sanitize(json_search)
+
+ db = me.get_db()
+ data = db.movie.find({'name': safe_search})
+
+# if __name__ == "__main__":
+# app.run(debug=True)
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_get_db_via_connection_bad.py b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_get_db_via_connection_bad.py
new file mode 100644
index 00000000000..3fe927e113a
--- /dev/null
+++ b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_get_db_via_connection_bad.py
@@ -0,0 +1,30 @@
+from flask import Flask, request
+import mongoengine as me
+from mongoengine.connection import get_db, connect
+import json
+
+app = Flask(__name__)
+
+
+class Movie(me.Document):
+ title = me.StringField(required=True)
+ year = me.IntField()
+ rated = me.StringField()
+ director = me.StringField()
+ actors = me.ListField()
+
+
+Movie(title='aa').save()
+Movie(title='bb').save()
+
+
+@app.route("/")
+def home_page():
+ unsafe_search = request.args['search']
+ json_search = json.loads(unsafe_search)
+
+ db = get_db()
+ data = db.movie.find({'name': json_search})
+
+# if __name__ == "__main__":
+# app.run(debug=True)
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_get_db_via_connection_good.py b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_get_db_via_connection_good.py
new file mode 100644
index 00000000000..bc5f48c037e
--- /dev/null
+++ b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_get_db_via_connection_good.py
@@ -0,0 +1,32 @@
+from flask import Flask, request
+import mongoengine as me
+from mongoengine.connection import get_db, connect
+from mongosanitizer.sanitizer import sanitize
+import json
+
+app = Flask(__name__)
+
+
+class Movie(me.Document):
+ title = me.StringField(required=True)
+ year = me.IntField()
+ rated = me.StringField()
+ director = me.StringField()
+ actors = me.ListField()
+
+
+Movie(title='aa').save()
+Movie(title='bb').save()
+
+
+@app.route("/")
+def home_page():
+ unsafe_search = request.args['search']
+ json_search = json.loads(unsafe_search)
+ safe_search = sanitize(json_search)
+
+ db = get_db()
+ data = db.movie.find({'name': safe_search})
+
+# if __name__ == "__main__":
+# app.run(debug=True)
From 8f8eff231aa30e1741f6d659ad0e6ced56cd4d03 Mon Sep 17 00:00:00 2001
From: thank_you
Date: Fri, 7 May 2021 15:08:48 -0400
Subject: [PATCH 070/429] Fix comment description of predicate
---
python/ql/src/experimental/semmle/python/frameworks/Stdlib.qll | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/python/ql/src/experimental/semmle/python/frameworks/Stdlib.qll b/python/ql/src/experimental/semmle/python/frameworks/Stdlib.qll
index 9339780b06c..4d8efefb941 100644
--- a/python/ql/src/experimental/semmle/python/frameworks/Stdlib.qll
+++ b/python/ql/src/experimental/semmle/python/frameworks/Stdlib.qll
@@ -11,7 +11,7 @@ private import experimental.semmle.python.Concepts
private import semmle.python.ApiGraphs
private module NoSQL {
- /** Gets a reference to a `MongoClient` DB. */
+ /** Gets a reference to a `MongoClient` instance. */
private API::Node mongoClientInstance() {
result = API::moduleImport("pymongo").getMember("MongoClient").getReturn() or
result =
From 9a44020af3ff8a979d6bcb24ad5fa9c1c0592d8d Mon Sep 17 00:00:00 2001
From: thank_you
Date: Fri, 7 May 2021 15:13:30 -0400
Subject: [PATCH 071/429] Rename StdLib.qll file to NoSQL.qll file
It makes more sense to have this file represent just the NoSQL module
---
.../semmle/python/frameworks/{Stdlib.qll => NoSQL.qll} | 0
1 file changed, 0 insertions(+), 0 deletions(-)
rename python/ql/src/experimental/semmle/python/frameworks/{Stdlib.qll => NoSQL.qll} (100%)
diff --git a/python/ql/src/experimental/semmle/python/frameworks/Stdlib.qll b/python/ql/src/experimental/semmle/python/frameworks/NoSQL.qll
similarity index 100%
rename from python/ql/src/experimental/semmle/python/frameworks/Stdlib.qll
rename to python/ql/src/experimental/semmle/python/frameworks/NoSQL.qll
From 83f087023130e34d80a8d3bdacace3c7e32010bb Mon Sep 17 00:00:00 2001
From: thank_you
Date: Fri, 7 May 2021 15:13:56 -0400
Subject: [PATCH 072/429] Update file path of module
---
python/ql/src/experimental/semmle/python/Frameworks.qll | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/python/ql/src/experimental/semmle/python/Frameworks.qll b/python/ql/src/experimental/semmle/python/Frameworks.qll
index ca1dd04e57d..116a6b65046 100644
--- a/python/ql/src/experimental/semmle/python/Frameworks.qll
+++ b/python/ql/src/experimental/semmle/python/Frameworks.qll
@@ -2,4 +2,4 @@
* Helper file that imports all framework modeling.
*/
-private import experimental.semmle.python.frameworks.Stdlib
+private import experimental.semmle.python.frameworks.NoSQL
From aa24c689bc71932800617bf2cfa695020e7f735a Mon Sep 17 00:00:00 2001
From: thank_you
Date: Fri, 7 May 2021 15:17:01 -0400
Subject: [PATCH 073/429] Add back accidentally deleted StdLib.qll file
---
.../ql/src/experimental/semmle/python/Frameworks.qll | 1 +
.../experimental/semmle/python/frameworks/StdLib.qll | 11 +++++++++++
2 files changed, 12 insertions(+)
create mode 100644 python/ql/src/experimental/semmle/python/frameworks/StdLib.qll
diff --git a/python/ql/src/experimental/semmle/python/Frameworks.qll b/python/ql/src/experimental/semmle/python/Frameworks.qll
index 116a6b65046..49b16d9443a 100644
--- a/python/ql/src/experimental/semmle/python/Frameworks.qll
+++ b/python/ql/src/experimental/semmle/python/Frameworks.qll
@@ -2,4 +2,5 @@
* Helper file that imports all framework modeling.
*/
+private import experimental.semmle.python.frameworks.Stdlib
private import experimental.semmle.python.frameworks.NoSQL
diff --git a/python/ql/src/experimental/semmle/python/frameworks/StdLib.qll b/python/ql/src/experimental/semmle/python/frameworks/StdLib.qll
new file mode 100644
index 00000000000..420caf0d73b
--- /dev/null
+++ b/python/ql/src/experimental/semmle/python/frameworks/StdLib.qll
@@ -0,0 +1,11 @@
+/**
+ * Provides classes modeling security-relevant aspects of the standard libraries.
+ * Note: some modeling is done internally in the dataflow/taint tracking implementation.
+ */
+
+private import python
+private import semmle.python.dataflow.new.DataFlow
+private import semmle.python.dataflow.new.TaintTracking
+private import semmle.python.dataflow.new.RemoteFlowSources
+private import experimental.semmle.python.Concepts
+private import semmle.python.ApiGraphs
From 65c6f1976ae4040f206cdcc33764b708a52a5c50 Mon Sep 17 00:00:00 2001
From: jorgectf
Date: Fri, 7 May 2021 23:00:08 +0200
Subject: [PATCH 074/429] Rename mongoengine-flask-db-document-subclass
---
...class-bad.py => mongoengine_flask_db_document_subclass_bad.py} | 0
...ass-good.py => mongoengine_flask_db_document_subclass_good.py} | 0
2 files changed, 0 insertions(+), 0 deletions(-)
rename python/ql/test/experimental/query-tests/Security/CWE-943/{mongoengine-flask-db-document-subclass-bad.py => mongoengine_flask_db_document_subclass_bad.py} (100%)
rename python/ql/test/experimental/query-tests/Security/CWE-943/{mongoengine-flask-db-document-subclass-good.py => mongoengine_flask_db_document_subclass_good.py} (100%)
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine-flask-db-document-subclass-bad.py b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_flask_db_document_subclass_bad.py
similarity index 100%
rename from python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine-flask-db-document-subclass-bad.py
rename to python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_flask_db_document_subclass_bad.py
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine-flask-db-document-subclass-good.py b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_flask_db_document_subclass_good.py
similarity index 100%
rename from python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine-flask-db-document-subclass-good.py
rename to python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_flask_db_document_subclass_good.py
From e7bdc73420e3d6ead5bd5ce7087e2da3d30a8d11 Mon Sep 17 00:00:00 2001
From: jorgectf
Date: Fri, 7 May 2021 23:00:21 +0200
Subject: [PATCH 075/429] Update .expected
---
.../Security/CWE-943/NoSQLInjection.expected | 119 ++++++++++++++++++
1 file changed, 119 insertions(+)
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/NoSQLInjection.expected b/python/ql/test/experimental/query-tests/Security/CWE-943/NoSQLInjection.expected
index 9135d887e31..c101db1f810 100644
--- a/python/ql/test/experimental/query-tests/Security/CWE-943/NoSQLInjection.expected
+++ b/python/ql/test/experimental/query-tests/Security/CWE-943/NoSQLInjection.expected
@@ -3,6 +3,13 @@ edges
| flask_mongoengine_bad.py:24:26:24:37 | ControlFlowNode for Attribute | flask_mongoengine_bad.py:24:26:24:47 | ControlFlowNode for Subscript |
| flask_mongoengine_bad.py:24:26:24:47 | ControlFlowNode for Subscript | flask_mongoengine_bad.py:25:30:25:47 | ControlFlowNode for unsanitized_search |
| flask_mongoengine_bad.py:25:30:25:47 | ControlFlowNode for unsanitized_search | flask_mongoengine_bad.py:27:36:27:46 | ControlFlowNode for json_search |
+| flask_mongoengine_get_db_bad.py:24:26:24:32 | ControlFlowNode for request | flask_mongoengine_get_db_bad.py:24:26:24:37 | ControlFlowNode for Attribute |
+| flask_mongoengine_get_db_bad.py:24:26:24:37 | ControlFlowNode for Attribute | flask_mongoengine_get_db_bad.py:24:26:24:47 | ControlFlowNode for Subscript |
+| flask_mongoengine_get_db_bad.py:24:26:24:47 | ControlFlowNode for Subscript | flask_mongoengine_get_db_bad.py:25:30:25:47 | ControlFlowNode for unsanitized_search |
+| flask_mongoengine_get_db_bad.py:25:30:25:47 | ControlFlowNode for unsanitized_search | flask_mongoengine_get_db_bad.py:28:52:28:72 | ControlFlowNode for Dict |
+| flask_mongoengine_get_db_good.py:25:26:25:32 | ControlFlowNode for request | flask_mongoengine_get_db_good.py:25:26:25:37 | ControlFlowNode for Attribute |
+| flask_mongoengine_get_db_good.py:25:26:25:37 | ControlFlowNode for Attribute | flask_mongoengine_get_db_good.py:25:26:25:47 | ControlFlowNode for Subscript |
+| flask_mongoengine_get_db_good.py:25:26:25:47 | ControlFlowNode for Subscript | flask_mongoengine_get_db_good.py:26:30:26:47 | ControlFlowNode for unsanitized_search |
| flask_mongoengine_good.py:25:21:25:27 | ControlFlowNode for request | flask_mongoengine_good.py:25:21:25:32 | ControlFlowNode for Attribute |
| flask_mongoengine_good.py:25:21:25:32 | ControlFlowNode for Attribute | flask_mongoengine_good.py:25:21:25:42 | ControlFlowNode for Subscript |
| flask_mongoengine_good.py:25:21:25:42 | ControlFlowNode for Subscript | flask_mongoengine_good.py:26:30:26:42 | ControlFlowNode for unsafe_search |
@@ -13,10 +20,52 @@ edges
| flask_pymongo_good.py:12:21:12:27 | ControlFlowNode for request | flask_pymongo_good.py:12:21:12:32 | ControlFlowNode for Attribute |
| flask_pymongo_good.py:12:21:12:32 | ControlFlowNode for Attribute | flask_pymongo_good.py:12:21:12:42 | ControlFlowNode for Subscript |
| flask_pymongo_good.py:12:21:12:42 | ControlFlowNode for Subscript | flask_pymongo_good.py:13:30:13:42 | ControlFlowNode for unsafe_search |
+| mongoclient_subscript_bad.py:22:21:22:27 | ControlFlowNode for request | mongoclient_subscript_bad.py:22:21:22:32 | ControlFlowNode for Attribute |
+| mongoclient_subscript_bad.py:22:21:22:32 | ControlFlowNode for Attribute | mongoclient_subscript_bad.py:22:21:22:42 | ControlFlowNode for Subscript |
+| mongoclient_subscript_bad.py:22:21:22:42 | ControlFlowNode for Subscript | mongoclient_subscript_bad.py:23:30:23:42 | ControlFlowNode for unsafe_search |
+| mongoclient_subscript_bad.py:23:30:23:42 | ControlFlowNode for unsafe_search | mongoclient_subscript_bad.py:26:37:26:57 | ControlFlowNode for Dict |
+| mongoclient_subscript_good.py:23:21:23:27 | ControlFlowNode for request | mongoclient_subscript_good.py:23:21:23:32 | ControlFlowNode for Attribute |
+| mongoclient_subscript_good.py:23:21:23:32 | ControlFlowNode for Attribute | mongoclient_subscript_good.py:23:21:23:42 | ControlFlowNode for Subscript |
+| mongoclient_subscript_good.py:23:21:23:42 | ControlFlowNode for Subscript | mongoclient_subscript_good.py:24:30:24:42 | ControlFlowNode for unsafe_search |
| mongoengine_bad.py:22:21:22:27 | ControlFlowNode for request | mongoengine_bad.py:22:21:22:32 | ControlFlowNode for Attribute |
| mongoengine_bad.py:22:21:22:32 | ControlFlowNode for Attribute | mongoengine_bad.py:22:21:22:42 | ControlFlowNode for Subscript |
| mongoengine_bad.py:22:21:22:42 | ControlFlowNode for Subscript | mongoengine_bad.py:23:30:23:42 | ControlFlowNode for unsafe_search |
| mongoengine_bad.py:23:30:23:42 | ControlFlowNode for unsafe_search | mongoengine_bad.py:25:34:25:44 | ControlFlowNode for json_search |
+| mongoengine_connect_bad.py:22:21:22:27 | ControlFlowNode for request | mongoengine_connect_bad.py:22:21:22:32 | ControlFlowNode for Attribute |
+| mongoengine_connect_bad.py:22:21:22:32 | ControlFlowNode for Attribute | mongoengine_connect_bad.py:22:21:22:42 | ControlFlowNode for Subscript |
+| mongoengine_connect_bad.py:22:21:22:42 | ControlFlowNode for Subscript | mongoengine_connect_bad.py:23:30:23:42 | ControlFlowNode for unsafe_search |
+| mongoengine_connect_bad.py:23:30:23:42 | ControlFlowNode for unsafe_search | mongoengine_connect_bad.py:26:31:26:51 | ControlFlowNode for Dict |
+| mongoengine_connect_good.py:23:21:23:27 | ControlFlowNode for request | mongoengine_connect_good.py:23:21:23:32 | ControlFlowNode for Attribute |
+| mongoengine_connect_good.py:23:21:23:32 | ControlFlowNode for Attribute | mongoengine_connect_good.py:23:21:23:42 | ControlFlowNode for Subscript |
+| mongoengine_connect_good.py:23:21:23:42 | ControlFlowNode for Subscript | mongoengine_connect_good.py:24:30:24:42 | ControlFlowNode for unsafe_search |
+| mongoengine_connect_via_connection_bad.py:23:21:23:27 | ControlFlowNode for request | mongoengine_connect_via_connection_bad.py:23:21:23:32 | ControlFlowNode for Attribute |
+| mongoengine_connect_via_connection_bad.py:23:21:23:32 | ControlFlowNode for Attribute | mongoengine_connect_via_connection_bad.py:23:21:23:42 | ControlFlowNode for Subscript |
+| mongoengine_connect_via_connection_bad.py:23:21:23:42 | ControlFlowNode for Subscript | mongoengine_connect_via_connection_bad.py:24:30:24:42 | ControlFlowNode for unsafe_search |
+| mongoengine_connect_via_connection_bad.py:24:30:24:42 | ControlFlowNode for unsafe_search | mongoengine_connect_via_connection_bad.py:27:31:27:51 | ControlFlowNode for Dict |
+| mongoengine_connect_via_connection_good.py:24:21:24:27 | ControlFlowNode for request | mongoengine_connect_via_connection_good.py:24:21:24:32 | ControlFlowNode for Attribute |
+| mongoengine_connect_via_connection_good.py:24:21:24:32 | ControlFlowNode for Attribute | mongoengine_connect_via_connection_good.py:24:21:24:42 | ControlFlowNode for Subscript |
+| mongoengine_connect_via_connection_good.py:24:21:24:42 | ControlFlowNode for Subscript | mongoengine_connect_via_connection_good.py:25:30:25:42 | ControlFlowNode for unsafe_search |
+| mongoengine_flask_db_document_subclass_bad.py:23:21:23:27 | ControlFlowNode for request | mongoengine_flask_db_document_subclass_bad.py:23:21:23:32 | ControlFlowNode for Attribute |
+| mongoengine_flask_db_document_subclass_bad.py:23:21:23:32 | ControlFlowNode for Attribute | mongoengine_flask_db_document_subclass_bad.py:23:21:23:42 | ControlFlowNode for Subscript |
+| mongoengine_flask_db_document_subclass_bad.py:23:21:23:42 | ControlFlowNode for Subscript | mongoengine_flask_db_document_subclass_bad.py:24:30:24:42 | ControlFlowNode for unsafe_search |
+| mongoengine_flask_db_document_subclass_bad.py:24:30:24:42 | ControlFlowNode for unsafe_search | mongoengine_flask_db_document_subclass_bad.py:26:34:26:44 | ControlFlowNode for json_search |
+| mongoengine_flask_db_document_subclass_good.py:24:21:24:27 | ControlFlowNode for request | mongoengine_flask_db_document_subclass_good.py:24:21:24:32 | ControlFlowNode for Attribute |
+| mongoengine_flask_db_document_subclass_good.py:24:21:24:32 | ControlFlowNode for Attribute | mongoengine_flask_db_document_subclass_good.py:24:21:24:42 | ControlFlowNode for Subscript |
+| mongoengine_flask_db_document_subclass_good.py:24:21:24:42 | ControlFlowNode for Subscript | mongoengine_flask_db_document_subclass_good.py:25:30:25:42 | ControlFlowNode for unsafe_search |
+| mongoengine_get_db_bad.py:22:21:22:27 | ControlFlowNode for request | mongoengine_get_db_bad.py:22:21:22:32 | ControlFlowNode for Attribute |
+| mongoengine_get_db_bad.py:22:21:22:32 | ControlFlowNode for Attribute | mongoengine_get_db_bad.py:22:21:22:42 | ControlFlowNode for Subscript |
+| mongoengine_get_db_bad.py:22:21:22:42 | ControlFlowNode for Subscript | mongoengine_get_db_bad.py:23:30:23:42 | ControlFlowNode for unsafe_search |
+| mongoengine_get_db_bad.py:23:30:23:42 | ControlFlowNode for unsafe_search | mongoengine_get_db_bad.py:26:26:26:46 | ControlFlowNode for Dict |
+| mongoengine_get_db_good.py:23:21:23:27 | ControlFlowNode for request | mongoengine_get_db_good.py:23:21:23:32 | ControlFlowNode for Attribute |
+| mongoengine_get_db_good.py:23:21:23:32 | ControlFlowNode for Attribute | mongoengine_get_db_good.py:23:21:23:42 | ControlFlowNode for Subscript |
+| mongoengine_get_db_good.py:23:21:23:42 | ControlFlowNode for Subscript | mongoengine_get_db_good.py:24:30:24:42 | ControlFlowNode for unsafe_search |
+| mongoengine_get_db_via_connection_bad.py:23:21:23:27 | ControlFlowNode for request | mongoengine_get_db_via_connection_bad.py:23:21:23:32 | ControlFlowNode for Attribute |
+| mongoengine_get_db_via_connection_bad.py:23:21:23:32 | ControlFlowNode for Attribute | mongoengine_get_db_via_connection_bad.py:23:21:23:42 | ControlFlowNode for Subscript |
+| mongoengine_get_db_via_connection_bad.py:23:21:23:42 | ControlFlowNode for Subscript | mongoengine_get_db_via_connection_bad.py:24:30:24:42 | ControlFlowNode for unsafe_search |
+| mongoengine_get_db_via_connection_bad.py:24:30:24:42 | ControlFlowNode for unsafe_search | mongoengine_get_db_via_connection_bad.py:27:26:27:46 | ControlFlowNode for Dict |
+| mongoengine_get_db_via_connection_good.py:24:21:24:27 | ControlFlowNode for request | mongoengine_get_db_via_connection_good.py:24:21:24:32 | ControlFlowNode for Attribute |
+| mongoengine_get_db_via_connection_good.py:24:21:24:32 | ControlFlowNode for Attribute | mongoengine_get_db_via_connection_good.py:24:21:24:42 | ControlFlowNode for Subscript |
+| mongoengine_get_db_via_connection_good.py:24:21:24:42 | ControlFlowNode for Subscript | mongoengine_get_db_via_connection_good.py:25:30:25:42 | ControlFlowNode for unsafe_search |
| mongoengine_good.py:23:21:23:27 | ControlFlowNode for request | mongoengine_good.py:23:21:23:32 | ControlFlowNode for Attribute |
| mongoengine_good.py:23:21:23:32 | ControlFlowNode for Attribute | mongoengine_good.py:23:21:23:42 | ControlFlowNode for Subscript |
| mongoengine_good.py:23:21:23:42 | ControlFlowNode for Subscript | mongoengine_good.py:24:30:24:42 | ControlFlowNode for unsafe_search |
@@ -33,6 +82,15 @@ nodes
| flask_mongoengine_bad.py:24:26:24:47 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
| flask_mongoengine_bad.py:25:30:25:47 | ControlFlowNode for unsanitized_search | semmle.label | ControlFlowNode for unsanitized_search |
| flask_mongoengine_bad.py:27:36:27:46 | ControlFlowNode for json_search | semmle.label | ControlFlowNode for json_search |
+| flask_mongoengine_get_db_bad.py:24:26:24:32 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
+| flask_mongoengine_get_db_bad.py:24:26:24:37 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
+| flask_mongoengine_get_db_bad.py:24:26:24:47 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
+| flask_mongoengine_get_db_bad.py:25:30:25:47 | ControlFlowNode for unsanitized_search | semmle.label | ControlFlowNode for unsanitized_search |
+| flask_mongoengine_get_db_bad.py:28:52:28:72 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict |
+| flask_mongoengine_get_db_good.py:25:26:25:32 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
+| flask_mongoengine_get_db_good.py:25:26:25:37 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
+| flask_mongoengine_get_db_good.py:25:26:25:47 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
+| flask_mongoengine_get_db_good.py:26:30:26:47 | ControlFlowNode for unsanitized_search | semmle.label | ControlFlowNode for unsanitized_search |
| flask_mongoengine_good.py:25:21:25:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
| flask_mongoengine_good.py:25:21:25:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
| flask_mongoengine_good.py:25:21:25:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
@@ -46,11 +104,65 @@ nodes
| flask_pymongo_good.py:12:21:12:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
| flask_pymongo_good.py:12:21:12:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
| flask_pymongo_good.py:13:30:13:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search |
+| mongoclient_subscript_bad.py:22:21:22:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
+| mongoclient_subscript_bad.py:22:21:22:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
+| mongoclient_subscript_bad.py:22:21:22:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
+| mongoclient_subscript_bad.py:23:30:23:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search |
+| mongoclient_subscript_bad.py:26:37:26:57 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict |
+| mongoclient_subscript_good.py:23:21:23:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
+| mongoclient_subscript_good.py:23:21:23:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
+| mongoclient_subscript_good.py:23:21:23:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
+| mongoclient_subscript_good.py:24:30:24:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search |
| mongoengine_bad.py:22:21:22:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
| mongoengine_bad.py:22:21:22:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
| mongoengine_bad.py:22:21:22:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
| mongoengine_bad.py:23:30:23:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search |
| mongoengine_bad.py:25:34:25:44 | ControlFlowNode for json_search | semmle.label | ControlFlowNode for json_search |
+| mongoengine_connect_bad.py:22:21:22:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
+| mongoengine_connect_bad.py:22:21:22:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
+| mongoengine_connect_bad.py:22:21:22:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
+| mongoengine_connect_bad.py:23:30:23:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search |
+| mongoengine_connect_bad.py:26:31:26:51 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict |
+| mongoengine_connect_good.py:23:21:23:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
+| mongoengine_connect_good.py:23:21:23:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
+| mongoengine_connect_good.py:23:21:23:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
+| mongoengine_connect_good.py:24:30:24:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search |
+| mongoengine_connect_via_connection_bad.py:23:21:23:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
+| mongoengine_connect_via_connection_bad.py:23:21:23:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
+| mongoengine_connect_via_connection_bad.py:23:21:23:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
+| mongoengine_connect_via_connection_bad.py:24:30:24:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search |
+| mongoengine_connect_via_connection_bad.py:27:31:27:51 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict |
+| mongoengine_connect_via_connection_good.py:24:21:24:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
+| mongoengine_connect_via_connection_good.py:24:21:24:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
+| mongoengine_connect_via_connection_good.py:24:21:24:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
+| mongoengine_connect_via_connection_good.py:25:30:25:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search |
+| mongoengine_flask_db_document_subclass_bad.py:23:21:23:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
+| mongoengine_flask_db_document_subclass_bad.py:23:21:23:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
+| mongoengine_flask_db_document_subclass_bad.py:23:21:23:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
+| mongoengine_flask_db_document_subclass_bad.py:24:30:24:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search |
+| mongoengine_flask_db_document_subclass_bad.py:26:34:26:44 | ControlFlowNode for json_search | semmle.label | ControlFlowNode for json_search |
+| mongoengine_flask_db_document_subclass_good.py:24:21:24:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
+| mongoengine_flask_db_document_subclass_good.py:24:21:24:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
+| mongoengine_flask_db_document_subclass_good.py:24:21:24:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
+| mongoengine_flask_db_document_subclass_good.py:25:30:25:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search |
+| mongoengine_get_db_bad.py:22:21:22:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
+| mongoengine_get_db_bad.py:22:21:22:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
+| mongoengine_get_db_bad.py:22:21:22:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
+| mongoengine_get_db_bad.py:23:30:23:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search |
+| mongoengine_get_db_bad.py:26:26:26:46 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict |
+| mongoengine_get_db_good.py:23:21:23:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
+| mongoengine_get_db_good.py:23:21:23:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
+| mongoengine_get_db_good.py:23:21:23:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
+| mongoengine_get_db_good.py:24:30:24:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search |
+| mongoengine_get_db_via_connection_bad.py:23:21:23:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
+| mongoengine_get_db_via_connection_bad.py:23:21:23:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
+| mongoengine_get_db_via_connection_bad.py:23:21:23:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
+| mongoengine_get_db_via_connection_bad.py:24:30:24:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search |
+| mongoengine_get_db_via_connection_bad.py:27:26:27:46 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict |
+| mongoengine_get_db_via_connection_good.py:24:21:24:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
+| mongoengine_get_db_via_connection_good.py:24:21:24:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
+| mongoengine_get_db_via_connection_good.py:24:21:24:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
+| mongoengine_get_db_via_connection_good.py:25:30:25:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search |
| mongoengine_good.py:23:21:23:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
| mongoengine_good.py:23:21:23:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
| mongoengine_good.py:23:21:23:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
@@ -66,6 +178,13 @@ nodes
| pymongo_good.py:13:30:13:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search |
#select
| flask_mongoengine_bad.py:27:36:27:46 | ControlFlowNode for json_search | flask_mongoengine_bad.py:24:26:24:32 | ControlFlowNode for request | flask_mongoengine_bad.py:27:36:27:46 | ControlFlowNode for json_search | $@ NoSQL query contains an unsanitized $@ | flask_mongoengine_bad.py:27:36:27:46 | ControlFlowNode for json_search | This | flask_mongoengine_bad.py:24:26:24:32 | ControlFlowNode for request | user-provided value |
+| flask_mongoengine_get_db_bad.py:28:52:28:72 | ControlFlowNode for Dict | flask_mongoengine_get_db_bad.py:24:26:24:32 | ControlFlowNode for request | flask_mongoengine_get_db_bad.py:28:52:28:72 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | flask_mongoengine_get_db_bad.py:28:52:28:72 | ControlFlowNode for Dict | This | flask_mongoengine_get_db_bad.py:24:26:24:32 | ControlFlowNode for request | user-provided value |
| flask_pymongo_bad.py:14:33:14:53 | ControlFlowNode for Dict | flask_pymongo_bad.py:11:26:11:32 | ControlFlowNode for request | flask_pymongo_bad.py:14:33:14:53 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | flask_pymongo_bad.py:14:33:14:53 | ControlFlowNode for Dict | This | flask_pymongo_bad.py:11:26:11:32 | ControlFlowNode for request | user-provided value |
+| mongoclient_subscript_bad.py:26:37:26:57 | ControlFlowNode for Dict | mongoclient_subscript_bad.py:22:21:22:27 | ControlFlowNode for request | mongoclient_subscript_bad.py:26:37:26:57 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | mongoclient_subscript_bad.py:26:37:26:57 | ControlFlowNode for Dict | This | mongoclient_subscript_bad.py:22:21:22:27 | ControlFlowNode for request | user-provided value |
| mongoengine_bad.py:25:34:25:44 | ControlFlowNode for json_search | mongoengine_bad.py:22:21:22:27 | ControlFlowNode for request | mongoengine_bad.py:25:34:25:44 | ControlFlowNode for json_search | $@ NoSQL query contains an unsanitized $@ | mongoengine_bad.py:25:34:25:44 | ControlFlowNode for json_search | This | mongoengine_bad.py:22:21:22:27 | ControlFlowNode for request | user-provided value |
+| mongoengine_connect_bad.py:26:31:26:51 | ControlFlowNode for Dict | mongoengine_connect_bad.py:22:21:22:27 | ControlFlowNode for request | mongoengine_connect_bad.py:26:31:26:51 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | mongoengine_connect_bad.py:26:31:26:51 | ControlFlowNode for Dict | This | mongoengine_connect_bad.py:22:21:22:27 | ControlFlowNode for request | user-provided value |
+| mongoengine_connect_via_connection_bad.py:27:31:27:51 | ControlFlowNode for Dict | mongoengine_connect_via_connection_bad.py:23:21:23:27 | ControlFlowNode for request | mongoengine_connect_via_connection_bad.py:27:31:27:51 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | mongoengine_connect_via_connection_bad.py:27:31:27:51 | ControlFlowNode for Dict | This | mongoengine_connect_via_connection_bad.py:23:21:23:27 | ControlFlowNode for request | user-provided value |
+| mongoengine_flask_db_document_subclass_bad.py:26:34:26:44 | ControlFlowNode for json_search | mongoengine_flask_db_document_subclass_bad.py:23:21:23:27 | ControlFlowNode for request | mongoengine_flask_db_document_subclass_bad.py:26:34:26:44 | ControlFlowNode for json_search | $@ NoSQL query contains an unsanitized $@ | mongoengine_flask_db_document_subclass_bad.py:26:34:26:44 | ControlFlowNode for json_search | This | mongoengine_flask_db_document_subclass_bad.py:23:21:23:27 | ControlFlowNode for request | user-provided value |
+| mongoengine_get_db_bad.py:26:26:26:46 | ControlFlowNode for Dict | mongoengine_get_db_bad.py:22:21:22:27 | ControlFlowNode for request | mongoengine_get_db_bad.py:26:26:26:46 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | mongoengine_get_db_bad.py:26:26:26:46 | ControlFlowNode for Dict | This | mongoengine_get_db_bad.py:22:21:22:27 | ControlFlowNode for request | user-provided value |
+| mongoengine_get_db_via_connection_bad.py:27:26:27:46 | ControlFlowNode for Dict | mongoengine_get_db_via_connection_bad.py:23:21:23:27 | ControlFlowNode for request | mongoengine_get_db_via_connection_bad.py:27:26:27:46 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | mongoengine_get_db_via_connection_bad.py:27:26:27:46 | ControlFlowNode for Dict | This | mongoengine_get_db_via_connection_bad.py:23:21:23:27 | ControlFlowNode for request | user-provided value |
| pymongo_bad.py:14:44:14:64 | ControlFlowNode for Dict | pymongo_bad.py:11:21:11:27 | ControlFlowNode for request | pymongo_bad.py:14:44:14:64 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | pymongo_bad.py:14:44:14:64 | ControlFlowNode for Dict | This | pymongo_bad.py:11:21:11:27 | ControlFlowNode for request | user-provided value |
From 0fc044dfd574729cb447b4fadc5cece1cc1b5653 Mon Sep 17 00:00:00 2001
From: jorgectf
Date: Fri, 7 May 2021 23:03:23 +0200
Subject: [PATCH 076/429] Checkout Stdlib.qll
---
.../experimental/semmle/python/frameworks/Stdlib.qll | 11 +++++++++++
1 file changed, 11 insertions(+)
create mode 100644 python/ql/src/experimental/semmle/python/frameworks/Stdlib.qll
diff --git a/python/ql/src/experimental/semmle/python/frameworks/Stdlib.qll b/python/ql/src/experimental/semmle/python/frameworks/Stdlib.qll
new file mode 100644
index 00000000000..420caf0d73b
--- /dev/null
+++ b/python/ql/src/experimental/semmle/python/frameworks/Stdlib.qll
@@ -0,0 +1,11 @@
+/**
+ * Provides classes modeling security-relevant aspects of the standard libraries.
+ * Note: some modeling is done internally in the dataflow/taint tracking implementation.
+ */
+
+private import python
+private import semmle.python.dataflow.new.DataFlow
+private import semmle.python.dataflow.new.TaintTracking
+private import semmle.python.dataflow.new.RemoteFlowSources
+private import experimental.semmle.python.Concepts
+private import semmle.python.ApiGraphs
From 67bc576e30c5029164a0511abeb7af78d5ead982 Mon Sep 17 00:00:00 2001
From: "${sleep,5}" <52643283+mrthankyou@users.noreply.github.com>
Date: Fri, 7 May 2021 17:37:02 -0400
Subject: [PATCH 077/429] Delete StdLib.qll
---
.../experimental/semmle/python/frameworks/StdLib.qll | 11 -----------
1 file changed, 11 deletions(-)
delete mode 100644 python/ql/src/experimental/semmle/python/frameworks/StdLib.qll
diff --git a/python/ql/src/experimental/semmle/python/frameworks/StdLib.qll b/python/ql/src/experimental/semmle/python/frameworks/StdLib.qll
deleted file mode 100644
index 420caf0d73b..00000000000
--- a/python/ql/src/experimental/semmle/python/frameworks/StdLib.qll
+++ /dev/null
@@ -1,11 +0,0 @@
-/**
- * Provides classes modeling security-relevant aspects of the standard libraries.
- * Note: some modeling is done internally in the dataflow/taint tracking implementation.
- */
-
-private import python
-private import semmle.python.dataflow.new.DataFlow
-private import semmle.python.dataflow.new.TaintTracking
-private import semmle.python.dataflow.new.RemoteFlowSources
-private import experimental.semmle.python.Concepts
-private import semmle.python.ApiGraphs
From 07c3e224280046e26ee0c0c978fd71e2ff79c20c Mon Sep 17 00:00:00 2001
From: thank_you
Date: Sun, 9 May 2021 19:23:52 -0400
Subject: [PATCH 078/429] Fix method name to match flask_mongoengine library
---
.../Security/CWE-943/flask_mongoengine_get_db_bad.py | 2 +-
.../Security/CWE-943/flask_mongoengine_get_db_good.py | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/flask_mongoengine_get_db_bad.py b/python/ql/test/experimental/query-tests/Security/CWE-943/flask_mongoengine_get_db_bad.py
index b4013ab1950..df8dde96f3e 100644
--- a/python/ql/test/experimental/query-tests/Security/CWE-943/flask_mongoengine_get_db_bad.py
+++ b/python/ql/test/experimental/query-tests/Security/CWE-943/flask_mongoengine_get_db_bad.py
@@ -25,7 +25,7 @@ def home_page():
json_search = json.loads(unsanitized_search)
retrieved_db = db.get_db()
- result = retrieved_db["Movie"].find_one_or_404({'name': json_search})
+ result = retrieved_db["Movie"].find({'name': json_search})
# if __name__ == "__main__":
# app.run(debug=True)
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/flask_mongoengine_get_db_good.py b/python/ql/test/experimental/query-tests/Security/CWE-943/flask_mongoengine_get_db_good.py
index 1cc57a2b364..ce5fa89dc7f 100644
--- a/python/ql/test/experimental/query-tests/Security/CWE-943/flask_mongoengine_get_db_good.py
+++ b/python/ql/test/experimental/query-tests/Security/CWE-943/flask_mongoengine_get_db_good.py
@@ -27,7 +27,7 @@ def home_page():
safe_search = sanitize(json_search)
retrieved_db = db.get_db()
- result = retrieved_db["Movie"].find_one_or_404({'name': safe_search})
+ result = retrieved_db["Movie"].find({'name': safe_search})
# if __name__ == "__main__":
# app.run(debug=True)
From 0238e51c1067754ead8b5daaaa1820b59991decd Mon Sep 17 00:00:00 2001
From: thank_you
Date: Sun, 9 May 2021 19:42:40 -0400
Subject: [PATCH 079/429] Add checks for EmbeddedDocument classes
Mongoengine supports EmbeddedDocument documents. We should check for this in our query.
---
.../experimental/semmle/python/frameworks/NoSQL.qll | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/python/ql/src/experimental/semmle/python/frameworks/NoSQL.qll b/python/ql/src/experimental/semmle/python/frameworks/NoSQL.qll
index 4d8efefb941..94d327d7901 100644
--- a/python/ql/src/experimental/semmle/python/frameworks/NoSQL.qll
+++ b/python/ql/src/experimental/semmle/python/frameworks/NoSQL.qll
@@ -96,7 +96,7 @@ private module NoSQL {
MongoEngineObjectsCall() {
this =
API::moduleImport("mongoengine")
- .getMember("Document")
+ .getMember(["Document", "EmbeddedDocument"])
.getASubclass()
.getMember("objects")
.getACall()
@@ -111,7 +111,7 @@ private module NoSQL {
API::moduleImport("flask_mongoengine")
.getMember("MongoEngine")
.getReturn()
- .getMember("Document")
+ .getMember(["Document", "EmbeddedDocument"])
.getASubclass()
.getMember("objects")
.getACall()
@@ -125,13 +125,13 @@ private module NoSQL {
}
/**
- * A MongoEngine.Document subclass which represents a single MongoDB table.
+ * A MongoEngine.Document or MongoEngine.EmbeddedDocument subclass which represents a MongoDB document.
*/
private class FlaskMongoEngineDocumentClass extends ClassValue {
FlaskMongoEngineDocumentClass() {
- this.getASuperType().getName() = "Document" and
+ this.getASuperType().getName() in ["Document", "EmbeddedDocument"] and
exists(AttrNode documentClass |
- documentClass.getName() = "Document" and
+ documentClass.getName() in ["Document", "EmbeddedDocument"] and
documentClass.getObject() = flaskMongoEngineInstance().asCfgNode() and
// This is super hacky. It checks to see if the class is a subclass of a flaskMongoEngineInstance.Document
this.getASuperType()
From 3e25b14a680b71ee994736dd11542ecbbe54be72 Mon Sep 17 00:00:00 2001
From: thank_you
Date: Tue, 11 May 2021 20:07:09 -0400
Subject: [PATCH 080/429] Update NoSQLInjection.expected
---
.../query-tests/Security/CWE-943/NoSQLInjection.expected | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/NoSQLInjection.expected b/python/ql/test/experimental/query-tests/Security/CWE-943/NoSQLInjection.expected
index c101db1f810..fd02261ed90 100644
--- a/python/ql/test/experimental/query-tests/Security/CWE-943/NoSQLInjection.expected
+++ b/python/ql/test/experimental/query-tests/Security/CWE-943/NoSQLInjection.expected
@@ -6,7 +6,7 @@ edges
| flask_mongoengine_get_db_bad.py:24:26:24:32 | ControlFlowNode for request | flask_mongoengine_get_db_bad.py:24:26:24:37 | ControlFlowNode for Attribute |
| flask_mongoengine_get_db_bad.py:24:26:24:37 | ControlFlowNode for Attribute | flask_mongoengine_get_db_bad.py:24:26:24:47 | ControlFlowNode for Subscript |
| flask_mongoengine_get_db_bad.py:24:26:24:47 | ControlFlowNode for Subscript | flask_mongoengine_get_db_bad.py:25:30:25:47 | ControlFlowNode for unsanitized_search |
-| flask_mongoengine_get_db_bad.py:25:30:25:47 | ControlFlowNode for unsanitized_search | flask_mongoengine_get_db_bad.py:28:52:28:72 | ControlFlowNode for Dict |
+| flask_mongoengine_get_db_bad.py:25:30:25:47 | ControlFlowNode for unsanitized_search | flask_mongoengine_get_db_bad.py:28:41:28:61 | ControlFlowNode for Dict |
| flask_mongoengine_get_db_good.py:25:26:25:32 | ControlFlowNode for request | flask_mongoengine_get_db_good.py:25:26:25:37 | ControlFlowNode for Attribute |
| flask_mongoengine_get_db_good.py:25:26:25:37 | ControlFlowNode for Attribute | flask_mongoengine_get_db_good.py:25:26:25:47 | ControlFlowNode for Subscript |
| flask_mongoengine_get_db_good.py:25:26:25:47 | ControlFlowNode for Subscript | flask_mongoengine_get_db_good.py:26:30:26:47 | ControlFlowNode for unsanitized_search |
@@ -86,7 +86,7 @@ nodes
| flask_mongoengine_get_db_bad.py:24:26:24:37 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
| flask_mongoengine_get_db_bad.py:24:26:24:47 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
| flask_mongoengine_get_db_bad.py:25:30:25:47 | ControlFlowNode for unsanitized_search | semmle.label | ControlFlowNode for unsanitized_search |
-| flask_mongoengine_get_db_bad.py:28:52:28:72 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict |
+| flask_mongoengine_get_db_bad.py:28:41:28:61 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict |
| flask_mongoengine_get_db_good.py:25:26:25:32 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
| flask_mongoengine_get_db_good.py:25:26:25:37 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
| flask_mongoengine_get_db_good.py:25:26:25:47 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
@@ -178,7 +178,7 @@ nodes
| pymongo_good.py:13:30:13:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search |
#select
| flask_mongoengine_bad.py:27:36:27:46 | ControlFlowNode for json_search | flask_mongoengine_bad.py:24:26:24:32 | ControlFlowNode for request | flask_mongoengine_bad.py:27:36:27:46 | ControlFlowNode for json_search | $@ NoSQL query contains an unsanitized $@ | flask_mongoengine_bad.py:27:36:27:46 | ControlFlowNode for json_search | This | flask_mongoengine_bad.py:24:26:24:32 | ControlFlowNode for request | user-provided value |
-| flask_mongoengine_get_db_bad.py:28:52:28:72 | ControlFlowNode for Dict | flask_mongoengine_get_db_bad.py:24:26:24:32 | ControlFlowNode for request | flask_mongoengine_get_db_bad.py:28:52:28:72 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | flask_mongoengine_get_db_bad.py:28:52:28:72 | ControlFlowNode for Dict | This | flask_mongoengine_get_db_bad.py:24:26:24:32 | ControlFlowNode for request | user-provided value |
+| flask_mongoengine_get_db_bad.py:28:41:28:61 | ControlFlowNode for Dict | flask_mongoengine_get_db_bad.py:24:26:24:32 | ControlFlowNode for request | flask_mongoengine_get_db_bad.py:28:41:28:61 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | flask_mongoengine_get_db_bad.py:28:41:28:61 | ControlFlowNode for Dict | This | flask_mongoengine_get_db_bad.py:24:26:24:32 | ControlFlowNode for request | user-provided value |
| flask_pymongo_bad.py:14:33:14:53 | ControlFlowNode for Dict | flask_pymongo_bad.py:11:26:11:32 | ControlFlowNode for request | flask_pymongo_bad.py:14:33:14:53 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | flask_pymongo_bad.py:14:33:14:53 | ControlFlowNode for Dict | This | flask_pymongo_bad.py:11:26:11:32 | ControlFlowNode for request | user-provided value |
| mongoclient_subscript_bad.py:26:37:26:57 | ControlFlowNode for Dict | mongoclient_subscript_bad.py:22:21:22:27 | ControlFlowNode for request | mongoclient_subscript_bad.py:26:37:26:57 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | mongoclient_subscript_bad.py:26:37:26:57 | ControlFlowNode for Dict | This | mongoclient_subscript_bad.py:22:21:22:27 | ControlFlowNode for request | user-provided value |
| mongoengine_bad.py:25:34:25:44 | ControlFlowNode for json_search | mongoengine_bad.py:22:21:22:27 | ControlFlowNode for request | mongoengine_bad.py:25:34:25:44 | ControlFlowNode for json_search | $@ NoSQL query contains an unsanitized $@ | mongoengine_bad.py:25:34:25:44 | ControlFlowNode for json_search | This | mongoengine_bad.py:22:21:22:27 | ControlFlowNode for request | user-provided value |
From 6bed8594f23e7c1b72fa5722d9df0634c7763053 Mon Sep 17 00:00:00 2001
From: jorgectf
Date: Tue, 15 Jun 2021 16:27:32 +0200
Subject: [PATCH 081/429] Match sanitizer inputs' naming
---
python/ql/src/experimental/semmle/python/Concepts.qll | 4 ++--
python/ql/src/experimental/semmle/python/frameworks/NoSQL.qll | 4 ++--
.../semmle/python/security/injection/NoSQLInjection.qll | 4 ++--
3 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/python/ql/src/experimental/semmle/python/Concepts.qll b/python/ql/src/experimental/semmle/python/Concepts.qll
index 07e9f21e33e..2134b32e60a 100644
--- a/python/ql/src/experimental/semmle/python/Concepts.qll
+++ b/python/ql/src/experimental/semmle/python/Concepts.qll
@@ -163,7 +163,7 @@ class NoSQLQuery extends DataFlow::Node {
module NoSQLSanitizer {
abstract class Range extends DataFlow::Node {
- abstract DataFlow::Node getSanitizerNode();
+ abstract DataFlow::Node getAnInput();
}
}
@@ -172,5 +172,5 @@ class NoSQLSanitizer extends DataFlow::Node {
NoSQLSanitizer() { this = range }
- DataFlow::Node getSanitizerNode() { result = range.getSanitizerNode() }
+ DataFlow::Node getAnInput() { result = range.getAnInput() }
}
diff --git a/python/ql/src/experimental/semmle/python/frameworks/NoSQL.qll b/python/ql/src/experimental/semmle/python/frameworks/NoSQL.qll
index 94d327d7901..6561db67f9a 100644
--- a/python/ql/src/experimental/semmle/python/frameworks/NoSQL.qll
+++ b/python/ql/src/experimental/semmle/python/frameworks/NoSQL.qll
@@ -166,7 +166,7 @@ private module NoSQL {
API::moduleImport("mongosanitizer").getMember("sanitizer").getMember("sanitize").getACall()
}
- override DataFlow::Node getSanitizerNode() { result = this.getArg(0) }
+ override DataFlow::Node getAnInput() { result = this.getArg(0) }
}
/**
@@ -182,6 +182,6 @@ private module NoSQL {
.getACall()
}
- override DataFlow::Node getSanitizerNode() { result = this.getArg(0) }
+ override DataFlow::Node getAnInput() { result = this.getArg(0) }
}
}
diff --git a/python/ql/src/experimental/semmle/python/security/injection/NoSQLInjection.qll b/python/ql/src/experimental/semmle/python/security/injection/NoSQLInjection.qll
index 27109bb3439..8217f370af7 100644
--- a/python/ql/src/experimental/semmle/python/security/injection/NoSQLInjection.qll
+++ b/python/ql/src/experimental/semmle/python/security/injection/NoSQLInjection.qll
@@ -42,7 +42,7 @@ class RFSToDictConfig extends TaintTracking::Configuration {
override predicate isSink(DataFlow::Node sink) { sink instanceof DataToDictSink }
override predicate isSanitizer(DataFlow::Node sanitizer) {
- sanitizer = any(NoSQLSanitizer noSQLSanitizer).getSanitizerNode()
+ sanitizer = any(NoSQLSanitizer noSQLSanitizer).getAnInput()
}
}
@@ -54,7 +54,7 @@ class FromDataDictToSink extends TaintTracking2::Configuration {
override predicate isSink(DataFlow::Node sink) { sink = any(NoSQLQuery noSQLQuery).getQuery() }
override predicate isSanitizer(DataFlow::Node sanitizer) {
- sanitizer = any(NoSQLSanitizer noSQLSanitizer).getSanitizerNode()
+ sanitizer = any(NoSQLSanitizer noSQLSanitizer).getAnInput()
}
}
From e61cf9a58d5a6a8a420e37479d2765490336b05d Mon Sep 17 00:00:00 2001
From: jorgectf
Date: Tue, 15 Jun 2021 19:32:02 +0200
Subject: [PATCH 082/429] Simplify tests
---
.../query-tests/Security/CWE-943/flask_mongoengine_bad.py | 7 +------
.../Security/CWE-943/flask_mongoengine_get_db_bad.py | 7 +------
.../Security/CWE-943/flask_mongoengine_get_db_good.py | 7 +------
.../query-tests/Security/CWE-943/flask_mongoengine_good.py | 7 +------
.../Security/CWE-943/mongoclient_subscript_bad.py | 7 +------
.../Security/CWE-943/mongoclient_subscript_good.py | 7 +------
.../query-tests/Security/CWE-943/mongoengine_bad.py | 7 +------
.../Security/CWE-943/mongoengine_connect_bad.py | 7 +------
.../Security/CWE-943/mongoengine_connect_good.py | 7 +------
.../CWE-943/mongoengine_connect_via_connection_bad.py | 7 +------
.../CWE-943/mongoengine_connect_via_connection_good.py | 7 +------
.../CWE-943/mongoengine_flask_db_document_subclass_bad.py | 7 +------
.../CWE-943/mongoengine_flask_db_document_subclass_good.py | 7 +------
.../query-tests/Security/CWE-943/mongoengine_get_db_bad.py | 7 +------
.../Security/CWE-943/mongoengine_get_db_good.py | 7 +------
.../CWE-943/mongoengine_get_db_via_connection_bad.py | 7 +------
.../CWE-943/mongoengine_get_db_via_connection_good.py | 7 +------
.../query-tests/Security/CWE-943/mongoengine_good.py | 7 +------
18 files changed, 18 insertions(+), 108 deletions(-)
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/flask_mongoengine_bad.py b/python/ql/test/experimental/query-tests/Security/CWE-943/flask_mongoengine_bad.py
index b7dca69f70b..8f9da2d6d72 100644
--- a/python/ql/test/experimental/query-tests/Security/CWE-943/flask_mongoengine_bad.py
+++ b/python/ql/test/experimental/query-tests/Security/CWE-943/flask_mongoengine_bad.py
@@ -9,14 +9,9 @@ db.init_app(app)
class Movie(db.Document):
title = db.StringField(required=True)
- year = db.IntField()
- rated = db.StringField()
- director = db.StringField()
- actors = db.ListField()
-Movie(title='aa').save()
-Movie(title='bb').save()
+Movie(title='test').save()
@app.route("/")
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/flask_mongoengine_get_db_bad.py b/python/ql/test/experimental/query-tests/Security/CWE-943/flask_mongoengine_get_db_bad.py
index df8dde96f3e..0becf217e53 100644
--- a/python/ql/test/experimental/query-tests/Security/CWE-943/flask_mongoengine_get_db_bad.py
+++ b/python/ql/test/experimental/query-tests/Security/CWE-943/flask_mongoengine_get_db_bad.py
@@ -9,14 +9,9 @@ db.init_app(app)
class Movie(db.Document):
title = db.StringField(required=True)
- year = db.IntField()
- rated = db.StringField()
- director = db.StringField()
- actors = db.ListField()
-Movie(title='aa').save()
-Movie(title='bb').save()
+Movie(title='test').save()
@app.route("/")
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/flask_mongoengine_get_db_good.py b/python/ql/test/experimental/query-tests/Security/CWE-943/flask_mongoengine_get_db_good.py
index ce5fa89dc7f..e1d4ea7d778 100644
--- a/python/ql/test/experimental/query-tests/Security/CWE-943/flask_mongoengine_get_db_good.py
+++ b/python/ql/test/experimental/query-tests/Security/CWE-943/flask_mongoengine_get_db_good.py
@@ -10,14 +10,9 @@ db.init_app(app)
class Movie(db.Document):
title = db.StringField(required=True)
- year = db.IntField()
- rated = db.StringField()
- director = db.StringField()
- actors = db.ListField()
-Movie(title='aa').save()
-Movie(title='bb').save()
+Movie(title='test').save()
@app.route("/")
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/flask_mongoengine_good.py b/python/ql/test/experimental/query-tests/Security/CWE-943/flask_mongoengine_good.py
index 89f6d49a3d1..5b34de49781 100644
--- a/python/ql/test/experimental/query-tests/Security/CWE-943/flask_mongoengine_good.py
+++ b/python/ql/test/experimental/query-tests/Security/CWE-943/flask_mongoengine_good.py
@@ -10,14 +10,9 @@ db.init_app(app)
class Movie(db.Document):
title = db.StringField(required=True)
- year = db.IntField()
- rated = db.StringField()
- director = db.StringField()
- actors = db.ListField()
-Movie(title='aa').save()
-Movie(title='bb').save()
+Movie(title='test').save()
@app.route("/")
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoclient_subscript_bad.py b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoclient_subscript_bad.py
index 14f1177a023..cc1fd7ce59a 100644
--- a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoclient_subscript_bad.py
+++ b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoclient_subscript_bad.py
@@ -7,14 +7,9 @@ app = Flask(__name__)
class Movie(me.Document):
title = me.StringField(required=True)
- year = me.IntField()
- rated = me.StringField()
- director = me.StringField()
- actors = me.ListField()
-Movie(title='aa').save()
-Movie(title='bb').save()
+Movie(title='test').save()
@app.route("/")
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoclient_subscript_good.py b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoclient_subscript_good.py
index 1d1aad89780..8a5bed832c6 100644
--- a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoclient_subscript_good.py
+++ b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoclient_subscript_good.py
@@ -8,14 +8,9 @@ app = Flask(__name__)
class Movie(me.Document):
title = me.StringField(required=True)
- year = me.IntField()
- rated = me.StringField()
- director = me.StringField()
- actors = me.ListField()
-Movie(title='aa').save()
-Movie(title='bb').save()
+Movie(title='test').save()
@app.route("/")
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_bad.py b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_bad.py
index c48f7bb9ddb..95467393541 100644
--- a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_bad.py
+++ b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_bad.py
@@ -7,14 +7,9 @@ app = Flask(__name__)
class Movie(me.Document):
title = me.StringField(required=True)
- year = me.IntField()
- rated = me.StringField()
- director = me.StringField()
- actors = me.ListField()
-Movie(title='aa').save()
-Movie(title='bb').save()
+Movie(title='test').save()
@app.route("/")
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_connect_bad.py b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_connect_bad.py
index 7d50fc8bd44..8d6a0c30d52 100644
--- a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_connect_bad.py
+++ b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_connect_bad.py
@@ -7,14 +7,9 @@ app = Flask(__name__)
class Movie(me.Document):
title = me.StringField(required=True)
- year = me.IntField()
- rated = me.StringField()
- director = me.StringField()
- actors = me.ListField()
-Movie(title='aa').save()
-Movie(title='bb').save()
+Movie(title='test').save()
@app.route("/")
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_connect_good.py b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_connect_good.py
index 0dfaac547dd..93109deeaf9 100644
--- a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_connect_good.py
+++ b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_connect_good.py
@@ -8,14 +8,9 @@ app = Flask(__name__)
class Movie(me.Document):
title = me.StringField(required=True)
- year = me.IntField()
- rated = me.StringField()
- director = me.StringField()
- actors = me.ListField()
-Movie(title='aa').save()
-Movie(title='bb').save()
+Movie(title='test').save()
@app.route("/")
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_connect_via_connection_bad.py b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_connect_via_connection_bad.py
index 10d9e17523f..167eddeb5e9 100644
--- a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_connect_via_connection_bad.py
+++ b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_connect_via_connection_bad.py
@@ -8,14 +8,9 @@ app = Flask(__name__)
class Movie(me.Document):
title = me.StringField(required=True)
- year = me.IntField()
- rated = me.StringField()
- director = me.StringField()
- actors = me.ListField()
-Movie(title='aa').save()
-Movie(title='bb').save()
+Movie(title='test').save()
@app.route("/")
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_connect_via_connection_good.py b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_connect_via_connection_good.py
index d00d82894de..0283bfdd57a 100644
--- a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_connect_via_connection_good.py
+++ b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_connect_via_connection_good.py
@@ -9,14 +9,9 @@ app = Flask(__name__)
class Movie(me.Document):
title = me.StringField(required=True)
- year = me.IntField()
- rated = me.StringField()
- director = me.StringField()
- actors = me.ListField()
-Movie(title='aa').save()
-Movie(title='bb').save()
+Movie(title='test').save()
@app.route("/")
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_flask_db_document_subclass_bad.py b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_flask_db_document_subclass_bad.py
index e8f05bba707..f55f3270f47 100644
--- a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_flask_db_document_subclass_bad.py
+++ b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_flask_db_document_subclass_bad.py
@@ -8,14 +8,9 @@ db = MongoEngine(app)
class Movie(db.Document):
title = db.StringField(required=True)
- year = db.IntField()
- rated = db.StringField()
- director = db.StringField()
- actors = db.ListField()
-Movie(title='aa').save()
-Movie(title='bb').save()
+Movie(title='test').save()
@app.route("/")
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_flask_db_document_subclass_good.py b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_flask_db_document_subclass_good.py
index 7fd0e927155..c0a03d718aa 100644
--- a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_flask_db_document_subclass_good.py
+++ b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_flask_db_document_subclass_good.py
@@ -9,14 +9,9 @@ db = MongoEngine(app)
class Movie(db.Document):
title = db.StringField(required=True)
- year = db.IntField()
- rated = db.StringField()
- director = db.StringField()
- actors = db.ListField()
-Movie(title='aa').save()
-Movie(title='bb').save()
+Movie(title='test').save()
@app.route("/")
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_get_db_bad.py b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_get_db_bad.py
index 5722881fc3e..8b1d8ebb6fb 100644
--- a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_get_db_bad.py
+++ b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_get_db_bad.py
@@ -7,14 +7,9 @@ app = Flask(__name__)
class Movie(me.Document):
title = me.StringField(required=True)
- year = me.IntField()
- rated = me.StringField()
- director = me.StringField()
- actors = me.ListField()
-Movie(title='aa').save()
-Movie(title='bb').save()
+Movie(title='test').save()
@app.route("/")
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_get_db_good.py b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_get_db_good.py
index 7c4aad77f8f..08c43b4d209 100644
--- a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_get_db_good.py
+++ b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_get_db_good.py
@@ -8,14 +8,9 @@ app = Flask(__name__)
class Movie(me.Document):
title = me.StringField(required=True)
- year = me.IntField()
- rated = me.StringField()
- director = me.StringField()
- actors = me.ListField()
-Movie(title='aa').save()
-Movie(title='bb').save()
+Movie(title='test').save()
@app.route("/")
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_get_db_via_connection_bad.py b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_get_db_via_connection_bad.py
index 3fe927e113a..76b32a69572 100644
--- a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_get_db_via_connection_bad.py
+++ b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_get_db_via_connection_bad.py
@@ -8,14 +8,9 @@ app = Flask(__name__)
class Movie(me.Document):
title = me.StringField(required=True)
- year = me.IntField()
- rated = me.StringField()
- director = me.StringField()
- actors = me.ListField()
-Movie(title='aa').save()
-Movie(title='bb').save()
+Movie(title='test').save()
@app.route("/")
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_get_db_via_connection_good.py b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_get_db_via_connection_good.py
index bc5f48c037e..9ac27c8c54a 100644
--- a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_get_db_via_connection_good.py
+++ b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_get_db_via_connection_good.py
@@ -9,14 +9,9 @@ app = Flask(__name__)
class Movie(me.Document):
title = me.StringField(required=True)
- year = me.IntField()
- rated = me.StringField()
- director = me.StringField()
- actors = me.ListField()
-Movie(title='aa').save()
-Movie(title='bb').save()
+Movie(title='test').save()
@app.route("/")
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_good.py b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_good.py
index ac7937195e8..c852d550464 100644
--- a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_good.py
+++ b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_good.py
@@ -8,14 +8,9 @@ app = Flask(__name__)
class Movie(me.Document):
title = me.StringField(required=True)
- year = me.IntField()
- rated = me.StringField()
- director = me.StringField()
- actors = me.ListField()
-Movie(title='aa').save()
-Movie(title='bb').save()
+Movie(title='test').save()
@app.route("/")
From 5123b8f4e34e343e6a5d3ffb058ce854016069d3 Mon Sep 17 00:00:00 2001
From: jorgectf
Date: Tue, 15 Jun 2021 20:29:33 +0200
Subject: [PATCH 083/429] Update .expected
---
.../Security/CWE-943/NoSQLInjection.expected | 306 +++++++++---------
1 file changed, 153 insertions(+), 153 deletions(-)
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/NoSQLInjection.expected b/python/ql/test/experimental/query-tests/Security/CWE-943/NoSQLInjection.expected
index fd02261ed90..dd247bc9206 100644
--- a/python/ql/test/experimental/query-tests/Security/CWE-943/NoSQLInjection.expected
+++ b/python/ql/test/experimental/query-tests/Security/CWE-943/NoSQLInjection.expected
@@ -1,18 +1,18 @@
edges
-| flask_mongoengine_bad.py:24:26:24:32 | ControlFlowNode for request | flask_mongoengine_bad.py:24:26:24:37 | ControlFlowNode for Attribute |
-| flask_mongoengine_bad.py:24:26:24:37 | ControlFlowNode for Attribute | flask_mongoengine_bad.py:24:26:24:47 | ControlFlowNode for Subscript |
-| flask_mongoengine_bad.py:24:26:24:47 | ControlFlowNode for Subscript | flask_mongoengine_bad.py:25:30:25:47 | ControlFlowNode for unsanitized_search |
-| flask_mongoengine_bad.py:25:30:25:47 | ControlFlowNode for unsanitized_search | flask_mongoengine_bad.py:27:36:27:46 | ControlFlowNode for json_search |
-| flask_mongoengine_get_db_bad.py:24:26:24:32 | ControlFlowNode for request | flask_mongoengine_get_db_bad.py:24:26:24:37 | ControlFlowNode for Attribute |
-| flask_mongoengine_get_db_bad.py:24:26:24:37 | ControlFlowNode for Attribute | flask_mongoengine_get_db_bad.py:24:26:24:47 | ControlFlowNode for Subscript |
-| flask_mongoengine_get_db_bad.py:24:26:24:47 | ControlFlowNode for Subscript | flask_mongoengine_get_db_bad.py:25:30:25:47 | ControlFlowNode for unsanitized_search |
-| flask_mongoengine_get_db_bad.py:25:30:25:47 | ControlFlowNode for unsanitized_search | flask_mongoengine_get_db_bad.py:28:41:28:61 | ControlFlowNode for Dict |
-| flask_mongoengine_get_db_good.py:25:26:25:32 | ControlFlowNode for request | flask_mongoengine_get_db_good.py:25:26:25:37 | ControlFlowNode for Attribute |
-| flask_mongoengine_get_db_good.py:25:26:25:37 | ControlFlowNode for Attribute | flask_mongoengine_get_db_good.py:25:26:25:47 | ControlFlowNode for Subscript |
-| flask_mongoengine_get_db_good.py:25:26:25:47 | ControlFlowNode for Subscript | flask_mongoengine_get_db_good.py:26:30:26:47 | ControlFlowNode for unsanitized_search |
-| flask_mongoengine_good.py:25:21:25:27 | ControlFlowNode for request | flask_mongoengine_good.py:25:21:25:32 | ControlFlowNode for Attribute |
-| flask_mongoengine_good.py:25:21:25:32 | ControlFlowNode for Attribute | flask_mongoengine_good.py:25:21:25:42 | ControlFlowNode for Subscript |
-| flask_mongoengine_good.py:25:21:25:42 | ControlFlowNode for Subscript | flask_mongoengine_good.py:26:30:26:42 | ControlFlowNode for unsafe_search |
+| flask_mongoengine_bad.py:19:26:19:32 | ControlFlowNode for request | flask_mongoengine_bad.py:19:26:19:37 | ControlFlowNode for Attribute |
+| flask_mongoengine_bad.py:19:26:19:37 | ControlFlowNode for Attribute | flask_mongoengine_bad.py:19:26:19:47 | ControlFlowNode for Subscript |
+| flask_mongoengine_bad.py:19:26:19:47 | ControlFlowNode for Subscript | flask_mongoengine_bad.py:20:30:20:47 | ControlFlowNode for unsanitized_search |
+| flask_mongoengine_bad.py:20:30:20:47 | ControlFlowNode for unsanitized_search | flask_mongoengine_bad.py:22:36:22:46 | ControlFlowNode for json_search |
+| flask_mongoengine_get_db_bad.py:19:26:19:32 | ControlFlowNode for request | flask_mongoengine_get_db_bad.py:19:26:19:37 | ControlFlowNode for Attribute |
+| flask_mongoengine_get_db_bad.py:19:26:19:37 | ControlFlowNode for Attribute | flask_mongoengine_get_db_bad.py:19:26:19:47 | ControlFlowNode for Subscript |
+| flask_mongoengine_get_db_bad.py:19:26:19:47 | ControlFlowNode for Subscript | flask_mongoengine_get_db_bad.py:20:30:20:47 | ControlFlowNode for unsanitized_search |
+| flask_mongoengine_get_db_bad.py:20:30:20:47 | ControlFlowNode for unsanitized_search | flask_mongoengine_get_db_bad.py:23:41:23:61 | ControlFlowNode for Dict |
+| flask_mongoengine_get_db_good.py:20:26:20:32 | ControlFlowNode for request | flask_mongoengine_get_db_good.py:20:26:20:37 | ControlFlowNode for Attribute |
+| flask_mongoengine_get_db_good.py:20:26:20:37 | ControlFlowNode for Attribute | flask_mongoengine_get_db_good.py:20:26:20:47 | ControlFlowNode for Subscript |
+| flask_mongoengine_get_db_good.py:20:26:20:47 | ControlFlowNode for Subscript | flask_mongoengine_get_db_good.py:21:30:21:47 | ControlFlowNode for unsanitized_search |
+| flask_mongoengine_good.py:20:21:20:27 | ControlFlowNode for request | flask_mongoengine_good.py:20:21:20:32 | ControlFlowNode for Attribute |
+| flask_mongoengine_good.py:20:21:20:32 | ControlFlowNode for Attribute | flask_mongoengine_good.py:20:21:20:42 | ControlFlowNode for Subscript |
+| flask_mongoengine_good.py:20:21:20:42 | ControlFlowNode for Subscript | flask_mongoengine_good.py:21:30:21:42 | ControlFlowNode for unsafe_search |
| flask_pymongo_bad.py:11:26:11:32 | ControlFlowNode for request | flask_pymongo_bad.py:11:26:11:37 | ControlFlowNode for Attribute |
| flask_pymongo_bad.py:11:26:11:37 | ControlFlowNode for Attribute | flask_pymongo_bad.py:11:26:11:47 | ControlFlowNode for Subscript |
| flask_pymongo_bad.py:11:26:11:47 | ControlFlowNode for Subscript | flask_pymongo_bad.py:12:30:12:47 | ControlFlowNode for unsanitized_search |
@@ -20,55 +20,55 @@ edges
| flask_pymongo_good.py:12:21:12:27 | ControlFlowNode for request | flask_pymongo_good.py:12:21:12:32 | ControlFlowNode for Attribute |
| flask_pymongo_good.py:12:21:12:32 | ControlFlowNode for Attribute | flask_pymongo_good.py:12:21:12:42 | ControlFlowNode for Subscript |
| flask_pymongo_good.py:12:21:12:42 | ControlFlowNode for Subscript | flask_pymongo_good.py:13:30:13:42 | ControlFlowNode for unsafe_search |
-| mongoclient_subscript_bad.py:22:21:22:27 | ControlFlowNode for request | mongoclient_subscript_bad.py:22:21:22:32 | ControlFlowNode for Attribute |
-| mongoclient_subscript_bad.py:22:21:22:32 | ControlFlowNode for Attribute | mongoclient_subscript_bad.py:22:21:22:42 | ControlFlowNode for Subscript |
-| mongoclient_subscript_bad.py:22:21:22:42 | ControlFlowNode for Subscript | mongoclient_subscript_bad.py:23:30:23:42 | ControlFlowNode for unsafe_search |
-| mongoclient_subscript_bad.py:23:30:23:42 | ControlFlowNode for unsafe_search | mongoclient_subscript_bad.py:26:37:26:57 | ControlFlowNode for Dict |
-| mongoclient_subscript_good.py:23:21:23:27 | ControlFlowNode for request | mongoclient_subscript_good.py:23:21:23:32 | ControlFlowNode for Attribute |
-| mongoclient_subscript_good.py:23:21:23:32 | ControlFlowNode for Attribute | mongoclient_subscript_good.py:23:21:23:42 | ControlFlowNode for Subscript |
-| mongoclient_subscript_good.py:23:21:23:42 | ControlFlowNode for Subscript | mongoclient_subscript_good.py:24:30:24:42 | ControlFlowNode for unsafe_search |
-| mongoengine_bad.py:22:21:22:27 | ControlFlowNode for request | mongoengine_bad.py:22:21:22:32 | ControlFlowNode for Attribute |
-| mongoengine_bad.py:22:21:22:32 | ControlFlowNode for Attribute | mongoengine_bad.py:22:21:22:42 | ControlFlowNode for Subscript |
-| mongoengine_bad.py:22:21:22:42 | ControlFlowNode for Subscript | mongoengine_bad.py:23:30:23:42 | ControlFlowNode for unsafe_search |
-| mongoengine_bad.py:23:30:23:42 | ControlFlowNode for unsafe_search | mongoengine_bad.py:25:34:25:44 | ControlFlowNode for json_search |
-| mongoengine_connect_bad.py:22:21:22:27 | ControlFlowNode for request | mongoengine_connect_bad.py:22:21:22:32 | ControlFlowNode for Attribute |
-| mongoengine_connect_bad.py:22:21:22:32 | ControlFlowNode for Attribute | mongoengine_connect_bad.py:22:21:22:42 | ControlFlowNode for Subscript |
-| mongoengine_connect_bad.py:22:21:22:42 | ControlFlowNode for Subscript | mongoengine_connect_bad.py:23:30:23:42 | ControlFlowNode for unsafe_search |
-| mongoengine_connect_bad.py:23:30:23:42 | ControlFlowNode for unsafe_search | mongoengine_connect_bad.py:26:31:26:51 | ControlFlowNode for Dict |
-| mongoengine_connect_good.py:23:21:23:27 | ControlFlowNode for request | mongoengine_connect_good.py:23:21:23:32 | ControlFlowNode for Attribute |
-| mongoengine_connect_good.py:23:21:23:32 | ControlFlowNode for Attribute | mongoengine_connect_good.py:23:21:23:42 | ControlFlowNode for Subscript |
-| mongoengine_connect_good.py:23:21:23:42 | ControlFlowNode for Subscript | mongoengine_connect_good.py:24:30:24:42 | ControlFlowNode for unsafe_search |
-| mongoengine_connect_via_connection_bad.py:23:21:23:27 | ControlFlowNode for request | mongoengine_connect_via_connection_bad.py:23:21:23:32 | ControlFlowNode for Attribute |
-| mongoengine_connect_via_connection_bad.py:23:21:23:32 | ControlFlowNode for Attribute | mongoengine_connect_via_connection_bad.py:23:21:23:42 | ControlFlowNode for Subscript |
-| mongoengine_connect_via_connection_bad.py:23:21:23:42 | ControlFlowNode for Subscript | mongoengine_connect_via_connection_bad.py:24:30:24:42 | ControlFlowNode for unsafe_search |
-| mongoengine_connect_via_connection_bad.py:24:30:24:42 | ControlFlowNode for unsafe_search | mongoengine_connect_via_connection_bad.py:27:31:27:51 | ControlFlowNode for Dict |
-| mongoengine_connect_via_connection_good.py:24:21:24:27 | ControlFlowNode for request | mongoengine_connect_via_connection_good.py:24:21:24:32 | ControlFlowNode for Attribute |
-| mongoengine_connect_via_connection_good.py:24:21:24:32 | ControlFlowNode for Attribute | mongoengine_connect_via_connection_good.py:24:21:24:42 | ControlFlowNode for Subscript |
-| mongoengine_connect_via_connection_good.py:24:21:24:42 | ControlFlowNode for Subscript | mongoengine_connect_via_connection_good.py:25:30:25:42 | ControlFlowNode for unsafe_search |
-| mongoengine_flask_db_document_subclass_bad.py:23:21:23:27 | ControlFlowNode for request | mongoengine_flask_db_document_subclass_bad.py:23:21:23:32 | ControlFlowNode for Attribute |
-| mongoengine_flask_db_document_subclass_bad.py:23:21:23:32 | ControlFlowNode for Attribute | mongoengine_flask_db_document_subclass_bad.py:23:21:23:42 | ControlFlowNode for Subscript |
-| mongoengine_flask_db_document_subclass_bad.py:23:21:23:42 | ControlFlowNode for Subscript | mongoengine_flask_db_document_subclass_bad.py:24:30:24:42 | ControlFlowNode for unsafe_search |
-| mongoengine_flask_db_document_subclass_bad.py:24:30:24:42 | ControlFlowNode for unsafe_search | mongoengine_flask_db_document_subclass_bad.py:26:34:26:44 | ControlFlowNode for json_search |
-| mongoengine_flask_db_document_subclass_good.py:24:21:24:27 | ControlFlowNode for request | mongoengine_flask_db_document_subclass_good.py:24:21:24:32 | ControlFlowNode for Attribute |
-| mongoengine_flask_db_document_subclass_good.py:24:21:24:32 | ControlFlowNode for Attribute | mongoengine_flask_db_document_subclass_good.py:24:21:24:42 | ControlFlowNode for Subscript |
-| mongoengine_flask_db_document_subclass_good.py:24:21:24:42 | ControlFlowNode for Subscript | mongoengine_flask_db_document_subclass_good.py:25:30:25:42 | ControlFlowNode for unsafe_search |
-| mongoengine_get_db_bad.py:22:21:22:27 | ControlFlowNode for request | mongoengine_get_db_bad.py:22:21:22:32 | ControlFlowNode for Attribute |
-| mongoengine_get_db_bad.py:22:21:22:32 | ControlFlowNode for Attribute | mongoengine_get_db_bad.py:22:21:22:42 | ControlFlowNode for Subscript |
-| mongoengine_get_db_bad.py:22:21:22:42 | ControlFlowNode for Subscript | mongoengine_get_db_bad.py:23:30:23:42 | ControlFlowNode for unsafe_search |
-| mongoengine_get_db_bad.py:23:30:23:42 | ControlFlowNode for unsafe_search | mongoengine_get_db_bad.py:26:26:26:46 | ControlFlowNode for Dict |
-| mongoengine_get_db_good.py:23:21:23:27 | ControlFlowNode for request | mongoengine_get_db_good.py:23:21:23:32 | ControlFlowNode for Attribute |
-| mongoengine_get_db_good.py:23:21:23:32 | ControlFlowNode for Attribute | mongoengine_get_db_good.py:23:21:23:42 | ControlFlowNode for Subscript |
-| mongoengine_get_db_good.py:23:21:23:42 | ControlFlowNode for Subscript | mongoengine_get_db_good.py:24:30:24:42 | ControlFlowNode for unsafe_search |
-| mongoengine_get_db_via_connection_bad.py:23:21:23:27 | ControlFlowNode for request | mongoengine_get_db_via_connection_bad.py:23:21:23:32 | ControlFlowNode for Attribute |
-| mongoengine_get_db_via_connection_bad.py:23:21:23:32 | ControlFlowNode for Attribute | mongoengine_get_db_via_connection_bad.py:23:21:23:42 | ControlFlowNode for Subscript |
-| mongoengine_get_db_via_connection_bad.py:23:21:23:42 | ControlFlowNode for Subscript | mongoengine_get_db_via_connection_bad.py:24:30:24:42 | ControlFlowNode for unsafe_search |
-| mongoengine_get_db_via_connection_bad.py:24:30:24:42 | ControlFlowNode for unsafe_search | mongoengine_get_db_via_connection_bad.py:27:26:27:46 | ControlFlowNode for Dict |
-| mongoengine_get_db_via_connection_good.py:24:21:24:27 | ControlFlowNode for request | mongoengine_get_db_via_connection_good.py:24:21:24:32 | ControlFlowNode for Attribute |
-| mongoengine_get_db_via_connection_good.py:24:21:24:32 | ControlFlowNode for Attribute | mongoengine_get_db_via_connection_good.py:24:21:24:42 | ControlFlowNode for Subscript |
-| mongoengine_get_db_via_connection_good.py:24:21:24:42 | ControlFlowNode for Subscript | mongoengine_get_db_via_connection_good.py:25:30:25:42 | ControlFlowNode for unsafe_search |
-| mongoengine_good.py:23:21:23:27 | ControlFlowNode for request | mongoengine_good.py:23:21:23:32 | ControlFlowNode for Attribute |
-| mongoengine_good.py:23:21:23:32 | ControlFlowNode for Attribute | mongoengine_good.py:23:21:23:42 | ControlFlowNode for Subscript |
-| mongoengine_good.py:23:21:23:42 | ControlFlowNode for Subscript | mongoengine_good.py:24:30:24:42 | ControlFlowNode for unsafe_search |
+| mongoclient_subscript_bad.py:17:21:17:27 | ControlFlowNode for request | mongoclient_subscript_bad.py:17:21:17:32 | ControlFlowNode for Attribute |
+| mongoclient_subscript_bad.py:17:21:17:32 | ControlFlowNode for Attribute | mongoclient_subscript_bad.py:17:21:17:42 | ControlFlowNode for Subscript |
+| mongoclient_subscript_bad.py:17:21:17:42 | ControlFlowNode for Subscript | mongoclient_subscript_bad.py:18:30:18:42 | ControlFlowNode for unsafe_search |
+| mongoclient_subscript_bad.py:18:30:18:42 | ControlFlowNode for unsafe_search | mongoclient_subscript_bad.py:21:37:21:57 | ControlFlowNode for Dict |
+| mongoclient_subscript_good.py:18:21:18:27 | ControlFlowNode for request | mongoclient_subscript_good.py:18:21:18:32 | ControlFlowNode for Attribute |
+| mongoclient_subscript_good.py:18:21:18:32 | ControlFlowNode for Attribute | mongoclient_subscript_good.py:18:21:18:42 | ControlFlowNode for Subscript |
+| mongoclient_subscript_good.py:18:21:18:42 | ControlFlowNode for Subscript | mongoclient_subscript_good.py:19:30:19:42 | ControlFlowNode for unsafe_search |
+| mongoengine_bad.py:17:21:17:27 | ControlFlowNode for request | mongoengine_bad.py:17:21:17:32 | ControlFlowNode for Attribute |
+| mongoengine_bad.py:17:21:17:32 | ControlFlowNode for Attribute | mongoengine_bad.py:17:21:17:42 | ControlFlowNode for Subscript |
+| mongoengine_bad.py:17:21:17:42 | ControlFlowNode for Subscript | mongoengine_bad.py:18:30:18:42 | ControlFlowNode for unsafe_search |
+| mongoengine_bad.py:18:30:18:42 | ControlFlowNode for unsafe_search | mongoengine_bad.py:20:34:20:44 | ControlFlowNode for json_search |
+| mongoengine_connect_bad.py:17:21:17:27 | ControlFlowNode for request | mongoengine_connect_bad.py:17:21:17:32 | ControlFlowNode for Attribute |
+| mongoengine_connect_bad.py:17:21:17:32 | ControlFlowNode for Attribute | mongoengine_connect_bad.py:17:21:17:42 | ControlFlowNode for Subscript |
+| mongoengine_connect_bad.py:17:21:17:42 | ControlFlowNode for Subscript | mongoengine_connect_bad.py:18:30:18:42 | ControlFlowNode for unsafe_search |
+| mongoengine_connect_bad.py:18:30:18:42 | ControlFlowNode for unsafe_search | mongoengine_connect_bad.py:21:31:21:51 | ControlFlowNode for Dict |
+| mongoengine_connect_good.py:18:21:18:27 | ControlFlowNode for request | mongoengine_connect_good.py:18:21:18:32 | ControlFlowNode for Attribute |
+| mongoengine_connect_good.py:18:21:18:32 | ControlFlowNode for Attribute | mongoengine_connect_good.py:18:21:18:42 | ControlFlowNode for Subscript |
+| mongoengine_connect_good.py:18:21:18:42 | ControlFlowNode for Subscript | mongoengine_connect_good.py:19:30:19:42 | ControlFlowNode for unsafe_search |
+| mongoengine_connect_via_connection_bad.py:18:21:18:27 | ControlFlowNode for request | mongoengine_connect_via_connection_bad.py:18:21:18:32 | ControlFlowNode for Attribute |
+| mongoengine_connect_via_connection_bad.py:18:21:18:32 | ControlFlowNode for Attribute | mongoengine_connect_via_connection_bad.py:18:21:18:42 | ControlFlowNode for Subscript |
+| mongoengine_connect_via_connection_bad.py:18:21:18:42 | ControlFlowNode for Subscript | mongoengine_connect_via_connection_bad.py:19:30:19:42 | ControlFlowNode for unsafe_search |
+| mongoengine_connect_via_connection_bad.py:19:30:19:42 | ControlFlowNode for unsafe_search | mongoengine_connect_via_connection_bad.py:22:31:22:51 | ControlFlowNode for Dict |
+| mongoengine_connect_via_connection_good.py:19:21:19:27 | ControlFlowNode for request | mongoengine_connect_via_connection_good.py:19:21:19:32 | ControlFlowNode for Attribute |
+| mongoengine_connect_via_connection_good.py:19:21:19:32 | ControlFlowNode for Attribute | mongoengine_connect_via_connection_good.py:19:21:19:42 | ControlFlowNode for Subscript |
+| mongoengine_connect_via_connection_good.py:19:21:19:42 | ControlFlowNode for Subscript | mongoengine_connect_via_connection_good.py:20:30:20:42 | ControlFlowNode for unsafe_search |
+| mongoengine_flask_db_document_subclass_bad.py:18:21:18:27 | ControlFlowNode for request | mongoengine_flask_db_document_subclass_bad.py:18:21:18:32 | ControlFlowNode for Attribute |
+| mongoengine_flask_db_document_subclass_bad.py:18:21:18:32 | ControlFlowNode for Attribute | mongoengine_flask_db_document_subclass_bad.py:18:21:18:42 | ControlFlowNode for Subscript |
+| mongoengine_flask_db_document_subclass_bad.py:18:21:18:42 | ControlFlowNode for Subscript | mongoengine_flask_db_document_subclass_bad.py:19:30:19:42 | ControlFlowNode for unsafe_search |
+| mongoengine_flask_db_document_subclass_bad.py:19:30:19:42 | ControlFlowNode for unsafe_search | mongoengine_flask_db_document_subclass_bad.py:21:34:21:44 | ControlFlowNode for json_search |
+| mongoengine_flask_db_document_subclass_good.py:19:21:19:27 | ControlFlowNode for request | mongoengine_flask_db_document_subclass_good.py:19:21:19:32 | ControlFlowNode for Attribute |
+| mongoengine_flask_db_document_subclass_good.py:19:21:19:32 | ControlFlowNode for Attribute | mongoengine_flask_db_document_subclass_good.py:19:21:19:42 | ControlFlowNode for Subscript |
+| mongoengine_flask_db_document_subclass_good.py:19:21:19:42 | ControlFlowNode for Subscript | mongoengine_flask_db_document_subclass_good.py:20:30:20:42 | ControlFlowNode for unsafe_search |
+| mongoengine_get_db_bad.py:17:21:17:27 | ControlFlowNode for request | mongoengine_get_db_bad.py:17:21:17:32 | ControlFlowNode for Attribute |
+| mongoengine_get_db_bad.py:17:21:17:32 | ControlFlowNode for Attribute | mongoengine_get_db_bad.py:17:21:17:42 | ControlFlowNode for Subscript |
+| mongoengine_get_db_bad.py:17:21:17:42 | ControlFlowNode for Subscript | mongoengine_get_db_bad.py:18:30:18:42 | ControlFlowNode for unsafe_search |
+| mongoengine_get_db_bad.py:18:30:18:42 | ControlFlowNode for unsafe_search | mongoengine_get_db_bad.py:21:26:21:46 | ControlFlowNode for Dict |
+| mongoengine_get_db_good.py:18:21:18:27 | ControlFlowNode for request | mongoengine_get_db_good.py:18:21:18:32 | ControlFlowNode for Attribute |
+| mongoengine_get_db_good.py:18:21:18:32 | ControlFlowNode for Attribute | mongoengine_get_db_good.py:18:21:18:42 | ControlFlowNode for Subscript |
+| mongoengine_get_db_good.py:18:21:18:42 | ControlFlowNode for Subscript | mongoengine_get_db_good.py:19:30:19:42 | ControlFlowNode for unsafe_search |
+| mongoengine_get_db_via_connection_bad.py:18:21:18:27 | ControlFlowNode for request | mongoengine_get_db_via_connection_bad.py:18:21:18:32 | ControlFlowNode for Attribute |
+| mongoengine_get_db_via_connection_bad.py:18:21:18:32 | ControlFlowNode for Attribute | mongoengine_get_db_via_connection_bad.py:18:21:18:42 | ControlFlowNode for Subscript |
+| mongoengine_get_db_via_connection_bad.py:18:21:18:42 | ControlFlowNode for Subscript | mongoengine_get_db_via_connection_bad.py:19:30:19:42 | ControlFlowNode for unsafe_search |
+| mongoengine_get_db_via_connection_bad.py:19:30:19:42 | ControlFlowNode for unsafe_search | mongoengine_get_db_via_connection_bad.py:22:26:22:46 | ControlFlowNode for Dict |
+| mongoengine_get_db_via_connection_good.py:19:21:19:27 | ControlFlowNode for request | mongoengine_get_db_via_connection_good.py:19:21:19:32 | ControlFlowNode for Attribute |
+| mongoengine_get_db_via_connection_good.py:19:21:19:32 | ControlFlowNode for Attribute | mongoengine_get_db_via_connection_good.py:19:21:19:42 | ControlFlowNode for Subscript |
+| mongoengine_get_db_via_connection_good.py:19:21:19:42 | ControlFlowNode for Subscript | mongoengine_get_db_via_connection_good.py:20:30:20:42 | ControlFlowNode for unsafe_search |
+| mongoengine_good.py:18:21:18:27 | ControlFlowNode for request | mongoengine_good.py:18:21:18:32 | ControlFlowNode for Attribute |
+| mongoengine_good.py:18:21:18:32 | ControlFlowNode for Attribute | mongoengine_good.py:18:21:18:42 | ControlFlowNode for Subscript |
+| mongoengine_good.py:18:21:18:42 | ControlFlowNode for Subscript | mongoengine_good.py:19:30:19:42 | ControlFlowNode for unsafe_search |
| pymongo_bad.py:11:21:11:27 | ControlFlowNode for request | pymongo_bad.py:11:21:11:32 | ControlFlowNode for Attribute |
| pymongo_bad.py:11:21:11:32 | ControlFlowNode for Attribute | pymongo_bad.py:11:21:11:42 | ControlFlowNode for Subscript |
| pymongo_bad.py:11:21:11:42 | ControlFlowNode for Subscript | pymongo_bad.py:12:30:12:42 | ControlFlowNode for unsafe_search |
@@ -77,24 +77,24 @@ edges
| pymongo_good.py:12:21:12:32 | ControlFlowNode for Attribute | pymongo_good.py:12:21:12:42 | ControlFlowNode for Subscript |
| pymongo_good.py:12:21:12:42 | ControlFlowNode for Subscript | pymongo_good.py:13:30:13:42 | ControlFlowNode for unsafe_search |
nodes
-| flask_mongoengine_bad.py:24:26:24:32 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
-| flask_mongoengine_bad.py:24:26:24:37 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
-| flask_mongoengine_bad.py:24:26:24:47 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
-| flask_mongoengine_bad.py:25:30:25:47 | ControlFlowNode for unsanitized_search | semmle.label | ControlFlowNode for unsanitized_search |
-| flask_mongoengine_bad.py:27:36:27:46 | ControlFlowNode for json_search | semmle.label | ControlFlowNode for json_search |
-| flask_mongoengine_get_db_bad.py:24:26:24:32 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
-| flask_mongoengine_get_db_bad.py:24:26:24:37 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
-| flask_mongoengine_get_db_bad.py:24:26:24:47 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
-| flask_mongoengine_get_db_bad.py:25:30:25:47 | ControlFlowNode for unsanitized_search | semmle.label | ControlFlowNode for unsanitized_search |
-| flask_mongoengine_get_db_bad.py:28:41:28:61 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict |
-| flask_mongoengine_get_db_good.py:25:26:25:32 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
-| flask_mongoengine_get_db_good.py:25:26:25:37 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
-| flask_mongoengine_get_db_good.py:25:26:25:47 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
-| flask_mongoengine_get_db_good.py:26:30:26:47 | ControlFlowNode for unsanitized_search | semmle.label | ControlFlowNode for unsanitized_search |
-| flask_mongoengine_good.py:25:21:25:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
-| flask_mongoengine_good.py:25:21:25:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
-| flask_mongoengine_good.py:25:21:25:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
-| flask_mongoengine_good.py:26:30:26:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search |
+| flask_mongoengine_bad.py:19:26:19:32 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
+| flask_mongoengine_bad.py:19:26:19:37 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
+| flask_mongoengine_bad.py:19:26:19:47 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
+| flask_mongoengine_bad.py:20:30:20:47 | ControlFlowNode for unsanitized_search | semmle.label | ControlFlowNode for unsanitized_search |
+| flask_mongoengine_bad.py:22:36:22:46 | ControlFlowNode for json_search | semmle.label | ControlFlowNode for json_search |
+| flask_mongoengine_get_db_bad.py:19:26:19:32 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
+| flask_mongoengine_get_db_bad.py:19:26:19:37 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
+| flask_mongoengine_get_db_bad.py:19:26:19:47 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
+| flask_mongoengine_get_db_bad.py:20:30:20:47 | ControlFlowNode for unsanitized_search | semmle.label | ControlFlowNode for unsanitized_search |
+| flask_mongoengine_get_db_bad.py:23:41:23:61 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict |
+| flask_mongoengine_get_db_good.py:20:26:20:32 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
+| flask_mongoengine_get_db_good.py:20:26:20:37 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
+| flask_mongoengine_get_db_good.py:20:26:20:47 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
+| flask_mongoengine_get_db_good.py:21:30:21:47 | ControlFlowNode for unsanitized_search | semmle.label | ControlFlowNode for unsanitized_search |
+| flask_mongoengine_good.py:20:21:20:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
+| flask_mongoengine_good.py:20:21:20:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
+| flask_mongoengine_good.py:20:21:20:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
+| flask_mongoengine_good.py:21:30:21:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search |
| flask_pymongo_bad.py:11:26:11:32 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
| flask_pymongo_bad.py:11:26:11:37 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
| flask_pymongo_bad.py:11:26:11:47 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
@@ -104,69 +104,69 @@ nodes
| flask_pymongo_good.py:12:21:12:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
| flask_pymongo_good.py:12:21:12:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
| flask_pymongo_good.py:13:30:13:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search |
-| mongoclient_subscript_bad.py:22:21:22:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
-| mongoclient_subscript_bad.py:22:21:22:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
-| mongoclient_subscript_bad.py:22:21:22:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
-| mongoclient_subscript_bad.py:23:30:23:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search |
-| mongoclient_subscript_bad.py:26:37:26:57 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict |
-| mongoclient_subscript_good.py:23:21:23:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
-| mongoclient_subscript_good.py:23:21:23:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
-| mongoclient_subscript_good.py:23:21:23:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
-| mongoclient_subscript_good.py:24:30:24:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search |
-| mongoengine_bad.py:22:21:22:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
-| mongoengine_bad.py:22:21:22:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
-| mongoengine_bad.py:22:21:22:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
-| mongoengine_bad.py:23:30:23:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search |
-| mongoengine_bad.py:25:34:25:44 | ControlFlowNode for json_search | semmle.label | ControlFlowNode for json_search |
-| mongoengine_connect_bad.py:22:21:22:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
-| mongoengine_connect_bad.py:22:21:22:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
-| mongoengine_connect_bad.py:22:21:22:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
-| mongoengine_connect_bad.py:23:30:23:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search |
-| mongoengine_connect_bad.py:26:31:26:51 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict |
-| mongoengine_connect_good.py:23:21:23:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
-| mongoengine_connect_good.py:23:21:23:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
-| mongoengine_connect_good.py:23:21:23:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
-| mongoengine_connect_good.py:24:30:24:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search |
-| mongoengine_connect_via_connection_bad.py:23:21:23:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
-| mongoengine_connect_via_connection_bad.py:23:21:23:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
-| mongoengine_connect_via_connection_bad.py:23:21:23:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
-| mongoengine_connect_via_connection_bad.py:24:30:24:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search |
-| mongoengine_connect_via_connection_bad.py:27:31:27:51 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict |
-| mongoengine_connect_via_connection_good.py:24:21:24:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
-| mongoengine_connect_via_connection_good.py:24:21:24:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
-| mongoengine_connect_via_connection_good.py:24:21:24:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
-| mongoengine_connect_via_connection_good.py:25:30:25:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search |
-| mongoengine_flask_db_document_subclass_bad.py:23:21:23:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
-| mongoengine_flask_db_document_subclass_bad.py:23:21:23:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
-| mongoengine_flask_db_document_subclass_bad.py:23:21:23:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
-| mongoengine_flask_db_document_subclass_bad.py:24:30:24:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search |
-| mongoengine_flask_db_document_subclass_bad.py:26:34:26:44 | ControlFlowNode for json_search | semmle.label | ControlFlowNode for json_search |
-| mongoengine_flask_db_document_subclass_good.py:24:21:24:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
-| mongoengine_flask_db_document_subclass_good.py:24:21:24:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
-| mongoengine_flask_db_document_subclass_good.py:24:21:24:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
-| mongoengine_flask_db_document_subclass_good.py:25:30:25:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search |
-| mongoengine_get_db_bad.py:22:21:22:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
-| mongoengine_get_db_bad.py:22:21:22:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
-| mongoengine_get_db_bad.py:22:21:22:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
-| mongoengine_get_db_bad.py:23:30:23:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search |
-| mongoengine_get_db_bad.py:26:26:26:46 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict |
-| mongoengine_get_db_good.py:23:21:23:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
-| mongoengine_get_db_good.py:23:21:23:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
-| mongoengine_get_db_good.py:23:21:23:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
-| mongoengine_get_db_good.py:24:30:24:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search |
-| mongoengine_get_db_via_connection_bad.py:23:21:23:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
-| mongoengine_get_db_via_connection_bad.py:23:21:23:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
-| mongoengine_get_db_via_connection_bad.py:23:21:23:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
-| mongoengine_get_db_via_connection_bad.py:24:30:24:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search |
-| mongoengine_get_db_via_connection_bad.py:27:26:27:46 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict |
-| mongoengine_get_db_via_connection_good.py:24:21:24:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
-| mongoengine_get_db_via_connection_good.py:24:21:24:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
-| mongoengine_get_db_via_connection_good.py:24:21:24:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
-| mongoengine_get_db_via_connection_good.py:25:30:25:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search |
-| mongoengine_good.py:23:21:23:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
-| mongoengine_good.py:23:21:23:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
-| mongoengine_good.py:23:21:23:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
-| mongoengine_good.py:24:30:24:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search |
+| mongoclient_subscript_bad.py:17:21:17:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
+| mongoclient_subscript_bad.py:17:21:17:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
+| mongoclient_subscript_bad.py:17:21:17:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
+| mongoclient_subscript_bad.py:18:30:18:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search |
+| mongoclient_subscript_bad.py:21:37:21:57 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict |
+| mongoclient_subscript_good.py:18:21:18:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
+| mongoclient_subscript_good.py:18:21:18:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
+| mongoclient_subscript_good.py:18:21:18:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
+| mongoclient_subscript_good.py:19:30:19:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search |
+| mongoengine_bad.py:17:21:17:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
+| mongoengine_bad.py:17:21:17:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
+| mongoengine_bad.py:17:21:17:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
+| mongoengine_bad.py:18:30:18:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search |
+| mongoengine_bad.py:20:34:20:44 | ControlFlowNode for json_search | semmle.label | ControlFlowNode for json_search |
+| mongoengine_connect_bad.py:17:21:17:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
+| mongoengine_connect_bad.py:17:21:17:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
+| mongoengine_connect_bad.py:17:21:17:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
+| mongoengine_connect_bad.py:18:30:18:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search |
+| mongoengine_connect_bad.py:21:31:21:51 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict |
+| mongoengine_connect_good.py:18:21:18:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
+| mongoengine_connect_good.py:18:21:18:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
+| mongoengine_connect_good.py:18:21:18:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
+| mongoengine_connect_good.py:19:30:19:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search |
+| mongoengine_connect_via_connection_bad.py:18:21:18:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
+| mongoengine_connect_via_connection_bad.py:18:21:18:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
+| mongoengine_connect_via_connection_bad.py:18:21:18:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
+| mongoengine_connect_via_connection_bad.py:19:30:19:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search |
+| mongoengine_connect_via_connection_bad.py:22:31:22:51 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict |
+| mongoengine_connect_via_connection_good.py:19:21:19:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
+| mongoengine_connect_via_connection_good.py:19:21:19:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
+| mongoengine_connect_via_connection_good.py:19:21:19:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
+| mongoengine_connect_via_connection_good.py:20:30:20:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search |
+| mongoengine_flask_db_document_subclass_bad.py:18:21:18:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
+| mongoengine_flask_db_document_subclass_bad.py:18:21:18:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
+| mongoengine_flask_db_document_subclass_bad.py:18:21:18:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
+| mongoengine_flask_db_document_subclass_bad.py:19:30:19:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search |
+| mongoengine_flask_db_document_subclass_bad.py:21:34:21:44 | ControlFlowNode for json_search | semmle.label | ControlFlowNode for json_search |
+| mongoengine_flask_db_document_subclass_good.py:19:21:19:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
+| mongoengine_flask_db_document_subclass_good.py:19:21:19:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
+| mongoengine_flask_db_document_subclass_good.py:19:21:19:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
+| mongoengine_flask_db_document_subclass_good.py:20:30:20:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search |
+| mongoengine_get_db_bad.py:17:21:17:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
+| mongoengine_get_db_bad.py:17:21:17:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
+| mongoengine_get_db_bad.py:17:21:17:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
+| mongoengine_get_db_bad.py:18:30:18:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search |
+| mongoengine_get_db_bad.py:21:26:21:46 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict |
+| mongoengine_get_db_good.py:18:21:18:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
+| mongoengine_get_db_good.py:18:21:18:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
+| mongoengine_get_db_good.py:18:21:18:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
+| mongoengine_get_db_good.py:19:30:19:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search |
+| mongoengine_get_db_via_connection_bad.py:18:21:18:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
+| mongoengine_get_db_via_connection_bad.py:18:21:18:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
+| mongoengine_get_db_via_connection_bad.py:18:21:18:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
+| mongoengine_get_db_via_connection_bad.py:19:30:19:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search |
+| mongoengine_get_db_via_connection_bad.py:22:26:22:46 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict |
+| mongoengine_get_db_via_connection_good.py:19:21:19:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
+| mongoengine_get_db_via_connection_good.py:19:21:19:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
+| mongoengine_get_db_via_connection_good.py:19:21:19:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
+| mongoengine_get_db_via_connection_good.py:20:30:20:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search |
+| mongoengine_good.py:18:21:18:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
+| mongoengine_good.py:18:21:18:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
+| mongoengine_good.py:18:21:18:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
+| mongoengine_good.py:19:30:19:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search |
| pymongo_bad.py:11:21:11:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
| pymongo_bad.py:11:21:11:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
| pymongo_bad.py:11:21:11:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
@@ -177,14 +177,14 @@ nodes
| pymongo_good.py:12:21:12:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
| pymongo_good.py:13:30:13:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search |
#select
-| flask_mongoengine_bad.py:27:36:27:46 | ControlFlowNode for json_search | flask_mongoengine_bad.py:24:26:24:32 | ControlFlowNode for request | flask_mongoengine_bad.py:27:36:27:46 | ControlFlowNode for json_search | $@ NoSQL query contains an unsanitized $@ | flask_mongoengine_bad.py:27:36:27:46 | ControlFlowNode for json_search | This | flask_mongoengine_bad.py:24:26:24:32 | ControlFlowNode for request | user-provided value |
-| flask_mongoengine_get_db_bad.py:28:41:28:61 | ControlFlowNode for Dict | flask_mongoengine_get_db_bad.py:24:26:24:32 | ControlFlowNode for request | flask_mongoengine_get_db_bad.py:28:41:28:61 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | flask_mongoengine_get_db_bad.py:28:41:28:61 | ControlFlowNode for Dict | This | flask_mongoengine_get_db_bad.py:24:26:24:32 | ControlFlowNode for request | user-provided value |
+| flask_mongoengine_bad.py:22:36:22:46 | ControlFlowNode for json_search | flask_mongoengine_bad.py:19:26:19:32 | ControlFlowNode for request | flask_mongoengine_bad.py:22:36:22:46 | ControlFlowNode for json_search | $@ NoSQL query contains an unsanitized $@ | flask_mongoengine_bad.py:22:36:22:46 | ControlFlowNode for json_search | This | flask_mongoengine_bad.py:19:26:19:32 | ControlFlowNode for request | user-provided value |
+| flask_mongoengine_get_db_bad.py:23:41:23:61 | ControlFlowNode for Dict | flask_mongoengine_get_db_bad.py:19:26:19:32 | ControlFlowNode for request | flask_mongoengine_get_db_bad.py:23:41:23:61 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | flask_mongoengine_get_db_bad.py:23:41:23:61 | ControlFlowNode for Dict | This | flask_mongoengine_get_db_bad.py:19:26:19:32 | ControlFlowNode for request | user-provided value |
| flask_pymongo_bad.py:14:33:14:53 | ControlFlowNode for Dict | flask_pymongo_bad.py:11:26:11:32 | ControlFlowNode for request | flask_pymongo_bad.py:14:33:14:53 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | flask_pymongo_bad.py:14:33:14:53 | ControlFlowNode for Dict | This | flask_pymongo_bad.py:11:26:11:32 | ControlFlowNode for request | user-provided value |
-| mongoclient_subscript_bad.py:26:37:26:57 | ControlFlowNode for Dict | mongoclient_subscript_bad.py:22:21:22:27 | ControlFlowNode for request | mongoclient_subscript_bad.py:26:37:26:57 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | mongoclient_subscript_bad.py:26:37:26:57 | ControlFlowNode for Dict | This | mongoclient_subscript_bad.py:22:21:22:27 | ControlFlowNode for request | user-provided value |
-| mongoengine_bad.py:25:34:25:44 | ControlFlowNode for json_search | mongoengine_bad.py:22:21:22:27 | ControlFlowNode for request | mongoengine_bad.py:25:34:25:44 | ControlFlowNode for json_search | $@ NoSQL query contains an unsanitized $@ | mongoengine_bad.py:25:34:25:44 | ControlFlowNode for json_search | This | mongoengine_bad.py:22:21:22:27 | ControlFlowNode for request | user-provided value |
-| mongoengine_connect_bad.py:26:31:26:51 | ControlFlowNode for Dict | mongoengine_connect_bad.py:22:21:22:27 | ControlFlowNode for request | mongoengine_connect_bad.py:26:31:26:51 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | mongoengine_connect_bad.py:26:31:26:51 | ControlFlowNode for Dict | This | mongoengine_connect_bad.py:22:21:22:27 | ControlFlowNode for request | user-provided value |
-| mongoengine_connect_via_connection_bad.py:27:31:27:51 | ControlFlowNode for Dict | mongoengine_connect_via_connection_bad.py:23:21:23:27 | ControlFlowNode for request | mongoengine_connect_via_connection_bad.py:27:31:27:51 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | mongoengine_connect_via_connection_bad.py:27:31:27:51 | ControlFlowNode for Dict | This | mongoengine_connect_via_connection_bad.py:23:21:23:27 | ControlFlowNode for request | user-provided value |
-| mongoengine_flask_db_document_subclass_bad.py:26:34:26:44 | ControlFlowNode for json_search | mongoengine_flask_db_document_subclass_bad.py:23:21:23:27 | ControlFlowNode for request | mongoengine_flask_db_document_subclass_bad.py:26:34:26:44 | ControlFlowNode for json_search | $@ NoSQL query contains an unsanitized $@ | mongoengine_flask_db_document_subclass_bad.py:26:34:26:44 | ControlFlowNode for json_search | This | mongoengine_flask_db_document_subclass_bad.py:23:21:23:27 | ControlFlowNode for request | user-provided value |
-| mongoengine_get_db_bad.py:26:26:26:46 | ControlFlowNode for Dict | mongoengine_get_db_bad.py:22:21:22:27 | ControlFlowNode for request | mongoengine_get_db_bad.py:26:26:26:46 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | mongoengine_get_db_bad.py:26:26:26:46 | ControlFlowNode for Dict | This | mongoengine_get_db_bad.py:22:21:22:27 | ControlFlowNode for request | user-provided value |
-| mongoengine_get_db_via_connection_bad.py:27:26:27:46 | ControlFlowNode for Dict | mongoengine_get_db_via_connection_bad.py:23:21:23:27 | ControlFlowNode for request | mongoengine_get_db_via_connection_bad.py:27:26:27:46 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | mongoengine_get_db_via_connection_bad.py:27:26:27:46 | ControlFlowNode for Dict | This | mongoengine_get_db_via_connection_bad.py:23:21:23:27 | ControlFlowNode for request | user-provided value |
+| mongoclient_subscript_bad.py:21:37:21:57 | ControlFlowNode for Dict | mongoclient_subscript_bad.py:17:21:17:27 | ControlFlowNode for request | mongoclient_subscript_bad.py:21:37:21:57 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | mongoclient_subscript_bad.py:21:37:21:57 | ControlFlowNode for Dict | This | mongoclient_subscript_bad.py:17:21:17:27 | ControlFlowNode for request | user-provided value |
+| mongoengine_bad.py:20:34:20:44 | ControlFlowNode for json_search | mongoengine_bad.py:17:21:17:27 | ControlFlowNode for request | mongoengine_bad.py:20:34:20:44 | ControlFlowNode for json_search | $@ NoSQL query contains an unsanitized $@ | mongoengine_bad.py:20:34:20:44 | ControlFlowNode for json_search | This | mongoengine_bad.py:17:21:17:27 | ControlFlowNode for request | user-provided value |
+| mongoengine_connect_bad.py:21:31:21:51 | ControlFlowNode for Dict | mongoengine_connect_bad.py:17:21:17:27 | ControlFlowNode for request | mongoengine_connect_bad.py:21:31:21:51 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | mongoengine_connect_bad.py:21:31:21:51 | ControlFlowNode for Dict | This | mongoengine_connect_bad.py:17:21:17:27 | ControlFlowNode for request | user-provided value |
+| mongoengine_connect_via_connection_bad.py:22:31:22:51 | ControlFlowNode for Dict | mongoengine_connect_via_connection_bad.py:18:21:18:27 | ControlFlowNode for request | mongoengine_connect_via_connection_bad.py:22:31:22:51 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | mongoengine_connect_via_connection_bad.py:22:31:22:51 | ControlFlowNode for Dict | This | mongoengine_connect_via_connection_bad.py:18:21:18:27 | ControlFlowNode for request | user-provided value |
+| mongoengine_flask_db_document_subclass_bad.py:21:34:21:44 | ControlFlowNode for json_search | mongoengine_flask_db_document_subclass_bad.py:18:21:18:27 | ControlFlowNode for request | mongoengine_flask_db_document_subclass_bad.py:21:34:21:44 | ControlFlowNode for json_search | $@ NoSQL query contains an unsanitized $@ | mongoengine_flask_db_document_subclass_bad.py:21:34:21:44 | ControlFlowNode for json_search | This | mongoengine_flask_db_document_subclass_bad.py:18:21:18:27 | ControlFlowNode for request | user-provided value |
+| mongoengine_get_db_bad.py:21:26:21:46 | ControlFlowNode for Dict | mongoengine_get_db_bad.py:17:21:17:27 | ControlFlowNode for request | mongoengine_get_db_bad.py:21:26:21:46 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | mongoengine_get_db_bad.py:21:26:21:46 | ControlFlowNode for Dict | This | mongoengine_get_db_bad.py:17:21:17:27 | ControlFlowNode for request | user-provided value |
+| mongoengine_get_db_via_connection_bad.py:22:26:22:46 | ControlFlowNode for Dict | mongoengine_get_db_via_connection_bad.py:18:21:18:27 | ControlFlowNode for request | mongoengine_get_db_via_connection_bad.py:22:26:22:46 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | mongoengine_get_db_via_connection_bad.py:22:26:22:46 | ControlFlowNode for Dict | This | mongoengine_get_db_via_connection_bad.py:18:21:18:27 | ControlFlowNode for request | user-provided value |
| pymongo_bad.py:14:44:14:64 | ControlFlowNode for Dict | pymongo_bad.py:11:21:11:27 | ControlFlowNode for request | pymongo_bad.py:14:44:14:64 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | pymongo_bad.py:14:44:14:64 | ControlFlowNode for Dict | This | pymongo_bad.py:11:21:11:27 | ControlFlowNode for request | user-provided value |
From 81505fbd76d4add27d7fb6e2146473b3e77387f5 Mon Sep 17 00:00:00 2001
From: jorgectf
Date: Wed, 16 Jun 2021 23:18:38 +0200
Subject: [PATCH 084/429] Normalize tests
---
.../Security/CWE-943/flask_mongoengine_bad.py | 25 -----------------
...k_mongoengine_db_document_subclass_bad.py} | 0
..._mongoengine_db_document_subclass_good.py} | 0
.../CWE-943/flask_mongoengine_get_db_bad.py | 8 +++---
.../CWE-943/flask_mongoengine_get_db_good.py | 8 +++---
.../CWE-943/flask_mongoengine_good.py | 27 -------------------
.../Security/CWE-943/flask_pymongo_bad.py | 6 ++---
.../Security/CWE-943/flask_pymongo_good.py | 2 +-
.../CWE-943/mongoclient_subscript_bad.py | 2 +-
.../CWE-943/mongoclient_subscript_good.py | 2 +-
.../CWE-943/mongoengine_connect_bad.py | 2 +-
.../CWE-943/mongoengine_connect_good.py | 2 +-
.../mongoengine_connect_via_connection_bad.py | 2 +-
...mongoengine_connect_via_connection_good.py | 2 +-
...y => mongoengine_document_subclass_bad.py} | 0
... => mongoengine_document_subclass_good.py} | 0
.../Security/CWE-943/pymongo_bad.py | 2 +-
.../Security/CWE-943/pymongo_good.py | 2 +-
18 files changed, 20 insertions(+), 72 deletions(-)
delete mode 100644 python/ql/test/experimental/query-tests/Security/CWE-943/flask_mongoengine_bad.py
rename python/ql/test/experimental/query-tests/Security/CWE-943/{mongoengine_flask_db_document_subclass_bad.py => flask_mongoengine_db_document_subclass_bad.py} (100%)
rename python/ql/test/experimental/query-tests/Security/CWE-943/{mongoengine_flask_db_document_subclass_good.py => flask_mongoengine_db_document_subclass_good.py} (100%)
delete mode 100644 python/ql/test/experimental/query-tests/Security/CWE-943/flask_mongoengine_good.py
rename python/ql/test/experimental/query-tests/Security/CWE-943/{mongoengine_bad.py => mongoengine_document_subclass_bad.py} (100%)
rename python/ql/test/experimental/query-tests/Security/CWE-943/{mongoengine_good.py => mongoengine_document_subclass_good.py} (100%)
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/flask_mongoengine_bad.py b/python/ql/test/experimental/query-tests/Security/CWE-943/flask_mongoengine_bad.py
deleted file mode 100644
index 8f9da2d6d72..00000000000
--- a/python/ql/test/experimental/query-tests/Security/CWE-943/flask_mongoengine_bad.py
+++ /dev/null
@@ -1,25 +0,0 @@
-from flask import Flask, request
-from flask_mongoengine import MongoEngine
-import json
-
-app = Flask(__name__)
-db = MongoEngine(app)
-db.init_app(app)
-
-
-class Movie(db.Document):
- title = db.StringField(required=True)
-
-
-Movie(title='test').save()
-
-
-@app.route("/")
-def home_page():
- unsanitized_search = request.args['search']
- json_search = json.loads(unsanitized_search)
-
- result = Movie.objects(__raw__=json_search)
-
-# if __name__ == "__main__":
-# app.run(debug=True)
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_flask_db_document_subclass_bad.py b/python/ql/test/experimental/query-tests/Security/CWE-943/flask_mongoengine_db_document_subclass_bad.py
similarity index 100%
rename from python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_flask_db_document_subclass_bad.py
rename to python/ql/test/experimental/query-tests/Security/CWE-943/flask_mongoengine_db_document_subclass_bad.py
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_flask_db_document_subclass_good.py b/python/ql/test/experimental/query-tests/Security/CWE-943/flask_mongoengine_db_document_subclass_good.py
similarity index 100%
rename from python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_flask_db_document_subclass_good.py
rename to python/ql/test/experimental/query-tests/Security/CWE-943/flask_mongoengine_db_document_subclass_good.py
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/flask_mongoengine_get_db_bad.py b/python/ql/test/experimental/query-tests/Security/CWE-943/flask_mongoengine_get_db_bad.py
index 0becf217e53..468e1d865a7 100644
--- a/python/ql/test/experimental/query-tests/Security/CWE-943/flask_mongoengine_get_db_bad.py
+++ b/python/ql/test/experimental/query-tests/Security/CWE-943/flask_mongoengine_get_db_bad.py
@@ -3,8 +3,8 @@ from flask_mongoengine import MongoEngine
import json
app = Flask(__name__)
+app.config.from_pyfile('the-config.cfg')
db = MongoEngine(app)
-db.init_app(app)
class Movie(db.Document):
@@ -16,11 +16,11 @@ Movie(title='test').save()
@app.route("/")
def home_page():
- unsanitized_search = request.args['search']
- json_search = json.loads(unsanitized_search)
+ unsafe_search = request.args['search']
+ json_search = json.loads(unsafe_search)
retrieved_db = db.get_db()
- result = retrieved_db["Movie"].find({'name': json_search})
+ data = retrieved_db["Movie"].find({'name': json_search})
# if __name__ == "__main__":
# app.run(debug=True)
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/flask_mongoengine_get_db_good.py b/python/ql/test/experimental/query-tests/Security/CWE-943/flask_mongoengine_get_db_good.py
index e1d4ea7d778..5837eaa2d58 100644
--- a/python/ql/test/experimental/query-tests/Security/CWE-943/flask_mongoengine_get_db_good.py
+++ b/python/ql/test/experimental/query-tests/Security/CWE-943/flask_mongoengine_get_db_good.py
@@ -4,8 +4,8 @@ from mongosanitizer.sanitizer import sanitize
import json
app = Flask(__name__)
+app.config.from_pyfile('the-config.cfg')
db = MongoEngine(app)
-db.init_app(app)
class Movie(db.Document):
@@ -17,12 +17,12 @@ Movie(title='test').save()
@app.route("/")
def home_page():
- unsanitized_search = request.args['search']
- json_search = json.loads(unsanitized_search)
+ unsafe_search = request.args['search']
+ json_search = json.loads(unsafe_search)
safe_search = sanitize(json_search)
retrieved_db = db.get_db()
- result = retrieved_db["Movie"].find({'name': safe_search})
+ data = retrieved_db["Movie"].find({'name': safe_search})
# if __name__ == "__main__":
# app.run(debug=True)
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/flask_mongoengine_good.py b/python/ql/test/experimental/query-tests/Security/CWE-943/flask_mongoengine_good.py
deleted file mode 100644
index 5b34de49781..00000000000
--- a/python/ql/test/experimental/query-tests/Security/CWE-943/flask_mongoengine_good.py
+++ /dev/null
@@ -1,27 +0,0 @@
-from flask import Flask, request
-from flask_mongoengine import MongoEngine
-from mongosanitizer.sanitizer import sanitize
-import json
-
-app = Flask(__name__)
-db = MongoEngine(app)
-db.init_app(app)
-
-
-class Movie(db.Document):
- title = db.StringField(required=True)
-
-
-Movie(title='test').save()
-
-
-@app.route("/")
-def home_page():
- unsafe_search = request.args['search']
- json_search = json.loads(unsafe_search)
- safe_search = sanitize(json_search)
-
- result = Movie.objects(__raw__=safe_search)
-
-# if __name__ == "__main__":
-# app.run(debug=True)
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/flask_pymongo_bad.py b/python/ql/test/experimental/query-tests/Security/CWE-943/flask_pymongo_bad.py
index 421e2d65a9e..93c570fbe58 100644
--- a/python/ql/test/experimental/query-tests/Security/CWE-943/flask_pymongo_bad.py
+++ b/python/ql/test/experimental/query-tests/Security/CWE-943/flask_pymongo_bad.py
@@ -8,10 +8,10 @@ mongo = PyMongo(app)
@app.route("/")
def home_page():
- unsanitized_search = request.args['search']
- json_search = json.loads(unsanitized_search)
+ unsafe_search = request.args['search']
+ json_search = json.loads(unsafe_search)
- result = mongo.db.user.find({'name': json_search})
+ data = mongo.db.user.find({'name': json_search})
# if __name__ == "__main__":
# app.run(debug=True)
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/flask_pymongo_good.py b/python/ql/test/experimental/query-tests/Security/CWE-943/flask_pymongo_good.py
index 72907b6ba43..29af42d8536 100644
--- a/python/ql/test/experimental/query-tests/Security/CWE-943/flask_pymongo_good.py
+++ b/python/ql/test/experimental/query-tests/Security/CWE-943/flask_pymongo_good.py
@@ -13,7 +13,7 @@ def home_page():
json_search = json.loads(unsafe_search)
safe_search = sanitize(json_search)
- result = mongo.db.user.find({'name': safe_search})
+ data = mongo.db.user.find({'name': safe_search})
# if __name__ == "__main__":
# app.run(debug=True)
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoclient_subscript_bad.py b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoclient_subscript_bad.py
index cc1fd7ce59a..96e08418b24 100644
--- a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoclient_subscript_bad.py
+++ b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoclient_subscript_bad.py
@@ -18,7 +18,7 @@ def home_page():
json_search = json.loads(unsafe_search)
db = me.connect('mydb')
- data = db['mydb']['movie'].find({'name': json_search})
+ data = db['movie'].find({'name': json_search})
# if __name__ == "__main__":
# app.run(debug=True)
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoclient_subscript_good.py b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoclient_subscript_good.py
index 8a5bed832c6..e9be8dd3e3c 100644
--- a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoclient_subscript_good.py
+++ b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoclient_subscript_good.py
@@ -20,7 +20,7 @@ def home_page():
safe_search = sanitize(json_search)
db = me.connect('mydb')
- data = db['mydb']['movie'].find({'name': safe_search})
+ data = db['movie'].find({'name': safe_search})
# if __name__ == "__main__":
# app.run(debug=True)
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_connect_bad.py b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_connect_bad.py
index 8d6a0c30d52..1443f72720d 100644
--- a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_connect_bad.py
+++ b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_connect_bad.py
@@ -18,7 +18,7 @@ def home_page():
json_search = json.loads(unsafe_search)
db = me.connect('mydb')
- data = db.mydb.movie.find({'name': json_search})
+ data = db.movie.find({'name': json_search})
# if __name__ == "__main__":
# app.run(debug=True)
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_connect_good.py b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_connect_good.py
index 93109deeaf9..219503a213a 100644
--- a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_connect_good.py
+++ b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_connect_good.py
@@ -20,7 +20,7 @@ def home_page():
safe_search = sanitize(json_search)
db = me.connect('mydb')
- data = db.mydb.movie.find({'name': safe_search})
+ data = db.movie.find({'name': json_search})
# if __name__ == "__main__":
# app.run(debug=True)
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_connect_via_connection_bad.py b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_connect_via_connection_bad.py
index 167eddeb5e9..398199bc0cd 100644
--- a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_connect_via_connection_bad.py
+++ b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_connect_via_connection_bad.py
@@ -19,7 +19,7 @@ def home_page():
json_search = json.loads(unsafe_search)
db = connect('mydb')
- data = db.mydb.movie.find({'name': json_search})
+ data = db.movie.find({'name': json_search})
# if __name__ == "__main__":
# app.run(debug=True)
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_connect_via_connection_good.py b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_connect_via_connection_good.py
index 0283bfdd57a..51b801468ce 100644
--- a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_connect_via_connection_good.py
+++ b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_connect_via_connection_good.py
@@ -21,7 +21,7 @@ def home_page():
safe_search = sanitize(json_search)
db = connect('mydb')
- data = db.mydb.movie.find({'name': json_search})
+ data = db.movie.find({'name': json_search})
# if __name__ == "__main__":
# app.run(debug=True)
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_bad.py b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_document_subclass_bad.py
similarity index 100%
rename from python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_bad.py
rename to python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_document_subclass_bad.py
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_good.py b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_document_subclass_good.py
similarity index 100%
rename from python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_good.py
rename to python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_document_subclass_good.py
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/pymongo_bad.py b/python/ql/test/experimental/query-tests/Security/CWE-943/pymongo_bad.py
index e280f90a9f9..e0fc3514d73 100644
--- a/python/ql/test/experimental/query-tests/Security/CWE-943/pymongo_bad.py
+++ b/python/ql/test/experimental/query-tests/Security/CWE-943/pymongo_bad.py
@@ -11,7 +11,7 @@ def home_page():
unsafe_search = request.args['search']
json_search = json.loads(unsafe_search)
- result = client.db.collection.find_one({'data': json_search})
+ data = client.db.collection.find_one({'data': json_search})
# if __name__ == "__main__":
# app.run(debug=True)
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/pymongo_good.py b/python/ql/test/experimental/query-tests/Security/CWE-943/pymongo_good.py
index f6a113203f9..0e52609fd7d 100644
--- a/python/ql/test/experimental/query-tests/Security/CWE-943/pymongo_good.py
+++ b/python/ql/test/experimental/query-tests/Security/CWE-943/pymongo_good.py
@@ -13,7 +13,7 @@ def home_page():
json_search = json.loads(unsafe_search)
safe_search = sanitize(json_search)
- result = client.db.collection.find_one({'data': safe_search})
+ data = client.db.collection.find_one({'data': safe_search})
# if __name__ == "__main__":
# app.run(debug=True)
From 5c7229c715496d479104bdec8f957a52bf585159 Mon Sep 17 00:00:00 2001
From: jorgectf
Date: Wed, 16 Jun 2021 23:19:05 +0200
Subject: [PATCH 085/429] Optimize Type Tracking stuff
---
.../semmle/python/frameworks/NoSQL.qll | 174 +++++++-----------
1 file changed, 64 insertions(+), 110 deletions(-)
diff --git a/python/ql/src/experimental/semmle/python/frameworks/NoSQL.qll b/python/ql/src/experimental/semmle/python/frameworks/NoSQL.qll
index 6561db67f9a..2b6fbb1f752 100644
--- a/python/ql/src/experimental/semmle/python/frameworks/NoSQL.qll
+++ b/python/ql/src/experimental/semmle/python/frameworks/NoSQL.qll
@@ -11,64 +11,76 @@ private import experimental.semmle.python.Concepts
private import semmle.python.ApiGraphs
private module NoSQL {
- /** Gets a reference to a `MongoClient` instance. */
- private API::Node mongoClientInstance() {
- result = API::moduleImport("pymongo").getMember("MongoClient").getReturn() or
- result =
- API::moduleImport("flask_mongoengine")
- .getMember("MongoEngine")
- .getReturn()
- .getMember("get_db")
- .getReturn() or
- result =
- API::moduleImport(["mongoengine", "mongoengine.connection"])
- .getMember(["get_db", "connect"])
- .getReturn() or
+ /** API Nodes returning `Mongo` instances. */
+ private API::Node pyMongo() {
+ result = API::moduleImport("pymongo").getMember("MongoClient").getReturn()
+ }
+
+ private API::Node flask_PyMongo() {
result = API::moduleImport("flask_pymongo").getMember("PyMongo").getReturn()
}
- /** Gets a reference to a `MongoClient` DB. */
- private DataFlow::LocalSourceNode mongoClientDB(DataFlow::TypeTracker t) {
+ private API::Node mongoEngine() { result = API::moduleImport("mongoengine") }
+
+ private API::Node flask_MongoEngine() {
+ result = API::moduleImport("flask_mongoengine").getMember("MongoEngine").getReturn()
+ }
+
+ /** Gets a reference to a initialized `Mongo` instance. */
+ private API::Node mongoInstance() {
+ result = pyMongo() or
+ result = flask_PyMongo()
+ }
+
+ /** Gets a reference to a initialized `Mongo` DB instance. */
+ private API::Node mongoDBInstance() {
+ result = mongoEngine().getMember(["get_db", "connect"]).getReturn() or
+ result = mongoEngine().getMember("connection").getMember(["get_db", "connect"]).getReturn() or
+ result = flask_MongoEngine().getMember("get_db").getReturn()
+ }
+
+ /** Gets a reference to a `Mongo` DB use. */
+ private DataFlow::LocalSourceNode mongoDB(DataFlow::TypeTracker t) {
+ t.start() and
+ (
+ exists(SubscriptNode subscript |
+ subscript.getObject() = mongoInstance().getAUse().asCfgNode() and
+ result.asCfgNode() = subscript
+ )
+ or
+ result.(DataFlow::AttrRead).getObject() = mongoInstance().getAUse()
+ or
+ result = mongoDBInstance().getAUse()
+ )
+ or
+ exists(DataFlow::TypeTracker t2 | result = mongoDB(t2).track(t2, t))
+ }
+
+ /** Gets a reference to a `Mongo` DB use. */
+ private DataFlow::Node mongoDB() { mongoDB(DataFlow::TypeTracker::end()).flowsTo(result) }
+
+ /** Gets a reference to a `Mongo` collection use. */
+ private DataFlow::LocalSourceNode mongoCollection(DataFlow::TypeTracker t) {
t.start() and
(
exists(SubscriptNode subscript | result.asCfgNode() = subscript |
- subscript.getObject() = mongoClientInstance().getAUse().asCfgNode()
+ subscript.getObject() = mongoDB().asCfgNode()
)
or
- result.(DataFlow::AttrRead).getObject() = mongoClientInstance().getAUse()
+ result.(DataFlow::AttrRead).getObject() = mongoDB()
)
or
- exists(DataFlow::TypeTracker t2 | result = mongoClientDB(t2).track(t2, t))
+ exists(DataFlow::TypeTracker t2 | result = mongoCollection(t2).track(t2, t))
}
- /** Gets a reference to a `MongoClient` DB. */
- private DataFlow::Node mongoClientDB() {
- mongoClientDB(DataFlow::TypeTracker::end()).flowsTo(result)
+ /** Gets a reference to a `Mongo` collection use. */
+ private DataFlow::Node mongoCollection() {
+ mongoCollection(DataFlow::TypeTracker::end()).flowsTo(result)
}
- /** Gets a reference to a `MongoClient` collection. */
- private DataFlow::LocalSourceNode mongoClientCollection(DataFlow::TypeTracker t) {
- t.start() and
- (
- exists(SubscriptNode subscript | result.asCfgNode() = subscript |
- subscript.getObject() = mongoClientDB().asCfgNode()
- )
- or
- result.(DataFlow::AttrRead).getObject() = mongoClientDB()
- )
- or
- exists(DataFlow::TypeTracker t2 | result = mongoClientCollection(t2).track(t2, t))
- }
-
- /** Gets a reference to a `MongoClient` collection. */
- private DataFlow::Node mongoClientCollection() {
- mongoClientCollection(DataFlow::TypeTracker::end()).flowsTo(result)
- }
-
- /** This class represents names of find_* relevant MongoClient collection level operation methods. */
- private class MongoClientMethodNames extends string {
- MongoClientMethodNames() {
- // the find_one_or_404 method is only found in the Pymongo Flask library.
+ /** This class represents names of find_* relevant `Mongo` collection-level operation methods. */
+ private class MongoCollectionMethodNames extends string {
+ MongoCollectionMethodNames() {
this in [
"find", "find_raw_batches", "find_one", "find_one_and_delete", "find_and_modify",
"find_one_and_replace", "find_one_and_update", "find_one_or_404"
@@ -76,18 +88,15 @@ private module NoSQL {
}
}
- /** Gets a reference to a `MongoClient` Collection method. */
- private DataFlow::Node mongoClientMethod() {
- result.(DataFlow::AttrRead).getAttributeName() instanceof MongoClientMethodNames and
- (
- result.(DataFlow::AttrRead).getObject() = mongoClientCollection() or
- result.(DataFlow::AttrRead) = mongoClientCollection()
- )
+ /** Gets a reference to a `Mongo` collection method. */
+ private DataFlow::Node mongoCollectionMethod() {
+ mongoCollection() in [result.(DataFlow::AttrRead), result.(DataFlow::AttrRead).getObject()] and
+ result.(DataFlow::AttrRead).getAttributeName() instanceof MongoCollectionMethodNames
}
- /** Gets a reference to a `MongoClient` call */
- private class MongoClientCall extends DataFlow::CallCfgNode, NoSQLQuery::Range {
- MongoClientCall() { this.getFunction() = mongoClientMethod() }
+ /** Gets a reference to a `Mongo` collection method call */
+ private class MongoCollectionCall extends DataFlow::CallCfgNode, NoSQLQuery::Range {
+ MongoCollectionCall() { this.getFunction() = mongoCollectionMethod() }
override DataFlow::Node getQuery() { result = this.getArg(0) }
}
@@ -95,7 +104,7 @@ private module NoSQL {
private class MongoEngineObjectsCall extends DataFlow::CallCfgNode, NoSQLQuery::Range {
MongoEngineObjectsCall() {
this =
- API::moduleImport("mongoengine")
+ [mongoEngine(), flask_MongoEngine()]
.getMember(["Document", "EmbeddedDocument"])
.getASubclass()
.getMember("objects")
@@ -105,61 +114,6 @@ private module NoSQL {
override DataFlow::Node getQuery() { result = this.getArgByName(_) }
}
- private class FlaskMongoEngineObjectsCall extends DataFlow::CallCfgNode, NoSQLQuery::Range {
- FlaskMongoEngineObjectsCall() {
- this =
- API::moduleImport("flask_mongoengine")
- .getMember("MongoEngine")
- .getReturn()
- .getMember(["Document", "EmbeddedDocument"])
- .getASubclass()
- .getMember("objects")
- .getACall()
- }
-
- override DataFlow::Node getQuery() { result = this.getArgByName(_) }
- }
-
- private DataFlow::Node flaskMongoEngineInstance() {
- result = API::moduleImport("flask_mongoengine").getMember("MongoEngine").getReturn().getAUse()
- }
-
- /**
- * A MongoEngine.Document or MongoEngine.EmbeddedDocument subclass which represents a MongoDB document.
- */
- private class FlaskMongoEngineDocumentClass extends ClassValue {
- FlaskMongoEngineDocumentClass() {
- this.getASuperType().getName() in ["Document", "EmbeddedDocument"] and
- exists(AttrNode documentClass |
- documentClass.getName() in ["Document", "EmbeddedDocument"] and
- documentClass.getObject() = flaskMongoEngineInstance().asCfgNode() and
- // This is super hacky. It checks to see if the class is a subclass of a flaskMongoEngineInstance.Document
- this.getASuperType()
- .getAReference()
- .getNode()
- .(ClassExpr)
- .contains(documentClass.getNode().getObject())
- )
- }
- }
-
- private class FlaskMongoEngineDocumentSubclassInstanceCall extends DataFlow::CallCfgNode,
- NoSQLQuery::Range {
- FlaskMongoEngineDocumentSubclassInstanceCall() {
- exists(
- DataFlow::CallCfgNode objectsCall,
- FlaskMongoEngineDocumentClass flaskMongoEngineDocumentClass
- |
- objectsCall.getFunction().asExpr().(Attribute).getObject().getAFlowNode() =
- flaskMongoEngineDocumentClass.getAReference() and
- objectsCall.asCfgNode().(CallNode).getNode().getFunc().(Attribute).getName() = "objects" and
- this = objectsCall
- )
- }
-
- override DataFlow::Node getQuery() { result = this.getArgByName(_) }
- }
-
private class MongoSanitizerCall extends DataFlow::CallCfgNode, NoSQLSanitizer::Range {
MongoSanitizerCall() {
this =
From 8527ccc6d6f4aea5aa889b2e69847203c9b2d09d Mon Sep 17 00:00:00 2001
From: jorgectf
Date: Wed, 16 Jun 2021 23:19:14 +0200
Subject: [PATCH 086/429] Update .expected
---
.../Security/CWE-943/NoSQLInjection.expected | 163 ++++++++----------
1 file changed, 73 insertions(+), 90 deletions(-)
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/NoSQLInjection.expected b/python/ql/test/experimental/query-tests/Security/CWE-943/NoSQLInjection.expected
index dd247bc9206..da28a2d0d15 100644
--- a/python/ql/test/experimental/query-tests/Security/CWE-943/NoSQLInjection.expected
+++ b/python/ql/test/experimental/query-tests/Security/CWE-943/NoSQLInjection.expected
@@ -1,57 +1,53 @@
edges
-| flask_mongoengine_bad.py:19:26:19:32 | ControlFlowNode for request | flask_mongoengine_bad.py:19:26:19:37 | ControlFlowNode for Attribute |
-| flask_mongoengine_bad.py:19:26:19:37 | ControlFlowNode for Attribute | flask_mongoengine_bad.py:19:26:19:47 | ControlFlowNode for Subscript |
-| flask_mongoengine_bad.py:19:26:19:47 | ControlFlowNode for Subscript | flask_mongoengine_bad.py:20:30:20:47 | ControlFlowNode for unsanitized_search |
-| flask_mongoengine_bad.py:20:30:20:47 | ControlFlowNode for unsanitized_search | flask_mongoengine_bad.py:22:36:22:46 | ControlFlowNode for json_search |
-| flask_mongoengine_get_db_bad.py:19:26:19:32 | ControlFlowNode for request | flask_mongoengine_get_db_bad.py:19:26:19:37 | ControlFlowNode for Attribute |
-| flask_mongoengine_get_db_bad.py:19:26:19:37 | ControlFlowNode for Attribute | flask_mongoengine_get_db_bad.py:19:26:19:47 | ControlFlowNode for Subscript |
-| flask_mongoengine_get_db_bad.py:19:26:19:47 | ControlFlowNode for Subscript | flask_mongoengine_get_db_bad.py:20:30:20:47 | ControlFlowNode for unsanitized_search |
-| flask_mongoengine_get_db_bad.py:20:30:20:47 | ControlFlowNode for unsanitized_search | flask_mongoengine_get_db_bad.py:23:41:23:61 | ControlFlowNode for Dict |
-| flask_mongoengine_get_db_good.py:20:26:20:32 | ControlFlowNode for request | flask_mongoengine_get_db_good.py:20:26:20:37 | ControlFlowNode for Attribute |
-| flask_mongoengine_get_db_good.py:20:26:20:37 | ControlFlowNode for Attribute | flask_mongoengine_get_db_good.py:20:26:20:47 | ControlFlowNode for Subscript |
-| flask_mongoengine_get_db_good.py:20:26:20:47 | ControlFlowNode for Subscript | flask_mongoengine_get_db_good.py:21:30:21:47 | ControlFlowNode for unsanitized_search |
-| flask_mongoengine_good.py:20:21:20:27 | ControlFlowNode for request | flask_mongoengine_good.py:20:21:20:32 | ControlFlowNode for Attribute |
-| flask_mongoengine_good.py:20:21:20:32 | ControlFlowNode for Attribute | flask_mongoengine_good.py:20:21:20:42 | ControlFlowNode for Subscript |
-| flask_mongoengine_good.py:20:21:20:42 | ControlFlowNode for Subscript | flask_mongoengine_good.py:21:30:21:42 | ControlFlowNode for unsafe_search |
-| flask_pymongo_bad.py:11:26:11:32 | ControlFlowNode for request | flask_pymongo_bad.py:11:26:11:37 | ControlFlowNode for Attribute |
-| flask_pymongo_bad.py:11:26:11:37 | ControlFlowNode for Attribute | flask_pymongo_bad.py:11:26:11:47 | ControlFlowNode for Subscript |
-| flask_pymongo_bad.py:11:26:11:47 | ControlFlowNode for Subscript | flask_pymongo_bad.py:12:30:12:47 | ControlFlowNode for unsanitized_search |
-| flask_pymongo_bad.py:12:30:12:47 | ControlFlowNode for unsanitized_search | flask_pymongo_bad.py:14:33:14:53 | ControlFlowNode for Dict |
+| flask_mongoengine_db_document_subclass_bad.py:18:21:18:27 | ControlFlowNode for request | flask_mongoengine_db_document_subclass_bad.py:18:21:18:32 | ControlFlowNode for Attribute |
+| flask_mongoengine_db_document_subclass_bad.py:18:21:18:32 | ControlFlowNode for Attribute | flask_mongoengine_db_document_subclass_bad.py:18:21:18:42 | ControlFlowNode for Subscript |
+| flask_mongoengine_db_document_subclass_bad.py:18:21:18:42 | ControlFlowNode for Subscript | flask_mongoengine_db_document_subclass_bad.py:19:30:19:42 | ControlFlowNode for unsafe_search |
+| flask_mongoengine_db_document_subclass_bad.py:19:30:19:42 | ControlFlowNode for unsafe_search | flask_mongoengine_db_document_subclass_bad.py:21:34:21:44 | ControlFlowNode for json_search |
+| flask_mongoengine_db_document_subclass_good.py:19:21:19:27 | ControlFlowNode for request | flask_mongoengine_db_document_subclass_good.py:19:21:19:32 | ControlFlowNode for Attribute |
+| flask_mongoengine_db_document_subclass_good.py:19:21:19:32 | ControlFlowNode for Attribute | flask_mongoengine_db_document_subclass_good.py:19:21:19:42 | ControlFlowNode for Subscript |
+| flask_mongoengine_db_document_subclass_good.py:19:21:19:42 | ControlFlowNode for Subscript | flask_mongoengine_db_document_subclass_good.py:20:30:20:42 | ControlFlowNode for unsafe_search |
+| flask_mongoengine_get_db_bad.py:19:21:19:27 | ControlFlowNode for request | flask_mongoengine_get_db_bad.py:19:21:19:32 | ControlFlowNode for Attribute |
+| flask_mongoengine_get_db_bad.py:19:21:19:32 | ControlFlowNode for Attribute | flask_mongoengine_get_db_bad.py:19:21:19:42 | ControlFlowNode for Subscript |
+| flask_mongoengine_get_db_bad.py:19:21:19:42 | ControlFlowNode for Subscript | flask_mongoengine_get_db_bad.py:20:30:20:42 | ControlFlowNode for unsafe_search |
+| flask_mongoengine_get_db_bad.py:20:30:20:42 | ControlFlowNode for unsafe_search | flask_mongoengine_get_db_bad.py:23:39:23:59 | ControlFlowNode for Dict |
+| flask_mongoengine_get_db_good.py:20:21:20:27 | ControlFlowNode for request | flask_mongoengine_get_db_good.py:20:21:20:32 | ControlFlowNode for Attribute |
+| flask_mongoengine_get_db_good.py:20:21:20:32 | ControlFlowNode for Attribute | flask_mongoengine_get_db_good.py:20:21:20:42 | ControlFlowNode for Subscript |
+| flask_mongoengine_get_db_good.py:20:21:20:42 | ControlFlowNode for Subscript | flask_mongoengine_get_db_good.py:21:30:21:42 | ControlFlowNode for unsafe_search |
+| flask_pymongo_bad.py:11:21:11:27 | ControlFlowNode for request | flask_pymongo_bad.py:11:21:11:32 | ControlFlowNode for Attribute |
+| flask_pymongo_bad.py:11:21:11:32 | ControlFlowNode for Attribute | flask_pymongo_bad.py:11:21:11:42 | ControlFlowNode for Subscript |
+| flask_pymongo_bad.py:11:21:11:42 | ControlFlowNode for Subscript | flask_pymongo_bad.py:12:30:12:42 | ControlFlowNode for unsafe_search |
+| flask_pymongo_bad.py:12:30:12:42 | ControlFlowNode for unsafe_search | flask_pymongo_bad.py:14:31:14:51 | ControlFlowNode for Dict |
| flask_pymongo_good.py:12:21:12:27 | ControlFlowNode for request | flask_pymongo_good.py:12:21:12:32 | ControlFlowNode for Attribute |
| flask_pymongo_good.py:12:21:12:32 | ControlFlowNode for Attribute | flask_pymongo_good.py:12:21:12:42 | ControlFlowNode for Subscript |
| flask_pymongo_good.py:12:21:12:42 | ControlFlowNode for Subscript | flask_pymongo_good.py:13:30:13:42 | ControlFlowNode for unsafe_search |
| mongoclient_subscript_bad.py:17:21:17:27 | ControlFlowNode for request | mongoclient_subscript_bad.py:17:21:17:32 | ControlFlowNode for Attribute |
| mongoclient_subscript_bad.py:17:21:17:32 | ControlFlowNode for Attribute | mongoclient_subscript_bad.py:17:21:17:42 | ControlFlowNode for Subscript |
| mongoclient_subscript_bad.py:17:21:17:42 | ControlFlowNode for Subscript | mongoclient_subscript_bad.py:18:30:18:42 | ControlFlowNode for unsafe_search |
-| mongoclient_subscript_bad.py:18:30:18:42 | ControlFlowNode for unsafe_search | mongoclient_subscript_bad.py:21:37:21:57 | ControlFlowNode for Dict |
+| mongoclient_subscript_bad.py:18:30:18:42 | ControlFlowNode for unsafe_search | mongoclient_subscript_bad.py:21:29:21:49 | ControlFlowNode for Dict |
| mongoclient_subscript_good.py:18:21:18:27 | ControlFlowNode for request | mongoclient_subscript_good.py:18:21:18:32 | ControlFlowNode for Attribute |
| mongoclient_subscript_good.py:18:21:18:32 | ControlFlowNode for Attribute | mongoclient_subscript_good.py:18:21:18:42 | ControlFlowNode for Subscript |
| mongoclient_subscript_good.py:18:21:18:42 | ControlFlowNode for Subscript | mongoclient_subscript_good.py:19:30:19:42 | ControlFlowNode for unsafe_search |
-| mongoengine_bad.py:17:21:17:27 | ControlFlowNode for request | mongoengine_bad.py:17:21:17:32 | ControlFlowNode for Attribute |
-| mongoengine_bad.py:17:21:17:32 | ControlFlowNode for Attribute | mongoengine_bad.py:17:21:17:42 | ControlFlowNode for Subscript |
-| mongoengine_bad.py:17:21:17:42 | ControlFlowNode for Subscript | mongoengine_bad.py:18:30:18:42 | ControlFlowNode for unsafe_search |
-| mongoengine_bad.py:18:30:18:42 | ControlFlowNode for unsafe_search | mongoengine_bad.py:20:34:20:44 | ControlFlowNode for json_search |
| mongoengine_connect_bad.py:17:21:17:27 | ControlFlowNode for request | mongoengine_connect_bad.py:17:21:17:32 | ControlFlowNode for Attribute |
| mongoengine_connect_bad.py:17:21:17:32 | ControlFlowNode for Attribute | mongoengine_connect_bad.py:17:21:17:42 | ControlFlowNode for Subscript |
| mongoengine_connect_bad.py:17:21:17:42 | ControlFlowNode for Subscript | mongoengine_connect_bad.py:18:30:18:42 | ControlFlowNode for unsafe_search |
-| mongoengine_connect_bad.py:18:30:18:42 | ControlFlowNode for unsafe_search | mongoengine_connect_bad.py:21:31:21:51 | ControlFlowNode for Dict |
+| mongoengine_connect_bad.py:18:30:18:42 | ControlFlowNode for unsafe_search | mongoengine_connect_bad.py:21:26:21:46 | ControlFlowNode for Dict |
| mongoengine_connect_good.py:18:21:18:27 | ControlFlowNode for request | mongoengine_connect_good.py:18:21:18:32 | ControlFlowNode for Attribute |
| mongoengine_connect_good.py:18:21:18:32 | ControlFlowNode for Attribute | mongoengine_connect_good.py:18:21:18:42 | ControlFlowNode for Subscript |
| mongoengine_connect_good.py:18:21:18:42 | ControlFlowNode for Subscript | mongoengine_connect_good.py:19:30:19:42 | ControlFlowNode for unsafe_search |
| mongoengine_connect_via_connection_bad.py:18:21:18:27 | ControlFlowNode for request | mongoengine_connect_via_connection_bad.py:18:21:18:32 | ControlFlowNode for Attribute |
| mongoengine_connect_via_connection_bad.py:18:21:18:32 | ControlFlowNode for Attribute | mongoengine_connect_via_connection_bad.py:18:21:18:42 | ControlFlowNode for Subscript |
| mongoengine_connect_via_connection_bad.py:18:21:18:42 | ControlFlowNode for Subscript | mongoengine_connect_via_connection_bad.py:19:30:19:42 | ControlFlowNode for unsafe_search |
-| mongoengine_connect_via_connection_bad.py:19:30:19:42 | ControlFlowNode for unsafe_search | mongoengine_connect_via_connection_bad.py:22:31:22:51 | ControlFlowNode for Dict |
+| mongoengine_connect_via_connection_bad.py:19:30:19:42 | ControlFlowNode for unsafe_search | mongoengine_connect_via_connection_bad.py:22:26:22:46 | ControlFlowNode for Dict |
| mongoengine_connect_via_connection_good.py:19:21:19:27 | ControlFlowNode for request | mongoengine_connect_via_connection_good.py:19:21:19:32 | ControlFlowNode for Attribute |
| mongoengine_connect_via_connection_good.py:19:21:19:32 | ControlFlowNode for Attribute | mongoengine_connect_via_connection_good.py:19:21:19:42 | ControlFlowNode for Subscript |
| mongoengine_connect_via_connection_good.py:19:21:19:42 | ControlFlowNode for Subscript | mongoengine_connect_via_connection_good.py:20:30:20:42 | ControlFlowNode for unsafe_search |
-| mongoengine_flask_db_document_subclass_bad.py:18:21:18:27 | ControlFlowNode for request | mongoengine_flask_db_document_subclass_bad.py:18:21:18:32 | ControlFlowNode for Attribute |
-| mongoengine_flask_db_document_subclass_bad.py:18:21:18:32 | ControlFlowNode for Attribute | mongoengine_flask_db_document_subclass_bad.py:18:21:18:42 | ControlFlowNode for Subscript |
-| mongoengine_flask_db_document_subclass_bad.py:18:21:18:42 | ControlFlowNode for Subscript | mongoengine_flask_db_document_subclass_bad.py:19:30:19:42 | ControlFlowNode for unsafe_search |
-| mongoengine_flask_db_document_subclass_bad.py:19:30:19:42 | ControlFlowNode for unsafe_search | mongoengine_flask_db_document_subclass_bad.py:21:34:21:44 | ControlFlowNode for json_search |
-| mongoengine_flask_db_document_subclass_good.py:19:21:19:27 | ControlFlowNode for request | mongoengine_flask_db_document_subclass_good.py:19:21:19:32 | ControlFlowNode for Attribute |
-| mongoengine_flask_db_document_subclass_good.py:19:21:19:32 | ControlFlowNode for Attribute | mongoengine_flask_db_document_subclass_good.py:19:21:19:42 | ControlFlowNode for Subscript |
-| mongoengine_flask_db_document_subclass_good.py:19:21:19:42 | ControlFlowNode for Subscript | mongoengine_flask_db_document_subclass_good.py:20:30:20:42 | ControlFlowNode for unsafe_search |
+| mongoengine_document_subclass_bad.py:17:21:17:27 | ControlFlowNode for request | mongoengine_document_subclass_bad.py:17:21:17:32 | ControlFlowNode for Attribute |
+| mongoengine_document_subclass_bad.py:17:21:17:32 | ControlFlowNode for Attribute | mongoengine_document_subclass_bad.py:17:21:17:42 | ControlFlowNode for Subscript |
+| mongoengine_document_subclass_bad.py:17:21:17:42 | ControlFlowNode for Subscript | mongoengine_document_subclass_bad.py:18:30:18:42 | ControlFlowNode for unsafe_search |
+| mongoengine_document_subclass_bad.py:18:30:18:42 | ControlFlowNode for unsafe_search | mongoengine_document_subclass_bad.py:20:34:20:44 | ControlFlowNode for json_search |
+| mongoengine_document_subclass_good.py:18:21:18:27 | ControlFlowNode for request | mongoengine_document_subclass_good.py:18:21:18:32 | ControlFlowNode for Attribute |
+| mongoengine_document_subclass_good.py:18:21:18:32 | ControlFlowNode for Attribute | mongoengine_document_subclass_good.py:18:21:18:42 | ControlFlowNode for Subscript |
+| mongoengine_document_subclass_good.py:18:21:18:42 | ControlFlowNode for Subscript | mongoengine_document_subclass_good.py:19:30:19:42 | ControlFlowNode for unsafe_search |
| mongoengine_get_db_bad.py:17:21:17:27 | ControlFlowNode for request | mongoengine_get_db_bad.py:17:21:17:32 | ControlFlowNode for Attribute |
| mongoengine_get_db_bad.py:17:21:17:32 | ControlFlowNode for Attribute | mongoengine_get_db_bad.py:17:21:17:42 | ControlFlowNode for Subscript |
| mongoengine_get_db_bad.py:17:21:17:42 | ControlFlowNode for Subscript | mongoengine_get_db_bad.py:18:30:18:42 | ControlFlowNode for unsafe_search |
@@ -66,40 +62,37 @@ edges
| mongoengine_get_db_via_connection_good.py:19:21:19:27 | ControlFlowNode for request | mongoengine_get_db_via_connection_good.py:19:21:19:32 | ControlFlowNode for Attribute |
| mongoengine_get_db_via_connection_good.py:19:21:19:32 | ControlFlowNode for Attribute | mongoengine_get_db_via_connection_good.py:19:21:19:42 | ControlFlowNode for Subscript |
| mongoengine_get_db_via_connection_good.py:19:21:19:42 | ControlFlowNode for Subscript | mongoengine_get_db_via_connection_good.py:20:30:20:42 | ControlFlowNode for unsafe_search |
-| mongoengine_good.py:18:21:18:27 | ControlFlowNode for request | mongoengine_good.py:18:21:18:32 | ControlFlowNode for Attribute |
-| mongoengine_good.py:18:21:18:32 | ControlFlowNode for Attribute | mongoengine_good.py:18:21:18:42 | ControlFlowNode for Subscript |
-| mongoengine_good.py:18:21:18:42 | ControlFlowNode for Subscript | mongoengine_good.py:19:30:19:42 | ControlFlowNode for unsafe_search |
| pymongo_bad.py:11:21:11:27 | ControlFlowNode for request | pymongo_bad.py:11:21:11:32 | ControlFlowNode for Attribute |
| pymongo_bad.py:11:21:11:32 | ControlFlowNode for Attribute | pymongo_bad.py:11:21:11:42 | ControlFlowNode for Subscript |
| pymongo_bad.py:11:21:11:42 | ControlFlowNode for Subscript | pymongo_bad.py:12:30:12:42 | ControlFlowNode for unsafe_search |
-| pymongo_bad.py:12:30:12:42 | ControlFlowNode for unsafe_search | pymongo_bad.py:14:44:14:64 | ControlFlowNode for Dict |
+| pymongo_bad.py:12:30:12:42 | ControlFlowNode for unsafe_search | pymongo_bad.py:14:42:14:62 | ControlFlowNode for Dict |
| pymongo_good.py:12:21:12:27 | ControlFlowNode for request | pymongo_good.py:12:21:12:32 | ControlFlowNode for Attribute |
| pymongo_good.py:12:21:12:32 | ControlFlowNode for Attribute | pymongo_good.py:12:21:12:42 | ControlFlowNode for Subscript |
| pymongo_good.py:12:21:12:42 | ControlFlowNode for Subscript | pymongo_good.py:13:30:13:42 | ControlFlowNode for unsafe_search |
nodes
-| flask_mongoengine_bad.py:19:26:19:32 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
-| flask_mongoengine_bad.py:19:26:19:37 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
-| flask_mongoengine_bad.py:19:26:19:47 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
-| flask_mongoengine_bad.py:20:30:20:47 | ControlFlowNode for unsanitized_search | semmle.label | ControlFlowNode for unsanitized_search |
-| flask_mongoengine_bad.py:22:36:22:46 | ControlFlowNode for json_search | semmle.label | ControlFlowNode for json_search |
-| flask_mongoengine_get_db_bad.py:19:26:19:32 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
-| flask_mongoengine_get_db_bad.py:19:26:19:37 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
-| flask_mongoengine_get_db_bad.py:19:26:19:47 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
-| flask_mongoengine_get_db_bad.py:20:30:20:47 | ControlFlowNode for unsanitized_search | semmle.label | ControlFlowNode for unsanitized_search |
-| flask_mongoengine_get_db_bad.py:23:41:23:61 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict |
-| flask_mongoengine_get_db_good.py:20:26:20:32 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
-| flask_mongoengine_get_db_good.py:20:26:20:37 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
-| flask_mongoengine_get_db_good.py:20:26:20:47 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
-| flask_mongoengine_get_db_good.py:21:30:21:47 | ControlFlowNode for unsanitized_search | semmle.label | ControlFlowNode for unsanitized_search |
-| flask_mongoengine_good.py:20:21:20:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
-| flask_mongoengine_good.py:20:21:20:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
-| flask_mongoengine_good.py:20:21:20:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
-| flask_mongoengine_good.py:21:30:21:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search |
-| flask_pymongo_bad.py:11:26:11:32 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
-| flask_pymongo_bad.py:11:26:11:37 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
-| flask_pymongo_bad.py:11:26:11:47 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
-| flask_pymongo_bad.py:12:30:12:47 | ControlFlowNode for unsanitized_search | semmle.label | ControlFlowNode for unsanitized_search |
-| flask_pymongo_bad.py:14:33:14:53 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict |
+| flask_mongoengine_db_document_subclass_bad.py:18:21:18:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
+| flask_mongoengine_db_document_subclass_bad.py:18:21:18:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
+| flask_mongoengine_db_document_subclass_bad.py:18:21:18:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
+| flask_mongoengine_db_document_subclass_bad.py:19:30:19:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search |
+| flask_mongoengine_db_document_subclass_bad.py:21:34:21:44 | ControlFlowNode for json_search | semmle.label | ControlFlowNode for json_search |
+| flask_mongoengine_db_document_subclass_good.py:19:21:19:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
+| flask_mongoengine_db_document_subclass_good.py:19:21:19:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
+| flask_mongoengine_db_document_subclass_good.py:19:21:19:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
+| flask_mongoengine_db_document_subclass_good.py:20:30:20:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search |
+| flask_mongoengine_get_db_bad.py:19:21:19:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
+| flask_mongoengine_get_db_bad.py:19:21:19:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
+| flask_mongoengine_get_db_bad.py:19:21:19:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
+| flask_mongoengine_get_db_bad.py:20:30:20:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search |
+| flask_mongoengine_get_db_bad.py:23:39:23:59 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict |
+| flask_mongoengine_get_db_good.py:20:21:20:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
+| flask_mongoengine_get_db_good.py:20:21:20:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
+| flask_mongoengine_get_db_good.py:20:21:20:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
+| flask_mongoengine_get_db_good.py:21:30:21:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search |
+| flask_pymongo_bad.py:11:21:11:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
+| flask_pymongo_bad.py:11:21:11:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
+| flask_pymongo_bad.py:11:21:11:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
+| flask_pymongo_bad.py:12:30:12:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search |
+| flask_pymongo_bad.py:14:31:14:51 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict |
| flask_pymongo_good.py:12:21:12:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
| flask_pymongo_good.py:12:21:12:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
| flask_pymongo_good.py:12:21:12:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
@@ -108,21 +101,16 @@ nodes
| mongoclient_subscript_bad.py:17:21:17:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
| mongoclient_subscript_bad.py:17:21:17:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
| mongoclient_subscript_bad.py:18:30:18:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search |
-| mongoclient_subscript_bad.py:21:37:21:57 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict |
+| mongoclient_subscript_bad.py:21:29:21:49 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict |
| mongoclient_subscript_good.py:18:21:18:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
| mongoclient_subscript_good.py:18:21:18:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
| mongoclient_subscript_good.py:18:21:18:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
| mongoclient_subscript_good.py:19:30:19:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search |
-| mongoengine_bad.py:17:21:17:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
-| mongoengine_bad.py:17:21:17:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
-| mongoengine_bad.py:17:21:17:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
-| mongoengine_bad.py:18:30:18:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search |
-| mongoengine_bad.py:20:34:20:44 | ControlFlowNode for json_search | semmle.label | ControlFlowNode for json_search |
| mongoengine_connect_bad.py:17:21:17:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
| mongoengine_connect_bad.py:17:21:17:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
| mongoengine_connect_bad.py:17:21:17:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
| mongoengine_connect_bad.py:18:30:18:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search |
-| mongoengine_connect_bad.py:21:31:21:51 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict |
+| mongoengine_connect_bad.py:21:26:21:46 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict |
| mongoengine_connect_good.py:18:21:18:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
| mongoengine_connect_good.py:18:21:18:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
| mongoengine_connect_good.py:18:21:18:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
@@ -131,20 +119,20 @@ nodes
| mongoengine_connect_via_connection_bad.py:18:21:18:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
| mongoengine_connect_via_connection_bad.py:18:21:18:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
| mongoengine_connect_via_connection_bad.py:19:30:19:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search |
-| mongoengine_connect_via_connection_bad.py:22:31:22:51 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict |
+| mongoengine_connect_via_connection_bad.py:22:26:22:46 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict |
| mongoengine_connect_via_connection_good.py:19:21:19:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
| mongoengine_connect_via_connection_good.py:19:21:19:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
| mongoengine_connect_via_connection_good.py:19:21:19:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
| mongoengine_connect_via_connection_good.py:20:30:20:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search |
-| mongoengine_flask_db_document_subclass_bad.py:18:21:18:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
-| mongoengine_flask_db_document_subclass_bad.py:18:21:18:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
-| mongoengine_flask_db_document_subclass_bad.py:18:21:18:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
-| mongoengine_flask_db_document_subclass_bad.py:19:30:19:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search |
-| mongoengine_flask_db_document_subclass_bad.py:21:34:21:44 | ControlFlowNode for json_search | semmle.label | ControlFlowNode for json_search |
-| mongoengine_flask_db_document_subclass_good.py:19:21:19:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
-| mongoengine_flask_db_document_subclass_good.py:19:21:19:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
-| mongoengine_flask_db_document_subclass_good.py:19:21:19:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
-| mongoengine_flask_db_document_subclass_good.py:20:30:20:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search |
+| mongoengine_document_subclass_bad.py:17:21:17:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
+| mongoengine_document_subclass_bad.py:17:21:17:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
+| mongoengine_document_subclass_bad.py:17:21:17:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
+| mongoengine_document_subclass_bad.py:18:30:18:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search |
+| mongoengine_document_subclass_bad.py:20:34:20:44 | ControlFlowNode for json_search | semmle.label | ControlFlowNode for json_search |
+| mongoengine_document_subclass_good.py:18:21:18:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
+| mongoengine_document_subclass_good.py:18:21:18:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
+| mongoengine_document_subclass_good.py:18:21:18:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
+| mongoengine_document_subclass_good.py:19:30:19:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search |
| mongoengine_get_db_bad.py:17:21:17:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
| mongoengine_get_db_bad.py:17:21:17:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
| mongoengine_get_db_bad.py:17:21:17:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
@@ -163,28 +151,23 @@ nodes
| mongoengine_get_db_via_connection_good.py:19:21:19:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
| mongoengine_get_db_via_connection_good.py:19:21:19:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
| mongoengine_get_db_via_connection_good.py:20:30:20:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search |
-| mongoengine_good.py:18:21:18:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
-| mongoengine_good.py:18:21:18:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
-| mongoengine_good.py:18:21:18:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
-| mongoengine_good.py:19:30:19:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search |
| pymongo_bad.py:11:21:11:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
| pymongo_bad.py:11:21:11:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
| pymongo_bad.py:11:21:11:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
| pymongo_bad.py:12:30:12:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search |
-| pymongo_bad.py:14:44:14:64 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict |
+| pymongo_bad.py:14:42:14:62 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict |
| pymongo_good.py:12:21:12:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
| pymongo_good.py:12:21:12:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
| pymongo_good.py:12:21:12:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
| pymongo_good.py:13:30:13:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search |
#select
-| flask_mongoengine_bad.py:22:36:22:46 | ControlFlowNode for json_search | flask_mongoengine_bad.py:19:26:19:32 | ControlFlowNode for request | flask_mongoengine_bad.py:22:36:22:46 | ControlFlowNode for json_search | $@ NoSQL query contains an unsanitized $@ | flask_mongoengine_bad.py:22:36:22:46 | ControlFlowNode for json_search | This | flask_mongoengine_bad.py:19:26:19:32 | ControlFlowNode for request | user-provided value |
-| flask_mongoengine_get_db_bad.py:23:41:23:61 | ControlFlowNode for Dict | flask_mongoengine_get_db_bad.py:19:26:19:32 | ControlFlowNode for request | flask_mongoengine_get_db_bad.py:23:41:23:61 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | flask_mongoengine_get_db_bad.py:23:41:23:61 | ControlFlowNode for Dict | This | flask_mongoengine_get_db_bad.py:19:26:19:32 | ControlFlowNode for request | user-provided value |
-| flask_pymongo_bad.py:14:33:14:53 | ControlFlowNode for Dict | flask_pymongo_bad.py:11:26:11:32 | ControlFlowNode for request | flask_pymongo_bad.py:14:33:14:53 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | flask_pymongo_bad.py:14:33:14:53 | ControlFlowNode for Dict | This | flask_pymongo_bad.py:11:26:11:32 | ControlFlowNode for request | user-provided value |
-| mongoclient_subscript_bad.py:21:37:21:57 | ControlFlowNode for Dict | mongoclient_subscript_bad.py:17:21:17:27 | ControlFlowNode for request | mongoclient_subscript_bad.py:21:37:21:57 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | mongoclient_subscript_bad.py:21:37:21:57 | ControlFlowNode for Dict | This | mongoclient_subscript_bad.py:17:21:17:27 | ControlFlowNode for request | user-provided value |
-| mongoengine_bad.py:20:34:20:44 | ControlFlowNode for json_search | mongoengine_bad.py:17:21:17:27 | ControlFlowNode for request | mongoengine_bad.py:20:34:20:44 | ControlFlowNode for json_search | $@ NoSQL query contains an unsanitized $@ | mongoengine_bad.py:20:34:20:44 | ControlFlowNode for json_search | This | mongoengine_bad.py:17:21:17:27 | ControlFlowNode for request | user-provided value |
-| mongoengine_connect_bad.py:21:31:21:51 | ControlFlowNode for Dict | mongoengine_connect_bad.py:17:21:17:27 | ControlFlowNode for request | mongoengine_connect_bad.py:21:31:21:51 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | mongoengine_connect_bad.py:21:31:21:51 | ControlFlowNode for Dict | This | mongoengine_connect_bad.py:17:21:17:27 | ControlFlowNode for request | user-provided value |
-| mongoengine_connect_via_connection_bad.py:22:31:22:51 | ControlFlowNode for Dict | mongoengine_connect_via_connection_bad.py:18:21:18:27 | ControlFlowNode for request | mongoengine_connect_via_connection_bad.py:22:31:22:51 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | mongoengine_connect_via_connection_bad.py:22:31:22:51 | ControlFlowNode for Dict | This | mongoengine_connect_via_connection_bad.py:18:21:18:27 | ControlFlowNode for request | user-provided value |
-| mongoengine_flask_db_document_subclass_bad.py:21:34:21:44 | ControlFlowNode for json_search | mongoengine_flask_db_document_subclass_bad.py:18:21:18:27 | ControlFlowNode for request | mongoengine_flask_db_document_subclass_bad.py:21:34:21:44 | ControlFlowNode for json_search | $@ NoSQL query contains an unsanitized $@ | mongoengine_flask_db_document_subclass_bad.py:21:34:21:44 | ControlFlowNode for json_search | This | mongoengine_flask_db_document_subclass_bad.py:18:21:18:27 | ControlFlowNode for request | user-provided value |
+| flask_mongoengine_db_document_subclass_bad.py:21:34:21:44 | ControlFlowNode for json_search | flask_mongoengine_db_document_subclass_bad.py:18:21:18:27 | ControlFlowNode for request | flask_mongoengine_db_document_subclass_bad.py:21:34:21:44 | ControlFlowNode for json_search | $@ NoSQL query contains an unsanitized $@ | flask_mongoengine_db_document_subclass_bad.py:21:34:21:44 | ControlFlowNode for json_search | This | flask_mongoengine_db_document_subclass_bad.py:18:21:18:27 | ControlFlowNode for request | user-provided value |
+| flask_mongoengine_get_db_bad.py:23:39:23:59 | ControlFlowNode for Dict | flask_mongoengine_get_db_bad.py:19:21:19:27 | ControlFlowNode for request | flask_mongoengine_get_db_bad.py:23:39:23:59 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | flask_mongoengine_get_db_bad.py:23:39:23:59 | ControlFlowNode for Dict | This | flask_mongoengine_get_db_bad.py:19:21:19:27 | ControlFlowNode for request | user-provided value |
+| flask_pymongo_bad.py:14:31:14:51 | ControlFlowNode for Dict | flask_pymongo_bad.py:11:21:11:27 | ControlFlowNode for request | flask_pymongo_bad.py:14:31:14:51 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | flask_pymongo_bad.py:14:31:14:51 | ControlFlowNode for Dict | This | flask_pymongo_bad.py:11:21:11:27 | ControlFlowNode for request | user-provided value |
+| mongoclient_subscript_bad.py:21:29:21:49 | ControlFlowNode for Dict | mongoclient_subscript_bad.py:17:21:17:27 | ControlFlowNode for request | mongoclient_subscript_bad.py:21:29:21:49 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | mongoclient_subscript_bad.py:21:29:21:49 | ControlFlowNode for Dict | This | mongoclient_subscript_bad.py:17:21:17:27 | ControlFlowNode for request | user-provided value |
+| mongoengine_connect_bad.py:21:26:21:46 | ControlFlowNode for Dict | mongoengine_connect_bad.py:17:21:17:27 | ControlFlowNode for request | mongoengine_connect_bad.py:21:26:21:46 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | mongoengine_connect_bad.py:21:26:21:46 | ControlFlowNode for Dict | This | mongoengine_connect_bad.py:17:21:17:27 | ControlFlowNode for request | user-provided value |
+| mongoengine_connect_via_connection_bad.py:22:26:22:46 | ControlFlowNode for Dict | mongoengine_connect_via_connection_bad.py:18:21:18:27 | ControlFlowNode for request | mongoengine_connect_via_connection_bad.py:22:26:22:46 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | mongoengine_connect_via_connection_bad.py:22:26:22:46 | ControlFlowNode for Dict | This | mongoengine_connect_via_connection_bad.py:18:21:18:27 | ControlFlowNode for request | user-provided value |
+| mongoengine_document_subclass_bad.py:20:34:20:44 | ControlFlowNode for json_search | mongoengine_document_subclass_bad.py:17:21:17:27 | ControlFlowNode for request | mongoengine_document_subclass_bad.py:20:34:20:44 | ControlFlowNode for json_search | $@ NoSQL query contains an unsanitized $@ | mongoengine_document_subclass_bad.py:20:34:20:44 | ControlFlowNode for json_search | This | mongoengine_document_subclass_bad.py:17:21:17:27 | ControlFlowNode for request | user-provided value |
| mongoengine_get_db_bad.py:21:26:21:46 | ControlFlowNode for Dict | mongoengine_get_db_bad.py:17:21:17:27 | ControlFlowNode for request | mongoengine_get_db_bad.py:21:26:21:46 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | mongoengine_get_db_bad.py:21:26:21:46 | ControlFlowNode for Dict | This | mongoengine_get_db_bad.py:17:21:17:27 | ControlFlowNode for request | user-provided value |
| mongoengine_get_db_via_connection_bad.py:22:26:22:46 | ControlFlowNode for Dict | mongoengine_get_db_via_connection_bad.py:18:21:18:27 | ControlFlowNode for request | mongoengine_get_db_via_connection_bad.py:22:26:22:46 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | mongoengine_get_db_via_connection_bad.py:22:26:22:46 | ControlFlowNode for Dict | This | mongoengine_get_db_via_connection_bad.py:18:21:18:27 | ControlFlowNode for request | user-provided value |
-| pymongo_bad.py:14:44:14:64 | ControlFlowNode for Dict | pymongo_bad.py:11:21:11:27 | ControlFlowNode for request | pymongo_bad.py:14:44:14:64 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | pymongo_bad.py:14:44:14:64 | ControlFlowNode for Dict | This | pymongo_bad.py:11:21:11:27 | ControlFlowNode for request | user-provided value |
+| pymongo_bad.py:14:42:14:62 | ControlFlowNode for Dict | pymongo_bad.py:11:21:11:27 | ControlFlowNode for request | pymongo_bad.py:14:42:14:62 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | pymongo_bad.py:14:42:14:62 | ControlFlowNode for Dict | This | pymongo_bad.py:11:21:11:27 | ControlFlowNode for request | user-provided value |
From b8e619a60c1cb0d801797a40ebdc2b15a27667a0 Mon Sep 17 00:00:00 2001
From: jorgectf
Date: Thu, 17 Jun 2021 15:42:45 +0200
Subject: [PATCH 087/429] Extend qhelp references
---
.../ql/src/experimental/Security/CWE-943/NoSQLInjection.qhelp | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/python/ql/src/experimental/Security/CWE-943/NoSQLInjection.qhelp b/python/ql/src/experimental/Security/CWE-943/NoSQLInjection.qhelp
index 339fc5d9d14..9771f8fd0d9 100644
--- a/python/ql/src/experimental/Security/CWE-943/NoSQLInjection.qhelp
+++ b/python/ql/src/experimental/Security/CWE-943/NoSQLInjection.qhelp
@@ -30,6 +30,10 @@
+ Mongoengine: Documentation.
+ Flask-Mongoengine: Documentation.
+ PyMongo: Documentation.
+ Flask-PyMongo: Documentation.
OWASP: NoSQL Injection.
Security Stack Exchange Discussion: Question 83231.
From 8e3d5ff3f9375f9f3a16cc039f85965e6279bae0 Mon Sep 17 00:00:00 2001
From: jorgectf
Date: Thu, 17 Jun 2021 15:43:01 +0200
Subject: [PATCH 088/429] Rename mongoclient tests
---
...{mongoclient_subscript_bad.py => mongoengine_subscript_bad.py} | 0
...ongoclient_subscript_good.py => mongoengine_subscript_good.py} | 0
2 files changed, 0 insertions(+), 0 deletions(-)
rename python/ql/test/experimental/query-tests/Security/CWE-943/{mongoclient_subscript_bad.py => mongoengine_subscript_bad.py} (100%)
rename python/ql/test/experimental/query-tests/Security/CWE-943/{mongoclient_subscript_good.py => mongoengine_subscript_good.py} (100%)
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoclient_subscript_bad.py b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_subscript_bad.py
similarity index 100%
rename from python/ql/test/experimental/query-tests/Security/CWE-943/mongoclient_subscript_bad.py
rename to python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_subscript_bad.py
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoclient_subscript_good.py b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_subscript_good.py
similarity index 100%
rename from python/ql/test/experimental/query-tests/Security/CWE-943/mongoclient_subscript_good.py
rename to python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_subscript_good.py
From 7e6032f5b4dd9c4b5d0a2a29aa892e74c58274e9 Mon Sep 17 00:00:00 2001
From: jorgectf
Date: Thu, 17 Jun 2021 15:43:54 +0200
Subject: [PATCH 089/429] Port to Decoding
---
.../semmle/python/frameworks/Stdlib.qll | 45 ++++++++++++++++++
.../security/injection/NoSQLInjection.qll | 47 +++++++------------
2 files changed, 62 insertions(+), 30 deletions(-)
diff --git a/python/ql/src/experimental/semmle/python/frameworks/Stdlib.qll b/python/ql/src/experimental/semmle/python/frameworks/Stdlib.qll
index 4f3457e0a99..7db995220d4 100644
--- a/python/ql/src/experimental/semmle/python/frameworks/Stdlib.qll
+++ b/python/ql/src/experimental/semmle/python/frameworks/Stdlib.qll
@@ -8,6 +8,7 @@ private import semmle.python.dataflow.new.DataFlow
private import semmle.python.dataflow.new.TaintTracking
private import semmle.python.dataflow.new.RemoteFlowSources
private import experimental.semmle.python.Concepts
+private import semmle.python.Concepts
private import semmle.python.ApiGraphs
/**
@@ -98,3 +99,47 @@ private module Re {
override DataFlow::Node getRegexNode() { result = regexNode }
}
}
+
+// ---------------------------------------------------------------------------
+// xmltodict
+// ---------------------------------------------------------------------------
+/** Gets a reference to the `xmltodict` module. */
+API::Node xmltodict() { result = API::moduleImport("xmltodict") }
+
+/**
+ * A call to `xmltodict.parse`
+ * See https://github.com/martinblech/xmltodict/blob/ae19c452ca000bf243bfc16274c060bf3bf7cf51/xmltodict.py#L198
+ */
+private class XmlToDictParseCall extends Decoding::Range, DataFlow::CallCfgNode {
+ XmlToDictParseCall() { this = xmltodict().getMember("parse").getACall() }
+
+ override predicate mayExecuteInput() { none() }
+
+ override DataFlow::Node getAnInput() { result = this.getArg(0) }
+
+ override DataFlow::Node getOutput() { result = this }
+
+ override string getFormat() { result = "JSON" }
+}
+
+// ---------------------------------------------------------------------------
+// ujson
+// ---------------------------------------------------------------------------
+/** Gets a reference to the `ujson` module. */
+API::Node ujson() { result = API::moduleImport("ujson") }
+
+/**
+ * A call to `ujson.loads`
+ * See https://pypi.org/project/ujson/#usage
+ */
+private class UltraJsonLoadsCall extends Decoding::Range, DataFlow::CallCfgNode {
+ UltraJsonLoadsCall() { this = ujson().getMember("loads").getACall() }
+
+ override predicate mayExecuteInput() { none() }
+
+ override DataFlow::Node getAnInput() { result = this.getArg(0) }
+
+ override DataFlow::Node getOutput() { result = this }
+
+ override string getFormat() { result = "JSON" }
+}
diff --git a/python/ql/src/experimental/semmle/python/security/injection/NoSQLInjection.qll b/python/ql/src/experimental/semmle/python/security/injection/NoSQLInjection.qll
index 8217f370af7..b15a844605c 100644
--- a/python/ql/src/experimental/semmle/python/security/injection/NoSQLInjection.qll
+++ b/python/ql/src/experimental/semmle/python/security/injection/NoSQLInjection.qll
@@ -3,53 +3,37 @@ import semmle.python.dataflow.new.DataFlow
import semmle.python.dataflow.new.DataFlow2
import semmle.python.dataflow.new.TaintTracking
import semmle.python.dataflow.new.TaintTracking2
-import experimental.semmle.python.Concepts
import semmle.python.dataflow.new.RemoteFlowSources
-import semmle.python.ApiGraphs
import semmle.python.security.dataflow.ChainedConfigs12
+import experimental.semmle.python.Concepts
+import semmle.python.Concepts
-class JsonLoadsCall extends DataFlow::CallCfgNode {
- JsonLoadsCall() { this = API::moduleImport("json").getMember("loads").getACall() }
-
- DataFlow::Node getLoadNode() { result = this.getArg(0) }
-}
-
-class XmlToDictParseCall extends DataFlow::CallCfgNode {
- XmlToDictParseCall() { this = API::moduleImport("xmltodict").getMember("parse").getACall() }
-
- DataFlow::Node getParseNode() { result = this.getArg(0) }
-}
-
-class UltraJsonLoadsCall extends DataFlow::CallCfgNode {
- UltraJsonLoadsCall() { this = API::moduleImport("ujson").getMember("loads").getACall() }
-
- DataFlow::Node getLoadNode() { result = this.getArg(0) }
-}
-
-class DataToDictSink extends DataFlow::Node {
- DataToDictSink() {
- this = any(JsonLoadsCall jsonLoads).getLoadNode() or
- this = any(XmlToDictParseCall jsonLoads).getParseNode() or
- this = any(UltraJsonLoadsCall jsonLoads).getLoadNode()
- }
-}
-
+/**
+ * A taint-tracking configuration for detecting string-to-dict conversions.
+ */
class RFSToDictConfig extends TaintTracking::Configuration {
RFSToDictConfig() { this = "RFSToDictConfig" }
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
- override predicate isSink(DataFlow::Node sink) { sink instanceof DataToDictSink }
+ override predicate isSink(DataFlow::Node sink) {
+ exists(Decoding decoding | decoding.getFormat() = "JSON" and sink = decoding)
+ }
override predicate isSanitizer(DataFlow::Node sanitizer) {
sanitizer = any(NoSQLSanitizer noSQLSanitizer).getAnInput()
}
}
+/**
+ * A taint-tracking configuration for detecting NoSQL injections (previously converted to a dict).
+ */
class FromDataDictToSink extends TaintTracking2::Configuration {
FromDataDictToSink() { this = "FromDataDictToSink" }
- override predicate isSource(DataFlow::Node source) { source instanceof DataToDictSink }
+ override predicate isSource(DataFlow::Node source) {
+ exists(Decoding decoding | decoding.getFormat() = "JSON" and source = decoding)
+ }
override predicate isSink(DataFlow::Node sink) { sink = any(NoSQLQuery noSQLQuery).getQuery() }
@@ -58,6 +42,9 @@ class FromDataDictToSink extends TaintTracking2::Configuration {
}
}
+/**
+ * A predicate checking string-to-dict conversion and its arrival to a NoSQL injection sink.
+ */
predicate noSQLInjectionFlow(CustomPathNode source, CustomPathNode sink) {
exists(
RFSToDictConfig config, DataFlow::PathNode mid1, DataFlow2::PathNode mid2,
From 4e74003cd5d70832477141e5696f16c1c30ae977 Mon Sep 17 00:00:00 2001
From: jorgectf
Date: Thu, 17 Jun 2021 15:44:51 +0200
Subject: [PATCH 090/429] Polish Concepts documentation
---
.../experimental/semmle/python/Concepts.qll | 30 +++++++++++++++++++
1 file changed, 30 insertions(+)
diff --git a/python/ql/src/experimental/semmle/python/Concepts.qll b/python/ql/src/experimental/semmle/python/Concepts.qll
index 2134b32e60a..891a6820801 100644
--- a/python/ql/src/experimental/semmle/python/Concepts.qll
+++ b/python/ql/src/experimental/semmle/python/Concepts.qll
@@ -147,30 +147,60 @@ class LDAPEscape extends DataFlow::Node {
DataFlow::Node getAnInput() { result = range.getAnInput() }
}
+/** Provides a class for modeling NoSQL execution APIs. */
module NoSQLQuery {
+ /**
+ * A data-flow node that executes NoSQL queries.
+ *
+ * Extend this class to model new APIs. If you want to refine existing API models,
+ * extend `NoSQLQuery` instead.
+ */
abstract class Range extends DataFlow::Node {
+ /** Gets the argument that specifies the NoSQL query to be executed. */
abstract DataFlow::Node getQuery();
}
}
+/**
+ * A data-flow node that executes NoSQL queries.
+ *
+ * Extend this class to refine existing API models. If you want to model new APIs,
+ * extend `NoSQLQuery::Range` instead.
+ */
class NoSQLQuery extends DataFlow::Node {
NoSQLQuery::Range range;
NoSQLQuery() { this = range }
+ /** Gets the argument that specifies the NoSQL query to be executed. */
DataFlow::Node getQuery() { result = range.getQuery() }
}
+/** Provides classes for modeling NoSQL sanitization-related APIs. */
module NoSQLSanitizer {
+ /**
+ * A data-flow node that collects functions sanitizing NoSQL queries.
+ *
+ * Extend this class to model new APIs. If you want to refine existing API models,
+ * extend `NoSQLSanitizer` instead.
+ */
abstract class Range extends DataFlow::Node {
+ /** Gets the argument that specifies the NoSQL query to be sanitized. */
abstract DataFlow::Node getAnInput();
}
}
+/**
+ * A data-flow node that collects functions sanitizing NoSQL queries.
+ *
+ * Extend this class to model new APIs. If you want to refine existing API models,
+ * extend `NoSQLSanitizer::Range` instead.
+ */
class NoSQLSanitizer extends DataFlow::Node {
NoSQLSanitizer::Range range;
NoSQLSanitizer() { this = range }
+ /** Gets the argument that specifies the NoSQL query to be sanitized. */
DataFlow::Node getAnInput() { result = range.getAnInput() }
}
From eb16018446340ff1b8d6fae7e72af345f93d31dc Mon Sep 17 00:00:00 2001
From: jorgectf
Date: Thu, 17 Jun 2021 15:45:05 +0200
Subject: [PATCH 091/429] Update .expected
---
.../Security/CWE-943/NoSQLInjection.expected | 124 +++++++++---------
1 file changed, 62 insertions(+), 62 deletions(-)
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/NoSQLInjection.expected b/python/ql/test/experimental/query-tests/Security/CWE-943/NoSQLInjection.expected
index da28a2d0d15..ad4a19510f1 100644
--- a/python/ql/test/experimental/query-tests/Security/CWE-943/NoSQLInjection.expected
+++ b/python/ql/test/experimental/query-tests/Security/CWE-943/NoSQLInjection.expected
@@ -1,173 +1,173 @@
edges
| flask_mongoengine_db_document_subclass_bad.py:18:21:18:27 | ControlFlowNode for request | flask_mongoengine_db_document_subclass_bad.py:18:21:18:32 | ControlFlowNode for Attribute |
| flask_mongoengine_db_document_subclass_bad.py:18:21:18:32 | ControlFlowNode for Attribute | flask_mongoengine_db_document_subclass_bad.py:18:21:18:42 | ControlFlowNode for Subscript |
-| flask_mongoengine_db_document_subclass_bad.py:18:21:18:42 | ControlFlowNode for Subscript | flask_mongoengine_db_document_subclass_bad.py:19:30:19:42 | ControlFlowNode for unsafe_search |
-| flask_mongoengine_db_document_subclass_bad.py:19:30:19:42 | ControlFlowNode for unsafe_search | flask_mongoengine_db_document_subclass_bad.py:21:34:21:44 | ControlFlowNode for json_search |
+| flask_mongoengine_db_document_subclass_bad.py:18:21:18:42 | ControlFlowNode for Subscript | flask_mongoengine_db_document_subclass_bad.py:19:19:19:43 | ControlFlowNode for Attribute() |
+| flask_mongoengine_db_document_subclass_bad.py:19:19:19:43 | ControlFlowNode for Attribute() | flask_mongoengine_db_document_subclass_bad.py:21:34:21:44 | ControlFlowNode for json_search |
| flask_mongoengine_db_document_subclass_good.py:19:21:19:27 | ControlFlowNode for request | flask_mongoengine_db_document_subclass_good.py:19:21:19:32 | ControlFlowNode for Attribute |
| flask_mongoengine_db_document_subclass_good.py:19:21:19:32 | ControlFlowNode for Attribute | flask_mongoengine_db_document_subclass_good.py:19:21:19:42 | ControlFlowNode for Subscript |
-| flask_mongoengine_db_document_subclass_good.py:19:21:19:42 | ControlFlowNode for Subscript | flask_mongoengine_db_document_subclass_good.py:20:30:20:42 | ControlFlowNode for unsafe_search |
+| flask_mongoengine_db_document_subclass_good.py:19:21:19:42 | ControlFlowNode for Subscript | flask_mongoengine_db_document_subclass_good.py:20:19:20:43 | ControlFlowNode for Attribute() |
| flask_mongoengine_get_db_bad.py:19:21:19:27 | ControlFlowNode for request | flask_mongoengine_get_db_bad.py:19:21:19:32 | ControlFlowNode for Attribute |
| flask_mongoengine_get_db_bad.py:19:21:19:32 | ControlFlowNode for Attribute | flask_mongoengine_get_db_bad.py:19:21:19:42 | ControlFlowNode for Subscript |
-| flask_mongoengine_get_db_bad.py:19:21:19:42 | ControlFlowNode for Subscript | flask_mongoengine_get_db_bad.py:20:30:20:42 | ControlFlowNode for unsafe_search |
-| flask_mongoengine_get_db_bad.py:20:30:20:42 | ControlFlowNode for unsafe_search | flask_mongoengine_get_db_bad.py:23:39:23:59 | ControlFlowNode for Dict |
+| flask_mongoengine_get_db_bad.py:19:21:19:42 | ControlFlowNode for Subscript | flask_mongoengine_get_db_bad.py:20:19:20:43 | ControlFlowNode for Attribute() |
+| flask_mongoengine_get_db_bad.py:20:19:20:43 | ControlFlowNode for Attribute() | flask_mongoengine_get_db_bad.py:23:39:23:59 | ControlFlowNode for Dict |
| flask_mongoengine_get_db_good.py:20:21:20:27 | ControlFlowNode for request | flask_mongoengine_get_db_good.py:20:21:20:32 | ControlFlowNode for Attribute |
| flask_mongoengine_get_db_good.py:20:21:20:32 | ControlFlowNode for Attribute | flask_mongoengine_get_db_good.py:20:21:20:42 | ControlFlowNode for Subscript |
-| flask_mongoengine_get_db_good.py:20:21:20:42 | ControlFlowNode for Subscript | flask_mongoengine_get_db_good.py:21:30:21:42 | ControlFlowNode for unsafe_search |
+| flask_mongoengine_get_db_good.py:20:21:20:42 | ControlFlowNode for Subscript | flask_mongoengine_get_db_good.py:21:19:21:43 | ControlFlowNode for Attribute() |
| flask_pymongo_bad.py:11:21:11:27 | ControlFlowNode for request | flask_pymongo_bad.py:11:21:11:32 | ControlFlowNode for Attribute |
| flask_pymongo_bad.py:11:21:11:32 | ControlFlowNode for Attribute | flask_pymongo_bad.py:11:21:11:42 | ControlFlowNode for Subscript |
-| flask_pymongo_bad.py:11:21:11:42 | ControlFlowNode for Subscript | flask_pymongo_bad.py:12:30:12:42 | ControlFlowNode for unsafe_search |
-| flask_pymongo_bad.py:12:30:12:42 | ControlFlowNode for unsafe_search | flask_pymongo_bad.py:14:31:14:51 | ControlFlowNode for Dict |
+| flask_pymongo_bad.py:11:21:11:42 | ControlFlowNode for Subscript | flask_pymongo_bad.py:12:19:12:43 | ControlFlowNode for Attribute() |
+| flask_pymongo_bad.py:12:19:12:43 | ControlFlowNode for Attribute() | flask_pymongo_bad.py:14:31:14:51 | ControlFlowNode for Dict |
| flask_pymongo_good.py:12:21:12:27 | ControlFlowNode for request | flask_pymongo_good.py:12:21:12:32 | ControlFlowNode for Attribute |
| flask_pymongo_good.py:12:21:12:32 | ControlFlowNode for Attribute | flask_pymongo_good.py:12:21:12:42 | ControlFlowNode for Subscript |
-| flask_pymongo_good.py:12:21:12:42 | ControlFlowNode for Subscript | flask_pymongo_good.py:13:30:13:42 | ControlFlowNode for unsafe_search |
-| mongoclient_subscript_bad.py:17:21:17:27 | ControlFlowNode for request | mongoclient_subscript_bad.py:17:21:17:32 | ControlFlowNode for Attribute |
-| mongoclient_subscript_bad.py:17:21:17:32 | ControlFlowNode for Attribute | mongoclient_subscript_bad.py:17:21:17:42 | ControlFlowNode for Subscript |
-| mongoclient_subscript_bad.py:17:21:17:42 | ControlFlowNode for Subscript | mongoclient_subscript_bad.py:18:30:18:42 | ControlFlowNode for unsafe_search |
-| mongoclient_subscript_bad.py:18:30:18:42 | ControlFlowNode for unsafe_search | mongoclient_subscript_bad.py:21:29:21:49 | ControlFlowNode for Dict |
-| mongoclient_subscript_good.py:18:21:18:27 | ControlFlowNode for request | mongoclient_subscript_good.py:18:21:18:32 | ControlFlowNode for Attribute |
-| mongoclient_subscript_good.py:18:21:18:32 | ControlFlowNode for Attribute | mongoclient_subscript_good.py:18:21:18:42 | ControlFlowNode for Subscript |
-| mongoclient_subscript_good.py:18:21:18:42 | ControlFlowNode for Subscript | mongoclient_subscript_good.py:19:30:19:42 | ControlFlowNode for unsafe_search |
+| flask_pymongo_good.py:12:21:12:42 | ControlFlowNode for Subscript | flask_pymongo_good.py:13:19:13:43 | ControlFlowNode for Attribute() |
| mongoengine_connect_bad.py:17:21:17:27 | ControlFlowNode for request | mongoengine_connect_bad.py:17:21:17:32 | ControlFlowNode for Attribute |
| mongoengine_connect_bad.py:17:21:17:32 | ControlFlowNode for Attribute | mongoengine_connect_bad.py:17:21:17:42 | ControlFlowNode for Subscript |
-| mongoengine_connect_bad.py:17:21:17:42 | ControlFlowNode for Subscript | mongoengine_connect_bad.py:18:30:18:42 | ControlFlowNode for unsafe_search |
-| mongoengine_connect_bad.py:18:30:18:42 | ControlFlowNode for unsafe_search | mongoengine_connect_bad.py:21:26:21:46 | ControlFlowNode for Dict |
+| mongoengine_connect_bad.py:17:21:17:42 | ControlFlowNode for Subscript | mongoengine_connect_bad.py:18:19:18:43 | ControlFlowNode for Attribute() |
+| mongoengine_connect_bad.py:18:19:18:43 | ControlFlowNode for Attribute() | mongoengine_connect_bad.py:21:26:21:46 | ControlFlowNode for Dict |
| mongoengine_connect_good.py:18:21:18:27 | ControlFlowNode for request | mongoengine_connect_good.py:18:21:18:32 | ControlFlowNode for Attribute |
| mongoengine_connect_good.py:18:21:18:32 | ControlFlowNode for Attribute | mongoengine_connect_good.py:18:21:18:42 | ControlFlowNode for Subscript |
-| mongoengine_connect_good.py:18:21:18:42 | ControlFlowNode for Subscript | mongoengine_connect_good.py:19:30:19:42 | ControlFlowNode for unsafe_search |
+| mongoengine_connect_good.py:18:21:18:42 | ControlFlowNode for Subscript | mongoengine_connect_good.py:19:19:19:43 | ControlFlowNode for Attribute() |
| mongoengine_connect_via_connection_bad.py:18:21:18:27 | ControlFlowNode for request | mongoengine_connect_via_connection_bad.py:18:21:18:32 | ControlFlowNode for Attribute |
| mongoengine_connect_via_connection_bad.py:18:21:18:32 | ControlFlowNode for Attribute | mongoengine_connect_via_connection_bad.py:18:21:18:42 | ControlFlowNode for Subscript |
-| mongoengine_connect_via_connection_bad.py:18:21:18:42 | ControlFlowNode for Subscript | mongoengine_connect_via_connection_bad.py:19:30:19:42 | ControlFlowNode for unsafe_search |
-| mongoengine_connect_via_connection_bad.py:19:30:19:42 | ControlFlowNode for unsafe_search | mongoengine_connect_via_connection_bad.py:22:26:22:46 | ControlFlowNode for Dict |
+| mongoengine_connect_via_connection_bad.py:18:21:18:42 | ControlFlowNode for Subscript | mongoengine_connect_via_connection_bad.py:19:19:19:43 | ControlFlowNode for Attribute() |
+| mongoengine_connect_via_connection_bad.py:19:19:19:43 | ControlFlowNode for Attribute() | mongoengine_connect_via_connection_bad.py:22:26:22:46 | ControlFlowNode for Dict |
| mongoengine_connect_via_connection_good.py:19:21:19:27 | ControlFlowNode for request | mongoengine_connect_via_connection_good.py:19:21:19:32 | ControlFlowNode for Attribute |
| mongoengine_connect_via_connection_good.py:19:21:19:32 | ControlFlowNode for Attribute | mongoengine_connect_via_connection_good.py:19:21:19:42 | ControlFlowNode for Subscript |
-| mongoengine_connect_via_connection_good.py:19:21:19:42 | ControlFlowNode for Subscript | mongoengine_connect_via_connection_good.py:20:30:20:42 | ControlFlowNode for unsafe_search |
+| mongoengine_connect_via_connection_good.py:19:21:19:42 | ControlFlowNode for Subscript | mongoengine_connect_via_connection_good.py:20:19:20:43 | ControlFlowNode for Attribute() |
| mongoengine_document_subclass_bad.py:17:21:17:27 | ControlFlowNode for request | mongoengine_document_subclass_bad.py:17:21:17:32 | ControlFlowNode for Attribute |
| mongoengine_document_subclass_bad.py:17:21:17:32 | ControlFlowNode for Attribute | mongoengine_document_subclass_bad.py:17:21:17:42 | ControlFlowNode for Subscript |
-| mongoengine_document_subclass_bad.py:17:21:17:42 | ControlFlowNode for Subscript | mongoengine_document_subclass_bad.py:18:30:18:42 | ControlFlowNode for unsafe_search |
-| mongoengine_document_subclass_bad.py:18:30:18:42 | ControlFlowNode for unsafe_search | mongoengine_document_subclass_bad.py:20:34:20:44 | ControlFlowNode for json_search |
+| mongoengine_document_subclass_bad.py:17:21:17:42 | ControlFlowNode for Subscript | mongoengine_document_subclass_bad.py:18:19:18:43 | ControlFlowNode for Attribute() |
+| mongoengine_document_subclass_bad.py:18:19:18:43 | ControlFlowNode for Attribute() | mongoengine_document_subclass_bad.py:20:34:20:44 | ControlFlowNode for json_search |
| mongoengine_document_subclass_good.py:18:21:18:27 | ControlFlowNode for request | mongoengine_document_subclass_good.py:18:21:18:32 | ControlFlowNode for Attribute |
| mongoengine_document_subclass_good.py:18:21:18:32 | ControlFlowNode for Attribute | mongoengine_document_subclass_good.py:18:21:18:42 | ControlFlowNode for Subscript |
-| mongoengine_document_subclass_good.py:18:21:18:42 | ControlFlowNode for Subscript | mongoengine_document_subclass_good.py:19:30:19:42 | ControlFlowNode for unsafe_search |
+| mongoengine_document_subclass_good.py:18:21:18:42 | ControlFlowNode for Subscript | mongoengine_document_subclass_good.py:19:19:19:43 | ControlFlowNode for Attribute() |
| mongoengine_get_db_bad.py:17:21:17:27 | ControlFlowNode for request | mongoengine_get_db_bad.py:17:21:17:32 | ControlFlowNode for Attribute |
| mongoengine_get_db_bad.py:17:21:17:32 | ControlFlowNode for Attribute | mongoengine_get_db_bad.py:17:21:17:42 | ControlFlowNode for Subscript |
-| mongoengine_get_db_bad.py:17:21:17:42 | ControlFlowNode for Subscript | mongoengine_get_db_bad.py:18:30:18:42 | ControlFlowNode for unsafe_search |
-| mongoengine_get_db_bad.py:18:30:18:42 | ControlFlowNode for unsafe_search | mongoengine_get_db_bad.py:21:26:21:46 | ControlFlowNode for Dict |
+| mongoengine_get_db_bad.py:17:21:17:42 | ControlFlowNode for Subscript | mongoengine_get_db_bad.py:18:19:18:43 | ControlFlowNode for Attribute() |
+| mongoengine_get_db_bad.py:18:19:18:43 | ControlFlowNode for Attribute() | mongoengine_get_db_bad.py:21:26:21:46 | ControlFlowNode for Dict |
| mongoengine_get_db_good.py:18:21:18:27 | ControlFlowNode for request | mongoengine_get_db_good.py:18:21:18:32 | ControlFlowNode for Attribute |
| mongoengine_get_db_good.py:18:21:18:32 | ControlFlowNode for Attribute | mongoengine_get_db_good.py:18:21:18:42 | ControlFlowNode for Subscript |
-| mongoengine_get_db_good.py:18:21:18:42 | ControlFlowNode for Subscript | mongoengine_get_db_good.py:19:30:19:42 | ControlFlowNode for unsafe_search |
+| mongoengine_get_db_good.py:18:21:18:42 | ControlFlowNode for Subscript | mongoengine_get_db_good.py:19:19:19:43 | ControlFlowNode for Attribute() |
| mongoengine_get_db_via_connection_bad.py:18:21:18:27 | ControlFlowNode for request | mongoengine_get_db_via_connection_bad.py:18:21:18:32 | ControlFlowNode for Attribute |
| mongoengine_get_db_via_connection_bad.py:18:21:18:32 | ControlFlowNode for Attribute | mongoengine_get_db_via_connection_bad.py:18:21:18:42 | ControlFlowNode for Subscript |
-| mongoengine_get_db_via_connection_bad.py:18:21:18:42 | ControlFlowNode for Subscript | mongoengine_get_db_via_connection_bad.py:19:30:19:42 | ControlFlowNode for unsafe_search |
-| mongoengine_get_db_via_connection_bad.py:19:30:19:42 | ControlFlowNode for unsafe_search | mongoengine_get_db_via_connection_bad.py:22:26:22:46 | ControlFlowNode for Dict |
+| mongoengine_get_db_via_connection_bad.py:18:21:18:42 | ControlFlowNode for Subscript | mongoengine_get_db_via_connection_bad.py:19:19:19:43 | ControlFlowNode for Attribute() |
+| mongoengine_get_db_via_connection_bad.py:19:19:19:43 | ControlFlowNode for Attribute() | mongoengine_get_db_via_connection_bad.py:22:26:22:46 | ControlFlowNode for Dict |
| mongoengine_get_db_via_connection_good.py:19:21:19:27 | ControlFlowNode for request | mongoengine_get_db_via_connection_good.py:19:21:19:32 | ControlFlowNode for Attribute |
| mongoengine_get_db_via_connection_good.py:19:21:19:32 | ControlFlowNode for Attribute | mongoengine_get_db_via_connection_good.py:19:21:19:42 | ControlFlowNode for Subscript |
-| mongoengine_get_db_via_connection_good.py:19:21:19:42 | ControlFlowNode for Subscript | mongoengine_get_db_via_connection_good.py:20:30:20:42 | ControlFlowNode for unsafe_search |
+| mongoengine_get_db_via_connection_good.py:19:21:19:42 | ControlFlowNode for Subscript | mongoengine_get_db_via_connection_good.py:20:19:20:43 | ControlFlowNode for Attribute() |
+| mongoengine_subscript_bad.py:17:21:17:27 | ControlFlowNode for request | mongoengine_subscript_bad.py:17:21:17:32 | ControlFlowNode for Attribute |
+| mongoengine_subscript_bad.py:17:21:17:32 | ControlFlowNode for Attribute | mongoengine_subscript_bad.py:17:21:17:42 | ControlFlowNode for Subscript |
+| mongoengine_subscript_bad.py:17:21:17:42 | ControlFlowNode for Subscript | mongoengine_subscript_bad.py:18:19:18:43 | ControlFlowNode for Attribute() |
+| mongoengine_subscript_bad.py:18:19:18:43 | ControlFlowNode for Attribute() | mongoengine_subscript_bad.py:21:29:21:49 | ControlFlowNode for Dict |
+| mongoengine_subscript_good.py:18:21:18:27 | ControlFlowNode for request | mongoengine_subscript_good.py:18:21:18:32 | ControlFlowNode for Attribute |
+| mongoengine_subscript_good.py:18:21:18:32 | ControlFlowNode for Attribute | mongoengine_subscript_good.py:18:21:18:42 | ControlFlowNode for Subscript |
+| mongoengine_subscript_good.py:18:21:18:42 | ControlFlowNode for Subscript | mongoengine_subscript_good.py:19:19:19:43 | ControlFlowNode for Attribute() |
| pymongo_bad.py:11:21:11:27 | ControlFlowNode for request | pymongo_bad.py:11:21:11:32 | ControlFlowNode for Attribute |
| pymongo_bad.py:11:21:11:32 | ControlFlowNode for Attribute | pymongo_bad.py:11:21:11:42 | ControlFlowNode for Subscript |
-| pymongo_bad.py:11:21:11:42 | ControlFlowNode for Subscript | pymongo_bad.py:12:30:12:42 | ControlFlowNode for unsafe_search |
-| pymongo_bad.py:12:30:12:42 | ControlFlowNode for unsafe_search | pymongo_bad.py:14:42:14:62 | ControlFlowNode for Dict |
+| pymongo_bad.py:11:21:11:42 | ControlFlowNode for Subscript | pymongo_bad.py:12:19:12:43 | ControlFlowNode for Attribute() |
+| pymongo_bad.py:12:19:12:43 | ControlFlowNode for Attribute() | pymongo_bad.py:14:42:14:62 | ControlFlowNode for Dict |
| pymongo_good.py:12:21:12:27 | ControlFlowNode for request | pymongo_good.py:12:21:12:32 | ControlFlowNode for Attribute |
| pymongo_good.py:12:21:12:32 | ControlFlowNode for Attribute | pymongo_good.py:12:21:12:42 | ControlFlowNode for Subscript |
-| pymongo_good.py:12:21:12:42 | ControlFlowNode for Subscript | pymongo_good.py:13:30:13:42 | ControlFlowNode for unsafe_search |
+| pymongo_good.py:12:21:12:42 | ControlFlowNode for Subscript | pymongo_good.py:13:19:13:43 | ControlFlowNode for Attribute() |
nodes
| flask_mongoengine_db_document_subclass_bad.py:18:21:18:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
| flask_mongoengine_db_document_subclass_bad.py:18:21:18:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
| flask_mongoengine_db_document_subclass_bad.py:18:21:18:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
-| flask_mongoengine_db_document_subclass_bad.py:19:30:19:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search |
+| flask_mongoengine_db_document_subclass_bad.py:19:19:19:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
| flask_mongoengine_db_document_subclass_bad.py:21:34:21:44 | ControlFlowNode for json_search | semmle.label | ControlFlowNode for json_search |
| flask_mongoengine_db_document_subclass_good.py:19:21:19:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
| flask_mongoengine_db_document_subclass_good.py:19:21:19:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
| flask_mongoengine_db_document_subclass_good.py:19:21:19:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
-| flask_mongoengine_db_document_subclass_good.py:20:30:20:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search |
+| flask_mongoengine_db_document_subclass_good.py:20:19:20:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
| flask_mongoengine_get_db_bad.py:19:21:19:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
| flask_mongoengine_get_db_bad.py:19:21:19:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
| flask_mongoengine_get_db_bad.py:19:21:19:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
-| flask_mongoengine_get_db_bad.py:20:30:20:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search |
+| flask_mongoengine_get_db_bad.py:20:19:20:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
| flask_mongoengine_get_db_bad.py:23:39:23:59 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict |
| flask_mongoengine_get_db_good.py:20:21:20:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
| flask_mongoengine_get_db_good.py:20:21:20:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
| flask_mongoengine_get_db_good.py:20:21:20:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
-| flask_mongoengine_get_db_good.py:21:30:21:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search |
+| flask_mongoengine_get_db_good.py:21:19:21:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
| flask_pymongo_bad.py:11:21:11:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
| flask_pymongo_bad.py:11:21:11:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
| flask_pymongo_bad.py:11:21:11:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
-| flask_pymongo_bad.py:12:30:12:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search |
+| flask_pymongo_bad.py:12:19:12:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
| flask_pymongo_bad.py:14:31:14:51 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict |
| flask_pymongo_good.py:12:21:12:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
| flask_pymongo_good.py:12:21:12:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
| flask_pymongo_good.py:12:21:12:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
-| flask_pymongo_good.py:13:30:13:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search |
-| mongoclient_subscript_bad.py:17:21:17:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
-| mongoclient_subscript_bad.py:17:21:17:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
-| mongoclient_subscript_bad.py:17:21:17:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
-| mongoclient_subscript_bad.py:18:30:18:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search |
-| mongoclient_subscript_bad.py:21:29:21:49 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict |
-| mongoclient_subscript_good.py:18:21:18:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
-| mongoclient_subscript_good.py:18:21:18:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
-| mongoclient_subscript_good.py:18:21:18:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
-| mongoclient_subscript_good.py:19:30:19:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search |
+| flask_pymongo_good.py:13:19:13:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
| mongoengine_connect_bad.py:17:21:17:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
| mongoengine_connect_bad.py:17:21:17:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
| mongoengine_connect_bad.py:17:21:17:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
-| mongoengine_connect_bad.py:18:30:18:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search |
+| mongoengine_connect_bad.py:18:19:18:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
| mongoengine_connect_bad.py:21:26:21:46 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict |
| mongoengine_connect_good.py:18:21:18:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
| mongoengine_connect_good.py:18:21:18:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
| mongoengine_connect_good.py:18:21:18:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
-| mongoengine_connect_good.py:19:30:19:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search |
+| mongoengine_connect_good.py:19:19:19:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
| mongoengine_connect_via_connection_bad.py:18:21:18:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
| mongoengine_connect_via_connection_bad.py:18:21:18:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
| mongoengine_connect_via_connection_bad.py:18:21:18:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
-| mongoengine_connect_via_connection_bad.py:19:30:19:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search |
+| mongoengine_connect_via_connection_bad.py:19:19:19:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
| mongoengine_connect_via_connection_bad.py:22:26:22:46 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict |
| mongoengine_connect_via_connection_good.py:19:21:19:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
| mongoengine_connect_via_connection_good.py:19:21:19:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
| mongoengine_connect_via_connection_good.py:19:21:19:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
-| mongoengine_connect_via_connection_good.py:20:30:20:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search |
+| mongoengine_connect_via_connection_good.py:20:19:20:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
| mongoengine_document_subclass_bad.py:17:21:17:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
| mongoengine_document_subclass_bad.py:17:21:17:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
| mongoengine_document_subclass_bad.py:17:21:17:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
-| mongoengine_document_subclass_bad.py:18:30:18:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search |
+| mongoengine_document_subclass_bad.py:18:19:18:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
| mongoengine_document_subclass_bad.py:20:34:20:44 | ControlFlowNode for json_search | semmle.label | ControlFlowNode for json_search |
| mongoengine_document_subclass_good.py:18:21:18:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
| mongoengine_document_subclass_good.py:18:21:18:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
| mongoengine_document_subclass_good.py:18:21:18:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
-| mongoengine_document_subclass_good.py:19:30:19:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search |
+| mongoengine_document_subclass_good.py:19:19:19:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
| mongoengine_get_db_bad.py:17:21:17:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
| mongoengine_get_db_bad.py:17:21:17:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
| mongoengine_get_db_bad.py:17:21:17:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
-| mongoengine_get_db_bad.py:18:30:18:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search |
+| mongoengine_get_db_bad.py:18:19:18:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
| mongoengine_get_db_bad.py:21:26:21:46 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict |
| mongoengine_get_db_good.py:18:21:18:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
| mongoengine_get_db_good.py:18:21:18:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
| mongoengine_get_db_good.py:18:21:18:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
-| mongoengine_get_db_good.py:19:30:19:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search |
+| mongoengine_get_db_good.py:19:19:19:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
| mongoengine_get_db_via_connection_bad.py:18:21:18:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
| mongoengine_get_db_via_connection_bad.py:18:21:18:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
| mongoengine_get_db_via_connection_bad.py:18:21:18:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
-| mongoengine_get_db_via_connection_bad.py:19:30:19:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search |
+| mongoengine_get_db_via_connection_bad.py:19:19:19:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
| mongoengine_get_db_via_connection_bad.py:22:26:22:46 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict |
| mongoengine_get_db_via_connection_good.py:19:21:19:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
| mongoengine_get_db_via_connection_good.py:19:21:19:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
| mongoengine_get_db_via_connection_good.py:19:21:19:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
-| mongoengine_get_db_via_connection_good.py:20:30:20:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search |
+| mongoengine_get_db_via_connection_good.py:20:19:20:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
+| mongoengine_subscript_bad.py:17:21:17:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
+| mongoengine_subscript_bad.py:17:21:17:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
+| mongoengine_subscript_bad.py:17:21:17:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
+| mongoengine_subscript_bad.py:18:19:18:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
+| mongoengine_subscript_bad.py:21:29:21:49 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict |
+| mongoengine_subscript_good.py:18:21:18:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
+| mongoengine_subscript_good.py:18:21:18:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
+| mongoengine_subscript_good.py:18:21:18:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
+| mongoengine_subscript_good.py:19:19:19:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
| pymongo_bad.py:11:21:11:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
| pymongo_bad.py:11:21:11:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
| pymongo_bad.py:11:21:11:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
-| pymongo_bad.py:12:30:12:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search |
+| pymongo_bad.py:12:19:12:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
| pymongo_bad.py:14:42:14:62 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict |
| pymongo_good.py:12:21:12:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
| pymongo_good.py:12:21:12:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
| pymongo_good.py:12:21:12:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
-| pymongo_good.py:13:30:13:42 | ControlFlowNode for unsafe_search | semmle.label | ControlFlowNode for unsafe_search |
+| pymongo_good.py:13:19:13:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
#select
| flask_mongoengine_db_document_subclass_bad.py:21:34:21:44 | ControlFlowNode for json_search | flask_mongoengine_db_document_subclass_bad.py:18:21:18:27 | ControlFlowNode for request | flask_mongoengine_db_document_subclass_bad.py:21:34:21:44 | ControlFlowNode for json_search | $@ NoSQL query contains an unsanitized $@ | flask_mongoengine_db_document_subclass_bad.py:21:34:21:44 | ControlFlowNode for json_search | This | flask_mongoengine_db_document_subclass_bad.py:18:21:18:27 | ControlFlowNode for request | user-provided value |
| flask_mongoengine_get_db_bad.py:23:39:23:59 | ControlFlowNode for Dict | flask_mongoengine_get_db_bad.py:19:21:19:27 | ControlFlowNode for request | flask_mongoengine_get_db_bad.py:23:39:23:59 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | flask_mongoengine_get_db_bad.py:23:39:23:59 | ControlFlowNode for Dict | This | flask_mongoengine_get_db_bad.py:19:21:19:27 | ControlFlowNode for request | user-provided value |
| flask_pymongo_bad.py:14:31:14:51 | ControlFlowNode for Dict | flask_pymongo_bad.py:11:21:11:27 | ControlFlowNode for request | flask_pymongo_bad.py:14:31:14:51 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | flask_pymongo_bad.py:14:31:14:51 | ControlFlowNode for Dict | This | flask_pymongo_bad.py:11:21:11:27 | ControlFlowNode for request | user-provided value |
-| mongoclient_subscript_bad.py:21:29:21:49 | ControlFlowNode for Dict | mongoclient_subscript_bad.py:17:21:17:27 | ControlFlowNode for request | mongoclient_subscript_bad.py:21:29:21:49 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | mongoclient_subscript_bad.py:21:29:21:49 | ControlFlowNode for Dict | This | mongoclient_subscript_bad.py:17:21:17:27 | ControlFlowNode for request | user-provided value |
| mongoengine_connect_bad.py:21:26:21:46 | ControlFlowNode for Dict | mongoengine_connect_bad.py:17:21:17:27 | ControlFlowNode for request | mongoengine_connect_bad.py:21:26:21:46 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | mongoengine_connect_bad.py:21:26:21:46 | ControlFlowNode for Dict | This | mongoengine_connect_bad.py:17:21:17:27 | ControlFlowNode for request | user-provided value |
| mongoengine_connect_via_connection_bad.py:22:26:22:46 | ControlFlowNode for Dict | mongoengine_connect_via_connection_bad.py:18:21:18:27 | ControlFlowNode for request | mongoengine_connect_via_connection_bad.py:22:26:22:46 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | mongoengine_connect_via_connection_bad.py:22:26:22:46 | ControlFlowNode for Dict | This | mongoengine_connect_via_connection_bad.py:18:21:18:27 | ControlFlowNode for request | user-provided value |
| mongoengine_document_subclass_bad.py:20:34:20:44 | ControlFlowNode for json_search | mongoengine_document_subclass_bad.py:17:21:17:27 | ControlFlowNode for request | mongoengine_document_subclass_bad.py:20:34:20:44 | ControlFlowNode for json_search | $@ NoSQL query contains an unsanitized $@ | mongoengine_document_subclass_bad.py:20:34:20:44 | ControlFlowNode for json_search | This | mongoengine_document_subclass_bad.py:17:21:17:27 | ControlFlowNode for request | user-provided value |
| mongoengine_get_db_bad.py:21:26:21:46 | ControlFlowNode for Dict | mongoengine_get_db_bad.py:17:21:17:27 | ControlFlowNode for request | mongoengine_get_db_bad.py:21:26:21:46 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | mongoengine_get_db_bad.py:21:26:21:46 | ControlFlowNode for Dict | This | mongoengine_get_db_bad.py:17:21:17:27 | ControlFlowNode for request | user-provided value |
| mongoengine_get_db_via_connection_bad.py:22:26:22:46 | ControlFlowNode for Dict | mongoengine_get_db_via_connection_bad.py:18:21:18:27 | ControlFlowNode for request | mongoengine_get_db_via_connection_bad.py:22:26:22:46 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | mongoengine_get_db_via_connection_bad.py:22:26:22:46 | ControlFlowNode for Dict | This | mongoengine_get_db_via_connection_bad.py:18:21:18:27 | ControlFlowNode for request | user-provided value |
+| mongoengine_subscript_bad.py:21:29:21:49 | ControlFlowNode for Dict | mongoengine_subscript_bad.py:17:21:17:27 | ControlFlowNode for request | mongoengine_subscript_bad.py:21:29:21:49 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | mongoengine_subscript_bad.py:21:29:21:49 | ControlFlowNode for Dict | This | mongoengine_subscript_bad.py:17:21:17:27 | ControlFlowNode for request | user-provided value |
| pymongo_bad.py:14:42:14:62 | ControlFlowNode for Dict | pymongo_bad.py:11:21:11:27 | ControlFlowNode for request | pymongo_bad.py:14:42:14:62 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | pymongo_bad.py:14:42:14:62 | ControlFlowNode for Dict | This | pymongo_bad.py:11:21:11:27 | ControlFlowNode for request | user-provided value |
From c476c89de5373913ccba1c693ccd3a04166b547c Mon Sep 17 00:00:00 2001
From: Rasmus Wriedt Larsen
Date: Fri, 25 Jun 2021 16:08:57 +0200
Subject: [PATCH 092/429] Python: Add tests for `peewee`
---
.../frameworks/peewee/ConceptsTest.expected | 0
.../frameworks/peewee/ConceptsTest.ql | 2 ++
.../peewee/InlineTaintTest.expected | 3 +++
.../frameworks/peewee/InlineTaintTest.ql | 1 +
.../frameworks/peewee/sql_execution.py | 19 +++++++++++++++++++
5 files changed, 25 insertions(+)
create mode 100644 python/ql/test/library-tests/frameworks/peewee/ConceptsTest.expected
create mode 100644 python/ql/test/library-tests/frameworks/peewee/ConceptsTest.ql
create mode 100644 python/ql/test/library-tests/frameworks/peewee/InlineTaintTest.expected
create mode 100644 python/ql/test/library-tests/frameworks/peewee/InlineTaintTest.ql
create mode 100644 python/ql/test/library-tests/frameworks/peewee/sql_execution.py
diff --git a/python/ql/test/library-tests/frameworks/peewee/ConceptsTest.expected b/python/ql/test/library-tests/frameworks/peewee/ConceptsTest.expected
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/python/ql/test/library-tests/frameworks/peewee/ConceptsTest.ql b/python/ql/test/library-tests/frameworks/peewee/ConceptsTest.ql
new file mode 100644
index 00000000000..b557a0bccb6
--- /dev/null
+++ b/python/ql/test/library-tests/frameworks/peewee/ConceptsTest.ql
@@ -0,0 +1,2 @@
+import python
+import experimental.meta.ConceptsTest
diff --git a/python/ql/test/library-tests/frameworks/peewee/InlineTaintTest.expected b/python/ql/test/library-tests/frameworks/peewee/InlineTaintTest.expected
new file mode 100644
index 00000000000..79d760d87f4
--- /dev/null
+++ b/python/ql/test/library-tests/frameworks/peewee/InlineTaintTest.expected
@@ -0,0 +1,3 @@
+argumentToEnsureNotTaintedNotMarkedAsSpurious
+untaintedArgumentToEnsureTaintedNotMarkedAsMissing
+failures
diff --git a/python/ql/test/library-tests/frameworks/peewee/InlineTaintTest.ql b/python/ql/test/library-tests/frameworks/peewee/InlineTaintTest.ql
new file mode 100644
index 00000000000..027ad8667be
--- /dev/null
+++ b/python/ql/test/library-tests/frameworks/peewee/InlineTaintTest.ql
@@ -0,0 +1 @@
+import experimental.meta.InlineTaintTest
diff --git a/python/ql/test/library-tests/frameworks/peewee/sql_execution.py b/python/ql/test/library-tests/frameworks/peewee/sql_execution.py
new file mode 100644
index 00000000000..c9146cad2eb
--- /dev/null
+++ b/python/ql/test/library-tests/frameworks/peewee/sql_execution.py
@@ -0,0 +1,19 @@
+import peewee
+import playhouse.pool
+
+# This is just one example of one of the support databases
+# see https://docs.peewee-orm.com/en/latest/peewee/database.html
+db = peewee.MySQLDatabase()
+
+conn = db.connection()
+cursor = conn.cursor()
+cursor.execute("sql") # $ MISSING: getSql="sql"
+
+cursor = db.cursor()
+cursor.execute("sql") # $ MISSING: getSql="sql"
+
+db.execute_sql("sql") # $ MISSING: getSql="sql"
+
+# Pool extension
+pool = playhouse.pool.PooledMySQLDatabase(...)
+pool.execute_sql("sql") # $ MISSING: getSql="sql"
From 5cfc43395ba99471bc17371996470fa13ded4ddc Mon Sep 17 00:00:00 2001
From: Rasmus Wriedt Larsen
Date: Fri, 25 Jun 2021 17:15:12 +0200
Subject: [PATCH 093/429] Python: Refactor PEP249 to encapsulate in module
So global namespace doesn't contain `Connection` whenever `PEP249.qll`
is imported
---
.../ql/src/semmle/python/frameworks/Aioch.qll | 1 -
.../python/frameworks/ClickhouseDriver.qll | 2 +-
.../src/semmle/python/frameworks/Django.qll | 4 +-
.../src/semmle/python/frameworks/MySQLdb.qll | 2 +-
.../ql/src/semmle/python/frameworks/Mysql.qll | 2 +-
.../src/semmle/python/frameworks/PEP249.qll | 107 ++------------
.../src/semmle/python/frameworks/Psycopg2.qll | 2 +-
.../src/semmle/python/frameworks/PyMySQL.qll | 2 +-
.../src/semmle/python/frameworks/Stdlib.qll | 2 +-
.../python/frameworks/internal/PEP249Impl.qll | 134 ++++++++++++++++++
10 files changed, 154 insertions(+), 104 deletions(-)
create mode 100644 python/ql/src/semmle/python/frameworks/internal/PEP249Impl.qll
diff --git a/python/ql/src/semmle/python/frameworks/Aioch.qll b/python/ql/src/semmle/python/frameworks/Aioch.qll
index ede732e35dc..8595a708fb7 100644
--- a/python/ql/src/semmle/python/frameworks/Aioch.qll
+++ b/python/ql/src/semmle/python/frameworks/Aioch.qll
@@ -8,7 +8,6 @@
private import python
private import semmle.python.Concepts
private import semmle.python.ApiGraphs
-private import semmle.python.frameworks.PEP249
private import semmle.python.frameworks.ClickhouseDriver
/**
diff --git a/python/ql/src/semmle/python/frameworks/ClickhouseDriver.qll b/python/ql/src/semmle/python/frameworks/ClickhouseDriver.qll
index 8863b1dbe66..949f4d5e870 100644
--- a/python/ql/src/semmle/python/frameworks/ClickhouseDriver.qll
+++ b/python/ql/src/semmle/python/frameworks/ClickhouseDriver.qll
@@ -23,7 +23,7 @@ module ClickhouseDriver {
* `clickhouse_driver` implements PEP249,
* providing ways to execute SQL statements against a database.
*/
- class ClickHouseDriverPEP249 extends PEP249ModuleApiNode {
+ class ClickHouseDriverPEP249 extends PEP249::PEP249ModuleApiNode {
ClickHouseDriverPEP249() { this = API::moduleImport("clickhouse_driver") }
}
diff --git a/python/ql/src/semmle/python/frameworks/Django.qll b/python/ql/src/semmle/python/frameworks/Django.qll
index d9f59b05fa6..d3ff9248e80 100644
--- a/python/ql/src/semmle/python/frameworks/Django.qll
+++ b/python/ql/src/semmle/python/frameworks/Django.qll
@@ -313,7 +313,7 @@ private module PrivateDjango {
/**
* `django.db` implements PEP249, providing ways to execute SQL statements against a database.
*/
- private class DjangoDb extends PEP249ModuleApiNode {
+ private class DjangoDb extends PEP249::PEP249ModuleApiNode {
DjangoDb() { this = API::moduleImport("django").getMember("db") }
}
@@ -322,7 +322,7 @@ private module PrivateDjango {
/** Gets a reference to the `django.db.connection` object. */
API::Node connection() { result = db().getMember("connection") }
- class DjangoDbConnection extends Connection::InstanceSource {
+ class DjangoDbConnection extends PEP249::Connection::InstanceSource {
DjangoDbConnection() { this = connection().getAUse() }
}
diff --git a/python/ql/src/semmle/python/frameworks/MySQLdb.qll b/python/ql/src/semmle/python/frameworks/MySQLdb.qll
index 5f10cdc0c84..e1d7262c087 100644
--- a/python/ql/src/semmle/python/frameworks/MySQLdb.qll
+++ b/python/ql/src/semmle/python/frameworks/MySQLdb.qll
@@ -25,7 +25,7 @@ private module MySQLdb {
// MySQLdb
// ---------------------------------------------------------------------------
/** MySQLdb implements PEP 249, providing ways to execute SQL statements against a database. */
- class MySQLdb extends PEP249ModuleApiNode {
+ class MySQLdb extends PEP249::PEP249ModuleApiNode {
MySQLdb() { this = API::moduleImport("MySQLdb") }
}
}
diff --git a/python/ql/src/semmle/python/frameworks/Mysql.qll b/python/ql/src/semmle/python/frameworks/Mysql.qll
index 5049124ad83..a1a297e88c0 100644
--- a/python/ql/src/semmle/python/frameworks/Mysql.qll
+++ b/python/ql/src/semmle/python/frameworks/Mysql.qll
@@ -30,7 +30,7 @@ private module Mysql {
* The mysql.connector module
* See https://dev.mysql.com/doc/connector-python/en/connector-python-example-connecting.html
*/
- class MysqlConnector extends PEP249ModuleApiNode {
+ class MysqlConnector extends PEP249::PEP249ModuleApiNode {
MysqlConnector() { this = API::moduleImport("mysql").getMember("connector") }
}
}
diff --git a/python/ql/src/semmle/python/frameworks/PEP249.qll b/python/ql/src/semmle/python/frameworks/PEP249.qll
index ef58ef1fbdb..6f9b4f2ed4e 100644
--- a/python/ql/src/semmle/python/frameworks/PEP249.qll
+++ b/python/ql/src/semmle/python/frameworks/PEP249.qll
@@ -8,119 +8,36 @@ private import semmle.python.dataflow.new.DataFlow
private import semmle.python.dataflow.new.RemoteFlowSources
private import semmle.python.Concepts
private import semmle.python.ApiGraphs
+import semmle.python.frameworks.internal.PEP249Impl
/**
* A module implementing PEP 249. Extend this class for implementations.
*
- * DEPRECATED: Extend `PEP249ModuleApiNode` instead.
+ * DEPRECATED: Extend `PEP249::PEP249ModuleApiNode` instead.
*/
abstract deprecated class PEP249Module extends DataFlow::Node { }
/**
- * An abstract class encompassing API graph nodes that implement PEP 249.
- * Extend this class for implementations.
+ * DEPRECATED: Use `PEP249::PEP249ModuleApiNode` instead.
*/
-abstract class PEP249ModuleApiNode extends API::Node {
- /** Gets a string representation of this element. */
- override string toString() { result = this.(API::Node).toString() }
-}
-
-/** Gets a reference to a connect call. */
-DataFlow::Node connect() { result = any(PEP249ModuleApiNode a).getMember("connect").getAUse() }
+deprecated class PEP249ModuleApiNode = PEP249::PEP249ModuleApiNode;
/**
- * Provides models for the `db.Connection` class
- *
- * See https://www.python.org/dev/peps/pep-0249/#connection-objects.
+ * DEPRECATED: Use `PEP249::Connection` instead.
*/
-module Connection {
- /**
- * A source of instances of `db.Connection`, extend this class to model new instances.
- *
- * This can include instantiations of the class, return values from function
- * calls, or a special parameter that will be set when functions are called by external
- * libraries.
- *
- * Use the predicate `Connection::instance()` to get references to instances of `db.Connection`.
- *
- * Extend this class if the module implementing PEP 249 offers more direct ways to obtain
- * a connection than going through `connect`.
- */
- abstract class InstanceSource extends DataFlow::Node { }
-
- /** A direct instantiation of `db.Connection`. */
- private class ClassInstantiation extends InstanceSource, DataFlow::CallCfgNode {
- ClassInstantiation() { this.getFunction() = connect() }
- }
-
- /** Gets a reference to an instance of `db.Connection`. */
- private DataFlow::LocalSourceNode instance(DataFlow::TypeTracker t) {
- t.start() and
- result instanceof InstanceSource
- or
- exists(DataFlow::TypeTracker t2 | result = instance(t2).track(t2, t))
- }
-
- /** Gets a reference to an instance of `db.Connection`. */
- DataFlow::Node instance() { instance(DataFlow::TypeTracker::end()).flowsTo(result) }
-}
+deprecated module Connection = PEP249::Connection;
/**
- * Provides models for the `cursor` method on a connection.
- * See https://www.python.org/dev/peps/pep-0249/#cursor.
+ * DEPRECATED: Use `PEP249::cursor` instead.
*/
-module cursor {
- /** Gets a reference to the `cursor` method on a connection. */
- private DataFlow::LocalSourceNode methodRef(DataFlow::TypeTracker t) {
- t.startInAttr("cursor") and
- result = Connection::instance()
- or
- exists(DataFlow::TypeTracker t2 | result = methodRef(t2).track(t2, t))
- }
-
- /** Gets a reference to the `cursor` method on a connection. */
- DataFlow::Node methodRef() { methodRef(DataFlow::TypeTracker::end()).flowsTo(result) }
-
- /** Gets a reference to a result of calling the `cursor` method on a connection. */
- private DataFlow::LocalSourceNode methodResult(DataFlow::TypeTracker t) {
- t.start() and
- result.asCfgNode().(CallNode).getFunction() = methodRef().asCfgNode()
- or
- exists(DataFlow::TypeTracker t2 | result = methodResult(t2).track(t2, t))
- }
-
- /** Gets a reference to a result of calling the `cursor` method on a connection. */
- DataFlow::Node methodResult() { methodResult(DataFlow::TypeTracker::end()).flowsTo(result) }
-}
+deprecated module cursor = PEP249::cursor;
/**
- * Gets a reference to the `execute` method on a cursor (or on a connection).
- *
- * Note: while `execute` method on a connection is not part of PEP249, if it is used, we
- * recognize it as an alias for constructing a cursor and calling `execute` on it.
- *
- * See https://www.python.org/dev/peps/pep-0249/#id15.
+ * DEPRECATED: Use `PEP249::execute` instead.
*/
-private DataFlow::LocalSourceNode execute(DataFlow::TypeTracker t) {
- t.startInAttr("execute") and
- result in [cursor::methodResult(), Connection::instance()]
- or
- exists(DataFlow::TypeTracker t2 | result = execute(t2).track(t2, t))
-}
+deprecated predicate execute = PEP249::execute/0;
/**
- * Gets a reference to the `execute` method on a cursor (or on a connection).
- *
- * Note: while `execute` method on a connection is not part of PEP249, if it is used, we
- * recognize it as an alias for constructing a cursor and calling `execute` on it.
- *
- * See https://www.python.org/dev/peps/pep-0249/#id15.
+ * DEPRECATED: Use `PEP249::connect` instead.
*/
-DataFlow::Node execute() { execute(DataFlow::TypeTracker::end()).flowsTo(result) }
-
-/** A call to the `execute` method on a cursor (or on a connection). */
-private class ExecuteCall extends SqlExecution::Range, DataFlow::CallCfgNode {
- ExecuteCall() { this.getFunction() = execute() }
-
- override DataFlow::Node getSql() { result in [this.getArg(0), this.getArgByName("sql")] }
-}
+deprecated predicate connect = PEP249::connect/0;
diff --git a/python/ql/src/semmle/python/frameworks/Psycopg2.qll b/python/ql/src/semmle/python/frameworks/Psycopg2.qll
index d966776b082..01f33b37cd0 100644
--- a/python/ql/src/semmle/python/frameworks/Psycopg2.qll
+++ b/python/ql/src/semmle/python/frameworks/Psycopg2.qll
@@ -23,7 +23,7 @@ private module Psycopg2 {
// Psycopg
// ---------------------------------------------------------------------------
/** psycopg2 implements PEP 249, providing ways to execute SQL statements against a database. */
- class Psycopg2 extends PEP249ModuleApiNode {
+ class Psycopg2 extends PEP249::PEP249ModuleApiNode {
Psycopg2() { this = API::moduleImport("psycopg2") }
}
}
diff --git a/python/ql/src/semmle/python/frameworks/PyMySQL.qll b/python/ql/src/semmle/python/frameworks/PyMySQL.qll
index 452b87ed030..834dd2438dc 100644
--- a/python/ql/src/semmle/python/frameworks/PyMySQL.qll
+++ b/python/ql/src/semmle/python/frameworks/PyMySQL.qll
@@ -16,7 +16,7 @@ private import semmle.python.frameworks.PEP249
*/
private module PyMySQL {
/** PyMySQL implements PEP 249, providing ways to execute SQL statements against a database. */
- class PyMySQLPEP249 extends PEP249ModuleApiNode {
+ class PyMySQLPEP249 extends PEP249::PEP249ModuleApiNode {
PyMySQLPEP249() { this = API::moduleImport("pymysql") }
}
}
diff --git a/python/ql/src/semmle/python/frameworks/Stdlib.qll b/python/ql/src/semmle/python/frameworks/Stdlib.qll
index 66018e45b62..1f5afdc463b 100644
--- a/python/ql/src/semmle/python/frameworks/Stdlib.qll
+++ b/python/ql/src/semmle/python/frameworks/Stdlib.qll
@@ -885,7 +885,7 @@ private module Stdlib {
*
* See https://devdocs.io/python~3.9/library/sqlite3
*/
- class Sqlite3 extends PEP249ModuleApiNode {
+ class Sqlite3 extends PEP249::PEP249ModuleApiNode {
Sqlite3() { this = API::moduleImport("sqlite3") }
}
diff --git a/python/ql/src/semmle/python/frameworks/internal/PEP249Impl.qll b/python/ql/src/semmle/python/frameworks/internal/PEP249Impl.qll
new file mode 100644
index 00000000000..bcef36a17b5
--- /dev/null
+++ b/python/ql/src/semmle/python/frameworks/internal/PEP249Impl.qll
@@ -0,0 +1,134 @@
+/**
+ * INTERNAL: Do not use.
+ *
+ * Provides internal implementation of PEP249. This currently resides in a different
+ * file than `python/ql/src/semmle/python/frameworks/PEP249.qll`, since we used to
+ * export everything without being encapsulated in a module, and shadowing rules means
+ * that we can't just add the module directly to that file :(
+ *
+ * So once we can remove those deprecated things (Start of July 2022), we can also move
+ * the core implementation into its' proper place.
+ *
+ * Provides classes modeling PEP 249.
+ * See https://www.python.org/dev/peps/pep-0249/.
+ */
+
+private import python
+private import semmle.python.dataflow.new.DataFlow
+private import semmle.python.dataflow.new.RemoteFlowSources
+private import semmle.python.Concepts
+private import semmle.python.ApiGraphs
+
+/**
+ * Provides classes modeling PEP 249.
+ */
+module PEP249 {
+ /**
+ * An abstract class encompassing API graph nodes that implement PEP 249.
+ * Extend this class for implementations.
+ */
+ abstract class PEP249ModuleApiNode extends API::Node {
+ /** Gets a string representation of this element. */
+ override string toString() { result = this.(API::Node).toString() }
+ }
+
+ /** Gets a reference to a connect call. */
+ DataFlow::Node connect() { result = any(PEP249ModuleApiNode a).getMember("connect").getAUse() }
+
+ /**
+ * Provides models for the `db.Connection` class
+ *
+ * See https://www.python.org/dev/peps/pep-0249/#connection-objects.
+ */
+ module Connection {
+ /**
+ * A source of instances of `db.Connection`, extend this class to model new instances.
+ *
+ * This can include instantiations of the class, return values from function
+ * calls, or a special parameter that will be set when functions are called by external
+ * libraries.
+ *
+ * Use the predicate `Connection::instance()` to get references to instances of `db.Connection`.
+ *
+ * Extend this class if the module implementing PEP 249 offers more direct ways to obtain
+ * a connection than going through `connect`.
+ */
+ abstract class InstanceSource extends DataFlow::Node { }
+
+ /** A direct instantiation of `db.Connection`. */
+ private class ClassInstantiation extends InstanceSource, DataFlow::CallCfgNode {
+ ClassInstantiation() { this.getFunction() = connect() }
+ }
+
+ /** Gets a reference to an instance of `db.Connection`. */
+ private DataFlow::LocalSourceNode instance(DataFlow::TypeTracker t) {
+ t.start() and
+ result instanceof InstanceSource
+ or
+ exists(DataFlow::TypeTracker t2 | result = instance(t2).track(t2, t))
+ }
+
+ /** Gets a reference to an instance of `db.Connection`. */
+ DataFlow::Node instance() { instance(DataFlow::TypeTracker::end()).flowsTo(result) }
+ }
+
+ /**
+ * Provides models for the `cursor` method on a connection.
+ * See https://www.python.org/dev/peps/pep-0249/#cursor.
+ */
+ module cursor {
+ /** Gets a reference to the `cursor` method on a connection. */
+ private DataFlow::LocalSourceNode methodRef(DataFlow::TypeTracker t) {
+ t.startInAttr("cursor") and
+ result = Connection::instance()
+ or
+ exists(DataFlow::TypeTracker t2 | result = methodRef(t2).track(t2, t))
+ }
+
+ /** Gets a reference to the `cursor` method on a connection. */
+ DataFlow::Node methodRef() { methodRef(DataFlow::TypeTracker::end()).flowsTo(result) }
+
+ /** Gets a reference to a result of calling the `cursor` method on a connection. */
+ private DataFlow::LocalSourceNode methodResult(DataFlow::TypeTracker t) {
+ t.start() and
+ result.asCfgNode().(CallNode).getFunction() = methodRef().asCfgNode()
+ or
+ exists(DataFlow::TypeTracker t2 | result = methodResult(t2).track(t2, t))
+ }
+
+ /** Gets a reference to a result of calling the `cursor` method on a connection. */
+ DataFlow::Node methodResult() { methodResult(DataFlow::TypeTracker::end()).flowsTo(result) }
+ }
+
+ /**
+ * Gets a reference to the `execute` method on a cursor (or on a connection).
+ *
+ * Note: while `execute` method on a connection is not part of PEP249, if it is used, we
+ * recognize it as an alias for constructing a cursor and calling `execute` on it.
+ *
+ * See https://www.python.org/dev/peps/pep-0249/#id15.
+ */
+ private DataFlow::LocalSourceNode execute(DataFlow::TypeTracker t) {
+ t.startInAttr("execute") and
+ result in [cursor::methodResult(), Connection::instance()]
+ or
+ exists(DataFlow::TypeTracker t2 | result = execute(t2).track(t2, t))
+ }
+
+ /**
+ * Gets a reference to the `execute` method on a cursor (or on a connection).
+ *
+ * Note: while `execute` method on a connection is not part of PEP249, if it is used, we
+ * recognize it as an alias for constructing a cursor and calling `execute` on it.
+ *
+ * See https://www.python.org/dev/peps/pep-0249/#id15.
+ */
+ DataFlow::Node execute() { execute(DataFlow::TypeTracker::end()).flowsTo(result) }
+
+ /** A call to the `execute` method on a cursor (or on a connection). */
+ private class ExecuteCall extends SqlExecution::Range, DataFlow::CallCfgNode {
+ ExecuteCall() { this.getFunction() = execute() }
+
+ override DataFlow::Node getSql() { result in [this.getArg(0), this.getArgByName("sql")] }
+ }
+}
From 6be0db2c227de9248befd8a5498bf5ccd385fad3 Mon Sep 17 00:00:00 2001
From: Rasmus Wriedt Larsen
Date: Fri, 25 Jun 2021 17:24:28 +0200
Subject: [PATCH 094/429] Python: Improve QLDoc of PEP249 modeling
---
.../python/frameworks/internal/PEP249Impl.qll | 36 ++++++++++---------
1 file changed, 19 insertions(+), 17 deletions(-)
diff --git a/python/ql/src/semmle/python/frameworks/internal/PEP249Impl.qll b/python/ql/src/semmle/python/frameworks/internal/PEP249Impl.qll
index bcef36a17b5..80f4c4b990c 100644
--- a/python/ql/src/semmle/python/frameworks/internal/PEP249Impl.qll
+++ b/python/ql/src/semmle/python/frameworks/internal/PEP249Impl.qll
@@ -20,47 +20,47 @@ private import semmle.python.Concepts
private import semmle.python.ApiGraphs
/**
- * Provides classes modeling PEP 249.
+ * Provides classes modeling database interfaces following PEP 249.
+ * See https://www.python.org/dev/peps/pep-0249/.
*/
module PEP249 {
/**
- * An abstract class encompassing API graph nodes that implement PEP 249.
- * Extend this class for implementations.
+ * An API graph node representing a module that implements PEP 249.
*/
abstract class PEP249ModuleApiNode extends API::Node {
/** Gets a string representation of this element. */
override string toString() { result = this.(API::Node).toString() }
}
- /** Gets a reference to a connect call. */
+ /** Gets a reference to the `connect` function of a module that implements PEP 249. */
DataFlow::Node connect() { result = any(PEP249ModuleApiNode a).getMember("connect").getAUse() }
/**
- * Provides models for the `db.Connection` class
+ * Provides models for database connections (following PEP 249).
*
* See https://www.python.org/dev/peps/pep-0249/#connection-objects.
*/
module Connection {
/**
- * A source of instances of `db.Connection`, extend this class to model new instances.
+ * A source of database connections (following PEP 249), extend this class to model new instances.
*
* This can include instantiations of the class, return values from function
* calls, or a special parameter that will be set when functions are called by external
* libraries.
*
- * Use the predicate `Connection::instance()` to get references to instances of `db.Connection`.
+ * Use the predicate `Connection::instance()` to get references database connections (following PEP 249).
*
* Extend this class if the module implementing PEP 249 offers more direct ways to obtain
* a connection than going through `connect`.
*/
abstract class InstanceSource extends DataFlow::Node { }
- /** A direct instantiation of `db.Connection`. */
- private class ClassInstantiation extends InstanceSource, DataFlow::CallCfgNode {
- ClassInstantiation() { this.getFunction() = connect() }
+ /** A call to the `connect` function of a module that implements PEP 249. */
+ private class ConnectCall extends InstanceSource, DataFlow::CallCfgNode {
+ ConnectCall() { this.getFunction() = connect() }
}
- /** Gets a reference to an instance of `db.Connection`. */
+ /** Gets a reference to a database connection (following PEP 249). */
private DataFlow::LocalSourceNode instance(DataFlow::TypeTracker t) {
t.start() and
result instanceof InstanceSource
@@ -68,16 +68,18 @@ module PEP249 {
exists(DataFlow::TypeTracker t2 | result = instance(t2).track(t2, t))
}
- /** Gets a reference to an instance of `db.Connection`. */
+ /** Gets a reference to a database connection (following PEP 249). */
DataFlow::Node instance() { instance(DataFlow::TypeTracker::end()).flowsTo(result) }
}
/**
- * Provides models for the `cursor` method on a connection.
+ * Provides models for database cursors (following PEP 249).
+ *
+ * These are are returned by the `cursor` method on a database connection.
* See https://www.python.org/dev/peps/pep-0249/#cursor.
*/
module cursor {
- /** Gets a reference to the `cursor` method on a connection. */
+ /** Gets a reference to the `cursor` method on a database connection. */
private DataFlow::LocalSourceNode methodRef(DataFlow::TypeTracker t) {
t.startInAttr("cursor") and
result = Connection::instance()
@@ -85,10 +87,10 @@ module PEP249 {
exists(DataFlow::TypeTracker t2 | result = methodRef(t2).track(t2, t))
}
- /** Gets a reference to the `cursor` method on a connection. */
+ /** Gets a reference to the `cursor` method on a database connection. */
DataFlow::Node methodRef() { methodRef(DataFlow::TypeTracker::end()).flowsTo(result) }
- /** Gets a reference to a result of calling the `cursor` method on a connection. */
+ /** Gets a reference to a result of calling the `cursor` method on a database connection. */
private DataFlow::LocalSourceNode methodResult(DataFlow::TypeTracker t) {
t.start() and
result.asCfgNode().(CallNode).getFunction() = methodRef().asCfgNode()
@@ -96,7 +98,7 @@ module PEP249 {
exists(DataFlow::TypeTracker t2 | result = methodResult(t2).track(t2, t))
}
- /** Gets a reference to a result of calling the `cursor` method on a connection. */
+ /** Gets a reference to a result of calling the `cursor` method on a database connection. */
DataFlow::Node methodResult() { methodResult(DataFlow::TypeTracker::end()).flowsTo(result) }
}
From d8db83d0818388c3f3dee1b5f75874297b87bfed Mon Sep 17 00:00:00 2001
From: Rasmus Wriedt Larsen
Date: Fri, 25 Jun 2021 17:29:32 +0200
Subject: [PATCH 095/429] Python: Add cursor::instance for PEP249
For Peewee modeling I want to be able to define new cursor instances
just like I can do for connections.
---
.../python/frameworks/internal/PEP249Impl.qll | 42 +++++++++++++++++--
1 file changed, 39 insertions(+), 3 deletions(-)
diff --git a/python/ql/src/semmle/python/frameworks/internal/PEP249Impl.qll b/python/ql/src/semmle/python/frameworks/internal/PEP249Impl.qll
index 80f4c4b990c..b6e36f3a78b 100644
--- a/python/ql/src/semmle/python/frameworks/internal/PEP249Impl.qll
+++ b/python/ql/src/semmle/python/frameworks/internal/PEP249Impl.qll
@@ -79,6 +79,31 @@ module PEP249 {
* See https://www.python.org/dev/peps/pep-0249/#cursor.
*/
module cursor {
+ /**
+ * A source of database cursors (following PEP 249), extend this class to model new instances.
+ *
+ * This can include instantiations of the class, return values from function
+ * calls, or a special parameter that will be set when functions are called by external
+ * libraries.
+ *
+ * Use the predicate `Connection::instance()` to get references database cursors (following PEP 249).
+ *
+ * Extend this class if the module implementing PEP 249 offers more direct ways to obtain
+ * a connection than going through `connect`.
+ */
+ abstract class InstanceSource extends DataFlow::LocalSourceNode { }
+
+ /** Gets a reference to a database cursor. */
+ private DataFlow::LocalSourceNode instance(DataFlow::TypeTracker t) {
+ t.start() and
+ result instanceof InstanceSource
+ or
+ exists(DataFlow::TypeTracker t2 | result = instance(t2).track(t2, t))
+ }
+
+ /** Gets a reference to a database cursor. */
+ DataFlow::Node instance() { instance(DataFlow::TypeTracker::end()).flowsTo(result) }
+
/** Gets a reference to the `cursor` method on a database connection. */
private DataFlow::LocalSourceNode methodRef(DataFlow::TypeTracker t) {
t.startInAttr("cursor") and
@@ -90,6 +115,11 @@ module PEP249 {
/** Gets a reference to the `cursor` method on a database connection. */
DataFlow::Node methodRef() { methodRef(DataFlow::TypeTracker::end()).flowsTo(result) }
+ /** A call to the `cursor` method on a database connection */
+ private class CursorCall extends InstanceSource, DataFlow::CallCfgNode {
+ CursorCall() { this.getFunction() = methodRef() }
+ }
+
/** Gets a reference to a result of calling the `cursor` method on a database connection. */
private DataFlow::LocalSourceNode methodResult(DataFlow::TypeTracker t) {
t.start() and
@@ -98,8 +128,14 @@ module PEP249 {
exists(DataFlow::TypeTracker t2 | result = methodResult(t2).track(t2, t))
}
- /** Gets a reference to a result of calling the `cursor` method on a database connection. */
- DataFlow::Node methodResult() { methodResult(DataFlow::TypeTracker::end()).flowsTo(result) }
+ /**
+ * DEPRECATED: Use `Cursor::instance()` to get references to database cursors instead.
+ *
+ * Gets a reference to a result of calling the `cursor` method on a database connection.
+ */
+ deprecated DataFlow::Node methodResult() {
+ methodResult(DataFlow::TypeTracker::end()).flowsTo(result)
+ }
}
/**
@@ -112,7 +148,7 @@ module PEP249 {
*/
private DataFlow::LocalSourceNode execute(DataFlow::TypeTracker t) {
t.startInAttr("execute") and
- result in [cursor::methodResult(), Connection::instance()]
+ result in [cursor::instance(), Connection::instance()]
or
exists(DataFlow::TypeTracker t2 | result = execute(t2).track(t2, t))
}
From 1317ae298ce6f1b614dae86e435f14b95f50b6e2 Mon Sep 17 00:00:00 2001
From: Rasmus Wriedt Larsen
Date: Fri, 25 Jun 2021 17:30:35 +0200
Subject: [PATCH 096/429] Python: Rename `cursor` => `Cursor` in PEP249
Notice that since this will be part of the same PR as 5cfc433, it is OK
to do this change without keeping `PEP249::cursor` for backwards
compatibility.
---
python/ql/src/semmle/python/frameworks/PEP249.qll | 4 ++--
.../ql/src/semmle/python/frameworks/internal/PEP249Impl.qll | 4 ++--
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/python/ql/src/semmle/python/frameworks/PEP249.qll b/python/ql/src/semmle/python/frameworks/PEP249.qll
index 6f9b4f2ed4e..2ad7bc8898f 100644
--- a/python/ql/src/semmle/python/frameworks/PEP249.qll
+++ b/python/ql/src/semmle/python/frameworks/PEP249.qll
@@ -28,9 +28,9 @@ deprecated class PEP249ModuleApiNode = PEP249::PEP249ModuleApiNode;
deprecated module Connection = PEP249::Connection;
/**
- * DEPRECATED: Use `PEP249::cursor` instead.
+ * DEPRECATED: Use `PEP249::Cursor` instead.
*/
-deprecated module cursor = PEP249::cursor;
+deprecated module cursor = PEP249::Cursor;
/**
* DEPRECATED: Use `PEP249::execute` instead.
diff --git a/python/ql/src/semmle/python/frameworks/internal/PEP249Impl.qll b/python/ql/src/semmle/python/frameworks/internal/PEP249Impl.qll
index b6e36f3a78b..254dcb98cb6 100644
--- a/python/ql/src/semmle/python/frameworks/internal/PEP249Impl.qll
+++ b/python/ql/src/semmle/python/frameworks/internal/PEP249Impl.qll
@@ -78,7 +78,7 @@ module PEP249 {
* These are are returned by the `cursor` method on a database connection.
* See https://www.python.org/dev/peps/pep-0249/#cursor.
*/
- module cursor {
+ module Cursor {
/**
* A source of database cursors (following PEP 249), extend this class to model new instances.
*
@@ -148,7 +148,7 @@ module PEP249 {
*/
private DataFlow::LocalSourceNode execute(DataFlow::TypeTracker t) {
t.startInAttr("execute") and
- result in [cursor::instance(), Connection::instance()]
+ result in [Cursor::instance(), Connection::instance()]
or
exists(DataFlow::TypeTracker t2 | result = execute(t2).track(t2, t))
}
From 97571e0b4fe0c30974d42e9201935cfcc2d7f9a3 Mon Sep 17 00:00:00 2001
From: Rasmus Wriedt Larsen
Date: Fri, 25 Jun 2021 17:50:59 +0200
Subject: [PATCH 097/429] Python: Add modeling of `peewee`
---
docs/codeql/support/reusables/frameworks.rst | 1 +
.../2021-06-25-add-peewee-modeling.md | 2 +
python/ql/src/semmle/python/Frameworks.qll | 1 +
.../src/semmle/python/frameworks/Peewee.qll | 192 ++++++++++++++++++
.../frameworks/peewee/sql_execution.py | 8 +-
5 files changed, 200 insertions(+), 4 deletions(-)
create mode 100644 python/change-notes/2021-06-25-add-peewee-modeling.md
create mode 100644 python/ql/src/semmle/python/frameworks/Peewee.qll
diff --git a/docs/codeql/support/reusables/frameworks.rst b/docs/codeql/support/reusables/frameworks.rst
index dd52ded0ec1..5af414a8153 100644
--- a/docs/codeql/support/reusables/frameworks.rst
+++ b/docs/codeql/support/reusables/frameworks.rst
@@ -174,6 +174,7 @@ Python built-in support
MySQL-python, Database
psycopg2, Database
sqlite3, Database
+ peewee, Database ORM
cryptography, Cryptography library
pycryptodome, Cryptography library
pycryptodomex, Cryptography library
diff --git a/python/change-notes/2021-06-25-add-peewee-modeling.md b/python/change-notes/2021-06-25-add-peewee-modeling.md
new file mode 100644
index 00000000000..ff5b4025d47
--- /dev/null
+++ b/python/change-notes/2021-06-25-add-peewee-modeling.md
@@ -0,0 +1,2 @@
+lgtm,codescanning
+* Added modeling of raw SQL execution from the PyPI package `peewee`.
diff --git a/python/ql/src/semmle/python/Frameworks.qll b/python/ql/src/semmle/python/Frameworks.qll
index 48e47108bbe..6e201babd35 100644
--- a/python/ql/src/semmle/python/Frameworks.qll
+++ b/python/ql/src/semmle/python/Frameworks.qll
@@ -25,6 +25,7 @@ private import semmle.python.frameworks.Rsa
private import semmle.python.frameworks.Simplejson
private import semmle.python.frameworks.Stdlib
private import semmle.python.frameworks.Tornado
+private import semmle.python.frameworks.Peewee
private import semmle.python.frameworks.Twisted
private import semmle.python.frameworks.Ujson
private import semmle.python.frameworks.Yaml
diff --git a/python/ql/src/semmle/python/frameworks/Peewee.qll b/python/ql/src/semmle/python/frameworks/Peewee.qll
new file mode 100644
index 00000000000..189ab14876a
--- /dev/null
+++ b/python/ql/src/semmle/python/frameworks/Peewee.qll
@@ -0,0 +1,192 @@
+/**
+ * Provides classes modeling security-relevant aspects of the `peewee` PyPI package.
+ * See
+ * - https://pypi.org/project/peewee/
+ * - https://docs.peewee-orm.com/en/latest/index.html
+ */
+
+private import python
+private import semmle.python.dataflow.new.DataFlow
+private import semmle.python.dataflow.new.TaintTracking
+private import semmle.python.Concepts
+private import semmle.python.ApiGraphs
+private import semmle.python.frameworks.PEP249
+
+/**
+ * Provides models for the `peewee` PyPI package.
+ * See
+ * - https://pypi.org/project/peewee/
+ * - https://docs.peewee-orm.com/en/latest/index.html
+ */
+private module Peewee {
+ /** Provides models for the `peewee.Database` class and subclasses. */
+ module Database {
+ /** Gets a reference to the `peewee.Database` class or any subclass. */
+ API::Node subclassRef() {
+ result = API::moduleImport("peewee").getMember("Database").getASubclass*()
+ or
+ // known subclasses
+ result =
+ API::moduleImport("peewee")
+ .getMember(["SqliteDatabase", "MySQLDatabase", "PostgresqlDatabase"])
+ .getASubclass*()
+ or
+ // Ohter known subclasses, semi auto generated by using
+ // ```codeql
+ // class DBClass extends Class, SelfRefMixin {
+ // DBClass() {
+ // exists(this.getLocation().getFile().getRelativePath()) and
+ // this.getName().matches("%Database") and
+ // this.getABase().(Name).getId().matches("%Database")
+ // }
+ // }
+ //
+ // from DBClass dbClass, Module mod
+ // where
+ // dbClass.getScope() = mod
+ // select mod.getName()+ "." + dbClass.getName()
+ // ```
+ result =
+ API::moduleImport("playhouse")
+ .getMember("apsw_ext")
+ .getMember("APSWDatabase")
+ .getASubclass*()
+ or
+ result =
+ API::moduleImport("playhouse")
+ .getMember("cockroachdb")
+ .getMember("CockroachDatabase")
+ .getASubclass*()
+ or
+ result =
+ API::moduleImport("playhouse")
+ .getMember("cockroachdb")
+ .getMember("PooledCockroachDatabase")
+ .getASubclass*()
+ or
+ result =
+ API::moduleImport("playhouse")
+ .getMember("mysql_ext")
+ .getMember("MySQLConnectorDatabase")
+ .getASubclass*()
+ or
+ result =
+ API::moduleImport("playhouse")
+ .getMember("pool")
+ .getMember("PooledCSqliteExtDatabase")
+ .getASubclass*()
+ or
+ result =
+ API::moduleImport("playhouse")
+ .getMember("pool")
+ .getMember("PooledMySQLDatabase")
+ .getASubclass*()
+ or
+ result =
+ API::moduleImport("playhouse")
+ .getMember("pool")
+ .getMember("PooledPostgresqlDatabase")
+ .getASubclass*()
+ or
+ result =
+ API::moduleImport("playhouse")
+ .getMember("pool")
+ .getMember("PooledPostgresqlExtDatabase")
+ .getASubclass*()
+ or
+ result =
+ API::moduleImport("playhouse")
+ .getMember("pool")
+ .getMember("PooledSqliteDatabase")
+ .getASubclass*()
+ or
+ result =
+ API::moduleImport("playhouse")
+ .getMember("pool")
+ .getMember("PooledSqliteExtDatabase")
+ .getASubclass*()
+ or
+ result =
+ API::moduleImport("playhouse")
+ .getMember("pool")
+ .getMember("_PooledPostgresqlDatabase")
+ .getASubclass*()
+ or
+ result =
+ API::moduleImport("playhouse")
+ .getMember("pool")
+ .getMember("_PooledSqliteDatabase")
+ .getASubclass*()
+ or
+ result =
+ API::moduleImport("playhouse")
+ .getMember("postgres_ext")
+ .getMember("PostgresqlExtDatabase")
+ .getASubclass*()
+ or
+ result =
+ API::moduleImport("playhouse")
+ .getMember("sqlcipher_ext")
+ .getMember("SqlCipherDatabase")
+ .getASubclass*()
+ or
+ result =
+ API::moduleImport("playhouse")
+ .getMember("sqlcipher_ext")
+ .getMember("SqlCipherExtDatabase")
+ .getASubclass*()
+ or
+ result =
+ API::moduleImport("playhouse")
+ .getMember("sqlite_ext")
+ .getMember("CSqliteExtDatabase")
+ .getASubclass*()
+ or
+ result =
+ API::moduleImport("playhouse")
+ .getMember("sqlite_ext")
+ .getMember("SqliteExtDatabase")
+ .getASubclass*()
+ or
+ result =
+ API::moduleImport("playhouse")
+ .getMember("sqliteq")
+ .getMember("SqliteQueueDatabase")
+ .getASubclass*()
+ }
+
+ /** Gets a reference to an instance of `peewee.Database` or any subclass. */
+ API::Node instance() { result = subclassRef().getReturn() }
+ }
+
+ /**
+ * A call to the `connection` method on a `peewee.Database` instance.
+ * https://docs.peewee-orm.com/en/latest/peewee/api.html#Database.connection.
+ */
+ class PeeweeDatabaseConnectionCall extends PEP249::Connection::InstanceSource,
+ DataFlow::CallCfgNode {
+ PeeweeDatabaseConnectionCall() {
+ this = Database::instance().getMember("connection").getACall()
+ }
+ }
+
+ /**
+ * A call to the `cursor` method on a `peewee.Database` instance.
+ * https://docs.peewee-orm.com/en/latest/peewee/api.html#Database.cursor.
+ */
+ class PeeweeDatabaseCursorCall extends PEP249::Cursor::InstanceSource, DataFlow::CallCfgNode {
+ PeeweeDatabaseCursorCall() { this = Database::instance().getMember("cursor").getACall() }
+ }
+
+ /**
+ * A call to the `execute_sql` method on a `peewee.Database` instance.
+ * See https://docs.peewee-orm.com/en/latest/peewee/api.html#Database.execute_sql.
+ */
+ class PeeweeDatabaseExecuteSqlCall extends SqlExecution::Range, DataFlow::CallCfgNode {
+ PeeweeDatabaseExecuteSqlCall() {
+ this = Database::instance().getMember("execute_sql").getACall()
+ }
+
+ override DataFlow::Node getSql() { result in [this.getArg(0), this.getArgByName("sql")] }
+ }
+}
diff --git a/python/ql/test/library-tests/frameworks/peewee/sql_execution.py b/python/ql/test/library-tests/frameworks/peewee/sql_execution.py
index c9146cad2eb..e6f195eeb47 100644
--- a/python/ql/test/library-tests/frameworks/peewee/sql_execution.py
+++ b/python/ql/test/library-tests/frameworks/peewee/sql_execution.py
@@ -7,13 +7,13 @@ db = peewee.MySQLDatabase()
conn = db.connection()
cursor = conn.cursor()
-cursor.execute("sql") # $ MISSING: getSql="sql"
+cursor.execute("sql") # $ getSql="sql"
cursor = db.cursor()
-cursor.execute("sql") # $ MISSING: getSql="sql"
+cursor.execute("sql") # $ getSql="sql"
-db.execute_sql("sql") # $ MISSING: getSql="sql"
+db.execute_sql("sql") # $ getSql="sql"
# Pool extension
pool = playhouse.pool.PooledMySQLDatabase(...)
-pool.execute_sql("sql") # $ MISSING: getSql="sql"
+pool.execute_sql("sql") # $ getSql="sql"
From 59711424bd88abf2caf7fb7459f471ea778baf9e Mon Sep 17 00:00:00 2001
From: Rasmus Wriedt Larsen
Date: Mon, 28 Jun 2021 11:48:28 +0200
Subject: [PATCH 098/429] Python: Fix qhelp for NoSQL injection
---
.../ql/src/experimental/Security/CWE-943/NoSQLInjection.qhelp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/python/ql/src/experimental/Security/CWE-943/NoSQLInjection.qhelp b/python/ql/src/experimental/Security/CWE-943/NoSQLInjection.qhelp
index 9771f8fd0d9..2bfd5682010 100644
--- a/python/ql/src/experimental/Security/CWE-943/NoSQLInjection.qhelp
+++ b/python/ql/src/experimental/Security/CWE-943/NoSQLInjection.qhelp
@@ -20,14 +20,14 @@
NoSQL injections can be prevented by escaping user-input's special characters that are passed into the NoSQL query from the user-supplied source.
Alternatively, using a sanitize library such as MongoSanitizer will ensure that user-supplied sources can not act as a malicious query.
-
+
In the example below, the user-supplied source is passed to a MongoDB function that queries the MongoDB database.
This can be fixed by using a sanitizer library like MongoSanitizer as shown in this annotated code version below.
-
+
Mongoengine: Documentation.
From 318694ccc86bc2251493e06b4b0e1a7dac6e206e Mon Sep 17 00:00:00 2001
From: Rasmus Wriedt Larsen
Date: Mon, 28 Jun 2021 13:17:45 +0200
Subject: [PATCH 099/429] Python: Don't rely on `d = d.getOutput()` for
`Decoding`
Although it is for `json.loads` and the like.
---
.../semmle/python/security/injection/NoSQLInjection.qll | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/python/ql/src/experimental/semmle/python/security/injection/NoSQLInjection.qll b/python/ql/src/experimental/semmle/python/security/injection/NoSQLInjection.qll
index b15a844605c..fb3890d2f7e 100644
--- a/python/ql/src/experimental/semmle/python/security/injection/NoSQLInjection.qll
+++ b/python/ql/src/experimental/semmle/python/security/injection/NoSQLInjection.qll
@@ -17,7 +17,7 @@ class RFSToDictConfig extends TaintTracking::Configuration {
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
override predicate isSink(DataFlow::Node sink) {
- exists(Decoding decoding | decoding.getFormat() = "JSON" and sink = decoding)
+ exists(Decoding decoding | decoding.getFormat() = "JSON" and sink = decoding.getOutput())
}
override predicate isSanitizer(DataFlow::Node sanitizer) {
@@ -32,7 +32,7 @@ class FromDataDictToSink extends TaintTracking2::Configuration {
FromDataDictToSink() { this = "FromDataDictToSink" }
override predicate isSource(DataFlow::Node source) {
- exists(Decoding decoding | decoding.getFormat() = "JSON" and source = decoding)
+ exists(Decoding decoding | decoding.getFormat() = "JSON" and source = decoding.getOutput())
}
override predicate isSink(DataFlow::Node sink) { sink = any(NoSQLQuery noSQLQuery).getQuery() }
From 0ca4f240d907a8d1f74fc6f6bf578d23bacebcd8 Mon Sep 17 00:00:00 2001
From: jorgectf
Date: Mon, 28 Jun 2021 20:13:53 +0200
Subject: [PATCH 100/429] Merge tests and update `.expected`
---
.../Security/CWE-943/NoSQLInjection.expected | 272 +++++++++---------
...get_db_bad.py => flask_mongoengine_bad.py} | 13 +-
...sk_mongoengine_db_document_subclass_bad.py | 24 --
...k_mongoengine_db_document_subclass_good.py | 26 --
...t_db_good.py => flask_mongoengine_good.py} | 12 +-
.../Security/CWE-943/mongoengine_bad.py | 64 +++++
.../CWE-943/mongoengine_connect_bad.py | 24 --
.../CWE-943/mongoengine_connect_good.py | 26 --
.../mongoengine_connect_via_connection_bad.py | 25 --
...mongoengine_connect_via_connection_good.py | 27 --
.../mongoengine_document_subclass_bad.py | 23 --
.../mongoengine_document_subclass_good.py | 25 --
.../CWE-943/mongoengine_get_db_bad.py | 24 --
.../CWE-943/mongoengine_get_db_good.py | 26 --
.../mongoengine_get_db_via_connection_bad.py | 25 --
.../mongoengine_get_db_via_connection_good.py | 27 --
.../Security/CWE-943/mongoengine_good.py | 68 +++++
.../CWE-943/mongoengine_subscript_bad.py | 24 --
.../CWE-943/mongoengine_subscript_good.py | 26 --
19 files changed, 288 insertions(+), 493 deletions(-)
rename python/ql/test/experimental/query-tests/Security/CWE-943/{flask_mongoengine_get_db_bad.py => flask_mongoengine_bad.py} (60%)
delete mode 100644 python/ql/test/experimental/query-tests/Security/CWE-943/flask_mongoengine_db_document_subclass_bad.py
delete mode 100644 python/ql/test/experimental/query-tests/Security/CWE-943/flask_mongoengine_db_document_subclass_good.py
rename python/ql/test/experimental/query-tests/Security/CWE-943/{flask_mongoengine_get_db_good.py => flask_mongoengine_good.py} (68%)
create mode 100644 python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_bad.py
delete mode 100644 python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_connect_bad.py
delete mode 100644 python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_connect_good.py
delete mode 100644 python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_connect_via_connection_bad.py
delete mode 100644 python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_connect_via_connection_good.py
delete mode 100644 python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_document_subclass_bad.py
delete mode 100644 python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_document_subclass_good.py
delete mode 100644 python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_get_db_bad.py
delete mode 100644 python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_get_db_good.py
delete mode 100644 python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_get_db_via_connection_bad.py
delete mode 100644 python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_get_db_via_connection_good.py
create mode 100644 python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_good.py
delete mode 100644 python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_subscript_bad.py
delete mode 100644 python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_subscript_good.py
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/NoSQLInjection.expected b/python/ql/test/experimental/query-tests/Security/CWE-943/NoSQLInjection.expected
index ad4a19510f1..10c1f852df5 100644
--- a/python/ql/test/experimental/query-tests/Security/CWE-943/NoSQLInjection.expected
+++ b/python/ql/test/experimental/query-tests/Security/CWE-943/NoSQLInjection.expected
@@ -1,18 +1,18 @@
edges
-| flask_mongoengine_db_document_subclass_bad.py:18:21:18:27 | ControlFlowNode for request | flask_mongoengine_db_document_subclass_bad.py:18:21:18:32 | ControlFlowNode for Attribute |
-| flask_mongoengine_db_document_subclass_bad.py:18:21:18:32 | ControlFlowNode for Attribute | flask_mongoengine_db_document_subclass_bad.py:18:21:18:42 | ControlFlowNode for Subscript |
-| flask_mongoengine_db_document_subclass_bad.py:18:21:18:42 | ControlFlowNode for Subscript | flask_mongoengine_db_document_subclass_bad.py:19:19:19:43 | ControlFlowNode for Attribute() |
-| flask_mongoengine_db_document_subclass_bad.py:19:19:19:43 | ControlFlowNode for Attribute() | flask_mongoengine_db_document_subclass_bad.py:21:34:21:44 | ControlFlowNode for json_search |
-| flask_mongoengine_db_document_subclass_good.py:19:21:19:27 | ControlFlowNode for request | flask_mongoengine_db_document_subclass_good.py:19:21:19:32 | ControlFlowNode for Attribute |
-| flask_mongoengine_db_document_subclass_good.py:19:21:19:32 | ControlFlowNode for Attribute | flask_mongoengine_db_document_subclass_good.py:19:21:19:42 | ControlFlowNode for Subscript |
-| flask_mongoengine_db_document_subclass_good.py:19:21:19:42 | ControlFlowNode for Subscript | flask_mongoengine_db_document_subclass_good.py:20:19:20:43 | ControlFlowNode for Attribute() |
-| flask_mongoengine_get_db_bad.py:19:21:19:27 | ControlFlowNode for request | flask_mongoengine_get_db_bad.py:19:21:19:32 | ControlFlowNode for Attribute |
-| flask_mongoengine_get_db_bad.py:19:21:19:32 | ControlFlowNode for Attribute | flask_mongoengine_get_db_bad.py:19:21:19:42 | ControlFlowNode for Subscript |
-| flask_mongoengine_get_db_bad.py:19:21:19:42 | ControlFlowNode for Subscript | flask_mongoengine_get_db_bad.py:20:19:20:43 | ControlFlowNode for Attribute() |
-| flask_mongoengine_get_db_bad.py:20:19:20:43 | ControlFlowNode for Attribute() | flask_mongoengine_get_db_bad.py:23:39:23:59 | ControlFlowNode for Dict |
-| flask_mongoengine_get_db_good.py:20:21:20:27 | ControlFlowNode for request | flask_mongoengine_get_db_good.py:20:21:20:32 | ControlFlowNode for Attribute |
-| flask_mongoengine_get_db_good.py:20:21:20:32 | ControlFlowNode for Attribute | flask_mongoengine_get_db_good.py:20:21:20:42 | ControlFlowNode for Subscript |
-| flask_mongoengine_get_db_good.py:20:21:20:42 | ControlFlowNode for Subscript | flask_mongoengine_get_db_good.py:21:19:21:43 | ControlFlowNode for Attribute() |
+| flask_mongoengine_bad.py:19:21:19:27 | ControlFlowNode for request | flask_mongoengine_bad.py:19:21:19:32 | ControlFlowNode for Attribute |
+| flask_mongoengine_bad.py:19:21:19:32 | ControlFlowNode for Attribute | flask_mongoengine_bad.py:19:21:19:42 | ControlFlowNode for Subscript |
+| flask_mongoengine_bad.py:19:21:19:42 | ControlFlowNode for Subscript | flask_mongoengine_bad.py:20:19:20:43 | ControlFlowNode for Attribute() |
+| flask_mongoengine_bad.py:20:19:20:43 | ControlFlowNode for Attribute() | flask_mongoengine_bad.py:22:34:22:44 | ControlFlowNode for json_search |
+| flask_mongoengine_bad.py:26:21:26:27 | ControlFlowNode for request | flask_mongoengine_bad.py:26:21:26:32 | ControlFlowNode for Attribute |
+| flask_mongoengine_bad.py:26:21:26:32 | ControlFlowNode for Attribute | flask_mongoengine_bad.py:26:21:26:42 | ControlFlowNode for Subscript |
+| flask_mongoengine_bad.py:26:21:26:42 | ControlFlowNode for Subscript | flask_mongoengine_bad.py:27:19:27:43 | ControlFlowNode for Attribute() |
+| flask_mongoengine_bad.py:27:19:27:43 | ControlFlowNode for Attribute() | flask_mongoengine_bad.py:30:39:30:59 | ControlFlowNode for Dict |
+| flask_mongoengine_good.py:20:21:20:27 | ControlFlowNode for request | flask_mongoengine_good.py:20:21:20:32 | ControlFlowNode for Attribute |
+| flask_mongoengine_good.py:20:21:20:32 | ControlFlowNode for Attribute | flask_mongoengine_good.py:20:21:20:42 | ControlFlowNode for Subscript |
+| flask_mongoengine_good.py:20:21:20:42 | ControlFlowNode for Subscript | flask_mongoengine_good.py:21:19:21:43 | ControlFlowNode for Attribute() |
+| flask_mongoengine_good.py:28:21:28:27 | ControlFlowNode for request | flask_mongoengine_good.py:28:21:28:32 | ControlFlowNode for Attribute |
+| flask_mongoengine_good.py:28:21:28:32 | ControlFlowNode for Attribute | flask_mongoengine_good.py:28:21:28:42 | ControlFlowNode for Subscript |
+| flask_mongoengine_good.py:28:21:28:42 | ControlFlowNode for Subscript | flask_mongoengine_good.py:29:19:29:43 | ControlFlowNode for Attribute() |
| flask_pymongo_bad.py:11:21:11:27 | ControlFlowNode for request | flask_pymongo_bad.py:11:21:11:32 | ControlFlowNode for Attribute |
| flask_pymongo_bad.py:11:21:11:32 | ControlFlowNode for Attribute | flask_pymongo_bad.py:11:21:11:42 | ControlFlowNode for Subscript |
| flask_pymongo_bad.py:11:21:11:42 | ControlFlowNode for Subscript | flask_pymongo_bad.py:12:19:12:43 | ControlFlowNode for Attribute() |
@@ -20,48 +20,48 @@ edges
| flask_pymongo_good.py:12:21:12:27 | ControlFlowNode for request | flask_pymongo_good.py:12:21:12:32 | ControlFlowNode for Attribute |
| flask_pymongo_good.py:12:21:12:32 | ControlFlowNode for Attribute | flask_pymongo_good.py:12:21:12:42 | ControlFlowNode for Subscript |
| flask_pymongo_good.py:12:21:12:42 | ControlFlowNode for Subscript | flask_pymongo_good.py:13:19:13:43 | ControlFlowNode for Attribute() |
-| mongoengine_connect_bad.py:17:21:17:27 | ControlFlowNode for request | mongoengine_connect_bad.py:17:21:17:32 | ControlFlowNode for Attribute |
-| mongoengine_connect_bad.py:17:21:17:32 | ControlFlowNode for Attribute | mongoengine_connect_bad.py:17:21:17:42 | ControlFlowNode for Subscript |
-| mongoengine_connect_bad.py:17:21:17:42 | ControlFlowNode for Subscript | mongoengine_connect_bad.py:18:19:18:43 | ControlFlowNode for Attribute() |
-| mongoengine_connect_bad.py:18:19:18:43 | ControlFlowNode for Attribute() | mongoengine_connect_bad.py:21:26:21:46 | ControlFlowNode for Dict |
-| mongoengine_connect_good.py:18:21:18:27 | ControlFlowNode for request | mongoengine_connect_good.py:18:21:18:32 | ControlFlowNode for Attribute |
-| mongoengine_connect_good.py:18:21:18:32 | ControlFlowNode for Attribute | mongoengine_connect_good.py:18:21:18:42 | ControlFlowNode for Subscript |
-| mongoengine_connect_good.py:18:21:18:42 | ControlFlowNode for Subscript | mongoengine_connect_good.py:19:19:19:43 | ControlFlowNode for Attribute() |
-| mongoengine_connect_via_connection_bad.py:18:21:18:27 | ControlFlowNode for request | mongoengine_connect_via_connection_bad.py:18:21:18:32 | ControlFlowNode for Attribute |
-| mongoengine_connect_via_connection_bad.py:18:21:18:32 | ControlFlowNode for Attribute | mongoengine_connect_via_connection_bad.py:18:21:18:42 | ControlFlowNode for Subscript |
-| mongoengine_connect_via_connection_bad.py:18:21:18:42 | ControlFlowNode for Subscript | mongoengine_connect_via_connection_bad.py:19:19:19:43 | ControlFlowNode for Attribute() |
-| mongoengine_connect_via_connection_bad.py:19:19:19:43 | ControlFlowNode for Attribute() | mongoengine_connect_via_connection_bad.py:22:26:22:46 | ControlFlowNode for Dict |
-| mongoengine_connect_via_connection_good.py:19:21:19:27 | ControlFlowNode for request | mongoengine_connect_via_connection_good.py:19:21:19:32 | ControlFlowNode for Attribute |
-| mongoengine_connect_via_connection_good.py:19:21:19:32 | ControlFlowNode for Attribute | mongoengine_connect_via_connection_good.py:19:21:19:42 | ControlFlowNode for Subscript |
-| mongoengine_connect_via_connection_good.py:19:21:19:42 | ControlFlowNode for Subscript | mongoengine_connect_via_connection_good.py:20:19:20:43 | ControlFlowNode for Attribute() |
-| mongoengine_document_subclass_bad.py:17:21:17:27 | ControlFlowNode for request | mongoengine_document_subclass_bad.py:17:21:17:32 | ControlFlowNode for Attribute |
-| mongoengine_document_subclass_bad.py:17:21:17:32 | ControlFlowNode for Attribute | mongoengine_document_subclass_bad.py:17:21:17:42 | ControlFlowNode for Subscript |
-| mongoengine_document_subclass_bad.py:17:21:17:42 | ControlFlowNode for Subscript | mongoengine_document_subclass_bad.py:18:19:18:43 | ControlFlowNode for Attribute() |
-| mongoengine_document_subclass_bad.py:18:19:18:43 | ControlFlowNode for Attribute() | mongoengine_document_subclass_bad.py:20:34:20:44 | ControlFlowNode for json_search |
-| mongoengine_document_subclass_good.py:18:21:18:27 | ControlFlowNode for request | mongoengine_document_subclass_good.py:18:21:18:32 | ControlFlowNode for Attribute |
-| mongoengine_document_subclass_good.py:18:21:18:32 | ControlFlowNode for Attribute | mongoengine_document_subclass_good.py:18:21:18:42 | ControlFlowNode for Subscript |
-| mongoengine_document_subclass_good.py:18:21:18:42 | ControlFlowNode for Subscript | mongoengine_document_subclass_good.py:19:19:19:43 | ControlFlowNode for Attribute() |
-| mongoengine_get_db_bad.py:17:21:17:27 | ControlFlowNode for request | mongoengine_get_db_bad.py:17:21:17:32 | ControlFlowNode for Attribute |
-| mongoengine_get_db_bad.py:17:21:17:32 | ControlFlowNode for Attribute | mongoengine_get_db_bad.py:17:21:17:42 | ControlFlowNode for Subscript |
-| mongoengine_get_db_bad.py:17:21:17:42 | ControlFlowNode for Subscript | mongoengine_get_db_bad.py:18:19:18:43 | ControlFlowNode for Attribute() |
-| mongoengine_get_db_bad.py:18:19:18:43 | ControlFlowNode for Attribute() | mongoengine_get_db_bad.py:21:26:21:46 | ControlFlowNode for Dict |
-| mongoengine_get_db_good.py:18:21:18:27 | ControlFlowNode for request | mongoengine_get_db_good.py:18:21:18:32 | ControlFlowNode for Attribute |
-| mongoengine_get_db_good.py:18:21:18:32 | ControlFlowNode for Attribute | mongoengine_get_db_good.py:18:21:18:42 | ControlFlowNode for Subscript |
-| mongoengine_get_db_good.py:18:21:18:42 | ControlFlowNode for Subscript | mongoengine_get_db_good.py:19:19:19:43 | ControlFlowNode for Attribute() |
-| mongoengine_get_db_via_connection_bad.py:18:21:18:27 | ControlFlowNode for request | mongoengine_get_db_via_connection_bad.py:18:21:18:32 | ControlFlowNode for Attribute |
-| mongoengine_get_db_via_connection_bad.py:18:21:18:32 | ControlFlowNode for Attribute | mongoengine_get_db_via_connection_bad.py:18:21:18:42 | ControlFlowNode for Subscript |
-| mongoengine_get_db_via_connection_bad.py:18:21:18:42 | ControlFlowNode for Subscript | mongoengine_get_db_via_connection_bad.py:19:19:19:43 | ControlFlowNode for Attribute() |
-| mongoengine_get_db_via_connection_bad.py:19:19:19:43 | ControlFlowNode for Attribute() | mongoengine_get_db_via_connection_bad.py:22:26:22:46 | ControlFlowNode for Dict |
-| mongoengine_get_db_via_connection_good.py:19:21:19:27 | ControlFlowNode for request | mongoengine_get_db_via_connection_good.py:19:21:19:32 | ControlFlowNode for Attribute |
-| mongoengine_get_db_via_connection_good.py:19:21:19:32 | ControlFlowNode for Attribute | mongoengine_get_db_via_connection_good.py:19:21:19:42 | ControlFlowNode for Subscript |
-| mongoengine_get_db_via_connection_good.py:19:21:19:42 | ControlFlowNode for Subscript | mongoengine_get_db_via_connection_good.py:20:19:20:43 | ControlFlowNode for Attribute() |
-| mongoengine_subscript_bad.py:17:21:17:27 | ControlFlowNode for request | mongoengine_subscript_bad.py:17:21:17:32 | ControlFlowNode for Attribute |
-| mongoengine_subscript_bad.py:17:21:17:32 | ControlFlowNode for Attribute | mongoengine_subscript_bad.py:17:21:17:42 | ControlFlowNode for Subscript |
-| mongoengine_subscript_bad.py:17:21:17:42 | ControlFlowNode for Subscript | mongoengine_subscript_bad.py:18:19:18:43 | ControlFlowNode for Attribute() |
-| mongoengine_subscript_bad.py:18:19:18:43 | ControlFlowNode for Attribute() | mongoengine_subscript_bad.py:21:29:21:49 | ControlFlowNode for Dict |
-| mongoengine_subscript_good.py:18:21:18:27 | ControlFlowNode for request | mongoengine_subscript_good.py:18:21:18:32 | ControlFlowNode for Attribute |
-| mongoengine_subscript_good.py:18:21:18:32 | ControlFlowNode for Attribute | mongoengine_subscript_good.py:18:21:18:42 | ControlFlowNode for Subscript |
-| mongoengine_subscript_good.py:18:21:18:42 | ControlFlowNode for Subscript | mongoengine_subscript_good.py:19:19:19:43 | ControlFlowNode for Attribute() |
+| mongoengine_bad.py:18:21:18:27 | ControlFlowNode for request | mongoengine_bad.py:18:21:18:32 | ControlFlowNode for Attribute |
+| mongoengine_bad.py:18:21:18:32 | ControlFlowNode for Attribute | mongoengine_bad.py:18:21:18:42 | ControlFlowNode for Subscript |
+| mongoengine_bad.py:18:21:18:42 | ControlFlowNode for Subscript | mongoengine_bad.py:19:19:19:43 | ControlFlowNode for Attribute() |
+| mongoengine_bad.py:19:19:19:43 | ControlFlowNode for Attribute() | mongoengine_bad.py:22:26:22:46 | ControlFlowNode for Dict |
+| mongoengine_bad.py:26:21:26:27 | ControlFlowNode for request | mongoengine_bad.py:26:21:26:32 | ControlFlowNode for Attribute |
+| mongoengine_bad.py:26:21:26:32 | ControlFlowNode for Attribute | mongoengine_bad.py:26:21:26:42 | ControlFlowNode for Subscript |
+| mongoengine_bad.py:26:21:26:42 | ControlFlowNode for Subscript | mongoengine_bad.py:27:19:27:43 | ControlFlowNode for Attribute() |
+| mongoengine_bad.py:27:19:27:43 | ControlFlowNode for Attribute() | mongoengine_bad.py:30:26:30:46 | ControlFlowNode for Dict |
+| mongoengine_bad.py:34:21:34:27 | ControlFlowNode for request | mongoengine_bad.py:34:21:34:32 | ControlFlowNode for Attribute |
+| mongoengine_bad.py:34:21:34:32 | ControlFlowNode for Attribute | mongoengine_bad.py:34:21:34:42 | ControlFlowNode for Subscript |
+| mongoengine_bad.py:34:21:34:42 | ControlFlowNode for Subscript | mongoengine_bad.py:35:19:35:43 | ControlFlowNode for Attribute() |
+| mongoengine_bad.py:35:19:35:43 | ControlFlowNode for Attribute() | mongoengine_bad.py:38:26:38:46 | ControlFlowNode for Dict |
+| mongoengine_bad.py:42:21:42:27 | ControlFlowNode for request | mongoengine_bad.py:42:21:42:32 | ControlFlowNode for Attribute |
+| mongoengine_bad.py:42:21:42:32 | ControlFlowNode for Attribute | mongoengine_bad.py:42:21:42:42 | ControlFlowNode for Subscript |
+| mongoengine_bad.py:42:21:42:42 | ControlFlowNode for Subscript | mongoengine_bad.py:43:19:43:43 | ControlFlowNode for Attribute() |
+| mongoengine_bad.py:43:19:43:43 | ControlFlowNode for Attribute() | mongoengine_bad.py:46:26:46:46 | ControlFlowNode for Dict |
+| mongoengine_bad.py:50:21:50:27 | ControlFlowNode for request | mongoengine_bad.py:50:21:50:32 | ControlFlowNode for Attribute |
+| mongoengine_bad.py:50:21:50:32 | ControlFlowNode for Attribute | mongoengine_bad.py:50:21:50:42 | ControlFlowNode for Subscript |
+| mongoengine_bad.py:50:21:50:42 | ControlFlowNode for Subscript | mongoengine_bad.py:51:19:51:43 | ControlFlowNode for Attribute() |
+| mongoengine_bad.py:51:19:51:43 | ControlFlowNode for Attribute() | mongoengine_bad.py:53:34:53:44 | ControlFlowNode for json_search |
+| mongoengine_bad.py:57:21:57:27 | ControlFlowNode for request | mongoengine_bad.py:57:21:57:32 | ControlFlowNode for Attribute |
+| mongoengine_bad.py:57:21:57:32 | ControlFlowNode for Attribute | mongoengine_bad.py:57:21:57:42 | ControlFlowNode for Subscript |
+| mongoengine_bad.py:57:21:57:42 | ControlFlowNode for Subscript | mongoengine_bad.py:58:19:58:43 | ControlFlowNode for Attribute() |
+| mongoengine_bad.py:58:19:58:43 | ControlFlowNode for Attribute() | mongoengine_bad.py:61:29:61:49 | ControlFlowNode for Dict |
+| mongoengine_good.py:19:21:19:27 | ControlFlowNode for request | mongoengine_good.py:19:21:19:32 | ControlFlowNode for Attribute |
+| mongoengine_good.py:19:21:19:32 | ControlFlowNode for Attribute | mongoengine_good.py:19:21:19:42 | ControlFlowNode for Subscript |
+| mongoengine_good.py:19:21:19:42 | ControlFlowNode for Subscript | mongoengine_good.py:20:19:20:43 | ControlFlowNode for Attribute() |
+| mongoengine_good.py:28:21:28:27 | ControlFlowNode for request | mongoengine_good.py:28:21:28:32 | ControlFlowNode for Attribute |
+| mongoengine_good.py:28:21:28:32 | ControlFlowNode for Attribute | mongoengine_good.py:28:21:28:42 | ControlFlowNode for Subscript |
+| mongoengine_good.py:28:21:28:42 | ControlFlowNode for Subscript | mongoengine_good.py:29:19:29:43 | ControlFlowNode for Attribute() |
+| mongoengine_good.py:37:21:37:27 | ControlFlowNode for request | mongoengine_good.py:37:21:37:32 | ControlFlowNode for Attribute |
+| mongoengine_good.py:37:21:37:32 | ControlFlowNode for Attribute | mongoengine_good.py:37:21:37:42 | ControlFlowNode for Subscript |
+| mongoengine_good.py:37:21:37:42 | ControlFlowNode for Subscript | mongoengine_good.py:38:19:38:43 | ControlFlowNode for Attribute() |
+| mongoengine_good.py:45:21:45:27 | ControlFlowNode for request | mongoengine_good.py:45:21:45:32 | ControlFlowNode for Attribute |
+| mongoengine_good.py:45:21:45:32 | ControlFlowNode for Attribute | mongoengine_good.py:45:21:45:42 | ControlFlowNode for Subscript |
+| mongoengine_good.py:45:21:45:42 | ControlFlowNode for Subscript | mongoengine_good.py:46:19:46:43 | ControlFlowNode for Attribute() |
+| mongoengine_good.py:54:21:54:27 | ControlFlowNode for request | mongoengine_good.py:54:21:54:32 | ControlFlowNode for Attribute |
+| mongoengine_good.py:54:21:54:32 | ControlFlowNode for Attribute | mongoengine_good.py:54:21:54:42 | ControlFlowNode for Subscript |
+| mongoengine_good.py:54:21:54:42 | ControlFlowNode for Subscript | mongoengine_good.py:55:19:55:43 | ControlFlowNode for Attribute() |
+| mongoengine_good.py:63:21:63:27 | ControlFlowNode for request | mongoengine_good.py:63:21:63:32 | ControlFlowNode for Attribute |
+| mongoengine_good.py:63:21:63:32 | ControlFlowNode for Attribute | mongoengine_good.py:63:21:63:42 | ControlFlowNode for Subscript |
+| mongoengine_good.py:63:21:63:42 | ControlFlowNode for Subscript | mongoengine_good.py:64:19:64:43 | ControlFlowNode for Attribute() |
| pymongo_bad.py:11:21:11:27 | ControlFlowNode for request | pymongo_bad.py:11:21:11:32 | ControlFlowNode for Attribute |
| pymongo_bad.py:11:21:11:32 | ControlFlowNode for Attribute | pymongo_bad.py:11:21:11:42 | ControlFlowNode for Subscript |
| pymongo_bad.py:11:21:11:42 | ControlFlowNode for Subscript | pymongo_bad.py:12:19:12:43 | ControlFlowNode for Attribute() |
@@ -70,24 +70,24 @@ edges
| pymongo_good.py:12:21:12:32 | ControlFlowNode for Attribute | pymongo_good.py:12:21:12:42 | ControlFlowNode for Subscript |
| pymongo_good.py:12:21:12:42 | ControlFlowNode for Subscript | pymongo_good.py:13:19:13:43 | ControlFlowNode for Attribute() |
nodes
-| flask_mongoengine_db_document_subclass_bad.py:18:21:18:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
-| flask_mongoengine_db_document_subclass_bad.py:18:21:18:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
-| flask_mongoengine_db_document_subclass_bad.py:18:21:18:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
-| flask_mongoengine_db_document_subclass_bad.py:19:19:19:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
-| flask_mongoengine_db_document_subclass_bad.py:21:34:21:44 | ControlFlowNode for json_search | semmle.label | ControlFlowNode for json_search |
-| flask_mongoengine_db_document_subclass_good.py:19:21:19:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
-| flask_mongoengine_db_document_subclass_good.py:19:21:19:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
-| flask_mongoengine_db_document_subclass_good.py:19:21:19:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
-| flask_mongoengine_db_document_subclass_good.py:20:19:20:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
-| flask_mongoengine_get_db_bad.py:19:21:19:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
-| flask_mongoengine_get_db_bad.py:19:21:19:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
-| flask_mongoengine_get_db_bad.py:19:21:19:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
-| flask_mongoengine_get_db_bad.py:20:19:20:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
-| flask_mongoengine_get_db_bad.py:23:39:23:59 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict |
-| flask_mongoengine_get_db_good.py:20:21:20:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
-| flask_mongoengine_get_db_good.py:20:21:20:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
-| flask_mongoengine_get_db_good.py:20:21:20:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
-| flask_mongoengine_get_db_good.py:21:19:21:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
+| flask_mongoengine_bad.py:19:21:19:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
+| flask_mongoengine_bad.py:19:21:19:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
+| flask_mongoengine_bad.py:19:21:19:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
+| flask_mongoengine_bad.py:20:19:20:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
+| flask_mongoengine_bad.py:22:34:22:44 | ControlFlowNode for json_search | semmle.label | ControlFlowNode for json_search |
+| flask_mongoengine_bad.py:26:21:26:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
+| flask_mongoengine_bad.py:26:21:26:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
+| flask_mongoengine_bad.py:26:21:26:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
+| flask_mongoengine_bad.py:27:19:27:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
+| flask_mongoengine_bad.py:30:39:30:59 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict |
+| flask_mongoengine_good.py:20:21:20:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
+| flask_mongoengine_good.py:20:21:20:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
+| flask_mongoengine_good.py:20:21:20:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
+| flask_mongoengine_good.py:21:19:21:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
+| flask_mongoengine_good.py:28:21:28:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
+| flask_mongoengine_good.py:28:21:28:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
+| flask_mongoengine_good.py:28:21:28:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
+| flask_mongoengine_good.py:29:19:29:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
| flask_pymongo_bad.py:11:21:11:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
| flask_pymongo_bad.py:11:21:11:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
| flask_pymongo_bad.py:11:21:11:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
@@ -97,60 +97,60 @@ nodes
| flask_pymongo_good.py:12:21:12:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
| flask_pymongo_good.py:12:21:12:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
| flask_pymongo_good.py:13:19:13:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
-| mongoengine_connect_bad.py:17:21:17:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
-| mongoengine_connect_bad.py:17:21:17:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
-| mongoengine_connect_bad.py:17:21:17:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
-| mongoengine_connect_bad.py:18:19:18:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
-| mongoengine_connect_bad.py:21:26:21:46 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict |
-| mongoengine_connect_good.py:18:21:18:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
-| mongoengine_connect_good.py:18:21:18:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
-| mongoengine_connect_good.py:18:21:18:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
-| mongoengine_connect_good.py:19:19:19:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
-| mongoengine_connect_via_connection_bad.py:18:21:18:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
-| mongoengine_connect_via_connection_bad.py:18:21:18:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
-| mongoengine_connect_via_connection_bad.py:18:21:18:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
-| mongoengine_connect_via_connection_bad.py:19:19:19:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
-| mongoengine_connect_via_connection_bad.py:22:26:22:46 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict |
-| mongoengine_connect_via_connection_good.py:19:21:19:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
-| mongoengine_connect_via_connection_good.py:19:21:19:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
-| mongoengine_connect_via_connection_good.py:19:21:19:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
-| mongoengine_connect_via_connection_good.py:20:19:20:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
-| mongoengine_document_subclass_bad.py:17:21:17:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
-| mongoengine_document_subclass_bad.py:17:21:17:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
-| mongoengine_document_subclass_bad.py:17:21:17:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
-| mongoengine_document_subclass_bad.py:18:19:18:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
-| mongoengine_document_subclass_bad.py:20:34:20:44 | ControlFlowNode for json_search | semmle.label | ControlFlowNode for json_search |
-| mongoengine_document_subclass_good.py:18:21:18:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
-| mongoengine_document_subclass_good.py:18:21:18:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
-| mongoengine_document_subclass_good.py:18:21:18:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
-| mongoengine_document_subclass_good.py:19:19:19:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
-| mongoengine_get_db_bad.py:17:21:17:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
-| mongoengine_get_db_bad.py:17:21:17:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
-| mongoengine_get_db_bad.py:17:21:17:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
-| mongoengine_get_db_bad.py:18:19:18:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
-| mongoengine_get_db_bad.py:21:26:21:46 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict |
-| mongoengine_get_db_good.py:18:21:18:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
-| mongoengine_get_db_good.py:18:21:18:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
-| mongoengine_get_db_good.py:18:21:18:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
-| mongoengine_get_db_good.py:19:19:19:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
-| mongoengine_get_db_via_connection_bad.py:18:21:18:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
-| mongoengine_get_db_via_connection_bad.py:18:21:18:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
-| mongoengine_get_db_via_connection_bad.py:18:21:18:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
-| mongoengine_get_db_via_connection_bad.py:19:19:19:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
-| mongoengine_get_db_via_connection_bad.py:22:26:22:46 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict |
-| mongoengine_get_db_via_connection_good.py:19:21:19:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
-| mongoengine_get_db_via_connection_good.py:19:21:19:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
-| mongoengine_get_db_via_connection_good.py:19:21:19:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
-| mongoengine_get_db_via_connection_good.py:20:19:20:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
-| mongoengine_subscript_bad.py:17:21:17:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
-| mongoengine_subscript_bad.py:17:21:17:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
-| mongoengine_subscript_bad.py:17:21:17:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
-| mongoengine_subscript_bad.py:18:19:18:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
-| mongoengine_subscript_bad.py:21:29:21:49 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict |
-| mongoengine_subscript_good.py:18:21:18:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
-| mongoengine_subscript_good.py:18:21:18:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
-| mongoengine_subscript_good.py:18:21:18:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
-| mongoengine_subscript_good.py:19:19:19:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
+| mongoengine_bad.py:18:21:18:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
+| mongoengine_bad.py:18:21:18:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
+| mongoengine_bad.py:18:21:18:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
+| mongoengine_bad.py:19:19:19:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
+| mongoengine_bad.py:22:26:22:46 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict |
+| mongoengine_bad.py:26:21:26:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
+| mongoengine_bad.py:26:21:26:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
+| mongoengine_bad.py:26:21:26:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
+| mongoengine_bad.py:27:19:27:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
+| mongoengine_bad.py:30:26:30:46 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict |
+| mongoengine_bad.py:34:21:34:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
+| mongoengine_bad.py:34:21:34:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
+| mongoengine_bad.py:34:21:34:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
+| mongoengine_bad.py:35:19:35:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
+| mongoengine_bad.py:38:26:38:46 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict |
+| mongoengine_bad.py:42:21:42:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
+| mongoengine_bad.py:42:21:42:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
+| mongoengine_bad.py:42:21:42:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
+| mongoengine_bad.py:43:19:43:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
+| mongoengine_bad.py:46:26:46:46 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict |
+| mongoengine_bad.py:50:21:50:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
+| mongoengine_bad.py:50:21:50:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
+| mongoengine_bad.py:50:21:50:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
+| mongoengine_bad.py:51:19:51:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
+| mongoengine_bad.py:53:34:53:44 | ControlFlowNode for json_search | semmle.label | ControlFlowNode for json_search |
+| mongoengine_bad.py:57:21:57:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
+| mongoengine_bad.py:57:21:57:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
+| mongoengine_bad.py:57:21:57:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
+| mongoengine_bad.py:58:19:58:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
+| mongoengine_bad.py:61:29:61:49 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict |
+| mongoengine_good.py:19:21:19:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
+| mongoengine_good.py:19:21:19:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
+| mongoengine_good.py:19:21:19:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
+| mongoengine_good.py:20:19:20:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
+| mongoengine_good.py:28:21:28:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
+| mongoengine_good.py:28:21:28:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
+| mongoengine_good.py:28:21:28:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
+| mongoengine_good.py:29:19:29:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
+| mongoengine_good.py:37:21:37:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
+| mongoengine_good.py:37:21:37:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
+| mongoengine_good.py:37:21:37:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
+| mongoengine_good.py:38:19:38:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
+| mongoengine_good.py:45:21:45:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
+| mongoengine_good.py:45:21:45:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
+| mongoengine_good.py:45:21:45:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
+| mongoengine_good.py:46:19:46:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
+| mongoengine_good.py:54:21:54:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
+| mongoengine_good.py:54:21:54:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
+| mongoengine_good.py:54:21:54:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
+| mongoengine_good.py:55:19:55:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
+| mongoengine_good.py:63:21:63:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
+| mongoengine_good.py:63:21:63:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
+| mongoengine_good.py:63:21:63:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
+| mongoengine_good.py:64:19:64:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
| pymongo_bad.py:11:21:11:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
| pymongo_bad.py:11:21:11:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
| pymongo_bad.py:11:21:11:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
@@ -161,13 +161,13 @@ nodes
| pymongo_good.py:12:21:12:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
| pymongo_good.py:13:19:13:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
#select
-| flask_mongoengine_db_document_subclass_bad.py:21:34:21:44 | ControlFlowNode for json_search | flask_mongoengine_db_document_subclass_bad.py:18:21:18:27 | ControlFlowNode for request | flask_mongoengine_db_document_subclass_bad.py:21:34:21:44 | ControlFlowNode for json_search | $@ NoSQL query contains an unsanitized $@ | flask_mongoengine_db_document_subclass_bad.py:21:34:21:44 | ControlFlowNode for json_search | This | flask_mongoengine_db_document_subclass_bad.py:18:21:18:27 | ControlFlowNode for request | user-provided value |
-| flask_mongoengine_get_db_bad.py:23:39:23:59 | ControlFlowNode for Dict | flask_mongoengine_get_db_bad.py:19:21:19:27 | ControlFlowNode for request | flask_mongoengine_get_db_bad.py:23:39:23:59 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | flask_mongoengine_get_db_bad.py:23:39:23:59 | ControlFlowNode for Dict | This | flask_mongoengine_get_db_bad.py:19:21:19:27 | ControlFlowNode for request | user-provided value |
+| flask_mongoengine_bad.py:22:34:22:44 | ControlFlowNode for json_search | flask_mongoengine_bad.py:19:21:19:27 | ControlFlowNode for request | flask_mongoengine_bad.py:22:34:22:44 | ControlFlowNode for json_search | $@ NoSQL query contains an unsanitized $@ | flask_mongoengine_bad.py:22:34:22:44 | ControlFlowNode for json_search | This | flask_mongoengine_bad.py:19:21:19:27 | ControlFlowNode for request | user-provided value |
+| flask_mongoengine_bad.py:30:39:30:59 | ControlFlowNode for Dict | flask_mongoengine_bad.py:26:21:26:27 | ControlFlowNode for request | flask_mongoengine_bad.py:30:39:30:59 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | flask_mongoengine_bad.py:30:39:30:59 | ControlFlowNode for Dict | This | flask_mongoengine_bad.py:26:21:26:27 | ControlFlowNode for request | user-provided value |
| flask_pymongo_bad.py:14:31:14:51 | ControlFlowNode for Dict | flask_pymongo_bad.py:11:21:11:27 | ControlFlowNode for request | flask_pymongo_bad.py:14:31:14:51 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | flask_pymongo_bad.py:14:31:14:51 | ControlFlowNode for Dict | This | flask_pymongo_bad.py:11:21:11:27 | ControlFlowNode for request | user-provided value |
-| mongoengine_connect_bad.py:21:26:21:46 | ControlFlowNode for Dict | mongoengine_connect_bad.py:17:21:17:27 | ControlFlowNode for request | mongoengine_connect_bad.py:21:26:21:46 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | mongoengine_connect_bad.py:21:26:21:46 | ControlFlowNode for Dict | This | mongoengine_connect_bad.py:17:21:17:27 | ControlFlowNode for request | user-provided value |
-| mongoengine_connect_via_connection_bad.py:22:26:22:46 | ControlFlowNode for Dict | mongoengine_connect_via_connection_bad.py:18:21:18:27 | ControlFlowNode for request | mongoengine_connect_via_connection_bad.py:22:26:22:46 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | mongoengine_connect_via_connection_bad.py:22:26:22:46 | ControlFlowNode for Dict | This | mongoengine_connect_via_connection_bad.py:18:21:18:27 | ControlFlowNode for request | user-provided value |
-| mongoengine_document_subclass_bad.py:20:34:20:44 | ControlFlowNode for json_search | mongoengine_document_subclass_bad.py:17:21:17:27 | ControlFlowNode for request | mongoengine_document_subclass_bad.py:20:34:20:44 | ControlFlowNode for json_search | $@ NoSQL query contains an unsanitized $@ | mongoengine_document_subclass_bad.py:20:34:20:44 | ControlFlowNode for json_search | This | mongoengine_document_subclass_bad.py:17:21:17:27 | ControlFlowNode for request | user-provided value |
-| mongoengine_get_db_bad.py:21:26:21:46 | ControlFlowNode for Dict | mongoengine_get_db_bad.py:17:21:17:27 | ControlFlowNode for request | mongoengine_get_db_bad.py:21:26:21:46 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | mongoengine_get_db_bad.py:21:26:21:46 | ControlFlowNode for Dict | This | mongoengine_get_db_bad.py:17:21:17:27 | ControlFlowNode for request | user-provided value |
-| mongoengine_get_db_via_connection_bad.py:22:26:22:46 | ControlFlowNode for Dict | mongoengine_get_db_via_connection_bad.py:18:21:18:27 | ControlFlowNode for request | mongoengine_get_db_via_connection_bad.py:22:26:22:46 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | mongoengine_get_db_via_connection_bad.py:22:26:22:46 | ControlFlowNode for Dict | This | mongoengine_get_db_via_connection_bad.py:18:21:18:27 | ControlFlowNode for request | user-provided value |
-| mongoengine_subscript_bad.py:21:29:21:49 | ControlFlowNode for Dict | mongoengine_subscript_bad.py:17:21:17:27 | ControlFlowNode for request | mongoengine_subscript_bad.py:21:29:21:49 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | mongoengine_subscript_bad.py:21:29:21:49 | ControlFlowNode for Dict | This | mongoengine_subscript_bad.py:17:21:17:27 | ControlFlowNode for request | user-provided value |
+| mongoengine_bad.py:22:26:22:46 | ControlFlowNode for Dict | mongoengine_bad.py:18:21:18:27 | ControlFlowNode for request | mongoengine_bad.py:22:26:22:46 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | mongoengine_bad.py:22:26:22:46 | ControlFlowNode for Dict | This | mongoengine_bad.py:18:21:18:27 | ControlFlowNode for request | user-provided value |
+| mongoengine_bad.py:30:26:30:46 | ControlFlowNode for Dict | mongoengine_bad.py:26:21:26:27 | ControlFlowNode for request | mongoengine_bad.py:30:26:30:46 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | mongoengine_bad.py:30:26:30:46 | ControlFlowNode for Dict | This | mongoengine_bad.py:26:21:26:27 | ControlFlowNode for request | user-provided value |
+| mongoengine_bad.py:38:26:38:46 | ControlFlowNode for Dict | mongoengine_bad.py:34:21:34:27 | ControlFlowNode for request | mongoengine_bad.py:38:26:38:46 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | mongoengine_bad.py:38:26:38:46 | ControlFlowNode for Dict | This | mongoengine_bad.py:34:21:34:27 | ControlFlowNode for request | user-provided value |
+| mongoengine_bad.py:46:26:46:46 | ControlFlowNode for Dict | mongoengine_bad.py:42:21:42:27 | ControlFlowNode for request | mongoengine_bad.py:46:26:46:46 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | mongoengine_bad.py:46:26:46:46 | ControlFlowNode for Dict | This | mongoengine_bad.py:42:21:42:27 | ControlFlowNode for request | user-provided value |
+| mongoengine_bad.py:53:34:53:44 | ControlFlowNode for json_search | mongoengine_bad.py:50:21:50:27 | ControlFlowNode for request | mongoengine_bad.py:53:34:53:44 | ControlFlowNode for json_search | $@ NoSQL query contains an unsanitized $@ | mongoengine_bad.py:53:34:53:44 | ControlFlowNode for json_search | This | mongoengine_bad.py:50:21:50:27 | ControlFlowNode for request | user-provided value |
+| mongoengine_bad.py:61:29:61:49 | ControlFlowNode for Dict | mongoengine_bad.py:57:21:57:27 | ControlFlowNode for request | mongoengine_bad.py:61:29:61:49 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | mongoengine_bad.py:61:29:61:49 | ControlFlowNode for Dict | This | mongoengine_bad.py:57:21:57:27 | ControlFlowNode for request | user-provided value |
| pymongo_bad.py:14:42:14:62 | ControlFlowNode for Dict | pymongo_bad.py:11:21:11:27 | ControlFlowNode for request | pymongo_bad.py:14:42:14:62 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | pymongo_bad.py:14:42:14:62 | ControlFlowNode for Dict | This | pymongo_bad.py:11:21:11:27 | ControlFlowNode for request | user-provided value |
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/flask_mongoengine_get_db_bad.py b/python/ql/test/experimental/query-tests/Security/CWE-943/flask_mongoengine_bad.py
similarity index 60%
rename from python/ql/test/experimental/query-tests/Security/CWE-943/flask_mongoengine_get_db_bad.py
rename to python/ql/test/experimental/query-tests/Security/CWE-943/flask_mongoengine_bad.py
index 468e1d865a7..9fc8aaefc0f 100644
--- a/python/ql/test/experimental/query-tests/Security/CWE-943/flask_mongoengine_get_db_bad.py
+++ b/python/ql/test/experimental/query-tests/Security/CWE-943/flask_mongoengine_bad.py
@@ -14,13 +14,20 @@ class Movie(db.Document):
Movie(title='test').save()
-@app.route("/")
-def home_page():
+@app.route("/subclass_objects")
+def subclass_objects():
+ unsafe_search = request.args['search']
+ json_search = json.loads(unsafe_search)
+
+ return Movie.objects(__raw__=json_search)
+
+@app.route("/get_db_find")
+def get_db_find():
unsafe_search = request.args['search']
json_search = json.loads(unsafe_search)
retrieved_db = db.get_db()
- data = retrieved_db["Movie"].find({'name': json_search})
+ return retrieved_db["Movie"].find({'name': json_search})
# if __name__ == "__main__":
# app.run(debug=True)
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/flask_mongoengine_db_document_subclass_bad.py b/python/ql/test/experimental/query-tests/Security/CWE-943/flask_mongoengine_db_document_subclass_bad.py
deleted file mode 100644
index f55f3270f47..00000000000
--- a/python/ql/test/experimental/query-tests/Security/CWE-943/flask_mongoengine_db_document_subclass_bad.py
+++ /dev/null
@@ -1,24 +0,0 @@
-from flask import Flask, request
-from flask_mongoengine import MongoEngine
-import json
-
-app = Flask(__name__)
-app.config.from_pyfile('the-config.cfg')
-db = MongoEngine(app)
-
-class Movie(db.Document):
- title = db.StringField(required=True)
-
-
-Movie(title='test').save()
-
-
-@app.route("/")
-def home_page():
- unsafe_search = request.args['search']
- json_search = json.loads(unsafe_search)
-
- data = Movie.objects(__raw__=json_search)
-
-# if __name__ == "__main__":
-# app.run(debug=True)
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/flask_mongoengine_db_document_subclass_good.py b/python/ql/test/experimental/query-tests/Security/CWE-943/flask_mongoengine_db_document_subclass_good.py
deleted file mode 100644
index c0a03d718aa..00000000000
--- a/python/ql/test/experimental/query-tests/Security/CWE-943/flask_mongoengine_db_document_subclass_good.py
+++ /dev/null
@@ -1,26 +0,0 @@
-from flask import Flask, request
-from flask_mongoengine import MongoEngine
-from mongosanitizer.sanitizer import sanitize
-import json
-
-app = Flask(__name__)
-app.config.from_pyfile('the-config.cfg')
-db = MongoEngine(app)
-
-class Movie(db.Document):
- title = db.StringField(required=True)
-
-
-Movie(title='test').save()
-
-
-@app.route("/")
-def home_page():
- unsafe_search = request.args['search']
- json_search = json.loads(unsafe_search)
- safe_search = sanitize(json_search)
-
- data = Movie.objects(__raw__=safe_search)
-
-# if __name__ == "__main__":
-# app.run(debug=True)
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/flask_mongoengine_get_db_good.py b/python/ql/test/experimental/query-tests/Security/CWE-943/flask_mongoengine_good.py
similarity index 68%
rename from python/ql/test/experimental/query-tests/Security/CWE-943/flask_mongoengine_get_db_good.py
rename to python/ql/test/experimental/query-tests/Security/CWE-943/flask_mongoengine_good.py
index 5837eaa2d58..abfcfaba48c 100644
--- a/python/ql/test/experimental/query-tests/Security/CWE-943/flask_mongoengine_get_db_good.py
+++ b/python/ql/test/experimental/query-tests/Security/CWE-943/flask_mongoengine_good.py
@@ -15,8 +15,16 @@ class Movie(db.Document):
Movie(title='test').save()
-@app.route("/")
-def home_page():
+@app.route("/subclass_objects")
+def subclass_objects():
+ unsafe_search = request.args['search']
+ json_search = json.loads(unsafe_search)
+ safe_search = sanitize(json_search)
+
+ return Movie.objects(__raw__=safe_search)
+
+@app.route("/get_db_find")
+def get_db_find():
unsafe_search = request.args['search']
json_search = json.loads(unsafe_search)
safe_search = sanitize(json_search)
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_bad.py b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_bad.py
new file mode 100644
index 00000000000..81800425e46
--- /dev/null
+++ b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_bad.py
@@ -0,0 +1,64 @@
+from flask import Flask, request
+import mongoengine as me
+from mongoengine.connection import get_db, connect
+import json
+
+app = Flask(__name__)
+
+
+class Movie(me.Document):
+ title = me.StringField(required=True)
+
+
+Movie(title='test').save()
+
+
+@app.route("/connect_find")
+def connect_find():
+ unsafe_search = request.args['search']
+ json_search = json.loads(unsafe_search)
+
+ db = me.connect('mydb')
+ return db.movie.find({'name': json_search})
+
+@app.route("/connection_connect_find")
+def connection_connect_find():
+ unsafe_search = request.args['search']
+ json_search = json.loads(unsafe_search)
+
+ db = connect('mydb')
+ return db.movie.find({'name': json_search})
+
+@app.route("/get_db_find")
+def get_db_find():
+ unsafe_search = request.args['search']
+ json_search = json.loads(unsafe_search)
+
+ db = me.get_db()
+ return db.movie.find({'name': json_search})
+
+@app.route("/connection_get_db_find")
+def connection_get_db_find():
+ unsafe_search = request.args['search']
+ json_search = json.loads(unsafe_search)
+
+ db = get_db()
+ return db.movie.find({'name': json_search})
+
+@app.route("/subclass_objects")
+def subclass_objects():
+ unsafe_search = request.args['search']
+ json_search = json.loads(unsafe_search)
+
+ return Movie.objects(__raw__=json_search)
+
+@app.route("/subscript_find")
+def subscript_find():
+ unsafe_search = request.args['search']
+ json_search = json.loads(unsafe_search)
+
+ db = me.connect('mydb')
+ return db['movie'].find({'name': json_search})
+
+# if __name__ == "__main__":
+# app.run(debug=True)
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_connect_bad.py b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_connect_bad.py
deleted file mode 100644
index 1443f72720d..00000000000
--- a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_connect_bad.py
+++ /dev/null
@@ -1,24 +0,0 @@
-from flask import Flask, request
-import mongoengine as me
-import json
-
-app = Flask(__name__)
-
-
-class Movie(me.Document):
- title = me.StringField(required=True)
-
-
-Movie(title='test').save()
-
-
-@app.route("/")
-def home_page():
- unsafe_search = request.args['search']
- json_search = json.loads(unsafe_search)
-
- db = me.connect('mydb')
- data = db.movie.find({'name': json_search})
-
-# if __name__ == "__main__":
-# app.run(debug=True)
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_connect_good.py b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_connect_good.py
deleted file mode 100644
index 219503a213a..00000000000
--- a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_connect_good.py
+++ /dev/null
@@ -1,26 +0,0 @@
-from flask import Flask, request
-import mongoengine as me
-from mongosanitizer.sanitizer import sanitize
-import json
-
-app = Flask(__name__)
-
-
-class Movie(me.Document):
- title = me.StringField(required=True)
-
-
-Movie(title='test').save()
-
-
-@app.route("/")
-def home_page():
- unsafe_search = request.args['search']
- json_search = json.loads(unsafe_search)
- safe_search = sanitize(json_search)
-
- db = me.connect('mydb')
- data = db.movie.find({'name': json_search})
-
-# if __name__ == "__main__":
-# app.run(debug=True)
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_connect_via_connection_bad.py b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_connect_via_connection_bad.py
deleted file mode 100644
index 398199bc0cd..00000000000
--- a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_connect_via_connection_bad.py
+++ /dev/null
@@ -1,25 +0,0 @@
-from flask import Flask, request
-import mongoengine as me
-from mongoengine.connection import get_db, connect
-import json
-
-app = Flask(__name__)
-
-
-class Movie(me.Document):
- title = me.StringField(required=True)
-
-
-Movie(title='test').save()
-
-
-@app.route("/")
-def home_page():
- unsafe_search = request.args['search']
- json_search = json.loads(unsafe_search)
-
- db = connect('mydb')
- data = db.movie.find({'name': json_search})
-
-# if __name__ == "__main__":
-# app.run(debug=True)
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_connect_via_connection_good.py b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_connect_via_connection_good.py
deleted file mode 100644
index 51b801468ce..00000000000
--- a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_connect_via_connection_good.py
+++ /dev/null
@@ -1,27 +0,0 @@
-from flask import Flask, request
-import mongoengine as me
-from mongoengine.connection import get_db, connect
-from mongosanitizer.sanitizer import sanitize
-import json
-
-app = Flask(__name__)
-
-
-class Movie(me.Document):
- title = me.StringField(required=True)
-
-
-Movie(title='test').save()
-
-
-@app.route("/")
-def home_page():
- unsafe_search = request.args['search']
- json_search = json.loads(unsafe_search)
- safe_search = sanitize(json_search)
-
- db = connect('mydb')
- data = db.movie.find({'name': json_search})
-
-# if __name__ == "__main__":
-# app.run(debug=True)
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_document_subclass_bad.py b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_document_subclass_bad.py
deleted file mode 100644
index 95467393541..00000000000
--- a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_document_subclass_bad.py
+++ /dev/null
@@ -1,23 +0,0 @@
-from flask import Flask, request
-import mongoengine as me
-import json
-
-app = Flask(__name__)
-
-
-class Movie(me.Document):
- title = me.StringField(required=True)
-
-
-Movie(title='test').save()
-
-
-@app.route("/")
-def home_page():
- unsafe_search = request.args['search']
- json_search = json.loads(unsafe_search)
-
- data = Movie.objects(__raw__=json_search)
-
-# if __name__ == "__main__":
-# app.run(debug=True)
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_document_subclass_good.py b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_document_subclass_good.py
deleted file mode 100644
index c852d550464..00000000000
--- a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_document_subclass_good.py
+++ /dev/null
@@ -1,25 +0,0 @@
-from flask import Flask, request
-import mongoengine as me
-from mongosanitizer.sanitizer import sanitize
-import json
-
-app = Flask(__name__)
-
-
-class Movie(me.Document):
- title = me.StringField(required=True)
-
-
-Movie(title='test').save()
-
-
-@app.route("/")
-def home_page():
- unsafe_search = request.args['search']
- json_search = json.loads(unsafe_search)
- safe_search = sanitize(json_search)
-
- data = Movie.objects(__raw__=safe_search)
-
-# if __name__ == "__main__":
-# app.run(debug=True)
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_get_db_bad.py b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_get_db_bad.py
deleted file mode 100644
index 8b1d8ebb6fb..00000000000
--- a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_get_db_bad.py
+++ /dev/null
@@ -1,24 +0,0 @@
-from flask import Flask, request
-import mongoengine as me
-import json
-
-app = Flask(__name__)
-
-
-class Movie(me.Document):
- title = me.StringField(required=True)
-
-
-Movie(title='test').save()
-
-
-@app.route("/")
-def home_page():
- unsafe_search = request.args['search']
- json_search = json.loads(unsafe_search)
-
- db = me.get_db()
- data = db.movie.find({'name': json_search})
-
-# if __name__ == "__main__":
-# app.run(debug=True)
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_get_db_good.py b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_get_db_good.py
deleted file mode 100644
index 08c43b4d209..00000000000
--- a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_get_db_good.py
+++ /dev/null
@@ -1,26 +0,0 @@
-from flask import Flask, request
-import mongoengine as me
-from mongosanitizer.sanitizer import sanitize
-import json
-
-app = Flask(__name__)
-
-
-class Movie(me.Document):
- title = me.StringField(required=True)
-
-
-Movie(title='test').save()
-
-
-@app.route("/")
-def home_page():
- unsafe_search = request.args['search']
- json_search = json.loads(unsafe_search)
- safe_search = sanitize(json_search)
-
- db = me.get_db()
- data = db.movie.find({'name': safe_search})
-
-# if __name__ == "__main__":
-# app.run(debug=True)
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_get_db_via_connection_bad.py b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_get_db_via_connection_bad.py
deleted file mode 100644
index 76b32a69572..00000000000
--- a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_get_db_via_connection_bad.py
+++ /dev/null
@@ -1,25 +0,0 @@
-from flask import Flask, request
-import mongoengine as me
-from mongoengine.connection import get_db, connect
-import json
-
-app = Flask(__name__)
-
-
-class Movie(me.Document):
- title = me.StringField(required=True)
-
-
-Movie(title='test').save()
-
-
-@app.route("/")
-def home_page():
- unsafe_search = request.args['search']
- json_search = json.loads(unsafe_search)
-
- db = get_db()
- data = db.movie.find({'name': json_search})
-
-# if __name__ == "__main__":
-# app.run(debug=True)
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_get_db_via_connection_good.py b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_get_db_via_connection_good.py
deleted file mode 100644
index 9ac27c8c54a..00000000000
--- a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_get_db_via_connection_good.py
+++ /dev/null
@@ -1,27 +0,0 @@
-from flask import Flask, request
-import mongoengine as me
-from mongoengine.connection import get_db, connect
-from mongosanitizer.sanitizer import sanitize
-import json
-
-app = Flask(__name__)
-
-
-class Movie(me.Document):
- title = me.StringField(required=True)
-
-
-Movie(title='test').save()
-
-
-@app.route("/")
-def home_page():
- unsafe_search = request.args['search']
- json_search = json.loads(unsafe_search)
- safe_search = sanitize(json_search)
-
- db = get_db()
- data = db.movie.find({'name': safe_search})
-
-# if __name__ == "__main__":
-# app.run(debug=True)
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_good.py b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_good.py
new file mode 100644
index 00000000000..14bc3e6c2ea
--- /dev/null
+++ b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_good.py
@@ -0,0 +1,68 @@
+from flask import Flask, request
+import mongoengine as me
+from mongoengine.connection import get_db, connect
+from mongosanitizer.sanitizer import sanitize
+import json
+
+app = Flask(__name__)
+
+
+class Movie(me.Document):
+ title = me.StringField(required=True)
+
+
+Movie(title='test').save()
+
+
+@app.route("/connect_find")
+def connect_find():
+ unsafe_search = request.args['search']
+ json_search = json.loads(unsafe_search)
+ safe_search = sanitize(json_search)
+
+ db = me.connect('mydb')
+ return db.movie.find({'name': json_search})
+
+@app.route("/connection_connect_find")
+def connection_connect_find():
+ unsafe_search = request.args['search']
+ json_search = json.loads(unsafe_search)
+ safe_search = sanitize(json_search)
+
+ db = connect('mydb')
+ return db.movie.find({'name': json_search})
+
+@app.route("/subclass_objects")
+def subclass_objects():
+ unsafe_search = request.args['search']
+ json_search = json.loads(unsafe_search)
+ safe_search = sanitize(json_search)
+
+ return Movie.objects(__raw__=safe_search)
+
+@app.route("/get_db_find")
+def get_db_find():
+ unsafe_search = request.args['search']
+ json_search = json.loads(unsafe_search)
+ safe_search = sanitize(json_search)
+
+ db = me.get_db()
+ return db.movie.find({'name': safe_search})
+
+@app.route("/connection_get_db_find")
+def connection_get_db_find():
+ unsafe_search = request.args['search']
+ json_search = json.loads(unsafe_search)
+ safe_search = sanitize(json_search)
+
+ db = get_db()
+ return db.movie.find({'name': safe_search})
+
+@app.route("/subscript_find")
+def subscript_find():
+ unsafe_search = request.args['search']
+ json_search = json.loads(unsafe_search)
+ safe_search = sanitize(json_search)
+
+ db = me.connect('mydb')
+ return db['movie'].find({'name': safe_search})
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_subscript_bad.py b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_subscript_bad.py
deleted file mode 100644
index 96e08418b24..00000000000
--- a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_subscript_bad.py
+++ /dev/null
@@ -1,24 +0,0 @@
-from flask import Flask, request
-import mongoengine as me
-import json
-
-app = Flask(__name__)
-
-
-class Movie(me.Document):
- title = me.StringField(required=True)
-
-
-Movie(title='test').save()
-
-
-@app.route("/")
-def home_page():
- unsafe_search = request.args['search']
- json_search = json.loads(unsafe_search)
-
- db = me.connect('mydb')
- data = db['movie'].find({'name': json_search})
-
-# if __name__ == "__main__":
-# app.run(debug=True)
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_subscript_good.py b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_subscript_good.py
deleted file mode 100644
index e9be8dd3e3c..00000000000
--- a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_subscript_good.py
+++ /dev/null
@@ -1,26 +0,0 @@
-from flask import Flask, request
-import mongoengine as me
-from mongosanitizer.sanitizer import sanitize
-import json
-
-app = Flask(__name__)
-
-
-class Movie(me.Document):
- title = me.StringField(required=True)
-
-
-Movie(title='test').save()
-
-
-@app.route("/")
-def home_page():
- unsafe_search = request.args['search']
- json_search = json.loads(unsafe_search)
- safe_search = sanitize(json_search)
-
- db = me.connect('mydb')
- data = db['movie'].find({'name': safe_search})
-
-# if __name__ == "__main__":
-# app.run(debug=True)
From 3fd11298958ee4d8bb18806faebcacd59433818e Mon Sep 17 00:00:00 2001
From: jorgectf
Date: Mon, 28 Jun 2021 20:18:31 +0200
Subject: [PATCH 101/429] Delete trivial tests
---
.../Security/CWE-943/flask_mongoengine_good.py | 2 +-
.../Security/CWE-943/flask_pymongo_bad.py | 2 +-
.../Security/CWE-943/flask_pymongo_good.py | 2 +-
.../Security/CWE-943/mongoengine_bad.py | 16 ----------------
.../Security/CWE-943/mongoengine_good.py | 18 ------------------
.../Security/CWE-943/pymongo_bad.py | 2 +-
.../Security/CWE-943/pymongo_good.py | 2 +-
7 files changed, 5 insertions(+), 39 deletions(-)
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/flask_mongoengine_good.py b/python/ql/test/experimental/query-tests/Security/CWE-943/flask_mongoengine_good.py
index abfcfaba48c..04f82bf0a92 100644
--- a/python/ql/test/experimental/query-tests/Security/CWE-943/flask_mongoengine_good.py
+++ b/python/ql/test/experimental/query-tests/Security/CWE-943/flask_mongoengine_good.py
@@ -30,7 +30,7 @@ def get_db_find():
safe_search = sanitize(json_search)
retrieved_db = db.get_db()
- data = retrieved_db["Movie"].find({'name': safe_search})
+ return retrieved_db["Movie"].find({'name': safe_search})
# if __name__ == "__main__":
# app.run(debug=True)
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/flask_pymongo_bad.py b/python/ql/test/experimental/query-tests/Security/CWE-943/flask_pymongo_bad.py
index 93c570fbe58..0c1023971da 100644
--- a/python/ql/test/experimental/query-tests/Security/CWE-943/flask_pymongo_bad.py
+++ b/python/ql/test/experimental/query-tests/Security/CWE-943/flask_pymongo_bad.py
@@ -11,7 +11,7 @@ def home_page():
unsafe_search = request.args['search']
json_search = json.loads(unsafe_search)
- data = mongo.db.user.find({'name': json_search})
+ return mongo.db.user.find({'name': json_search})
# if __name__ == "__main__":
# app.run(debug=True)
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/flask_pymongo_good.py b/python/ql/test/experimental/query-tests/Security/CWE-943/flask_pymongo_good.py
index 29af42d8536..6576ba88af8 100644
--- a/python/ql/test/experimental/query-tests/Security/CWE-943/flask_pymongo_good.py
+++ b/python/ql/test/experimental/query-tests/Security/CWE-943/flask_pymongo_good.py
@@ -13,7 +13,7 @@ def home_page():
json_search = json.loads(unsafe_search)
safe_search = sanitize(json_search)
- data = mongo.db.user.find({'name': safe_search})
+ return mongo.db.user.find({'name': safe_search})
# if __name__ == "__main__":
# app.run(debug=True)
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_bad.py b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_bad.py
index 81800425e46..fd5dd7e4bb7 100644
--- a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_bad.py
+++ b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_bad.py
@@ -21,22 +21,6 @@ def connect_find():
db = me.connect('mydb')
return db.movie.find({'name': json_search})
-@app.route("/connection_connect_find")
-def connection_connect_find():
- unsafe_search = request.args['search']
- json_search = json.loads(unsafe_search)
-
- db = connect('mydb')
- return db.movie.find({'name': json_search})
-
-@app.route("/get_db_find")
-def get_db_find():
- unsafe_search = request.args['search']
- json_search = json.loads(unsafe_search)
-
- db = me.get_db()
- return db.movie.find({'name': json_search})
-
@app.route("/connection_get_db_find")
def connection_get_db_find():
unsafe_search = request.args['search']
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_good.py b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_good.py
index 14bc3e6c2ea..6a874e6b698 100644
--- a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_good.py
+++ b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_good.py
@@ -23,15 +23,6 @@ def connect_find():
db = me.connect('mydb')
return db.movie.find({'name': json_search})
-@app.route("/connection_connect_find")
-def connection_connect_find():
- unsafe_search = request.args['search']
- json_search = json.loads(unsafe_search)
- safe_search = sanitize(json_search)
-
- db = connect('mydb')
- return db.movie.find({'name': json_search})
-
@app.route("/subclass_objects")
def subclass_objects():
unsafe_search = request.args['search']
@@ -40,15 +31,6 @@ def subclass_objects():
return Movie.objects(__raw__=safe_search)
-@app.route("/get_db_find")
-def get_db_find():
- unsafe_search = request.args['search']
- json_search = json.loads(unsafe_search)
- safe_search = sanitize(json_search)
-
- db = me.get_db()
- return db.movie.find({'name': safe_search})
-
@app.route("/connection_get_db_find")
def connection_get_db_find():
unsafe_search = request.args['search']
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/pymongo_bad.py b/python/ql/test/experimental/query-tests/Security/CWE-943/pymongo_bad.py
index e0fc3514d73..da16df828b8 100644
--- a/python/ql/test/experimental/query-tests/Security/CWE-943/pymongo_bad.py
+++ b/python/ql/test/experimental/query-tests/Security/CWE-943/pymongo_bad.py
@@ -11,7 +11,7 @@ def home_page():
unsafe_search = request.args['search']
json_search = json.loads(unsafe_search)
- data = client.db.collection.find_one({'data': json_search})
+ return client.db.collection.find_one({'data': json_search})
# if __name__ == "__main__":
# app.run(debug=True)
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/pymongo_good.py b/python/ql/test/experimental/query-tests/Security/CWE-943/pymongo_good.py
index 0e52609fd7d..5b112e12385 100644
--- a/python/ql/test/experimental/query-tests/Security/CWE-943/pymongo_good.py
+++ b/python/ql/test/experimental/query-tests/Security/CWE-943/pymongo_good.py
@@ -13,7 +13,7 @@ def home_page():
json_search = json.loads(unsafe_search)
safe_search = sanitize(json_search)
- data = client.db.collection.find_one({'data': safe_search})
+ return client.db.collection.find_one({'data': safe_search})
# if __name__ == "__main__":
# app.run(debug=True)
From 68c683189a902d403f3f6801e3ce283314528e8a Mon Sep 17 00:00:00 2001
From: jorgectf
Date: Mon, 28 Jun 2021 20:55:49 +0200
Subject: [PATCH 102/429] Polish documentation, `mongoCollectionMethod()` and
update `.expected`
---
.../semmle/python/frameworks/NoSQL.qll | 94 +++++++++++++++++--
.../Security/CWE-943/NoSQLInjection.expected | 74 ++++-----------
2 files changed, 104 insertions(+), 64 deletions(-)
diff --git a/python/ql/src/experimental/semmle/python/frameworks/NoSQL.qll b/python/ql/src/experimental/semmle/python/frameworks/NoSQL.qll
index 2b6fbb1f752..f7ba8390677 100644
--- a/python/ql/src/experimental/semmle/python/frameworks/NoSQL.qll
+++ b/python/ql/src/experimental/semmle/python/frameworks/NoSQL.qll
@@ -11,35 +11,49 @@ private import experimental.semmle.python.Concepts
private import semmle.python.ApiGraphs
private module NoSQL {
- /** API Nodes returning `Mongo` instances. */
+ // API Nodes returning `Mongo` instances.
+ /** Gets a reference to `pymongo.MongoClient` */
private API::Node pyMongo() {
result = API::moduleImport("pymongo").getMember("MongoClient").getReturn()
}
+ /** Gets a reference to `flask_pymongo.PyMongo` */
private API::Node flask_PyMongo() {
result = API::moduleImport("flask_pymongo").getMember("PyMongo").getReturn()
}
+ /** Gets a reference to `mongoengine` */
private API::Node mongoEngine() { result = API::moduleImport("mongoengine") }
+ /** Gets a reference to `flask_mongoengine.MongoEngine` */
private API::Node flask_MongoEngine() {
result = API::moduleImport("flask_mongoengine").getMember("MongoEngine").getReturn()
}
- /** Gets a reference to a initialized `Mongo` instance. */
+ /**
+ * Gets a reference to a initialized `Mongo` instance.
+ * See `pyMongo()`, `flask_PyMongo()`
+ */
private API::Node mongoInstance() {
result = pyMongo() or
result = flask_PyMongo()
}
- /** Gets a reference to a initialized `Mongo` DB instance. */
+ /**
+ * Gets a reference to a initialized `Mongo` DB instance.
+ * See `mongoEngine()`, `flask_MongoEngine()`
+ */
private API::Node mongoDBInstance() {
result = mongoEngine().getMember(["get_db", "connect"]).getReturn() or
result = mongoEngine().getMember("connection").getMember(["get_db", "connect"]).getReturn() or
result = flask_MongoEngine().getMember("get_db").getReturn()
}
- /** Gets a reference to a `Mongo` DB use. */
+ /**
+ * Gets a reference to a `Mongo` DB use.
+ *
+ * See `mongoInstance()`, `mongoDBInstance()`.
+ */
private DataFlow::LocalSourceNode mongoDB(DataFlow::TypeTracker t) {
t.start() and
(
@@ -56,10 +70,24 @@ private module NoSQL {
exists(DataFlow::TypeTracker t2 | result = mongoDB(t2).track(t2, t))
}
- /** Gets a reference to a `Mongo` DB use. */
+ /**
+ * Gets a reference to a `Mongo` DB use.
+ *
+ * ```py
+ * from flask_pymongo import PyMongo
+ * mongo = PyMongo(app)
+ * mongo.db.user.find({'name': safe_search})
+ * ```
+ *
+ * `mongo.db` would be a `use` of a `Mongo` instance, and so the result.
+ */
private DataFlow::Node mongoDB() { mongoDB(DataFlow::TypeTracker::end()).flowsTo(result) }
- /** Gets a reference to a `Mongo` collection use. */
+ /**
+ * Gets a reference to a `Mongo` collection use.
+ *
+ * See `mongoDB()`.
+ */
private DataFlow::LocalSourceNode mongoCollection(DataFlow::TypeTracker t) {
t.start() and
(
@@ -73,7 +101,17 @@ private module NoSQL {
exists(DataFlow::TypeTracker t2 | result = mongoCollection(t2).track(t2, t))
}
- /** Gets a reference to a `Mongo` collection use. */
+ /**
+ * Gets a reference to a `Mongo` collection use.
+ *
+ * ```py
+ * from flask_pymongo import PyMongo
+ * mongo = PyMongo(app)
+ * mongo.db.user.find({'name': safe_search})
+ * ```
+ *
+ * `mongo.db.user` would be a `use` of a `Mongo` collection, and so the result.
+ */
private DataFlow::Node mongoCollection() {
mongoCollection(DataFlow::TypeTracker::end()).flowsTo(result)
}
@@ -88,19 +126,54 @@ private module NoSQL {
}
}
- /** Gets a reference to a `Mongo` collection method. */
+ /**
+ * Gets a reference to a `Mongo` collection method.
+ *
+ * ```py
+ * from flask_pymongo import PyMongo
+ * mongo = PyMongo(app)
+ * mongo.db.user.find({'name': safe_search})
+ * ```
+ *
+ * `mongo.db.user.find` would be a collection method, and so the result.
+ */
private DataFlow::Node mongoCollectionMethod() {
- mongoCollection() in [result.(DataFlow::AttrRead), result.(DataFlow::AttrRead).getObject()] and
+ mongoCollection() = result.(DataFlow::AttrRead).getObject() and
result.(DataFlow::AttrRead).getAttributeName() instanceof MongoCollectionMethodNames
}
- /** Gets a reference to a `Mongo` collection method call */
+ /**
+ * Gets a reference to a `Mongo` collection method call
+ *
+ * ```py
+ * from flask_pymongo import PyMongo
+ * mongo = PyMongo(app)
+ * mongo.db.user.find({'name': safe_search})
+ * ```
+ *
+ * `mongo.db.user.find({'name': safe_search})` would be a collection method call, and so the result.
+ */
private class MongoCollectionCall extends DataFlow::CallCfgNode, NoSQLQuery::Range {
MongoCollectionCall() { this.getFunction() = mongoCollectionMethod() }
override DataFlow::Node getQuery() { result = this.getArg(0) }
}
+ /**
+ * Gets a reference to a call from a class whose base is a reference to `mongoEngine()` or `flask_MongoEngine()`'s
+ * `Document` or `EmbeddedDocument` objects and its attribute is `objects`.
+ *
+ * ```py
+ * from flask_mongoengine import MongoEngine
+ * db = MongoEngine(app)
+ * class Movie(db.Document):
+ * title = db.StringField(required=True)
+ *
+ * Movie.objects(__raw__=json_search)
+ * ```
+ *
+ * `Movie.objects(__raw__=json_search)` would be the result.
+ */
private class MongoEngineObjectsCall extends DataFlow::CallCfgNode, NoSQLQuery::Range {
MongoEngineObjectsCall() {
this =
@@ -114,6 +187,7 @@ private module NoSQL {
override DataFlow::Node getQuery() { result = this.getArgByName(_) }
}
+ /** Gets a reference to `mongosanitizer.sanitizer.sanitize` */
private class MongoSanitizerCall extends DataFlow::CallCfgNode, NoSQLSanitizer::Range {
MongoSanitizerCall() {
this =
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/NoSQLInjection.expected b/python/ql/test/experimental/query-tests/Security/CWE-943/NoSQLInjection.expected
index 10c1f852df5..80c54422542 100644
--- a/python/ql/test/experimental/query-tests/Security/CWE-943/NoSQLInjection.expected
+++ b/python/ql/test/experimental/query-tests/Security/CWE-943/NoSQLInjection.expected
@@ -31,37 +31,23 @@ edges
| mongoengine_bad.py:34:21:34:27 | ControlFlowNode for request | mongoengine_bad.py:34:21:34:32 | ControlFlowNode for Attribute |
| mongoengine_bad.py:34:21:34:32 | ControlFlowNode for Attribute | mongoengine_bad.py:34:21:34:42 | ControlFlowNode for Subscript |
| mongoengine_bad.py:34:21:34:42 | ControlFlowNode for Subscript | mongoengine_bad.py:35:19:35:43 | ControlFlowNode for Attribute() |
-| mongoengine_bad.py:35:19:35:43 | ControlFlowNode for Attribute() | mongoengine_bad.py:38:26:38:46 | ControlFlowNode for Dict |
-| mongoengine_bad.py:42:21:42:27 | ControlFlowNode for request | mongoengine_bad.py:42:21:42:32 | ControlFlowNode for Attribute |
-| mongoengine_bad.py:42:21:42:32 | ControlFlowNode for Attribute | mongoengine_bad.py:42:21:42:42 | ControlFlowNode for Subscript |
-| mongoengine_bad.py:42:21:42:42 | ControlFlowNode for Subscript | mongoengine_bad.py:43:19:43:43 | ControlFlowNode for Attribute() |
-| mongoengine_bad.py:43:19:43:43 | ControlFlowNode for Attribute() | mongoengine_bad.py:46:26:46:46 | ControlFlowNode for Dict |
-| mongoengine_bad.py:50:21:50:27 | ControlFlowNode for request | mongoengine_bad.py:50:21:50:32 | ControlFlowNode for Attribute |
-| mongoengine_bad.py:50:21:50:32 | ControlFlowNode for Attribute | mongoengine_bad.py:50:21:50:42 | ControlFlowNode for Subscript |
-| mongoengine_bad.py:50:21:50:42 | ControlFlowNode for Subscript | mongoengine_bad.py:51:19:51:43 | ControlFlowNode for Attribute() |
-| mongoengine_bad.py:51:19:51:43 | ControlFlowNode for Attribute() | mongoengine_bad.py:53:34:53:44 | ControlFlowNode for json_search |
-| mongoengine_bad.py:57:21:57:27 | ControlFlowNode for request | mongoengine_bad.py:57:21:57:32 | ControlFlowNode for Attribute |
-| mongoengine_bad.py:57:21:57:32 | ControlFlowNode for Attribute | mongoengine_bad.py:57:21:57:42 | ControlFlowNode for Subscript |
-| mongoengine_bad.py:57:21:57:42 | ControlFlowNode for Subscript | mongoengine_bad.py:58:19:58:43 | ControlFlowNode for Attribute() |
-| mongoengine_bad.py:58:19:58:43 | ControlFlowNode for Attribute() | mongoengine_bad.py:61:29:61:49 | ControlFlowNode for Dict |
+| mongoengine_bad.py:35:19:35:43 | ControlFlowNode for Attribute() | mongoengine_bad.py:37:34:37:44 | ControlFlowNode for json_search |
+| mongoengine_bad.py:41:21:41:27 | ControlFlowNode for request | mongoengine_bad.py:41:21:41:32 | ControlFlowNode for Attribute |
+| mongoengine_bad.py:41:21:41:32 | ControlFlowNode for Attribute | mongoengine_bad.py:41:21:41:42 | ControlFlowNode for Subscript |
+| mongoengine_bad.py:41:21:41:42 | ControlFlowNode for Subscript | mongoengine_bad.py:42:19:42:43 | ControlFlowNode for Attribute() |
+| mongoengine_bad.py:42:19:42:43 | ControlFlowNode for Attribute() | mongoengine_bad.py:45:29:45:49 | ControlFlowNode for Dict |
| mongoengine_good.py:19:21:19:27 | ControlFlowNode for request | mongoengine_good.py:19:21:19:32 | ControlFlowNode for Attribute |
| mongoengine_good.py:19:21:19:32 | ControlFlowNode for Attribute | mongoengine_good.py:19:21:19:42 | ControlFlowNode for Subscript |
| mongoengine_good.py:19:21:19:42 | ControlFlowNode for Subscript | mongoengine_good.py:20:19:20:43 | ControlFlowNode for Attribute() |
| mongoengine_good.py:28:21:28:27 | ControlFlowNode for request | mongoengine_good.py:28:21:28:32 | ControlFlowNode for Attribute |
| mongoengine_good.py:28:21:28:32 | ControlFlowNode for Attribute | mongoengine_good.py:28:21:28:42 | ControlFlowNode for Subscript |
| mongoengine_good.py:28:21:28:42 | ControlFlowNode for Subscript | mongoengine_good.py:29:19:29:43 | ControlFlowNode for Attribute() |
-| mongoengine_good.py:37:21:37:27 | ControlFlowNode for request | mongoengine_good.py:37:21:37:32 | ControlFlowNode for Attribute |
-| mongoengine_good.py:37:21:37:32 | ControlFlowNode for Attribute | mongoengine_good.py:37:21:37:42 | ControlFlowNode for Subscript |
-| mongoengine_good.py:37:21:37:42 | ControlFlowNode for Subscript | mongoengine_good.py:38:19:38:43 | ControlFlowNode for Attribute() |
+| mongoengine_good.py:36:21:36:27 | ControlFlowNode for request | mongoengine_good.py:36:21:36:32 | ControlFlowNode for Attribute |
+| mongoengine_good.py:36:21:36:32 | ControlFlowNode for Attribute | mongoengine_good.py:36:21:36:42 | ControlFlowNode for Subscript |
+| mongoengine_good.py:36:21:36:42 | ControlFlowNode for Subscript | mongoengine_good.py:37:19:37:43 | ControlFlowNode for Attribute() |
| mongoengine_good.py:45:21:45:27 | ControlFlowNode for request | mongoengine_good.py:45:21:45:32 | ControlFlowNode for Attribute |
| mongoengine_good.py:45:21:45:32 | ControlFlowNode for Attribute | mongoengine_good.py:45:21:45:42 | ControlFlowNode for Subscript |
| mongoengine_good.py:45:21:45:42 | ControlFlowNode for Subscript | mongoengine_good.py:46:19:46:43 | ControlFlowNode for Attribute() |
-| mongoengine_good.py:54:21:54:27 | ControlFlowNode for request | mongoengine_good.py:54:21:54:32 | ControlFlowNode for Attribute |
-| mongoengine_good.py:54:21:54:32 | ControlFlowNode for Attribute | mongoengine_good.py:54:21:54:42 | ControlFlowNode for Subscript |
-| mongoengine_good.py:54:21:54:42 | ControlFlowNode for Subscript | mongoengine_good.py:55:19:55:43 | ControlFlowNode for Attribute() |
-| mongoengine_good.py:63:21:63:27 | ControlFlowNode for request | mongoengine_good.py:63:21:63:32 | ControlFlowNode for Attribute |
-| mongoengine_good.py:63:21:63:32 | ControlFlowNode for Attribute | mongoengine_good.py:63:21:63:42 | ControlFlowNode for Subscript |
-| mongoengine_good.py:63:21:63:42 | ControlFlowNode for Subscript | mongoengine_good.py:64:19:64:43 | ControlFlowNode for Attribute() |
| pymongo_bad.py:11:21:11:27 | ControlFlowNode for request | pymongo_bad.py:11:21:11:32 | ControlFlowNode for Attribute |
| pymongo_bad.py:11:21:11:32 | ControlFlowNode for Attribute | pymongo_bad.py:11:21:11:42 | ControlFlowNode for Subscript |
| pymongo_bad.py:11:21:11:42 | ControlFlowNode for Subscript | pymongo_bad.py:12:19:12:43 | ControlFlowNode for Attribute() |
@@ -111,22 +97,12 @@ nodes
| mongoengine_bad.py:34:21:34:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
| mongoengine_bad.py:34:21:34:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
| mongoengine_bad.py:35:19:35:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
-| mongoengine_bad.py:38:26:38:46 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict |
-| mongoengine_bad.py:42:21:42:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
-| mongoengine_bad.py:42:21:42:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
-| mongoengine_bad.py:42:21:42:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
-| mongoengine_bad.py:43:19:43:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
-| mongoengine_bad.py:46:26:46:46 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict |
-| mongoengine_bad.py:50:21:50:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
-| mongoengine_bad.py:50:21:50:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
-| mongoengine_bad.py:50:21:50:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
-| mongoengine_bad.py:51:19:51:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
-| mongoengine_bad.py:53:34:53:44 | ControlFlowNode for json_search | semmle.label | ControlFlowNode for json_search |
-| mongoengine_bad.py:57:21:57:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
-| mongoengine_bad.py:57:21:57:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
-| mongoengine_bad.py:57:21:57:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
-| mongoengine_bad.py:58:19:58:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
-| mongoengine_bad.py:61:29:61:49 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict |
+| mongoengine_bad.py:37:34:37:44 | ControlFlowNode for json_search | semmle.label | ControlFlowNode for json_search |
+| mongoengine_bad.py:41:21:41:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
+| mongoengine_bad.py:41:21:41:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
+| mongoengine_bad.py:41:21:41:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
+| mongoengine_bad.py:42:19:42:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
+| mongoengine_bad.py:45:29:45:49 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict |
| mongoengine_good.py:19:21:19:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
| mongoengine_good.py:19:21:19:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
| mongoengine_good.py:19:21:19:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
@@ -135,22 +111,14 @@ nodes
| mongoengine_good.py:28:21:28:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
| mongoengine_good.py:28:21:28:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
| mongoengine_good.py:29:19:29:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
-| mongoengine_good.py:37:21:37:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
-| mongoengine_good.py:37:21:37:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
-| mongoengine_good.py:37:21:37:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
-| mongoengine_good.py:38:19:38:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
+| mongoengine_good.py:36:21:36:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
+| mongoengine_good.py:36:21:36:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
+| mongoengine_good.py:36:21:36:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
+| mongoengine_good.py:37:19:37:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
| mongoengine_good.py:45:21:45:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
| mongoengine_good.py:45:21:45:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
| mongoengine_good.py:45:21:45:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
| mongoengine_good.py:46:19:46:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
-| mongoengine_good.py:54:21:54:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
-| mongoengine_good.py:54:21:54:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
-| mongoengine_good.py:54:21:54:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
-| mongoengine_good.py:55:19:55:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
-| mongoengine_good.py:63:21:63:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
-| mongoengine_good.py:63:21:63:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
-| mongoengine_good.py:63:21:63:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
-| mongoengine_good.py:64:19:64:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
| pymongo_bad.py:11:21:11:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
| pymongo_bad.py:11:21:11:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
| pymongo_bad.py:11:21:11:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
@@ -166,8 +134,6 @@ nodes
| flask_pymongo_bad.py:14:31:14:51 | ControlFlowNode for Dict | flask_pymongo_bad.py:11:21:11:27 | ControlFlowNode for request | flask_pymongo_bad.py:14:31:14:51 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | flask_pymongo_bad.py:14:31:14:51 | ControlFlowNode for Dict | This | flask_pymongo_bad.py:11:21:11:27 | ControlFlowNode for request | user-provided value |
| mongoengine_bad.py:22:26:22:46 | ControlFlowNode for Dict | mongoengine_bad.py:18:21:18:27 | ControlFlowNode for request | mongoengine_bad.py:22:26:22:46 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | mongoengine_bad.py:22:26:22:46 | ControlFlowNode for Dict | This | mongoengine_bad.py:18:21:18:27 | ControlFlowNode for request | user-provided value |
| mongoengine_bad.py:30:26:30:46 | ControlFlowNode for Dict | mongoengine_bad.py:26:21:26:27 | ControlFlowNode for request | mongoengine_bad.py:30:26:30:46 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | mongoengine_bad.py:30:26:30:46 | ControlFlowNode for Dict | This | mongoengine_bad.py:26:21:26:27 | ControlFlowNode for request | user-provided value |
-| mongoengine_bad.py:38:26:38:46 | ControlFlowNode for Dict | mongoengine_bad.py:34:21:34:27 | ControlFlowNode for request | mongoengine_bad.py:38:26:38:46 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | mongoengine_bad.py:38:26:38:46 | ControlFlowNode for Dict | This | mongoengine_bad.py:34:21:34:27 | ControlFlowNode for request | user-provided value |
-| mongoengine_bad.py:46:26:46:46 | ControlFlowNode for Dict | mongoengine_bad.py:42:21:42:27 | ControlFlowNode for request | mongoengine_bad.py:46:26:46:46 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | mongoengine_bad.py:46:26:46:46 | ControlFlowNode for Dict | This | mongoengine_bad.py:42:21:42:27 | ControlFlowNode for request | user-provided value |
-| mongoengine_bad.py:53:34:53:44 | ControlFlowNode for json_search | mongoengine_bad.py:50:21:50:27 | ControlFlowNode for request | mongoengine_bad.py:53:34:53:44 | ControlFlowNode for json_search | $@ NoSQL query contains an unsanitized $@ | mongoengine_bad.py:53:34:53:44 | ControlFlowNode for json_search | This | mongoengine_bad.py:50:21:50:27 | ControlFlowNode for request | user-provided value |
-| mongoengine_bad.py:61:29:61:49 | ControlFlowNode for Dict | mongoengine_bad.py:57:21:57:27 | ControlFlowNode for request | mongoengine_bad.py:61:29:61:49 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | mongoengine_bad.py:61:29:61:49 | ControlFlowNode for Dict | This | mongoengine_bad.py:57:21:57:27 | ControlFlowNode for request | user-provided value |
+| mongoengine_bad.py:37:34:37:44 | ControlFlowNode for json_search | mongoengine_bad.py:34:21:34:27 | ControlFlowNode for request | mongoengine_bad.py:37:34:37:44 | ControlFlowNode for json_search | $@ NoSQL query contains an unsanitized $@ | mongoengine_bad.py:37:34:37:44 | ControlFlowNode for json_search | This | mongoengine_bad.py:34:21:34:27 | ControlFlowNode for request | user-provided value |
+| mongoengine_bad.py:45:29:45:49 | ControlFlowNode for Dict | mongoengine_bad.py:41:21:41:27 | ControlFlowNode for request | mongoengine_bad.py:45:29:45:49 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | mongoengine_bad.py:45:29:45:49 | ControlFlowNode for Dict | This | mongoengine_bad.py:41:21:41:27 | ControlFlowNode for request | user-provided value |
| pymongo_bad.py:14:42:14:62 | ControlFlowNode for Dict | pymongo_bad.py:11:21:11:27 | ControlFlowNode for request | pymongo_bad.py:14:42:14:62 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | pymongo_bad.py:14:42:14:62 | ControlFlowNode for Dict | This | pymongo_bad.py:11:21:11:27 | ControlFlowNode for request | user-provided value |
From 350440897c753a3a948a8a4e10171d413997a435 Mon Sep 17 00:00:00 2001
From: Jorge <46056498+jorgectf@users.noreply.github.com>
Date: Mon, 28 Jun 2021 21:02:40 +0200
Subject: [PATCH 103/429] Apply suggestions from code review
Update `xmltodict` format and delete `ujson` modeling.
Co-authored-by: Rasmus Wriedt Larsen
---
.../semmle/python/frameworks/Stdlib.qll | 24 +------------------
1 file changed, 1 insertion(+), 23 deletions(-)
diff --git a/python/ql/src/experimental/semmle/python/frameworks/Stdlib.qll b/python/ql/src/experimental/semmle/python/frameworks/Stdlib.qll
index 7db995220d4..d16acdcb183 100644
--- a/python/ql/src/experimental/semmle/python/frameworks/Stdlib.qll
+++ b/python/ql/src/experimental/semmle/python/frameworks/Stdlib.qll
@@ -119,27 +119,5 @@ private class XmlToDictParseCall extends Decoding::Range, DataFlow::CallCfgNode
override DataFlow::Node getOutput() { result = this }
- override string getFormat() { result = "JSON" }
-}
-
-// ---------------------------------------------------------------------------
-// ujson
-// ---------------------------------------------------------------------------
-/** Gets a reference to the `ujson` module. */
-API::Node ujson() { result = API::moduleImport("ujson") }
-
-/**
- * A call to `ujson.loads`
- * See https://pypi.org/project/ujson/#usage
- */
-private class UltraJsonLoadsCall extends Decoding::Range, DataFlow::CallCfgNode {
- UltraJsonLoadsCall() { this = ujson().getMember("loads").getACall() }
-
- override predicate mayExecuteInput() { none() }
-
- override DataFlow::Node getAnInput() { result = this.getArg(0) }
-
- override DataFlow::Node getOutput() { result = this }
-
- override string getFormat() { result = "JSON" }
+ override string getFormat() { result = "XML" }
}
From 51395d155f68b99c1210689c675e80c2389fa0e1 Mon Sep 17 00:00:00 2001
From: jorgectf
Date: Mon, 28 Jun 2021 21:08:43 +0200
Subject: [PATCH 104/429] Move `xmltodict` to its own file under `frameworks/`
---
.../semmle/python/frameworks/Stdlib.qll | 23 -------------
.../semmle/python/frameworks/Xmltodict.qll | 34 +++++++++++++++++++
2 files changed, 34 insertions(+), 23 deletions(-)
create mode 100644 python/ql/src/experimental/semmle/python/frameworks/Xmltodict.qll
diff --git a/python/ql/src/experimental/semmle/python/frameworks/Stdlib.qll b/python/ql/src/experimental/semmle/python/frameworks/Stdlib.qll
index d16acdcb183..4f3457e0a99 100644
--- a/python/ql/src/experimental/semmle/python/frameworks/Stdlib.qll
+++ b/python/ql/src/experimental/semmle/python/frameworks/Stdlib.qll
@@ -8,7 +8,6 @@ private import semmle.python.dataflow.new.DataFlow
private import semmle.python.dataflow.new.TaintTracking
private import semmle.python.dataflow.new.RemoteFlowSources
private import experimental.semmle.python.Concepts
-private import semmle.python.Concepts
private import semmle.python.ApiGraphs
/**
@@ -99,25 +98,3 @@ private module Re {
override DataFlow::Node getRegexNode() { result = regexNode }
}
}
-
-// ---------------------------------------------------------------------------
-// xmltodict
-// ---------------------------------------------------------------------------
-/** Gets a reference to the `xmltodict` module. */
-API::Node xmltodict() { result = API::moduleImport("xmltodict") }
-
-/**
- * A call to `xmltodict.parse`
- * See https://github.com/martinblech/xmltodict/blob/ae19c452ca000bf243bfc16274c060bf3bf7cf51/xmltodict.py#L198
- */
-private class XmlToDictParseCall extends Decoding::Range, DataFlow::CallCfgNode {
- XmlToDictParseCall() { this = xmltodict().getMember("parse").getACall() }
-
- override predicate mayExecuteInput() { none() }
-
- override DataFlow::Node getAnInput() { result = this.getArg(0) }
-
- override DataFlow::Node getOutput() { result = this }
-
- override string getFormat() { result = "XML" }
-}
diff --git a/python/ql/src/experimental/semmle/python/frameworks/Xmltodict.qll b/python/ql/src/experimental/semmle/python/frameworks/Xmltodict.qll
new file mode 100644
index 00000000000..353130fdc9c
--- /dev/null
+++ b/python/ql/src/experimental/semmle/python/frameworks/Xmltodict.qll
@@ -0,0 +1,34 @@
+/**
+ * Provides classes modeling security-relevant aspects of the `xmltodict` PyPI package.
+ * See https://pypi.org/project/xmltodict/
+ */
+
+private import python
+private import semmle.python.dataflow.new.DataFlow
+private import semmle.python.Concepts
+private import semmle.python.ApiGraphs
+
+/**
+ * Provides models for the `xmltodict` PyPI package.
+ * See https://pypi.org/project/xmltodict/
+ */
+private module XmlToDictModel {
+ /** Gets a reference to the `xmltodict` module. */
+ API::Node xmltodict() { result = API::moduleImport("xmltodict") }
+
+ /**
+ * A call to `xmltodict.parse`
+ * See https://github.com/martinblech/xmltodict/blob/ae19c452ca000bf243bfc16274c060bf3bf7cf51/xmltodict.py#L198
+ */
+ private class XmlToDictParseCall extends Decoding::Range, DataFlow::CallCfgNode {
+ XmlToDictParseCall() { this = xmltodict().getMember("parse").getACall() }
+
+ override predicate mayExecuteInput() { none() }
+
+ override DataFlow::Node getAnInput() { result = this.getArg(0) }
+
+ override DataFlow::Node getOutput() { result = this }
+
+ override string getFormat() { result = "XML" }
+ }
+}
From 0819090fcbc78c0487370d0683d9449a2ad8f183 Mon Sep 17 00:00:00 2001
From: jorgectf
Date: Tue, 29 Jun 2021 16:53:32 +0200
Subject: [PATCH 105/429] Fix qldocs typo
---
.../src/experimental/semmle/python/frameworks/NoSQL.qll | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/python/ql/src/experimental/semmle/python/frameworks/NoSQL.qll b/python/ql/src/experimental/semmle/python/frameworks/NoSQL.qll
index f7ba8390677..545a7e9d6a5 100644
--- a/python/ql/src/experimental/semmle/python/frameworks/NoSQL.qll
+++ b/python/ql/src/experimental/semmle/python/frameworks/NoSQL.qll
@@ -31,7 +31,7 @@ private module NoSQL {
}
/**
- * Gets a reference to a initialized `Mongo` instance.
+ * Gets a reference to an initialized `Mongo` instance.
* See `pyMongo()`, `flask_PyMongo()`
*/
private API::Node mongoInstance() {
@@ -40,7 +40,7 @@ private module NoSQL {
}
/**
- * Gets a reference to a initialized `Mongo` DB instance.
+ * Gets a reference to an initialized `Mongo` DB instance.
* See `mongoEngine()`, `flask_MongoEngine()`
*/
private API::Node mongoDBInstance() {
@@ -79,7 +79,7 @@ private module NoSQL {
* mongo.db.user.find({'name': safe_search})
* ```
*
- * `mongo.db` would be a `use` of a `Mongo` instance, and so the result.
+ * `mongo.db` would be a use of a `Mongo` instance, and so the result.
*/
private DataFlow::Node mongoDB() { mongoDB(DataFlow::TypeTracker::end()).flowsTo(result) }
@@ -110,7 +110,7 @@ private module NoSQL {
* mongo.db.user.find({'name': safe_search})
* ```
*
- * `mongo.db.user` would be a `use` of a `Mongo` collection, and so the result.
+ * `mongo.db.user` would be a use of a `Mongo` collection, and so the result.
*/
private DataFlow::Node mongoCollection() {
mongoCollection(DataFlow::TypeTracker::end()).flowsTo(result)
From 9a8d1f8e0f7327aeb61faa14d28dea5e0e5a2d1b Mon Sep 17 00:00:00 2001
From: jorgectf
Date: Tue, 29 Jun 2021 16:53:44 +0200
Subject: [PATCH 106/429] Take back non-trivial tests
---
.../Security/CWE-943/mongoengine_bad.py | 16 ++++++++++++++++
.../Security/CWE-943/mongoengine_good.py | 18 ++++++++++++++++++
2 files changed, 34 insertions(+)
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_bad.py b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_bad.py
index fd5dd7e4bb7..81800425e46 100644
--- a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_bad.py
+++ b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_bad.py
@@ -21,6 +21,22 @@ def connect_find():
db = me.connect('mydb')
return db.movie.find({'name': json_search})
+@app.route("/connection_connect_find")
+def connection_connect_find():
+ unsafe_search = request.args['search']
+ json_search = json.loads(unsafe_search)
+
+ db = connect('mydb')
+ return db.movie.find({'name': json_search})
+
+@app.route("/get_db_find")
+def get_db_find():
+ unsafe_search = request.args['search']
+ json_search = json.loads(unsafe_search)
+
+ db = me.get_db()
+ return db.movie.find({'name': json_search})
+
@app.route("/connection_get_db_find")
def connection_get_db_find():
unsafe_search = request.args['search']
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_good.py b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_good.py
index 6a874e6b698..14bc3e6c2ea 100644
--- a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_good.py
+++ b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_good.py
@@ -23,6 +23,15 @@ def connect_find():
db = me.connect('mydb')
return db.movie.find({'name': json_search})
+@app.route("/connection_connect_find")
+def connection_connect_find():
+ unsafe_search = request.args['search']
+ json_search = json.loads(unsafe_search)
+ safe_search = sanitize(json_search)
+
+ db = connect('mydb')
+ return db.movie.find({'name': json_search})
+
@app.route("/subclass_objects")
def subclass_objects():
unsafe_search = request.args['search']
@@ -31,6 +40,15 @@ def subclass_objects():
return Movie.objects(__raw__=safe_search)
+@app.route("/get_db_find")
+def get_db_find():
+ unsafe_search = request.args['search']
+ json_search = json.loads(unsafe_search)
+ safe_search = sanitize(json_search)
+
+ db = me.get_db()
+ return db.movie.find({'name': safe_search})
+
@app.route("/connection_get_db_find")
def connection_get_db_find():
unsafe_search = request.args['search']
From 621a810b7b83a6af0adef87e2940007fd3735e99 Mon Sep 17 00:00:00 2001
From: jorgectf
Date: Tue, 29 Jun 2021 16:53:53 +0200
Subject: [PATCH 107/429] Update `.expected`
---
.../Security/CWE-943/NoSQLInjection.expected | 74 ++++++++++++++-----
1 file changed, 54 insertions(+), 20 deletions(-)
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/NoSQLInjection.expected b/python/ql/test/experimental/query-tests/Security/CWE-943/NoSQLInjection.expected
index 80c54422542..10c1f852df5 100644
--- a/python/ql/test/experimental/query-tests/Security/CWE-943/NoSQLInjection.expected
+++ b/python/ql/test/experimental/query-tests/Security/CWE-943/NoSQLInjection.expected
@@ -31,23 +31,37 @@ edges
| mongoengine_bad.py:34:21:34:27 | ControlFlowNode for request | mongoengine_bad.py:34:21:34:32 | ControlFlowNode for Attribute |
| mongoengine_bad.py:34:21:34:32 | ControlFlowNode for Attribute | mongoengine_bad.py:34:21:34:42 | ControlFlowNode for Subscript |
| mongoengine_bad.py:34:21:34:42 | ControlFlowNode for Subscript | mongoengine_bad.py:35:19:35:43 | ControlFlowNode for Attribute() |
-| mongoengine_bad.py:35:19:35:43 | ControlFlowNode for Attribute() | mongoengine_bad.py:37:34:37:44 | ControlFlowNode for json_search |
-| mongoengine_bad.py:41:21:41:27 | ControlFlowNode for request | mongoengine_bad.py:41:21:41:32 | ControlFlowNode for Attribute |
-| mongoengine_bad.py:41:21:41:32 | ControlFlowNode for Attribute | mongoengine_bad.py:41:21:41:42 | ControlFlowNode for Subscript |
-| mongoengine_bad.py:41:21:41:42 | ControlFlowNode for Subscript | mongoengine_bad.py:42:19:42:43 | ControlFlowNode for Attribute() |
-| mongoengine_bad.py:42:19:42:43 | ControlFlowNode for Attribute() | mongoengine_bad.py:45:29:45:49 | ControlFlowNode for Dict |
+| mongoengine_bad.py:35:19:35:43 | ControlFlowNode for Attribute() | mongoengine_bad.py:38:26:38:46 | ControlFlowNode for Dict |
+| mongoengine_bad.py:42:21:42:27 | ControlFlowNode for request | mongoengine_bad.py:42:21:42:32 | ControlFlowNode for Attribute |
+| mongoengine_bad.py:42:21:42:32 | ControlFlowNode for Attribute | mongoengine_bad.py:42:21:42:42 | ControlFlowNode for Subscript |
+| mongoengine_bad.py:42:21:42:42 | ControlFlowNode for Subscript | mongoengine_bad.py:43:19:43:43 | ControlFlowNode for Attribute() |
+| mongoengine_bad.py:43:19:43:43 | ControlFlowNode for Attribute() | mongoengine_bad.py:46:26:46:46 | ControlFlowNode for Dict |
+| mongoengine_bad.py:50:21:50:27 | ControlFlowNode for request | mongoengine_bad.py:50:21:50:32 | ControlFlowNode for Attribute |
+| mongoengine_bad.py:50:21:50:32 | ControlFlowNode for Attribute | mongoengine_bad.py:50:21:50:42 | ControlFlowNode for Subscript |
+| mongoengine_bad.py:50:21:50:42 | ControlFlowNode for Subscript | mongoengine_bad.py:51:19:51:43 | ControlFlowNode for Attribute() |
+| mongoengine_bad.py:51:19:51:43 | ControlFlowNode for Attribute() | mongoengine_bad.py:53:34:53:44 | ControlFlowNode for json_search |
+| mongoengine_bad.py:57:21:57:27 | ControlFlowNode for request | mongoengine_bad.py:57:21:57:32 | ControlFlowNode for Attribute |
+| mongoengine_bad.py:57:21:57:32 | ControlFlowNode for Attribute | mongoengine_bad.py:57:21:57:42 | ControlFlowNode for Subscript |
+| mongoengine_bad.py:57:21:57:42 | ControlFlowNode for Subscript | mongoengine_bad.py:58:19:58:43 | ControlFlowNode for Attribute() |
+| mongoengine_bad.py:58:19:58:43 | ControlFlowNode for Attribute() | mongoengine_bad.py:61:29:61:49 | ControlFlowNode for Dict |
| mongoengine_good.py:19:21:19:27 | ControlFlowNode for request | mongoengine_good.py:19:21:19:32 | ControlFlowNode for Attribute |
| mongoengine_good.py:19:21:19:32 | ControlFlowNode for Attribute | mongoengine_good.py:19:21:19:42 | ControlFlowNode for Subscript |
| mongoengine_good.py:19:21:19:42 | ControlFlowNode for Subscript | mongoengine_good.py:20:19:20:43 | ControlFlowNode for Attribute() |
| mongoengine_good.py:28:21:28:27 | ControlFlowNode for request | mongoengine_good.py:28:21:28:32 | ControlFlowNode for Attribute |
| mongoengine_good.py:28:21:28:32 | ControlFlowNode for Attribute | mongoengine_good.py:28:21:28:42 | ControlFlowNode for Subscript |
| mongoengine_good.py:28:21:28:42 | ControlFlowNode for Subscript | mongoengine_good.py:29:19:29:43 | ControlFlowNode for Attribute() |
-| mongoengine_good.py:36:21:36:27 | ControlFlowNode for request | mongoengine_good.py:36:21:36:32 | ControlFlowNode for Attribute |
-| mongoengine_good.py:36:21:36:32 | ControlFlowNode for Attribute | mongoengine_good.py:36:21:36:42 | ControlFlowNode for Subscript |
-| mongoengine_good.py:36:21:36:42 | ControlFlowNode for Subscript | mongoengine_good.py:37:19:37:43 | ControlFlowNode for Attribute() |
+| mongoengine_good.py:37:21:37:27 | ControlFlowNode for request | mongoengine_good.py:37:21:37:32 | ControlFlowNode for Attribute |
+| mongoengine_good.py:37:21:37:32 | ControlFlowNode for Attribute | mongoengine_good.py:37:21:37:42 | ControlFlowNode for Subscript |
+| mongoengine_good.py:37:21:37:42 | ControlFlowNode for Subscript | mongoengine_good.py:38:19:38:43 | ControlFlowNode for Attribute() |
| mongoengine_good.py:45:21:45:27 | ControlFlowNode for request | mongoengine_good.py:45:21:45:32 | ControlFlowNode for Attribute |
| mongoengine_good.py:45:21:45:32 | ControlFlowNode for Attribute | mongoengine_good.py:45:21:45:42 | ControlFlowNode for Subscript |
| mongoengine_good.py:45:21:45:42 | ControlFlowNode for Subscript | mongoengine_good.py:46:19:46:43 | ControlFlowNode for Attribute() |
+| mongoengine_good.py:54:21:54:27 | ControlFlowNode for request | mongoengine_good.py:54:21:54:32 | ControlFlowNode for Attribute |
+| mongoengine_good.py:54:21:54:32 | ControlFlowNode for Attribute | mongoengine_good.py:54:21:54:42 | ControlFlowNode for Subscript |
+| mongoengine_good.py:54:21:54:42 | ControlFlowNode for Subscript | mongoengine_good.py:55:19:55:43 | ControlFlowNode for Attribute() |
+| mongoengine_good.py:63:21:63:27 | ControlFlowNode for request | mongoengine_good.py:63:21:63:32 | ControlFlowNode for Attribute |
+| mongoengine_good.py:63:21:63:32 | ControlFlowNode for Attribute | mongoengine_good.py:63:21:63:42 | ControlFlowNode for Subscript |
+| mongoengine_good.py:63:21:63:42 | ControlFlowNode for Subscript | mongoengine_good.py:64:19:64:43 | ControlFlowNode for Attribute() |
| pymongo_bad.py:11:21:11:27 | ControlFlowNode for request | pymongo_bad.py:11:21:11:32 | ControlFlowNode for Attribute |
| pymongo_bad.py:11:21:11:32 | ControlFlowNode for Attribute | pymongo_bad.py:11:21:11:42 | ControlFlowNode for Subscript |
| pymongo_bad.py:11:21:11:42 | ControlFlowNode for Subscript | pymongo_bad.py:12:19:12:43 | ControlFlowNode for Attribute() |
@@ -97,12 +111,22 @@ nodes
| mongoengine_bad.py:34:21:34:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
| mongoengine_bad.py:34:21:34:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
| mongoengine_bad.py:35:19:35:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
-| mongoengine_bad.py:37:34:37:44 | ControlFlowNode for json_search | semmle.label | ControlFlowNode for json_search |
-| mongoengine_bad.py:41:21:41:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
-| mongoengine_bad.py:41:21:41:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
-| mongoengine_bad.py:41:21:41:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
-| mongoengine_bad.py:42:19:42:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
-| mongoengine_bad.py:45:29:45:49 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict |
+| mongoengine_bad.py:38:26:38:46 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict |
+| mongoengine_bad.py:42:21:42:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
+| mongoengine_bad.py:42:21:42:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
+| mongoengine_bad.py:42:21:42:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
+| mongoengine_bad.py:43:19:43:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
+| mongoengine_bad.py:46:26:46:46 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict |
+| mongoengine_bad.py:50:21:50:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
+| mongoengine_bad.py:50:21:50:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
+| mongoengine_bad.py:50:21:50:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
+| mongoengine_bad.py:51:19:51:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
+| mongoengine_bad.py:53:34:53:44 | ControlFlowNode for json_search | semmle.label | ControlFlowNode for json_search |
+| mongoengine_bad.py:57:21:57:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
+| mongoengine_bad.py:57:21:57:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
+| mongoengine_bad.py:57:21:57:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
+| mongoengine_bad.py:58:19:58:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
+| mongoengine_bad.py:61:29:61:49 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict |
| mongoengine_good.py:19:21:19:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
| mongoengine_good.py:19:21:19:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
| mongoengine_good.py:19:21:19:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
@@ -111,14 +135,22 @@ nodes
| mongoengine_good.py:28:21:28:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
| mongoengine_good.py:28:21:28:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
| mongoengine_good.py:29:19:29:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
-| mongoengine_good.py:36:21:36:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
-| mongoengine_good.py:36:21:36:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
-| mongoengine_good.py:36:21:36:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
-| mongoengine_good.py:37:19:37:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
+| mongoengine_good.py:37:21:37:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
+| mongoengine_good.py:37:21:37:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
+| mongoengine_good.py:37:21:37:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
+| mongoengine_good.py:38:19:38:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
| mongoengine_good.py:45:21:45:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
| mongoengine_good.py:45:21:45:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
| mongoengine_good.py:45:21:45:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
| mongoengine_good.py:46:19:46:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
+| mongoengine_good.py:54:21:54:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
+| mongoengine_good.py:54:21:54:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
+| mongoengine_good.py:54:21:54:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
+| mongoengine_good.py:55:19:55:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
+| mongoengine_good.py:63:21:63:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
+| mongoengine_good.py:63:21:63:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
+| mongoengine_good.py:63:21:63:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
+| mongoengine_good.py:64:19:64:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
| pymongo_bad.py:11:21:11:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
| pymongo_bad.py:11:21:11:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
| pymongo_bad.py:11:21:11:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
@@ -134,6 +166,8 @@ nodes
| flask_pymongo_bad.py:14:31:14:51 | ControlFlowNode for Dict | flask_pymongo_bad.py:11:21:11:27 | ControlFlowNode for request | flask_pymongo_bad.py:14:31:14:51 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | flask_pymongo_bad.py:14:31:14:51 | ControlFlowNode for Dict | This | flask_pymongo_bad.py:11:21:11:27 | ControlFlowNode for request | user-provided value |
| mongoengine_bad.py:22:26:22:46 | ControlFlowNode for Dict | mongoengine_bad.py:18:21:18:27 | ControlFlowNode for request | mongoengine_bad.py:22:26:22:46 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | mongoengine_bad.py:22:26:22:46 | ControlFlowNode for Dict | This | mongoengine_bad.py:18:21:18:27 | ControlFlowNode for request | user-provided value |
| mongoengine_bad.py:30:26:30:46 | ControlFlowNode for Dict | mongoengine_bad.py:26:21:26:27 | ControlFlowNode for request | mongoengine_bad.py:30:26:30:46 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | mongoengine_bad.py:30:26:30:46 | ControlFlowNode for Dict | This | mongoengine_bad.py:26:21:26:27 | ControlFlowNode for request | user-provided value |
-| mongoengine_bad.py:37:34:37:44 | ControlFlowNode for json_search | mongoengine_bad.py:34:21:34:27 | ControlFlowNode for request | mongoengine_bad.py:37:34:37:44 | ControlFlowNode for json_search | $@ NoSQL query contains an unsanitized $@ | mongoengine_bad.py:37:34:37:44 | ControlFlowNode for json_search | This | mongoengine_bad.py:34:21:34:27 | ControlFlowNode for request | user-provided value |
-| mongoengine_bad.py:45:29:45:49 | ControlFlowNode for Dict | mongoengine_bad.py:41:21:41:27 | ControlFlowNode for request | mongoengine_bad.py:45:29:45:49 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | mongoengine_bad.py:45:29:45:49 | ControlFlowNode for Dict | This | mongoengine_bad.py:41:21:41:27 | ControlFlowNode for request | user-provided value |
+| mongoengine_bad.py:38:26:38:46 | ControlFlowNode for Dict | mongoengine_bad.py:34:21:34:27 | ControlFlowNode for request | mongoengine_bad.py:38:26:38:46 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | mongoengine_bad.py:38:26:38:46 | ControlFlowNode for Dict | This | mongoengine_bad.py:34:21:34:27 | ControlFlowNode for request | user-provided value |
+| mongoengine_bad.py:46:26:46:46 | ControlFlowNode for Dict | mongoengine_bad.py:42:21:42:27 | ControlFlowNode for request | mongoengine_bad.py:46:26:46:46 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | mongoengine_bad.py:46:26:46:46 | ControlFlowNode for Dict | This | mongoengine_bad.py:42:21:42:27 | ControlFlowNode for request | user-provided value |
+| mongoengine_bad.py:53:34:53:44 | ControlFlowNode for json_search | mongoengine_bad.py:50:21:50:27 | ControlFlowNode for request | mongoengine_bad.py:53:34:53:44 | ControlFlowNode for json_search | $@ NoSQL query contains an unsanitized $@ | mongoengine_bad.py:53:34:53:44 | ControlFlowNode for json_search | This | mongoengine_bad.py:50:21:50:27 | ControlFlowNode for request | user-provided value |
+| mongoengine_bad.py:61:29:61:49 | ControlFlowNode for Dict | mongoengine_bad.py:57:21:57:27 | ControlFlowNode for request | mongoengine_bad.py:61:29:61:49 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | mongoengine_bad.py:61:29:61:49 | ControlFlowNode for Dict | This | mongoengine_bad.py:57:21:57:27 | ControlFlowNode for request | user-provided value |
| pymongo_bad.py:14:42:14:62 | ControlFlowNode for Dict | pymongo_bad.py:11:21:11:27 | ControlFlowNode for request | pymongo_bad.py:14:42:14:62 | ControlFlowNode for Dict | $@ NoSQL query contains an unsanitized $@ | pymongo_bad.py:14:42:14:62 | ControlFlowNode for Dict | This | pymongo_bad.py:11:21:11:27 | ControlFlowNode for request | user-provided value |
From e02a63a27a5309312653593c7a62fe3e5a1055f6 Mon Sep 17 00:00:00 2001
From: jorgectf
Date: Tue, 29 Jun 2021 23:03:41 +0200
Subject: [PATCH 108/429] Delete trivial `*_good.py` tests
---
.../CWE-943/flask_mongoengine_good.py | 9 ----
.../Security/CWE-943/mongoengine_good.py | 45 +------------------
2 files changed, 2 insertions(+), 52 deletions(-)
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/flask_mongoengine_good.py b/python/ql/test/experimental/query-tests/Security/CWE-943/flask_mongoengine_good.py
index 04f82bf0a92..29a2c75d664 100644
--- a/python/ql/test/experimental/query-tests/Security/CWE-943/flask_mongoengine_good.py
+++ b/python/ql/test/experimental/query-tests/Security/CWE-943/flask_mongoengine_good.py
@@ -23,14 +23,5 @@ def subclass_objects():
return Movie.objects(__raw__=safe_search)
-@app.route("/get_db_find")
-def get_db_find():
- unsafe_search = request.args['search']
- json_search = json.loads(unsafe_search)
- safe_search = sanitize(json_search)
-
- retrieved_db = db.get_db()
- return retrieved_db["Movie"].find({'name': safe_search})
-
# if __name__ == "__main__":
# app.run(debug=True)
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_good.py b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_good.py
index 14bc3e6c2ea..1ece6997a89 100644
--- a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_good.py
+++ b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_good.py
@@ -23,46 +23,5 @@ def connect_find():
db = me.connect('mydb')
return db.movie.find({'name': json_search})
-@app.route("/connection_connect_find")
-def connection_connect_find():
- unsafe_search = request.args['search']
- json_search = json.loads(unsafe_search)
- safe_search = sanitize(json_search)
-
- db = connect('mydb')
- return db.movie.find({'name': json_search})
-
-@app.route("/subclass_objects")
-def subclass_objects():
- unsafe_search = request.args['search']
- json_search = json.loads(unsafe_search)
- safe_search = sanitize(json_search)
-
- return Movie.objects(__raw__=safe_search)
-
-@app.route("/get_db_find")
-def get_db_find():
- unsafe_search = request.args['search']
- json_search = json.loads(unsafe_search)
- safe_search = sanitize(json_search)
-
- db = me.get_db()
- return db.movie.find({'name': safe_search})
-
-@app.route("/connection_get_db_find")
-def connection_get_db_find():
- unsafe_search = request.args['search']
- json_search = json.loads(unsafe_search)
- safe_search = sanitize(json_search)
-
- db = get_db()
- return db.movie.find({'name': safe_search})
-
-@app.route("/subscript_find")
-def subscript_find():
- unsafe_search = request.args['search']
- json_search = json.loads(unsafe_search)
- safe_search = sanitize(json_search)
-
- db = me.connect('mydb')
- return db['movie'].find({'name': safe_search})
+# if __name__ == "__main__":
+# app.run(debug=True)
From c3ac3ca41c3f7d3b9f332e977701dc6642b09188 Mon Sep 17 00:00:00 2001
From: edvraa
Date: Mon, 14 Jun 2021 22:38:27 +0300
Subject: [PATCH 109/429] FsPickler
---
.../dataflow/UnsafeDeserialization.qll | 48 ++++++++
.../csharp/serialization/Deserializers.qll | 111 ++++++++++++++++++
2 files changed, 159 insertions(+)
diff --git a/csharp/ql/src/semmle/code/csharp/security/dataflow/UnsafeDeserialization.qll b/csharp/ql/src/semmle/code/csharp/security/dataflow/UnsafeDeserialization.qll
index 407d7b22bbc..bb71ffa7b1d 100644
--- a/csharp/ql/src/semmle/code/csharp/security/dataflow/UnsafeDeserialization.qll
+++ b/csharp/ql/src/semmle/code/csharp/security/dataflow/UnsafeDeserialization.qll
@@ -750,4 +750,52 @@ module UnsafeDeserialization {
)
}
}
+
+ /** FsPickler */
+ private predicate isWeakTypeFsPicklerCall(MethodCall mc, Method m) {
+ m = mc.getTarget() and
+ (
+ m instanceof FsPicklerSerializerClassUnPickleUntypedMethod or
+ m instanceof FsPicklerSerializerClassDeserializeUntypedMethod or
+ m instanceof FsPicklerSerializerClassDeserializeSequenceUntypedMethod
+ ) and
+ not mc.getArgument(0).hasValue()
+ }
+
+ abstract private class FsPicklerWeakTypeSink extends ConstructorOrStaticMethodSink { }
+
+ private class FsPicklerDeserializeWeakTypeMethodSink extends FsPicklerWeakTypeSink {
+ FsPicklerDeserializeWeakTypeMethodSink() {
+ exists(MethodCall mc, Method m |
+ isWeakTypeFsPicklerCall(mc, m) and
+ this.asExpr() = mc.getArgument(0)
+ )
+ }
+ }
+
+ private predicate isStrongTypeFsPicklerCall(MethodCall mc, Method m) {
+ m = mc.getTarget() and
+ (
+ m instanceof FsPicklerSerializerClassDeserializeMethod or
+ m instanceof FsPicklerSerializerClassDeserializeSequenceMethod or
+ m instanceof FsPicklerSerializerClasDeserializeSiftedMethod or
+ m instanceof FsPicklerSerializerClassUnPickleMethod or
+ m instanceof FsPicklerSerializerClassUnPickleSiftedMethod or
+ m instanceof CsPicklerSerializerClassDeserializeMethod or
+ m instanceof CsPicklerSerializerClassUnPickleMethod or
+ m instanceof CsPicklerSerializerClassUnPickleOfStringMethod
+ ) and
+ not mc.getArgument(0).hasValue()
+ }
+
+ abstract private class FsPicklerStrongTypeSink extends InstanceMethodSink { }
+
+ private class FsPicklerDeserializeStrongTypeMethodSink extends FsPicklerStrongTypeSink {
+ FsPicklerDeserializeStrongTypeMethodSink() {
+ exists(MethodCall mc, Method m |
+ isStrongTypeFsPicklerCall(mc, m) and
+ this.asExpr() = mc.getArgument(0)
+ )
+ }
+ }
}
diff --git a/csharp/ql/src/semmle/code/csharp/serialization/Deserializers.qll b/csharp/ql/src/semmle/code/csharp/serialization/Deserializers.qll
index 58b6375bc13..5a076703afc 100644
--- a/csharp/ql/src/semmle/code/csharp/serialization/Deserializers.qll
+++ b/csharp/ql/src/semmle/code/csharp/serialization/Deserializers.qll
@@ -18,6 +18,12 @@ class StrongTypeDeserializer extends Class {
this instanceof DataContractSerializerClass
or
this instanceof XmlMessageFormatterClass
+ or
+ this instanceof FsPicklerSerializerClass
+ or
+ this instanceof CsPicklerSerializerClass
+ or
+ this instanceof CsPicklerTextSerializerClass
}
}
@@ -513,3 +519,108 @@ class ServiceStackTextXmlSerializerDeserializeFromStreamMethod extends Method, U
this.isStatic()
}
}
+
+/** MBrace.FsPickler.FsPicklerSerializer */
+private class FsPicklerSerializerClass extends Class {
+ FsPicklerSerializerClass() { this.hasQualifiedName("MBrace.FsPickler.FsPicklerSerializer") }
+}
+
+/** `MBrace.FsPickler.FsPicklerSerializer.Deserialize` method */
+class FsPicklerSerializerClassDeserializeMethod extends Method, UnsafeDeserializer {
+ FsPicklerSerializerClassDeserializeMethod() {
+ this.getDeclaringType().getBaseClass*() instanceof FsPicklerSerializerClass and
+ this.hasName("Deserialize")
+ }
+}
+
+/** `MBrace.FsPickler.FsPicklerSerializer.DeserializeSequence` method */
+class FsPicklerSerializerClassDeserializeSequenceMethod extends Method, UnsafeDeserializer {
+ FsPicklerSerializerClassDeserializeSequenceMethod() {
+ this.getDeclaringType().getBaseClass*() instanceof FsPicklerSerializerClass and
+ this.hasName("DeserializeSequence")
+ }
+}
+
+/** `MBrace.FsPickler.FsPicklerSerializer.DeserializeSifted` method */
+class FsPicklerSerializerClasDeserializeSiftedMethod extends Method, UnsafeDeserializer {
+ FsPicklerSerializerClasDeserializeSiftedMethod() {
+ this.getDeclaringType().getBaseClass*() instanceof FsPicklerSerializerClass and
+ this.hasName("DeserializeSifted")
+ }
+}
+
+/** `MBrace.FsPickler.FsPicklerSerializer.UnPickle` method */
+class FsPicklerSerializerClassUnPickleMethod extends Method, UnsafeDeserializer {
+ FsPicklerSerializerClassUnPickleMethod() {
+ this.getDeclaringType().getBaseClass*() instanceof FsPicklerSerializerClass and
+ this.hasName("UnPickle")
+ }
+}
+
+/** `MBrace.FsPickler.FsPicklerSerializer.UnPickleSifted` method */
+class FsPicklerSerializerClassUnPickleSiftedMethod extends Method, UnsafeDeserializer {
+ FsPicklerSerializerClassUnPickleSiftedMethod() {
+ this.getDeclaringType().getBaseClass*() instanceof FsPicklerSerializerClass and
+ this.hasName("UnPickleSifted")
+ }
+}
+
+/** `MBrace.FsPickler.FsPicklerSerializer.DeserializeUntyped` method */
+class FsPicklerSerializerClassDeserializeUntypedMethod extends Method, UnsafeDeserializer {
+ FsPicklerSerializerClassDeserializeUntypedMethod() {
+ this.getDeclaringType().getBaseClass*() instanceof FsPicklerSerializerClass and
+ this.hasName("DeserializeUntyped")
+ }
+}
+
+/** `MBrace.FsPickler.FsPicklerSerializer.DeserializeSequenceUntyped` method */
+class FsPicklerSerializerClassDeserializeSequenceUntypedMethod extends Method, UnsafeDeserializer {
+ FsPicklerSerializerClassDeserializeSequenceUntypedMethod() {
+ this.getDeclaringType().getBaseClass*() instanceof FsPicklerSerializerClass and
+ this.hasName("DeserializeSequenceUntyped")
+ }
+}
+
+/** `MBrace.FsPickler.FsPicklerSerializer.UnPickleUntyped` method */
+class FsPicklerSerializerClassUnPickleUntypedMethod extends Method, UnsafeDeserializer {
+ FsPicklerSerializerClassUnPickleUntypedMethod() {
+ this.getDeclaringType().getBaseClass*() instanceof FsPicklerSerializerClass and
+ this.hasName("UnPickleUntyped")
+ }
+}
+
+/** MBrace.CsPickler.CsPicklerSerializer */
+private class CsPicklerSerializerClass extends Class {
+ CsPicklerSerializerClass() { this.hasQualifiedName("MBrace.CsPickler.CsPicklerSerializer") }
+}
+
+/** `MBrace.FsPickler.CsPicklerSerializer.Deserialize` method */
+class CsPicklerSerializerClassDeserializeMethod extends Method, UnsafeDeserializer {
+ CsPicklerSerializerClassDeserializeMethod() {
+ this.getDeclaringType().getBaseClass*() instanceof CsPicklerSerializerClass and
+ this.hasName("Deserialize")
+ }
+}
+
+/** `MBrace.FsPickler.CsPicklerSerializer.UnPickle` method */
+class CsPicklerSerializerClassUnPickleMethod extends Method, UnsafeDeserializer {
+ CsPicklerSerializerClassUnPickleMethod() {
+ this.getDeclaringType().getBaseClass*() instanceof CsPicklerSerializerClass and
+ this.hasName("UnPickle")
+ }
+}
+
+/** MBrace.CsPickler.CsPicklerTextSerializer */
+private class CsPicklerTextSerializerClass extends Class {
+ CsPicklerTextSerializerClass() {
+ this.hasQualifiedName("MBrace.CsPickler.CsPicklerTextSerializer")
+ }
+}
+
+/** `MBrace.FsPickler.CsPicklerTextSerializer.UnPickleOfString` method */
+class CsPicklerSerializerClassUnPickleOfStringMethod extends Method, UnsafeDeserializer {
+ CsPicklerSerializerClassUnPickleOfStringMethod() {
+ this.getDeclaringType().getBaseClass*() instanceof CsPicklerTextSerializerClass and
+ this.hasName("UnPickleOfString")
+ }
+}
From 1e4409f9edf1cb34c7e5b0b9665ce128f554d109 Mon Sep 17 00:00:00 2001
From: edvraa
Date: Mon, 14 Jun 2021 23:26:28 +0300
Subject: [PATCH 110/429] SharpSerializer
---
.../security/dataflow/UnsafeDeserialization.qll | 14 ++++++++++++++
.../code/csharp/serialization/Deserializers.qll | 15 +++++++++++++++
2 files changed, 29 insertions(+)
diff --git a/csharp/ql/src/semmle/code/csharp/security/dataflow/UnsafeDeserialization.qll b/csharp/ql/src/semmle/code/csharp/security/dataflow/UnsafeDeserialization.qll
index bb71ffa7b1d..573b4eaf461 100644
--- a/csharp/ql/src/semmle/code/csharp/security/dataflow/UnsafeDeserialization.qll
+++ b/csharp/ql/src/semmle/code/csharp/security/dataflow/UnsafeDeserialization.qll
@@ -798,4 +798,18 @@ module UnsafeDeserialization {
)
}
}
+
+ /** SharpSerializer */
+ private class SharpSerializerDeserializeMethodSink extends InstanceMethodSink {
+ SharpSerializerDeserializeMethodSink() {
+ exists(MethodCall mc, Method m |
+ m = mc.getTarget() and
+ (
+ not mc.getArgument(0).hasValue() and
+ m instanceof SharpSerializerClassDeserializeMethod
+ ) and
+ this.asExpr() = mc.getArgument(0)
+ )
+ }
+ }
}
diff --git a/csharp/ql/src/semmle/code/csharp/serialization/Deserializers.qll b/csharp/ql/src/semmle/code/csharp/serialization/Deserializers.qll
index 5a076703afc..012c74bbe9a 100644
--- a/csharp/ql/src/semmle/code/csharp/serialization/Deserializers.qll
+++ b/csharp/ql/src/semmle/code/csharp/serialization/Deserializers.qll
@@ -63,6 +63,8 @@ class WeakTypeDeserializer extends Class {
this instanceof ServiceStackTextCsvSerializerClass
or
this instanceof ServiceStackTextXmlSerializerClass
+ or
+ this instanceof SharpSerializerClass
}
}
@@ -624,3 +626,16 @@ class CsPicklerSerializerClassUnPickleOfStringMethod extends Method, UnsafeDeser
this.hasName("UnPickleOfString")
}
}
+
+/** Polenter.Serialization.SharpSerializer */
+private class SharpSerializerClass extends Class {
+ SharpSerializerClass() { this.hasQualifiedName("Polenter.Serialization.SharpSerializer") }
+}
+
+/** `Polenter.Serialization.SharpSerializer.Deserialize` method */
+class SharpSerializerClassDeserializeMethod extends Method, UnsafeDeserializer {
+ SharpSerializerClassDeserializeMethod() {
+ this.getDeclaringType().getBaseClass*() instanceof SharpSerializerClass and
+ this.hasName("Deserialize")
+ }
+}
From f4cb6c50c00c4e3f7d9240a8a930f4872c0911b8 Mon Sep 17 00:00:00 2001
From: edvraa
Date: Tue, 15 Jun 2021 12:23:52 +0300
Subject: [PATCH 111/429] YamlDotNet
---
.../dataflow/UnsafeDeserialization.qll | 14 ++++++++++++++
.../csharp/serialization/Deserializers.qll | 18 ++++++++++++++++++
2 files changed, 32 insertions(+)
diff --git a/csharp/ql/src/semmle/code/csharp/security/dataflow/UnsafeDeserialization.qll b/csharp/ql/src/semmle/code/csharp/security/dataflow/UnsafeDeserialization.qll
index 573b4eaf461..d56935534ca 100644
--- a/csharp/ql/src/semmle/code/csharp/security/dataflow/UnsafeDeserialization.qll
+++ b/csharp/ql/src/semmle/code/csharp/security/dataflow/UnsafeDeserialization.qll
@@ -812,4 +812,18 @@ module UnsafeDeserialization {
)
}
}
+
+ /** YamlDotNet */
+ private class YamlDotNetDeserializerDeserializeMethodSink extends ConstructorOrStaticMethodSink {
+ YamlDotNetDeserializerDeserializeMethodSink() {
+ exists(MethodCall mc, Method m |
+ m = mc.getTarget() and
+ (
+ not mc.getArgument(0).hasValue() and
+ m instanceof YamlDotNetDeserializerClasseserializeMethod
+ ) and
+ this.asExpr() = mc.getArgument(0)
+ )
+ }
+ }
}
diff --git a/csharp/ql/src/semmle/code/csharp/serialization/Deserializers.qll b/csharp/ql/src/semmle/code/csharp/serialization/Deserializers.qll
index 012c74bbe9a..48dbe6f70f7 100644
--- a/csharp/ql/src/semmle/code/csharp/serialization/Deserializers.qll
+++ b/csharp/ql/src/semmle/code/csharp/serialization/Deserializers.qll
@@ -65,6 +65,8 @@ class WeakTypeDeserializer extends Class {
this instanceof ServiceStackTextXmlSerializerClass
or
this instanceof SharpSerializerClass
+ or
+ this instanceof YamlDotNetDeserializerClass
}
}
@@ -639,3 +641,19 @@ class SharpSerializerClassDeserializeMethod extends Method, UnsafeDeserializer {
this.hasName("Deserialize")
}
}
+
+/** YamlDotNet.Serialization.Deserializer */
+private class YamlDotNetDeserializerClass extends Class {
+ YamlDotNetDeserializerClass() { this.hasQualifiedName("YamlDotNet.Serialization.Deserializer") }
+}
+
+/** `YamlDotNet.Serialization.Deserializer.Deserialize` method */
+class YamlDotNetDeserializerClasseserializeMethod extends Method, UnsafeDeserializer {
+ YamlDotNetDeserializerClasseserializeMethod() {
+ exists(YamlDotNetDeserializerClass c |
+ this.getDeclaringType().getBaseClass*() = c and
+ this.hasName("Deserialize") and
+ c.getALocation().(Assembly).getVersion().getMajor() < 5
+ )
+ }
+}
From a0942e0360e70da7cff65e039e5f25229a7054a2 Mon Sep 17 00:00:00 2001
From: edvraa
Date: Mon, 12 Jul 2021 15:10:21 +0300
Subject: [PATCH 112/429] JsonConvert
---
.../UnsafeDeserializationUntrustedInput.ql | 11 +++
.../semmle/code/csharp/frameworks/JsonNET.qll | 13 +++
.../dataflow/UnsafeDeserialization.qll | 88 ++++++++++++++++++-
.../csharp/serialization/Deserializers.qll | 12 +++
4 files changed, 122 insertions(+), 2 deletions(-)
diff --git a/csharp/ql/src/Security Features/CWE-502/UnsafeDeserializationUntrustedInput.ql b/csharp/ql/src/Security Features/CWE-502/UnsafeDeserializationUntrustedInput.ql
index 963896e6d66..e8ee6bbe058 100644
--- a/csharp/ql/src/Security Features/CWE-502/UnsafeDeserializationUntrustedInput.ql
+++ b/csharp/ql/src/Security Features/CWE-502/UnsafeDeserializationUntrustedInput.ql
@@ -46,5 +46,16 @@ where
exists(TaintToConstructorOrStaticMethodTrackingConfig taintTracking2 |
taintTracking2.hasFlowPath(userInput, deserializeCallArg)
)
+ or
+ // JsonConvert static method call, but with additional unsafe typename tracking
+ exists(
+ JsonConvertTrackingConfig taintTrackingJsonConvert, TypeNameTrackingConfig typenameTracking,
+ DataFlow::PathNode settingsCallArg
+ |
+ taintTrackingJsonConvert.hasFlowPath(userInput, deserializeCallArg) and
+ typenameTracking.hasFlowPath(_, settingsCallArg) and
+ deserializeCallArg.getNode().asExpr().getParent() =
+ settingsCallArg.getNode().asExpr().getParent()
+ )
select deserializeCallArg, userInput, deserializeCallArg, "$@ flows to unsafe deserializer.",
userInput, "User-provided data"
diff --git a/csharp/ql/src/semmle/code/csharp/frameworks/JsonNET.qll b/csharp/ql/src/semmle/code/csharp/frameworks/JsonNET.qll
index 54019d13216..abd820bdfe4 100644
--- a/csharp/ql/src/semmle/code/csharp/frameworks/JsonNET.qll
+++ b/csharp/ql/src/semmle/code/csharp/frameworks/JsonNET.qll
@@ -17,6 +17,19 @@ module JsonNET {
JsonClass() { this.getParent() instanceof JsonNETNamespace }
}
+ /** Newtonsoft.Json.TypeNameHandling enum */
+ class TypeNameHandlingEnum extends Enum {
+ TypeNameHandlingEnum() {
+ this.getParent() instanceof JsonNETNamespace and
+ this.hasName("TypeNameHandling")
+ }
+ }
+
+ /** Newtonsoft.Json.JsonSerializerSettings class */
+ class JsonSerializerSettingsClass extends JsonClass {
+ JsonSerializerSettingsClass() { this.hasName("JsonSerializerSettings") }
+ }
+
/** The class `Newtonsoft.Json.JsonConvert`. */
class JsonConvertClass extends JsonClass, LibraryTypeDataFlow {
JsonConvertClass() { this.hasName("JsonConvert") }
diff --git a/csharp/ql/src/semmle/code/csharp/security/dataflow/UnsafeDeserialization.qll b/csharp/ql/src/semmle/code/csharp/security/dataflow/UnsafeDeserialization.qll
index d56935534ca..69aaab1fed2 100644
--- a/csharp/ql/src/semmle/code/csharp/security/dataflow/UnsafeDeserialization.qll
+++ b/csharp/ql/src/semmle/code/csharp/security/dataflow/UnsafeDeserialization.qll
@@ -59,7 +59,7 @@ module UnsafeDeserialization {
* User input to object method call deserialization flow tracking.
*/
class TaintToObjectMethodTrackingConfig extends TaintTracking::Configuration {
- TaintToObjectMethodTrackingConfig() { this = "UnsafeDeserialization1" }
+ TaintToObjectMethodTrackingConfig() { this = "TaintToObjectMethodTrackingConfig" }
override predicate isSource(DataFlow::Node source) { source instanceof Source }
@@ -68,11 +68,81 @@ module UnsafeDeserialization {
override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer }
}
+ /**
+ * User input to `JsonConvert` call deserialization flow tracking.
+ */
+ class JsonConvertTrackingConfig extends TaintTracking::Configuration {
+ JsonConvertTrackingConfig() { this = "JsonConvertTrackingConfig" }
+
+ override predicate isSource(DataFlow::Node source) { source instanceof Source }
+
+ override predicate isSink(DataFlow::Node sink) {
+ sink instanceof NewtonsoftJsonConvertDeserializeObjectMethodSink
+ }
+
+ override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer }
+ }
+
+ /**
+ * Tracks unsafe `TypeNameHandling` setting to `JsonConvert` call
+ */
+ class TypeNameTrackingConfig extends DataFlow::Configuration {
+ TypeNameTrackingConfig() { this = "TypeNameTrackingConfig" }
+
+ override predicate isSource(DataFlow::Node source) {
+ (
+ source.asExpr() instanceof MemberConstantAccess and
+ source.getType() instanceof TypeNameHandlingEnum
+ or
+ source.asExpr() instanceof IntegerLiteral
+ ) and
+ source.asExpr().hasValue() and
+ not source.asExpr().getValue() = "0"
+ }
+
+ override predicate isSink(DataFlow::Node sink) {
+ exists(MethodCall mc, Method m, Expr expr |
+ m = mc.getTarget() and
+ (
+ not mc.getArgument(0).hasValue() and
+ m instanceof NewtonsoftJsonConvertClassDeserializeObjectMethod
+ ) and
+ expr = mc.getAnArgument() and
+ sink.asExpr() = expr and
+ expr.getType() instanceof JsonSerializerSettingsClass
+ )
+ }
+
+ override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
+ node1.asExpr() instanceof IntegerLiteral and
+ node2.asExpr().(CastExpr).getExpr() = node1.asExpr()
+ or
+ node1.getType() instanceof TypeNameHandlingEnum and
+ exists(PropertyWrite pw, Property p, Assignment a |
+ a.getLValue() = pw and
+ pw.getProperty() = p and
+ p.getDeclaringType() instanceof JsonSerializerSettingsClass and
+ p.hasName("TypeNameHandling") and
+ (
+ node1.asExpr() = a.getRValue() and
+ node2.asExpr() = pw.getQualifier()
+ or
+ exists(ObjectInitializer oi |
+ node1.asExpr() = oi.getAMemberInitializer().getRValue() and
+ node2.asExpr() = oi
+ )
+ )
+ )
+ }
+ }
+
/**
* User input to static method or constructor call deserialization flow tracking.
*/
class TaintToConstructorOrStaticMethodTrackingConfig extends TaintTracking::Configuration {
- TaintToConstructorOrStaticMethodTrackingConfig() { this = "UnsafeDeserialization2" }
+ TaintToConstructorOrStaticMethodTrackingConfig() {
+ this = "TaintToConstructorOrStaticMethodTrackingConfig"
+ }
override predicate isSource(DataFlow::Node source) { source instanceof Source }
@@ -826,4 +896,18 @@ module UnsafeDeserialization {
)
}
}
+
+ /** Newtonsoft.Json.JsonConvert */
+ private class NewtonsoftJsonConvertDeserializeObjectMethodSink extends ConstructorOrStaticMethodSink {
+ NewtonsoftJsonConvertDeserializeObjectMethodSink() {
+ exists(MethodCall mc, Method m |
+ m = mc.getTarget() and
+ (
+ not mc.getArgument(0).hasValue() and
+ m instanceof NewtonsoftJsonConvertClassDeserializeObjectMethod
+ ) and
+ this.asExpr() = mc.getArgument(0)
+ )
+ }
+ }
}
diff --git a/csharp/ql/src/semmle/code/csharp/serialization/Deserializers.qll b/csharp/ql/src/semmle/code/csharp/serialization/Deserializers.qll
index 48dbe6f70f7..c395840c032 100644
--- a/csharp/ql/src/semmle/code/csharp/serialization/Deserializers.qll
+++ b/csharp/ql/src/semmle/code/csharp/serialization/Deserializers.qll
@@ -4,6 +4,7 @@
*/
import csharp
+import semmle.code.csharp.frameworks.JsonNET::JsonNET
/** An unsafe deserializer. */
abstract class UnsafeDeserializer extends Callable { }
@@ -67,6 +68,8 @@ class WeakTypeDeserializer extends Class {
this instanceof SharpSerializerClass
or
this instanceof YamlDotNetDeserializerClass
+ or
+ this instanceof JsonConvertClass
}
}
@@ -657,3 +660,12 @@ class YamlDotNetDeserializerClasseserializeMethod extends Method, UnsafeDeserial
)
}
}
+
+/** `Newtonsoft.Json.JsonConvert.DeserializeObject` method */
+class NewtonsoftJsonConvertClassDeserializeObjectMethod extends Method, UnsafeDeserializer {
+ NewtonsoftJsonConvertClassDeserializeObjectMethod() {
+ this.getDeclaringType() instanceof JsonConvertClass and
+ this.hasName("DeserializeObject") and
+ this.isStatic()
+ }
+}
From 51a614025806756b33b0c9764fd91b3e2405570b Mon Sep 17 00:00:00 2001
From: "${sleep,5}" <52643283+mrthankyou@users.noreply.github.com>
Date: Tue, 13 Jul 2021 14:04:06 -0400
Subject: [PATCH 113/429] Change variable name to correct sanitized input
variable
Co-authored-by: Rasmus Wriedt Larsen
---
.../query-tests/Security/CWE-943/mongoengine_good.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_good.py b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_good.py
index 1ece6997a89..c9b2b8e762f 100644
--- a/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_good.py
+++ b/python/ql/test/experimental/query-tests/Security/CWE-943/mongoengine_good.py
@@ -21,7 +21,7 @@ def connect_find():
safe_search = sanitize(json_search)
db = me.connect('mydb')
- return db.movie.find({'name': json_search})
+ return db.movie.find({'name': safe_search})
# if __name__ == "__main__":
# app.run(debug=True)
From fd4d8e259529d75cb99bfef7904de3fb12980a2e Mon Sep 17 00:00:00 2001
From: edvraa <80588099+edvraa@users.noreply.github.com>
Date: Wed, 14 Jul 2021 16:06:34 +0300
Subject: [PATCH 114/429] Use HasFlow instead HasFlowPath
---
.../CWE-502/UnsafeDeserializationUntrustedInput.ql | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/csharp/ql/src/Security Features/CWE-502/UnsafeDeserializationUntrustedInput.ql b/csharp/ql/src/Security Features/CWE-502/UnsafeDeserializationUntrustedInput.ql
index e8ee6bbe058..6fce8c14977 100644
--- a/csharp/ql/src/Security Features/CWE-502/UnsafeDeserializationUntrustedInput.ql
+++ b/csharp/ql/src/Security Features/CWE-502/UnsafeDeserializationUntrustedInput.ql
@@ -50,12 +50,11 @@ where
// JsonConvert static method call, but with additional unsafe typename tracking
exists(
JsonConvertTrackingConfig taintTrackingJsonConvert, TypeNameTrackingConfig typenameTracking,
- DataFlow::PathNode settingsCallArg
+ DataFlow::Node settingsCallArg
|
taintTrackingJsonConvert.hasFlowPath(userInput, deserializeCallArg) and
- typenameTracking.hasFlowPath(_, settingsCallArg) and
- deserializeCallArg.getNode().asExpr().getParent() =
- settingsCallArg.getNode().asExpr().getParent()
+ typenameTracking.hasFlow(_, settingsCallArg) and
+ deserializeCallArg.getNode().asExpr().getParent() = settingsCallArg.asExpr().getParent()
)
select deserializeCallArg, userInput, deserializeCallArg, "$@ flows to unsafe deserializer.",
userInput, "User-provided data"
From 80d784e37ac757175721fe8b2961e63ce7fdff2e Mon Sep 17 00:00:00 2001
From: Erik Krogh Kristensen
Date: Wed, 14 Jul 2021 21:51:36 +0200
Subject: [PATCH 115/429] add a step over empty lookaheads/lookbehinds
---
.../security/performance/ReDoSUtil.qll | 47 +++++++++++++++++++
.../performance/SuperlinearBackTracking.qll | 29 ------------
.../ReDoS/PolynomialBackTracking.expected | 4 ++
.../Performance/ReDoS/ReDoS.expected | 2 +
.../test/query-tests/Performance/ReDoS/tst.js | 9 +++-
5 files changed, 61 insertions(+), 30 deletions(-)
diff --git a/javascript/ql/src/semmle/javascript/security/performance/ReDoSUtil.qll b/javascript/ql/src/semmle/javascript/security/performance/ReDoSUtil.qll
index 40b05825bc6..38eede15e8a 100644
--- a/javascript/ql/src/semmle/javascript/security/performance/ReDoSUtil.qll
+++ b/javascript/ql/src/semmle/javascript/security/performance/ReDoSUtil.qll
@@ -71,6 +71,49 @@ private int ascii(string char) {
)
}
+/**
+ * Holds if `t` matches at least an epsilon symbol.
+ *
+ * That is, this term does not restrict the language of the enclosing regular expression.
+ *
+ * This is implemented as an under-approximation, and this predicate does not hold for sub-patterns in particular.
+ */
+predicate matchesEpsilon(RegExpTerm t) {
+ t instanceof RegExpStar
+ or
+ t instanceof RegExpOpt
+ or
+ t.(RegExpRange).getLowerBound() = 0
+ or
+ exists(RegExpTerm child |
+ child = t.getAChild() and
+ matchesEpsilon(child)
+ |
+ t instanceof RegExpAlt or
+ t instanceof RegExpGroup or
+ t instanceof RegExpPlus or
+ t instanceof RegExpRange
+ )
+ or
+ matchesEpsilon(t.(RegExpBackRef).getGroup())
+ or
+ forex(RegExpTerm child | child = t.(RegExpSequence).getAChild() | matchesEpsilon(child))
+}
+
+/**
+ * A lookahead/lookbehind that matches the empty string.
+ */
+class EmptyPositiveSubPatttern extends RegExpSubPattern {
+ EmptyPositiveSubPatttern() {
+ (
+ this instanceof RegExpPositiveLookahead
+ or
+ this instanceof RegExpPositiveLookbehind
+ ) and
+ matchesEpsilon(this.getOperand())
+ }
+}
+
/**
* A branch in a disjunction that is the root node in a literal, or a literal
* whose root node is not a disjunction.
@@ -550,6 +593,10 @@ predicate delta(State q1, EdgeLabel lbl, State q2) {
exists(RegExpDollar dollar | q1 = before(dollar) |
lbl = Epsilon() and q2 = Accept(getRoot(dollar))
)
+ or
+ exists(EmptyPositiveSubPatttern empty | q1 = before(empty) |
+ lbl = Epsilon() and q2 = after(empty)
+ )
}
/**
diff --git a/javascript/ql/src/semmle/javascript/security/performance/SuperlinearBackTracking.qll b/javascript/ql/src/semmle/javascript/security/performance/SuperlinearBackTracking.qll
index 0bbff12b49d..2b42165ff7e 100644
--- a/javascript/ql/src/semmle/javascript/security/performance/SuperlinearBackTracking.qll
+++ b/javascript/ql/src/semmle/javascript/security/performance/SuperlinearBackTracking.qll
@@ -363,35 +363,6 @@ predicate polynimalReDoS(RegExpTerm t, string pump, string prefixMsg, RegExpTerm
)
}
-/**
- * Holds if `t` matches at least an epsilon symbol.
- *
- * That is, this term does not restrict the language of the enclosing regular expression.
- *
- * This is implemented as an under-approximation, and this predicate does not hold for sub-patterns in particular.
- */
-private predicate matchesEpsilon(RegExpTerm t) {
- t instanceof RegExpStar
- or
- t instanceof RegExpOpt
- or
- t.(RegExpRange).getLowerBound() = 0
- or
- exists(RegExpTerm child |
- child = t.getAChild() and
- matchesEpsilon(child)
- |
- t instanceof RegExpAlt or
- t instanceof RegExpGroup or
- t instanceof RegExpPlus or
- t instanceof RegExpRange
- )
- or
- matchesEpsilon(t.(RegExpBackRef).getGroup())
- or
- forex(RegExpTerm child | child = t.(RegExpSequence).getAChild() | matchesEpsilon(child))
-}
-
/**
* Gets a message for why `term` can cause polynomial backtracking.
*/
diff --git a/javascript/ql/test/query-tests/Performance/ReDoS/PolynomialBackTracking.expected b/javascript/ql/test/query-tests/Performance/ReDoS/PolynomialBackTracking.expected
index ad6bbc49dbb..490373d8b46 100644
--- a/javascript/ql/test/query-tests/Performance/ReDoS/PolynomialBackTracking.expected
+++ b/javascript/ql/test/query-tests/Performance/ReDoS/PolynomialBackTracking.expected
@@ -493,3 +493,7 @@
| tst.js:351:15:351:16 | a+ | Strings with many repetitions of 'a' can start matching anywhere after the start of the preceeding (a+)* |
| tst.js:352:15:352:16 | a* | Strings with many repetitions of 'a' can start matching anywhere after the start of the preceeding (a*)+b |
| tst.js:353:15:353:16 | a+ | Strings with many repetitions of 'a' can start matching anywhere after the start of the preceeding (a+)+ |
+| tst.js:372:16:372:21 | [^"]*? | Strings starting with '"' and with many repetitions of '""' can start matching anywhere after the start of the preceeding ("[^"]*?"\|[^"\\s]+)+(?=\\s*\|\\s*$)X |
+| tst.js:372:24:372:30 | [^"\\s]+ | Strings with many repetitions of '!' can start matching anywhere after the start of the preceeding ("[^"]*?"\|[^"\\s]+)+ |
+| tst.js:373:16:373:21 | [^"]*? | Strings starting with '"' and with many repetitions of '""' can start matching anywhere after the start of the preceeding ("[^"]*?"\|[^"\\s]+)+(?=X) |
+| tst.js:373:24:373:30 | [^"\\s]+ | Strings with many repetitions of '!' can start matching anywhere after the start of the preceeding ("[^"]*?"\|[^"\\s]+)+ |
diff --git a/javascript/ql/test/query-tests/Performance/ReDoS/ReDoS.expected b/javascript/ql/test/query-tests/Performance/ReDoS/ReDoS.expected
index 7c7eedf6854..5c57c92108d 100644
--- a/javascript/ql/test/query-tests/Performance/ReDoS/ReDoS.expected
+++ b/javascript/ql/test/query-tests/Performance/ReDoS/ReDoS.expected
@@ -172,3 +172,5 @@
| tst.js:361:15:361:33 | ((?:a{0\|-)\|\\w\\{\\d)+ | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of 'a{0'. |
| tst.js:362:15:362:35 | ((?:a{0,\|-)\|\\w\\{\\d,)+ | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of 'a{0,'. |
| tst.js:363:15:363:38 | ((?:a{0,2\|-)\|\\w\\{\\d,\\d)+ | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of 'a{0,2'. |
+| tst.js:372:24:372:30 | [^"\\s]+ | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of '!'. |
+| tst.js:373:24:373:30 | [^"\\s]+ | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of '!'. |
diff --git a/javascript/ql/test/query-tests/Performance/ReDoS/tst.js b/javascript/ql/test/query-tests/Performance/ReDoS/tst.js
index 6185cdf8add..873ab3b78a0 100644
--- a/javascript/ql/test/query-tests/Performance/ReDoS/tst.js
+++ b/javascript/ql/test/query-tests/Performance/ReDoS/tst.js
@@ -363,4 +363,11 @@ var bad85 = /^((?:a{0,|-)|\w\{\d,)+X$/;
var bad86 = /^((?:a{0,2|-)|\w\{\d,\d)+X$/;
// GOOD:
-var good42 = /^((?:a{0,2}|-)|\w\{\d,\d\})+X$/;
\ No newline at end of file
+var good42 = /^((?:a{0,2}|-)|\w\{\d,\d\})+X$/;
+
+// GOOD
+var good43 = /("[^"]*?"|[^"\s]+)+(?=\s*|\s*$)/g;
+
+// BAD
+var bad87 = /("[^"]*?"|[^"\s]+)+(?=\s*|\s*$)X/g;
+var bad88 = /("[^"]*?"|[^"\s]+)+(?=X)/g;
\ No newline at end of file
From de8f64c5be90898ec934080234d52ffe315c9ca2 Mon Sep 17 00:00:00 2001
From: Erik Krogh Kristensen
Date: Wed, 14 Jul 2021 21:52:23 +0200
Subject: [PATCH 116/429] sync with python
---
.../python/security/performance/ReDoSUtil.qll | 47 +++++++++++++++++++
.../performance/SuperlinearBackTracking.qll | 29 ------------
2 files changed, 47 insertions(+), 29 deletions(-)
diff --git a/python/ql/src/semmle/python/security/performance/ReDoSUtil.qll b/python/ql/src/semmle/python/security/performance/ReDoSUtil.qll
index 40b05825bc6..38eede15e8a 100644
--- a/python/ql/src/semmle/python/security/performance/ReDoSUtil.qll
+++ b/python/ql/src/semmle/python/security/performance/ReDoSUtil.qll
@@ -71,6 +71,49 @@ private int ascii(string char) {
)
}
+/**
+ * Holds if `t` matches at least an epsilon symbol.
+ *
+ * That is, this term does not restrict the language of the enclosing regular expression.
+ *
+ * This is implemented as an under-approximation, and this predicate does not hold for sub-patterns in particular.
+ */
+predicate matchesEpsilon(RegExpTerm t) {
+ t instanceof RegExpStar
+ or
+ t instanceof RegExpOpt
+ or
+ t.(RegExpRange).getLowerBound() = 0
+ or
+ exists(RegExpTerm child |
+ child = t.getAChild() and
+ matchesEpsilon(child)
+ |
+ t instanceof RegExpAlt or
+ t instanceof RegExpGroup or
+ t instanceof RegExpPlus or
+ t instanceof RegExpRange
+ )
+ or
+ matchesEpsilon(t.(RegExpBackRef).getGroup())
+ or
+ forex(RegExpTerm child | child = t.(RegExpSequence).getAChild() | matchesEpsilon(child))
+}
+
+/**
+ * A lookahead/lookbehind that matches the empty string.
+ */
+class EmptyPositiveSubPatttern extends RegExpSubPattern {
+ EmptyPositiveSubPatttern() {
+ (
+ this instanceof RegExpPositiveLookahead
+ or
+ this instanceof RegExpPositiveLookbehind
+ ) and
+ matchesEpsilon(this.getOperand())
+ }
+}
+
/**
* A branch in a disjunction that is the root node in a literal, or a literal
* whose root node is not a disjunction.
@@ -550,6 +593,10 @@ predicate delta(State q1, EdgeLabel lbl, State q2) {
exists(RegExpDollar dollar | q1 = before(dollar) |
lbl = Epsilon() and q2 = Accept(getRoot(dollar))
)
+ or
+ exists(EmptyPositiveSubPatttern empty | q1 = before(empty) |
+ lbl = Epsilon() and q2 = after(empty)
+ )
}
/**
diff --git a/python/ql/src/semmle/python/security/performance/SuperlinearBackTracking.qll b/python/ql/src/semmle/python/security/performance/SuperlinearBackTracking.qll
index 0bbff12b49d..2b42165ff7e 100644
--- a/python/ql/src/semmle/python/security/performance/SuperlinearBackTracking.qll
+++ b/python/ql/src/semmle/python/security/performance/SuperlinearBackTracking.qll
@@ -363,35 +363,6 @@ predicate polynimalReDoS(RegExpTerm t, string pump, string prefixMsg, RegExpTerm
)
}
-/**
- * Holds if `t` matches at least an epsilon symbol.
- *
- * That is, this term does not restrict the language of the enclosing regular expression.
- *
- * This is implemented as an under-approximation, and this predicate does not hold for sub-patterns in particular.
- */
-private predicate matchesEpsilon(RegExpTerm t) {
- t instanceof RegExpStar
- or
- t instanceof RegExpOpt
- or
- t.(RegExpRange).getLowerBound() = 0
- or
- exists(RegExpTerm child |
- child = t.getAChild() and
- matchesEpsilon(child)
- |
- t instanceof RegExpAlt or
- t instanceof RegExpGroup or
- t instanceof RegExpPlus or
- t instanceof RegExpRange
- )
- or
- matchesEpsilon(t.(RegExpBackRef).getGroup())
- or
- forex(RegExpTerm child | child = t.(RegExpSequence).getAChild() | matchesEpsilon(child))
-}
-
/**
* Gets a message for why `term` can cause polynomial backtracking.
*/
From 383b5f2ff281e1a1fecda9b2dd5adfd59005cabc Mon Sep 17 00:00:00 2001
From: Erik Krogh Kristensen
Date: Thu, 15 Jul 2021 09:41:53 +0200
Subject: [PATCH 117/429] implement RegExpSubPattern.getOperand in the Python
regexp implementation
---
python/ql/src/semmle/python/RegexTreeView.qll | 7 +++++++
.../ql/test/query-tests/Security/CWE-730/ReDoS.expected | 2 ++
python/ql/test/query-tests/Security/CWE-730/redos.py | 9 ++++++++-
3 files changed, 17 insertions(+), 1 deletion(-)
diff --git a/python/ql/src/semmle/python/RegexTreeView.qll b/python/ql/src/semmle/python/RegexTreeView.qll
index 5aae3021899..5248f21922f 100644
--- a/python/ql/src/semmle/python/RegexTreeView.qll
+++ b/python/ql/src/semmle/python/RegexTreeView.qll
@@ -836,6 +836,13 @@ class RegExpZeroWidthMatch extends RegExpGroup {
*/
class RegExpSubPattern extends RegExpZeroWidthMatch {
RegExpSubPattern() { not re.emptyGroup(start, end) }
+
+ /** Gets the lookahead term. */
+ RegExpTerm getOperand() {
+ result.getRegex() = re and
+ result.getStart() = start + 3 and
+ result.getEnd() = end - 1
+ }
}
/**
diff --git a/python/ql/test/query-tests/Security/CWE-730/ReDoS.expected b/python/ql/test/query-tests/Security/CWE-730/ReDoS.expected
index 4a4b5ee4262..21db78dd092 100644
--- a/python/ql/test/query-tests/Security/CWE-730/ReDoS.expected
+++ b/python/ql/test/query-tests/Security/CWE-730/ReDoS.expected
@@ -93,5 +93,7 @@
| redos.py:364:25:364:45 | ((?:a{0,\|-)\|\\w\\{\\d,)+ | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of 'a{0,'. |
| redos.py:365:25:365:48 | ((?:a{0,2\|-)\|\\w\\{\\d,\\d)+ | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of 'a{0,2'. |
| redos.py:371:25:371:35 | (\\u0061\|a)* | This part of the regular expression may cause exponential backtracking on strings starting with 'X' and containing many repetitions of 'a'. |
+| redos.py:380:35:380:41 | [^"\\s]+ | This part of the regular expression may cause exponential backtracking on strings starting with '/' and containing many repetitions of '!'. |
+| redos.py:381:35:381:41 | [^"\\s]+ | This part of the regular expression may cause exponential backtracking on strings starting with '/' and containing many repetitions of '!'. |
| unittests.py:5:17:5:23 | (\u00c6\|\\\u00c6)+ | This part of the regular expression may cause exponential backtracking on strings starting with 'X' and containing many repetitions of '\u00c6'. |
| unittests.py:9:16:9:24 | (?:.\|\\n)* | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of '\\n'. |
diff --git a/python/ql/test/query-tests/Security/CWE-730/redos.py b/python/ql/test/query-tests/Security/CWE-730/redos.py
index 37c637c2750..733c594a53a 100644
--- a/python/ql/test/query-tests/Security/CWE-730/redos.py
+++ b/python/ql/test/query-tests/Security/CWE-730/redos.py
@@ -371,4 +371,11 @@ good42 = re.compile(r'''^((?:a{0,2}|-)|\w\{\d,\d\})+X$''')
bad87 = re.compile(r'X(\u0061|a)*Y')
# GOOD
-good43 = re.compile(r'X(\u0061|b)+Y')
\ No newline at end of file
+good43 = re.compile(r'X(\u0061|b)+Y')
+
+# GOOD
+good44 = re.compile(r'("[^"]*?"|[^"\s]+)+(?=\s*|\s*$)')
+
+# BAD
+bad88 = re.compile(r'/("[^"]*?"|[^"\s]+)+(?=\s*|\s*$)X')
+bad89 = re.compile(r'/("[^"]*?"|[^"\s]+)+(?=X)')
\ No newline at end of file
From 6f09b95019b2ac2b9980d4fdadb1c0706366d4dd Mon Sep 17 00:00:00 2001
From: jorgectf
Date: Thu, 15 Jul 2021 17:16:29 +0200
Subject: [PATCH 118/429] Update `.expected`
---
.../Security/CWE-943/NoSQLInjection.expected | 42 -------------------
1 file changed, 42 deletions(-)
diff --git a/python/ql/test/experimental/query-tests/Security/CWE-943/NoSQLInjection.expected b/python/ql/test/experimental/query-tests/Security/CWE-943/NoSQLInjection.expected
index 10c1f852df5..c6dd255a0de 100644
--- a/python/ql/test/experimental/query-tests/Security/CWE-943/NoSQLInjection.expected
+++ b/python/ql/test/experimental/query-tests/Security/CWE-943/NoSQLInjection.expected
@@ -10,9 +10,6 @@ edges
| flask_mongoengine_good.py:20:21:20:27 | ControlFlowNode for request | flask_mongoengine_good.py:20:21:20:32 | ControlFlowNode for Attribute |
| flask_mongoengine_good.py:20:21:20:32 | ControlFlowNode for Attribute | flask_mongoengine_good.py:20:21:20:42 | ControlFlowNode for Subscript |
| flask_mongoengine_good.py:20:21:20:42 | ControlFlowNode for Subscript | flask_mongoengine_good.py:21:19:21:43 | ControlFlowNode for Attribute() |
-| flask_mongoengine_good.py:28:21:28:27 | ControlFlowNode for request | flask_mongoengine_good.py:28:21:28:32 | ControlFlowNode for Attribute |
-| flask_mongoengine_good.py:28:21:28:32 | ControlFlowNode for Attribute | flask_mongoengine_good.py:28:21:28:42 | ControlFlowNode for Subscript |
-| flask_mongoengine_good.py:28:21:28:42 | ControlFlowNode for Subscript | flask_mongoengine_good.py:29:19:29:43 | ControlFlowNode for Attribute() |
| flask_pymongo_bad.py:11:21:11:27 | ControlFlowNode for request | flask_pymongo_bad.py:11:21:11:32 | ControlFlowNode for Attribute |
| flask_pymongo_bad.py:11:21:11:32 | ControlFlowNode for Attribute | flask_pymongo_bad.py:11:21:11:42 | ControlFlowNode for Subscript |
| flask_pymongo_bad.py:11:21:11:42 | ControlFlowNode for Subscript | flask_pymongo_bad.py:12:19:12:43 | ControlFlowNode for Attribute() |
@@ -47,21 +44,6 @@ edges
| mongoengine_good.py:19:21:19:27 | ControlFlowNode for request | mongoengine_good.py:19:21:19:32 | ControlFlowNode for Attribute |
| mongoengine_good.py:19:21:19:32 | ControlFlowNode for Attribute | mongoengine_good.py:19:21:19:42 | ControlFlowNode for Subscript |
| mongoengine_good.py:19:21:19:42 | ControlFlowNode for Subscript | mongoengine_good.py:20:19:20:43 | ControlFlowNode for Attribute() |
-| mongoengine_good.py:28:21:28:27 | ControlFlowNode for request | mongoengine_good.py:28:21:28:32 | ControlFlowNode for Attribute |
-| mongoengine_good.py:28:21:28:32 | ControlFlowNode for Attribute | mongoengine_good.py:28:21:28:42 | ControlFlowNode for Subscript |
-| mongoengine_good.py:28:21:28:42 | ControlFlowNode for Subscript | mongoengine_good.py:29:19:29:43 | ControlFlowNode for Attribute() |
-| mongoengine_good.py:37:21:37:27 | ControlFlowNode for request | mongoengine_good.py:37:21:37:32 | ControlFlowNode for Attribute |
-| mongoengine_good.py:37:21:37:32 | ControlFlowNode for Attribute | mongoengine_good.py:37:21:37:42 | ControlFlowNode for Subscript |
-| mongoengine_good.py:37:21:37:42 | ControlFlowNode for Subscript | mongoengine_good.py:38:19:38:43 | ControlFlowNode for Attribute() |
-| mongoengine_good.py:45:21:45:27 | ControlFlowNode for request | mongoengine_good.py:45:21:45:32 | ControlFlowNode for Attribute |
-| mongoengine_good.py:45:21:45:32 | ControlFlowNode for Attribute | mongoengine_good.py:45:21:45:42 | ControlFlowNode for Subscript |
-| mongoengine_good.py:45:21:45:42 | ControlFlowNode for Subscript | mongoengine_good.py:46:19:46:43 | ControlFlowNode for Attribute() |
-| mongoengine_good.py:54:21:54:27 | ControlFlowNode for request | mongoengine_good.py:54:21:54:32 | ControlFlowNode for Attribute |
-| mongoengine_good.py:54:21:54:32 | ControlFlowNode for Attribute | mongoengine_good.py:54:21:54:42 | ControlFlowNode for Subscript |
-| mongoengine_good.py:54:21:54:42 | ControlFlowNode for Subscript | mongoengine_good.py:55:19:55:43 | ControlFlowNode for Attribute() |
-| mongoengine_good.py:63:21:63:27 | ControlFlowNode for request | mongoengine_good.py:63:21:63:32 | ControlFlowNode for Attribute |
-| mongoengine_good.py:63:21:63:32 | ControlFlowNode for Attribute | mongoengine_good.py:63:21:63:42 | ControlFlowNode for Subscript |
-| mongoengine_good.py:63:21:63:42 | ControlFlowNode for Subscript | mongoengine_good.py:64:19:64:43 | ControlFlowNode for Attribute() |
| pymongo_bad.py:11:21:11:27 | ControlFlowNode for request | pymongo_bad.py:11:21:11:32 | ControlFlowNode for Attribute |
| pymongo_bad.py:11:21:11:32 | ControlFlowNode for Attribute | pymongo_bad.py:11:21:11:42 | ControlFlowNode for Subscript |
| pymongo_bad.py:11:21:11:42 | ControlFlowNode for Subscript | pymongo_bad.py:12:19:12:43 | ControlFlowNode for Attribute() |
@@ -84,10 +66,6 @@ nodes
| flask_mongoengine_good.py:20:21:20:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
| flask_mongoengine_good.py:20:21:20:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
| flask_mongoengine_good.py:21:19:21:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
-| flask_mongoengine_good.py:28:21:28:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
-| flask_mongoengine_good.py:28:21:28:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
-| flask_mongoengine_good.py:28:21:28:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
-| flask_mongoengine_good.py:29:19:29:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
| flask_pymongo_bad.py:11:21:11:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
| flask_pymongo_bad.py:11:21:11:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
| flask_pymongo_bad.py:11:21:11:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
@@ -131,26 +109,6 @@ nodes
| mongoengine_good.py:19:21:19:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
| mongoengine_good.py:19:21:19:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
| mongoengine_good.py:20:19:20:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
-| mongoengine_good.py:28:21:28:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
-| mongoengine_good.py:28:21:28:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
-| mongoengine_good.py:28:21:28:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
-| mongoengine_good.py:29:19:29:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
-| mongoengine_good.py:37:21:37:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
-| mongoengine_good.py:37:21:37:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
-| mongoengine_good.py:37:21:37:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
-| mongoengine_good.py:38:19:38:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
-| mongoengine_good.py:45:21:45:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
-| mongoengine_good.py:45:21:45:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
-| mongoengine_good.py:45:21:45:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
-| mongoengine_good.py:46:19:46:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
-| mongoengine_good.py:54:21:54:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
-| mongoengine_good.py:54:21:54:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
-| mongoengine_good.py:54:21:54:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
-| mongoengine_good.py:55:19:55:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
-| mongoengine_good.py:63:21:63:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
-| mongoengine_good.py:63:21:63:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
-| mongoengine_good.py:63:21:63:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
-| mongoengine_good.py:64:19:64:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
| pymongo_bad.py:11:21:11:27 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
| pymongo_bad.py:11:21:11:32 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
| pymongo_bad.py:11:21:11:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
From b2b736db104f5b6d4656d6b4809d4f901a6e283f Mon Sep 17 00:00:00 2001
From: Erik Krogh Kristensen
Date: Fri, 16 Jul 2021 13:25:37 +0200
Subject: [PATCH 119/429] add more tests for non-empty positive lookaheads
---
.../Performance/ReDoS/PolynomialBackTracking.expected | 4 ++++
.../ql/test/query-tests/Performance/ReDoS/ReDoS.expected | 4 ++++
javascript/ql/test/query-tests/Performance/ReDoS/tst.js | 6 +++++-
3 files changed, 13 insertions(+), 1 deletion(-)
diff --git a/javascript/ql/test/query-tests/Performance/ReDoS/PolynomialBackTracking.expected b/javascript/ql/test/query-tests/Performance/ReDoS/PolynomialBackTracking.expected
index 490373d8b46..e45cc194d9b 100644
--- a/javascript/ql/test/query-tests/Performance/ReDoS/PolynomialBackTracking.expected
+++ b/javascript/ql/test/query-tests/Performance/ReDoS/PolynomialBackTracking.expected
@@ -497,3 +497,7 @@
| tst.js:372:24:372:30 | [^"\\s]+ | Strings with many repetitions of '!' can start matching anywhere after the start of the preceeding ("[^"]*?"\|[^"\\s]+)+ |
| tst.js:373:16:373:21 | [^"]*? | Strings starting with '"' and with many repetitions of '""' can start matching anywhere after the start of the preceeding ("[^"]*?"\|[^"\\s]+)+(?=X) |
| tst.js:373:24:373:30 | [^"\\s]+ | Strings with many repetitions of '!' can start matching anywhere after the start of the preceeding ("[^"]*?"\|[^"\\s]+)+ |
+| tst.js:374:15:374:16 | x* | Strings with many repetitions of 'x' can start matching anywhere after the start of the preceeding (x*)+(?=$) |
+| tst.js:375:15:375:16 | x* | Strings with many repetitions of 'x' can start matching anywhere after the start of the preceeding (x*)+(?=$\|y) |
+| tst.js:376:15:376:21 | [\\s\\S]* | Strings with many repetitions of 'a' can start matching anywhere after the start of the preceeding ([\\s\\S]*)+(?=$) |
+| tst.js:377:15:377:21 | [\\s\\S]* | Strings with many repetitions of 'a' can start matching anywhere after the start of the preceeding ([\\s\\S]*)+(?=$\|y) |
diff --git a/javascript/ql/test/query-tests/Performance/ReDoS/ReDoS.expected b/javascript/ql/test/query-tests/Performance/ReDoS/ReDoS.expected
index 5c57c92108d..346cf99d0da 100644
--- a/javascript/ql/test/query-tests/Performance/ReDoS/ReDoS.expected
+++ b/javascript/ql/test/query-tests/Performance/ReDoS/ReDoS.expected
@@ -174,3 +174,7 @@
| tst.js:363:15:363:38 | ((?:a{0,2\|-)\|\\w\\{\\d,\\d)+ | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of 'a{0,2'. |
| tst.js:372:24:372:30 | [^"\\s]+ | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of '!'. |
| tst.js:373:24:373:30 | [^"\\s]+ | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of '!'. |
+| tst.js:374:15:374:16 | x* | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of 'x'. |
+| tst.js:375:15:375:16 | x* | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of 'x'. |
+| tst.js:376:15:376:21 | [\\s\\S]* | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of 'a'. |
+| tst.js:377:15:377:21 | [\\s\\S]* | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of 'a'. |
diff --git a/javascript/ql/test/query-tests/Performance/ReDoS/tst.js b/javascript/ql/test/query-tests/Performance/ReDoS/tst.js
index 873ab3b78a0..8612448014f 100644
--- a/javascript/ql/test/query-tests/Performance/ReDoS/tst.js
+++ b/javascript/ql/test/query-tests/Performance/ReDoS/tst.js
@@ -370,4 +370,8 @@ var good43 = /("[^"]*?"|[^"\s]+)+(?=\s*|\s*$)/g;
// BAD
var bad87 = /("[^"]*?"|[^"\s]+)+(?=\s*|\s*$)X/g;
-var bad88 = /("[^"]*?"|[^"\s]+)+(?=X)/g;
\ No newline at end of file
+var bad88 = /("[^"]*?"|[^"\s]+)+(?=X)/g;
+var bad89 = /(x*)+(?=$)/
+var bad90 = /(x*)+(?=$|y)/
+var bad91 = /([\s\S]*)+(?=$)/
+var bad92 = /([\s\S]*)+(?=$|y)/
\ No newline at end of file
From 6da1007f679ad3d2163673c9b48bd765acff1aad Mon Sep 17 00:00:00 2001
From: Erik Krogh Kristensen
Date: Fri, 16 Jul 2021 13:37:47 +0200
Subject: [PATCH 120/429] mark new redos tests correctly
---
.../Performance/ReDoS/PolynomialBackTracking.expected | 4 ++--
.../ql/test/query-tests/Performance/ReDoS/ReDoS.expected | 4 ++--
javascript/ql/test/query-tests/Performance/ReDoS/tst.js | 6 ++++--
3 files changed, 8 insertions(+), 6 deletions(-)
diff --git a/javascript/ql/test/query-tests/Performance/ReDoS/PolynomialBackTracking.expected b/javascript/ql/test/query-tests/Performance/ReDoS/PolynomialBackTracking.expected
index e45cc194d9b..03b43ea97be 100644
--- a/javascript/ql/test/query-tests/Performance/ReDoS/PolynomialBackTracking.expected
+++ b/javascript/ql/test/query-tests/Performance/ReDoS/PolynomialBackTracking.expected
@@ -499,5 +499,5 @@
| tst.js:373:24:373:30 | [^"\\s]+ | Strings with many repetitions of '!' can start matching anywhere after the start of the preceeding ("[^"]*?"\|[^"\\s]+)+ |
| tst.js:374:15:374:16 | x* | Strings with many repetitions of 'x' can start matching anywhere after the start of the preceeding (x*)+(?=$) |
| tst.js:375:15:375:16 | x* | Strings with many repetitions of 'x' can start matching anywhere after the start of the preceeding (x*)+(?=$\|y) |
-| tst.js:376:15:376:21 | [\\s\\S]* | Strings with many repetitions of 'a' can start matching anywhere after the start of the preceeding ([\\s\\S]*)+(?=$) |
-| tst.js:377:15:377:21 | [\\s\\S]* | Strings with many repetitions of 'a' can start matching anywhere after the start of the preceeding ([\\s\\S]*)+(?=$\|y) |
+| tst.js:378:16:378:22 | [\\s\\S]* | Strings with many repetitions of 'a' can start matching anywhere after the start of the preceeding ([\\s\\S]*)+(?=$) |
+| tst.js:379:16:379:22 | [\\s\\S]* | Strings with many repetitions of 'a' can start matching anywhere after the start of the preceeding ([\\s\\S]*)+(?=$\|y) |
diff --git a/javascript/ql/test/query-tests/Performance/ReDoS/ReDoS.expected b/javascript/ql/test/query-tests/Performance/ReDoS/ReDoS.expected
index 346cf99d0da..05352f7a20d 100644
--- a/javascript/ql/test/query-tests/Performance/ReDoS/ReDoS.expected
+++ b/javascript/ql/test/query-tests/Performance/ReDoS/ReDoS.expected
@@ -176,5 +176,5 @@
| tst.js:373:24:373:30 | [^"\\s]+ | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of '!'. |
| tst.js:374:15:374:16 | x* | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of 'x'. |
| tst.js:375:15:375:16 | x* | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of 'x'. |
-| tst.js:376:15:376:21 | [\\s\\S]* | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of 'a'. |
-| tst.js:377:15:377:21 | [\\s\\S]* | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of 'a'. |
+| tst.js:378:16:378:22 | [\\s\\S]* | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of 'a'. |
+| tst.js:379:16:379:22 | [\\s\\S]* | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of 'a'. |
diff --git a/javascript/ql/test/query-tests/Performance/ReDoS/tst.js b/javascript/ql/test/query-tests/Performance/ReDoS/tst.js
index 8612448014f..762929080ae 100644
--- a/javascript/ql/test/query-tests/Performance/ReDoS/tst.js
+++ b/javascript/ql/test/query-tests/Performance/ReDoS/tst.js
@@ -373,5 +373,7 @@ var bad87 = /("[^"]*?"|[^"\s]+)+(?=\s*|\s*$)X/g;
var bad88 = /("[^"]*?"|[^"\s]+)+(?=X)/g;
var bad89 = /(x*)+(?=$)/
var bad90 = /(x*)+(?=$|y)/
-var bad91 = /([\s\S]*)+(?=$)/
-var bad92 = /([\s\S]*)+(?=$|y)/
\ No newline at end of file
+
+// GOOD - but we spuriously conclude that a rejecting suffix exists.
+var good44 = /([\s\S]*)+(?=$)/;
+var good45 = /([\s\S]*)+(?=$|y)/;
\ No newline at end of file
From 218731ca0aca5c3810bcfd42c9df6655104bc0e3 Mon Sep 17 00:00:00 2001
From: Artem Smotrakov
Date: Sun, 11 Jul 2021 17:35:26 +0200
Subject: [PATCH 121/429] Added a query for static initialization vectors in
encryption
- Added StaticInitializationVector.ql
- Added StaticInitializationVector.qhelp
- Added tests
---
.../BadStaticInitializationVector.java | 4 +
.../GoodRandomInitializationVector.java | 6 +
.../CWE-1204/StaticInitializationVector.qhelp | 46 +++++
.../CWE-1204/StaticInitializationVector.ql | 190 ++++++++++++++++++
.../StaticInitializationVector.expected | 15 ++
.../CWE-1204/StaticInitializationVector.java | 118 +++++++++++
.../CWE-1204/StaticInitializationVector.qlref | 1 +
7 files changed, 380 insertions(+)
create mode 100644 java/ql/src/experimental/Security/CWE/CWE-1204/BadStaticInitializationVector.java
create mode 100644 java/ql/src/experimental/Security/CWE/CWE-1204/GoodRandomInitializationVector.java
create mode 100644 java/ql/src/experimental/Security/CWE/CWE-1204/StaticInitializationVector.qhelp
create mode 100644 java/ql/src/experimental/Security/CWE/CWE-1204/StaticInitializationVector.ql
create mode 100644 java/ql/test/experimental/query-tests/security/CWE-1204/StaticInitializationVector.expected
create mode 100644 java/ql/test/experimental/query-tests/security/CWE-1204/StaticInitializationVector.java
create mode 100644 java/ql/test/experimental/query-tests/security/CWE-1204/StaticInitializationVector.qlref
diff --git a/java/ql/src/experimental/Security/CWE/CWE-1204/BadStaticInitializationVector.java b/java/ql/src/experimental/Security/CWE/CWE-1204/BadStaticInitializationVector.java
new file mode 100644
index 00000000000..85e8be6d8ce
--- /dev/null
+++ b/java/ql/src/experimental/Security/CWE/CWE-1204/BadStaticInitializationVector.java
@@ -0,0 +1,4 @@
+byte[] iv = new byte[16]; // all zeroes
+GCMParameterSpec params = new GCMParameterSpec(128, iv);
+Cipher cipher = Cipher.getInstance("AES/GCM/PKCS5PADDING");
+cipher.init(Cipher.ENCRYPT_MODE, key, params);
\ No newline at end of file
diff --git a/java/ql/src/experimental/Security/CWE/CWE-1204/GoodRandomInitializationVector.java b/java/ql/src/experimental/Security/CWE/CWE-1204/GoodRandomInitializationVector.java
new file mode 100644
index 00000000000..faceb119d64
--- /dev/null
+++ b/java/ql/src/experimental/Security/CWE/CWE-1204/GoodRandomInitializationVector.java
@@ -0,0 +1,6 @@
+byte[] iv = new byte[16];
+SecureRandom random = SecureRandom.getInstanceStrong();
+random.nextBytes(iv);
+GCMParameterSpec params = new GCMParameterSpec(128, iv);
+Cipher cipher = Cipher.getInstance("AES/GCM/PKCS5PADDING");
+cipher.init(Cipher.ENCRYPT_MODE, key, params);
\ No newline at end of file
diff --git a/java/ql/src/experimental/Security/CWE/CWE-1204/StaticInitializationVector.qhelp b/java/ql/src/experimental/Security/CWE/CWE-1204/StaticInitializationVector.qhelp
new file mode 100644
index 00000000000..49f5862f3de
--- /dev/null
+++ b/java/ql/src/experimental/Security/CWE/CWE-1204/StaticInitializationVector.qhelp
@@ -0,0 +1,46 @@
+
+
+
+
+
+A cipher needs an initialization vector (IV) when it is used in certain modes
+such as CBC or GCM. Under the same secret key, IVs should be unique and ideally unpredictable.
+Given a secret key, if the same IV is used for encryption, the same plaintexts result in the same ciphertexts.
+This lets an attacker learn if the same data pieces are transfered or stored,
+or this can help the attacker run a dictionary attack.
+
+
+
+
+
+Use a random IV generated by SecureRandom.
+
+
+
+
+
+The following example initializes a cipher with a static IV which is unsafe:
+
+
+
+
+The next example initializes a cipher with a random IV:
+
+
+
+
+
+
+ Wikipedia:
+ Initialization vector.
+
+
+ National Institute of Standards and Technology:
+ Recommendation for Block Cipher Modes of Operation.
+
+
+ National Institute of Standards and Technology:
+ FIPS 140-2: Security Requirements for Cryptographic Modules.
+
+
+
\ No newline at end of file
diff --git a/java/ql/src/experimental/Security/CWE/CWE-1204/StaticInitializationVector.ql b/java/ql/src/experimental/Security/CWE/CWE-1204/StaticInitializationVector.ql
new file mode 100644
index 00000000000..0d5dcf4ff4d
--- /dev/null
+++ b/java/ql/src/experimental/Security/CWE/CWE-1204/StaticInitializationVector.ql
@@ -0,0 +1,190 @@
+/**
+ * @name Using a static initialization vector for encryption
+ * @description A cipher needs an initialization vector (IV) in some cases,
+ * for example, when CBC or GCM modes are used. IVs are used to randomize the encryption,
+ * therefore they should be unique and ideally unpredictable.
+ * Otherwise, the same plaintexts result in same ciphertexts under a given secret key.
+ * If a static IV is used for encryption, this lets an attacker learn
+ * if the same data pieces are transfered or stored,
+ * or this can help the attacker run a dictionary attack.
+ * @kind path-problem
+ * @problem.severity warning
+ * @precision high
+ * @id java/static-initialization-vector
+ * @tags security
+ * external/cwe/cwe-329
+ * external/cwe/cwe-1204
+ */
+
+import java
+import semmle.code.java.dataflow.TaintTracking
+import semmle.code.java.dataflow.TaintTracking2
+import DataFlow::PathGraph
+
+/**
+ * Holds if `array` is initialized only with constants, for example,
+ * `new byte[8]` or `new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 }`.
+ */
+private predicate initializedWithConstants(ArrayCreationExpr array) {
+ not exists(array.getInit())
+ or
+ forex(Expr element | element = array.getInit().getAChildExpr() |
+ element instanceof CompileTimeConstantExpr
+ )
+}
+
+/**
+ * An expression that creates a byte array that is initialized with constants.
+ */
+private class StaticByteArrayCreation extends ArrayCreationExpr {
+ StaticByteArrayCreation() {
+ this.getType().(Array).getElementType().(PrimitiveType).getName() = "byte" and
+ initializedWithConstants(this)
+ }
+}
+
+/** Defines a sub-set of expressions that update an array. */
+private class ArrayUpdate extends Expr {
+ Expr array;
+
+ ArrayUpdate() {
+ exists(Assignment assign, ArrayAccess arrayAccess | arrayAccess = assign.getDest() |
+ assign = this and
+ arrayAccess.getArray() = array and
+ not assign.getSource() instanceof CompileTimeConstantExpr
+ )
+ or
+ exists(StaticMethodAccess ma |
+ ma.getMethod().hasQualifiedName("java.lang", "System", "arraycopy") and
+ ma = this and
+ ma.getArgument(2) = array
+ )
+ or
+ exists(StaticMethodAccess ma |
+ ma.getMethod().hasQualifiedName("java.util", "Arrays", "copyOf") and
+ ma = this and
+ ma = array
+ )
+ or
+ exists(MethodAccess ma, Method m |
+ m = ma.getMethod() and
+ ma = this and
+ ma.getArgument(0) = array
+ |
+ m.hasQualifiedName("java.io", "InputStream", "read") or
+ m.hasQualifiedName("java.nio", "ByteBuffer", "get") or
+ m.hasQualifiedName("java.security", "SecureRandom", "nextBytes") or
+ m.hasQualifiedName("java.util", "Random", "nextBytes")
+ )
+ }
+
+ /** Returns the updated array. */
+ Expr getArray() { result = array }
+}
+
+/**
+ * A config that tracks dataflow from creating an array to an operation that updates it.
+ */
+private class ArrayUpdateConfig extends TaintTracking2::Configuration {
+ ArrayUpdateConfig() { this = "ArrayUpdateConfig" }
+
+ override predicate isSource(DataFlow::Node source) {
+ source.asExpr() instanceof StaticByteArrayCreation
+ }
+
+ override predicate isSink(DataFlow::Node sink) {
+ exists(ArrayUpdate update | update.getArray() = sink.asExpr())
+ }
+}
+
+/**
+ * A source that defines an array that doesn't get updated.
+ */
+private class StaticInitializationVectorSource extends DataFlow::Node {
+ StaticInitializationVectorSource() {
+ exists(StaticByteArrayCreation array | array = this.asExpr() |
+ not exists(ArrayUpdate update, ArrayUpdateConfig config |
+ config.hasFlow(DataFlow2::exprNode(array), DataFlow2::exprNode(update.getArray()))
+ )
+ )
+ }
+}
+
+/**
+ * A config that tracks initialization of a cipher for encryption.
+ */
+private class EncryptionModeConfig extends TaintTracking2::Configuration {
+ EncryptionModeConfig() { this = "EncryptionModeConfig" }
+
+ override predicate isSource(DataFlow::Node source) {
+ source.asExpr().(VarAccess).getVariable().hasName("ENCRYPT_MODE")
+ }
+
+ override predicate isSink(DataFlow::Node sink) {
+ exists(MethodAccess ma, Method m | m = ma.getMethod() |
+ m.hasQualifiedName("javax.crypto", "Cipher", "init") and
+ ma.getArgument(0) = sink.asExpr()
+ )
+ }
+}
+
+/**
+ * A sink that initializes a cipher for encryption with unsafe parameters.
+ */
+private class EncryptionInitializationSink extends DataFlow::Node {
+ EncryptionInitializationSink() {
+ exists(MethodAccess ma, Method m, EncryptionModeConfig config | m = ma.getMethod() |
+ m.hasQualifiedName("javax.crypto", "Cipher", "init") and
+ m.getParameterType(2)
+ .(RefType)
+ .hasQualifiedName("java.security.spec", "AlgorithmParameterSpec") and
+ ma.getArgument(2) = this.asExpr() and
+ config.hasFlowToExpr(ma.getArgument(0))
+ )
+ }
+}
+
+/**
+ * Holds if `fromNode` to `toNode` is a dataflow step
+ * that creates cipher's parameters with initialization vector.
+ */
+private predicate createInitializationVectorSpecStep(DataFlow::Node fromNode, DataFlow::Node toNode) {
+ exists(ConstructorCall cc, RefType type |
+ cc = toNode.asExpr() and type = cc.getConstructedType()
+ |
+ type.hasQualifiedName("javax.crypto.spec", "IvParameterSpec") and
+ cc.getArgument(0) = fromNode.asExpr()
+ or
+ type.hasQualifiedName("javax.crypto.spec", ["GCMParameterSpec", "RC2ParameterSpec"]) and
+ cc.getArgument(1) = fromNode.asExpr()
+ or
+ type.hasQualifiedName("javax.crypto.spec", "RC5ParameterSpec") and
+ cc.getArgument(3) = fromNode.asExpr()
+ )
+}
+
+/**
+ * A config that tracks dataflow to initializing a cipher with a static initialization vector.
+ */
+private class StaticInitializationVectorConfig extends TaintTracking::Configuration {
+ StaticInitializationVectorConfig() { this = "StaticInitializationVectorConfig" }
+
+ override predicate isSource(DataFlow::Node source) {
+ source instanceof StaticInitializationVectorSource
+ }
+
+ override predicate isSink(DataFlow::Node sink) { sink instanceof EncryptionInitializationSink }
+
+ override predicate isAdditionalTaintStep(DataFlow::Node fromNode, DataFlow::Node toNode) {
+ createInitializationVectorSpecStep(fromNode, toNode)
+ }
+
+ override predicate isSanitizer(DataFlow::Node node) {
+ exists(ArrayUpdate update | update.getArray() = node.asExpr())
+ }
+}
+
+from DataFlow::PathNode source, DataFlow::PathNode sink, StaticInitializationVectorConfig conf
+where conf.hasFlowPath(source, sink)
+select sink.getNode(), source, sink, "A $@ should not be used for encryption.", source.getNode(),
+ "static initialization vector"
diff --git a/java/ql/test/experimental/query-tests/security/CWE-1204/StaticInitializationVector.expected b/java/ql/test/experimental/query-tests/security/CWE-1204/StaticInitializationVector.expected
new file mode 100644
index 00000000000..a26dc0b26ae
--- /dev/null
+++ b/java/ql/test/experimental/query-tests/security/CWE-1204/StaticInitializationVector.expected
@@ -0,0 +1,15 @@
+edges
+| StaticInitializationVector.java:13:21:13:81 | new byte[] : byte[] | StaticInitializationVector.java:19:51:19:56 | ivSpec |
+| StaticInitializationVector.java:26:21:26:32 | new byte[] : byte[] | StaticInitializationVector.java:32:51:32:56 | ivSpec |
+| StaticInitializationVector.java:39:21:39:32 | new byte[] : byte[] | StaticInitializationVector.java:48:51:48:56 | ivSpec |
+nodes
+| StaticInitializationVector.java:13:21:13:81 | new byte[] : byte[] | semmle.label | new byte[] : byte[] |
+| StaticInitializationVector.java:19:51:19:56 | ivSpec | semmle.label | ivSpec |
+| StaticInitializationVector.java:26:21:26:32 | new byte[] : byte[] | semmle.label | new byte[] : byte[] |
+| StaticInitializationVector.java:32:51:32:56 | ivSpec | semmle.label | ivSpec |
+| StaticInitializationVector.java:39:21:39:32 | new byte[] : byte[] | semmle.label | new byte[] : byte[] |
+| StaticInitializationVector.java:48:51:48:56 | ivSpec | semmle.label | ivSpec |
+#select
+| StaticInitializationVector.java:19:51:19:56 | ivSpec | StaticInitializationVector.java:13:21:13:81 | new byte[] : byte[] | StaticInitializationVector.java:19:51:19:56 | ivSpec | A $@ should not be used for encryption. | StaticInitializationVector.java:13:21:13:81 | new byte[] | static initialization vector |
+| StaticInitializationVector.java:32:51:32:56 | ivSpec | StaticInitializationVector.java:26:21:26:32 | new byte[] : byte[] | StaticInitializationVector.java:32:51:32:56 | ivSpec | A $@ should not be used for encryption. | StaticInitializationVector.java:26:21:26:32 | new byte[] | static initialization vector |
+| StaticInitializationVector.java:48:51:48:56 | ivSpec | StaticInitializationVector.java:39:21:39:32 | new byte[] : byte[] | StaticInitializationVector.java:48:51:48:56 | ivSpec | A $@ should not be used for encryption. | StaticInitializationVector.java:39:21:39:32 | new byte[] | static initialization vector |
diff --git a/java/ql/test/experimental/query-tests/security/CWE-1204/StaticInitializationVector.java b/java/ql/test/experimental/query-tests/security/CWE-1204/StaticInitializationVector.java
new file mode 100644
index 00000000000..fe02f276bac
--- /dev/null
+++ b/java/ql/test/experimental/query-tests/security/CWE-1204/StaticInitializationVector.java
@@ -0,0 +1,118 @@
+import javax.crypto.Cipher;
+import javax.crypto.spec.GCMParameterSpec;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+
+import java.security.SecureRandom;
+import java.util.Arrays;
+
+public class StaticInitializationVector {
+
+ // BAD: AES-GCM with static IV from a byte array
+ public byte[] encryptWithStaticIvByteArrayWithInitializer(byte[] key, byte[] plaintext) throws Exception {
+ byte[] iv = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5 };
+
+ GCMParameterSpec ivSpec = new GCMParameterSpec(128, iv);
+ SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
+
+ Cipher cipher = Cipher.getInstance("AES/GCM/PKCS5PADDING");
+ cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);
+ cipher.update(plaintext);
+ return cipher.doFinal();
+ }
+
+ // BAD: AES-GCM with static IV from zero-initialized byte array
+ public byte[] encryptWithZeroStaticIvByteArray(byte[] key, byte[] plaintext) throws Exception {
+ byte[] iv = new byte[16];
+
+ GCMParameterSpec ivSpec = new GCMParameterSpec(128, iv);
+ SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
+
+ Cipher cipher = Cipher.getInstance("AES/GCM/PKCS5PADDING");
+ cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);
+ cipher.update(plaintext);
+ return cipher.doFinal();
+ }
+
+ // BAD: AES-CBC with static IV from zero-initialized byte array
+ public byte[] encryptWithStaticIvByteArray(byte[] key, byte[] plaintext) throws Exception {
+ byte[] iv = new byte[16];
+ for (byte i = 0; i < iv.length; i++) {
+ iv[i] = 1;
+ }
+
+ IvParameterSpec ivSpec = new IvParameterSpec(iv);
+ SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
+
+ Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
+ cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);
+ cipher.update(plaintext);
+ return cipher.doFinal();
+ }
+
+ // GOOD: AES-GCM with a random IV
+ public byte[] encryptWithRandomIv(byte[] key, byte[] plaintext) throws Exception {
+ byte[] iv = new byte[16];
+
+ SecureRandom random = SecureRandom.getInstanceStrong();
+ random.nextBytes(iv);
+
+ GCMParameterSpec ivSpec = new GCMParameterSpec(128, iv);
+ SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
+
+ Cipher cipher = Cipher.getInstance("AES/GCM/PKCS5PADDING");
+ cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);
+ cipher.update(plaintext);
+ return cipher.doFinal();
+ }
+
+ // GOOD: AES-GCM with a random IV
+ public byte[] encryptWithRandomIvByteByByte(byte[] key, byte[] plaintext) throws Exception {
+ SecureRandom random = SecureRandom.getInstanceStrong();
+ byte[] iv = new byte[16];
+ for (int i = 0; i < iv.length; i++) {
+ iv[i] = (byte) random.nextInt();
+ }
+
+ GCMParameterSpec ivSpec = new GCMParameterSpec(128, iv);
+ SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
+
+ Cipher cipher = Cipher.getInstance("AES/GCM/PKCS5PADDING");
+ cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);
+ cipher.update(plaintext);
+ return cipher.doFinal();
+ }
+
+ // GOOD: AES-GCM with a random IV
+ public byte[] encryptWithRandomIvWithSystemArrayCopy(byte[] key, byte[] plaintext) throws Exception {
+ byte[] randomBytes = new byte[16];
+ SecureRandom.getInstanceStrong().nextBytes(randomBytes);
+
+ byte[] iv = new byte[16];
+ System.arraycopy(randomBytes, 0, iv, 0, 16);
+
+ GCMParameterSpec ivSpec = new GCMParameterSpec(128, iv);
+ SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
+
+ Cipher cipher = Cipher.getInstance("AES/GCM/PKCS5PADDING");
+ cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);
+ cipher.update(plaintext);
+ return cipher.doFinal();
+ }
+
+ // GOOD: AES-GCM with a random IV
+ public byte[] encryptWithRandomIvWithArraysCopy(byte[] key, byte[] plaintext) throws Exception {
+ byte[] randomBytes = new byte[16];
+ SecureRandom.getInstanceStrong().nextBytes(randomBytes);
+
+ byte[] iv = Arrays.copyOf(randomBytes, 16);
+
+ GCMParameterSpec ivSpec = new GCMParameterSpec(128, iv);
+ SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
+
+ Cipher cipher = Cipher.getInstance("AES/GCM/PKCS5PADDING");
+ cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);
+ cipher.update(plaintext);
+ return cipher.doFinal();
+ }
+}
diff --git a/java/ql/test/experimental/query-tests/security/CWE-1204/StaticInitializationVector.qlref b/java/ql/test/experimental/query-tests/security/CWE-1204/StaticInitializationVector.qlref
new file mode 100644
index 00000000000..18df4ffb8d3
--- /dev/null
+++ b/java/ql/test/experimental/query-tests/security/CWE-1204/StaticInitializationVector.qlref
@@ -0,0 +1 @@
+experimental/Security/CWE/CWE-1204/StaticInitializationVector.ql
\ No newline at end of file
From cfe74b527a9bdbaf9c79e461fe62f3a7b9a5b115 Mon Sep 17 00:00:00 2001
From: Artem Smotrakov
Date: Sat, 17 Jul 2021 01:04:52 +0200
Subject: [PATCH 122/429] Use inline-expectation tests for
StaticInitializationVector.ql
---
.../CWE-1204/StaticInitializationVector.ql | 166 +-----------------
.../StaticInitializationVectorQuery.qll | 166 ++++++++++++++++++
.../StaticInitializationVector.expected | 15 --
.../CWE-1204/StaticInitializationVector.java | 6 +-
.../CWE-1204/StaticInitializationVector.qlref | 1 -
.../StaticInitializationVectorTest.expected | 0
.../StaticInitializationVectorTest.ql | 20 +++
7 files changed, 190 insertions(+), 184 deletions(-)
create mode 100644 java/ql/src/experimental/semmle/code/java/security/StaticInitializationVectorQuery.qll
delete mode 100644 java/ql/test/experimental/query-tests/security/CWE-1204/StaticInitializationVector.expected
delete mode 100644 java/ql/test/experimental/query-tests/security/CWE-1204/StaticInitializationVector.qlref
create mode 100644 java/ql/test/experimental/query-tests/security/CWE-1204/StaticInitializationVectorTest.expected
create mode 100644 java/ql/test/experimental/query-tests/security/CWE-1204/StaticInitializationVectorTest.ql
diff --git a/java/ql/src/experimental/Security/CWE/CWE-1204/StaticInitializationVector.ql b/java/ql/src/experimental/Security/CWE/CWE-1204/StaticInitializationVector.ql
index 0d5dcf4ff4d..f041919ed93 100644
--- a/java/ql/src/experimental/Security/CWE/CWE-1204/StaticInitializationVector.ql
+++ b/java/ql/src/experimental/Security/CWE/CWE-1204/StaticInitializationVector.ql
@@ -17,173 +17,9 @@
*/
import java
-import semmle.code.java.dataflow.TaintTracking
-import semmle.code.java.dataflow.TaintTracking2
+import experimental.semmle.code.java.security.StaticInitializationVectorQuery
import DataFlow::PathGraph
-/**
- * Holds if `array` is initialized only with constants, for example,
- * `new byte[8]` or `new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 }`.
- */
-private predicate initializedWithConstants(ArrayCreationExpr array) {
- not exists(array.getInit())
- or
- forex(Expr element | element = array.getInit().getAChildExpr() |
- element instanceof CompileTimeConstantExpr
- )
-}
-
-/**
- * An expression that creates a byte array that is initialized with constants.
- */
-private class StaticByteArrayCreation extends ArrayCreationExpr {
- StaticByteArrayCreation() {
- this.getType().(Array).getElementType().(PrimitiveType).getName() = "byte" and
- initializedWithConstants(this)
- }
-}
-
-/** Defines a sub-set of expressions that update an array. */
-private class ArrayUpdate extends Expr {
- Expr array;
-
- ArrayUpdate() {
- exists(Assignment assign, ArrayAccess arrayAccess | arrayAccess = assign.getDest() |
- assign = this and
- arrayAccess.getArray() = array and
- not assign.getSource() instanceof CompileTimeConstantExpr
- )
- or
- exists(StaticMethodAccess ma |
- ma.getMethod().hasQualifiedName("java.lang", "System", "arraycopy") and
- ma = this and
- ma.getArgument(2) = array
- )
- or
- exists(StaticMethodAccess ma |
- ma.getMethod().hasQualifiedName("java.util", "Arrays", "copyOf") and
- ma = this and
- ma = array
- )
- or
- exists(MethodAccess ma, Method m |
- m = ma.getMethod() and
- ma = this and
- ma.getArgument(0) = array
- |
- m.hasQualifiedName("java.io", "InputStream", "read") or
- m.hasQualifiedName("java.nio", "ByteBuffer", "get") or
- m.hasQualifiedName("java.security", "SecureRandom", "nextBytes") or
- m.hasQualifiedName("java.util", "Random", "nextBytes")
- )
- }
-
- /** Returns the updated array. */
- Expr getArray() { result = array }
-}
-
-/**
- * A config that tracks dataflow from creating an array to an operation that updates it.
- */
-private class ArrayUpdateConfig extends TaintTracking2::Configuration {
- ArrayUpdateConfig() { this = "ArrayUpdateConfig" }
-
- override predicate isSource(DataFlow::Node source) {
- source.asExpr() instanceof StaticByteArrayCreation
- }
-
- override predicate isSink(DataFlow::Node sink) {
- exists(ArrayUpdate update | update.getArray() = sink.asExpr())
- }
-}
-
-/**
- * A source that defines an array that doesn't get updated.
- */
-private class StaticInitializationVectorSource extends DataFlow::Node {
- StaticInitializationVectorSource() {
- exists(StaticByteArrayCreation array | array = this.asExpr() |
- not exists(ArrayUpdate update, ArrayUpdateConfig config |
- config.hasFlow(DataFlow2::exprNode(array), DataFlow2::exprNode(update.getArray()))
- )
- )
- }
-}
-
-/**
- * A config that tracks initialization of a cipher for encryption.
- */
-private class EncryptionModeConfig extends TaintTracking2::Configuration {
- EncryptionModeConfig() { this = "EncryptionModeConfig" }
-
- override predicate isSource(DataFlow::Node source) {
- source.asExpr().(VarAccess).getVariable().hasName("ENCRYPT_MODE")
- }
-
- override predicate isSink(DataFlow::Node sink) {
- exists(MethodAccess ma, Method m | m = ma.getMethod() |
- m.hasQualifiedName("javax.crypto", "Cipher", "init") and
- ma.getArgument(0) = sink.asExpr()
- )
- }
-}
-
-/**
- * A sink that initializes a cipher for encryption with unsafe parameters.
- */
-private class EncryptionInitializationSink extends DataFlow::Node {
- EncryptionInitializationSink() {
- exists(MethodAccess ma, Method m, EncryptionModeConfig config | m = ma.getMethod() |
- m.hasQualifiedName("javax.crypto", "Cipher", "init") and
- m.getParameterType(2)
- .(RefType)
- .hasQualifiedName("java.security.spec", "AlgorithmParameterSpec") and
- ma.getArgument(2) = this.asExpr() and
- config.hasFlowToExpr(ma.getArgument(0))
- )
- }
-}
-
-/**
- * Holds if `fromNode` to `toNode` is a dataflow step
- * that creates cipher's parameters with initialization vector.
- */
-private predicate createInitializationVectorSpecStep(DataFlow::Node fromNode, DataFlow::Node toNode) {
- exists(ConstructorCall cc, RefType type |
- cc = toNode.asExpr() and type = cc.getConstructedType()
- |
- type.hasQualifiedName("javax.crypto.spec", "IvParameterSpec") and
- cc.getArgument(0) = fromNode.asExpr()
- or
- type.hasQualifiedName("javax.crypto.spec", ["GCMParameterSpec", "RC2ParameterSpec"]) and
- cc.getArgument(1) = fromNode.asExpr()
- or
- type.hasQualifiedName("javax.crypto.spec", "RC5ParameterSpec") and
- cc.getArgument(3) = fromNode.asExpr()
- )
-}
-
-/**
- * A config that tracks dataflow to initializing a cipher with a static initialization vector.
- */
-private class StaticInitializationVectorConfig extends TaintTracking::Configuration {
- StaticInitializationVectorConfig() { this = "StaticInitializationVectorConfig" }
-
- override predicate isSource(DataFlow::Node source) {
- source instanceof StaticInitializationVectorSource
- }
-
- override predicate isSink(DataFlow::Node sink) { sink instanceof EncryptionInitializationSink }
-
- override predicate isAdditionalTaintStep(DataFlow::Node fromNode, DataFlow::Node toNode) {
- createInitializationVectorSpecStep(fromNode, toNode)
- }
-
- override predicate isSanitizer(DataFlow::Node node) {
- exists(ArrayUpdate update | update.getArray() = node.asExpr())
- }
-}
-
from DataFlow::PathNode source, DataFlow::PathNode sink, StaticInitializationVectorConfig conf
where conf.hasFlowPath(source, sink)
select sink.getNode(), source, sink, "A $@ should not be used for encryption.", source.getNode(),
diff --git a/java/ql/src/experimental/semmle/code/java/security/StaticInitializationVectorQuery.qll b/java/ql/src/experimental/semmle/code/java/security/StaticInitializationVectorQuery.qll
new file mode 100644
index 00000000000..f190153385e
--- /dev/null
+++ b/java/ql/src/experimental/semmle/code/java/security/StaticInitializationVectorQuery.qll
@@ -0,0 +1,166 @@
+import java
+import semmle.code.java.dataflow.TaintTracking
+import semmle.code.java.dataflow.TaintTracking2
+
+/**
+ * Holds if `array` is initialized only with constants, for example,
+ * `new byte[8]` or `new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 }`.
+ */
+private predicate initializedWithConstants(ArrayCreationExpr array) {
+ not exists(array.getInit())
+ or
+ forex(Expr element | element = array.getInit().getAChildExpr() |
+ element instanceof CompileTimeConstantExpr
+ )
+}
+
+/**
+ * An expression that creates a byte array that is initialized with constants.
+ */
+private class StaticByteArrayCreation extends ArrayCreationExpr {
+ StaticByteArrayCreation() {
+ this.getType().(Array).getElementType().(PrimitiveType).getName() = "byte" and
+ initializedWithConstants(this)
+ }
+}
+
+/** Defines a sub-set of expressions that update an array. */
+private class ArrayUpdate extends Expr {
+ Expr array;
+
+ ArrayUpdate() {
+ exists(Assignment assign, ArrayAccess arrayAccess | arrayAccess = assign.getDest() |
+ assign = this and
+ arrayAccess.getArray() = array and
+ not assign.getSource() instanceof CompileTimeConstantExpr
+ )
+ or
+ exists(StaticMethodAccess ma |
+ ma.getMethod().hasQualifiedName("java.lang", "System", "arraycopy") and
+ ma = this and
+ ma.getArgument(2) = array
+ )
+ or
+ exists(StaticMethodAccess ma |
+ ma.getMethod().hasQualifiedName("java.util", "Arrays", "copyOf") and
+ ma = this and
+ ma = array
+ )
+ or
+ exists(MethodAccess ma, Method m |
+ m = ma.getMethod() and
+ ma = this and
+ ma.getArgument(0) = array
+ |
+ m.hasQualifiedName("java.io", "InputStream", "read") or
+ m.hasQualifiedName("java.nio", "ByteBuffer", "get") or
+ m.hasQualifiedName("java.security", "SecureRandom", "nextBytes") or
+ m.hasQualifiedName("java.util", "Random", "nextBytes")
+ )
+ }
+
+ /** Returns the updated array. */
+ Expr getArray() { result = array }
+}
+
+/**
+ * A config that tracks dataflow from creating an array to an operation that updates it.
+ */
+private class ArrayUpdateConfig extends TaintTracking2::Configuration {
+ ArrayUpdateConfig() { this = "ArrayUpdateConfig" }
+
+ override predicate isSource(DataFlow::Node source) {
+ source.asExpr() instanceof StaticByteArrayCreation
+ }
+
+ override predicate isSink(DataFlow::Node sink) {
+ exists(ArrayUpdate update | update.getArray() = sink.asExpr())
+ }
+}
+
+/**
+ * A source that defines an array that doesn't get updated.
+ */
+private class StaticInitializationVectorSource extends DataFlow::Node {
+ StaticInitializationVectorSource() {
+ exists(StaticByteArrayCreation array | array = this.asExpr() |
+ not exists(ArrayUpdate update, ArrayUpdateConfig config |
+ config.hasFlow(DataFlow2::exprNode(array), DataFlow2::exprNode(update.getArray()))
+ )
+ )
+ }
+}
+
+/**
+ * A config that tracks initialization of a cipher for encryption.
+ */
+private class EncryptionModeConfig extends TaintTracking2::Configuration {
+ EncryptionModeConfig() { this = "EncryptionModeConfig" }
+
+ override predicate isSource(DataFlow::Node source) {
+ source.asExpr().(VarAccess).getVariable().hasName("ENCRYPT_MODE")
+ }
+
+ override predicate isSink(DataFlow::Node sink) {
+ exists(MethodAccess ma, Method m | m = ma.getMethod() |
+ m.hasQualifiedName("javax.crypto", "Cipher", "init") and
+ ma.getArgument(0) = sink.asExpr()
+ )
+ }
+}
+
+/**
+ * A sink that initializes a cipher for encryption with unsafe parameters.
+ */
+private class EncryptionInitializationSink extends DataFlow::Node {
+ EncryptionInitializationSink() {
+ exists(MethodAccess ma, Method m, EncryptionModeConfig config | m = ma.getMethod() |
+ m.hasQualifiedName("javax.crypto", "Cipher", "init") and
+ m.getParameterType(2)
+ .(RefType)
+ .hasQualifiedName("java.security.spec", "AlgorithmParameterSpec") and
+ ma.getArgument(2) = this.asExpr() and
+ config.hasFlowToExpr(ma.getArgument(0))
+ )
+ }
+}
+
+/**
+ * Holds if `fromNode` to `toNode` is a dataflow step
+ * that creates cipher's parameters with initialization vector.
+ */
+private predicate createInitializationVectorSpecStep(DataFlow::Node fromNode, DataFlow::Node toNode) {
+ exists(ConstructorCall cc, RefType type |
+ cc = toNode.asExpr() and type = cc.getConstructedType()
+ |
+ type.hasQualifiedName("javax.crypto.spec", "IvParameterSpec") and
+ cc.getArgument(0) = fromNode.asExpr()
+ or
+ type.hasQualifiedName("javax.crypto.spec", ["GCMParameterSpec", "RC2ParameterSpec"]) and
+ cc.getArgument(1) = fromNode.asExpr()
+ or
+ type.hasQualifiedName("javax.crypto.spec", "RC5ParameterSpec") and
+ cc.getArgument(3) = fromNode.asExpr()
+ )
+}
+
+/**
+ * A config that tracks dataflow to initializing a cipher with a static initialization vector.
+ */
+class StaticInitializationVectorConfig extends TaintTracking::Configuration {
+ StaticInitializationVectorConfig() { this = "StaticInitializationVectorConfig" }
+
+ override predicate isSource(DataFlow::Node source) {
+ source instanceof StaticInitializationVectorSource
+ }
+
+ override predicate isSink(DataFlow::Node sink) { sink instanceof EncryptionInitializationSink }
+
+ override predicate isAdditionalTaintStep(DataFlow::Node fromNode, DataFlow::Node toNode) {
+ createInitializationVectorSpecStep(fromNode, toNode)
+ }
+
+ override predicate isSanitizer(DataFlow::Node node) {
+ exists(ArrayUpdate update | update.getArray() = node.asExpr())
+ }
+}
diff --git a/java/ql/test/experimental/query-tests/security/CWE-1204/StaticInitializationVector.expected b/java/ql/test/experimental/query-tests/security/CWE-1204/StaticInitializationVector.expected
deleted file mode 100644
index a26dc0b26ae..00000000000
--- a/java/ql/test/experimental/query-tests/security/CWE-1204/StaticInitializationVector.expected
+++ /dev/null
@@ -1,15 +0,0 @@
-edges
-| StaticInitializationVector.java:13:21:13:81 | new byte[] : byte[] | StaticInitializationVector.java:19:51:19:56 | ivSpec |
-| StaticInitializationVector.java:26:21:26:32 | new byte[] : byte[] | StaticInitializationVector.java:32:51:32:56 | ivSpec |
-| StaticInitializationVector.java:39:21:39:32 | new byte[] : byte[] | StaticInitializationVector.java:48:51:48:56 | ivSpec |
-nodes
-| StaticInitializationVector.java:13:21:13:81 | new byte[] : byte[] | semmle.label | new byte[] : byte[] |
-| StaticInitializationVector.java:19:51:19:56 | ivSpec | semmle.label | ivSpec |
-| StaticInitializationVector.java:26:21:26:32 | new byte[] : byte[] | semmle.label | new byte[] : byte[] |
-| StaticInitializationVector.java:32:51:32:56 | ivSpec | semmle.label | ivSpec |
-| StaticInitializationVector.java:39:21:39:32 | new byte[] : byte[] | semmle.label | new byte[] : byte[] |
-| StaticInitializationVector.java:48:51:48:56 | ivSpec | semmle.label | ivSpec |
-#select
-| StaticInitializationVector.java:19:51:19:56 | ivSpec | StaticInitializationVector.java:13:21:13:81 | new byte[] : byte[] | StaticInitializationVector.java:19:51:19:56 | ivSpec | A $@ should not be used for encryption. | StaticInitializationVector.java:13:21:13:81 | new byte[] | static initialization vector |
-| StaticInitializationVector.java:32:51:32:56 | ivSpec | StaticInitializationVector.java:26:21:26:32 | new byte[] : byte[] | StaticInitializationVector.java:32:51:32:56 | ivSpec | A $@ should not be used for encryption. | StaticInitializationVector.java:26:21:26:32 | new byte[] | static initialization vector |
-| StaticInitializationVector.java:48:51:48:56 | ivSpec | StaticInitializationVector.java:39:21:39:32 | new byte[] : byte[] | StaticInitializationVector.java:48:51:48:56 | ivSpec | A $@ should not be used for encryption. | StaticInitializationVector.java:39:21:39:32 | new byte[] | static initialization vector |
diff --git a/java/ql/test/experimental/query-tests/security/CWE-1204/StaticInitializationVector.java b/java/ql/test/experimental/query-tests/security/CWE-1204/StaticInitializationVector.java
index fe02f276bac..95a0d4b49f8 100644
--- a/java/ql/test/experimental/query-tests/security/CWE-1204/StaticInitializationVector.java
+++ b/java/ql/test/experimental/query-tests/security/CWE-1204/StaticInitializationVector.java
@@ -16,7 +16,7 @@ public class StaticInitializationVector {
SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
Cipher cipher = Cipher.getInstance("AES/GCM/PKCS5PADDING");
- cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);
+ cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec); // $staticInitializationVector
cipher.update(plaintext);
return cipher.doFinal();
}
@@ -29,7 +29,7 @@ public class StaticInitializationVector {
SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
Cipher cipher = Cipher.getInstance("AES/GCM/PKCS5PADDING");
- cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);
+ cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec); // $staticInitializationVector
cipher.update(plaintext);
return cipher.doFinal();
}
@@ -45,7 +45,7 @@ public class StaticInitializationVector {
SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
- cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);
+ cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec); // $staticInitializationVector
cipher.update(plaintext);
return cipher.doFinal();
}
diff --git a/java/ql/test/experimental/query-tests/security/CWE-1204/StaticInitializationVector.qlref b/java/ql/test/experimental/query-tests/security/CWE-1204/StaticInitializationVector.qlref
deleted file mode 100644
index 18df4ffb8d3..00000000000
--- a/java/ql/test/experimental/query-tests/security/CWE-1204/StaticInitializationVector.qlref
+++ /dev/null
@@ -1 +0,0 @@
-experimental/Security/CWE/CWE-1204/StaticInitializationVector.ql
\ No newline at end of file
diff --git a/java/ql/test/experimental/query-tests/security/CWE-1204/StaticInitializationVectorTest.expected b/java/ql/test/experimental/query-tests/security/CWE-1204/StaticInitializationVectorTest.expected
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/java/ql/test/experimental/query-tests/security/CWE-1204/StaticInitializationVectorTest.ql b/java/ql/test/experimental/query-tests/security/CWE-1204/StaticInitializationVectorTest.ql
new file mode 100644
index 00000000000..29afc31ab04
--- /dev/null
+++ b/java/ql/test/experimental/query-tests/security/CWE-1204/StaticInitializationVectorTest.ql
@@ -0,0 +1,20 @@
+import java
+import experimental.semmle.code.java.security.StaticInitializationVectorQuery
+import TestUtilities.InlineExpectationsTest
+
+class StaticInitializationVectorTest extends InlineExpectationsTest {
+ StaticInitializationVectorTest() { this = "StaticInitializationVectorTest" }
+
+ override string getARelevantTag() { result = "staticInitializationVector" }
+
+ override predicate hasActualResult(Location location, string element, string tag, string value) {
+ tag = "staticInitializationVector" and
+ exists(DataFlow::Node src, DataFlow::Node sink, StaticInitializationVectorConfig conf |
+ conf.hasFlow(src, sink)
+ |
+ sink.getLocation() = location and
+ element = sink.toString() and
+ value = ""
+ )
+ }
+}
From 69dab4907304743efe4e9208541a3da17318c117 Mon Sep 17 00:00:00 2001
From: shati-patel <42641846+shati-patel@users.noreply.github.com>
Date: Mon, 19 Jul 2021 12:24:05 +0100
Subject: [PATCH 123/429] Docs: Running query on multiple DBs in CodeQL for VS
Code
---
.../analyzing-your-projects.rst | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/docs/codeql/codeql-for-visual-studio-code/analyzing-your-projects.rst b/docs/codeql/codeql-for-visual-studio-code/analyzing-your-projects.rst
index b9a275cfb41..cfd1746499c 100644
--- a/docs/codeql/codeql-for-visual-studio-code/analyzing-your-projects.rst
+++ b/docs/codeql/codeql-for-visual-studio-code/analyzing-your-projects.rst
@@ -97,6 +97,15 @@ For example, in the following snippet, you could select the predicate name ``foo
predicate foo(string s) { s = "bar" }
+Running a query on multiple databases
+--------------------------------------
+
+This is helpful if you want to test your query on multiple codebases, or find a vulnerability in multiple projects.
+
+#. Open a query (``.ql``) file.
+#. Right-click and select **CodeQL: Run Query on Multiple Databases**.
+#. From the dropdown menu, select the databases that you want to run the query on.
+
Viewing previous queries
--------------------------
From 7939a1372e3068a19a5563f6f36400013806be5e Mon Sep 17 00:00:00 2001
From: Rasmus Wriedt Larsen
Date: Mon, 19 Jul 2021 16:44:41 +0200
Subject: [PATCH 124/429] Python: Move Jinja2WithoutEscaping tests to own
folder
---
.../Jinja2WithoutEscaping.expected | 0
.../Jinja2WithoutEscaping.qlref | 0
.../{CWE-079 => CWE-079-Jinja2WithoutEscaping}/jinja2_escaping.py | 0
.../Security/{CWE-079 => CWE-079-Jinja2WithoutEscaping}/options | 0
4 files changed, 0 insertions(+), 0 deletions(-)
rename python/ql/test/query-tests/Security/{CWE-079 => CWE-079-Jinja2WithoutEscaping}/Jinja2WithoutEscaping.expected (100%)
rename python/ql/test/query-tests/Security/{CWE-079 => CWE-079-Jinja2WithoutEscaping}/Jinja2WithoutEscaping.qlref (100%)
rename python/ql/test/query-tests/Security/{CWE-079 => CWE-079-Jinja2WithoutEscaping}/jinja2_escaping.py (100%)
rename python/ql/test/query-tests/Security/{CWE-079 => CWE-079-Jinja2WithoutEscaping}/options (100%)
diff --git a/python/ql/test/query-tests/Security/CWE-079/Jinja2WithoutEscaping.expected b/python/ql/test/query-tests/Security/CWE-079-Jinja2WithoutEscaping/Jinja2WithoutEscaping.expected
similarity index 100%
rename from python/ql/test/query-tests/Security/CWE-079/Jinja2WithoutEscaping.expected
rename to python/ql/test/query-tests/Security/CWE-079-Jinja2WithoutEscaping/Jinja2WithoutEscaping.expected
diff --git a/python/ql/test/query-tests/Security/CWE-079/Jinja2WithoutEscaping.qlref b/python/ql/test/query-tests/Security/CWE-079-Jinja2WithoutEscaping/Jinja2WithoutEscaping.qlref
similarity index 100%
rename from python/ql/test/query-tests/Security/CWE-079/Jinja2WithoutEscaping.qlref
rename to python/ql/test/query-tests/Security/CWE-079-Jinja2WithoutEscaping/Jinja2WithoutEscaping.qlref
diff --git a/python/ql/test/query-tests/Security/CWE-079/jinja2_escaping.py b/python/ql/test/query-tests/Security/CWE-079-Jinja2WithoutEscaping/jinja2_escaping.py
similarity index 100%
rename from python/ql/test/query-tests/Security/CWE-079/jinja2_escaping.py
rename to python/ql/test/query-tests/Security/CWE-079-Jinja2WithoutEscaping/jinja2_escaping.py
diff --git a/python/ql/test/query-tests/Security/CWE-079/options b/python/ql/test/query-tests/Security/CWE-079-Jinja2WithoutEscaping/options
similarity index 100%
rename from python/ql/test/query-tests/Security/CWE-079/options
rename to python/ql/test/query-tests/Security/CWE-079-Jinja2WithoutEscaping/options
From da021feb8b014574f8f7f4e6dcf9b651c82b8fda Mon Sep 17 00:00:00 2001
From: Rasmus Wriedt Larsen
Date: Mon, 19 Jul 2021 16:48:21 +0200
Subject: [PATCH 125/429] Python: Move `py/incomplete-hostname-regexp` tests to
own folder
---
.../IncompleteHostnameRegExp.expected | 0
.../IncompleteHostnameRegExp.qlref | 0
.../{CWE-020 => CWE-020-IncompleteHostnameRegExp}/hosttest.py | 0
3 files changed, 0 insertions(+), 0 deletions(-)
rename python/ql/test/query-tests/Security/{CWE-020 => CWE-020-IncompleteHostnameRegExp}/IncompleteHostnameRegExp.expected (100%)
rename python/ql/test/query-tests/Security/{CWE-020 => CWE-020-IncompleteHostnameRegExp}/IncompleteHostnameRegExp.qlref (100%)
rename python/ql/test/query-tests/Security/{CWE-020 => CWE-020-IncompleteHostnameRegExp}/hosttest.py (100%)
diff --git a/python/ql/test/query-tests/Security/CWE-020/IncompleteHostnameRegExp.expected b/python/ql/test/query-tests/Security/CWE-020-IncompleteHostnameRegExp/IncompleteHostnameRegExp.expected
similarity index 100%
rename from python/ql/test/query-tests/Security/CWE-020/IncompleteHostnameRegExp.expected
rename to python/ql/test/query-tests/Security/CWE-020-IncompleteHostnameRegExp/IncompleteHostnameRegExp.expected
diff --git a/python/ql/test/query-tests/Security/CWE-020/IncompleteHostnameRegExp.qlref b/python/ql/test/query-tests/Security/CWE-020-IncompleteHostnameRegExp/IncompleteHostnameRegExp.qlref
similarity index 100%
rename from python/ql/test/query-tests/Security/CWE-020/IncompleteHostnameRegExp.qlref
rename to python/ql/test/query-tests/Security/CWE-020-IncompleteHostnameRegExp/IncompleteHostnameRegExp.qlref
diff --git a/python/ql/test/query-tests/Security/CWE-020/hosttest.py b/python/ql/test/query-tests/Security/CWE-020-IncompleteHostnameRegExp/hosttest.py
similarity index 100%
rename from python/ql/test/query-tests/Security/CWE-020/hosttest.py
rename to python/ql/test/query-tests/Security/CWE-020-IncompleteHostnameRegExp/hosttest.py
From 77021ae1193be29d73667940c613234790cdd6f8 Mon Sep 17 00:00:00 2001
From: Rasmus Wriedt Larsen
Date: Mon, 19 Jul 2021 16:54:34 +0200
Subject: [PATCH 126/429] Python: Restructure security tests to contain query
name
We were mixing between things, so this is just to keep things
consistent. Even though it's not strictly needed for all queries,
it does look nice I think
---
.../IncompleteUrlSubstringSanitization.expected | 0
.../IncompleteUrlSubstringSanitization.qlref | 0
.../urltest.py | 0
.../CommandInjection.expected | 0
.../CommandInjection.qlref | 0
.../command_injection.py | 0
.../{CWE-078-py2 => CWE-078-CommandInjection-py2}/options | 0
.../CommandInjection.expected | 0
.../{CWE-078 => CWE-078-CommandInjection}/CommandInjection.qlref | 0
.../{CWE-078 => CWE-078-CommandInjection}/command_injection.py | 0
.../Security/{CWE-078 => CWE-078-CommandInjection}/options | 0
.../{CWE-079 => CWE-079-ReflectedXss}/ReflectedXss.expected | 0
.../Security/{CWE-079 => CWE-079-ReflectedXss}/ReflectedXss.qlref | 0
.../Security/{CWE-079 => CWE-079-ReflectedXss}/reflected_xss.py | 0
.../{CWE-089 => CWE-089-SqlInjection}/SqlInjection.expected | 0
.../Security/{CWE-089 => CWE-089-SqlInjection}/SqlInjection.qlref | 0
.../Security/{CWE-089 => CWE-089-SqlInjection}/sql_injection.py | 0
.../{CWE-094 => CWE-094-CodeInjection}/CodeInjection.expected | 0
.../{CWE-094 => CWE-094-CodeInjection}/CodeInjection.qlref | 0
.../Security/{CWE-094 => CWE-094-CodeInjection}/code_injection.py | 0
.../ExceptionInfo.expected | 0
.../{CWE-209 => CWE-209-StackTraceExposure}/ExceptionInfo.ql | 0
.../{CWE-209 => CWE-209-StackTraceExposure}/Exceptions.py | 0
.../StackTraceExposure.expected | 0
.../StackTraceExposure.qlref | 0
.../{CWE-209 => CWE-209-StackTraceExposure}/Stacktrace.py | 0
.../Security/{CWE-209 => CWE-209-StackTraceExposure}/options | 0
.../Security/{CWE-209 => CWE-209-StackTraceExposure}/test.py | 0
.../Security/{CWE-215 => CWE-215-FlaskDebug}/FlaskDebug.expected | 0
.../Security/{CWE-215 => CWE-215-FlaskDebug}/FlaskDebug.qlref | 0
.../query-tests/Security/{CWE-215 => CWE-215-FlaskDebug}/options | 0
.../Security/{CWE-215 => CWE-215-FlaskDebug}/settings.py | 0
.../query-tests/Security/{CWE-215 => CWE-215-FlaskDebug}/test.py | 0
.../{CWE-326 => CWE-326-WeakCryptoKey}/WeakCryptoKey.expected | 0
.../{CWE-326 => CWE-326-WeakCryptoKey}/WeakCryptoKey.qlref | 0
.../Security/{CWE-326 => CWE-326-WeakCryptoKey}/test_example.py | 0
.../Security/{CWE-326 => CWE-326-WeakCryptoKey}/weak_crypto.py | 0
.../InsecureTemporaryFile.expected | 0
.../InsecureTemporaryFile.py | 0
.../InsecureTemporaryFile.qlref | 0
.../SecureTemporaryFile.py | 0
.../UnsafeDeserialization.expected | 0
.../UnsafeDeserialization.qlref | 0
.../unsafe_deserialization.py | 0
.../{CWE-601 => CWE-601-UrlRedirect}/UrlRedirect.expected | 0
.../Security/{CWE-601 => CWE-601-UrlRedirect}/UrlRedirect.qlref | 0
.../query-tests/Security/{CWE-601 => CWE-601-UrlRedirect}/options | 0
.../query-tests/Security/{CWE-601 => CWE-601-UrlRedirect}/test.py | 0
.../WeakFilePermissions.expected | 0
.../WeakFilePermissions.qlref | 0
.../Security/{CWE-732 => CWE-732-WeakFilePermissions}/options | 0
.../Security/{CWE-732 => CWE-732-WeakFilePermissions}/test.py | 0
.../HardcodedCredentials.expected | 0
.../HardcodedCredentials.qlref | 0
.../Security/{CWE-798 => CWE-798-HardcodedCredentials}/test.py | 0
55 files changed, 0 insertions(+), 0 deletions(-)
rename python/ql/test/query-tests/Security/{CWE-020 => CWE-020-IncompleteUrlSubstringSanitization}/IncompleteUrlSubstringSanitization.expected (100%)
rename python/ql/test/query-tests/Security/{CWE-020 => CWE-020-IncompleteUrlSubstringSanitization}/IncompleteUrlSubstringSanitization.qlref (100%)
rename python/ql/test/query-tests/Security/{CWE-020 => CWE-020-IncompleteUrlSubstringSanitization}/urltest.py (100%)
rename python/ql/test/query-tests/Security/{CWE-078-py2 => CWE-078-CommandInjection-py2}/CommandInjection.expected (100%)
rename python/ql/test/query-tests/Security/{CWE-078-py2 => CWE-078-CommandInjection-py2}/CommandInjection.qlref (100%)
rename python/ql/test/query-tests/Security/{CWE-078-py2 => CWE-078-CommandInjection-py2}/command_injection.py (100%)
rename python/ql/test/query-tests/Security/{CWE-078-py2 => CWE-078-CommandInjection-py2}/options (100%)
rename python/ql/test/query-tests/Security/{CWE-078 => CWE-078-CommandInjection}/CommandInjection.expected (100%)
rename python/ql/test/query-tests/Security/{CWE-078 => CWE-078-CommandInjection}/CommandInjection.qlref (100%)
rename python/ql/test/query-tests/Security/{CWE-078 => CWE-078-CommandInjection}/command_injection.py (100%)
rename python/ql/test/query-tests/Security/{CWE-078 => CWE-078-CommandInjection}/options (100%)
rename python/ql/test/query-tests/Security/{CWE-079 => CWE-079-ReflectedXss}/ReflectedXss.expected (100%)
rename python/ql/test/query-tests/Security/{CWE-079 => CWE-079-ReflectedXss}/ReflectedXss.qlref (100%)
rename python/ql/test/query-tests/Security/{CWE-079 => CWE-079-ReflectedXss}/reflected_xss.py (100%)
rename python/ql/test/query-tests/Security/{CWE-089 => CWE-089-SqlInjection}/SqlInjection.expected (100%)
rename python/ql/test/query-tests/Security/{CWE-089 => CWE-089-SqlInjection}/SqlInjection.qlref (100%)
rename python/ql/test/query-tests/Security/{CWE-089 => CWE-089-SqlInjection}/sql_injection.py (100%)
rename python/ql/test/query-tests/Security/{CWE-094 => CWE-094-CodeInjection}/CodeInjection.expected (100%)
rename python/ql/test/query-tests/Security/{CWE-094 => CWE-094-CodeInjection}/CodeInjection.qlref (100%)
rename python/ql/test/query-tests/Security/{CWE-094 => CWE-094-CodeInjection}/code_injection.py (100%)
rename python/ql/test/query-tests/Security/{CWE-209 => CWE-209-StackTraceExposure}/ExceptionInfo.expected (100%)
rename python/ql/test/query-tests/Security/{CWE-209 => CWE-209-StackTraceExposure}/ExceptionInfo.ql (100%)
rename python/ql/test/query-tests/Security/{CWE-209 => CWE-209-StackTraceExposure}/Exceptions.py (100%)
rename python/ql/test/query-tests/Security/{CWE-209 => CWE-209-StackTraceExposure}/StackTraceExposure.expected (100%)
rename python/ql/test/query-tests/Security/{CWE-209 => CWE-209-StackTraceExposure}/StackTraceExposure.qlref (100%)
rename python/ql/test/query-tests/Security/{CWE-209 => CWE-209-StackTraceExposure}/Stacktrace.py (100%)
rename python/ql/test/query-tests/Security/{CWE-209 => CWE-209-StackTraceExposure}/options (100%)
rename python/ql/test/query-tests/Security/{CWE-209 => CWE-209-StackTraceExposure}/test.py (100%)
rename python/ql/test/query-tests/Security/{CWE-215 => CWE-215-FlaskDebug}/FlaskDebug.expected (100%)
rename python/ql/test/query-tests/Security/{CWE-215 => CWE-215-FlaskDebug}/FlaskDebug.qlref (100%)
rename python/ql/test/query-tests/Security/{CWE-215 => CWE-215-FlaskDebug}/options (100%)
rename python/ql/test/query-tests/Security/{CWE-215 => CWE-215-FlaskDebug}/settings.py (100%)
rename python/ql/test/query-tests/Security/{CWE-215 => CWE-215-FlaskDebug}/test.py (100%)
rename python/ql/test/query-tests/Security/{CWE-326 => CWE-326-WeakCryptoKey}/WeakCryptoKey.expected (100%)
rename python/ql/test/query-tests/Security/{CWE-326 => CWE-326-WeakCryptoKey}/WeakCryptoKey.qlref (100%)
rename python/ql/test/query-tests/Security/{CWE-326 => CWE-326-WeakCryptoKey}/test_example.py (100%)
rename python/ql/test/query-tests/Security/{CWE-326 => CWE-326-WeakCryptoKey}/weak_crypto.py (100%)
rename python/ql/test/query-tests/Security/{CWE-377 => CWE-377-InsecureTemporaryFile}/InsecureTemporaryFile.expected (100%)
rename python/ql/test/query-tests/Security/{CWE-377 => CWE-377-InsecureTemporaryFile}/InsecureTemporaryFile.py (100%)
rename python/ql/test/query-tests/Security/{CWE-377 => CWE-377-InsecureTemporaryFile}/InsecureTemporaryFile.qlref (100%)
rename python/ql/test/query-tests/Security/{CWE-377 => CWE-377-InsecureTemporaryFile}/SecureTemporaryFile.py (100%)
rename python/ql/test/query-tests/Security/{CWE-502 => CWE-502-UnsafeDeserialization}/UnsafeDeserialization.expected (100%)
rename python/ql/test/query-tests/Security/{CWE-502 => CWE-502-UnsafeDeserialization}/UnsafeDeserialization.qlref (100%)
rename python/ql/test/query-tests/Security/{CWE-502 => CWE-502-UnsafeDeserialization}/unsafe_deserialization.py (100%)
rename python/ql/test/query-tests/Security/{CWE-601 => CWE-601-UrlRedirect}/UrlRedirect.expected (100%)
rename python/ql/test/query-tests/Security/{CWE-601 => CWE-601-UrlRedirect}/UrlRedirect.qlref (100%)
rename python/ql/test/query-tests/Security/{CWE-601 => CWE-601-UrlRedirect}/options (100%)
rename python/ql/test/query-tests/Security/{CWE-601 => CWE-601-UrlRedirect}/test.py (100%)
rename python/ql/test/query-tests/Security/{CWE-732 => CWE-732-WeakFilePermissions}/WeakFilePermissions.expected (100%)
rename python/ql/test/query-tests/Security/{CWE-732 => CWE-732-WeakFilePermissions}/WeakFilePermissions.qlref (100%)
rename python/ql/test/query-tests/Security/{CWE-732 => CWE-732-WeakFilePermissions}/options (100%)
rename python/ql/test/query-tests/Security/{CWE-732 => CWE-732-WeakFilePermissions}/test.py (100%)
rename python/ql/test/query-tests/Security/{CWE-798 => CWE-798-HardcodedCredentials}/HardcodedCredentials.expected (100%)
rename python/ql/test/query-tests/Security/{CWE-798 => CWE-798-HardcodedCredentials}/HardcodedCredentials.qlref (100%)
rename python/ql/test/query-tests/Security/{CWE-798 => CWE-798-HardcodedCredentials}/test.py (100%)
diff --git a/python/ql/test/query-tests/Security/CWE-020/IncompleteUrlSubstringSanitization.expected b/python/ql/test/query-tests/Security/CWE-020-IncompleteUrlSubstringSanitization/IncompleteUrlSubstringSanitization.expected
similarity index 100%
rename from python/ql/test/query-tests/Security/CWE-020/IncompleteUrlSubstringSanitization.expected
rename to python/ql/test/query-tests/Security/CWE-020-IncompleteUrlSubstringSanitization/IncompleteUrlSubstringSanitization.expected
diff --git a/python/ql/test/query-tests/Security/CWE-020/IncompleteUrlSubstringSanitization.qlref b/python/ql/test/query-tests/Security/CWE-020-IncompleteUrlSubstringSanitization/IncompleteUrlSubstringSanitization.qlref
similarity index 100%
rename from python/ql/test/query-tests/Security/CWE-020/IncompleteUrlSubstringSanitization.qlref
rename to python/ql/test/query-tests/Security/CWE-020-IncompleteUrlSubstringSanitization/IncompleteUrlSubstringSanitization.qlref
diff --git a/python/ql/test/query-tests/Security/CWE-020/urltest.py b/python/ql/test/query-tests/Security/CWE-020-IncompleteUrlSubstringSanitization/urltest.py
similarity index 100%
rename from python/ql/test/query-tests/Security/CWE-020/urltest.py
rename to python/ql/test/query-tests/Security/CWE-020-IncompleteUrlSubstringSanitization/urltest.py
diff --git a/python/ql/test/query-tests/Security/CWE-078-py2/CommandInjection.expected b/python/ql/test/query-tests/Security/CWE-078-CommandInjection-py2/CommandInjection.expected
similarity index 100%
rename from python/ql/test/query-tests/Security/CWE-078-py2/CommandInjection.expected
rename to python/ql/test/query-tests/Security/CWE-078-CommandInjection-py2/CommandInjection.expected
diff --git a/python/ql/test/query-tests/Security/CWE-078-py2/CommandInjection.qlref b/python/ql/test/query-tests/Security/CWE-078-CommandInjection-py2/CommandInjection.qlref
similarity index 100%
rename from python/ql/test/query-tests/Security/CWE-078-py2/CommandInjection.qlref
rename to python/ql/test/query-tests/Security/CWE-078-CommandInjection-py2/CommandInjection.qlref
diff --git a/python/ql/test/query-tests/Security/CWE-078-py2/command_injection.py b/python/ql/test/query-tests/Security/CWE-078-CommandInjection-py2/command_injection.py
similarity index 100%
rename from python/ql/test/query-tests/Security/CWE-078-py2/command_injection.py
rename to python/ql/test/query-tests/Security/CWE-078-CommandInjection-py2/command_injection.py
diff --git a/python/ql/test/query-tests/Security/CWE-078-py2/options b/python/ql/test/query-tests/Security/CWE-078-CommandInjection-py2/options
similarity index 100%
rename from python/ql/test/query-tests/Security/CWE-078-py2/options
rename to python/ql/test/query-tests/Security/CWE-078-CommandInjection-py2/options
diff --git a/python/ql/test/query-tests/Security/CWE-078/CommandInjection.expected b/python/ql/test/query-tests/Security/CWE-078-CommandInjection/CommandInjection.expected
similarity index 100%
rename from python/ql/test/query-tests/Security/CWE-078/CommandInjection.expected
rename to python/ql/test/query-tests/Security/CWE-078-CommandInjection/CommandInjection.expected
diff --git a/python/ql/test/query-tests/Security/CWE-078/CommandInjection.qlref b/python/ql/test/query-tests/Security/CWE-078-CommandInjection/CommandInjection.qlref
similarity index 100%
rename from python/ql/test/query-tests/Security/CWE-078/CommandInjection.qlref
rename to python/ql/test/query-tests/Security/CWE-078-CommandInjection/CommandInjection.qlref
diff --git a/python/ql/test/query-tests/Security/CWE-078/command_injection.py b/python/ql/test/query-tests/Security/CWE-078-CommandInjection/command_injection.py
similarity index 100%
rename from python/ql/test/query-tests/Security/CWE-078/command_injection.py
rename to python/ql/test/query-tests/Security/CWE-078-CommandInjection/command_injection.py
diff --git a/python/ql/test/query-tests/Security/CWE-078/options b/python/ql/test/query-tests/Security/CWE-078-CommandInjection/options
similarity index 100%
rename from python/ql/test/query-tests/Security/CWE-078/options
rename to python/ql/test/query-tests/Security/CWE-078-CommandInjection/options
diff --git a/python/ql/test/query-tests/Security/CWE-079/ReflectedXss.expected b/python/ql/test/query-tests/Security/CWE-079-ReflectedXss/ReflectedXss.expected
similarity index 100%
rename from python/ql/test/query-tests/Security/CWE-079/ReflectedXss.expected
rename to python/ql/test/query-tests/Security/CWE-079-ReflectedXss/ReflectedXss.expected
diff --git a/python/ql/test/query-tests/Security/CWE-079/ReflectedXss.qlref b/python/ql/test/query-tests/Security/CWE-079-ReflectedXss/ReflectedXss.qlref
similarity index 100%
rename from python/ql/test/query-tests/Security/CWE-079/ReflectedXss.qlref
rename to python/ql/test/query-tests/Security/CWE-079-ReflectedXss/ReflectedXss.qlref
diff --git a/python/ql/test/query-tests/Security/CWE-079/reflected_xss.py b/python/ql/test/query-tests/Security/CWE-079-ReflectedXss/reflected_xss.py
similarity index 100%
rename from python/ql/test/query-tests/Security/CWE-079/reflected_xss.py
rename to python/ql/test/query-tests/Security/CWE-079-ReflectedXss/reflected_xss.py
diff --git a/python/ql/test/query-tests/Security/CWE-089/SqlInjection.expected b/python/ql/test/query-tests/Security/CWE-089-SqlInjection/SqlInjection.expected
similarity index 100%
rename from python/ql/test/query-tests/Security/CWE-089/SqlInjection.expected
rename to python/ql/test/query-tests/Security/CWE-089-SqlInjection/SqlInjection.expected
diff --git a/python/ql/test/query-tests/Security/CWE-089/SqlInjection.qlref b/python/ql/test/query-tests/Security/CWE-089-SqlInjection/SqlInjection.qlref
similarity index 100%
rename from python/ql/test/query-tests/Security/CWE-089/SqlInjection.qlref
rename to python/ql/test/query-tests/Security/CWE-089-SqlInjection/SqlInjection.qlref
diff --git a/python/ql/test/query-tests/Security/CWE-089/sql_injection.py b/python/ql/test/query-tests/Security/CWE-089-SqlInjection/sql_injection.py
similarity index 100%
rename from python/ql/test/query-tests/Security/CWE-089/sql_injection.py
rename to python/ql/test/query-tests/Security/CWE-089-SqlInjection/sql_injection.py
diff --git a/python/ql/test/query-tests/Security/CWE-094/CodeInjection.expected b/python/ql/test/query-tests/Security/CWE-094-CodeInjection/CodeInjection.expected
similarity index 100%
rename from python/ql/test/query-tests/Security/CWE-094/CodeInjection.expected
rename to python/ql/test/query-tests/Security/CWE-094-CodeInjection/CodeInjection.expected
diff --git a/python/ql/test/query-tests/Security/CWE-094/CodeInjection.qlref b/python/ql/test/query-tests/Security/CWE-094-CodeInjection/CodeInjection.qlref
similarity index 100%
rename from python/ql/test/query-tests/Security/CWE-094/CodeInjection.qlref
rename to python/ql/test/query-tests/Security/CWE-094-CodeInjection/CodeInjection.qlref
diff --git a/python/ql/test/query-tests/Security/CWE-094/code_injection.py b/python/ql/test/query-tests/Security/CWE-094-CodeInjection/code_injection.py
similarity index 100%
rename from python/ql/test/query-tests/Security/CWE-094/code_injection.py
rename to python/ql/test/query-tests/Security/CWE-094-CodeInjection/code_injection.py
diff --git a/python/ql/test/query-tests/Security/CWE-209/ExceptionInfo.expected b/python/ql/test/query-tests/Security/CWE-209-StackTraceExposure/ExceptionInfo.expected
similarity index 100%
rename from python/ql/test/query-tests/Security/CWE-209/ExceptionInfo.expected
rename to python/ql/test/query-tests/Security/CWE-209-StackTraceExposure/ExceptionInfo.expected
diff --git a/python/ql/test/query-tests/Security/CWE-209/ExceptionInfo.ql b/python/ql/test/query-tests/Security/CWE-209-StackTraceExposure/ExceptionInfo.ql
similarity index 100%
rename from python/ql/test/query-tests/Security/CWE-209/ExceptionInfo.ql
rename to python/ql/test/query-tests/Security/CWE-209-StackTraceExposure/ExceptionInfo.ql
diff --git a/python/ql/test/query-tests/Security/CWE-209/Exceptions.py b/python/ql/test/query-tests/Security/CWE-209-StackTraceExposure/Exceptions.py
similarity index 100%
rename from python/ql/test/query-tests/Security/CWE-209/Exceptions.py
rename to python/ql/test/query-tests/Security/CWE-209-StackTraceExposure/Exceptions.py
diff --git a/python/ql/test/query-tests/Security/CWE-209/StackTraceExposure.expected b/python/ql/test/query-tests/Security/CWE-209-StackTraceExposure/StackTraceExposure.expected
similarity index 100%
rename from python/ql/test/query-tests/Security/CWE-209/StackTraceExposure.expected
rename to python/ql/test/query-tests/Security/CWE-209-StackTraceExposure/StackTraceExposure.expected
diff --git a/python/ql/test/query-tests/Security/CWE-209/StackTraceExposure.qlref b/python/ql/test/query-tests/Security/CWE-209-StackTraceExposure/StackTraceExposure.qlref
similarity index 100%
rename from python/ql/test/query-tests/Security/CWE-209/StackTraceExposure.qlref
rename to python/ql/test/query-tests/Security/CWE-209-StackTraceExposure/StackTraceExposure.qlref
diff --git a/python/ql/test/query-tests/Security/CWE-209/Stacktrace.py b/python/ql/test/query-tests/Security/CWE-209-StackTraceExposure/Stacktrace.py
similarity index 100%
rename from python/ql/test/query-tests/Security/CWE-209/Stacktrace.py
rename to python/ql/test/query-tests/Security/CWE-209-StackTraceExposure/Stacktrace.py
diff --git a/python/ql/test/query-tests/Security/CWE-209/options b/python/ql/test/query-tests/Security/CWE-209-StackTraceExposure/options
similarity index 100%
rename from python/ql/test/query-tests/Security/CWE-209/options
rename to python/ql/test/query-tests/Security/CWE-209-StackTraceExposure/options
diff --git a/python/ql/test/query-tests/Security/CWE-209/test.py b/python/ql/test/query-tests/Security/CWE-209-StackTraceExposure/test.py
similarity index 100%
rename from python/ql/test/query-tests/Security/CWE-209/test.py
rename to python/ql/test/query-tests/Security/CWE-209-StackTraceExposure/test.py
diff --git a/python/ql/test/query-tests/Security/CWE-215/FlaskDebug.expected b/python/ql/test/query-tests/Security/CWE-215-FlaskDebug/FlaskDebug.expected
similarity index 100%
rename from python/ql/test/query-tests/Security/CWE-215/FlaskDebug.expected
rename to python/ql/test/query-tests/Security/CWE-215-FlaskDebug/FlaskDebug.expected
diff --git a/python/ql/test/query-tests/Security/CWE-215/FlaskDebug.qlref b/python/ql/test/query-tests/Security/CWE-215-FlaskDebug/FlaskDebug.qlref
similarity index 100%
rename from python/ql/test/query-tests/Security/CWE-215/FlaskDebug.qlref
rename to python/ql/test/query-tests/Security/CWE-215-FlaskDebug/FlaskDebug.qlref
diff --git a/python/ql/test/query-tests/Security/CWE-215/options b/python/ql/test/query-tests/Security/CWE-215-FlaskDebug/options
similarity index 100%
rename from python/ql/test/query-tests/Security/CWE-215/options
rename to python/ql/test/query-tests/Security/CWE-215-FlaskDebug/options
diff --git a/python/ql/test/query-tests/Security/CWE-215/settings.py b/python/ql/test/query-tests/Security/CWE-215-FlaskDebug/settings.py
similarity index 100%
rename from python/ql/test/query-tests/Security/CWE-215/settings.py
rename to python/ql/test/query-tests/Security/CWE-215-FlaskDebug/settings.py
diff --git a/python/ql/test/query-tests/Security/CWE-215/test.py b/python/ql/test/query-tests/Security/CWE-215-FlaskDebug/test.py
similarity index 100%
rename from python/ql/test/query-tests/Security/CWE-215/test.py
rename to python/ql/test/query-tests/Security/CWE-215-FlaskDebug/test.py
diff --git a/python/ql/test/query-tests/Security/CWE-326/WeakCryptoKey.expected b/python/ql/test/query-tests/Security/CWE-326-WeakCryptoKey/WeakCryptoKey.expected
similarity index 100%
rename from python/ql/test/query-tests/Security/CWE-326/WeakCryptoKey.expected
rename to python/ql/test/query-tests/Security/CWE-326-WeakCryptoKey/WeakCryptoKey.expected
diff --git a/python/ql/test/query-tests/Security/CWE-326/WeakCryptoKey.qlref b/python/ql/test/query-tests/Security/CWE-326-WeakCryptoKey/WeakCryptoKey.qlref
similarity index 100%
rename from python/ql/test/query-tests/Security/CWE-326/WeakCryptoKey.qlref
rename to python/ql/test/query-tests/Security/CWE-326-WeakCryptoKey/WeakCryptoKey.qlref
diff --git a/python/ql/test/query-tests/Security/CWE-326/test_example.py b/python/ql/test/query-tests/Security/CWE-326-WeakCryptoKey/test_example.py
similarity index 100%
rename from python/ql/test/query-tests/Security/CWE-326/test_example.py
rename to python/ql/test/query-tests/Security/CWE-326-WeakCryptoKey/test_example.py
diff --git a/python/ql/test/query-tests/Security/CWE-326/weak_crypto.py b/python/ql/test/query-tests/Security/CWE-326-WeakCryptoKey/weak_crypto.py
similarity index 100%
rename from python/ql/test/query-tests/Security/CWE-326/weak_crypto.py
rename to python/ql/test/query-tests/Security/CWE-326-WeakCryptoKey/weak_crypto.py
diff --git a/python/ql/test/query-tests/Security/CWE-377/InsecureTemporaryFile.expected b/python/ql/test/query-tests/Security/CWE-377-InsecureTemporaryFile/InsecureTemporaryFile.expected
similarity index 100%
rename from python/ql/test/query-tests/Security/CWE-377/InsecureTemporaryFile.expected
rename to python/ql/test/query-tests/Security/CWE-377-InsecureTemporaryFile/InsecureTemporaryFile.expected
diff --git a/python/ql/test/query-tests/Security/CWE-377/InsecureTemporaryFile.py b/python/ql/test/query-tests/Security/CWE-377-InsecureTemporaryFile/InsecureTemporaryFile.py
similarity index 100%
rename from python/ql/test/query-tests/Security/CWE-377/InsecureTemporaryFile.py
rename to python/ql/test/query-tests/Security/CWE-377-InsecureTemporaryFile/InsecureTemporaryFile.py
diff --git a/python/ql/test/query-tests/Security/CWE-377/InsecureTemporaryFile.qlref b/python/ql/test/query-tests/Security/CWE-377-InsecureTemporaryFile/InsecureTemporaryFile.qlref
similarity index 100%
rename from python/ql/test/query-tests/Security/CWE-377/InsecureTemporaryFile.qlref
rename to python/ql/test/query-tests/Security/CWE-377-InsecureTemporaryFile/InsecureTemporaryFile.qlref
diff --git a/python/ql/test/query-tests/Security/CWE-377/SecureTemporaryFile.py b/python/ql/test/query-tests/Security/CWE-377-InsecureTemporaryFile/SecureTemporaryFile.py
similarity index 100%
rename from python/ql/test/query-tests/Security/CWE-377/SecureTemporaryFile.py
rename to python/ql/test/query-tests/Security/CWE-377-InsecureTemporaryFile/SecureTemporaryFile.py
diff --git a/python/ql/test/query-tests/Security/CWE-502/UnsafeDeserialization.expected b/python/ql/test/query-tests/Security/CWE-502-UnsafeDeserialization/UnsafeDeserialization.expected
similarity index 100%
rename from python/ql/test/query-tests/Security/CWE-502/UnsafeDeserialization.expected
rename to python/ql/test/query-tests/Security/CWE-502-UnsafeDeserialization/UnsafeDeserialization.expected
diff --git a/python/ql/test/query-tests/Security/CWE-502/UnsafeDeserialization.qlref b/python/ql/test/query-tests/Security/CWE-502-UnsafeDeserialization/UnsafeDeserialization.qlref
similarity index 100%
rename from python/ql/test/query-tests/Security/CWE-502/UnsafeDeserialization.qlref
rename to python/ql/test/query-tests/Security/CWE-502-UnsafeDeserialization/UnsafeDeserialization.qlref
diff --git a/python/ql/test/query-tests/Security/CWE-502/unsafe_deserialization.py b/python/ql/test/query-tests/Security/CWE-502-UnsafeDeserialization/unsafe_deserialization.py
similarity index 100%
rename from python/ql/test/query-tests/Security/CWE-502/unsafe_deserialization.py
rename to python/ql/test/query-tests/Security/CWE-502-UnsafeDeserialization/unsafe_deserialization.py
diff --git a/python/ql/test/query-tests/Security/CWE-601/UrlRedirect.expected b/python/ql/test/query-tests/Security/CWE-601-UrlRedirect/UrlRedirect.expected
similarity index 100%
rename from python/ql/test/query-tests/Security/CWE-601/UrlRedirect.expected
rename to python/ql/test/query-tests/Security/CWE-601-UrlRedirect/UrlRedirect.expected
diff --git a/python/ql/test/query-tests/Security/CWE-601/UrlRedirect.qlref b/python/ql/test/query-tests/Security/CWE-601-UrlRedirect/UrlRedirect.qlref
similarity index 100%
rename from python/ql/test/query-tests/Security/CWE-601/UrlRedirect.qlref
rename to python/ql/test/query-tests/Security/CWE-601-UrlRedirect/UrlRedirect.qlref
diff --git a/python/ql/test/query-tests/Security/CWE-601/options b/python/ql/test/query-tests/Security/CWE-601-UrlRedirect/options
similarity index 100%
rename from python/ql/test/query-tests/Security/CWE-601/options
rename to python/ql/test/query-tests/Security/CWE-601-UrlRedirect/options
diff --git a/python/ql/test/query-tests/Security/CWE-601/test.py b/python/ql/test/query-tests/Security/CWE-601-UrlRedirect/test.py
similarity index 100%
rename from python/ql/test/query-tests/Security/CWE-601/test.py
rename to python/ql/test/query-tests/Security/CWE-601-UrlRedirect/test.py
diff --git a/python/ql/test/query-tests/Security/CWE-732/WeakFilePermissions.expected b/python/ql/test/query-tests/Security/CWE-732-WeakFilePermissions/WeakFilePermissions.expected
similarity index 100%
rename from python/ql/test/query-tests/Security/CWE-732/WeakFilePermissions.expected
rename to python/ql/test/query-tests/Security/CWE-732-WeakFilePermissions/WeakFilePermissions.expected
diff --git a/python/ql/test/query-tests/Security/CWE-732/WeakFilePermissions.qlref b/python/ql/test/query-tests/Security/CWE-732-WeakFilePermissions/WeakFilePermissions.qlref
similarity index 100%
rename from python/ql/test/query-tests/Security/CWE-732/WeakFilePermissions.qlref
rename to python/ql/test/query-tests/Security/CWE-732-WeakFilePermissions/WeakFilePermissions.qlref
diff --git a/python/ql/test/query-tests/Security/CWE-732/options b/python/ql/test/query-tests/Security/CWE-732-WeakFilePermissions/options
similarity index 100%
rename from python/ql/test/query-tests/Security/CWE-732/options
rename to python/ql/test/query-tests/Security/CWE-732-WeakFilePermissions/options
diff --git a/python/ql/test/query-tests/Security/CWE-732/test.py b/python/ql/test/query-tests/Security/CWE-732-WeakFilePermissions/test.py
similarity index 100%
rename from python/ql/test/query-tests/Security/CWE-732/test.py
rename to python/ql/test/query-tests/Security/CWE-732-WeakFilePermissions/test.py
diff --git a/python/ql/test/query-tests/Security/CWE-798/HardcodedCredentials.expected b/python/ql/test/query-tests/Security/CWE-798-HardcodedCredentials/HardcodedCredentials.expected
similarity index 100%
rename from python/ql/test/query-tests/Security/CWE-798/HardcodedCredentials.expected
rename to python/ql/test/query-tests/Security/CWE-798-HardcodedCredentials/HardcodedCredentials.expected
diff --git a/python/ql/test/query-tests/Security/CWE-798/HardcodedCredentials.qlref b/python/ql/test/query-tests/Security/CWE-798-HardcodedCredentials/HardcodedCredentials.qlref
similarity index 100%
rename from python/ql/test/query-tests/Security/CWE-798/HardcodedCredentials.qlref
rename to python/ql/test/query-tests/Security/CWE-798-HardcodedCredentials/HardcodedCredentials.qlref
diff --git a/python/ql/test/query-tests/Security/CWE-798/test.py b/python/ql/test/query-tests/Security/CWE-798-HardcodedCredentials/test.py
similarity index 100%
rename from python/ql/test/query-tests/Security/CWE-798/test.py
rename to python/ql/test/query-tests/Security/CWE-798-HardcodedCredentials/test.py
From 5939128a76d137d292752ddf18528b7c182d73e7 Mon Sep 17 00:00:00 2001
From: Rasmus Wriedt Larsen
Date: Mon, 19 Jul 2021 16:56:07 +0200
Subject: [PATCH 127/429] Python: Fix test folder for InsecureDefaultProtocol
it was named wrong before. whoops.
---
.../InsecureDefaultProtocol.expected | 0
.../InsecureDefaultProtocol.qlref | 0
.../InsecureProtocol.py | 0
3 files changed, 0 insertions(+), 0 deletions(-)
rename python/ql/test/query-tests/Security/{CWE-327-InsecureProtocol => CWE-327-InsecureDefaultProtocol}/InsecureDefaultProtocol.expected (100%)
rename python/ql/test/query-tests/Security/{CWE-327-InsecureProtocol => CWE-327-InsecureDefaultProtocol}/InsecureDefaultProtocol.qlref (100%)
rename python/ql/test/query-tests/Security/{CWE-327-InsecureProtocol => CWE-327-InsecureDefaultProtocol}/InsecureProtocol.py (100%)
diff --git a/python/ql/test/query-tests/Security/CWE-327-InsecureProtocol/InsecureDefaultProtocol.expected b/python/ql/test/query-tests/Security/CWE-327-InsecureDefaultProtocol/InsecureDefaultProtocol.expected
similarity index 100%
rename from python/ql/test/query-tests/Security/CWE-327-InsecureProtocol/InsecureDefaultProtocol.expected
rename to python/ql/test/query-tests/Security/CWE-327-InsecureDefaultProtocol/InsecureDefaultProtocol.expected
diff --git a/python/ql/test/query-tests/Security/CWE-327-InsecureProtocol/InsecureDefaultProtocol.qlref b/python/ql/test/query-tests/Security/CWE-327-InsecureDefaultProtocol/InsecureDefaultProtocol.qlref
similarity index 100%
rename from python/ql/test/query-tests/Security/CWE-327-InsecureProtocol/InsecureDefaultProtocol.qlref
rename to python/ql/test/query-tests/Security/CWE-327-InsecureDefaultProtocol/InsecureDefaultProtocol.qlref
diff --git a/python/ql/test/query-tests/Security/CWE-327-InsecureProtocol/InsecureProtocol.py b/python/ql/test/query-tests/Security/CWE-327-InsecureDefaultProtocol/InsecureProtocol.py
similarity index 100%
rename from python/ql/test/query-tests/Security/CWE-327-InsecureProtocol/InsecureProtocol.py
rename to python/ql/test/query-tests/Security/CWE-327-InsecureDefaultProtocol/InsecureProtocol.py
From 5249591747f7f4058a12d4a9df513c15fec8db11 Mon Sep 17 00:00:00 2001
From: Rasmus Wriedt Larsen
Date: Mon, 19 Jul 2021 16:57:00 +0200
Subject: [PATCH 128/429] Python: Fix test folder for InsecureProtocol
---
.../InsecureProtocol.expected | 0
.../{CWE-327 => CWE-327-InsecureProtocol}/InsecureProtocol.py | 0
.../{CWE-327 => CWE-327-InsecureProtocol}/InsecureProtocol.qlref | 0
.../Security/{CWE-327 => CWE-327-InsecureProtocol}/options | 0
.../{CWE-327 => CWE-327-InsecureProtocol}/pyOpenSSL_fluent.py | 0
.../Security/{CWE-327 => CWE-327-InsecureProtocol}/ssl_fluent.py | 0
6 files changed, 0 insertions(+), 0 deletions(-)
rename python/ql/test/query-tests/Security/{CWE-327 => CWE-327-InsecureProtocol}/InsecureProtocol.expected (100%)
rename python/ql/test/query-tests/Security/{CWE-327 => CWE-327-InsecureProtocol}/InsecureProtocol.py (100%)
rename python/ql/test/query-tests/Security/{CWE-327 => CWE-327-InsecureProtocol}/InsecureProtocol.qlref (100%)
rename python/ql/test/query-tests/Security/{CWE-327 => CWE-327-InsecureProtocol}/options (100%)
rename python/ql/test/query-tests/Security/{CWE-327 => CWE-327-InsecureProtocol}/pyOpenSSL_fluent.py (100%)
rename python/ql/test/query-tests/Security/{CWE-327 => CWE-327-InsecureProtocol}/ssl_fluent.py (100%)
diff --git a/python/ql/test/query-tests/Security/CWE-327/InsecureProtocol.expected b/python/ql/test/query-tests/Security/CWE-327-InsecureProtocol/InsecureProtocol.expected
similarity index 100%
rename from python/ql/test/query-tests/Security/CWE-327/InsecureProtocol.expected
rename to python/ql/test/query-tests/Security/CWE-327-InsecureProtocol/InsecureProtocol.expected
diff --git a/python/ql/test/query-tests/Security/CWE-327/InsecureProtocol.py b/python/ql/test/query-tests/Security/CWE-327-InsecureProtocol/InsecureProtocol.py
similarity index 100%
rename from python/ql/test/query-tests/Security/CWE-327/InsecureProtocol.py
rename to python/ql/test/query-tests/Security/CWE-327-InsecureProtocol/InsecureProtocol.py
diff --git a/python/ql/test/query-tests/Security/CWE-327/InsecureProtocol.qlref b/python/ql/test/query-tests/Security/CWE-327-InsecureProtocol/InsecureProtocol.qlref
similarity index 100%
rename from python/ql/test/query-tests/Security/CWE-327/InsecureProtocol.qlref
rename to python/ql/test/query-tests/Security/CWE-327-InsecureProtocol/InsecureProtocol.qlref
diff --git a/python/ql/test/query-tests/Security/CWE-327/options b/python/ql/test/query-tests/Security/CWE-327-InsecureProtocol/options
similarity index 100%
rename from python/ql/test/query-tests/Security/CWE-327/options
rename to python/ql/test/query-tests/Security/CWE-327-InsecureProtocol/options
diff --git a/python/ql/test/query-tests/Security/CWE-327/pyOpenSSL_fluent.py b/python/ql/test/query-tests/Security/CWE-327-InsecureProtocol/pyOpenSSL_fluent.py
similarity index 100%
rename from python/ql/test/query-tests/Security/CWE-327/pyOpenSSL_fluent.py
rename to python/ql/test/query-tests/Security/CWE-327-InsecureProtocol/pyOpenSSL_fluent.py
diff --git a/python/ql/test/query-tests/Security/CWE-327/ssl_fluent.py b/python/ql/test/query-tests/Security/CWE-327-InsecureProtocol/ssl_fluent.py
similarity index 100%
rename from python/ql/test/query-tests/Security/CWE-327/ssl_fluent.py
rename to python/ql/test/query-tests/Security/CWE-327-InsecureProtocol/ssl_fluent.py
From 930d576cfb2f241c6fc843d88f4ec7b5f4de7b3c Mon Sep 17 00:00:00 2001
From: Shawn P
Date: Fri, 23 Jul 2021 00:45:02 +0800
Subject: [PATCH 129/429] Fixed `isUncertain()` description
---
.../codeql-language-guides/codeql-library-for-javascript.rst | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/codeql/codeql-language-guides/codeql-library-for-javascript.rst b/docs/codeql/codeql-language-guides/codeql-library-for-javascript.rst
index d88b8b10d57..756740790bd 100644
--- a/docs/codeql/codeql-language-guides/codeql-library-for-javascript.rst
+++ b/docs/codeql/codeql-language-guides/codeql-library-for-javascript.rst
@@ -694,7 +694,7 @@ Furthermore, there are three member predicates that indicate the quality of the
- ``DataFlow::InvokeNode.isImprecise()``: holds for invocations where the call graph builder might infer spurious call targets.
- ``DataFlow::InvokeNode.isIncomplete()``: holds for invocations where the call graph builder might fail to infer possible call targets.
-- ``DataFlow::InvokeNode.isUncertain()``: holds if either ``isImprecise()`` or ``isUncertain()`` holds.
+- ``DataFlow::InvokeNode.isUncertain()``: holds if either ``isImprecise()`` or ``isIncomplete()`` holds.
As an example of a call-graph-based query, here is a query to find invocations for which the call graph builder could not find any callees, despite the analysis being complete for this invocation:
From 3bcb46f875b1ecb11e9e8a86febd90e7fc735041 Mon Sep 17 00:00:00 2001
From: Joe Farebrother
Date: Thu, 29 Jul 2021 14:46:29 +0100
Subject: [PATCH 130/429] Model guava cache package
---
.../code/java/frameworks/guava/Cache.qll | 28 +++++++++++++++++++
.../code/java/frameworks/guava/Guava.qll | 1 +
2 files changed, 29 insertions(+)
create mode 100644 java/ql/src/semmle/code/java/frameworks/guava/Cache.qll
diff --git a/java/ql/src/semmle/code/java/frameworks/guava/Cache.qll b/java/ql/src/semmle/code/java/frameworks/guava/Cache.qll
new file mode 100644
index 00000000000..4134158a975
--- /dev/null
+++ b/java/ql/src/semmle/code/java/frameworks/guava/Cache.qll
@@ -0,0 +1,28 @@
+/** Flow steps through methods of `com.google.common.cache` */
+
+import java
+private import semmle.code.java.dataflow.ExternalFlow
+
+private class GuavaBaseCsv extends SummaryModelCsv {
+ override predicate row(string row) {
+ row =
+ [
+ //`namespace; type; subtypes; name; signature; ext; input; output; kind`
+ "com.google.common.cache;Cache;true;asMap;();;MapKey of Argument[-1];MapKey of ReturnValue;value",
+ "com.google.common.cache;Cache;true;asMap;();;MapValue of Argument[-1];MapValue of ReturnValue;value",
+ // lambda flow from Argument[1] not implemented
+ "com.google.common.cache;Cache;true;get;(Object,Callable);;MapValue of Argument[-1];ReturnValue;value",
+ "com.google.common.cache;Cache;true;getIfPresent;(Object);;MapValue of Argument[-1];ReturnValue;value",
+ "com.google.common.cache;Cache;true;getAllPresent;(Iterable);;MapValue of Argument[-1];MapValue of ReturnValue;value",
+ "com.google.common.cache;Cache;true;put;(Object,Object);;Argument[0];MapKey of Argument[-1];value",
+ "com.google.common.cache;Cache;true;put;(Object,Object);;Argument[1];MapValue of Argument[-1];value",
+ "com.google.common.cache;Cache;true;putAll;(Map);;MapKey of Argument[0];MapKey of Argument[-1];value",
+ "com.google.common.cache;Cache;true;putAll;(Map);;MapValue of Argument[0];MapValue of Argument[-1];value",
+ "com.google.common.cache;LoadingCache;true;get;(Object);;MapValue of Argument[-1];ReturnValue;value",
+ "com.google.common.cache;LoadingCache;true;getUnchecked;(Object);;MapValue of Argument[-1];ReturnValue;value",
+ "com.google.common.cache;LoadingCache;true;apply;(Object);;MapValue of Argument[-1];ReturnValue;value",
+ "com.google.common.cache;LoadingCache;true;getAll;(Iterable);;Element of Argument[0];MapKey of ReturnValue;value",
+ "com.google.common.cache;LoadingCache;true;getAll;(Iterable);;MapValue of Argument[-1];MapValue of ReturnValue;value"
+ ]
+ }
+}
diff --git a/java/ql/src/semmle/code/java/frameworks/guava/Guava.qll b/java/ql/src/semmle/code/java/frameworks/guava/Guava.qll
index 629ac74b426..d7a4ab959df 100644
--- a/java/ql/src/semmle/code/java/frameworks/guava/Guava.qll
+++ b/java/ql/src/semmle/code/java/frameworks/guava/Guava.qll
@@ -6,3 +6,4 @@ import java
import Base
import Collections
import IO
+import Cache
From 096509b9aa3ddf77b4640de4a74278021f92d34d Mon Sep 17 00:00:00 2001
From: Joe Farebrother
Date: Thu, 29 Jul 2021 15:01:50 +0100
Subject: [PATCH 131/429] Generate tests and stubs
---
.../guava/generated/cache/Test.java | 138 +++++++++++
.../frameworks/guava/generated/cache/options | 1 +
.../guava/generated/cache/test.expected | 0
.../frameworks/guava/generated/cache/test.ql | 67 ++++++
.../com/google/common/base/Function.java | 26 +--
.../com/google/common/cache/Cache.java | 25 ++
.../com/google/common/cache/CacheStats.java | 27 +++
.../com/google/common/cache/LoadingCache.java | 18 ++
.../common/collect/AbstractMultimap.java | 115 +++------
.../common/collect/BaseImmutableMultimap.java | 10 +
.../common/collect/ImmutableCollection.java | 78 +++----
.../google/common/collect/ImmutableList.java | 160 ++++++-------
.../google/common/collect/ImmutableMap.java | 220 +++++++-----------
.../common/collect/ImmutableMultimap.java | 190 ++++++---------
.../common/collect/ImmutableMultiset.java | 172 +++++---------
...eMultisetGwtSerializationDependencies.java | 10 +
.../google/common/collect/ImmutableSet.java | 128 ++++------
.../common/collect/ImmutableSetMultimap.java | 54 +++++
.../com/google/common/collect/Multimap.java | 81 ++-----
.../com/google/common/collect/Multiset.java | 76 +++---
.../google/common/collect/SetMultimap.java | 18 ++
.../common/collect/UnmodifiableIterator.java | 11 +
.../collect/UnmodifiableListIterator.java | 13 ++
23 files changed, 853 insertions(+), 785 deletions(-)
create mode 100644 java/ql/test/library-tests/frameworks/guava/generated/cache/Test.java
create mode 100644 java/ql/test/library-tests/frameworks/guava/generated/cache/options
create mode 100644 java/ql/test/library-tests/frameworks/guava/generated/cache/test.expected
create mode 100644 java/ql/test/library-tests/frameworks/guava/generated/cache/test.ql
create mode 100644 java/ql/test/stubs/guava-30.0/com/google/common/cache/Cache.java
create mode 100644 java/ql/test/stubs/guava-30.0/com/google/common/cache/CacheStats.java
create mode 100644 java/ql/test/stubs/guava-30.0/com/google/common/cache/LoadingCache.java
create mode 100644 java/ql/test/stubs/guava-30.0/com/google/common/collect/BaseImmutableMultimap.java
create mode 100644 java/ql/test/stubs/guava-30.0/com/google/common/collect/ImmutableMultisetGwtSerializationDependencies.java
create mode 100644 java/ql/test/stubs/guava-30.0/com/google/common/collect/ImmutableSetMultimap.java
create mode 100644 java/ql/test/stubs/guava-30.0/com/google/common/collect/SetMultimap.java
create mode 100644 java/ql/test/stubs/guava-30.0/com/google/common/collect/UnmodifiableIterator.java
create mode 100644 java/ql/test/stubs/guava-30.0/com/google/common/collect/UnmodifiableListIterator.java
diff --git a/java/ql/test/library-tests/frameworks/guava/generated/cache/Test.java b/java/ql/test/library-tests/frameworks/guava/generated/cache/Test.java
new file mode 100644
index 00000000000..877c886f66a
--- /dev/null
+++ b/java/ql/test/library-tests/frameworks/guava/generated/cache/Test.java
@@ -0,0 +1,138 @@
+package generatedtest;
+
+import com.google.common.cache.Cache;
+import com.google.common.cache.LoadingCache;
+import com.google.common.collect.ImmutableMap;
+import java.util.Map;
+import java.util.concurrent.ConcurrentMap;
+
+// Test case generated by GenerateFlowTestCase.ql
+public class Test {
+
+ Object getMapKey(Object container) { return null; }
+ Object getMapValue(Object container) { return null; }
+ Object newWithElement(Object element) { return null; }
+ Object newWithMapKey(Object element) { return null; }
+ Object newWithMapValue(Object element) { return null; }
+ Object source() { return null; }
+ void sink(Object o) { }
+
+ public void test() throws Exception {
+
+ {
+ // "com.google.common.cache;Cache;true;asMap;();;MapKey of Argument[-1];MapKey of ReturnValue;value"
+ ConcurrentMap out = null;
+ LoadingCache in = (LoadingCache)newWithMapKey(source());
+ out = in.asMap();
+ sink(getMapKey(out)); // $ hasValueFlow
+ }
+ {
+ // "com.google.common.cache;Cache;true;asMap;();;MapKey of Argument[-1];MapKey of ReturnValue;value"
+ ConcurrentMap out = null;
+ Cache in = (Cache)newWithMapKey(source());
+ out = in.asMap();
+ sink(getMapKey(out)); // $ hasValueFlow
+ }
+ {
+ // "com.google.common.cache;Cache;true;asMap;();;MapValue of Argument[-1];MapValue of ReturnValue;value"
+ ConcurrentMap out = null;
+ LoadingCache in = (LoadingCache)newWithMapValue(source());
+ out = in.asMap();
+ sink(getMapValue(out)); // $ hasValueFlow
+ }
+ {
+ // "com.google.common.cache;Cache;true;asMap;();;MapValue of Argument[-1];MapValue of ReturnValue;value"
+ ConcurrentMap out = null;
+ Cache in = (Cache)newWithMapValue(source());
+ out = in.asMap();
+ sink(getMapValue(out)); // $ hasValueFlow
+ }
+ {
+ // "com.google.common.cache;Cache;true;get;(Object,Callable);;MapValue of Argument[-1];ReturnValue;value"
+ Object out = null;
+ Cache in = (Cache)newWithMapValue(source());
+ out = in.get(null, null);
+ sink(out); // $ hasValueFlow
+ }
+ {
+ // "com.google.common.cache;Cache;true;getAllPresent;(Iterable);;MapValue of Argument[-1];MapValue of ReturnValue;value"
+ ImmutableMap out = null;
+ Cache in = (Cache)newWithMapValue(source());
+ out = in.getAllPresent(null);
+ sink(getMapValue(out)); // $ hasValueFlow
+ }
+ {
+ // "com.google.common.cache;Cache;true;getIfPresent;(Object);;MapValue of Argument[-1];ReturnValue;value"
+ Object out = null;
+ Cache in = (Cache)newWithMapValue(source());
+ out = in.getIfPresent(null);
+ sink(out); // $ hasValueFlow
+ }
+ {
+ // "com.google.common.cache;Cache;true;put;(Object,Object);;Argument[0];MapKey of Argument[-1];value"
+ Cache out = null;
+ Object in = (Object)source();
+ out.put(in, null);
+ sink(getMapKey(out)); // $ hasValueFlow
+ }
+ {
+ // "com.google.common.cache;Cache;true;put;(Object,Object);;Argument[1];MapValue of Argument[-1];value"
+ Cache out = null;
+ Object in = (Object)source();
+ out.put(null, in);
+ sink(getMapValue(out)); // $ hasValueFlow
+ }
+ {
+ // "com.google.common.cache;Cache;true;putAll;(Map);;MapKey of Argument[0];MapKey of Argument[-1];value"
+ Cache out = null;
+ Map in = (Map)newWithMapKey(source());
+ out.putAll(in);
+ sink(getMapKey(out)); // $ hasValueFlow
+ }
+ {
+ // "com.google.common.cache;Cache;true;putAll;(Map);;MapValue of Argument[0];MapValue of Argument[-1];value"
+ Cache out = null;
+ Map in = (Map)newWithMapValue(source());
+ out.putAll(in);
+ sink(getMapValue(out)); // $ hasValueFlow
+ }
+ {
+ // "com.google.common.cache;LoadingCache;true;apply;(Object);;MapValue of Argument[-1];ReturnValue;value"
+ Object out = null;
+ LoadingCache in = (LoadingCache)newWithMapValue(source());
+ out = in.apply(null);
+ sink(out); // $ hasValueFlow
+ }
+ {
+ // "com.google.common.cache;LoadingCache;true;get;(Object);;MapValue of Argument[-1];ReturnValue;value"
+ Object out = null;
+ LoadingCache in = (LoadingCache)newWithMapValue(source());
+ out = in.get(null);
+ sink(out); // $ hasValueFlow
+ }
+ {
+ // "com.google.common.cache;LoadingCache;true;getAll;(Iterable);;Element of Argument[0];MapKey of ReturnValue;value"
+ ImmutableMap out = null;
+ Iterable in = (Iterable)newWithElement(source());
+ LoadingCache instance = null;
+ out = instance.getAll(in);
+ sink(getMapKey(out)); // $ hasValueFlow
+ }
+ {
+ // "com.google.common.cache;LoadingCache;true;getAll;(Iterable);;MapValue of Argument[-1];MapValue of ReturnValue;value"
+ ImmutableMap out = null;
+ LoadingCache in = (LoadingCache)newWithMapValue(source());
+ out = in.getAll(null);
+ sink(getMapValue(out)); // $ hasValueFlow
+ }
+ {
+ // "com.google.common.cache;LoadingCache;true;getUnchecked;(Object);;MapValue of Argument[-1];ReturnValue;value"
+ Object out = null;
+ LoadingCache in = (LoadingCache)newWithMapValue(source());
+ out = in.getUnchecked(null);
+ sink(out); // $ hasValueFlow
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/java/ql/test/library-tests/frameworks/guava/generated/cache/options b/java/ql/test/library-tests/frameworks/guava/generated/cache/options
new file mode 100644
index 00000000000..c894bb5413e
--- /dev/null
+++ b/java/ql/test/library-tests/frameworks/guava/generated/cache/options
@@ -0,0 +1 @@
+//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../../stubs/guava-30.0
\ No newline at end of file
diff --git a/java/ql/test/library-tests/frameworks/guava/generated/cache/test.expected b/java/ql/test/library-tests/frameworks/guava/generated/cache/test.expected
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/java/ql/test/library-tests/frameworks/guava/generated/cache/test.ql b/java/ql/test/library-tests/frameworks/guava/generated/cache/test.ql
new file mode 100644
index 00000000000..f280580a5a7
--- /dev/null
+++ b/java/ql/test/library-tests/frameworks/guava/generated/cache/test.ql
@@ -0,0 +1,67 @@
+import java
+import semmle.code.java.dataflow.DataFlow
+import semmle.code.java.dataflow.ExternalFlow
+import semmle.code.java.dataflow.TaintTracking
+import TestUtilities.InlineExpectationsTest
+
+class SummaryModelTest extends SummaryModelCsv {
+ override predicate row(string row) {
+ row =
+ [
+ //"package;type;overrides;name;signature;ext;inputspec;outputspec;kind",
+ "generatedtest;Test;false;newWithElement;;;Argument[0];Element of ReturnValue;value",
+ "generatedtest;Test;false;getMapKey;;;MapKey of Argument[0];ReturnValue;value",
+ "generatedtest;Test;false;newWithMapKey;;;Argument[0];MapKey of ReturnValue;value",
+ "generatedtest;Test;false;getMapValue;;;MapValue of Argument[0];ReturnValue;value",
+ "generatedtest;Test;false;newWithMapValue;;;Argument[0];MapValue of ReturnValue;value"
+ ]
+ }
+}
+
+class ValueFlowConf extends DataFlow::Configuration {
+ ValueFlowConf() { this = "qltest:valueFlowConf" }
+
+ override predicate isSource(DataFlow::Node n) {
+ n.asExpr().(MethodAccess).getMethod().hasName("source")
+ }
+
+ override predicate isSink(DataFlow::Node n) {
+ n.asExpr().(Argument).getCall().getCallee().hasName("sink")
+ }
+}
+
+class TaintFlowConf extends TaintTracking::Configuration {
+ TaintFlowConf() { this = "qltest:taintFlowConf" }
+
+ override predicate isSource(DataFlow::Node n) {
+ n.asExpr().(MethodAccess).getMethod().hasName("source")
+ }
+
+ override predicate isSink(DataFlow::Node n) {
+ n.asExpr().(Argument).getCall().getCallee().hasName("sink")
+ }
+}
+
+class HasFlowTest extends InlineExpectationsTest {
+ HasFlowTest() { this = "HasFlowTest" }
+
+ override string getARelevantTag() { result = ["hasValueFlow", "hasTaintFlow"] }
+
+ override predicate hasActualResult(Location location, string element, string tag, string value) {
+ tag = "hasValueFlow" and
+ exists(DataFlow::Node src, DataFlow::Node sink, ValueFlowConf conf | conf.hasFlow(src, sink) |
+ sink.getLocation() = location and
+ element = sink.toString() and
+ value = ""
+ )
+ or
+ tag = "hasTaintFlow" and
+ exists(DataFlow::Node src, DataFlow::Node sink, TaintFlowConf conf |
+ conf.hasFlow(src, sink) and not any(ValueFlowConf c).hasFlow(src, sink)
+ |
+ sink.getLocation() = location and
+ element = sink.toString() and
+ value = ""
+ )
+ }
+}
diff --git a/java/ql/test/stubs/guava-30.0/com/google/common/base/Function.java b/java/ql/test/stubs/guava-30.0/com/google/common/base/Function.java
index 75acf7f8a54..b5d12261264 100644
--- a/java/ql/test/stubs/guava-30.0/com/google/common/base/Function.java
+++ b/java/ql/test/stubs/guava-30.0/com/google/common/base/Function.java
@@ -1,25 +1,9 @@
-/*
- * Copyright (C) 2007 The Guava Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
+// Generated automatically from com.google.common.base.Function for testing purposes, and adjusted manually
package com.google.common.base;
-import org.checkerframework.checker.nullness.qual.Nullable;
-
-public interface Function extends java.util.function.Function {
- @Override
- T apply(@Nullable F input);
-
- @Override
- boolean equals(@Nullable Object object);
+public interface Function extends java.util.function.Function
+{
+ T apply(F p0);
+ boolean equals(Object p0);
}
diff --git a/java/ql/test/stubs/guava-30.0/com/google/common/cache/Cache.java b/java/ql/test/stubs/guava-30.0/com/google/common/cache/Cache.java
new file mode 100644
index 00000000000..e509bbc8b97
--- /dev/null
+++ b/java/ql/test/stubs/guava-30.0/com/google/common/cache/Cache.java
@@ -0,0 +1,25 @@
+// Generated automatically from com.google.common.cache.Cache for testing purposes
+
+package com.google.common.cache;
+
+import com.google.common.cache.CacheStats;
+import com.google.common.collect.ImmutableMap;
+import java.util.Map;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ConcurrentMap;
+
+public interface Cache
+{
+ CacheStats stats();
+ ConcurrentMap asMap();
+ ImmutableMap getAllPresent(Iterable extends Object> p0);
+ V get(K p0, Callable extends V> p1);
+ V getIfPresent(Object p0);
+ long size();
+ void cleanUp();
+ void invalidate(Object p0);
+ void invalidateAll();
+ void invalidateAll(Iterable extends Object> p0);
+ void put(K p0, V p1);
+ void putAll(Map extends K, ? extends V> p0);
+}
diff --git a/java/ql/test/stubs/guava-30.0/com/google/common/cache/CacheStats.java b/java/ql/test/stubs/guava-30.0/com/google/common/cache/CacheStats.java
new file mode 100644
index 00000000000..fbd5ba9656a
--- /dev/null
+++ b/java/ql/test/stubs/guava-30.0/com/google/common/cache/CacheStats.java
@@ -0,0 +1,27 @@
+// Generated automatically from com.google.common.cache.CacheStats for testing purposes
+
+package com.google.common.cache;
+
+
+public class CacheStats
+{
+ protected CacheStats() {}
+ public CacheStats minus(CacheStats p0){ return null; }
+ public CacheStats plus(CacheStats p0){ return null; }
+ public CacheStats(long p0, long p1, long p2, long p3, long p4, long p5){}
+ public String toString(){ return null; }
+ public boolean equals(Object p0){ return false; }
+ public double averageLoadPenalty(){ return 0; }
+ public double hitRate(){ return 0; }
+ public double loadExceptionRate(){ return 0; }
+ public double missRate(){ return 0; }
+ public int hashCode(){ return 0; }
+ public long evictionCount(){ return 0; }
+ public long hitCount(){ return 0; }
+ public long loadCount(){ return 0; }
+ public long loadExceptionCount(){ return 0; }
+ public long loadSuccessCount(){ return 0; }
+ public long missCount(){ return 0; }
+ public long requestCount(){ return 0; }
+ public long totalLoadTime(){ return 0; }
+}
diff --git a/java/ql/test/stubs/guava-30.0/com/google/common/cache/LoadingCache.java b/java/ql/test/stubs/guava-30.0/com/google/common/cache/LoadingCache.java
new file mode 100644
index 00000000000..3918ace190d
--- /dev/null
+++ b/java/ql/test/stubs/guava-30.0/com/google/common/cache/LoadingCache.java
@@ -0,0 +1,18 @@
+// Generated automatically from com.google.common.cache.LoadingCache for testing purposes
+
+package com.google.common.cache;
+
+import com.google.common.base.Function;
+import com.google.common.cache.Cache;
+import com.google.common.collect.ImmutableMap;
+import java.util.concurrent.ConcurrentMap;
+
+public interface LoadingCache extends Cache, Function
+{
+ ConcurrentMap asMap();
+ ImmutableMap getAll(Iterable extends K> p0);
+ V apply(K p0);
+ V get(K p0);
+ V getUnchecked(K p0);
+ void refresh(K p0);
+}
diff --git a/java/ql/test/stubs/guava-30.0/com/google/common/collect/AbstractMultimap.java b/java/ql/test/stubs/guava-30.0/com/google/common/collect/AbstractMultimap.java
index 0b9120bfd8b..e670680077c 100644
--- a/java/ql/test/stubs/guava-30.0/com/google/common/collect/AbstractMultimap.java
+++ b/java/ql/test/stubs/guava-30.0/com/google/common/collect/AbstractMultimap.java
@@ -1,90 +1,41 @@
-/*
- * Copyright (C) 2012 The Guava Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
+// Generated automatically from com.google.common.collect.AbstractMultimap for testing purposes
package com.google.common.collect;
+import com.google.common.collect.Multimap;
+import com.google.common.collect.Multiset;
import java.util.Collection;
+import java.util.Iterator;
import java.util.Map;
-import java.util.Map.Entry;
import java.util.Set;
+import java.util.Spliterator;
-abstract class AbstractMultimap implements Multimap {
- @Override
- public boolean isEmpty() {
- return false;
- }
-
- @Override
- public boolean containsValue(Object value) {
- return false;
- }
-
- @Override
- public boolean containsEntry(Object key, Object value) {
- return false;
- }
-
- @Override
- public boolean remove(Object key, Object value) {
- return false;
- }
-
- @Override
- public boolean put(K key, V value) {
- return false;
- }
-
- @Override
- public boolean putAll(K key, Iterable extends V> values) {
- return false;
- }
-
- @Override
- public boolean putAll(Multimap extends K, ? extends V> multimap) {
- return false;
- }
-
- @Override
- public Collection replaceValues(K key, Iterable extends V> values) {
- return null;
- }
-
- @Override
- public Collection> entries() {
- return null;
- }
-
- @Override
- public Set keySet() {
- return null;
- }
-
- @Override
- public Multiset keys() {
- return null;
- }
-
- @Override
- public Collection values() {
- return null;
- }
-
- @Override
- public Map> asMap() {
- return null;
- }
-
+abstract class AbstractMultimap implements Multimap
+{
+ AbstractMultimap(){}
+ Iterator valueIterator(){ return null; }
+ Spliterator> entrySpliterator(){ return null; }
+ Spliterator valueSpliterator(){ return null; }
+ abstract Collection> createEntries();
+ abstract Collection createValues();
+ abstract Iterator> entryIterator();
+ abstract Map> createAsMap();
+ abstract Multiset createKeys();
+ abstract Set createKeySet();
+ public Collection> entries(){ return null; }
+ public Collection replaceValues(K p0, Iterable extends V> p1){ return null; }
+ public Collection values(){ return null; }
+ public Map> asMap(){ return null; }
+ public Multiset keys(){ return null; }
+ public Set keySet(){ return null; }
+ public String toString(){ return null; }
+ public boolean containsEntry(Object p0, Object p1){ return false; }
+ public boolean containsValue(Object p0){ return false; }
+ public boolean equals(Object p0){ return false; }
+ public boolean isEmpty(){ return false; }
+ public boolean put(K p0, V p1){ return false; }
+ public boolean putAll(K p0, Iterable extends V> p1){ return false; }
+ public boolean putAll(Multimap extends K, ? extends V> p0){ return false; }
+ public boolean remove(Object p0, Object p1){ return false; }
+ public int hashCode(){ return 0; }
}
diff --git a/java/ql/test/stubs/guava-30.0/com/google/common/collect/BaseImmutableMultimap.java b/java/ql/test/stubs/guava-30.0/com/google/common/collect/BaseImmutableMultimap.java
new file mode 100644
index 00000000000..5fba2033c73
--- /dev/null
+++ b/java/ql/test/stubs/guava-30.0/com/google/common/collect/BaseImmutableMultimap.java
@@ -0,0 +1,10 @@
+// Generated automatically from com.google.common.collect.BaseImmutableMultimap for testing purposes
+
+package com.google.common.collect;
+
+import com.google.common.collect.AbstractMultimap;
+
+abstract class BaseImmutableMultimap extends AbstractMultimap
+{
+ BaseImmutableMultimap(){}
+}
diff --git a/java/ql/test/stubs/guava-30.0/com/google/common/collect/ImmutableCollection.java b/java/ql/test/stubs/guava-30.0/com/google/common/collect/ImmutableCollection.java
index 670016cdab6..dc3c1ebfc9c 100644
--- a/java/ql/test/stubs/guava-30.0/com/google/common/collect/ImmutableCollection.java
+++ b/java/ql/test/stubs/guava-30.0/com/google/common/collect/ImmutableCollection.java
@@ -1,50 +1,48 @@
-/*
- * Copyright (C) 2008 The Guava Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
+// Generated automatically from com.google.common.collect.ImmutableCollection for testing purposes
package com.google.common.collect;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.UnmodifiableIterator;
import java.io.Serializable;
import java.util.AbstractCollection;
import java.util.Collection;
import java.util.Iterator;
+import java.util.Spliterator;
+import java.util.function.Predicate;
-public abstract class ImmutableCollection extends AbstractCollection implements Serializable {
- ImmutableCollection() {}
-
- public ImmutableList asList() {
- return null;
- }
-
- public abstract static class Builder {
- Builder() {}
-
- public abstract Builder add(E element);
-
- public Builder add(E... elements) {
- return null;
+abstract public class ImmutableCollection extends AbstractCollection implements Serializable
+{
+ ImmutableCollection(){}
+ Object writeReplace(){ return null; }
+ Object[] internalArray(){ return null; }
+ abstract boolean isPartialView();
+ abstract static public class Builder
+ {
+ Builder(){}
+ public ImmutableCollection.Builder add(E... p0){ return null; }
+ public ImmutableCollection.Builder addAll(Iterable extends E> p0){ return null; }
+ public ImmutableCollection.Builder addAll(Iterator extends E> p0){ return null; }
+ public abstract ImmutableCollection.Builder add(E p0);
+ public abstract ImmutableCollection build();
+ static int DEFAULT_INITIAL_CAPACITY = 0;
+ static int expandedCapacity(int p0, int p1){ return 0; }
}
-
- public Builder addAll(Iterable extends E> elements) {
- return null;
- }
-
- public Builder addAll(Iterator extends E> elements) {
- return null;
- }
-
- public abstract ImmutableCollection build();
- }
+ int copyIntoArray(Object[] p0, int p1){ return 0; }
+ int internalArrayEnd(){ return 0; }
+ int internalArrayStart(){ return 0; }
+ public ImmutableList asList(){ return null; }
+ public Spliterator spliterator(){ return null; }
+ public abstract UnmodifiableIterator iterator();
+ public abstract boolean contains(Object p0);
+ public final T[] toArray(T[] p0){ return null; }
+ public final Object[] toArray(){ return null; }
+ public final boolean add(E p0){ return false; }
+ public final boolean addAll(Collection extends E> p0){ return false; }
+ public final boolean remove(Object p0){ return false; }
+ public final boolean removeAll(Collection extends Object> p0){ return false; }
+ public final boolean removeIf(Predicate super E> p0){ return false; }
+ public final boolean retainAll(Collection extends Object> p0){ return false; }
+ public final void clear(){}
+ static int SPLITERATOR_CHARACTERISTICS = 0;
}
diff --git a/java/ql/test/stubs/guava-30.0/com/google/common/collect/ImmutableList.java b/java/ql/test/stubs/guava-30.0/com/google/common/collect/ImmutableList.java
index 3e4fcf39d0a..2252c3b692d 100644
--- a/java/ql/test/stubs/guava-30.0/com/google/common/collect/ImmutableList.java
+++ b/java/ql/test/stubs/guava-30.0/com/google/common/collect/ImmutableList.java
@@ -1,101 +1,79 @@
-/*
- * Copyright (C) 2007 The Guava Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
+// Generated automatically from com.google.common.collect.ImmutableList for testing purposes
package com.google.common.collect;
-import java.util.Arrays;
+import com.google.common.collect.ImmutableCollection;
+import com.google.common.collect.UnmodifiableIterator;
+import com.google.common.collect.UnmodifiableListIterator;
import java.util.Collection;
-import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
+import java.util.RandomAccess;
+import java.util.Spliterator;
+import java.util.function.Consumer;
+import java.util.function.UnaryOperator;
+import java.util.stream.Collector;
-public abstract class ImmutableList extends ImmutableCollection
- implements List{
-
- public static ImmutableList of() {
- return null;
- }
-
- public static ImmutableList of(E element) {
- return null;
- }
-
- public static ImmutableList of(E e1, E e2) {
- return null;
- }
-
- public static ImmutableList of(E e1, E e2, E e3) {
- return null;
- }
-
- public static ImmutableList of(E e1, E e2, E e3, E e4) {
- return null;
- }
-
- public static ImmutableList of(
- E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9, E e10, E e11, E e12, E... others) {
- return null;
- }
-
- public static ImmutableList copyOf(Iterable extends E> elements) {
- return null;
- }
-
- public static ImmutableList copyOf(Collection extends E> elements) {
- return null;
- }
-
- public static ImmutableList copyOf(Iterator extends E> elements) {
- return null;
- }
-
- public static ImmutableList copyOf(E[] elements) {
- return null;
- }
-
- public static > ImmutableList sortedCopyOf(
- Iterable extends E> elements) {
- return null;
- }
-
- public static ImmutableList sortedCopyOf(
- Comparator super E> comparator, Iterable extends E> elements) {
- return null;
- }
-
- ImmutableList() {}
-
- public ImmutableList reverse() {
- return null;
- }
-
- public static Builder builder() {
- return null;
- }
-
- public static final class Builder extends ImmutableCollection.Builder {
- @Override
- public Builder add(E element) {
- return null;
+abstract public class ImmutableList extends ImmutableCollection implements List, RandomAccess
+{
+ ImmutableList(){}
+ ImmutableList subListUnchecked(int p0, int p1){ return null; }
+ Object writeReplace(){ return null; }
+ int copyIntoArray(Object[] p0, int p1){ return 0; }
+ public ImmutableList reverse(){ return null; }
+ public ImmutableList subList(int p0, int p1){ return null; }
+ public Spliterator spliterator(){ return null; }
+ public UnmodifiableIterator iterator(){ return null; }
+ public UnmodifiableListIterator listIterator(){ return null; }
+ public UnmodifiableListIterator listIterator(int p0){ return null; }
+ public boolean contains(Object p0){ return false; }
+ public boolean equals(Object p0){ return false; }
+ public final E remove(int p0){ return null; }
+ public final E set(int p0, E p1){ return null; }
+ public final ImmutableList asList(){ return null; }
+ public final boolean addAll(int p0, Collection extends E> p1){ return false; }
+ public final void add(int p0, E p1){}
+ public final void replaceAll(UnaryOperator p0){}
+ public final void sort(Comparator super E> p0){}
+ public int hashCode(){ return 0; }
+ public int indexOf(Object p0){ return 0; }
+ public int lastIndexOf(Object p0){ return 0; }
+ public static > ImmutableList sortedCopyOf(Iterable extends E> p0){ return null; }
+ public static Collector> toImmutableList(){ return null; }
+ public static ImmutableList.Builder builder(){ return null; }
+ public static ImmutableList.Builder builderWithExpectedSize(int p0){ return null; }
+ public static ImmutableList copyOf(Collection extends E> p0){ return null; }
+ public static ImmutableList copyOf(E[] p0){ return null; }
+ public static ImmutableList copyOf(Iterable extends E> p0){ return null; }
+ public static ImmutableList copyOf(Iterator extends E> p0){ return null; }
+ public static ImmutableList of(){ return null; }
+ public static ImmutableList of(E p0){ return null; }
+ public static ImmutableList of(E p0, E p1){ return null; }
+ public static ImmutableList of(E p0, E p1, E p2){ return null; }
+ public static ImmutableList of(E p0, E p1, E p2, E p3){ return null; }
+ public static ImmutableList of(E p0, E p1, E p2, E p3, E p4){ return null; }
+ public static ImmutableList of(E p0, E p1, E p2, E p3, E p4, E p5){ return null; }
+ public static ImmutableList of(E p0, E p1, E p2, E p3, E p4, E p5, E p6){ return null; }
+ public static ImmutableList of(E p0, E p1, E p2, E p3, E p4, E p5, E p6, E p7){ return null; }
+ public static ImmutableList of(E p0, E p1, E p2, E p3, E p4, E p5, E p6, E p7, E p8){ return null; }
+ public static ImmutableList of(E p0, E p1, E p2, E p3, E p4, E p5, E p6, E p7, E p8, E p9){ return null; }
+ public static ImmutableList of(E p0, E p1, E p2, E p3, E p4, E p5, E p6, E p7, E p8, E p9, E p10){ return null; }
+ public static ImmutableList of(E p0, E p1, E p2, E p3, E p4, E p5, E p6, E p7, E p8, E p9, E p10, E p11, E... p12){ return null; }
+ public static ImmutableList sortedCopyOf(Comparator super E> p0, Iterable extends E> p1){ return null; }
+ public void forEach(Consumer super E> p0){}
+ static ImmutableList asImmutableList(Object[] p0){ return null; }
+ static ImmutableList asImmutableList(Object[] p0, int p1){ return null; }
+ static public class Builder extends ImmutableCollection.Builder
+ {
+ Builder(int p0){}
+ ImmutableList.Builder combine(ImmutableList.Builder p0){ return null; }
+ Object[] contents = null;
+ public Builder(){}
+ public ImmutableList.Builder add(E p0){ return null; }
+ public ImmutableList.Builder add(E... p0){ return null; }
+ public ImmutableList.Builder addAll(Iterable extends E> p0){ return null; }
+ public ImmutableList.Builder addAll(Iterator extends E> p0){ return null; }
+ public ImmutableList build(){ return null; }
}
-
- @Override
- public ImmutableList build() {
- return null;
- }
- }
}
diff --git a/java/ql/test/stubs/guava-30.0/com/google/common/collect/ImmutableMap.java b/java/ql/test/stubs/guava-30.0/com/google/common/collect/ImmutableMap.java
index 631d25768fb..cae21e11cc5 100644
--- a/java/ql/test/stubs/guava-30.0/com/google/common/collect/ImmutableMap.java
+++ b/java/ql/test/stubs/guava-30.0/com/google/common/collect/ImmutableMap.java
@@ -1,149 +1,87 @@
-/*
- * Copyright (C) 2008 The Guava Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
+// Generated automatically from com.google.common.collect.ImmutableMap for testing purposes
package com.google.common.collect;
-import java.util.Collection;
+import com.google.common.collect.ImmutableCollection;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ImmutableSetMultimap;
+import com.google.common.collect.UnmodifiableIterator;
+import java.io.Serializable;
import java.util.Comparator;
import java.util.Map;
+import java.util.Spliterator;
+import java.util.function.BiFunction;
+import java.util.function.BinaryOperator;
+import java.util.function.Function;
+import java.util.stream.Collector;
-public abstract class ImmutableMap implements Map {
- public static ImmutableMap of() {
- return null;
- }
-
- public static ImmutableMap of(K k1, V v1) {
- return null;
- }
-
- public static ImmutableMap of(K k1, V v1, K k2, V v2) {
- return null;
- }
-
- public static ImmutableMap of(K k1, V v1, K k2, V v2, K k3, V v3) {
- return null;
- }
-
- public static ImmutableMap of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) {
- return null;
- }
-
- public static ImmutableMap of(
- K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5) {
- return null;
- }
-
- public static Builder builder() {
- return null;
- }
-
- public static Builder builderWithExpectedSize(int expectedSize) {
- return null;
- }
-
- public static class Builder {
- public Builder() {
+abstract public class ImmutableMap implements Map, Serializable
+{
+ ImmutableMap(){}
+ Object writeReplace(){ return null; }
+ Spliterator keySpliterator(){ return null; }
+ UnmodifiableIterator keyIterator(){ return null; }
+ abstract ImmutableCollection