From bb7b8e1ad0e345862980a163b688f4554ebc1df8 Mon Sep 17 00:00:00 2001 From: Sakshis Date: Mon, 16 Dec 2024 13:09:06 +0000 Subject: [PATCH 1/9] 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 Date: Wed, 22 Jan 2025 18:58:13 +0530 Subject: [PATCH 2/9] 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 Date: Wed, 22 Jan 2025 19:00:33 +0530 Subject: [PATCH 3/9] 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 Date: Wed, 22 Jan 2025 19:05:33 +0530 Subject: [PATCH 4/9] 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 7e77a0e66f633fe93f8c9ebf5f22c011b83b21f1 Mon Sep 17 00:00:00 2001 From: ESS-ENN Date: Wed, 26 Mar 2025 11:50:13 +0530 Subject: [PATCH 5/9] jwt-scala-hardcode-scala --- rules/scala/jwt-scala-hardcode-scala.yml | 118 ++++ .../jwt-scala-hardcode-scala-snapshot.yml | 534 ++++++++++++++++++ tests/scala/jwt-scala-hardcode-scala-test.yml | 93 +++ 3 files changed, 745 insertions(+) create mode 100644 rules/scala/jwt-scala-hardcode-scala.yml create mode 100644 tests/__snapshots__/jwt-scala-hardcode-scala-snapshot.yml create mode 100644 tests/scala/jwt-scala-hardcode-scala-test.yml diff --git a/rules/scala/jwt-scala-hardcode-scala.yml b/rules/scala/jwt-scala-hardcode-scala.yml new file mode 100644 index 00000000..3c7ea471 --- /dev/null +++ b/rules/scala/jwt-scala-hardcode-scala.yml @@ -0,0 +1,118 @@ +id: jwt-scala-hardcode-scala +language: scala +severity: warning +message: >- + Hardcoded JWT secret or private key is used. This is a Insufficiently + Protected Credentials weakness: + https://cwe.mitre.org/data/definitions/522.html Consider using an + appropriate security mechanism to protect the credentials (e.g. keeping + secrets in environment variables). +note: >- + [CWE-522] Insufficiently Protected Credentials. + [REFERENCES] + - https://jwt-scala.github.io/jwt-scala/ + +ast-grep-essentials: true + +utils: + PATTERN: + kind: call_expression + all: + - inside: + stopBy: end + follows: + stopBy: end + kind: import_declaration + regex: ^import pdi.jwt.* + - has: + kind: field_expression + all: + - has: + kind: identifier + nthChild: 1 + regex: ^(Jwt|JwtArgonaut|JwtCirce|JwtJson4s|JwtJson|JwtUpickle)$ + - has: + kind: identifier + nthChild: 2 + regex: ^(encode|decode|decodeRawAll|decodeRaw|decodeAll|validate|isValid|decodeJson|decodeJsonAll)$ + - has: + kind: arguments + has: + kind: string + not: + regex: ^""$ + nthChild: + position: 2 + ofRule: + not: + kind: comment + + PATTERN_with_Instance: + kind: call_expression + all: + - inside: + stopBy: end + follows: + stopBy: end + kind: import_declaration + regex: ^import pdi.jwt.* + - has: + kind: field_expression + all: + - has: + kind: identifier + nthChild: 1 + regex: ^(Jwt|JwtArgonaut|JwtCirce|JwtJson4s|JwtJson|JwtUpickle)$ + - has: + kind: identifier + nthChild: 2 + regex: ^(encode|decode|decodeRawAll|decodeRaw|decodeAll|validate|isValid|decodeJson|decodeJsonAll)$ + - has: + kind: arguments + any: + - has: + kind: field_expression + all: + - has: + nthChild: 1 + regex: ^this$ + - has: + nthChild: 2 + kind: identifier + pattern: $STRG + - has: + kind: identifier + pattern: $STRG + nthChild: + position: 2 + ofRule: + not: + kind: comment + - inside: + stopBy: end + follows: + stopBy: end + kind: val_definition + all: + - has: + kind: identifier + field: pattern + pattern: $STRG + # nthChild: 1 + - has: + kind: string + field: value + # nthChild: 2 + not: + regex: ^""$ + - inside: + stopBy: end + any: + - kind: object_definition + - kind: class_definition + +rule: + kind: call_expression + any: + - matches: PATTERN + - matches: PATTERN_with_Instance diff --git a/tests/__snapshots__/jwt-scala-hardcode-scala-snapshot.yml b/tests/__snapshots__/jwt-scala-hardcode-scala-snapshot.yml new file mode 100644 index 00000000..f4ebba81 --- /dev/null +++ b/tests/__snapshots__/jwt-scala-hardcode-scala-snapshot.yml @@ -0,0 +1,534 @@ +id: jwt-scala-hardcode-scala +snapshots: + ? | + import pdi.jwt.{JwtJson, JwtAlgorithm, JwtArgonaut} + class Test6 { + val secretKey = "secretKey" + def run() = { + val claim = Json.obj(("user", 1), ("nbf", 1431520421)) + val algo = JwtAlgorithm.HS256 + val token = JwtJson.encode(claim, secretKey, algo) + println(token) + } + } + : labels: + - source: JwtJson.encode(claim, secretKey, algo) + style: primary + start: 221 + end: 259 + - source: import pdi.jwt.{JwtJson, JwtAlgorithm, JwtArgonaut} + style: secondary + start: 0 + end: 51 + - source: import pdi.jwt.{JwtJson, JwtAlgorithm, JwtArgonaut} + style: secondary + start: 0 + end: 51 + - source: JwtJson + style: secondary + start: 221 + end: 228 + - source: encode + style: secondary + start: 229 + end: 235 + - source: JwtJson.encode + style: secondary + start: 221 + end: 235 + - source: secretKey + style: secondary + start: 243 + end: 252 + - source: (claim, secretKey, algo) + style: secondary + start: 235 + end: 259 + - source: secretKey + style: secondary + start: 72 + end: 81 + - source: '"secretKey"' + style: secondary + start: 84 + end: 95 + - source: |- + class Test6 { + val secretKey = "secretKey" + def run() = { + val claim = Json.obj(("user", 1), ("nbf", 1431520421)) + val algo = JwtAlgorithm.HS256 + val token = JwtJson.encode(claim, secretKey, algo) + println(token) + } + } + style: secondary + start: 52 + end: 284 + - source: val secretKey = "secretKey" + style: secondary + start: 68 + end: 95 + - source: val secretKey = "secretKey" + style: secondary + start: 68 + end: 95 + ? | + import pdi.jwt.{JwtJson, JwtAlgorithm, JwtArgonaut} + class Test7 { + val secretKey = "secretKey" + def run(token: String) = { + val algo = JwtAlgorithm.HS256 + val decoded = JwtJson.decodeJson(token, secretKey, Seq(algo)) + println(decoded) + } + } + : labels: + - source: JwtJson.decodeJson(token, secretKey, Seq(algo)) + style: primary + start: 177 + end: 224 + - source: import pdi.jwt.{JwtJson, JwtAlgorithm, JwtArgonaut} + style: secondary + start: 0 + end: 51 + - source: import pdi.jwt.{JwtJson, JwtAlgorithm, JwtArgonaut} + style: secondary + start: 0 + end: 51 + - source: JwtJson + style: secondary + start: 177 + end: 184 + - source: decodeJson + style: secondary + start: 185 + end: 195 + - source: JwtJson.decodeJson + style: secondary + start: 177 + end: 195 + - source: secretKey + style: secondary + start: 203 + end: 212 + - source: (token, secretKey, Seq(algo)) + style: secondary + start: 195 + end: 224 + - source: secretKey + style: secondary + start: 72 + end: 81 + - source: '"secretKey"' + style: secondary + start: 84 + end: 95 + - source: |- + class Test7 { + val secretKey = "secretKey" + def run(token: String) = { + val algo = JwtAlgorithm.HS256 + val decoded = JwtJson.decodeJson(token, secretKey, Seq(algo)) + println(decoded) + } + } + style: secondary + start: 52 + end: 251 + - source: val secretKey = "secretKey" + style: secondary + start: 68 + end: 95 + - source: val secretKey = "secretKey" + style: secondary + start: 68 + end: 95 + ? | + import pdi.jwt.{JwtJson, JwtAlgorithm, JwtArgonaut} + class Test9 { + val secretKey = "secretKey" + def run(token: String) = { + val algo = JwtAlgorithm.HS256 + val decodedRaw = JwtJson.decodeRaw(token, secretKey, Seq(algo)) + println(decodedRaw) + } + } + : labels: + - source: JwtJson.decodeRaw(token, secretKey, Seq(algo)) + style: primary + start: 180 + end: 226 + - source: import pdi.jwt.{JwtJson, JwtAlgorithm, JwtArgonaut} + style: secondary + start: 0 + end: 51 + - source: import pdi.jwt.{JwtJson, JwtAlgorithm, JwtArgonaut} + style: secondary + start: 0 + end: 51 + - source: JwtJson + style: secondary + start: 180 + end: 187 + - source: decodeRaw + style: secondary + start: 188 + end: 197 + - source: JwtJson.decodeRaw + style: secondary + start: 180 + end: 197 + - source: secretKey + style: secondary + start: 205 + end: 214 + - source: (token, secretKey, Seq(algo)) + style: secondary + start: 197 + end: 226 + - source: secretKey + style: secondary + start: 72 + end: 81 + - source: '"secretKey"' + style: secondary + start: 84 + end: 95 + - source: |- + class Test9 { + val secretKey = "secretKey" + def run(token: String) = { + val algo = JwtAlgorithm.HS256 + val decodedRaw = JwtJson.decodeRaw(token, secretKey, Seq(algo)) + println(decodedRaw) + } + } + style: secondary + start: 52 + end: 256 + - source: val secretKey = "secretKey" + style: secondary + start: 68 + end: 95 + - source: val secretKey = "secretKey" + style: secondary + start: 68 + end: 95 + ? "import pdi.jwt.{JwtJson, JwtAlgorithm, JwtArgonaut}\nobject Test1 {\n val secretKey = \"secretKey\" \n def run() = {\n val claim = Json.obj((\"user\", 1), (\"nbf\", 1431520421))\n val algo = JwtAlgorithm.HS256\n val token = JwtJson.encode(claim, secretKey, algo)\n println(token)\n }\n}\n" + : labels: + - source: JwtJson.encode(claim, secretKey, algo) + style: primary + start: 223 + end: 261 + - source: import pdi.jwt.{JwtJson, JwtAlgorithm, JwtArgonaut} + style: secondary + start: 0 + end: 51 + - source: import pdi.jwt.{JwtJson, JwtAlgorithm, JwtArgonaut} + style: secondary + start: 0 + end: 51 + - source: JwtJson + style: secondary + start: 223 + end: 230 + - source: encode + style: secondary + start: 231 + end: 237 + - source: JwtJson.encode + style: secondary + start: 223 + end: 237 + - source: secretKey + style: secondary + start: 245 + end: 254 + - source: (claim, secretKey, algo) + style: secondary + start: 237 + end: 261 + - source: secretKey + style: secondary + start: 73 + end: 82 + - source: '"secretKey"' + style: secondary + start: 85 + end: 96 + - source: "object Test1 {\n val secretKey = \"secretKey\" \n def run() = {\n val claim = Json.obj((\"user\", 1), (\"nbf\", 1431520421))\n val algo = JwtAlgorithm.HS256\n val token = JwtJson.encode(claim, secretKey, algo)\n println(token)\n }\n}" + style: secondary + start: 52 + end: 286 + - source: val secretKey = "secretKey" + style: secondary + start: 69 + end: 96 + - source: val secretKey = "secretKey" + style: secondary + start: 69 + end: 96 + ? | + import pdi.jwt.{JwtJson, JwtAlgorithm, JwtArgonaut} + object Test15 { + val secretKey = "secretKey" + def run(token: String) = { + val algo = JwtAlgorithm.HS256 + val decodedAll = JwtJson.decodeAll(token, this.secretKey, Seq(algo)) + println(decodedAll) + } + } + : labels: + - source: JwtJson.decodeAll(token, this.secretKey, Seq(algo)) + style: primary + start: 182 + end: 233 + - source: import pdi.jwt.{JwtJson, JwtAlgorithm, JwtArgonaut} + style: secondary + start: 0 + end: 51 + - source: import pdi.jwt.{JwtJson, JwtAlgorithm, JwtArgonaut} + style: secondary + start: 0 + end: 51 + - source: JwtJson + style: secondary + start: 182 + end: 189 + - source: decodeAll + style: secondary + start: 190 + end: 199 + - source: JwtJson.decodeAll + style: secondary + start: 182 + end: 199 + - source: this + style: secondary + start: 207 + end: 211 + - source: secretKey + style: secondary + start: 212 + end: 221 + - source: this.secretKey + style: secondary + start: 207 + end: 221 + - source: (token, this.secretKey, Seq(algo)) + style: secondary + start: 199 + end: 233 + - source: secretKey + style: secondary + start: 74 + end: 83 + - source: '"secretKey"' + style: secondary + start: 86 + end: 97 + - source: |- + object Test15 { + val secretKey = "secretKey" + def run(token: String) = { + val algo = JwtAlgorithm.HS256 + val decodedAll = JwtJson.decodeAll(token, this.secretKey, Seq(algo)) + println(decodedAll) + } + } + style: secondary + start: 52 + end: 263 + - source: val secretKey = "secretKey" + style: secondary + start: 70 + end: 97 + - source: val secretKey = "secretKey" + style: secondary + start: 70 + end: 97 + ? | + import pdi.jwt.{JwtJson, JwtAlgorithm, JwtArgonaut} + object Test2 { + val secretKey = "secretKey" + def run(token: String) = { + val algo = JwtAlgorithm.HS256 + val decoded = JwtJson.decodeJson(token, secretKey, Seq(algo)) + println(decoded) + } + } + : labels: + - source: JwtJson.decodeJson(token, secretKey, Seq(algo)) + style: primary + start: 178 + end: 225 + - source: import pdi.jwt.{JwtJson, JwtAlgorithm, JwtArgonaut} + style: secondary + start: 0 + end: 51 + - source: import pdi.jwt.{JwtJson, JwtAlgorithm, JwtArgonaut} + style: secondary + start: 0 + end: 51 + - source: JwtJson + style: secondary + start: 178 + end: 185 + - source: decodeJson + style: secondary + start: 186 + end: 196 + - source: JwtJson.decodeJson + style: secondary + start: 178 + end: 196 + - source: secretKey + style: secondary + start: 204 + end: 213 + - source: (token, secretKey, Seq(algo)) + style: secondary + start: 196 + end: 225 + - source: secretKey + style: secondary + start: 73 + end: 82 + - source: '"secretKey"' + style: secondary + start: 85 + end: 96 + - source: |- + object Test2 { + val secretKey = "secretKey" + def run(token: String) = { + val algo = JwtAlgorithm.HS256 + val decoded = JwtJson.decodeJson(token, secretKey, Seq(algo)) + println(decoded) + } + } + style: secondary + start: 52 + end: 252 + - source: val secretKey = "secretKey" + style: secondary + start: 69 + end: 96 + - source: val secretKey = "secretKey" + style: secondary + start: 69 + end: 96 + ? | + import pdi.jwt.{JwtJson, JwtAlgorithm, JwtArgonaut} + object Test3 { + val secretKey = "secretKey" + def run(token: String) = { + val algo = JwtAlgorithm.HS256 + val decodedJson = JwtJson.decodeJson(token, secretKey, Seq(algo)) + println(decodedJson) + } + } + : labels: + - source: JwtJson.decodeJson(token, secretKey, Seq(algo)) + style: primary + start: 182 + end: 229 + - source: import pdi.jwt.{JwtJson, JwtAlgorithm, JwtArgonaut} + style: secondary + start: 0 + end: 51 + - source: import pdi.jwt.{JwtJson, JwtAlgorithm, JwtArgonaut} + style: secondary + start: 0 + end: 51 + - source: JwtJson + style: secondary + start: 182 + end: 189 + - source: decodeJson + style: secondary + start: 190 + end: 200 + - source: JwtJson.decodeJson + style: secondary + start: 182 + end: 200 + - source: secretKey + style: secondary + start: 208 + end: 217 + - source: (token, secretKey, Seq(algo)) + style: secondary + start: 200 + end: 229 + - source: secretKey + style: secondary + start: 73 + end: 82 + - source: '"secretKey"' + style: secondary + start: 85 + end: 96 + - source: |- + object Test3 { + val secretKey = "secretKey" + def run(token: String) = { + val algo = JwtAlgorithm.HS256 + val decodedJson = JwtJson.decodeJson(token, secretKey, Seq(algo)) + println(decodedJson) + } + } + style: secondary + start: 52 + end: 260 + - source: val secretKey = "secretKey" + style: secondary + start: 69 + end: 96 + - source: val secretKey = "secretKey" + style: secondary + start: 69 + end: 96 + ? | + import pdi.jwt.{JwtJson, JwtAlgorithm, JwtArgonaut} + object Test5 { + def run(token: String) = { + val algo = JwtAlgorithm.HS256 + val decodedAll = JwtJson.decodeAll(token, "secretKey", Seq(algo)) + println(decodedAll) + } + } + : labels: + - source: JwtJson.decodeAll(token, "secretKey", Seq(algo)) + style: primary + start: 151 + end: 199 + - source: import pdi.jwt.{JwtJson, JwtAlgorithm, JwtArgonaut} + style: secondary + start: 0 + end: 51 + - source: import pdi.jwt.{JwtJson, JwtAlgorithm, JwtArgonaut} + style: secondary + start: 0 + end: 51 + - source: JwtJson + style: secondary + start: 151 + end: 158 + - source: decodeAll + style: secondary + start: 159 + end: 168 + - source: JwtJson.decodeAll + style: secondary + start: 151 + end: 168 + - source: '"secretKey"' + style: secondary + start: 176 + end: 187 + - source: (token, "secretKey", Seq(algo)) + style: secondary + start: 168 + end: 199 diff --git a/tests/scala/jwt-scala-hardcode-scala-test.yml b/tests/scala/jwt-scala-hardcode-scala-test.yml new file mode 100644 index 00000000..dd57e368 --- /dev/null +++ b/tests/scala/jwt-scala-hardcode-scala-test.yml @@ -0,0 +1,93 @@ +id: jwt-scala-hardcode-scala +valid: + - | + class Test7 { + val secretKey = "secretKey" + def run(token: String) = { + val algo = JwtAlgorithm.HS256 + val decoded = JwtJson.decodeJson(token, secretKey, Seq(algo)) + println(decoded) + } + } +invalid: + - | + import pdi.jwt.{JwtJson, JwtAlgorithm, JwtArgonaut} + object Test1 { + val secretKey = "secretKey" + def run() = { + val claim = Json.obj(("user", 1), ("nbf", 1431520421)) + val algo = JwtAlgorithm.HS256 + val token = JwtJson.encode(claim, secretKey, algo) + println(token) + } + } + - | + import pdi.jwt.{JwtJson, JwtAlgorithm, JwtArgonaut} + object Test2 { + val secretKey = "secretKey" + def run(token: String) = { + val algo = JwtAlgorithm.HS256 + val decoded = JwtJson.decodeJson(token, secretKey, Seq(algo)) + println(decoded) + } + } + - | + import pdi.jwt.{JwtJson, JwtAlgorithm, JwtArgonaut} + object Test3 { + val secretKey = "secretKey" + def run(token: String) = { + val algo = JwtAlgorithm.HS256 + val decodedJson = JwtJson.decodeJson(token, secretKey, Seq(algo)) + println(decodedJson) + } + } + - | + import pdi.jwt.{JwtJson, JwtAlgorithm, JwtArgonaut} + object Test5 { + def run(token: String) = { + val algo = JwtAlgorithm.HS256 + val decodedAll = JwtJson.decodeAll(token, "secretKey", Seq(algo)) + println(decodedAll) + } + } + - | + import pdi.jwt.{JwtJson, JwtAlgorithm, JwtArgonaut} + class Test6 { + val secretKey = "secretKey" + def run() = { + val claim = Json.obj(("user", 1), ("nbf", 1431520421)) + val algo = JwtAlgorithm.HS256 + val token = JwtJson.encode(claim, secretKey, algo) + println(token) + } + } + - | + import pdi.jwt.{JwtJson, JwtAlgorithm, JwtArgonaut} + class Test7 { + val secretKey = "secretKey" + def run(token: String) = { + val algo = JwtAlgorithm.HS256 + val decoded = JwtJson.decodeJson(token, secretKey, Seq(algo)) + println(decoded) + } + } + - | + import pdi.jwt.{JwtJson, JwtAlgorithm, JwtArgonaut} + class Test9 { + val secretKey = "secretKey" + def run(token: String) = { + val algo = JwtAlgorithm.HS256 + val decodedRaw = JwtJson.decodeRaw(token, secretKey, Seq(algo)) + println(decodedRaw) + } + } + - | + import pdi.jwt.{JwtJson, JwtAlgorithm, JwtArgonaut} + object Test15 { + val secretKey = "secretKey" + def run(token: String) = { + val algo = JwtAlgorithm.HS256 + val decodedAll = JwtJson.decodeAll(token, this.secretKey, Seq(algo)) + println(decodedAll) + } + } From ad0ff85369d3977d6b5ddfda2f2fc3253bdf216c Mon Sep 17 00:00:00 2001 From: ESS-ENN Date: Wed, 26 Mar 2025 11:54:03 +0530 Subject: [PATCH 6/9] jwt-go-none-algorithm-go --- .../security/jwt-go-none-algorithm-go.yml | 43 ++++++++++++++++ .../jwt-scala-hardcode-scala.yml | 0 .../jwt-go-none-algorithm-go-snapshot.yml | 49 +++++++++++++++++++ tests/scala/jwt-go-none-algorithm-go-test.yml | 32 ++++++++++++ 4 files changed, 124 insertions(+) create mode 100644 rules/scala/security/jwt-go-none-algorithm-go.yml rename rules/scala/{ => security}/jwt-scala-hardcode-scala.yml (100%) create mode 100644 tests/__snapshots__/jwt-go-none-algorithm-go-snapshot.yml create mode 100644 tests/scala/jwt-go-none-algorithm-go-test.yml diff --git a/rules/scala/security/jwt-go-none-algorithm-go.yml b/rules/scala/security/jwt-go-none-algorithm-go.yml new file mode 100644 index 00000000..496d995c --- /dev/null +++ b/rules/scala/security/jwt-go-none-algorithm-go.yml @@ -0,0 +1,43 @@ +id: jwt-go-none-algorithm-go +language: go +severity: warning +message: >- + Detected use of the 'none' algorithm in a JWT token. The 'none' + algorithm assumes the integrity of the token has already been verified. + This would allow a malicious actor to forge a JWT token that will + automatically be verified. Do not explicitly use the 'none' algorithm. + Instead, use an algorithm such as 'HS256'. +note: >- + [CWE-327]: Use of a Broken or Risky Cryptographic Algorithm + [OWASP A03:2017]: Sensitive Data Exposure + [OWASP A02:2021]: Cryptographic Failures + [REFERENCES] + https://owasp.org/Top10/A02_2021-Cryptographic_Failures + +ast-grep-essentials: true + +utils: + after_declaration: + inside: + stopBy: end + follows: + stopBy: end + kind: import_declaration + has: + stopBy: end + kind: import_spec + has: + kind: interpreted_string_literal + has: + kind: interpreted_string_literal_content + regex: ^(github.com/dgrijalva/jwt-go|github.com/golang-jwt/jwt)$ + +rule: + kind: selector_expression + all: + - pattern: $JWT_FUNC + - matches: after_declaration + +constraints: + JWT_FUNC: + regex: (jwt.SigningMethodNone|jwt.UnsafeAllowNoneSignatureType) diff --git a/rules/scala/jwt-scala-hardcode-scala.yml b/rules/scala/security/jwt-scala-hardcode-scala.yml similarity index 100% rename from rules/scala/jwt-scala-hardcode-scala.yml rename to rules/scala/security/jwt-scala-hardcode-scala.yml diff --git a/tests/__snapshots__/jwt-go-none-algorithm-go-snapshot.yml b/tests/__snapshots__/jwt-go-none-algorithm-go-snapshot.yml new file mode 100644 index 00000000..d6e5b671 --- /dev/null +++ b/tests/__snapshots__/jwt-go-none-algorithm-go-snapshot.yml @@ -0,0 +1,49 @@ +id: jwt-go-none-algorithm-go +snapshots: + ? | + import ( + "fmt" + "github.com/dgrijalva/jwt-go" + ) + func bad1(key []byte) { + claims := jwt.StandardClaims{ + ExpiresAt:15000, + Issuer:"test" + } + token := jwt.NewWithClaims(jwt.SigningMethodNone, claims) + ss, err := token.SignedString(jwt.UnsafeAllowNoneSignatureType) + fmt.Printf("%v %v\n", ss, err) + } + : labels: + - source: jwt.SigningMethodNone + style: primary + start: 179 + end: 200 + - source: github.com/dgrijalva/jwt-go + style: secondary + start: 20 + end: 47 + - source: '"github.com/dgrijalva/jwt-go"' + style: secondary + start: 19 + end: 48 + - source: '"github.com/dgrijalva/jwt-go"' + style: secondary + start: 19 + end: 48 + - source: |- + import ( + "fmt" + "github.com/dgrijalva/jwt-go" + ) + style: secondary + start: 0 + end: 50 + - source: |- + import ( + "fmt" + "github.com/dgrijalva/jwt-go" + ) + style: secondary + start: 0 + end: 50 diff --git a/tests/scala/jwt-go-none-algorithm-go-test.yml b/tests/scala/jwt-go-none-algorithm-go-test.yml new file mode 100644 index 00000000..33dd8c6f --- /dev/null +++ b/tests/scala/jwt-go-none-algorithm-go-test.yml @@ -0,0 +1,32 @@ +id: jwt-go-none-algorithm-go +valid: + - | + import ( + "fmt" + "github.com/dgrijalva/jwt-go" + ) + func ok1(key []byte){ + claims = jwt.StandardClaims{ + ExpiresAt:15000, + Issuer:"test" + } + token = jwt.NewWithClaims(jwt.SigningMethodHS256, claims) + ss, err = token.SignedString(key) + fmt.Printf("%v %v\n", ss, err) + } + +invalid: + - | + import ( + "fmt" + "github.com/dgrijalva/jwt-go" + ) + func bad1(key []byte) { + claims := jwt.StandardClaims{ + ExpiresAt:15000, + Issuer:"test" + } + token := jwt.NewWithClaims(jwt.SigningMethodNone, claims) + ss, err := token.SignedString(jwt.UnsafeAllowNoneSignatureType) + fmt.Printf("%v %v\n", ss, err) + } From fda0f5c54a7a096334048e14937b3c61f1441aa3 Mon Sep 17 00:00:00 2001 From: ESS-ENN Date: Wed, 26 Mar 2025 11:54:34 +0530 Subject: [PATCH 7/9] changing folder location for jwt-go-none-algorithm-go --- rules/{scala => go}/security/jwt-go-none-algorithm-go.yml | 0 tests/{scala => go}/jwt-go-none-algorithm-go-test.yml | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename rules/{scala => go}/security/jwt-go-none-algorithm-go.yml (100%) rename tests/{scala => go}/jwt-go-none-algorithm-go-test.yml (100%) diff --git a/rules/scala/security/jwt-go-none-algorithm-go.yml b/rules/go/security/jwt-go-none-algorithm-go.yml similarity index 100% rename from rules/scala/security/jwt-go-none-algorithm-go.yml rename to rules/go/security/jwt-go-none-algorithm-go.yml diff --git a/tests/scala/jwt-go-none-algorithm-go-test.yml b/tests/go/jwt-go-none-algorithm-go-test.yml similarity index 100% rename from tests/scala/jwt-go-none-algorithm-go-test.yml rename to tests/go/jwt-go-none-algorithm-go-test.yml From baa8c572124db466d1545e7e51c137ead6e280c8 Mon Sep 17 00:00:00 2001 From: ESS-ENN Date: Wed, 26 Mar 2025 11:56:37 +0530 Subject: [PATCH 8/9] jwt-hardcode-kotlin --- rules/kotlin/security/jwt-hardcode-kotlin.yml | 574 ++++++++++++++++++ .../jwt-hardcode-kotlin-snapshot.yml | 60 ++ tests/kotlin/jwt-hardcode-kotlin-test.yml | 23 + 3 files changed, 657 insertions(+) create mode 100644 rules/kotlin/security/jwt-hardcode-kotlin.yml create mode 100644 tests/__snapshots__/jwt-hardcode-kotlin-snapshot.yml create mode 100644 tests/kotlin/jwt-hardcode-kotlin-test.yml diff --git a/rules/kotlin/security/jwt-hardcode-kotlin.yml b/rules/kotlin/security/jwt-hardcode-kotlin.yml new file mode 100644 index 00000000..91bdc952 --- /dev/null +++ b/rules/kotlin/security/jwt-hardcode-kotlin.yml @@ -0,0 +1,574 @@ +id: jwt-hardcode-kotlin +language: kotlin +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. It is + recommended to rotate the secret and retrieve them from a secure secret + vault or Hardware Security Module (HSM), alternatively environment + variables can be used if allowed by your company policy. +note: >- + [CWE-798]: Use of Hard-coded Credentials + [OWASP A03:2021]: Identification and Authentication Failures + [REFERENCES] + - https://owasp.org/Top10/A07_2021-Identification_and_Authentication_Failures + +ast-grep-essentials: true + +utils: + match_Algorithm_HMAC256_follow_imports: + kind: call_expression + all: + - has: + kind: navigation_expression + all: + - has: + kind: simple_identifier + regex: "^Algorithm$" + - has: + kind: navigation_suffix + has: + kind: simple_identifier + regex: "^HMAC256$" + - has: + kind: call_suffix + has: + kind: value_arguments + not: + has: + nthChild: + position: 2 + ofRule: + not: + kind: line_comment + has: + kind: value_argument + has: + kind: string_literal + not: + regex: '""' + inside: + stopBy: end + follows: + stopBy: end + any: + - kind: import_list + has: + kind: import_header + any: + - pattern: import com.auth0.jwt.algorithms.* + - pattern: import com.auth0.jwt.algorithms.Algorithm + match_HMAC256: + kind: call_expression + all: + - has: + kind: simple_identifier + regex: "^HMAC256$" + - has: + kind: call_suffix + has: + kind: value_arguments + not: + has: + nthChild: + position: 2 + ofRule: + not: + kind: line_comment + has: + kind: value_argument + has: + kind: string_literal + not: + regex: '""' + inside: + stopBy: end + follows: + stopBy: end + any: + - kind: import_list + has: + kind: import_header + any: + - pattern: import com.auth0.jwt.algorithms.Algorithm.* + - pattern: import com.auth0.jwt.algorithms.Algorithm.HMAC256 + match_Algorithm_HMAC384: + kind: call_expression + all: + - has: + kind: navigation_expression + all: + - has: + kind: simple_identifier + regex: "^Algorithm$" + - has: + kind: navigation_suffix + has: + kind: simple_identifier + regex: "^HMAC384$" + - has: + kind: call_suffix + has: + kind: value_arguments + not: + has: + nthChild: + position: 2 + ofRule: + not: + kind: line_comment + has: + kind: value_argument + has: + kind: string_literal + not: + regex: '""' + inside: + stopBy: end + follows: + stopBy: end + any: + - kind: import_list + has: + kind: import_header + any: + - pattern: import com.auth0.jwt.algorithms.* + - pattern: import com.auth0.jwt.algorithms.Algorithm + match_HMAC384: + kind: call_expression + all: + - has: + kind: simple_identifier + regex: "^HMAC384$" + - has: + kind: call_suffix + has: + kind: value_arguments + not: + has: + nthChild: + position: 2 + ofRule: + not: + kind: line_comment + has: + kind: value_argument + has: + kind: string_literal + not: + regex: '""' + inside: + stopBy: end + follows: + stopBy: end + any: + - kind: import_list + has: + kind: import_header + any: + - pattern: import com.auth0.jwt.algorithms.Algorithm.* + - pattern: import com.auth0.jwt.algorithms.Algorithm.HMAC384 + match_algorithm_HMAC512: + kind: call_expression + all: + - has: + kind: navigation_expression + all: + - has: + kind: simple_identifier + regex: "^Algorithm$" + - has: + kind: navigation_suffix + has: + kind: simple_identifier + regex: "^HMAC512$" + - has: + kind: call_suffix + has: + kind: value_arguments + not: + has: + nthChild: + position: 2 + ofRule: + not: + kind: line_comment + has: + kind: value_argument + has: + kind: string_literal + not: + regex: '""' + inside: + stopBy: end + follows: + stopBy: end + any: + - kind: import_list + has: + kind: import_header + any: + - pattern: import com.auth0.jwt.algorithms.* + - pattern: import com.auth0.jwt.algorithms.Algorithm + match_HMAC512: + kind: call_expression + all: + - has: + kind: simple_identifier + regex: "^HMAC512$" + - has: + kind: call_suffix + has: + kind: value_arguments + not: + has: + nthChild: + position: 2 + ofRule: + not: + kind: line_comment + has: + kind: value_argument + has: + kind: string_literal + not: + regex: '""' + inside: + stopBy: end + follows: + stopBy: end + any: + - kind: import_list + has: + kind: import_header + any: + - pattern: import com.auth0.jwt.algorithms.Algorithm.* + - pattern: import com.auth0.jwt.algorithms.Algorithm.HMAC512 + match_Algorithm_HMAC256_follow_imports_with_identifier: + kind: call_expression + all: + - has: + kind: navigation_expression + all: + - has: + kind: simple_identifier + regex: "^Algorithm$" + - has: + kind: navigation_suffix + has: + kind: simple_identifier + regex: "^HMAC256$" + - has: + kind: call_suffix + has: + kind: value_arguments + not: + has: + nthChild: + position: 2 + ofRule: + not: + kind: line_comment + has: + kind: value_argument + has: + kind: simple_identifier + pattern: $A + inside: + stopBy: end + follows: + stopBy: end + kind: property_declaration + all: + - has: + kind: variable_declaration + has: + kind: simple_identifier + pattern: $A + - has: + kind: string_literal + not: + regex: '""' + inside: + stopBy: end + follows: + stopBy: end + any: + - kind: import_list + has: + kind: import_header + any: + - pattern: import com.auth0.jwt.algorithms.* + - pattern: import com.auth0.jwt.algorithms.Algorithm + match_HMAC256_with_identifier: + kind: call_expression + all: + - has: + kind: simple_identifier + regex: "^HMAC256$" + - has: + kind: call_suffix + has: + kind: value_arguments + not: + has: + nthChild: + position: 2 + ofRule: + not: + kind: line_comment + has: + kind: value_argument + has: + kind: simple_identifier + pattern: $B + inside: + stopBy: end + follows: + stopBy: end + kind: property_declaration + all: + - has: + kind: variable_declaration + has: + kind: simple_identifier + pattern: $B + - has: + kind: string_literal + not: + regex: '""' + inside: + stopBy: end + follows: + stopBy: end + any: + - kind: import_list + has: + kind: import_header + any: + - pattern: import com.auth0.jwt.algorithms.Algorithm.* + - pattern: import com.auth0.jwt.algorithms.Algorithm.HMAC256 + match_Algorithm_HMAC384_with_identifier: + kind: call_expression + all: + - has: + kind: navigation_expression + all: + - has: + kind: simple_identifier + regex: "^Algorithm$" + - has: + kind: navigation_suffix + has: + kind: simple_identifier + regex: "^HMAC384$" + - has: + kind: call_suffix + has: + kind: value_arguments + not: + has: + nthChild: + position: 2 + ofRule: + not: + kind: line_comment + has: + kind: value_argument + has: + kind: simple_identifier + pattern: $C + inside: + stopBy: end + follows: + stopBy: end + kind: property_declaration + all: + - has: + kind: variable_declaration + has: + kind: simple_identifier + pattern: $C + - has: + kind: string_literal + not: + regex: '""' + inside: + stopBy: end + follows: + stopBy: end + any: + - kind: import_list + has: + kind: import_header + any: + - pattern: import com.auth0.jwt.algorithms.* + - pattern: import com.auth0.jwt.algorithms.Algorithm + match_HMAC384_with_identifier: + kind: call_expression + all: + - has: + kind: simple_identifier + regex: "^HMAC384$" + - has: + kind: call_suffix + has: + kind: value_arguments + not: + has: + nthChild: + position: 2 + ofRule: + not: + kind: line_comment + has: + kind: value_argument + has: + kind: simple_identifier + pattern: $D + inside: + stopBy: end + follows: + stopBy: end + kind: property_declaration + all: + - has: + kind: variable_declaration + has: + kind: simple_identifier + pattern: $D + - has: + kind: string_literal + not: + regex: '""' + inside: + stopBy: end + follows: + stopBy: end + any: + - kind: import_list + has: + kind: import_header + any: + - pattern: import com.auth0.jwt.algorithms.Algorithm.* + - pattern: import com.auth0.jwt.algorithms.Algorithm.HMAC384 + match_algorithm_HMAC512_with_identifier: + kind: call_expression + all: + - has: + kind: navigation_expression + all: + - has: + kind: simple_identifier + regex: "^Algorithm$" + - has: + kind: navigation_suffix + has: + kind: simple_identifier + regex: "^HMAC512$" + - has: + kind: call_suffix + has: + kind: value_arguments + not: + has: + nthChild: + position: 2 + ofRule: + not: + kind: line_comment + has: + kind: value_argument + has: + kind: simple_identifier + pattern: $E + inside: + stopBy: end + follows: + stopBy: end + kind: property_declaration + all: + - has: + kind: variable_declaration + has: + kind: simple_identifier + pattern: $E + - has: + kind: string_literal + not: + regex: '""' + inside: + stopBy: end + follows: + stopBy: end + any: + - kind: import_list + has: + kind: import_header + any: + - pattern: import com.auth0.jwt.algorithms.* + - pattern: import com.auth0.jwt.algorithms.Algorithm + match_HMAC512_with_identifier: + kind: call_expression + all: + - has: + kind: simple_identifier + regex: "^HMAC512$" + - has: + kind: call_suffix + has: + kind: value_arguments + not: + has: + nthChild: + position: 2 + ofRule: + not: + kind: line_comment + has: + kind: value_argument + has: + kind: simple_identifier + pattern: $F + inside: + stopBy: end + follows: + stopBy: end + kind: property_declaration + all: + - has: + kind: variable_declaration + has: + kind: simple_identifier + pattern: $F + - has: + kind: string_literal + not: + regex: '""' + inside: + stopBy: end + follows: + stopBy: end + any: + - kind: import_list + has: + kind: import_header + any: + - pattern: import com.auth0.jwt.algorithms.Algorithm.* + - pattern: import com.auth0.jwt.algorithms.Algorithm.HMAC512 + +rule: + any: + - matches: match_Algorithm_HMAC256_follow_imports + - matches: match_HMAC256 + - matches: match_Algorithm_HMAC384 + - matches: match_HMAC384 + - matches: match_algorithm_HMAC512 + - matches: match_HMAC512 + - matches: match_Algorithm_HMAC256_follow_imports_with_identifier + - matches: match_HMAC256_with_identifier + - matches: match_Algorithm_HMAC384_with_identifier + - matches: match_HMAC384_with_identifier + - matches: match_algorithm_HMAC512_with_identifier + - matches: match_HMAC512_with_identifier diff --git a/tests/__snapshots__/jwt-hardcode-kotlin-snapshot.yml b/tests/__snapshots__/jwt-hardcode-kotlin-snapshot.yml new file mode 100644 index 00000000..636bc434 --- /dev/null +++ b/tests/__snapshots__/jwt-hardcode-kotlin-snapshot.yml @@ -0,0 +1,60 @@ +id: jwt-hardcode-kotlin +snapshots: + ? "package com.foobar.org.configuration\nimport com.auth0.jwt.JWT\nimport com.auth0.jwt.algorithms.Algorithm\nimport com.auth0.jwt.algorithms.Algorithm.HMAC512\nimport com.auth0.jwt.exceptions.JWTCreationException\nobject App {\n private fun bad1() {\n try {\n val algorithm = Algorithm.HMAC256(\"secret\")\n val token = JWT.create()\n .withIssuer(\"auth0\")\n .sign(algorithm)\n } \n catch (exception: JWTCreationException) {}\n }\n}\n" + : labels: + - source: Algorithm.HMAC256("secret") + style: primary + start: 275 + end: 302 + - source: Algorithm + style: secondary + start: 275 + end: 284 + - source: HMAC256 + style: secondary + start: 285 + end: 292 + - source: .HMAC256 + style: secondary + start: 284 + end: 292 + - source: Algorithm.HMAC256 + style: secondary + start: 275 + end: 292 + - source: '"secret"' + style: secondary + start: 293 + end: 301 + - source: '"secret"' + style: secondary + start: 293 + end: 301 + - source: ("secret") + style: secondary + start: 292 + end: 302 + - source: ("secret") + style: secondary + start: 292 + end: 302 + - source: import com.auth0.jwt.algorithms.Algorithm + style: secondary + start: 62 + end: 103 + - source: |- + import com.auth0.jwt.JWT + import com.auth0.jwt.algorithms.Algorithm + import com.auth0.jwt.algorithms.Algorithm.HMAC512 + import com.auth0.jwt.exceptions.JWTCreationException + style: secondary + start: 37 + end: 206 + - source: |- + import com.auth0.jwt.JWT + import com.auth0.jwt.algorithms.Algorithm + import com.auth0.jwt.algorithms.Algorithm.HMAC512 + import com.auth0.jwt.exceptions.JWTCreationException + style: secondary + start: 37 + end: 206 diff --git a/tests/kotlin/jwt-hardcode-kotlin-test.yml b/tests/kotlin/jwt-hardcode-kotlin-test.yml new file mode 100644 index 00000000..eb163b6e --- /dev/null +++ b/tests/kotlin/jwt-hardcode-kotlin-test.yml @@ -0,0 +1,23 @@ +id: jwt-hardcode-kotlin +valid: + - | + System.setProperty("javax.net.ssl.trustStorePassword", config); + System.setProperty("javax.net.ssl.keyStorePassword", config); +invalid: + - | + package com.foobar.org.configuration + import com.auth0.jwt.JWT + import com.auth0.jwt.algorithms.Algorithm + import com.auth0.jwt.algorithms.Algorithm.HMAC512 + import com.auth0.jwt.exceptions.JWTCreationException + object App { + private fun bad1() { + try { + val algorithm = Algorithm.HMAC256("secret") + val token = JWT.create() + .withIssuer("auth0") + .sign(algorithm) + } + catch (exception: JWTCreationException) {} + } + } From c0a0ac63d5a66107136c494d2f23541bb09c054e Mon Sep 17 00:00:00 2001 From: ESS-ENN Date: Wed, 26 Mar 2025 12:00:58 +0530 Subject: [PATCH 9/9] scala-jwt-hardcoded-secret-scala --- .../scala-jwt-hardcoded-secret-scala.yml | 183 ++++++++++++++++++ ...la-jwt-hardcoded-secret-scala-snapshot.yml | 80 ++++++++ .../scala-jwt-hardcoded-secret-scala-test.yml | 52 +++++ 3 files changed, 315 insertions(+) create mode 100644 rules/scala/security/scala-jwt-hardcoded-secret-scala.yml create mode 100644 tests/__snapshots__/scala-jwt-hardcoded-secret-scala-snapshot.yml create mode 100644 tests/scala/scala-jwt-hardcoded-secret-scala-test.yml diff --git a/rules/scala/security/scala-jwt-hardcoded-secret-scala.yml b/rules/scala/security/scala-jwt-hardcoded-secret-scala.yml new file mode 100644 index 00000000..20b710c2 --- /dev/null +++ b/rules/scala/security/scala-jwt-hardcoded-secret-scala.yml @@ -0,0 +1,183 @@ +id: scala-jwt-hardcoded-secret-scala +severity: warning +language: scala +message: >- + Hardcoded JWT secret or private key is used. This is a Insufficiently + Protected Credentials weakness: + https://cwe.mitre.org/data/definitions/522.html Consider using an + appropriate security mechanism to protect the credentials (e.g. keeping + secrets in environment variables). +note: >- + [CWE-522] Insufficiently Protected Credentials. + [REFERENCES] + - https://owasp.org/Top10/A04_2021-Insecure_Design + +ast-grep-essentials: true + +utils: + call_expression_HMAC256: + kind: call_expression + all: + - has: + kind: field_expression + nthChild: 1 + all: + - has: + kind: identifier + field: value + nthChild: 1 + regex: ^(Algorithm)$ + - has: + kind: identifier + field: field + nthChild: 2 + regex: ^(HMAC256)$ + - has: + kind: arguments + nthChild: 2 + has: + nthChild: + position: 1 + ofRule: + not: + kind: comment + kind: identifier + pattern: $STRG + + call_expression_HMAC256_no_import: + kind: call_expression + all: + - has: + kind: field_expression + nthChild: 1 + regex: ^(com\.auth0\.jwt\.algorithms\.Algorithm\.(HMAC256|HMAC512|HMAC384))$ + - has: + kind: arguments + nthChild: 2 + has: + nthChild: + position: 1 + ofRule: + not: + kind: comment + kind: identifier + pattern: $STRG + +rule: + any: + - kind: call_expression + all: + - has: + kind: field_expression + nthChild: 1 + regex: ^(com.auth0.jwt.algorithms.Algorithm.HMAC256|com.auth0.jwt.algorithms.Algorithm.HMAC384|com.auth0.jwt.algorithms.Algorithm.HMAC512)$ + precedes: + kind: arguments + not: + has: + nthChild: + position: 2 + ofRule: + not: + kind: comment + has: + nthChild: + position: 1 + ofRule: + not: + kind: comment + kind: string + not: + regex: ^""$ + - kind: call_expression + all: + - has: + kind: field_expression + regex: ^(Algorithm.HMAC256|Algorithm.HMAC384|Algorithm.HMAC512)$ + precedes: + kind: arguments + has: + kind: string + nthChild: + position: 1 + ofRule: + not: + kind: comment + not: + regex: ^""$ + not: + has: + nthChild: + position: 2 + ofRule: + not: + kind: comment + - inside: + stopBy: end + follows: + stopBy: end + kind: import_declaration + pattern: import com.auth0.jwt.algorithms.Algorithm + - kind: class_definition + has: + kind: template_body + has: + any: + - kind: val_definition + - kind: assignment_expression + all: + - has: + nthChild: 1 + kind: identifier + pattern: $STRG + - has: + nthChild: 2 + kind: string + not: + regex: ^""$ + - precedes: + stopBy: end + kind: function_definition + has: + kind: block + has: + any: + - matches: call_expression_HMAC256 + - kind: val_definition + has: + nthChild: 2 + matches: call_expression_HMAC256 + + follows: + stopBy: end + kind: import_declaration + pattern: import com.auth0.jwt.algorithms.Algorithm + - kind: class_definition + has: + kind: template_body + has: + any: + - kind: val_definition + - kind: assignment_expression + all: + - has: + nthChild: 1 + kind: identifier + pattern: $STRG + - has: + nthChild: 2 + kind: string + not: + regex: ^""$ + - precedes: + stopBy: end + kind: function_definition + has: + kind: block + has: + any: + - matches: call_expression_HMAC256_no_import + - kind: val_definition + has: + nthChild: 2 + matches: call_expression_HMAC256_no_import diff --git a/tests/__snapshots__/scala-jwt-hardcoded-secret-scala-snapshot.yml b/tests/__snapshots__/scala-jwt-hardcoded-secret-scala-snapshot.yml new file mode 100644 index 00000000..0b95154e --- /dev/null +++ b/tests/__snapshots__/scala-jwt-hardcoded-secret-scala-snapshot.yml @@ -0,0 +1,80 @@ +id: scala-jwt-hardcoded-secret-scala +snapshots: + ? "import com.auth0.jwt.algorithms.Algorithm\nclass App {\n def bad1(): Unit = {\n try {\n val algorithm = Algorithm.HMAC256(\"secret\")\n val token = JWT.create()\n .withIssuer(\"auth0\")\n .sign(algorithm)\n } catch {\n case exception: JWTCreationException => \n println(s\"Error creating JWT: ${exception.getMessage}\")\n }\n }\n}\n" + : labels: + - source: Algorithm.HMAC256("secret") + style: primary + start: 109 + end: 136 + - source: '"secret"' + style: secondary + start: 127 + end: 135 + - source: ("secret") + style: secondary + start: 126 + end: 136 + - source: Algorithm.HMAC256 + style: secondary + start: 109 + end: 126 + - source: import com.auth0.jwt.algorithms.Algorithm + style: secondary + start: 0 + end: 41 + - source: import com.auth0.jwt.algorithms.Algorithm + style: secondary + start: 0 + end: 41 + ? "import com.auth0.jwt.algorithms.Algorithm\nclass AuthService {\n def createAuthToken(username: String): String = {\n try {\n val algorithm = Algorithm.HMAC384(\"secretKey\")\n val token = JWT.create()\n .withIssuer(\"auth0\")\n .withClaim(\"username\", username)\n .sign(algorithm)\n token\n } catch {\n case e: JWTCreationException => \n }\n }\n}\n" + : labels: + - source: Algorithm.HMAC384("secretKey") + style: primary + start: 146 + end: 176 + - source: '"secretKey"' + style: secondary + start: 164 + end: 175 + - source: ("secretKey") + style: secondary + start: 163 + end: 176 + - source: Algorithm.HMAC384 + style: secondary + start: 146 + end: 163 + - source: import com.auth0.jwt.algorithms.Algorithm + style: secondary + start: 0 + end: 41 + - source: import com.auth0.jwt.algorithms.Algorithm + style: secondary + start: 0 + end: 41 + ? "import com.auth0.jwt.algorithms.Algorithm\nclass SessionService {\n def createSessionToken(userId: String): String = {\n try {\n val algorithm = Algorithm.HMAC512(\"secretKey\")\n val token = JWT.create()\n .withIssuer(\"auth0\")\n .withClaim(\"userId\", userId)\n .sign(algorithm)\n token\n } catch {\n case e: JWTCreationException => \n \"\"\n }\n }\n}\n" + : labels: + - source: Algorithm.HMAC512("secretKey") + style: primary + start: 156 + end: 186 + - source: '"secretKey"' + style: secondary + start: 174 + end: 185 + - source: ("secretKey") + style: secondary + start: 173 + end: 186 + - source: Algorithm.HMAC512 + style: secondary + start: 156 + end: 173 + - source: import com.auth0.jwt.algorithms.Algorithm + style: secondary + start: 0 + end: 41 + - source: import com.auth0.jwt.algorithms.Algorithm + style: secondary + start: 0 + end: 41 diff --git a/tests/scala/scala-jwt-hardcoded-secret-scala-test.yml b/tests/scala/scala-jwt-hardcoded-secret-scala-test.yml new file mode 100644 index 00000000..4449ce80 --- /dev/null +++ b/tests/scala/scala-jwt-hardcoded-secret-scala-test.yml @@ -0,0 +1,52 @@ +id: scala-jwt-hardcoded-secret-scala +valid: + - | +invalid: + - | + import com.auth0.jwt.algorithms.Algorithm + class App { + def bad1(): Unit = { + try { + val algorithm = Algorithm.HMAC256("secret") + val token = JWT.create() + .withIssuer("auth0") + .sign(algorithm) + } catch { + case exception: JWTCreationException => + println(s"Error creating JWT: ${exception.getMessage}") + } + } + } + - | + import com.auth0.jwt.algorithms.Algorithm + class SessionService { + def createSessionToken(userId: String): String = { + try { + val algorithm = Algorithm.HMAC512("secretKey") + val token = JWT.create() + .withIssuer("auth0") + .withClaim("userId", userId) + .sign(algorithm) + token + } catch { + case e: JWTCreationException => + "" + } + } + } + - | + import com.auth0.jwt.algorithms.Algorithm + class AuthService { + def createAuthToken(username: String): String = { + try { + val algorithm = Algorithm.HMAC384("secretKey") + val token = JWT.create() + .withIssuer("auth0") + .withClaim("username", username) + .sign(algorithm) + token + } catch { + case e: JWTCreationException => + } + } + }