From bb7b8e1ad0e345862980a163b688f4554ebc1df8 Mon Sep 17 00:00:00 2001
From: Sakshis <sakshil@abc.com>
Date: Mon, 16 Dec 2024 13:09:06 +0000
Subject: [PATCH 1/8] removed missing-secure-java

---
 rules/java/security/missing-secure-java.yml   | 70 -------------------
 .../missing-secure-java-snapshot.yml          | 32 ---------
 tests/java/missing-secure-java-test.yml       | 15 ----
 3 files changed, 117 deletions(-)
 delete mode 100644 rules/java/security/missing-secure-java.yml
 delete mode 100644 tests/__snapshots__/missing-secure-java-snapshot.yml
 delete mode 100644 tests/java/missing-secure-java-test.yml

diff --git a/rules/java/security/missing-secure-java.yml b/rules/java/security/missing-secure-java.yml
deleted file mode 100644
index 755e6660..00000000
--- a/rules/java/security/missing-secure-java.yml
+++ /dev/null
@@ -1,70 +0,0 @@
-id: missing-secure-java
-language: java
-severity: warning
-message: >-
-   Detected a cookie where the `Secure` flag is either missing or
-   disabled. The `Secure` cookie flag instructs the browser to forbid sending
-   the cookie over an insecure HTTP request. Set the `Secure` flag to `true`
-   so the cookie will only be sent over HTTPS.
-note: >-
-  [CWE-614]: Sensitive Cookie in HTTPS Session Without 'Secure' Attribute
-  [OWASP A05:2021]: Security Misconfiguration
-  [REFERENCES]
-      - https://owasp.org/Top10/A05_2021-Security_Misconfiguration
-utils:
-  match_without_httponly:
-    kind: argument_list
-    has:
-      kind: object_creation_expression
-    inside:
-      stopBy: end
-      kind: method_invocation      
-                       
-  match_cookie_last:
-    kind: argument_list
-    has:
-      kind: method_invocation
-      has:
-        kind: argument_list
-        has:
-          kind: string_literal
-
-  match_instance:
-    kind: local_variable_declaration
-    has:
-      stopBy: end
-      kind: identifier
-      follows:
-        stopBy: end
-        kind: variable_declarator
-
-  match_identifier_with_simplecookie:
-        kind: identifier
-        inside:
-            stopBy: end
-            kind: local_variable_declaration
-            all:
-                - has:
-                      stopBy: end
-                      kind: type_identifier
-                      regex: '^SimpleCookie$|^Cookie$'
-                - has:
-                      stopBy: neighbor
-                      kind: variable_declarator
-                      all:
-                          - has:
-                                stopBy: neighbor
-                                kind: identifier
-                          - has:
-                                stopBy: neighbor
-                                kind: object_creation_expression
-                - not:
-                      precedes:
-                          stopBy: neighbor
-                          kind: expression_statement
-rule:
-  any:
-    - matches: match_instance
-    - matches: match_without_httponly
-    - matches: match_cookie_last
-    - matches: match_identifier_with_simplecookie
diff --git a/tests/__snapshots__/missing-secure-java-snapshot.yml b/tests/__snapshots__/missing-secure-java-snapshot.yml
deleted file mode 100644
index 3931463b..00000000
--- a/tests/__snapshots__/missing-secure-java-snapshot.yml
+++ /dev/null
@@ -1,32 +0,0 @@
-id: missing-secure-java
-snapshots:
-  ? |
-    SimpleCookie s = new SimpleCookie("foo", "bar");
-    .orElse( new NettyCookie( "foo", "bar" ) );
-    Cookie z = new NettyCookie("foo", "bar");
-    return HttpResponse.ok().cookie(Cookie.of("zzz", "ddd"));
-  : labels:
-    - source: s
-      style: primary
-      start: 13
-      end: 14
-    - source: SimpleCookie
-      style: secondary
-      start: 0
-      end: 12
-    - source: s
-      style: secondary
-      start: 13
-      end: 14
-    - source: new SimpleCookie("foo", "bar")
-      style: secondary
-      start: 17
-      end: 47
-    - source: s = new SimpleCookie("foo", "bar")
-      style: secondary
-      start: 13
-      end: 47
-    - source: SimpleCookie s = new SimpleCookie("foo", "bar");
-      style: secondary
-      start: 0
-      end: 48
diff --git a/tests/java/missing-secure-java-test.yml b/tests/java/missing-secure-java-test.yml
deleted file mode 100644
index 507f951f..00000000
--- a/tests/java/missing-secure-java-test.yml
+++ /dev/null
@@ -1,15 +0,0 @@
-id: missing-secure-java
-valid:
-  - |
-    Cookie c1 = getCookieSomewhere();
-    return HttpResponse.ok().cookie(Cookie.of("foo", "bar").secure(true));
-    Cookie cookie = request.getCookies().findCookie( "foobar" )
-    Cookie c = new NettyCookie("foo", "bar");
-    c.secure(true);
-    NettyCookie r = new NettyCookie("foo", "bar").secure(true);
-invalid:
-  - |
-    SimpleCookie s = new SimpleCookie("foo", "bar");
-    .orElse( new NettyCookie( "foo", "bar" ) );
-    Cookie z = new NettyCookie("foo", "bar");
-    return HttpResponse.ok().cookie(Cookie.of("zzz", "ddd"));

From 12bb3aab8d57915cd459d2e2ac04c42dfb2dca48 Mon Sep 17 00:00:00 2001
From: ESS ENN <coderabbit@essenn.associates>
Date: Wed, 22 Jan 2025 18:58:13 +0530
Subject: [PATCH 2/8] httponly-false-csharp

---
 rules/csharp/security/httponly-false-csharp | 48 +++++++++++++++++++++
 tests/csharp/httponly-false-csharp-test.yml |  9 ++++
 2 files changed, 57 insertions(+)
 create mode 100644 rules/csharp/security/httponly-false-csharp
 create mode 100644 tests/csharp/httponly-false-csharp-test.yml

diff --git a/rules/csharp/security/httponly-false-csharp b/rules/csharp/security/httponly-false-csharp
new file mode 100644
index 00000000..af939938
--- /dev/null
+++ b/rules/csharp/security/httponly-false-csharp
@@ -0,0 +1,48 @@
+id: httponly-false-csharp
+language: csharp
+severity: warning
+message: >-
+  "Detected a cookie where the `HttpOnly` flag is either missing or
+      disabled. The `HttpOnly` cookie flag instructs the browser to forbid
+      client-side JavaScript to read the cookie. If JavaScript interaction is
+      required, you can ignore this finding. However, set the `HttpOnly` flag to
+      `true` in all other cases. If this wasn't intentional, it's recommended to
+      set the HttpOnly flag to true so the cookie will not be accessible through
+      client-side scripts or to use the Cookie Policy Middleware to globally set
+      the HttpOnly flag. You can then use the CookieOptions class when
+      instantiating the cookie, which inherits these settings and will require
+      future developers to have to explicitly override them on a case-by-case
+      basis if needed. This approach ensures cookies are secure by default."
+note: >-
+  [CWE-1004] Sensitive Cookie Without 'HttpOnly' Flag"
+  [REFERENCES]
+      - https://learn.microsoft.com/en-us/aspnet/core/security/authentication/cookie?view=aspnetcore-8.0#cookie-policy-middleware
+      - https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.http.cookieoptions
+      - https://owasp.org/Top10/A05_2021-Security_Misconfiguration
+
+
+ast-grep-essentials: true
+
+rule:
+  kind: boolean_literal
+  pattern: $LITERAL
+  follows:
+    regex: ^=$
+    follows:
+      kind: member_access_expression
+      inside:
+        kind: assignment_expression
+      all:
+        - has:
+            kind: member_access_expression
+            nthChild: 1
+            regex: \.Cookie$
+        - has:
+            kind: identifier
+            nthChild: 2
+            regex: ^HttpOnly$
+      
+constraints:
+  LITERAL:
+    regex: ^false$
+
diff --git a/tests/csharp/httponly-false-csharp-test.yml b/tests/csharp/httponly-false-csharp-test.yml
new file mode 100644
index 00000000..e29a7eab
--- /dev/null
+++ b/tests/csharp/httponly-false-csharp-test.yml
@@ -0,0 +1,9 @@
+id: httponly-false-csharp
+valid:
+  - |
+    myHttpOnlyCookie.HttpOnly = true;
+  - |
+    options.Cookie.HttpOnly = true;
+invalid:
+  - |
+    options.Cookie.HttpOnly = false;

From 2c5ea88476cdca70b993026ce65cb1435e602119 Mon Sep 17 00:00:00 2001
From: ESS ENN <coderabbit@essenn.associates>
Date: Wed, 22 Jan 2025 19:00:33 +0530
Subject: [PATCH 3/8] use-of-md5-digest-utils-java

---
 .../security/use-of-md5-digest-utils-java.yml | 42 +++++++++++++++++++
 .../use-of-md5-digest-utils-java-snapshot.yml | 29 +++++++++++++
 .../use-of-md5-digest-utils-java-test.yml     |  7 ++++
 3 files changed, 78 insertions(+)
 create mode 100644 rules/java/security/use-of-md5-digest-utils-java.yml
 create mode 100644 tests/__snapshots__/use-of-md5-digest-utils-java-snapshot.yml
 create mode 100644 tests/java/use-of-md5-digest-utils-java-test.yml

diff --git a/rules/java/security/use-of-md5-digest-utils-java.yml b/rules/java/security/use-of-md5-digest-utils-java.yml
new file mode 100644
index 00000000..553bac8a
--- /dev/null
+++ b/rules/java/security/use-of-md5-digest-utils-java.yml
@@ -0,0 +1,42 @@
+id: use-of-md5-digest-utils-java
+language: java
+severity: warning
+message: >-
+  'Detected MD5 hash algorithm which is considered insecure. MD5 is not
+      collision resistant and is therefore not suitable as a cryptographic
+      signature. Use HMAC instead.'
+note: >-
+  [CWE-328] Use of Weak Hash
+  [REFERENCES]
+      - https://owasp.org/Top10/A02_2021-Cryptographic_Failures
+
+ast-grep-essentials: true
+
+rule:
+  kind: identifier
+  regex: ^getMd5Digest$
+  nthChild: 2
+  precedes:
+    nthChild: 3
+    kind: argument_list
+    not:
+      has:
+        nthChild: 1
+  inside:
+    kind: method_invocation
+    nthChild: 1
+    inside:
+      kind: method_invocation
+      all:
+        - has:
+            kind: identifier
+            nthChild: 2
+            regex: ^digest$
+        - has:
+            kind: argument_list
+            nthChild: 3
+        - not:
+            has:
+              stopBy: end
+              kind: ERROR
+    
diff --git a/tests/__snapshots__/use-of-md5-digest-utils-java-snapshot.yml b/tests/__snapshots__/use-of-md5-digest-utils-java-snapshot.yml
new file mode 100644
index 00000000..2e74b70e
--- /dev/null
+++ b/tests/__snapshots__/use-of-md5-digest-utils-java-snapshot.yml
@@ -0,0 +1,29 @@
+id: use-of-md5-digest-utils-java
+snapshots:
+  ? |
+    byte[] hashValue = DigestUtils.getMd5Digest().digest(password.getBytes());
+  : labels:
+    - source: getMd5Digest
+      style: primary
+      start: 31
+      end: 43
+    - source: digest
+      style: secondary
+      start: 46
+      end: 52
+    - source: (password.getBytes())
+      style: secondary
+      start: 52
+      end: 73
+    - source: DigestUtils.getMd5Digest().digest(password.getBytes())
+      style: secondary
+      start: 19
+      end: 73
+    - source: DigestUtils.getMd5Digest()
+      style: secondary
+      start: 19
+      end: 45
+    - source: ()
+      style: secondary
+      start: 43
+      end: 45
diff --git a/tests/java/use-of-md5-digest-utils-java-test.yml b/tests/java/use-of-md5-digest-utils-java-test.yml
new file mode 100644
index 00000000..769a4b52
--- /dev/null
+++ b/tests/java/use-of-md5-digest-utils-java-test.yml
@@ -0,0 +1,7 @@
+id: use-of-md5-digest-utils-java
+valid:
+  - |
+    byte[] hashValue = DigestUtils.getSha512Digest().digest(password.getBytes());
+invalid:
+  - |
+    byte[] hashValue = DigestUtils.getMd5Digest().digest(password.getBytes());

From d3067f11ba31741fd738392f2d2efb1702116dcf Mon Sep 17 00:00:00 2001
From: ESS ENN <coderabbit@essenn.associates>
Date: Wed, 22 Jan 2025 19:05:33 +0530
Subject: [PATCH 4/8] removing use-of-md5-digest-utils and
 httponly-false-csharp

---
 rules/csharp/security/httponly-false-csharp   | 48 -------------------
 .../security/use-of-md5-digest-utils-java.yml | 42 ----------------
 tests/csharp/httponly-false-csharp-test.yml   |  9 ----
 .../use-of-md5-digest-utils-java-test.yml     |  7 ---
 4 files changed, 106 deletions(-)
 delete mode 100644 rules/csharp/security/httponly-false-csharp
 delete mode 100644 rules/java/security/use-of-md5-digest-utils-java.yml
 delete mode 100644 tests/csharp/httponly-false-csharp-test.yml
 delete mode 100644 tests/java/use-of-md5-digest-utils-java-test.yml

diff --git a/rules/csharp/security/httponly-false-csharp b/rules/csharp/security/httponly-false-csharp
deleted file mode 100644
index af939938..00000000
--- a/rules/csharp/security/httponly-false-csharp
+++ /dev/null
@@ -1,48 +0,0 @@
-id: httponly-false-csharp
-language: csharp
-severity: warning
-message: >-
-  "Detected a cookie where the `HttpOnly` flag is either missing or
-      disabled. The `HttpOnly` cookie flag instructs the browser to forbid
-      client-side JavaScript to read the cookie. If JavaScript interaction is
-      required, you can ignore this finding. However, set the `HttpOnly` flag to
-      `true` in all other cases. If this wasn't intentional, it's recommended to
-      set the HttpOnly flag to true so the cookie will not be accessible through
-      client-side scripts or to use the Cookie Policy Middleware to globally set
-      the HttpOnly flag. You can then use the CookieOptions class when
-      instantiating the cookie, which inherits these settings and will require
-      future developers to have to explicitly override them on a case-by-case
-      basis if needed. This approach ensures cookies are secure by default."
-note: >-
-  [CWE-1004] Sensitive Cookie Without 'HttpOnly' Flag"
-  [REFERENCES]
-      - https://learn.microsoft.com/en-us/aspnet/core/security/authentication/cookie?view=aspnetcore-8.0#cookie-policy-middleware
-      - https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.http.cookieoptions
-      - https://owasp.org/Top10/A05_2021-Security_Misconfiguration
-
-
-ast-grep-essentials: true
-
-rule:
-  kind: boolean_literal
-  pattern: $LITERAL
-  follows:
-    regex: ^=$
-    follows:
-      kind: member_access_expression
-      inside:
-        kind: assignment_expression
-      all:
-        - has:
-            kind: member_access_expression
-            nthChild: 1
-            regex: \.Cookie$
-        - has:
-            kind: identifier
-            nthChild: 2
-            regex: ^HttpOnly$
-      
-constraints:
-  LITERAL:
-    regex: ^false$
-
diff --git a/rules/java/security/use-of-md5-digest-utils-java.yml b/rules/java/security/use-of-md5-digest-utils-java.yml
deleted file mode 100644
index 553bac8a..00000000
--- a/rules/java/security/use-of-md5-digest-utils-java.yml
+++ /dev/null
@@ -1,42 +0,0 @@
-id: use-of-md5-digest-utils-java
-language: java
-severity: warning
-message: >-
-  'Detected MD5 hash algorithm which is considered insecure. MD5 is not
-      collision resistant and is therefore not suitable as a cryptographic
-      signature. Use HMAC instead.'
-note: >-
-  [CWE-328] Use of Weak Hash
-  [REFERENCES]
-      - https://owasp.org/Top10/A02_2021-Cryptographic_Failures
-
-ast-grep-essentials: true
-
-rule:
-  kind: identifier
-  regex: ^getMd5Digest$
-  nthChild: 2
-  precedes:
-    nthChild: 3
-    kind: argument_list
-    not:
-      has:
-        nthChild: 1
-  inside:
-    kind: method_invocation
-    nthChild: 1
-    inside:
-      kind: method_invocation
-      all:
-        - has:
-            kind: identifier
-            nthChild: 2
-            regex: ^digest$
-        - has:
-            kind: argument_list
-            nthChild: 3
-        - not:
-            has:
-              stopBy: end
-              kind: ERROR
-    
diff --git a/tests/csharp/httponly-false-csharp-test.yml b/tests/csharp/httponly-false-csharp-test.yml
deleted file mode 100644
index e29a7eab..00000000
--- a/tests/csharp/httponly-false-csharp-test.yml
+++ /dev/null
@@ -1,9 +0,0 @@
-id: httponly-false-csharp
-valid:
-  - |
-    myHttpOnlyCookie.HttpOnly = true;
-  - |
-    options.Cookie.HttpOnly = true;
-invalid:
-  - |
-    options.Cookie.HttpOnly = false;
diff --git a/tests/java/use-of-md5-digest-utils-java-test.yml b/tests/java/use-of-md5-digest-utils-java-test.yml
deleted file mode 100644
index 769a4b52..00000000
--- a/tests/java/use-of-md5-digest-utils-java-test.yml
+++ /dev/null
@@ -1,7 +0,0 @@
-id: use-of-md5-digest-utils-java
-valid:
-  - |
-    byte[] hashValue = DigestUtils.getSha512Digest().digest(password.getBytes());
-invalid:
-  - |
-    byte[] hashValue = DigestUtils.getMd5Digest().digest(password.getBytes());

From 2bca4c42221997ca9428d2b4e6b165d731c32bd4 Mon Sep 17 00:00:00 2001
From: ESS ENN <coderabbit@essenn.associates>
Date: Thu, 30 Jan 2025 10:39:46 +0530
Subject: [PATCH 5/8] python-pymongo-empty-password-python

---
 .../python-pymongo-empty-password-python.yml  | 88 +++++++++++++++++++
 ...pymongo-empty-password-python-snapshot.yml | 29 ++++++
 ...equests-empty-password-python-snapshot.yml | 36 ++++++++
 ...hon-pymongo-empty-password-python-test.yml |  7 ++
 4 files changed, 160 insertions(+)
 create mode 100644 rules/python/security/python-pymongo-empty-password-python.yml
 create mode 100644 tests/__snapshots__/python-pymongo-empty-password-python-snapshot.yml
 create mode 100644 tests/python/python-pymongo-empty-password-python-test.yml

diff --git a/rules/python/security/python-pymongo-empty-password-python.yml b/rules/python/security/python-pymongo-empty-password-python.yml
new file mode 100644
index 00000000..db0fd45c
--- /dev/null
+++ b/rules/python/security/python-pymongo-empty-password-python.yml
@@ -0,0 +1,88 @@
+id: python-pymongo-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
+
+ast-grep-essentials: true
+
+utils:
+  pymongo.MongoClient(..., password="",...):
+    kind: call
+    all:
+      - has:
+          stopBy: neighbor
+          kind: attribute
+          regex: ^pymongo.MongoClient$
+      - has:
+          stopBy: neighbor
+          kind: argument_list
+          has:
+            stopBy: neighbor
+            kind: keyword_argument
+            all:
+              - has:
+                  stopBy: neighbor
+                  kind: identifier
+                  regex: ^password$
+              - has:
+                  stopBy: neighbor
+                  kind: string
+                  not:
+                    has:
+                      stopBy: end
+                      kind: string_content
+  # $pymongo.MongoClient(..., password="",...):
+  #  kind: call
+  #  all:
+  #    - has:
+  #        stopBy: neighbor
+  #        kind: identifier
+  #        regex: ^MongoClient$
+  #    - has:
+  #        stopBy: neighbor
+  #        kind: argument_list
+  #        has:
+  #          stopBy: neighbor
+  #          kind: keyword_argument
+  #          all:
+  #           - has:
+  #               stopBy: neighbor
+  #               kind: identifier
+  #               regex: ^password$
+  #           - has:
+  #               stopBy: neighbor
+  #               kind: string
+  #               not:
+  #                 has:
+  #                  stopBy: end
+  #                  kind: string_content
+  #    - inside:
+  #        stopBy: end
+  #        follows:
+  #          stopBy: end
+  #          kind: import_from_statement
+  #          pattern: from pymongo import MongoClient
+rule:
+  kind: call
+  any:
+    - matches: pymongo.MongoClient(..., password="",...)
+  # - matches: $pymongo.MongoClient(..., password="",...)
+  not:
+    all:
+      - has:
+          stopBy: end
+          kind: ERROR
+      - inside:
+          stopBy: end
+          kind: ERROR
diff --git a/tests/__snapshots__/python-pymongo-empty-password-python-snapshot.yml b/tests/__snapshots__/python-pymongo-empty-password-python-snapshot.yml
new file mode 100644
index 00000000..e6b3959a
--- /dev/null
+++ b/tests/__snapshots__/python-pymongo-empty-password-python-snapshot.yml
@@ -0,0 +1,29 @@
+id: python-pymongo-empty-password-python
+snapshots:
+  ? |
+    pymongo.MongoClient(password="")
+  : labels:
+    - source: pymongo.MongoClient(password="")
+      style: primary
+      start: 0
+      end: 32
+    - source: pymongo.MongoClient
+      style: secondary
+      start: 0
+      end: 19
+    - source: password
+      style: secondary
+      start: 20
+      end: 28
+    - source: '""'
+      style: secondary
+      start: 29
+      end: 31
+    - source: password=""
+      style: secondary
+      start: 20
+      end: 31
+    - source: (password="")
+      style: secondary
+      start: 19
+      end: 32
diff --git a/tests/__snapshots__/python-requests-empty-password-python-snapshot.yml b/tests/__snapshots__/python-requests-empty-password-python-snapshot.yml
index 065843a3..7d5c779e 100644
--- a/tests/__snapshots__/python-requests-empty-password-python-snapshot.yml
+++ b/tests/__snapshots__/python-requests-empty-password-python-snapshot.yml
@@ -18,3 +18,39 @@ snapshots:
       style: secondary
       start: 89
       end: 101
+  ? "requests.get('https://httpbin.org/basic-auth/user/pass', auth=requests.auth.HTTPBasicAuth('user', ''))  \n"
+  : labels:
+    - source: requests.auth.HTTPBasicAuth('user', '')
+      style: primary
+      start: 62
+      end: 101
+    - source: requests.auth.HTTPBasicAuth
+      style: secondary
+      start: 62
+      end: 89
+    - source: ''''''
+      style: secondary
+      start: 98
+      end: 100
+    - source: ('user', '')
+      style: secondary
+      start: 89
+      end: 101
+  'requests.get(''https://httpbin.org/basic-auth/user/pass'', auth=requests.auth.HTTPBasicAuth(''username'', ''''))      ':
+    labels:
+    - source: requests.auth.HTTPBasicAuth('username', '')
+      style: primary
+      start: 62
+      end: 105
+    - source: requests.auth.HTTPBasicAuth
+      style: secondary
+      start: 62
+      end: 89
+    - source: ''''''
+      style: secondary
+      start: 102
+      end: 104
+    - source: ('username', '')
+      style: secondary
+      start: 89
+      end: 105
diff --git a/tests/python/python-pymongo-empty-password-python-test.yml b/tests/python/python-pymongo-empty-password-python-test.yml
new file mode 100644
index 00000000..581eaf8e
--- /dev/null
+++ b/tests/python/python-pymongo-empty-password-python-test.yml
@@ -0,0 +1,7 @@
+id: python-pymongo-empty-password-python
+valid:
+  - |
+    pymongo.MongoClient(password=os.env['secret'])
+invalid:
+  - |
+    pymongo.MongoClient(password="")

From 7c1442d083183fdc78a3de6b0f59887f49bac28e Mon Sep 17 00:00:00 2001
From: ESS ENN <coderabbit@essenn.associates>
Date: Thu, 30 Jan 2025 10:42:13 +0530
Subject: [PATCH 6/8] python-pymongo-hardcoded-secret-python

---
 ...python-pymongo-hardcoded-secret-python.yml | 85 +++++++++++++++++++
 ...mongo-hardcoded-secret-python-snapshot.yml | 33 +++++++
 ...n-pymongo-hardcoded-secret-python-test.yml |  9 ++
 3 files changed, 127 insertions(+)
 create mode 100644 rules/python/security/python-pymongo-hardcoded-secret-python.yml
 create mode 100644 tests/__snapshots__/python-pymongo-hardcoded-secret-python-snapshot.yml
 create mode 100644 tests/python/python-pymongo-hardcoded-secret-python-test.yml

diff --git a/rules/python/security/python-pymongo-hardcoded-secret-python.yml b/rules/python/security/python-pymongo-hardcoded-secret-python.yml
new file mode 100644
index 00000000..4690aa06
--- /dev/null
+++ b/rules/python/security/python-pymongo-hardcoded-secret-python.yml
@@ -0,0 +1,85 @@
+id: python-pymongo-hardcoded-secret-python
+language: python
+severity: warning
+message: >-
+  A secret is hard-coded in the application. Secrets stored in source
+  code, such as credentials, identifiers, and other types of sensitive data,
+  can be leaked and used by internal or external malicious actors. Use
+  environment variables to securely provide credentials and other secrets or
+  retrieve them from a secure vault or Hardware Security Module (HSM).
+note: >-
+  [CWE-798]: Use of Hard-coded Credentials
+  [OWASP A07:2021]: Identification and Authentication Failures
+  [REFERENCES]
+       https://cheatsheetseries.owasp.org/cheatsheets/Secrets_Management_Cheat_Sheet.html
+
+ast-grep-essentials: true
+
+utils:
+  pymongo.MongoClient(..., password="",...):
+    kind: call
+    all:
+      - has:
+          stopBy: neighbor
+          kind: attribute
+          regex: ^pymongo.MongoClient$
+      - has:
+          stopBy: neighbor
+          kind: argument_list
+          has:
+            stopBy: neighbor
+            kind: keyword_argument
+            all:
+              - has:
+                  stopBy: neighbor
+                  kind: identifier
+                  regex: ^password$
+              - has:
+                  stopBy: neighbor
+                  kind: string
+                  has:
+                    stopBy: end
+                    kind: string_content
+  # $pymongo.MongoClient(..., password="",...):
+  #  kind: call
+  #  all:
+  #    - has:
+  #        stopBy: neighbor
+  #        kind: identifier
+  #        regex: ^MongoClient$
+  #    - has:
+  #        stopBy: neighbor
+  #        kind: argument_list
+  #        has:
+  #          stopBy: neighbor
+  #          kind: keyword_argument
+  #          all:
+  #           - has:
+  #               stopBy: neighbor
+  #               kind: identifier
+  #               regex: ^password$
+  #           - has:
+  #               stopBy: neighbor
+  #               kind: string
+  #               has:
+  #                  stopBy: end
+  #                  kind: string_content
+  #    - inside:
+  #        stopBy: end
+  #        follows:
+  #          stopBy: end
+  #          kind: import_from_statement
+  #          pattern: from pymongo import MongoClient
+rule:
+  kind: call
+  any:
+    - matches: pymongo.MongoClient(..., password="",...)
+  # - matches: $pymongo.MongoClient(..., password="",...)
+  not:
+    all:
+      - has:
+          stopBy: end
+          kind: ERROR
+      - inside:
+          stopBy: end
+          kind: ERROR
diff --git a/tests/__snapshots__/python-pymongo-hardcoded-secret-python-snapshot.yml b/tests/__snapshots__/python-pymongo-hardcoded-secret-python-snapshot.yml
new file mode 100644
index 00000000..473e1741
--- /dev/null
+++ b/tests/__snapshots__/python-pymongo-hardcoded-secret-python-snapshot.yml
@@ -0,0 +1,33 @@
+id: python-pymongo-hardcoded-secret-python
+snapshots:
+  ? |
+    pymongo.MongoClient(password="a")
+  : labels:
+    - source: pymongo.MongoClient(password="a")
+      style: primary
+      start: 0
+      end: 33
+    - source: pymongo.MongoClient
+      style: secondary
+      start: 0
+      end: 19
+    - source: password
+      style: secondary
+      start: 20
+      end: 28
+    - source: a
+      style: secondary
+      start: 30
+      end: 31
+    - source: '"a"'
+      style: secondary
+      start: 29
+      end: 32
+    - source: password="a"
+      style: secondary
+      start: 20
+      end: 32
+    - source: (password="a")
+      style: secondary
+      start: 19
+      end: 33
diff --git a/tests/python/python-pymongo-hardcoded-secret-python-test.yml b/tests/python/python-pymongo-hardcoded-secret-python-test.yml
new file mode 100644
index 00000000..43301bc2
--- /dev/null
+++ b/tests/python/python-pymongo-hardcoded-secret-python-test.yml
@@ -0,0 +1,9 @@
+id: python-pymongo-hardcoded-secret-python
+valid:
+  - |
+    pymongo.MongoClient(password=os.env['secret'])
+  - |
+    pymongo.MongoClient(password=os.getenv('secret'))
+invalid:
+  - |
+    pymongo.MongoClient(password="a")

From bf8028462981c86de2345b16976ce8352f3f709b Mon Sep 17 00:00:00 2001
From: ESS ENN <coderabbit@essenn.associates>
Date: Thu, 30 Jan 2025 10:44:04 +0530
Subject: [PATCH 7/8] python-webrepl-empty-password-python

---
 .../python-webrepl-empty-password-python.yml  | 56 +++++++++++++++++++
 ...webrepl-empty-password-python-snapshot.yml | 29 ++++++++++
 ...hon-webrepl-empty-password-python-test.yml |  7 +++
 3 files changed, 92 insertions(+)
 create mode 100644 rules/python/security/python-webrepl-empty-password-python.yml
 create mode 100644 tests/__snapshots__/python-webrepl-empty-password-python-snapshot.yml
 create mode 100644 tests/python/python-webrepl-empty-password-python-test.yml

diff --git a/rules/python/security/python-webrepl-empty-password-python.yml b/rules/python/security/python-webrepl-empty-password-python.yml
new file mode 100644
index 00000000..1869d3ee
--- /dev/null
+++ b/rules/python/security/python-webrepl-empty-password-python.yml
@@ -0,0 +1,56 @@
+id: python-webrepl-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
+
+ast-grep-essentials: true
+
+utils:
+  webrepl.start(..., password="",...):
+   kind: call
+   all:
+     - has:
+         stopBy: neighbor
+         kind: attribute
+         regex: ^webrepl.start$
+     - has:
+         stopBy: neighbor
+         kind: argument_list
+         has:
+           stopBy: neighbor
+           kind: keyword_argument
+           all:
+            - has:
+                stopBy: neighbor
+                kind: identifier
+                regex: ^password$
+            - has:
+                stopBy: neighbor
+                kind: string
+                not:
+                 has:
+                  stopBy: end
+                  kind: string_content
+rule:
+  kind: call
+  matches: webrepl.start(..., password="",...)
+  not:
+    all:
+      - has:
+          stopBy: end
+          kind: ERROR
+      - inside:
+          stopBy: end
+          kind: ERROR
+
diff --git a/tests/__snapshots__/python-webrepl-empty-password-python-snapshot.yml b/tests/__snapshots__/python-webrepl-empty-password-python-snapshot.yml
new file mode 100644
index 00000000..c9e19b40
--- /dev/null
+++ b/tests/__snapshots__/python-webrepl-empty-password-python-snapshot.yml
@@ -0,0 +1,29 @@
+id: python-webrepl-empty-password-python
+snapshots:
+  ? |
+    webrepl.start(password="")
+  : labels:
+    - source: webrepl.start(password="")
+      style: primary
+      start: 0
+      end: 26
+    - source: webrepl.start
+      style: secondary
+      start: 0
+      end: 13
+    - source: password
+      style: secondary
+      start: 14
+      end: 22
+    - source: '""'
+      style: secondary
+      start: 23
+      end: 25
+    - source: password=""
+      style: secondary
+      start: 14
+      end: 25
+    - source: (password="")
+      style: secondary
+      start: 13
+      end: 26
diff --git a/tests/python/python-webrepl-empty-password-python-test.yml b/tests/python/python-webrepl-empty-password-python-test.yml
new file mode 100644
index 00000000..1696ea54
--- /dev/null
+++ b/tests/python/python-webrepl-empty-password-python-test.yml
@@ -0,0 +1,7 @@
+id: python-webrepl-empty-password-python
+valid:
+  - |
+    webrepl.start(password=SECURE_PASSWORD_CONFIG["password"])
+invalid:
+  - |
+    webrepl.start(password="")

From 56a53f1d46e06196f72cbdd2e4c38a3a9aa58887 Mon Sep 17 00:00:00 2001
From: ESS ENN <coderabbit@essenn.associates>
Date: Thu, 30 Jan 2025 10:45:37 +0530
Subject: [PATCH 8/8] python-webrepl-hardcoded-secret-python

---
 ...python-webrepl-hardcoded-secret-python.yml | 54 ++++++++++++++++
 ...brepl-hardcoded-secret-python-snapshot.yml | 64 +++++++++++++++++++
 ...n-webrepl-hardcoded-secret-python-test.yml |  9 +++
 3 files changed, 127 insertions(+)
 create mode 100644 rules/python/security/python-webrepl-hardcoded-secret-python.yml
 create mode 100644 tests/__snapshots__/python-webrepl-hardcoded-secret-python-snapshot.yml
 create mode 100644 tests/python/python-webrepl-hardcoded-secret-python-test.yml

diff --git a/rules/python/security/python-webrepl-hardcoded-secret-python.yml b/rules/python/security/python-webrepl-hardcoded-secret-python.yml
new file mode 100644
index 00000000..aa04e5a5
--- /dev/null
+++ b/rules/python/security/python-webrepl-hardcoded-secret-python.yml
@@ -0,0 +1,54 @@
+id: python-webrepl-hardcoded-secret-python
+language: python
+severity: warning
+message: >-
+  A secret is hard-coded in the application. Secrets stored in source
+  code, such as credentials, identifiers, and other types of sensitive data,
+  can be leaked and used by internal or external malicious actors. Use
+  environment variables to securely provide credentials and other secrets or
+  retrieve them from a secure vault or Hardware Security Module (HSM).
+note: >-
+  [CWE-798]: Use of Hard-coded Credentials
+  [OWASP A07:2021]: Identification and Authentication Failures
+  [REFERENCES]
+       https://cheatsheetseries.owasp.org/cheatsheets/Secrets_Management_Cheat_Sheet.html
+
+ast-grep-essentials: true
+
+utils:
+  webrepl.start(..., password="",...):
+   kind: call
+   all:
+     - has:
+         stopBy: neighbor
+         kind: attribute
+         regex: ^webrepl.start$
+     - has:
+         stopBy: neighbor
+         kind: argument_list
+         has:
+           stopBy: neighbor
+           kind: keyword_argument
+           all:
+            - has:
+                stopBy: neighbor
+                kind: identifier
+                regex: ^password$
+            - has:
+                stopBy: neighbor
+                kind: string
+                has:
+                  stopBy: end
+                  kind: string_content
+rule:
+  kind: call
+  matches: webrepl.start(..., password="",...)
+  not:
+    all:
+      - has:
+          stopBy: end
+          kind: ERROR
+      - inside:
+          stopBy: end
+          kind: ERROR
+
diff --git a/tests/__snapshots__/python-webrepl-hardcoded-secret-python-snapshot.yml b/tests/__snapshots__/python-webrepl-hardcoded-secret-python-snapshot.yml
new file mode 100644
index 00000000..a18db1cf
--- /dev/null
+++ b/tests/__snapshots__/python-webrepl-hardcoded-secret-python-snapshot.yml
@@ -0,0 +1,64 @@
+id: python-webrepl-hardcoded-secret-python
+snapshots:
+  ? |
+    webrepl.start(password="12345")
+  : labels:
+    - source: webrepl.start(password="12345")
+      style: primary
+      start: 0
+      end: 31
+    - source: webrepl.start
+      style: secondary
+      start: 0
+      end: 13
+    - source: password
+      style: secondary
+      start: 14
+      end: 22
+    - source: '12345'
+      style: secondary
+      start: 24
+      end: 29
+    - source: '"12345"'
+      style: secondary
+      start: 23
+      end: 30
+    - source: password="12345"
+      style: secondary
+      start: 14
+      end: 30
+    - source: (password="12345")
+      style: secondary
+      start: 13
+      end: 31
+  ? |
+    webrepl.start(password="mypassword")
+  : labels:
+    - source: webrepl.start(password="mypassword")
+      style: primary
+      start: 0
+      end: 36
+    - source: webrepl.start
+      style: secondary
+      start: 0
+      end: 13
+    - source: password
+      style: secondary
+      start: 14
+      end: 22
+    - source: mypassword
+      style: secondary
+      start: 24
+      end: 34
+    - source: '"mypassword"'
+      style: secondary
+      start: 23
+      end: 35
+    - source: password="mypassword"
+      style: secondary
+      start: 14
+      end: 35
+    - source: (password="mypassword")
+      style: secondary
+      start: 13
+      end: 36
diff --git a/tests/python/python-webrepl-hardcoded-secret-python-test.yml b/tests/python/python-webrepl-hardcoded-secret-python-test.yml
new file mode 100644
index 00000000..a7309bdd
--- /dev/null
+++ b/tests/python/python-webrepl-hardcoded-secret-python-test.yml
@@ -0,0 +1,9 @@
+id: python-webrepl-hardcoded-secret-python
+valid:
+  - |
+    webrepl.start(password=os.getenv('PASSWORD'))
+invalid:
+  - |
+    webrepl.start(password="mypassword")
+  - |
+    webrepl.start(password="12345")