diff --git a/rules/python/security/avoid-mktemp-python.yml b/rules/python/security/avoid-mktemp-python.yml new file mode 100644 index 00000000..24104809 --- /dev/null +++ b/rules/python/security/avoid-mktemp-python.yml @@ -0,0 +1,37 @@ +id: avoid-mktemp-python +language: python +severity: warning +message: >- + The function `mktemp` is deprecated. When using this function, it is + possible for an attacker to modify the created file before the filename is + returned. Use `NamedTemporaryFile()` instead and pass it the + `delete=False` parameter. +note: >- + [CWE-377]: Insecure Temporary File + [OWASP A01:2021]: Broken Access Control + [REFERENCES] + https://docs.python.org/3/library/tempfile.html#tempfile.mktemp + https://owasp.org/Top10/A01_2021-Broken_Access_Control +utils: + match_mktemp: + kind: call + has: + kind: identifier + pattern: $R + inside: + stopBy: end + kind: expression_statement + follows: + stopBy: end + kind: import_from_statement + has: + stopBy: end + kind: dotted_name + field: name + has: + stopBy: end + kind: identifier + pattern: $R +rule: + all: + - matches: match_mktemp diff --git a/rules/python/security/python-couchbase-empty-password-python.yml b/rules/python/security/python-couchbase-empty-password-python.yml new file mode 100644 index 00000000..36ce1fcc --- /dev/null +++ b/rules/python/security/python-couchbase-empty-password-python.yml @@ -0,0 +1,72 @@ +id: python-couchbase-empty-password-python +language: python +severity: warning +message: >- + The application creates a database connection with an empty password. + This can lead to unauthorized access by either an internal or external + malicious actor. To prevent this vulnerability, enforce authentication + when connecting to a database by using environment variables to securely + provide credentials or retrieving them from a secure vault or HSM + (Hardware Security Module). +note: >- + [CWE-287]: Improper Authentication + [OWASP A07:2021]: Identification and Authentication Failures + [REFERENCES] + https://cheatsheetseries.owasp.org/cheatsheets/Secrets_Management_Cheat_Sheet.html +utils: + match_passwordauthenticator: + kind: call + all: + - has: + kind: identifier + pattern: $R + - has: + stopBy: neighbor + kind: argument_list + all: + - has: + stopBy: neighbor + kind: string + has: + stopBy: neighbor + kind: string_content + - has: + stopBy: neighbor + kind: string + not: + has: + stopBy: neighbor + kind: string_content + + inside: + stopBy: end + kind: expression_statement + follows: + stopBy: end + kind: import_from_statement + all: + - has: + stopBy: end + kind: dotted_name + field: module_name + all: + - has: + stopBy: end + kind: identifier + regex: couchbase_core + - has: + stopBy: end + kind: identifier + regex: cluster + - has: + stopBy: end + kind: dotted_name + field: name + has: + stopBy: end + kind: identifier + pattern: $R + regex: PasswordAuthenticator +rule: + all: + - matches: match_passwordauthenticator diff --git a/tests/__snapshots__/avoid-mktemp-python-snapshot.yml b/tests/__snapshots__/avoid-mktemp-python-snapshot.yml new file mode 100644 index 00000000..cea452c6 --- /dev/null +++ b/tests/__snapshots__/avoid-mktemp-python-snapshot.yml @@ -0,0 +1,30 @@ +id: avoid-mktemp-python +snapshots: + ? | + from tempfile import mktemp + ff = mktemp() + : labels: + - source: mktemp() + style: primary + start: 33 + end: 41 + - source: mktemp + style: secondary + start: 21 + end: 27 + - source: mktemp + style: secondary + start: 21 + end: 27 + - source: from tempfile import mktemp + style: secondary + start: 0 + end: 27 + - source: ff = mktemp() + style: secondary + start: 28 + end: 41 + - source: mktemp + style: secondary + start: 33 + end: 39 diff --git a/tests/__snapshots__/python-couchbase-empty-password-python-snapshot.yml b/tests/__snapshots__/python-couchbase-empty-password-python-snapshot.yml new file mode 100644 index 00000000..ad79989c --- /dev/null +++ b/tests/__snapshots__/python-couchbase-empty-password-python-snapshot.yml @@ -0,0 +1,118 @@ +id: python-couchbase-empty-password-python +snapshots: + ? | + import os + from couchbase.cluster import Cluster, ClusterOptions + from couchbase_core.cluster import PasswordAuthenticator + PasswordAuthenticator('username', '') + : labels: + - source: PasswordAuthenticator('username', '') + style: primary + start: 121 + end: 158 + - source: PasswordAuthenticator + style: secondary + start: 121 + end: 142 + - source: username + style: secondary + start: 144 + end: 152 + - source: '''username''' + style: secondary + start: 143 + end: 153 + - source: '''''' + style: secondary + start: 155 + end: 157 + - source: ('username', '') + style: secondary + start: 142 + end: 158 + - source: couchbase_core + style: secondary + start: 69 + end: 83 + - source: cluster + style: secondary + start: 84 + end: 91 + - source: couchbase_core.cluster + style: secondary + start: 69 + end: 91 + - source: PasswordAuthenticator + style: secondary + start: 99 + end: 120 + - source: PasswordAuthenticator + style: secondary + start: 99 + end: 120 + - source: from couchbase_core.cluster import PasswordAuthenticator + style: secondary + start: 64 + end: 120 + - source: PasswordAuthenticator('username', '') + style: secondary + start: 121 + end: 158 + ? | + import os + from couchbase.cluster import Cluster, ClusterOptions + from couchbase_core.cluster import PasswordAuthenticator + cluster = Cluster('couchbase://localhost', ClusterOptions(PasswordAuthenticator('username', ''))) + : labels: + - source: PasswordAuthenticator('username', '') + style: primary + start: 179 + end: 216 + - source: PasswordAuthenticator + style: secondary + start: 179 + end: 200 + - source: username + style: secondary + start: 202 + end: 210 + - source: '''username''' + style: secondary + start: 201 + end: 211 + - source: '''''' + style: secondary + start: 213 + end: 215 + - source: ('username', '') + style: secondary + start: 200 + end: 216 + - source: couchbase_core + style: secondary + start: 69 + end: 83 + - source: cluster + style: secondary + start: 84 + end: 91 + - source: couchbase_core.cluster + style: secondary + start: 69 + end: 91 + - source: PasswordAuthenticator + style: secondary + start: 99 + end: 120 + - source: PasswordAuthenticator + style: secondary + start: 99 + end: 120 + - source: from couchbase_core.cluster import PasswordAuthenticator + style: secondary + start: 64 + end: 120 + - source: cluster = Cluster('couchbase://localhost', ClusterOptions(PasswordAuthenticator('username', ''))) + style: secondary + start: 121 + end: 218 diff --git a/tests/python/avoid-mktemp-python-test.yml b/tests/python/avoid-mktemp-python-test.yml new file mode 100644 index 00000000..dcfade76 --- /dev/null +++ b/tests/python/avoid-mktemp-python-test.yml @@ -0,0 +1,8 @@ +id: avoid-mktemp-python +valid: + - | + +invalid: + - | + from tempfile import mktemp + ff = mktemp() diff --git a/tests/python/python-couchbase-empty-password-python-test.yml b/tests/python/python-couchbase-empty-password-python-test.yml new file mode 100644 index 00000000..288034f0 --- /dev/null +++ b/tests/python/python-couchbase-empty-password-python-test.yml @@ -0,0 +1,23 @@ +id: python-couchbase-empty-password-python +valid: + - | + import os + from couchbase.cluster import Cluster, ClusterOptions + from couchbase_core.cluster import PasswordAuthenticator + PasswordAuthenticator('username', os.env['pass']) + - | + import os + from couchbase.cluster import Cluster, ClusterOptions + from couchbase_core.cluster import PasswordAuthenticator + PasswordAuthenticator('username', os.getenv('')) +invalid: + - | + import os + from couchbase.cluster import Cluster, ClusterOptions + from couchbase_core.cluster import PasswordAuthenticator + cluster = Cluster('couchbase://localhost', ClusterOptions(PasswordAuthenticator('username', ''))) + - | + import os + from couchbase.cluster import Cluster, ClusterOptions + from couchbase_core.cluster import PasswordAuthenticator + PasswordAuthenticator('username', '')