Merge branch 'main' of github.com:github/codeql into python/port-modification-of-default-value

Files have moved around, specifically PrintNode.qll.
This commit is contained in:
Rasmus Lerchedahl Petersen
2021-09-07 10:13:51 +02:00
1069 changed files with 31677 additions and 9223 deletions

View File

@@ -1,7 +1,7 @@
import python
import semmle.python.dataflow.new.DataFlow
import TestUtilities.InlineExpectationsTest
import experimental.dataflow.TestUtil.PrintNode
private import semmle.python.dataflow.new.internal.PrintNode
abstract class FlowTest extends InlineExpectationsTest {
bindingset[this]

View File

@@ -1,55 +0,0 @@
import python
import semmle.python.dataflow.new.DataFlow
string prettyExpr(Expr e) {
not e instanceof Num and
not e instanceof StrConst and
not e instanceof Subscript and
not e instanceof Call and
not e instanceof Attribute and
result = e.toString()
or
result = e.(Num).getN()
or
result =
e.(StrConst).getPrefix() + e.(StrConst).getText() +
e.(StrConst).getPrefix().regexpReplaceAll("[a-zA-Z]+", "")
or
result = prettyExpr(e.(Subscript).getObject()) + "[" + prettyExpr(e.(Subscript).getIndex()) + "]"
or
(
if exists(e.(Call).getAnArg()) or exists(e.(Call).getANamedArg())
then result = prettyExpr(e.(Call).getFunc()) + "(..)"
else result = prettyExpr(e.(Call).getFunc()) + "()"
)
or
result = prettyExpr(e.(Attribute).getObject()) + "." + e.(Attribute).getName()
}
/**
* Gets pretty-printed version of the DataFlow::Node `node`
*/
bindingset[node]
string prettyNode(DataFlow::Node node) {
if exists(node.asExpr()) then result = prettyExpr(node.asExpr()) else result = node.toString()
}
/**
* Gets pretty-printed version of the DataFlow::Node `node`, that is suitable for use
* with `TestUtilities.InlineExpectationsTest` (that is, no spaces unless required).
*/
bindingset[node]
string prettyNodeForInlineTest(DataFlow::Node node) {
exists(node.asExpr()) and
result = prettyExpr(node.asExpr())
or
exists(Expr e | e = node.(DataFlow::PostUpdateNode).getPreUpdateNode().asExpr() |
// since PostUpdateNode both has space in the `[post <thing>]` annotation, and does
// not pretty print the pre-update node, we do custom handling of this.
result = "[post]" + prettyExpr(e)
)
or
not exists(node.asExpr()) and
not exists(Expr e | e = node.(DataFlow::PostUpdateNode).getPreUpdateNode().asExpr()) and
result = node.toString()
}

View File

@@ -1,7 +1,7 @@
import python
import semmle.python.dataflow.new.DataFlow
import TestUtilities.InlineExpectationsTest
import experimental.dataflow.TestUtil.PrintNode
private import semmle.python.dataflow.new.internal.PrintNode
/**
* A routing test is designed to test that values are routed to the

View File

@@ -1,6 +1,6 @@
import python
import semmle.python.dataflow.new.DataFlow
import experimental.dataflow.TestUtil.PrintNode
private import semmle.python.dataflow.new.internal.PrintNode
query predicate conjunctive_lookup(
DataFlow::MethodCallNode methCall, string call, string object, string methodName

View File

@@ -1,7 +1,7 @@
import python
import semmle.python.dataflow.new.TaintTracking
import semmle.python.dataflow.new.DataFlow
import experimental.dataflow.TestUtil.PrintNode
private import semmle.python.dataflow.new.internal.PrintNode
class TestTaintTrackingConfiguration extends TaintTracking::Configuration {
TestTaintTrackingConfiguration() { this = "TestTaintTrackingConfiguration" }

View File

@@ -16,6 +16,15 @@ def test_access():
tainted_list.copy(), # $ tainted
)
for ((x, y, *z), a, b) in tainted_list:
ensure_tainted(
x, # $ tainted
y, # $ tainted
z, # $ tainted
a, # $ tainted
b, # $ tainted
)
def list_clear():
tainted_string = TAINTED_STRING

View File

@@ -52,6 +52,8 @@ def test_access(x, y, z):
reversed(tainted_list), # $ tainted
iter(tainted_list), # $ tainted
next(iter(tainted_list)), # $ tainted
[i for i in tainted_list], # $ tainted
[tainted_list for _i in [1,2,3]], # $ MISSING: tainted
)
a, b, c = tainted_list[0:3]

View File

@@ -2,7 +2,7 @@ import python
import semmle.python.dataflow.new.DataFlow
import semmle.python.Concepts
import TestUtilities.InlineExpectationsTest
import experimental.dataflow.TestUtil.PrintNode
private import semmle.python.dataflow.new.internal.PrintNode
class SystemCommandExecutionTest extends InlineExpectationsTest {
SystemCommandExecutionTest() { this = "SystemCommandExecutionTest" }

View File

@@ -14,7 +14,7 @@ import semmle.python.dataflow.new.DataFlow
import semmle.python.dataflow.new.TaintTracking
import semmle.python.dataflow.new.RemoteFlowSources
import TestUtilities.InlineExpectationsTest
import experimental.dataflow.TestUtil.PrintNode
private import semmle.python.dataflow.new.internal.PrintNode
DataFlow::Node shouldBeTainted() {
exists(DataFlow::CallCfgNode call |

View File

@@ -0,0 +1,131 @@
edges
| 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_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() |
| 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:19:13: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() |
| 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() |
| 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:19:13:43 | ControlFlowNode for Attribute() |
nodes
| 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_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: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:19:13: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() |
| 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: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:19:13:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
#select
| 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_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 |

View File

@@ -0,0 +1 @@
experimental/Security/CWE-943/NoSQLInjection.ql

View File

@@ -0,0 +1,33 @@
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("/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()
return retrieved_db["Movie"].find({'name': json_search})
# if __name__ == "__main__":
# app.run(debug=True)

View File

@@ -0,0 +1,27 @@
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("/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)
# if __name__ == "__main__":
# app.run(debug=True)

View File

@@ -0,0 +1,17 @@
from flask import Flask, request
from flask_pymongo import PyMongo
import json
app = Flask(__name__)
mongo = PyMongo(app)
@app.route("/")
def home_page():
unsafe_search = request.args['search']
json_search = json.loads(unsafe_search)
return mongo.db.user.find({'name': json_search})
# if __name__ == "__main__":
# app.run(debug=True)

View File

@@ -0,0 +1,19 @@
from flask import Flask, request
from flask_pymongo import PyMongo
from mongosanitizer.sanitizer import sanitize
import json
app = Flask(__name__)
mongo = PyMongo(app)
@app.route("/")
def home_page():
unsafe_search = request.args['search']
json_search = json.loads(unsafe_search)
safe_search = sanitize(json_search)
return mongo.db.user.find({'name': safe_search})
# if __name__ == "__main__":
# app.run(debug=True)

View File

@@ -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)

View File

@@ -0,0 +1,27 @@
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': safe_search})
# if __name__ == "__main__":
# app.run(debug=True)

View File

@@ -0,0 +1,17 @@
from flask import Flask, request
from pymongo import MongoClient
import json
app = Flask(__name__)
client = MongoClient()
@app.route("/")
def home_page():
unsafe_search = request.args['search']
json_search = json.loads(unsafe_search)
return client.db.collection.find_one({'data': json_search})
# if __name__ == "__main__":
# app.run(debug=True)

View File

@@ -0,0 +1,19 @@
from flask import Flask, request
from pymongo import MongoClient
from mongosanitizer.sanitizer import sanitize
import json
app = Flask(__name__)
client = MongoClient()
@app.route("/")
def home_page():
unsafe_search = request.args['search']
json_search = json.loads(unsafe_search)
safe_search = sanitize(json_search)
return client.db.collection.find_one({'data': safe_search})
# if __name__ == "__main__":
# app.run(debug=True)

View File

@@ -55,10 +55,10 @@ async def test_taint(request: web.Request): # $ requestHandler
await request.content.readline(), # $ tainted
await request.content.readchunk(), # $ tainted
(await request.content.readchunk())[0], # $ tainted
[line async for line in request.content], # $ MISSING: tainted
[data async for data in request.content.iter_chunked(1024)], # $ MISSING: tainted
[data async for data in request.content.iter_any()], # $ MISSING: tainted
[data async for data, _ in request.content.iter_chunks()], # $ MISSING: tainted
[line async for line in request.content], # $ tainted
[data async for data in request.content.iter_chunked(1024)], # $ tainted
[data async for data in request.content.iter_any()], # $ tainted
[data async for data, _ in request.content.iter_chunks()], # $ tainted
request.content.read_nowait(), # $ tainted
# aiohttp.StreamReader

View File

@@ -11,6 +11,9 @@ def test_taint(request: HttpRequest, foo, bar, baz=None): # $requestHandler rou
# Manually inspected all fields of the HttpRequest object
# https://docs.djangoproject.com/en/3.0/ref/request-response/#httprequest-objects
import django.urls
django.urls.ResolverMatch
ensure_tainted(
request, # $ tainted
@@ -35,8 +38,8 @@ def test_taint(request: HttpRequest, foo, bar, baz=None): # $requestHandler rou
request.GET, # $ tainted
request.GET["key"], # $ tainted
request.GET.get("key"), # $ tainted
request.GET.getlist("key"), # $ MISSING: tainted
request.GET.getlist("key")[0], # $ MISSING: tainted
request.GET.getlist("key"), # $ tainted
request.GET.getlist("key")[0], # $ tainted
request.GET.pop("key"), # $ tainted
request.GET.pop("key")[0], # $ tainted
# key
@@ -45,9 +48,10 @@ def test_taint(request: HttpRequest, foo, bar, baz=None): # $requestHandler rou
request.GET.popitem()[1], # $ tainted
# values[0]
request.GET.popitem()[1][0], # $ tainted
request.GET.dict(), # $ MISSING: tainted
request.GET.dict()["key"], # $ MISSING: tainted
request.GET.urlencode(), # $ MISSING: tainted
request.GET.lists(), # $ tainted
request.GET.dict(), # $ tainted
request.GET.dict()["key"], # $ tainted
request.GET.urlencode(), # $ tainted
# django.http.QueryDict (same as above, did not duplicate tests)
request.POST, # $ tainted
@@ -60,22 +64,23 @@ def test_taint(request: HttpRequest, foo, bar, baz=None): # $requestHandler rou
# MultiValueDict[str, UploadedFile]
request.FILES, # $ tainted
request.FILES["key"], # $ tainted
request.FILES["key"].content_type, # $ MISSING: tainted
request.FILES["key"].content_type_extra, # $ MISSING: tainted
request.FILES["key"].content_type_extra["key"], # $ MISSING: tainted
request.FILES["key"].charset, # $ MISSING: tainted
request.FILES["key"].name, # $ MISSING: tainted
request.FILES["key"].file, # $ MISSING: tainted
request.FILES["key"].file.read(), # $ MISSING: tainted
request.FILES["key"].content_type, # $ tainted
request.FILES["key"].content_type_extra, # $ tainted
request.FILES["key"].content_type_extra["key"], # $ tainted
request.FILES["key"].charset, # $ tainted
request.FILES["key"].name, # $ tainted
request.FILES["key"].file, # $ tainted
request.FILES["key"].file.read(), # $ tainted
request.FILES.get("key"), # $ tainted
request.FILES.get("key").name, # $ MISSING: tainted
request.FILES.getlist("key"), # $ MISSING: tainted
request.FILES.getlist("key")[0], # $ MISSING: tainted
request.FILES.getlist("key")[0].name, # $ MISSING: tainted
request.FILES.dict(), # $ MISSING: tainted
request.FILES.dict()["key"], # $ MISSING: tainted
request.FILES.dict()["key"].name, # $ MISSING: tainted
request.FILES.get("key").name, # $ tainted
request.FILES.getlist("key"), # $ tainted
request.FILES.getlist("key")[0], # $ tainted
request.FILES.getlist("key")[0].name, # $ tainted
request.FILES.dict(), # $ tainted
request.FILES.dict()["key"], # $ tainted
request.FILES.dict()["key"].name, # $ tainted
request.FILES.dict().get("key").name, # $ tainted
# Dict[str, Any]
request.META, # $ tainted
@@ -89,21 +94,21 @@ def test_taint(request: HttpRequest, foo, bar, baz=None): # $requestHandler rou
# django.urls.ResolverMatch
request.resolver_match, # $ tainted
request.resolver_match.args, # $ MISSING: tainted
request.resolver_match.args[0], # $ MISSING: tainted
request.resolver_match.kwargs, # $ MISSING: tainted
request.resolver_match.kwargs["key"], # $ MISSING: tainted
request.resolver_match.args, # $ tainted
request.resolver_match.args[0], # $ tainted
request.resolver_match.kwargs, # $ tainted
request.resolver_match.kwargs["key"], # $ tainted
request.get_full_path(), # $ MISSING: tainted
request.get_full_path_info(), # $ MISSING: tainted
request.get_full_path(), # $ tainted
request.get_full_path_info(), # $ tainted
# build_absolute_uri handled below
# get_signed_cookie handled below
request.read(), # $ MISSING: tainted
request.readline(), # $ MISSING: tainted
request.readlines(), # $ MISSING: tainted
request.readlines()[0], # $ MISSING: tainted
[line for line in request], # $ MISSING: tainted
request.read(), # $ tainted
request.readline(), # $ tainted
request.readlines(), # $ tainted
request.readlines()[0], # $ tainted
[line for line in request], # $ tainted
)
# django.urls.ResolverMatch also supports iterable unpacking
@@ -129,9 +134,9 @@ def test_taint(request: HttpRequest, foo, bar, baz=None): # $requestHandler rou
# build_absolute_uri
####################################
ensure_tainted(
request.build_absolute_uri(), # $ MISSING: tainted
request.build_absolute_uri(request.GET["key"]), # $ MISSING: tainted
request.build_absolute_uri(location=request.GET["key"]), # $ MISSING: tainted
request.build_absolute_uri(), # $ tainted
request.build_absolute_uri(request.GET["key"]), # $ tainted
request.build_absolute_uri(location=request.GET["key"]), # $ tainted
)
ensure_not_tainted(
request.build_absolute_uri("/hardcoded/"),

View File

@@ -0,0 +1,6 @@
from flask import Flask, request
app = Flask(__name__)
@app.route("/save-uploaded-file") # $routeSetup="/save-uploaded-file"
def test_taint(): # $requestHandler
request.files['key'].save("path") # $ getAPathArgument="path"

View File

@@ -44,7 +44,16 @@ def test_taint(name = "World!", number="0", foo="foo"): # $requestHandler route
# werkzeug.datastructures.Authorization (a dict, with some properties)
request.authorization, # $ tainted
request.authorization['username'], # $ tainted
request.authorization.username, # $ MISSING: tainted
request.authorization.username, # $ tainted
request.authorization.password, # $ tainted
request.authorization.realm, # $ tainted
request.authorization.nonce, # $ tainted
request.authorization.uri, # $ tainted
request.authorization.nc, # $ tainted
request.authorization.cnonce, # $ tainted
request.authorization.response, # $ tainted
request.authorization.opaque, # $ tainted
request.authorization.qop, # $ tainted
# werkzeug.datastructures.RequestCacheControl
request.cache_control, # $ tainted
@@ -68,14 +77,16 @@ def test_taint(name = "World!", number="0", foo="foo"): # $requestHandler route
# a werkzeug.datastructures.MultiDict, mapping [str, werkzeug.datastructures.FileStorage]
request.files, # $ tainted
request.files['key'], # $ tainted
request.files['key'].filename, # $ MISSING: tainted
request.files['key'].stream, # $ MISSING: tainted
request.files['key'].filename, # $ tainted
request.files['key'].stream, # $ tainted
request.files['key'].read(), # $ tainted
request.files['key'].stream.read(), # $ tainted
request.files.get('key'), # $ tainted
request.files.get('key').filename, # $ MISSING: tainted
request.files.get('key').stream, # $ MISSING: tainted
request.files.get('key').filename, # $ tainted
request.files.get('key').stream, # $ tainted
request.files.getlist('key'), # $ tainted
request.files.getlist('key')[0].filename, # $ MISSING: tainted
request.files.getlist('key')[0].stream, # $ MISSING: tainted
request.files.getlist('key')[0].filename, # $ tainted
request.files.getlist('key')[0].stream, # $ tainted
# By default werkzeug.datastructures.ImmutableMultiDict -- although can be changed :\
request.form, # $ tainted
@@ -94,11 +105,15 @@ def test_taint(name = "World!", number="0", foo="foo"): # $requestHandler route
request.headers, # $ tainted
request.headers['key'], # $ tainted
request.headers.get('key'), # $ tainted
request.headers.get_all('key'), # $ MISSING: tainted
request.headers.getlist('key'), # $ MISSING: tainted
request.headers.get_all('key'), # $ tainted
request.headers.getlist('key'), # $ tainted
# popitem returns `(key, value)`
request.headers.popitem(), # $ tainted
request.headers.popitem()[0], # $ tainted
request.headers.popitem()[1], # $ tainted
# two ways to get (k, v) lists
list(request.headers), # $ tainted
request.headers.to_wsgi_list(), # $ MISSING: tainted
request.headers.to_wsgi_list(), # $ tainted
request.json, # $ tainted
request.json['foo'], # $ tainted

View File

@@ -58,17 +58,17 @@ class MyHandler(BaseHTTPRequestHandler):
self.headers, # $ tainted
self.headers['Foo'], # $ tainted
self.headers.get('Foo'), # $ tainted
self.headers.get_all('Foo'), # $ MISSING: tainted
self.headers.keys(), # $ MISSING: tainted
self.headers.get_all('Foo'), # $ tainted
self.headers.keys(), # $ tainted
self.headers.values(), # $ tainted
self.headers.items(), # $ tainted
self.headers.as_bytes(), # $ MISSING: tainted
self.headers.as_string(), # $ MISSING: tainted
self.headers.as_bytes(), # $ tainted
self.headers.as_string(), # $ tainted
str(self.headers), # $ tainted
bytes(self.headers), # $ tainted
self.rfile, # $ tainted
self.rfile.read(), # $ MISSING: tainted
self.rfile.read(), # $ tainted
)
form = cgi.FieldStorage(

View File

@@ -61,15 +61,16 @@ class TaintTest(tornado.web.RequestHandler):
# dict-like, see https://www.tornadoweb.org/en/stable/httputil.html#tornado.httputil.HTTPHeaders
request.headers, # $ tainted
request.headers["header-name"], # $ tainted
request.headers.get_list("header-name"), # $ MISSING: tainted
request.headers.get_all(), # $ MISSING: tainted
[(k, v) for (k, v) in request.headers.get_all()], # $ MISSING: tainted
request.headers.get_list("header-name"), # $ tainted
request.headers.get_all(), # $ tainted
[(k, v) for (k, v) in request.headers.get_all()], # $ tainted
# Dict[str, http.cookies.Morsel]
request.cookies, # $ tainted
request.cookies["cookie-name"], # $ tainted
request.cookies["cookie-name"].key, # $ MISSING: tainted
request.cookies["cookie-name"].value, # $ MISSING: tainted
request.cookies["cookie-name"].key, # $ tainted
request.cookies["cookie-name"].value, # $ tainted
request.cookies["cookie-name"].coded_value, # $ tainted
)

View File

@@ -0,0 +1,4 @@
---
dependencies: {}
compiled: false
lockVersion: 1.0.0

View File

@@ -1,5 +1,7 @@
name: codeql-python-tests
version: 0.0.0
libraryPathDependencies: codeql-python
name: codeql/python-tests
version: 0.0.2
dependencies:
codeql/python-all: "*"
codeql/python-queries: "*"
extractor: python
tests: .

View File

@@ -0,0 +1,7 @@
import ssl
# secure versions
ssl.wrap_socket(ssl_version=ssl.PROTOCOL_TLSv1_2)
# possibly insecure default
ssl.wrap_socket()

View File

@@ -1,7 +1,37 @@
import ssl
from OpenSSL import SSL
from ssl import SSLContext
# secure versions
# insecure versions specified
ssl.wrap_socket(ssl_version=ssl.PROTOCOL_SSLv2)
ssl.wrap_socket(ssl_version=ssl.PROTOCOL_SSLv3)
ssl.wrap_socket(ssl_version=ssl.PROTOCOL_TLSv1)
SSLContext(protocol=ssl.PROTOCOL_SSLv2)
SSLContext(protocol=ssl.PROTOCOL_SSLv3)
SSLContext(protocol=ssl.PROTOCOL_TLSv1)
SSL.Context(SSL.SSLv2_METHOD)
SSL.Context(SSL.SSLv3_METHOD)
SSL.Context(SSL.TLSv1_METHOD)
METHOD = SSL.SSLv2_METHOD
SSL.Context(METHOD)
# importing the protocol constant directly
from ssl import PROTOCOL_SSLv2
ssl.wrap_socket(ssl_version=PROTOCOL_SSLv2)
SSLContext(protocol=PROTOCOL_SSLv2)
# secure versions specified
ssl.wrap_socket(ssl_version=ssl.PROTOCOL_TLSv1_2)
SSLContext(protocol=ssl.PROTOCOL_TLSv1_2)
SSL.Context(SSL.TLSv1_2_METHOD)
# possibly insecure default
ssl.wrap_socket()
# insecure versions allowed by specified range
SSLContext(protocol=ssl.PROTOCOL_SSLv23)
SSLContext(protocol=ssl.PROTOCOL_TLS)
SSLContext(protocol=ssl.PROTOCOL_TLS_CLIENT)
SSLContext(protocol=ssl.PROTOCOL_TLS_SERVER)
SSL.Context(SSL.SSLv23_METHOD)

View File

@@ -1,37 +0,0 @@
import ssl
from OpenSSL import SSL
from ssl import SSLContext
# insecure versions specified
ssl.wrap_socket(ssl_version=ssl.PROTOCOL_SSLv2)
ssl.wrap_socket(ssl_version=ssl.PROTOCOL_SSLv3)
ssl.wrap_socket(ssl_version=ssl.PROTOCOL_TLSv1)
SSLContext(protocol=ssl.PROTOCOL_SSLv2)
SSLContext(protocol=ssl.PROTOCOL_SSLv3)
SSLContext(protocol=ssl.PROTOCOL_TLSv1)
SSL.Context(SSL.SSLv2_METHOD)
SSL.Context(SSL.SSLv3_METHOD)
SSL.Context(SSL.TLSv1_METHOD)
METHOD = SSL.SSLv2_METHOD
SSL.Context(METHOD)
# importing the protocol constant directly
from ssl import PROTOCOL_SSLv2
ssl.wrap_socket(ssl_version=PROTOCOL_SSLv2)
SSLContext(protocol=PROTOCOL_SSLv2)
# secure versions specified
ssl.wrap_socket(ssl_version=ssl.PROTOCOL_TLSv1_2)
SSLContext(protocol=ssl.PROTOCOL_TLSv1_2)
SSL.Context(SSL.TLSv1_2_METHOD)
# insecure versions allowed by specified range
SSLContext(protocol=ssl.PROTOCOL_SSLv23)
SSLContext(protocol=ssl.PROTOCOL_TLS)
SSLContext(protocol=ssl.PROTOCOL_TLS_CLIENT)
SSLContext(protocol=ssl.PROTOCOL_TLS_SERVER)
SSL.Context(SSL.SSLv23_METHOD)