mirror of
https://github.com/github/codeql.git
synced 2026-04-30 11:15:13 +02:00
merge in main
This commit is contained in:
@@ -181,7 +181,7 @@ private string expectationCommentPattern() { result = "\\s*\\$((?:[^/]|/[^/])*)(
|
||||
/**
|
||||
* The possible columns in an expectation comment. The `TDefaultColumn` branch represents the first
|
||||
* column in a comment. This column is not precedeeded by a name. `TNamedColumn(name)` represents a
|
||||
* column containing expected results preceeded by the string `name:`.
|
||||
* column containing expected results preceded by the string `name:`.
|
||||
*/
|
||||
private newtype TColumn =
|
||||
TDefaultColumn() or
|
||||
@@ -239,12 +239,24 @@ private string getColumnString(TColumn column) {
|
||||
|
||||
/**
|
||||
* RegEx pattern to match a single expected result, not including the leading `$`. It consists of one or
|
||||
* more comma-separated tags containing only letters, digits, `-` and `_` (note that the first character
|
||||
* must not be a digit), optionally followed by `=` and the expected value.
|
||||
* more comma-separated tags optionally followed by `=` and the expected value.
|
||||
*
|
||||
* Tags must be only letters, digits, `-` and `_` (note that the first character
|
||||
* must not be a digit), but can contain anything enclosed in a single set of
|
||||
* square brackets.
|
||||
*
|
||||
* Examples:
|
||||
* - `tag`
|
||||
* - `tag=value`
|
||||
* - `tag,tag2=value`
|
||||
* - `tag[foo bar]=value`
|
||||
*
|
||||
* Not allowed:
|
||||
* - `tag[[[foo bar]`
|
||||
*/
|
||||
private string expectationPattern() {
|
||||
exists(string tag, string tags, string value |
|
||||
tag = "[A-Za-z-_][A-Za-z-_0-9]*" and
|
||||
tag = "[A-Za-z-_](?:[A-Za-z-_0-9]|\\[[^\\]\\]]*\\])*" and
|
||||
tags = "((?:" + tag + ")(?:\\s*,\\s*" + tag + ")*)" and
|
||||
// In Python, we allow both `"` and `'` for strings, as well as the prefixes `bru`.
|
||||
// For example, `b"foo"`.
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
| test.py:1:1:1:21 | ControlFlowNode for FunctionExpr | test.py:1:5:1:17 | GSSA Variable obfuscated_id |
|
||||
| test.py:1:1:1:21 | ControlFlowNode for FunctionExpr | test.py:1:5:1:17 | GSSA Variable obfuscated_id |
|
||||
| test.py:1:1:1:21 | ControlFlowNode for FunctionExpr | test.py:7:5:7:17 | ControlFlowNode for obfuscated_id |
|
||||
| test.py:1:1:1:21 | ControlFlowNode for FunctionExpr | test.py:7:5:7:17 | ControlFlowNode for obfuscated_id |
|
||||
| test.py:1:5:1:17 | GSSA Variable obfuscated_id | test.py:7:5:7:17 | ControlFlowNode for obfuscated_id |
|
||||
| test.py:1:5:1:17 | GSSA Variable obfuscated_id | test.py:7:5:7:17 | ControlFlowNode for obfuscated_id |
|
||||
| test.py:1:19:1:19 | ControlFlowNode for x | test.py:1:19:1:19 | SSA variable x |
|
||||
| test.py:1:19:1:19 | ControlFlowNode for x | test.py:1:19:1:19 | SSA variable x |
|
||||
@@ -97,7 +95,6 @@
|
||||
| test.py:6:5:6:6 | ControlFlowNode for IntegerLiteral | test.py:7:19:7:19 | ControlFlowNode for a |
|
||||
| test.py:6:5:6:6 | ControlFlowNode for IntegerLiteral | test.py:7:19:7:19 | ControlFlowNode for a |
|
||||
| test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | test.py:7:1:7:1 | GSSA Variable b |
|
||||
| test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | test.py:7:1:7:1 | GSSA Variable b |
|
||||
| test.py:7:19:7:19 | ControlFlowNode for a | test.py:1:19:1:19 | ControlFlowNode for x |
|
||||
| test.py:7:19:7:19 | ControlFlowNode for a | test.py:1:19:1:19 | ControlFlowNode for x |
|
||||
| test.py:7:19:7:19 | ControlFlowNode for a | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() |
|
||||
|
||||
@@ -2,7 +2,5 @@ import experimental.meta.InlineTaintTest
|
||||
import semmle.python.dataflow.new.BarrierGuards
|
||||
|
||||
class CustomSanitizerOverrides extends TestTaintTrackingConfiguration {
|
||||
override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) {
|
||||
guard instanceof StringConstCompare
|
||||
}
|
||||
override predicate isSanitizer(DataFlow::Node node) { node instanceof StringConstCompareBarrier }
|
||||
}
|
||||
|
||||
@@ -4,20 +4,14 @@ failures
|
||||
isSanitizer
|
||||
| TestTaintTrackingConfiguration | test.py:21:39:21:39 | ControlFlowNode for s |
|
||||
| TestTaintTrackingConfiguration | test.py:34:39:34:39 | ControlFlowNode for s |
|
||||
| TestTaintTrackingConfiguration | test.py:52:28:52:28 | ControlFlowNode for s |
|
||||
| TestTaintTrackingConfiguration | test.py:66:10:66:29 | ControlFlowNode for emulated_escaping() |
|
||||
isSanitizerGuard
|
||||
| TestTaintTrackingConfiguration | test.py:51:8:51:26 | ControlFlowNode for emulated_is_safe() |
|
||||
| TestTaintTrackingConfiguration | test_logical.py:29:8:29:17 | ControlFlowNode for is_safe() |
|
||||
| TestTaintTrackingConfiguration | test_logical.py:44:8:44:17 | ControlFlowNode for is_safe() |
|
||||
| TestTaintTrackingConfiguration | test_logical.py:49:8:49:17 | ControlFlowNode for is_safe() |
|
||||
| TestTaintTrackingConfiguration | test_logical.py:59:8:59:17 | ControlFlowNode for is_safe() |
|
||||
| TestTaintTrackingConfiguration | test_logical.py:67:12:67:21 | ControlFlowNode for is_safe() |
|
||||
| TestTaintTrackingConfiguration | test_logical.py:87:8:87:17 | ControlFlowNode for is_safe() |
|
||||
| TestTaintTrackingConfiguration | test_logical.py:95:12:95:21 | ControlFlowNode for is_safe() |
|
||||
| TestTaintTrackingConfiguration | test_logical.py:119:8:119:17 | ControlFlowNode for is_safe() |
|
||||
| TestTaintTrackingConfiguration | test_logical.py:142:12:142:21 | ControlFlowNode for is_safe() |
|
||||
| TestTaintTrackingConfiguration | test_logical.py:147:16:147:25 | ControlFlowNode for is_safe() |
|
||||
| TestTaintTrackingConfiguration | test_logical.py:152:20:152:29 | ControlFlowNode for is_safe() |
|
||||
| TestTaintTrackingConfiguration | test_reference.py:30:8:30:17 | ControlFlowNode for is_safe() |
|
||||
| TestTaintTrackingConfiguration | test_reference.py:40:8:40:25 | ControlFlowNode for is_safe() |
|
||||
| TestTaintTrackingConfiguration | test_reference.py:55:8:55:21 | ControlFlowNode for is_safe() |
|
||||
| TestTaintTrackingConfiguration | test_logical.py:30:28:30:28 | ControlFlowNode for s |
|
||||
| TestTaintTrackingConfiguration | test_logical.py:45:28:45:28 | ControlFlowNode for s |
|
||||
| TestTaintTrackingConfiguration | test_logical.py:50:28:50:28 | ControlFlowNode for s |
|
||||
| TestTaintTrackingConfiguration | test_logical.py:89:28:89:28 | ControlFlowNode for s |
|
||||
| TestTaintTrackingConfiguration | test_logical.py:100:28:100:28 | ControlFlowNode for s |
|
||||
| TestTaintTrackingConfiguration | test_logical.py:145:28:145:28 | ControlFlowNode for s |
|
||||
| TestTaintTrackingConfiguration | test_logical.py:148:28:148:28 | ControlFlowNode for s |
|
||||
| TestTaintTrackingConfiguration | test_logical.py:155:28:155:28 | ControlFlowNode for s |
|
||||
| TestTaintTrackingConfiguration | test_reference.py:31:28:31:28 | ControlFlowNode for s |
|
||||
|
||||
@@ -1,14 +1,9 @@
|
||||
import experimental.meta.InlineTaintTest
|
||||
|
||||
class IsSafeCheck extends DataFlow::BarrierGuard {
|
||||
IsSafeCheck() {
|
||||
this.(CallNode).getNode().getFunc().(Name).getId() in ["is_safe", "emulated_is_safe"]
|
||||
}
|
||||
|
||||
override predicate checks(ControlFlowNode node, boolean branch) {
|
||||
node = this.(CallNode).getAnArg() and
|
||||
branch = true
|
||||
}
|
||||
predicate isSafeCheck(DataFlow::GuardNode g, ControlFlowNode node, boolean branch) {
|
||||
g.(CallNode).getNode().getFunc().(Name).getId() in ["is_safe", "emulated_is_safe"] and
|
||||
node = g.(CallNode).getAnArg() and
|
||||
branch = true
|
||||
}
|
||||
|
||||
class CustomSanitizerOverrides extends TestTaintTrackingConfiguration {
|
||||
@@ -19,17 +14,12 @@ class CustomSanitizerOverrides extends TestTaintTrackingConfiguration {
|
||||
)
|
||||
or
|
||||
node.asExpr().(Call).getFunc().(Name).getId() = "emulated_escaping"
|
||||
or
|
||||
node = DataFlow::BarrierGuard<isSafeCheck/3>::getABarrierNode()
|
||||
}
|
||||
|
||||
override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { guard instanceof IsSafeCheck }
|
||||
}
|
||||
|
||||
query predicate isSanitizer(TestTaintTrackingConfiguration conf, DataFlow::Node node) {
|
||||
exists(node.getLocation().getFile().getRelativePath()) and
|
||||
conf.isSanitizer(node)
|
||||
}
|
||||
|
||||
query predicate isSanitizerGuard(TestTaintTrackingConfiguration conf, DataFlow::BarrierGuard guard) {
|
||||
exists(guard.getLocation().getFile().getRelativePath()) and
|
||||
conf.isSanitizerGuard(guard)
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
* s = SOURCE
|
||||
* SINK(s)
|
||||
* ```
|
||||
* `SOURCE` will be a source and the second occurance of `s` will be a sink.
|
||||
* `SOURCE` will be a source and the second occurrence of `s` will be a sink.
|
||||
*
|
||||
* In order to test literals, alternative sources are defined for each type:
|
||||
*
|
||||
|
||||
@@ -440,22 +440,15 @@ class PathNormalizationTest extends InlineExpectationsTest {
|
||||
class SafeAccessCheckTest extends InlineExpectationsTest {
|
||||
SafeAccessCheckTest() { this = "SafeAccessCheckTest" }
|
||||
|
||||
override string getARelevantTag() { result in ["checks", "branch"] }
|
||||
override string getARelevantTag() { result = "SafeAccessCheck" }
|
||||
|
||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
exists(location.getFile().getRelativePath()) and
|
||||
exists(Path::SafeAccessCheck c, DataFlow::Node checks, boolean branch |
|
||||
c.checks(checks.asCfgNode(), branch) and
|
||||
exists(Path::SafeAccessCheck c |
|
||||
location = c.getLocation() and
|
||||
(
|
||||
element = checks.toString() and
|
||||
value = prettyNodeForInlineTest(checks) and
|
||||
tag = "checks"
|
||||
or
|
||||
element = branch.toString() and
|
||||
value = branch.toString() and
|
||||
tag = "branch"
|
||||
)
|
||||
element = c.toString() and
|
||||
value = prettyNodeForInlineTest(c) and
|
||||
tag = "SafeAccessCheck"
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -487,7 +480,8 @@ class CryptographicOperationTest extends InlineExpectationsTest {
|
||||
|
||||
override string getARelevantTag() {
|
||||
result in [
|
||||
"CryptographicOperation", "CryptographicOperationInput", "CryptographicOperationAlgorithm"
|
||||
"CryptographicOperation", "CryptographicOperationInput", "CryptographicOperationAlgorithm",
|
||||
"CryptographicOperationBlockMode"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -507,6 +501,10 @@ class CryptographicOperationTest extends InlineExpectationsTest {
|
||||
element = cryptoOperation.toString() and
|
||||
value = cryptoOperation.getAlgorithm().getName() and
|
||||
tag = "CryptographicOperationAlgorithm"
|
||||
or
|
||||
element = cryptoOperation.toString() and
|
||||
value = cryptoOperation.getBlockMode() and
|
||||
tag = "CryptographicOperationBlockMode"
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
48
python/ql/test/experimental/meta/MaDTest.qll
Normal file
48
python/ql/test/experimental/meta/MaDTest.qll
Normal file
@@ -0,0 +1,48 @@
|
||||
import python
|
||||
private import semmle.python.dataflow.new.DataFlow
|
||||
private import semmle.python.dataflow.new.internal.PrintNode
|
||||
private import semmle.python.frameworks.data.ModelsAsData
|
||||
// need to import Frameworks to get the actual modeling imported
|
||||
private import semmle.python.Frameworks
|
||||
// this import needs to be public to get the query predicates propagated to the actual test files
|
||||
import TestUtilities.InlineExpectationsTest
|
||||
|
||||
class MadSinkTest extends InlineExpectationsTest {
|
||||
MadSinkTest() { this = "MadSinkTest" }
|
||||
|
||||
override string getARelevantTag() {
|
||||
exists(string kind | exists(ModelOutput::getASinkNode(kind)) |
|
||||
result = "mad-sink[" + kind + "]"
|
||||
)
|
||||
}
|
||||
|
||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
exists(location.getFile().getRelativePath()) and
|
||||
exists(DataFlow::Node sink, string kind |
|
||||
sink = ModelOutput::getASinkNode(kind).getARhs() and
|
||||
location = sink.getLocation() and
|
||||
element = sink.toString() and
|
||||
value = prettyNodeForInlineTest(sink) and
|
||||
tag = "mad-sink[" + kind + "]"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class MadSourceTest extends InlineExpectationsTest {
|
||||
MadSourceTest() { this = "MadSourceTest" }
|
||||
|
||||
override string getARelevantTag() {
|
||||
exists(string kind | exists(ModelOutput::getASourceNode(kind)) | result = "mad-source__" + kind)
|
||||
}
|
||||
|
||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
exists(location.getFile().getRelativePath()) and
|
||||
exists(DataFlow::Node source, string kind |
|
||||
source = ModelOutput::getASourceNode(kind).getAnImmediateUse() and
|
||||
location = source.getLocation() and
|
||||
element = source.toString() and
|
||||
value = prettyNodeForInlineTest(source) and
|
||||
tag = "mad-source__" + kind
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
import experimental.dataflow.tainttracking.TestTaintLib
|
||||
|
||||
query predicate sanitizerGuardControls(
|
||||
TestTaintTrackingConfiguration conf, DataFlow::BarrierGuard guard, ControlFlowNode node,
|
||||
boolean branch
|
||||
) {
|
||||
exists(guard.getLocation().getFile().getRelativePath()) and
|
||||
conf.isSanitizerGuard(guard) and
|
||||
guard.controlsBlock(node.getBasicBlock(), branch)
|
||||
}
|
||||
|
||||
query predicate sanitizerGuardedNode(
|
||||
TestTaintTrackingConfiguration conf, DataFlow::BarrierGuard guard, DataFlow::ExprNode node
|
||||
) {
|
||||
exists(guard.getLocation().getFile().getRelativePath()) and
|
||||
conf.isSanitizerGuard(guard) and
|
||||
node = guard.getAGuardedNode()
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
edges
|
||||
| flask_mail.py:13:22:13:28 | ControlFlowNode for request | flask_mail.py:13:22:13:33 | ControlFlowNode for Attribute |
|
||||
| flask_mail.py:13:22:13:28 | ControlFlowNode for request | flask_mail.py:18:14:18:25 | ControlFlowNode for Attribute |
|
||||
| flask_mail.py:13:22:13:33 | ControlFlowNode for Attribute | flask_mail.py:13:22:13:41 | ControlFlowNode for Subscript |
|
||||
| flask_mail.py:18:14:18:20 | ControlFlowNode for request | flask_mail.py:18:14:18:25 | ControlFlowNode for Attribute |
|
||||
| flask_mail.py:18:14:18:25 | ControlFlowNode for Attribute | flask_mail.py:18:14:18:33 | ControlFlowNode for Subscript |
|
||||
| flask_mail.py:31:24:31:30 | ControlFlowNode for request | flask_mail.py:31:24:31:35 | ControlFlowNode for Attribute |
|
||||
| flask_mail.py:31:24:31:35 | ControlFlowNode for Attribute | flask_mail.py:31:24:31:43 | ControlFlowNode for Subscript |
|
||||
| sendgrid_mail.py:14:22:14:28 | ControlFlowNode for request | sendgrid_mail.py:14:22:14:33 | ControlFlowNode for Attribute |
|
||||
| sendgrid_mail.py:14:22:14:33 | ControlFlowNode for Attribute | sendgrid_mail.py:14:22:14:49 | ControlFlowNode for Subscript |
|
||||
| sendgrid_mail.py:26:34:26:40 | ControlFlowNode for request | sendgrid_mail.py:26:34:26:45 | ControlFlowNode for Attribute |
|
||||
| sendgrid_mail.py:26:34:26:45 | ControlFlowNode for Attribute | sendgrid_mail.py:26:34:26:61 | ControlFlowNode for Subscript |
|
||||
| sendgrid_mail.py:26:34:26:61 | ControlFlowNode for Subscript | sendgrid_mail.py:26:22:26:62 | ControlFlowNode for HtmlContent() |
|
||||
| sendgrid_mail.py:37:41:37:47 | ControlFlowNode for request | sendgrid_mail.py:37:41:37:52 | ControlFlowNode for Attribute |
|
||||
| sendgrid_mail.py:37:41:37:52 | ControlFlowNode for Attribute | sendgrid_mail.py:37:41:37:68 | ControlFlowNode for Subscript |
|
||||
| sendgrid_via_mail_send_post_request_body_bad.py:16:51:16:57 | ControlFlowNode for request | sendgrid_via_mail_send_post_request_body_bad.py:16:51:16:62 | ControlFlowNode for Attribute |
|
||||
| sendgrid_via_mail_send_post_request_body_bad.py:16:51:16:57 | ControlFlowNode for request | sendgrid_via_mail_send_post_request_body_bad.py:27:50:27:61 | ControlFlowNode for Attribute |
|
||||
| sendgrid_via_mail_send_post_request_body_bad.py:16:51:16:57 | ControlFlowNode for request | sendgrid_via_mail_send_post_request_body_bad.py:41:50:41:61 | ControlFlowNode for Attribute |
|
||||
| sendgrid_via_mail_send_post_request_body_bad.py:16:51:16:62 | ControlFlowNode for Attribute | sendgrid_via_mail_send_post_request_body_bad.py:16:51:16:78 | ControlFlowNode for Subscript |
|
||||
| sendgrid_via_mail_send_post_request_body_bad.py:16:51:16:78 | ControlFlowNode for Subscript | sendgrid_via_mail_send_post_request_body_bad.py:16:26:16:79 | ControlFlowNode for Attribute() |
|
||||
| sendgrid_via_mail_send_post_request_body_bad.py:27:50:27:56 | ControlFlowNode for request | sendgrid_via_mail_send_post_request_body_bad.py:27:50:27:61 | ControlFlowNode for Attribute |
|
||||
| sendgrid_via_mail_send_post_request_body_bad.py:27:50:27:56 | ControlFlowNode for request | sendgrid_via_mail_send_post_request_body_bad.py:41:50:41:61 | ControlFlowNode for Attribute |
|
||||
| sendgrid_via_mail_send_post_request_body_bad.py:27:50:27:61 | ControlFlowNode for Attribute | sendgrid_via_mail_send_post_request_body_bad.py:27:50:27:76 | ControlFlowNode for Subscript |
|
||||
| sendgrid_via_mail_send_post_request_body_bad.py:27:50:27:76 | ControlFlowNode for Subscript | sendgrid_via_mail_send_post_request_body_bad.py:27:25:27:77 | ControlFlowNode for Attribute() |
|
||||
| sendgrid_via_mail_send_post_request_body_bad.py:41:50:41:56 | ControlFlowNode for request | sendgrid_via_mail_send_post_request_body_bad.py:41:50:41:61 | ControlFlowNode for Attribute |
|
||||
| sendgrid_via_mail_send_post_request_body_bad.py:41:50:41:61 | ControlFlowNode for Attribute | sendgrid_via_mail_send_post_request_body_bad.py:41:50:41:78 | ControlFlowNode for Subscript |
|
||||
| sendgrid_via_mail_send_post_request_body_bad.py:41:50:41:78 | ControlFlowNode for Subscript | sendgrid_via_mail_send_post_request_body_bad.py:41:25:41:79 | ControlFlowNode for Attribute() |
|
||||
| smtplib_bad_subparts.py:17:12:17:18 | ControlFlowNode for request | smtplib_bad_subparts.py:17:12:17:23 | ControlFlowNode for Attribute |
|
||||
| smtplib_bad_subparts.py:17:12:17:23 | ControlFlowNode for Attribute | smtplib_bad_subparts.py:17:12:17:33 | ControlFlowNode for Subscript |
|
||||
| smtplib_bad_subparts.py:17:12:17:33 | ControlFlowNode for Subscript | smtplib_bad_subparts.py:24:22:24:25 | ControlFlowNode for html |
|
||||
| smtplib_bad_via_attach.py:20:12:20:18 | ControlFlowNode for request | smtplib_bad_via_attach.py:20:12:20:23 | ControlFlowNode for Attribute |
|
||||
| smtplib_bad_via_attach.py:20:12:20:23 | ControlFlowNode for Attribute | smtplib_bad_via_attach.py:20:12:20:31 | ControlFlowNode for Subscript |
|
||||
| smtplib_bad_via_attach.py:20:12:20:31 | ControlFlowNode for Subscript | smtplib_bad_via_attach.py:27:22:27:25 | ControlFlowNode for html |
|
||||
nodes
|
||||
| django_mail.py:14:48:14:82 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
|
||||
| django_mail.py:23:30:23:64 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
|
||||
| django_mail.py:25:32:25:66 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
|
||||
| flask_mail.py:13:22:13:28 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| flask_mail.py:13:22:13:33 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| flask_mail.py:13:22:13:41 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| flask_mail.py:18:14:18:20 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| flask_mail.py:18:14:18:25 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| flask_mail.py:18:14:18:33 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| flask_mail.py:31:24:31:30 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| flask_mail.py:31:24:31:35 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| flask_mail.py:31:24:31:43 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| sendgrid_mail.py:14:22:14:28 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| sendgrid_mail.py:14:22:14:33 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| sendgrid_mail.py:14:22:14:49 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| sendgrid_mail.py:26:22:26:62 | ControlFlowNode for HtmlContent() | semmle.label | ControlFlowNode for HtmlContent() |
|
||||
| sendgrid_mail.py:26:34:26:40 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| sendgrid_mail.py:26:34:26:45 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| sendgrid_mail.py:26:34:26:61 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| sendgrid_mail.py:37:41:37:47 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| sendgrid_mail.py:37:41:37:52 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| sendgrid_mail.py:37:41:37:68 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| sendgrid_via_mail_send_post_request_body_bad.py:16:26:16:79 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
|
||||
| sendgrid_via_mail_send_post_request_body_bad.py:16:51:16:57 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| sendgrid_via_mail_send_post_request_body_bad.py:16:51:16:62 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| sendgrid_via_mail_send_post_request_body_bad.py:16:51:16:78 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| sendgrid_via_mail_send_post_request_body_bad.py:27:25:27:77 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
|
||||
| sendgrid_via_mail_send_post_request_body_bad.py:27:50:27:56 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| sendgrid_via_mail_send_post_request_body_bad.py:27:50:27:61 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| sendgrid_via_mail_send_post_request_body_bad.py:27:50:27:76 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| sendgrid_via_mail_send_post_request_body_bad.py:41:25:41:79 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
|
||||
| sendgrid_via_mail_send_post_request_body_bad.py:41:50:41:56 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| sendgrid_via_mail_send_post_request_body_bad.py:41:50:41:61 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| sendgrid_via_mail_send_post_request_body_bad.py:41:50:41:78 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| smtplib_bad_subparts.py:17:12:17:18 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| smtplib_bad_subparts.py:17:12:17:23 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| smtplib_bad_subparts.py:17:12:17:33 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| smtplib_bad_subparts.py:24:22:24:25 | ControlFlowNode for html | semmle.label | ControlFlowNode for html |
|
||||
| smtplib_bad_via_attach.py:20:12:20:18 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| smtplib_bad_via_attach.py:20:12:20:23 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| smtplib_bad_via_attach.py:20:12:20:31 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| smtplib_bad_via_attach.py:27:22:27:25 | ControlFlowNode for html | semmle.label | ControlFlowNode for html |
|
||||
subpaths
|
||||
#select
|
||||
| django_mail.py:14:48:14:82 | ControlFlowNode for Attribute() | django_mail.py:14:48:14:82 | ControlFlowNode for Attribute() | django_mail.py:14:48:14:82 | ControlFlowNode for Attribute() | Cross-site scripting vulnerability due to $@. | django_mail.py:14:48:14:82 | ControlFlowNode for Attribute() | a user-provided value |
|
||||
| django_mail.py:23:30:23:64 | ControlFlowNode for Attribute() | django_mail.py:23:30:23:64 | ControlFlowNode for Attribute() | django_mail.py:23:30:23:64 | ControlFlowNode for Attribute() | Cross-site scripting vulnerability due to $@. | django_mail.py:23:30:23:64 | ControlFlowNode for Attribute() | a user-provided value |
|
||||
| django_mail.py:25:32:25:66 | ControlFlowNode for Attribute() | django_mail.py:25:32:25:66 | ControlFlowNode for Attribute() | django_mail.py:25:32:25:66 | ControlFlowNode for Attribute() | Cross-site scripting vulnerability due to $@. | django_mail.py:25:32:25:66 | ControlFlowNode for Attribute() | a user-provided value |
|
||||
| flask_mail.py:13:22:13:41 | ControlFlowNode for Subscript | flask_mail.py:13:22:13:28 | ControlFlowNode for request | flask_mail.py:13:22:13:41 | ControlFlowNode for Subscript | Cross-site scripting vulnerability due to $@. | flask_mail.py:13:22:13:28 | ControlFlowNode for request | a user-provided value |
|
||||
| flask_mail.py:18:14:18:33 | ControlFlowNode for Subscript | flask_mail.py:13:22:13:28 | ControlFlowNode for request | flask_mail.py:18:14:18:33 | ControlFlowNode for Subscript | Cross-site scripting vulnerability due to $@. | flask_mail.py:13:22:13:28 | ControlFlowNode for request | a user-provided value |
|
||||
| flask_mail.py:18:14:18:33 | ControlFlowNode for Subscript | flask_mail.py:18:14:18:20 | ControlFlowNode for request | flask_mail.py:18:14:18:33 | ControlFlowNode for Subscript | Cross-site scripting vulnerability due to $@. | flask_mail.py:18:14:18:20 | ControlFlowNode for request | a user-provided value |
|
||||
| flask_mail.py:31:24:31:43 | ControlFlowNode for Subscript | flask_mail.py:31:24:31:30 | ControlFlowNode for request | flask_mail.py:31:24:31:43 | ControlFlowNode for Subscript | Cross-site scripting vulnerability due to $@. | flask_mail.py:31:24:31:30 | ControlFlowNode for request | a user-provided value |
|
||||
| sendgrid_mail.py:14:22:14:49 | ControlFlowNode for Subscript | sendgrid_mail.py:14:22:14:28 | ControlFlowNode for request | sendgrid_mail.py:14:22:14:49 | ControlFlowNode for Subscript | Cross-site scripting vulnerability due to $@. | sendgrid_mail.py:14:22:14:28 | ControlFlowNode for request | a user-provided value |
|
||||
| sendgrid_mail.py:26:22:26:62 | ControlFlowNode for HtmlContent() | sendgrid_mail.py:26:34:26:40 | ControlFlowNode for request | sendgrid_mail.py:26:22:26:62 | ControlFlowNode for HtmlContent() | Cross-site scripting vulnerability due to $@. | sendgrid_mail.py:26:34:26:40 | ControlFlowNode for request | a user-provided value |
|
||||
| sendgrid_mail.py:37:41:37:68 | ControlFlowNode for Subscript | sendgrid_mail.py:37:41:37:47 | ControlFlowNode for request | sendgrid_mail.py:37:41:37:68 | ControlFlowNode for Subscript | Cross-site scripting vulnerability due to $@. | sendgrid_mail.py:37:41:37:47 | ControlFlowNode for request | a user-provided value |
|
||||
| sendgrid_via_mail_send_post_request_body_bad.py:16:26:16:79 | ControlFlowNode for Attribute() | sendgrid_via_mail_send_post_request_body_bad.py:16:51:16:57 | ControlFlowNode for request | sendgrid_via_mail_send_post_request_body_bad.py:16:26:16:79 | ControlFlowNode for Attribute() | Cross-site scripting vulnerability due to $@. | sendgrid_via_mail_send_post_request_body_bad.py:16:51:16:57 | ControlFlowNode for request | a user-provided value |
|
||||
| sendgrid_via_mail_send_post_request_body_bad.py:27:25:27:77 | ControlFlowNode for Attribute() | sendgrid_via_mail_send_post_request_body_bad.py:16:51:16:57 | ControlFlowNode for request | sendgrid_via_mail_send_post_request_body_bad.py:27:25:27:77 | ControlFlowNode for Attribute() | Cross-site scripting vulnerability due to $@. | sendgrid_via_mail_send_post_request_body_bad.py:16:51:16:57 | ControlFlowNode for request | a user-provided value |
|
||||
| sendgrid_via_mail_send_post_request_body_bad.py:27:25:27:77 | ControlFlowNode for Attribute() | sendgrid_via_mail_send_post_request_body_bad.py:27:50:27:56 | ControlFlowNode for request | sendgrid_via_mail_send_post_request_body_bad.py:27:25:27:77 | ControlFlowNode for Attribute() | Cross-site scripting vulnerability due to $@. | sendgrid_via_mail_send_post_request_body_bad.py:27:50:27:56 | ControlFlowNode for request | a user-provided value |
|
||||
| sendgrid_via_mail_send_post_request_body_bad.py:41:25:41:79 | ControlFlowNode for Attribute() | sendgrid_via_mail_send_post_request_body_bad.py:16:51:16:57 | ControlFlowNode for request | sendgrid_via_mail_send_post_request_body_bad.py:41:25:41:79 | ControlFlowNode for Attribute() | Cross-site scripting vulnerability due to $@. | sendgrid_via_mail_send_post_request_body_bad.py:16:51:16:57 | ControlFlowNode for request | a user-provided value |
|
||||
| sendgrid_via_mail_send_post_request_body_bad.py:41:25:41:79 | ControlFlowNode for Attribute() | sendgrid_via_mail_send_post_request_body_bad.py:27:50:27:56 | ControlFlowNode for request | sendgrid_via_mail_send_post_request_body_bad.py:41:25:41:79 | ControlFlowNode for Attribute() | Cross-site scripting vulnerability due to $@. | sendgrid_via_mail_send_post_request_body_bad.py:27:50:27:56 | ControlFlowNode for request | a user-provided value |
|
||||
| sendgrid_via_mail_send_post_request_body_bad.py:41:25:41:79 | ControlFlowNode for Attribute() | sendgrid_via_mail_send_post_request_body_bad.py:41:50:41:56 | ControlFlowNode for request | sendgrid_via_mail_send_post_request_body_bad.py:41:25:41:79 | ControlFlowNode for Attribute() | Cross-site scripting vulnerability due to $@. | sendgrid_via_mail_send_post_request_body_bad.py:41:50:41:56 | ControlFlowNode for request | a user-provided value |
|
||||
| smtplib_bad_subparts.py:24:22:24:25 | ControlFlowNode for html | smtplib_bad_subparts.py:17:12:17:18 | ControlFlowNode for request | smtplib_bad_subparts.py:24:22:24:25 | ControlFlowNode for html | Cross-site scripting vulnerability due to $@. | smtplib_bad_subparts.py:17:12:17:18 | ControlFlowNode for request | a user-provided value |
|
||||
| smtplib_bad_via_attach.py:27:22:27:25 | ControlFlowNode for html | smtplib_bad_via_attach.py:20:12:20:18 | ControlFlowNode for request | smtplib_bad_via_attach.py:27:22:27:25 | ControlFlowNode for html | Cross-site scripting vulnerability due to $@. | smtplib_bad_via_attach.py:20:12:20:18 | ControlFlowNode for request | a user-provided value |
|
||||
@@ -0,0 +1 @@
|
||||
experimental/Security/CWE-079/ReflectedXSS.ql
|
||||
@@ -0,0 +1,25 @@
|
||||
import django.http
|
||||
from django.core.mail import send_mail, mail_admins, mail_managers
|
||||
|
||||
|
||||
def django_response(request):
|
||||
"""
|
||||
The Django.core.mail#send_mail function source code can be found in the link below:
|
||||
https://github.com/django/django/blob/ca9872905559026af82000e46cde6f7dedc897b6/django/core/mail/__init__.py#L38
|
||||
|
||||
send_mass_mail does not provide html_message as an argument to it's function. See the link below for more info:
|
||||
https://github.com/django/django/blob/ca9872905559026af82000e46cde6f7dedc897b6/django/core/mail/__init__.py#L64
|
||||
"""
|
||||
send_mail("Subject", "plain-text body", "from@example.com",
|
||||
["to@example.com"], html_message=django.http.request.GET.get("html"))
|
||||
|
||||
|
||||
def django_response(request):
|
||||
"""
|
||||
The Django.core.mail#mail_admins and Django.core.mail#mail_managers functions source code can be found in the link below:
|
||||
https://github.com/django/django/blob/ca9872905559026af82000e46cde6f7dedc897b6/django/core/mail/__init__.py#L90-L121
|
||||
"""
|
||||
mail_admins("Subject", "plain-text body",
|
||||
html_message=django.http.request.GET.get("html"))
|
||||
mail_managers("Subject", "plain-text body",
|
||||
html_message=django.http.request.GET.get("html"))
|
||||
@@ -0,0 +1,32 @@
|
||||
from flask import request, Flask
|
||||
from flask_mail import Mail, Message
|
||||
|
||||
app = Flask(__name__)
|
||||
mail = Mail(app)
|
||||
|
||||
@app.route("/send")
|
||||
def send():
|
||||
msg = Message(subject="Subject",
|
||||
sender="from@example.com",
|
||||
recipients=["to@example.com"],
|
||||
body="plain-text body",
|
||||
html=request.args["html"])
|
||||
|
||||
# The message can contain a body and/or HTML:
|
||||
msg.body = "plain-text body"
|
||||
# The email's HTML can be set via msg.html or as an initialize argument when creating a Message object.
|
||||
msg.html = request.args["html"]
|
||||
|
||||
mail.send(msg)
|
||||
|
||||
@app.route("/connect")
|
||||
def connect():
|
||||
"""
|
||||
Minimal example to test mail.connect() usage
|
||||
"""
|
||||
with mail.connect() as conn:
|
||||
msg = Message(subject="Subject",
|
||||
sender="from@example.com",
|
||||
recipients=["to@example.com"],
|
||||
html=request.args["html"])
|
||||
conn.send(msg)
|
||||
@@ -0,0 +1,57 @@
|
||||
from flask import request, Flask
|
||||
from sendgrid import SendGridAPIClient
|
||||
from sendgrid.helpers.mail import Mail, Email, To, Content, MimeType, HtmlContent
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
|
||||
@app.route("/send")
|
||||
def send():
|
||||
message = Mail(
|
||||
from_email='from_email@example.com',
|
||||
to_emails='to@example.com',
|
||||
subject='Sending with Twilio SendGrid is Fun',
|
||||
html_content=request.args["html_content"])
|
||||
|
||||
sg = SendGridAPIClient('SENDGRID_API_KEY')
|
||||
sg.send(message)
|
||||
|
||||
|
||||
@app.route("/send-HtmlContent")
|
||||
def send():
|
||||
message = Mail(
|
||||
from_email='from_email@example.com',
|
||||
to_emails='to@example.com',
|
||||
subject='Sending with Twilio SendGrid is Fun',
|
||||
html_content=HtmlContent(request.args["html_content"]))
|
||||
|
||||
sg = SendGridAPIClient('SENDGRID_API_KEY')
|
||||
sg.send(message)
|
||||
|
||||
|
||||
@app.route("/send_post")
|
||||
def send_post():
|
||||
from_email = Email("test@example.com")
|
||||
to_email = To("test@example.com")
|
||||
subject = "Sending with SendGrid is Fun"
|
||||
html_content = Content("text/html", request.args["html_content"])
|
||||
plain_content = Content("text/plain", request.args["plain_content"])
|
||||
|
||||
mail = Mail(from_email, to_email, subject, plain_content, html_content)
|
||||
|
||||
sg = SendGridAPIClient(api_key='SENDGRID_API_KEY')
|
||||
response = sg.client.mail.send.post(request_body=mail.get())
|
||||
|
||||
|
||||
@app.route("/send_post2")
|
||||
def send_post2():
|
||||
from_email = Email("test@example.com")
|
||||
to_email = To("test@example.com")
|
||||
subject = "Sending with SendGrid is Fun"
|
||||
html_content = Content(MimeType.html, request.args["html_content"])
|
||||
plain_content = Content(MimeType.text, request.args["plain_content"])
|
||||
|
||||
mail = Mail(from_email, to_email, subject, plain_content, html_content)
|
||||
|
||||
sg = SendGridAPIClient(api_key='SENDGRID_API_KEY')
|
||||
response = sg.client.mail.send.post(request_body=mail.get())
|
||||
@@ -0,0 +1,48 @@
|
||||
import sendgrid
|
||||
import os
|
||||
from flask import request, Flask
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
|
||||
@app.route("/sendgrid")
|
||||
def send():
|
||||
sg = sendgrid.SendGridAPIClient(os.environ.get('SENDGRID_API_KEY'))
|
||||
|
||||
data = {
|
||||
"content": [
|
||||
{
|
||||
"type": "text/html",
|
||||
"value": "<html>{}</html>".format(request.args["html_content"])
|
||||
}
|
||||
],
|
||||
"from": {
|
||||
"email": "sam.smith@example.com",
|
||||
"name": "Sam Smith"
|
||||
},
|
||||
"headers": {},
|
||||
"mail_settings": {
|
||||
"footer": {
|
||||
"enable": True,
|
||||
"html": "<html>{}</html>".format(request.args["html_footer"]),
|
||||
"text": "Thanks,/n The SendGrid Team"
|
||||
},
|
||||
},
|
||||
"reply_to": {
|
||||
"email": "sam.smith@example.com",
|
||||
"name": "Sam Smith"
|
||||
},
|
||||
"send_at": 1409348513,
|
||||
"subject": "Hello, World!",
|
||||
"template_id": "[YOUR TEMPLATE ID GOES HERE]",
|
||||
"tracking_settings": {
|
||||
"subscription_tracking": {
|
||||
"enable": True,
|
||||
"html": "<html>{}</html>".format(request.args["html_tracking"]),
|
||||
"substitution_tag": "<%click here%>",
|
||||
"text": "If you would like to unsubscribe and stop receiving these emails <% click here %>."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
response = sg.client.mail.send.post(request_body=data)
|
||||
@@ -0,0 +1,42 @@
|
||||
# This test checks that the developer doesn't pass a MIMEText instance to a MIMEMultipart initializer via the subparts parameter.
|
||||
from flask import Flask, request
|
||||
import json
|
||||
import smtplib
|
||||
import ssl
|
||||
from email.mime.text import MIMEText
|
||||
from email.mime.multipart import MIMEMultipart
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
|
||||
@app.route("/")
|
||||
def email_person():
|
||||
sender_email = "sender@gmail.com"
|
||||
receiver_email = "receiver@example.com"
|
||||
|
||||
name = request.args['search']
|
||||
# Create the plain-text and HTML version of your message
|
||||
text = "hello there"
|
||||
html = f"hello {name}"
|
||||
|
||||
# Turn these into plain/html MIMEText objects
|
||||
part1 = MIMEText(text, "plain")
|
||||
part2 = MIMEText(html, "html")
|
||||
|
||||
message = MIMEMultipart(_subparts=(part1, part2))
|
||||
message["Subject"] = "multipart test"
|
||||
message["From"] = sender_email
|
||||
message["To"] = receiver_email
|
||||
|
||||
# Create secure connection with server and send email
|
||||
context = ssl.create_default_context()
|
||||
server = smtplib.SMTP_SSL("smtp.gmail.com", 465, context=context)
|
||||
|
||||
server.login(sender_email, "SERVER_PASSWORD")
|
||||
server.sendmail(
|
||||
sender_email, receiver_email, message.as_string()
|
||||
)
|
||||
|
||||
|
||||
# if __name__ == "__main__":
|
||||
# app.run(debug=True)
|
||||
@@ -0,0 +1,45 @@
|
||||
# This test checks that the developer doesn't pass a MIMEText instance to a MIMEMultipart message.
|
||||
from flask import Flask, request
|
||||
import json
|
||||
import smtplib, ssl
|
||||
from email.mime.text import MIMEText
|
||||
from email.mime.multipart import MIMEMultipart
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
@app.route("/")
|
||||
def email_person():
|
||||
sender_email = "sender@gmail.com"
|
||||
receiver_email = "receiver@example.com"
|
||||
|
||||
message = MIMEMultipart("alternative")
|
||||
message["Subject"] = "multipart test"
|
||||
message["From"] = sender_email
|
||||
message["To"] = receiver_email
|
||||
|
||||
name = request.args['name']
|
||||
# Create the plain-text and HTML version of your message
|
||||
text = "hello there"
|
||||
html = f"hello {name}"
|
||||
|
||||
# Turn these into plain/html MIMEText objects
|
||||
part1 = MIMEText(text, "plain")
|
||||
part2 = MIMEText(html, "html")
|
||||
|
||||
# Add HTML/plain-text parts to MIMEMultipart message
|
||||
# The email client will try to render the last part first
|
||||
message.attach(part1)
|
||||
message.attach(part2)
|
||||
|
||||
# Create secure connection with server and send email
|
||||
context = ssl.create_default_context()
|
||||
server = smtplib.SMTP_SSL("smtp.gmail.com", 465, context=context)
|
||||
|
||||
server.login(sender_email, "SERVER_PASSWORD")
|
||||
server.sendmail(
|
||||
sender_email, receiver_email, message.as_string()
|
||||
)
|
||||
|
||||
|
||||
# if __name__ == "__main__":
|
||||
# app.run(debug=True)
|
||||
@@ -13,8 +13,6 @@ edges
|
||||
| flask_bad.py:35:18:35:24 | ControlFlowNode for request | flask_bad.py:35:18:35:29 | ControlFlowNode for Attribute |
|
||||
| flask_bad.py:35:18:35:29 | ControlFlowNode for Attribute | flask_bad.py:35:18:35:43 | ControlFlowNode for Subscript |
|
||||
| flask_bad.py:35:18:35:43 | ControlFlowNode for Subscript | flask_bad.py:38:24:38:33 | ControlFlowNode for rfs_header |
|
||||
| flask_bad.py:44:44:44:50 | ControlFlowNode for request | flask_bad.py:44:44:44:55 | ControlFlowNode for Attribute |
|
||||
| flask_bad.py:44:44:44:55 | ControlFlowNode for Attribute | flask_bad.py:44:44:44:69 | ControlFlowNode for Subscript |
|
||||
nodes
|
||||
| django_bad.py:5:18:5:58 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
|
||||
| django_bad.py:7:40:7:49 | ControlFlowNode for rfs_header | semmle.label | ControlFlowNode for rfs_header |
|
||||
@@ -36,9 +34,6 @@ nodes
|
||||
| flask_bad.py:35:18:35:29 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| flask_bad.py:35:18:35:43 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| flask_bad.py:38:24:38:33 | ControlFlowNode for rfs_header | semmle.label | ControlFlowNode for rfs_header |
|
||||
| flask_bad.py:44:44:44:50 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| flask_bad.py:44:44:44:55 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| flask_bad.py:44:44:44:69 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
subpaths
|
||||
#select
|
||||
| django_bad.py:7:40:7:49 | ControlFlowNode for rfs_header | django_bad.py:5:18:5:58 | ControlFlowNode for Attribute() | django_bad.py:7:40:7:49 | ControlFlowNode for rfs_header | $@ HTTP header is constructed from a $@. | django_bad.py:7:40:7:49 | ControlFlowNode for rfs_header | This | django_bad.py:5:18:5:58 | ControlFlowNode for Attribute() | user-provided value |
|
||||
@@ -47,4 +42,3 @@ subpaths
|
||||
| flask_bad.py:21:38:21:47 | ControlFlowNode for rfs_header | flask_bad.py:19:18:19:24 | ControlFlowNode for request | flask_bad.py:21:38:21:47 | ControlFlowNode for rfs_header | $@ HTTP header is constructed from a $@. | flask_bad.py:21:38:21:47 | ControlFlowNode for rfs_header | This | flask_bad.py:19:18:19:24 | ControlFlowNode for request | user-provided value |
|
||||
| flask_bad.py:29:34:29:43 | ControlFlowNode for rfs_header | flask_bad.py:27:18:27:24 | ControlFlowNode for request | flask_bad.py:29:34:29:43 | ControlFlowNode for rfs_header | $@ HTTP header is constructed from a $@. | flask_bad.py:29:34:29:43 | ControlFlowNode for rfs_header | This | flask_bad.py:27:18:27:24 | ControlFlowNode for request | user-provided value |
|
||||
| flask_bad.py:38:24:38:33 | ControlFlowNode for rfs_header | flask_bad.py:35:18:35:24 | ControlFlowNode for request | flask_bad.py:38:24:38:33 | ControlFlowNode for rfs_header | $@ HTTP header is constructed from a $@. | flask_bad.py:38:24:38:33 | ControlFlowNode for rfs_header | This | flask_bad.py:35:18:35:24 | ControlFlowNode for request | user-provided value |
|
||||
| flask_bad.py:44:44:44:69 | ControlFlowNode for Subscript | flask_bad.py:44:44:44:50 | ControlFlowNode for request | flask_bad.py:44:44:44:69 | ControlFlowNode for Subscript | $@ HTTP header is constructed from a $@. | flask_bad.py:44:44:44:69 | ControlFlowNode for Subscript | This | flask_bad.py:44:44:44:50 | ControlFlowNode for request | user-provided value |
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
edges
|
||||
| csv_bad.py:16:16:16:22 | ControlFlowNode for request | csv_bad.py:16:16:16:27 | ControlFlowNode for Attribute |
|
||||
| csv_bad.py:16:16:16:27 | ControlFlowNode for Attribute | csv_bad.py:18:24:18:31 | ControlFlowNode for csv_data |
|
||||
| csv_bad.py:16:16:16:27 | ControlFlowNode for Attribute | csv_bad.py:19:25:19:32 | ControlFlowNode for csv_data |
|
||||
| csv_bad.py:24:16:24:22 | ControlFlowNode for request | csv_bad.py:24:16:24:27 | ControlFlowNode for Attribute |
|
||||
| csv_bad.py:24:16:24:27 | ControlFlowNode for Attribute | csv_bad.py:25:46:25:53 | ControlFlowNode for csv_data |
|
||||
nodes
|
||||
| csv_bad.py:16:16:16:22 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| csv_bad.py:16:16:16:27 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| csv_bad.py:18:24:18:31 | ControlFlowNode for csv_data | semmle.label | ControlFlowNode for csv_data |
|
||||
| csv_bad.py:19:25:19:32 | ControlFlowNode for csv_data | semmle.label | ControlFlowNode for csv_data |
|
||||
| csv_bad.py:24:16:24:22 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| csv_bad.py:24:16:24:27 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| csv_bad.py:25:46:25:53 | ControlFlowNode for csv_data | semmle.label | ControlFlowNode for csv_data |
|
||||
subpaths
|
||||
#select
|
||||
| csv_bad.py:18:24:18:31 | ControlFlowNode for csv_data | csv_bad.py:16:16:16:22 | ControlFlowNode for request | csv_bad.py:18:24:18:31 | ControlFlowNode for csv_data | Csv injection might include code from $@. | csv_bad.py:16:16:16:22 | ControlFlowNode for request | this user input |
|
||||
| csv_bad.py:19:25:19:32 | ControlFlowNode for csv_data | csv_bad.py:16:16:16:22 | ControlFlowNode for request | csv_bad.py:19:25:19:32 | ControlFlowNode for csv_data | Csv injection might include code from $@. | csv_bad.py:16:16:16:22 | ControlFlowNode for request | this user input |
|
||||
| csv_bad.py:25:46:25:53 | ControlFlowNode for csv_data | csv_bad.py:24:16:24:22 | ControlFlowNode for request | csv_bad.py:25:46:25:53 | ControlFlowNode for csv_data | Csv injection might include code from $@. | csv_bad.py:24:16:24:22 | ControlFlowNode for request | this user input |
|
||||
@@ -0,0 +1 @@
|
||||
experimental/Security/CWE-1236/CsvInjection.ql
|
||||
@@ -0,0 +1,31 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: UTF-8 -*-
|
||||
"""
|
||||
@Desc :csv injection
|
||||
"""
|
||||
import copy
|
||||
import csv
|
||||
from flask import Flask
|
||||
from flask import request
|
||||
from typing import List
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
@app.route('/bad1')
|
||||
def bad1():
|
||||
csv_data = request.args.get('csv')
|
||||
csvWriter = csv.writer(open("test.csv", "wt"))
|
||||
csvWriter.writerow(csv_data) # bad
|
||||
csvWriter.writerows(csv_data) # bad
|
||||
return "bad1"
|
||||
|
||||
@app.route('/bad2')
|
||||
def bad2():
|
||||
csv_data = request.args.get('csv')
|
||||
csvWriter = csv.DictWriter(f, fieldnames=csv_data) # bad
|
||||
csvWriter.writeheader()
|
||||
return "bad2"
|
||||
|
||||
if __name__ == '__main__':
|
||||
app.debug = True
|
||||
app.run()
|
||||
@@ -1 +0,0 @@
|
||||
| pam_test.py:48:18:48:44 | ControlFlowNode for pam_authenticate() | This PAM authentication call may be lead to an authorization bypass. |
|
||||
@@ -1 +0,0 @@
|
||||
experimental/Security/CWE-285/PamAuthorization.ql
|
||||
@@ -1,6 +1,13 @@
|
||||
| test.py:4:1:4:23 | Class MyTest |
|
||||
| test.py:6:5:6:21 | Function test_1 |
|
||||
| test.py:9:5:9:21 | Function test_2 |
|
||||
| test_foo.py:3:1:3:15 | Function test_foo |
|
||||
| unittest_test.py:3:1:3:33 | Class FooTest |
|
||||
| unittest_test.py:4:5:4:25 | Function test_valid |
|
||||
| unittest_test.py:7:1:7:49 | Class FunctionFooTest |
|
||||
| unittest_test.py:8:5:8:25 | Function test_valid |
|
||||
| unittest_test.py:11:1:11:50 | Class AsyncTest |
|
||||
| unittest_test.py:12:11:12:31 | Function test_valid |
|
||||
| unittest_test.py:17:1:17:45 | Class MyDjangoUnitTest |
|
||||
| unittest_test.py:18:5:18:25 | Function test_valid |
|
||||
| unittest_test.py:23:1:23:56 | Class MyFlaskUnitTest |
|
||||
| unittest_test.py:24:5:24:25 | Function test_valid |
|
||||
| unittest_test.py:29:1:29:59 | Class MyTornadoUnitTest |
|
||||
| unittest_test.py:30:5:30:25 | Function test_valid |
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
class TestCase:
|
||||
pass
|
||||
|
||||
class MyTest(TestCase):
|
||||
|
||||
def test_1(self):
|
||||
pass
|
||||
|
||||
def test_2(self):
|
||||
pass
|
||||
@@ -3,3 +3,29 @@ import unittest
|
||||
class FooTest(unittest.TestCase):
|
||||
def test_valid(self):
|
||||
pass
|
||||
|
||||
class FunctionFooTest(unittest.FunctionTestCase):
|
||||
def test_valid(self):
|
||||
pass
|
||||
|
||||
class AsyncTest(unittest.IsolatedAsyncioTestCase):
|
||||
async def test_valid(self):
|
||||
pass
|
||||
|
||||
# django -- see https://docs.djangoproject.com/en/4.0/topics/testing/overview/
|
||||
import django.test
|
||||
class MyDjangoUnitTest(django.test.TestCase):
|
||||
def test_valid(self):
|
||||
pass
|
||||
|
||||
# flask -- see https://pythonhosted.org/Flask-Testing/
|
||||
import flask_testing
|
||||
class MyFlaskUnitTest(flask_testing.LiveServerTestCase):
|
||||
def test_valid(self):
|
||||
pass
|
||||
|
||||
# tornado -- see https://www.tornadoweb.org/en/stable/testing.html#tornado.testing.AsyncHTTPTestCase
|
||||
import tornado.testing
|
||||
class MyTornadoUnitTest(tornado.testing.AsyncHTTPTestCase):
|
||||
def test_valid(self):
|
||||
pass
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import aiohttp
|
||||
import asyncio
|
||||
import ssl
|
||||
|
||||
s = aiohttp.ClientSession()
|
||||
resp = s.request("method", "url") # $ clientRequestUrlPart="url"
|
||||
@@ -13,4 +14,22 @@ with aiohttp.ClientSession() as session:
|
||||
s = aiohttp.ClientSession()
|
||||
resp = s.post("url") # $ clientRequestUrlPart="url"
|
||||
resp = s.patch("url") # $ clientRequestUrlPart="url"
|
||||
resp = s.options("url") # $ clientRequestUrlPart="url"
|
||||
resp = s.options("url") # $ clientRequestUrlPart="url"
|
||||
|
||||
# disabling of SSL validation
|
||||
# see https://docs.aiohttp.org/en/stable/client_reference.html#aiohttp.ClientSession.request
|
||||
s.get("url", ssl=False) # $ clientRequestUrlPart="url" clientRequestCertValidationDisabled
|
||||
s.get("url", ssl=0) # $ clientRequestUrlPart="url" clientRequestCertValidationDisabled
|
||||
# None is treated as default and so does _not_ disable the check
|
||||
s.get("url", ssl=None) # $ clientRequestUrlPart="url"
|
||||
|
||||
# deprecated since 3.0, but still supported
|
||||
s.get("url", verify_ssl=False) # $ clientRequestUrlPart="url" clientRequestCertValidationDisabled
|
||||
|
||||
# A manually constructed SSLContext does not have safe defaults, so is effectively the
|
||||
# same as turning off SSL validation
|
||||
context = ssl.SSLContext()
|
||||
assert context.check_hostname == False
|
||||
assert context.verify_mode == ssl.VerifyMode.CERT_NONE
|
||||
|
||||
s.get("url", ssl=context) # $ clientRequestUrlPart="url" MISSING: clientRequestCertValidationDisabled
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
import python
|
||||
import experimental.meta.MaDTest
|
||||
@@ -7,17 +7,17 @@ async def test_connection():
|
||||
try:
|
||||
# The file-like object is passed in as a keyword-only argument.
|
||||
# See https://magicstack.github.io/asyncpg/current/api/index.html#asyncpg.connection.Connection.copy_from_query
|
||||
await conn.copy_from_query("sql", output="filepath") # $ getSql="sql" getAPathArgument="filepath"
|
||||
await conn.copy_from_query("sql", "arg1", "arg2", output="filepath") # $ getSql="sql" getAPathArgument="filepath"
|
||||
await conn.copy_from_query("sql", output="filepath") # $ mad-sink[sql-injection]="sql" mad-sink[path-injection]="filepath"
|
||||
await conn.copy_from_query("sql", "arg1", "arg2", output="filepath") # $ mad-sink[sql-injection]="sql" mad-sink[path-injection]="filepath"
|
||||
|
||||
await conn.copy_from_table("table", output="filepath") # $ getAPathArgument="filepath"
|
||||
await conn.copy_to_table("table", source="filepath") # $ getAPathArgument="filepath"
|
||||
await conn.copy_from_table("table", output="filepath") # $ mad-sink[path-injection]="filepath"
|
||||
await conn.copy_to_table("table", source="filepath") # $ mad-sink[path-injection]="filepath"
|
||||
|
||||
await conn.execute("sql") # $ getSql="sql"
|
||||
await conn.executemany("sql") # $ getSql="sql"
|
||||
await conn.fetch("sql") # $ getSql="sql"
|
||||
await conn.fetchrow("sql") # $ getSql="sql"
|
||||
await conn.fetchval("sql") # $ getSql="sql"
|
||||
await conn.execute("sql") # $ mad-sink[sql-injection]="sql"
|
||||
await conn.executemany("sql") # $ mad-sink[sql-injection]="sql"
|
||||
await conn.fetch("sql") # $ mad-sink[sql-injection]="sql"
|
||||
await conn.fetchrow("sql") # $ mad-sink[sql-injection]="sql"
|
||||
await conn.fetchval("sql") # $ mad-sink[sql-injection]="sql"
|
||||
|
||||
finally:
|
||||
await conn.close()
|
||||
@@ -27,11 +27,11 @@ async def test_prepared_statement():
|
||||
conn = await asyncpg.connect()
|
||||
|
||||
try:
|
||||
pstmt = await conn.prepare("psql") # $ constructedSql="psql"
|
||||
pstmt.executemany() # $ getSql="psql"
|
||||
pstmt.fetch() # $ getSql="psql"
|
||||
pstmt.fetchrow() # $ getSql="psql"
|
||||
pstmt.fetchval() # $ getSql="psql"
|
||||
pstmt = await conn.prepare("psql") # $ mad-sink[sql-injection]="psql"
|
||||
pstmt.executemany()
|
||||
pstmt.fetch()
|
||||
pstmt.fetchrow()
|
||||
pstmt.fetchval()
|
||||
|
||||
finally:
|
||||
await conn.close()
|
||||
@@ -46,7 +46,7 @@ async def test_cursor():
|
||||
cursor = await conn.cursor("sql") # $ getSql="sql" constructedSql="sql"
|
||||
await cursor.fetch()
|
||||
|
||||
pstmt = await conn.prepare("psql") # $ constructedSql="psql"
|
||||
pstmt = await conn.prepare("psql") # $ mad-sink[sql-injection]="psql"
|
||||
pcursor = await pstmt.cursor() # $ getSql="psql"
|
||||
await pcursor.fetch()
|
||||
|
||||
@@ -69,23 +69,23 @@ async def test_connection_pool():
|
||||
pool = await asyncpg.create_pool()
|
||||
|
||||
try:
|
||||
await pool.copy_from_query("sql", output="filepath") # $ getSql="sql" getAPathArgument="filepath"
|
||||
await pool.copy_from_query("sql", "arg1", "arg2", output="filepath") # $ getSql="sql" getAPathArgument="filepath"
|
||||
await pool.copy_from_table("table", output="filepath") # $ getAPathArgument="filepath"
|
||||
await pool.copy_to_table("table", source="filepath") # $ getAPathArgument="filepath"
|
||||
await pool.copy_from_query("sql", output="filepath") # $ mad-sink[sql-injection]="sql" mad-sink[path-injection]="filepath"
|
||||
await pool.copy_from_query("sql", "arg1", "arg2", output="filepath") # $ mad-sink[sql-injection]="sql" mad-sink[path-injection]="filepath"
|
||||
await pool.copy_from_table("table", output="filepath") # $ mad-sink[path-injection]="filepath"
|
||||
await pool.copy_to_table("table", source="filepath") # $ mad-sink[path-injection]="filepath"
|
||||
|
||||
await pool.execute("sql") # $ getSql="sql"
|
||||
await pool.executemany("sql") # $ getSql="sql"
|
||||
await pool.fetch("sql") # $ getSql="sql"
|
||||
await pool.fetchrow("sql") # $ getSql="sql"
|
||||
await pool.fetchval("sql") # $ getSql="sql"
|
||||
await pool.execute("sql") # $ mad-sink[sql-injection]="sql"
|
||||
await pool.executemany("sql") # $ mad-sink[sql-injection]="sql"
|
||||
await pool.fetch("sql") # $ mad-sink[sql-injection]="sql"
|
||||
await pool.fetchrow("sql") # $ mad-sink[sql-injection]="sql"
|
||||
await pool.fetchval("sql") # $ mad-sink[sql-injection]="sql"
|
||||
|
||||
async with pool.acquire() as conn:
|
||||
await conn.execute("sql") # $ getSql="sql"
|
||||
await conn.execute("sql") # $ mad-sink[sql-injection]="sql"
|
||||
|
||||
conn = await pool.acquire()
|
||||
try:
|
||||
await conn.fetch("sql") # $ getSql="sql"
|
||||
await conn.fetch("sql") # $ mad-sink[sql-injection]="sql"
|
||||
finally:
|
||||
await pool.release(conn)
|
||||
|
||||
@@ -93,13 +93,13 @@ async def test_connection_pool():
|
||||
await pool.close()
|
||||
|
||||
async with asyncpg.create_pool() as pool:
|
||||
await pool.execute("sql") # $ getSql="sql"
|
||||
await pool.execute("sql") # $ mad-sink[sql-injection]="sql"
|
||||
|
||||
async with pool.acquire() as conn:
|
||||
await conn.execute("sql") # $ getSql="sql"
|
||||
await conn.execute("sql") # $ mad-sink[sql-injection]="sql"
|
||||
|
||||
conn = await pool.acquire()
|
||||
try:
|
||||
await conn.fetch("sql") # $ getSql="sql"
|
||||
await conn.fetch("sql") # $ mad-sink[sql-injection]="sql"
|
||||
finally:
|
||||
await pool.release(conn)
|
||||
|
||||
@@ -21,14 +21,14 @@ padding = b"\0"*padding_len
|
||||
cipher = AES.new(key, AES.MODE_CBC, iv=iv)
|
||||
# using separate .encrypt calls on individual lines does not work
|
||||
whole_plantext = secret_message + padding
|
||||
encrypted = cipher.encrypt(whole_plantext) # $ CryptographicOperation CryptographicOperationAlgorithm=AES CryptographicOperationInput=whole_plantext
|
||||
encrypted = cipher.encrypt(whole_plantext) # $ CryptographicOperation CryptographicOperationAlgorithm=AES CryptographicOperationInput=whole_plantext CryptographicOperationBlockMode=CBC
|
||||
|
||||
print("encrypted={}".format(encrypted))
|
||||
|
||||
print()
|
||||
|
||||
cipher = AES.new(key, AES.MODE_CBC, iv=iv)
|
||||
decrypted = cipher.decrypt(encrypted) # $ CryptographicOperation CryptographicOperationAlgorithm=AES CryptographicOperationInput=encrypted
|
||||
decrypted = cipher.decrypt(encrypted) # $ CryptographicOperation CryptographicOperationAlgorithm=AES CryptographicOperationInput=encrypted CryptographicOperationBlockMode=CBC
|
||||
|
||||
decrypted = decrypted[:-padding_len]
|
||||
|
||||
|
||||
@@ -21,14 +21,14 @@ padding = b"\0"*padding_len
|
||||
cipher = AES.new(key, AES.MODE_CBC, iv=iv)
|
||||
# using separate .encrypt calls on individual lines does not work
|
||||
whole_plantext = secret_message + padding
|
||||
encrypted = cipher.encrypt(whole_plantext) # $ CryptographicOperation CryptographicOperationAlgorithm=AES CryptographicOperationInput=whole_plantext
|
||||
encrypted = cipher.encrypt(whole_plantext) # $ CryptographicOperation CryptographicOperationAlgorithm=AES CryptographicOperationInput=whole_plantext CryptographicOperationBlockMode=CBC
|
||||
|
||||
print("encrypted={}".format(encrypted))
|
||||
|
||||
print()
|
||||
|
||||
cipher = AES.new(key, AES.MODE_CBC, iv=iv)
|
||||
decrypted = cipher.decrypt(encrypted) # $ CryptographicOperation CryptographicOperationAlgorithm=AES CryptographicOperationInput=encrypted
|
||||
decrypted = cipher.decrypt(encrypted) # $ CryptographicOperation CryptographicOperationAlgorithm=AES CryptographicOperationInput=encrypted CryptographicOperationBlockMode=CBC
|
||||
|
||||
decrypted = decrypted[:-padding_len]
|
||||
|
||||
|
||||
@@ -22,8 +22,8 @@ padding = b"\0"*padding_len
|
||||
|
||||
encryptor = cipher.encryptor()
|
||||
print(padding_len)
|
||||
encrypted = encryptor.update(secret_message) # $ CryptographicOperation CryptographicOperationAlgorithm=AES CryptographicOperationInput=secret_message
|
||||
encrypted += encryptor.update(padding) # $ CryptographicOperation CryptographicOperationAlgorithm=AES CryptographicOperationInput=padding
|
||||
encrypted = encryptor.update(secret_message) # $ CryptographicOperation CryptographicOperationAlgorithm=AES CryptographicOperationInput=secret_message CryptographicOperationBlockMode=CBC
|
||||
encrypted += encryptor.update(padding) # $ CryptographicOperation CryptographicOperationAlgorithm=AES CryptographicOperationInput=padding CryptographicOperationBlockMode=CBC
|
||||
encrypted += encryptor.finalize()
|
||||
|
||||
print("encrypted={}".format(encrypted))
|
||||
@@ -31,7 +31,7 @@ print("encrypted={}".format(encrypted))
|
||||
print()
|
||||
|
||||
decryptor = cipher.decryptor()
|
||||
decrypted = decryptor.update(encrypted) # $ CryptographicOperation CryptographicOperationAlgorithm=AES CryptographicOperationInput=encrypted
|
||||
decrypted = decryptor.update(encrypted) # $ CryptographicOperation CryptographicOperationAlgorithm=AES CryptographicOperationInput=encrypted CryptographicOperationBlockMode=CBC
|
||||
decrypted += decryptor.finalize()
|
||||
|
||||
decrypted = decrypted[:-padding_len]
|
||||
|
||||
103
python/ql/test/library-tests/frameworks/data/test.expected
Normal file
103
python/ql/test/library-tests/frameworks/data/test.expected
Normal file
@@ -0,0 +1,103 @@
|
||||
taintFlow
|
||||
| test.py:3:5:3:15 | ControlFlowNode for getSource() | test.py:4:8:4:8 | ControlFlowNode for x |
|
||||
| test.py:3:5:3:15 | ControlFlowNode for getSource() | test.py:7:17:7:17 | ControlFlowNode for x |
|
||||
| test.py:9:8:9:14 | ControlFlowNode for alias() | test.py:9:8:9:14 | ControlFlowNode for alias() |
|
||||
| test.py:10:8:10:22 | ControlFlowNode for Attribute() | test.py:10:8:10:22 | ControlFlowNode for Attribute() |
|
||||
| test.py:11:8:11:30 | ControlFlowNode for Attribute() | test.py:11:8:11:30 | ControlFlowNode for Attribute() |
|
||||
| test.py:71:28:71:38 | ControlFlowNode for getSource() | test.py:71:8:71:39 | ControlFlowNode for Attribute() |
|
||||
| test.py:75:5:75:15 | ControlFlowNode for getSource() | test.py:76:22:76:22 | ControlFlowNode for x |
|
||||
| test.py:75:5:75:15 | ControlFlowNode for getSource() | test.py:77:22:77:22 | ControlFlowNode for y |
|
||||
| test.py:81:36:81:46 | ControlFlowNode for getSource() | test.py:81:8:81:47 | ControlFlowNode for Attribute() |
|
||||
| test.py:83:50:83:60 | ControlFlowNode for getSource() | test.py:83:8:83:61 | ControlFlowNode for Attribute() |
|
||||
| test.py:86:49:86:59 | ControlFlowNode for getSource() | test.py:86:8:86:60 | ControlFlowNode for Attribute() |
|
||||
| test.py:87:56:87:66 | ControlFlowNode for getSource() | test.py:87:8:87:67 | ControlFlowNode for Attribute() |
|
||||
isSink
|
||||
| test.py:4:8:4:8 | ControlFlowNode for x | test-sink |
|
||||
| test.py:7:17:7:17 | ControlFlowNode for x | test-sink |
|
||||
| test.py:9:8:9:14 | ControlFlowNode for alias() | test-sink |
|
||||
| test.py:10:8:10:22 | ControlFlowNode for Attribute() | test-sink |
|
||||
| test.py:11:8:11:30 | ControlFlowNode for Attribute() | test-sink |
|
||||
| test.py:12:8:12:34 | ControlFlowNode for Attribute() | test-sink |
|
||||
| test.py:16:11:16:13 | ControlFlowNode for one | test-sink |
|
||||
| test.py:17:19:17:21 | ControlFlowNode for two | test-sink |
|
||||
| test.py:17:24:17:28 | ControlFlowNode for three | test-sink |
|
||||
| test.py:17:31:17:34 | ControlFlowNode for four | test-sink |
|
||||
| test.py:18:37:18:40 | ControlFlowNode for five | test-sink |
|
||||
| test.py:19:21:19:26 | ControlFlowNode for second | test-sink |
|
||||
| test.py:30:21:30:23 | ControlFlowNode for one | test-sink |
|
||||
| test.py:32:22:32:24 | ControlFlowNode for one | test-sink |
|
||||
| test.py:32:27:32:29 | ControlFlowNode for two | test-sink |
|
||||
| test.py:33:22:33:24 | ControlFlowNode for one | test-sink |
|
||||
| test.py:33:27:33:29 | ControlFlowNode for two | test-sink |
|
||||
| test.py:33:32:33:36 | ControlFlowNode for three | test-sink |
|
||||
| test.py:57:27:57:33 | ControlFlowNode for arg_pos | test-sink |
|
||||
| test.py:66:17:66:20 | ControlFlowNode for arg1 | test-sink |
|
||||
| test.py:66:23:66:26 | ControlFlowNode for arg2 | test-sink |
|
||||
| test.py:66:34:66:43 | ControlFlowNode for namedThing | test-sink |
|
||||
| test.py:67:34:67:44 | ControlFlowNode for secondNamed | test-sink |
|
||||
| test.py:71:8:71:39 | ControlFlowNode for Attribute() | test-sink |
|
||||
| test.py:72:8:72:47 | ControlFlowNode for Attribute() | test-sink |
|
||||
| test.py:76:22:76:22 | ControlFlowNode for x | test-sink |
|
||||
| test.py:77:22:77:22 | ControlFlowNode for y | test-sink |
|
||||
| test.py:78:22:78:22 | ControlFlowNode for z | test-sink |
|
||||
| test.py:81:8:81:47 | ControlFlowNode for Attribute() | test-sink |
|
||||
| test.py:82:8:82:54 | ControlFlowNode for Attribute() | test-sink |
|
||||
| test.py:83:8:83:61 | ControlFlowNode for Attribute() | test-sink |
|
||||
| test.py:85:8:85:53 | ControlFlowNode for Attribute() | test-sink |
|
||||
| test.py:86:8:86:60 | ControlFlowNode for Attribute() | test-sink |
|
||||
| test.py:87:8:87:67 | ControlFlowNode for Attribute() | test-sink |
|
||||
| test.py:89:21:89:23 | ControlFlowNode for one | test-sink |
|
||||
| test.py:91:21:91:23 | ControlFlowNode for one | test-sink |
|
||||
| test.py:91:30:91:32 | ControlFlowNode for two | test-sink |
|
||||
| test.py:98:6:98:9 | ControlFlowNode for baz2 | test-sink |
|
||||
isSource
|
||||
| test.py:3:5:3:15 | ControlFlowNode for getSource() | test-source |
|
||||
| test.py:9:8:9:14 | ControlFlowNode for alias() | test-source |
|
||||
| test.py:10:8:10:14 | ControlFlowNode for alias() | test-source |
|
||||
| test.py:10:8:10:22 | ControlFlowNode for Attribute() | test-source |
|
||||
| test.py:11:8:11:14 | ControlFlowNode for alias() | test-source |
|
||||
| test.py:11:8:11:22 | ControlFlowNode for Attribute() | test-source |
|
||||
| test.py:11:8:11:30 | ControlFlowNode for Attribute() | test-source |
|
||||
| test.py:12:8:12:14 | ControlFlowNode for alias() | test-source |
|
||||
| test.py:12:8:12:22 | ControlFlowNode for Attribute() | test-source |
|
||||
| test.py:23:24:23:26 | ControlFlowNode for one | test-source |
|
||||
| test.py:24:33:24:35 | ControlFlowNode for two | test-source |
|
||||
| test.py:24:38:24:42 | ControlFlowNode for three | test-source |
|
||||
| test.py:24:45:24:48 | ControlFlowNode for four | test-source |
|
||||
| test.py:25:34:25:39 | ControlFlowNode for second | test-source |
|
||||
| test.py:39:11:39:20 | ControlFlowNode for Await | test-source |
|
||||
| test.py:41:8:41:27 | ControlFlowNode for Attribute() | test-source |
|
||||
| test.py:46:7:46:16 | ControlFlowNode for SubClass() | test-source |
|
||||
| test.py:53:7:53:16 | ControlFlowNode for Attribute() | test-source |
|
||||
| test.py:60:13:60:16 | ControlFlowNode for self | test-source |
|
||||
| test.py:60:24:60:28 | ControlFlowNode for named | test-source |
|
||||
| test.py:63:36:63:39 | ControlFlowNode for arg2 | test-source |
|
||||
| test.py:63:42:63:45 | ControlFlowNode for arg3 | test-source |
|
||||
| test.py:63:48:63:51 | ControlFlowNode for arg4 | test-source |
|
||||
| test.py:63:54:63:57 | ControlFlowNode for arg5 | test-source |
|
||||
| test.py:71:28:71:38 | ControlFlowNode for getSource() | test-source |
|
||||
| test.py:72:36:72:46 | ControlFlowNode for getSource() | test-source |
|
||||
| test.py:75:5:75:15 | ControlFlowNode for getSource() | test-source |
|
||||
| test.py:81:36:81:46 | ControlFlowNode for getSource() | test-source |
|
||||
| test.py:82:43:82:53 | ControlFlowNode for getSource() | test-source |
|
||||
| test.py:83:50:83:60 | ControlFlowNode for getSource() | test-source |
|
||||
| test.py:85:42:85:52 | ControlFlowNode for getSource() | test-source |
|
||||
| test.py:86:49:86:59 | ControlFlowNode for getSource() | test-source |
|
||||
| test.py:87:56:87:66 | ControlFlowNode for getSource() | test-source |
|
||||
| test.py:101:29:101:31 | ControlFlowNode for arg | test-source |
|
||||
| test.py:104:24:104:29 | ControlFlowNode for param1 | test-source |
|
||||
| test.py:104:32:104:37 | ControlFlowNode for param2 | test-source |
|
||||
| test.py:107:24:107:28 | ControlFlowNode for name1 | test-source |
|
||||
| test.py:107:31:107:35 | ControlFlowNode for name2 | test-source |
|
||||
syntaxErrors
|
||||
| Member[foo |
|
||||
| Member[foo] .Member[bar] |
|
||||
| Member[foo] Member[bar] |
|
||||
| Member[foo], Member[bar] |
|
||||
| Member[foo],Member[bar] |
|
||||
| Member[foo]. Member[bar] |
|
||||
| Member[foo]..Member[bar] |
|
||||
| Member[foo]Member[bar] |
|
||||
| Member[foo]] |
|
||||
| Member[foo]].Member[bar] |
|
||||
warning
|
||||
108
python/ql/test/library-tests/frameworks/data/test.py
Normal file
108
python/ql/test/library-tests/frameworks/data/test.py
Normal file
@@ -0,0 +1,108 @@
|
||||
from testlib import getSource, mySink, alias
|
||||
|
||||
x = getSource()
|
||||
mySink(x)
|
||||
|
||||
mySink(foo=x) # OK
|
||||
mySink(sinkName=x) # NOT OK
|
||||
|
||||
mySink(alias()) # NOT OK
|
||||
mySink(alias().chain()) # NOT OK
|
||||
mySink(alias().chain().chain()) # NOT OK
|
||||
mySink(alias().chain().safeThing()) # OK
|
||||
|
||||
from testlib import Args
|
||||
|
||||
Args.arg0(one, two, three, four, five)
|
||||
Args.arg1to3(one, two, three, four, five)
|
||||
Args.lastarg(one, two, three, four, five)
|
||||
Args.nonFist(first, second)
|
||||
|
||||
from testlib import Callbacks
|
||||
|
||||
Callbacks.first(lambda one, two, three, four, five: 0)
|
||||
Callbacks.param1to3(lambda one, two, three, four, five: 0)
|
||||
Callbacks.nonFirst(lambda first, second: 0)
|
||||
|
||||
from testlib import CallFilter
|
||||
|
||||
CallFilter.arityOne(one, two) # NO match
|
||||
CallFilter.arityOne(one) # Match
|
||||
CallFilter.twoOrMore(one) # NO match
|
||||
CallFilter.twoOrMore(one, two) # Match
|
||||
CallFilter.twoOrMore(one, two, three) # Match
|
||||
|
||||
from testlib import CommonTokens
|
||||
|
||||
async def async_func():
|
||||
prom = CommonTokens.makePromise(1);
|
||||
val = await prom
|
||||
|
||||
inst = CommonTokens.Class()
|
||||
|
||||
class SubClass (CommonTokens.Super):
|
||||
pass
|
||||
|
||||
sub = SubClass()
|
||||
|
||||
class Sub2Class (CommonTokens.Class):
|
||||
pass
|
||||
|
||||
sub2 = Sub2Class() # TODO: Currently not recognized as an instance of CommonTokens.Class
|
||||
|
||||
val = inst.foo()
|
||||
|
||||
from testlib import ArgPos
|
||||
|
||||
arg_pos = ArgPos(); val = arg_pos.self_thing(arg, named=2);
|
||||
|
||||
class SubClass (ArgPos.MyClass):
|
||||
def foo(self, arg, named=2, otherName=3):
|
||||
pass
|
||||
|
||||
def secondAndAfter(self, arg1, arg2, arg3, arg4, arg5):
|
||||
pass
|
||||
|
||||
ArgPos.anyParam(arg1, arg2, name=namedThing)
|
||||
ArgPos.anyNamed(arg4, arg5, name=secondNamed)
|
||||
|
||||
from testlib import Steps
|
||||
|
||||
mySink(Steps.preserveTaint(getSource())) # FLOW
|
||||
mySink(Steps.preserveTaint("safe", getSource())) # NO FLOW
|
||||
|
||||
Steps.taintIntoCallback(
|
||||
getSource(),
|
||||
lambda x: mySink(x), # FLOW
|
||||
lambda y: mySink(y), # FLOW
|
||||
lambda z: mySink(z) # NO FLOW
|
||||
)
|
||||
|
||||
mySink(Steps.preserveArgZeroAndTwo(getSource())) # FLOW
|
||||
mySink(Steps.preserveArgZeroAndTwo("foo", getSource())) # NO FLOW
|
||||
mySink(Steps.preserveArgZeroAndTwo("foo", "bar", getSource())) # FLOW
|
||||
|
||||
mySink(Steps.preserveAllButFirstArgument(getSource())) # NO FLOW
|
||||
mySink(Steps.preserveAllButFirstArgument("foo", getSource())) # FLOW
|
||||
mySink(Steps.preserveAllButFirstArgument("foo", "bar", getSource())) # FLOW
|
||||
|
||||
CallFilter.arityOne(one) # match
|
||||
CallFilter.arityOne(one=one) # NO match
|
||||
CallFilter.arityOne(one, two=two) # match - on both the named and positional arguments
|
||||
CallFilter.arityOne(one=one, two=two) # NO match
|
||||
|
||||
from foo1.bar import baz1
|
||||
baz1(baz1) # no match, and that's the point.
|
||||
|
||||
from foo2.bar import baz2
|
||||
baz2(baz2) # match
|
||||
|
||||
class OtherSubClass (ArgPos.MyClass):
|
||||
def otherSelfTest(self, arg, named=2, otherName=3): # test that Parameter[0] hits `arg`.
|
||||
pass
|
||||
|
||||
def anyParam(self, param1, param2): # Parameter[any] matches all non-self parameters
|
||||
pass
|
||||
|
||||
def anyNamed(self, name1, name2=2): # Parameter[any-named] matches all non-self named parameters
|
||||
pass
|
||||
127
python/ql/test/library-tests/frameworks/data/test.ql
Normal file
127
python/ql/test/library-tests/frameworks/data/test.ql
Normal file
@@ -0,0 +1,127 @@
|
||||
import python
|
||||
import semmle.python.frameworks.data.internal.AccessPathSyntax as AccessPathSyntax
|
||||
import semmle.python.frameworks.data.ModelsAsData
|
||||
import semmle.python.dataflow.new.TaintTracking
|
||||
import semmle.python.dataflow.new.DataFlow
|
||||
private import semmle.python.ApiGraphs
|
||||
|
||||
class Steps extends ModelInput::SummaryModelCsv {
|
||||
override predicate row(string row) {
|
||||
// package;type;path;input;output;kind
|
||||
row =
|
||||
[
|
||||
"testlib;;Member[Steps].Member[preserveTaint].Call;Argument[0];ReturnValue;taint",
|
||||
"testlib;;Member[Steps].Member[taintIntoCallback];Argument[0];Argument[1..2].Parameter[0];taint",
|
||||
"testlib;;Member[Steps].Member[preserveArgZeroAndTwo];Argument[0,2];ReturnValue;taint",
|
||||
"testlib;;Member[Steps].Member[preserveAllButFirstArgument].Call;Argument[1..];ReturnValue;taint",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
class Types extends ModelInput::TypeModelCsv {
|
||||
override predicate row(string row) {
|
||||
// package1;type1;package2;type2;path
|
||||
row =
|
||||
[
|
||||
"testlib;Alias;testlib;;Member[alias].ReturnValue",
|
||||
"testlib;Alias;testlib;Alias;Member[chain].ReturnValue",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
class Sinks extends ModelInput::SinkModelCsv {
|
||||
override predicate row(string row) {
|
||||
// package;type;path;kind
|
||||
row =
|
||||
[
|
||||
"testlib;;Member[mySink].Argument[0,sinkName:];test-sink",
|
||||
// testing argument syntax
|
||||
"testlib;;Member[Args].Member[arg0].Argument[0];test-sink", //
|
||||
"testlib;;Member[Args].Member[arg1to3].Argument[1..3];test-sink", //
|
||||
"testlib;;Member[Args].Member[lastarg].Argument[N-1];test-sink", //
|
||||
"testlib;;Member[Args].Member[nonFist].Argument[1..];test-sink", //
|
||||
// callsite filter.
|
||||
"testlib;;Member[CallFilter].Member[arityOne].WithArity[1].Argument[any];test-sink", //
|
||||
"testlib;;Member[CallFilter].Member[twoOrMore].WithArity[2..].Argument[0..];test-sink", //
|
||||
// testing non-positional arguments
|
||||
"testlib;;Member[ArgPos].Instance.Member[self_thing].Argument[self];test-sink", //
|
||||
// any argument
|
||||
"testlib;;Member[ArgPos].Member[anyParam].Argument[any];test-sink", //
|
||||
"testlib;;Member[ArgPos].Member[anyNamed].Argument[any-named];test-sink", //
|
||||
// testing package syntax
|
||||
"foo1.bar;;Member[baz1].Argument[any];test-sink", //
|
||||
"foo2;;Member[bar].Member[baz2].Argument[any];test-sink", //
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
class Sources extends ModelInput::SourceModelCsv {
|
||||
// package;type;path;kind
|
||||
override predicate row(string row) {
|
||||
row =
|
||||
[
|
||||
"testlib;;Member[getSource].ReturnValue;test-source", //
|
||||
"testlib;Alias;;test-source",
|
||||
// testing parameter syntax
|
||||
"testlib;;Member[Callbacks].Member[first].Argument[0].Parameter[0];test-source", //
|
||||
"testlib;;Member[Callbacks].Member[param1to3].Argument[0].Parameter[1..3];test-source", //
|
||||
"testlib;;Member[Callbacks].Member[nonFirst].Argument[0].Parameter[1..];test-source", //
|
||||
// Common tokens.
|
||||
"testlib;;Member[CommonTokens].Member[makePromise].ReturnValue.Awaited;test-source", //
|
||||
"testlib;;Member[CommonTokens].Member[Class].Instance;test-source", //
|
||||
"testlib;;Member[CommonTokens].Member[Super].Subclass.Instance;test-source", //
|
||||
// method
|
||||
"testlib;;Member[CommonTokens].Member[Class].Instance.Method[foo];test-source", //
|
||||
// testing non-positional arguments
|
||||
"testlib;;Member[ArgPos].Member[MyClass].Subclass.Member[foo].Parameter[self];test-source", //
|
||||
"testlib;;Member[ArgPos].Member[MyClass].Subclass.Member[foo].Parameter[named:];test-source", //
|
||||
"testlib;;Member[ArgPos].Member[MyClass].Subclass.Member[secondAndAfter].Parameter[1..];test-source", //
|
||||
"testlib;;Member[ArgPos].Member[MyClass].Subclass.Member[otherSelfTest].Parameter[0];test-source", //
|
||||
"testlib;;Member[ArgPos].Member[MyClass].Subclass.Member[anyParam].Parameter[any];test-source", //
|
||||
"testlib;;Member[ArgPos].Member[MyClass].Subclass.Member[anyNamed].Parameter[any-named];test-source", //
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
class BasicTaintTracking extends TaintTracking::Configuration {
|
||||
BasicTaintTracking() { this = "BasicTaintTracking" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
source = ModelOutput::getASourceNode("test-source").getAnImmediateUse()
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
sink = ModelOutput::getASinkNode("test-sink").getARhs()
|
||||
}
|
||||
}
|
||||
|
||||
query predicate taintFlow(DataFlow::Node source, DataFlow::Node sink) {
|
||||
any(BasicTaintTracking tr).hasFlow(source, sink)
|
||||
}
|
||||
|
||||
query predicate isSink(DataFlow::Node node, string kind) {
|
||||
node = ModelOutput::getASinkNode(kind).getARhs()
|
||||
}
|
||||
|
||||
query predicate isSource(DataFlow::Node node, string kind) {
|
||||
node = ModelOutput::getASourceNode(kind).getAnImmediateUse()
|
||||
}
|
||||
|
||||
class SyntaxErrorTest extends ModelInput::SinkModelCsv {
|
||||
override predicate row(string row) {
|
||||
row =
|
||||
[
|
||||
"testlib;;Member[foo],Member[bar];test-sink", "testlib;;Member[foo] Member[bar];test-sink",
|
||||
"testlib;;Member[foo]. Member[bar];test-sink",
|
||||
"testlib;;Member[foo], Member[bar];test-sink",
|
||||
"testlib;;Member[foo]..Member[bar];test-sink",
|
||||
"testlib;;Member[foo] .Member[bar];test-sink", "testlib;;Member[foo]Member[bar];test-sink",
|
||||
"testlib;;Member[foo;test-sink", "testlib;;Member[foo]];test-sink",
|
||||
"testlib;;Member[foo]].Member[bar];test-sink"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
query predicate syntaxErrors(AccessPathSyntax::AccessPath path) { path.hasSyntaxError() }
|
||||
|
||||
query predicate warning = ModelOutput::getAWarning/0;
|
||||
@@ -0,0 +1,7 @@
|
||||
| CSV type row should have 5 columns but has 2: test;TooFewColumns |
|
||||
| CSV type row should have 5 columns but has 8: test;TooManyColumns;;;Member[Foo].Instance;too;many;columns |
|
||||
| Invalid argument '0-1' in token 'Argument[0-1]' in access path: Method[foo].Argument[0-1] |
|
||||
| Invalid argument '*' in token 'Argument[*]' in access path: Method[foo].Argument[*] |
|
||||
| Invalid token 'Argument' is missing its arguments, in access path: Method[foo].Argument |
|
||||
| Invalid token 'Member' is missing its arguments, in access path: Method[foo].Member |
|
||||
| Invalid token name 'Arg' in access path: Method[foo].Arg[0] |
|
||||
25
python/ql/test/library-tests/frameworks/data/warnings.ql
Normal file
25
python/ql/test/library-tests/frameworks/data/warnings.ql
Normal file
@@ -0,0 +1,25 @@
|
||||
import python
|
||||
import semmle.python.frameworks.data.internal.AccessPathSyntax as AccessPathSyntax
|
||||
import semmle.python.frameworks.data.internal.ApiGraphModels as ApiGraphModels
|
||||
import semmle.python.frameworks.data.ModelsAsData
|
||||
|
||||
private class InvalidTypeModel extends ModelInput::TypeModelCsv {
|
||||
override predicate row(string row) {
|
||||
row =
|
||||
[
|
||||
"test;TooManyColumns;;;Member[Foo].Instance;too;many;columns", //
|
||||
"test;TooFewColumns", //
|
||||
"test;X;test;Y;Method[foo].Arg[0]", //
|
||||
"test;X;test;Y;Method[foo].Argument[0-1]", //
|
||||
"test;X;test;Y;Method[foo].Argument[*]", //
|
||||
"test;X;test;Y;Method[foo].Argument", //
|
||||
"test;X;test;Y;Method[foo].Member", //
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
class IsTesting extends ApiGraphModels::TestAllModels {
|
||||
IsTesting() { this = this }
|
||||
}
|
||||
|
||||
query predicate warning = ModelOutput::getAWarning/0;
|
||||
@@ -71,6 +71,7 @@ def test_taint(request: HttpRequest, foo, bar, baz=None): # $requestHandler rou
|
||||
request.FILES["key"].name, # $ tainted
|
||||
request.FILES["key"].file, # $ tainted
|
||||
request.FILES["key"].file.read(), # $ tainted
|
||||
request.FILES["key"].read(), # $ tainted
|
||||
|
||||
request.FILES.get("key"), # $ tainted
|
||||
request.FILES.get("key").name, # $ tainted
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import httpx
|
||||
import ssl
|
||||
|
||||
httpx.get("url") # $ clientRequestUrlPart="url"
|
||||
httpx.post("url") # $ clientRequestUrlPart="url"
|
||||
@@ -15,10 +16,30 @@ response = client.options("url") # $ clientRequestUrlPart="url"
|
||||
response = client.request("method", url="url") # $ clientRequestUrlPart="url"
|
||||
response = client.stream("method", url="url") # $ clientRequestUrlPart="url"
|
||||
|
||||
client = httpx.AsyncClient()
|
||||
response = client.get("url") # $ clientRequestUrlPart="url"
|
||||
response = client.post("url") # $ clientRequestUrlPart="url"
|
||||
response = client.patch("url") # $ clientRequestUrlPart="url"
|
||||
response = client.options("url") # $ clientRequestUrlPart="url"
|
||||
response = client.request("method", url="url") # $ clientRequestUrlPart="url"
|
||||
response = client.stream("method", url="url") # $ clientRequestUrlPart="url"
|
||||
async def async_test():
|
||||
client = httpx.AsyncClient()
|
||||
response = await client.get("url") # $ clientRequestUrlPart="url"
|
||||
response = await client.post("url") # $ clientRequestUrlPart="url"
|
||||
response = await client.patch("url") # $ clientRequestUrlPart="url"
|
||||
response = await client.options("url") # $ clientRequestUrlPart="url"
|
||||
response = await client.request("method", url="url") # $ clientRequestUrlPart="url"
|
||||
response = await client.stream("method", url="url") # $ clientRequestUrlPart="url"
|
||||
|
||||
# ==============================================================================
|
||||
# Disabling certificate validation
|
||||
# ==============================================================================
|
||||
|
||||
httpx.get("url", verify=False) # $ clientRequestUrlPart="url" clientRequestCertValidationDisabled
|
||||
httpx.get("url", verify=0) # $ clientRequestUrlPart="url" clientRequestCertValidationDisabled
|
||||
httpx.get("url", verify=None) # $ clientRequestUrlPart="url" clientRequestCertValidationDisabled
|
||||
|
||||
# A manually constructed SSLContext does not have safe defaults, so is effectively the
|
||||
# same as turning off SSL validation
|
||||
context = ssl.SSLContext()
|
||||
assert context.check_hostname == False
|
||||
assert context.verify_mode == ssl.VerifyMode.CERT_NONE
|
||||
|
||||
httpx.get("url", verify=context) # $ clientRequestUrlPart="url" MISSING: clientRequestCertValidationDisabled
|
||||
|
||||
client = httpx.Client(verify=False)
|
||||
client.get("url") # $ clientRequestUrlPart="url" clientRequestCertValidationDisabled
|
||||
|
||||
@@ -33,6 +33,10 @@ resp = requests.options("url") # $ clientRequestUrlPart="url"
|
||||
# ==============================================================================
|
||||
|
||||
resp = requests.get("url", verify=False) # $ clientRequestUrlPart="url" clientRequestCertValidationDisabled
|
||||
resp = requests.get("url", verify=0) # $ clientRequestUrlPart="url" clientRequestCertValidationDisabled
|
||||
|
||||
# in reuqests, using `verify=None` is just the default value, so does NOT turn off certificate validation
|
||||
resp = requests.get("url", verify=None) # $ clientRequestUrlPart="url"
|
||||
|
||||
def make_get(verify_arg):
|
||||
resp = requests.get("url", verify=verify_arg) # $ clientRequestUrlPart="url" clientRequestCertValidationDisabled
|
||||
|
||||
@@ -1,7 +1,20 @@
|
||||
import urllib2
|
||||
import ssl
|
||||
|
||||
resp = urllib2.Request("url") # $ clientRequestUrlPart="url"
|
||||
resp = urllib2.Request(url="url") # $ clientRequestUrlPart="url"
|
||||
|
||||
resp = urllib2.urlopen("url") # $ clientRequestUrlPart="url"
|
||||
resp = urllib2.urlopen(url="url") # $ clientRequestUrlPart="url"
|
||||
resp = urllib2.urlopen(url="url") # $ clientRequestUrlPart="url"
|
||||
|
||||
# ==============================================================================
|
||||
# Certificate validation disabled
|
||||
# ==============================================================================
|
||||
|
||||
# A manually constructed SSLContext does not have safe defaults, so is effectively the
|
||||
# same as turning off SSL validation
|
||||
context = ssl.SSLContext()
|
||||
assert context.check_hostname == False
|
||||
assert context.verify_mode == ssl.VerifyMode.CERT_NONE
|
||||
|
||||
urllib2.urlopen("url", context=context) # $ clientRequestUrlPart="url" MISSING: clientRequestCertValidationDisabled
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
s = "taintedString"
|
||||
|
||||
if s.startswith("tainted"): # $checks=s branch=true
|
||||
if s.startswith("tainted"):
|
||||
s2 = s # $SafeAccessCheck=s
|
||||
pass
|
||||
|
||||
sw = s.startswith
|
||||
if sw("safe"): # $ MISSING: checks=s branch=true
|
||||
if sw("safe"):
|
||||
s2 = s # $ MISSING: SafeAccessCheck=s
|
||||
pass
|
||||
|
||||
@@ -1,7 +1,20 @@
|
||||
import ssl
|
||||
from urllib.request import Request, urlopen
|
||||
|
||||
Request("url") # $ clientRequestUrlPart="url"
|
||||
Request(url="url") # $ clientRequestUrlPart="url"
|
||||
|
||||
urlopen("url") # $ clientRequestUrlPart="url"
|
||||
urlopen(url="url") # $ clientRequestUrlPart="url"
|
||||
urlopen(url="url") # $ clientRequestUrlPart="url"
|
||||
|
||||
# ==============================================================================
|
||||
# Certificate validation disabled
|
||||
# ==============================================================================
|
||||
|
||||
# A manually constructed SSLContext does not have safe defaults, so is effectively the
|
||||
# same as turning off SSL validation
|
||||
context = ssl.SSLContext()
|
||||
assert context.check_hostname == False
|
||||
assert context.verify_mode == ssl.VerifyMode.CERT_NONE
|
||||
|
||||
urlopen("url", context=context) # $ clientRequestUrlPart="url" MISSING: clientRequestCertValidationDisabled
|
||||
|
||||
@@ -27,3 +27,33 @@ resp = pool.request("method", "url") # $ clientRequestUrlPart="url"
|
||||
resp = pool.request("method", url="url") # $ clientRequestUrlPart="url"
|
||||
resp = pool.urlopen("method", "url") # $ clientRequestUrlPart="url"
|
||||
resp = pool.urlopen("method", url="url") # $ clientRequestUrlPart="url"
|
||||
|
||||
# ==============================================================================
|
||||
# Certificate validation disabled
|
||||
# ==============================================================================
|
||||
|
||||
# see https://docs.python.org/3.10/library/ssl.html#ssl.CERT_NONE
|
||||
pool = urllib3.HTTPSConnectionPool("host", cert_reqs='CERT_NONE')
|
||||
resp = pool.request("method", "url") # $ clientRequestUrlPart="url" clientRequestCertValidationDisabled
|
||||
|
||||
pool = urllib3.HTTPSConnectionPool("host", assert_hostname=False)
|
||||
resp = pool.request("method", "url") # $ clientRequestUrlPart="url" clientRequestCertValidationDisabled
|
||||
|
||||
pool = urllib3.HTTPSConnectionPool("host", cert_reqs='CERT_NONE', assert_hostname=False)
|
||||
resp = pool.request("method", "url") # $ clientRequestUrlPart="url" clientRequestCertValidationDisabled
|
||||
|
||||
|
||||
# same with PoolManager
|
||||
pool = urllib3.PoolManager(cert_reqs='CERT_NONE')
|
||||
resp = pool.request("method", "url") # $ clientRequestUrlPart="url" clientRequestCertValidationDisabled
|
||||
|
||||
pool = urllib3.PoolManager(assert_hostname=False)
|
||||
resp = pool.request("method", "url") # $ clientRequestUrlPart="url" clientRequestCertValidationDisabled
|
||||
|
||||
|
||||
# and same with ProxyManager
|
||||
pool = urllib3.ProxyManager("https://proxy", cert_reqs='CERT_NONE')
|
||||
resp = pool.request("method", "url") # $ clientRequestUrlPart="url" clientRequestCertValidationDisabled
|
||||
|
||||
pool = urllib3.ProxyManager("https://proxy", assert_hostname=False)
|
||||
resp = pool.request("method", "url") # $ clientRequestUrlPart="url" clientRequestCertValidationDisabled
|
||||
|
||||
@@ -2,4 +2,5 @@
|
||||
| jinja2_escaping.py:41:5:41:29 | ControlFlowNode for Environment() | Using jinja2 templates with autoescape=False can potentially allow XSS attacks. |
|
||||
| jinja2_escaping.py:43:1:43:3 | ControlFlowNode for E() | Using jinja2 templates with autoescape=False can potentially allow XSS attacks. |
|
||||
| jinja2_escaping.py:44:1:44:15 | ControlFlowNode for E() | Using jinja2 templates with autoescape=False can potentially allow XSS attacks. |
|
||||
| jinja2_escaping.py:50:13:50:40 | ControlFlowNode for Environment() | Using jinja2 templates with autoescape=False can potentially allow XSS attacks. |
|
||||
| jinja2_escaping.py:53:15:53:43 | ControlFlowNode for Template() | Using jinja2 templates with autoescape=False can potentially allow XSS attacks. |
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
| pam_test.py:48:18:48:44 | ControlFlowNode for pam_authenticate() | This PAM authentication call may lead to an authorization bypass, since 'pam_acct_mgmt' is not called afterwards. |
|
||||
@@ -0,0 +1 @@
|
||||
Security/CWE-285/PamAuthorization.ql
|
||||
@@ -1,5 +1,6 @@
|
||||
| make_request.py:5:1:5:48 | ControlFlowNode for Attribute() | Call to requests.get with verify=$@ | make_request.py:5:43:5:47 | ControlFlowNode for False | False |
|
||||
| make_request.py:7:1:7:49 | ControlFlowNode for Attribute() | Call to requests.post with verify=$@ | make_request.py:7:44:7:48 | ControlFlowNode for False | False |
|
||||
| make_request.py:12:1:12:39 | ControlFlowNode for put() | Call to requests.put with verify=$@ | make_request.py:12:34:12:38 | ControlFlowNode for False | False |
|
||||
| make_request.py:28:5:28:46 | ControlFlowNode for patch() | Call to requests.patch with verify=$@ | make_request.py:30:6:30:10 | ControlFlowNode for False | False |
|
||||
| make_request.py:34:1:34:45 | ControlFlowNode for Attribute() | Call to requests.post with verify=$@ | make_request.py:34:44:34:44 | ControlFlowNode for IntegerLiteral | False |
|
||||
| make_request.py:5:1:5:48 | ControlFlowNode for Attribute() | This request may run without certificate validation because it is $@. | make_request.py:5:43:5:47 | ControlFlowNode for False | disabled here | make_request.py:5:43:5:47 | ControlFlowNode for False | here |
|
||||
| make_request.py:7:1:7:49 | ControlFlowNode for Attribute() | This request may run without certificate validation because it is $@. | make_request.py:7:44:7:48 | ControlFlowNode for False | disabled here | make_request.py:7:44:7:48 | ControlFlowNode for False | here |
|
||||
| make_request.py:12:1:12:39 | ControlFlowNode for put() | This request may run without certificate validation because it is $@. | make_request.py:12:34:12:38 | ControlFlowNode for False | disabled here | make_request.py:12:34:12:38 | ControlFlowNode for False | here |
|
||||
| make_request.py:28:5:28:46 | ControlFlowNode for patch() | This request may run without certificate validation because it is $@ by the value from $@. | make_request.py:28:40:28:45 | ControlFlowNode for verify | disabled here | make_request.py:30:6:30:10 | ControlFlowNode for False | here |
|
||||
| make_request.py:34:1:34:45 | ControlFlowNode for Attribute() | This request may run without certificate validation because it is $@. | make_request.py:34:44:34:44 | ControlFlowNode for IntegerLiteral | disabled here | make_request.py:34:44:34:44 | ControlFlowNode for IntegerLiteral | here |
|
||||
| make_request.py:41:1:41:26 | ControlFlowNode for Attribute() | This request may run without certificate validation because it is $@. | make_request.py:41:21:41:25 | ControlFlowNode for False | disabled here | make_request.py:41:21:41:25 | ControlFlowNode for False | here |
|
||||
|
||||
@@ -36,3 +36,6 @@ requests.post('https://semmle.com', verify=0) # BAD
|
||||
# requests treat `None` as default value, which means it is turned on
|
||||
requests.get('https://semmle.com') # OK
|
||||
requests.get('https://semmle.com', verify=None) # OK
|
||||
|
||||
s = requests.Session()
|
||||
s.get("url", verify=False) # BAD
|
||||
|
||||
@@ -1,2 +1,4 @@
|
||||
| test_cryptodome.py:11:13:11:42 | ControlFlowNode for Attribute() | The cryptographic algorithm ARC4 is broken or weak, and should not be used. |
|
||||
| test_cryptodome.py:16:13:16:42 | ControlFlowNode for Attribute() | The block mode ECB is broken or weak, and should not be used. |
|
||||
| test_cryptography.py:13:13:13:44 | ControlFlowNode for Attribute() | The cryptographic algorithm ARC4 is broken or weak, and should not be used. |
|
||||
| test_cryptography.py:22:13:22:58 | ControlFlowNode for Attribute() | The block mode ECB is broken or weak, and should not be used. |
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# snippet from python/ql/test/experimental/library-tests/frameworks/cryptodome/test_rc4.py
|
||||
from Cryptodome.Cipher import ARC4
|
||||
from Cryptodome.Cipher import ARC4, AES
|
||||
|
||||
import os
|
||||
|
||||
@@ -11,3 +11,8 @@ cipher = ARC4.new(key)
|
||||
encrypted = cipher.encrypt(secret_message) # NOT OK
|
||||
|
||||
print(secret_message, encrypted)
|
||||
|
||||
cipher = AES.new(key, AES.MODE_ECB)
|
||||
encrypted = cipher.encrypt(secret_message) # NOT OK
|
||||
|
||||
print(secret_message, encrypted)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# snippet from python/ql/test/experimental/library-tests/frameworks/cryptography/test_rc4.py
|
||||
from cryptography.hazmat.primitives.ciphers import algorithms, Cipher
|
||||
from cryptography.hazmat.primitives.ciphers import algorithms, modes, Cipher
|
||||
import os
|
||||
|
||||
key = os.urandom(256//8)
|
||||
@@ -14,3 +14,12 @@ encrypted = encryptor.update(secret_message) # NOT OK
|
||||
encrypted += encryptor.finalize()
|
||||
|
||||
print(secret_message, encrypted)
|
||||
|
||||
algorithm = algorithms.AES(key)
|
||||
cipher = Cipher(algorithm, mode=modes.ECB())
|
||||
|
||||
encryptor = cipher.encryptor()
|
||||
encrypted = encryptor.update(secret_message + b'\x80\x00') # NOT OK
|
||||
encrypted += encryptor.finalize()
|
||||
|
||||
print(secret_message, encrypted)
|
||||
|
||||
@@ -2,6 +2,5 @@
|
||||
| test.py:8:1:8:20 | ControlFlowNode for Attribute() | Overly permissive mask in chmod sets file to world writable. |
|
||||
| test.py:9:1:9:21 | ControlFlowNode for Attribute() | Overly permissive mask in chmod sets file to world writable. |
|
||||
| test.py:11:1:11:21 | ControlFlowNode for Attribute() | Overly permissive mask in chmod sets file to group readable. |
|
||||
| test.py:13:1:13:28 | ControlFlowNode for Attribute() | Overly permissive mask in chmod sets file to group writable. |
|
||||
| test.py:14:1:14:19 | ControlFlowNode for Attribute() | Overly permissive mask in chmod sets file to group writable. |
|
||||
| test.py:16:1:16:25 | ControlFlowNode for Attribute() | Overly permissive mask in open sets file to world readable. |
|
||||
|
||||
@@ -1 +1 @@
|
||||
semmle-extractor-options: --max-import-depth=2 -p ../lib
|
||||
semmle-extractor-options: --max-import-depth=2 -p ../lib --lang=3
|
||||
|
||||
@@ -61,8 +61,8 @@ def ok_assert_false(x):
|
||||
if x:
|
||||
assert 0==1, "Ok"
|
||||
|
||||
class TestCase:
|
||||
pass
|
||||
from unittest import TestCase
|
||||
|
||||
|
||||
class MyTest(TestCase):
|
||||
def test_ok_assert_in_test(self, x):
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
| test.py:36:21:36:33 | Comment # lgtm method | lgtm method | lgtm | test.py:36:1:36:33 | suppression range |
|
||||
| test.py:39:4:39:8 | Comment #noqa | noqa | lgtm | test.py:39:1:39:8 | suppression range |
|
||||
| test.py:40:4:40:9 | Comment # noqa | noqa | lgtm | test.py:40:1:40:9 | suppression range |
|
||||
| test.py:45:4:45:31 | Comment # noqa -- Some extra detail. | noqa -- Some extra detail. | lgtm | test.py:45:1:45:31 | suppression range |
|
||||
| test.py:50:34:50:117 | Comment # noqa: E501; (line too long) pylint: disable=invalid-name; lgtm [py/missing-equals] | noqa: E501; (line too long) pylint: disable=invalid-name; lgtm [py/missing-equals] | lgtm [py/missing-equals] | test.py:50:1:50:117 | suppression range |
|
||||
| test.py:52:4:52:67 | Comment # noqa: E501; (line too long) pylint: disable=invalid-name; lgtm | noqa: E501; (line too long) pylint: disable=invalid-name; lgtm | lgtm | test.py:52:1:52:67 | suppression range |
|
||||
| test.py:53:4:53:78 | Comment # random nonsense lgtm [py/missing-equals] and then some more commentary... | random nonsense lgtm [py/missing-equals] and then some more commentary... | lgtm [py/missing-equals] | test.py:53:1:53:78 | suppression range |
|
||||
|
||||
Reference in New Issue
Block a user