diff --git a/rules/java/lang/hardcoded_secret.yml b/rules/java/lang/hardcoded_secret.yml new file mode 100644 index 000000000..66544a005 --- /dev/null +++ b/rules/java/lang/hardcoded_secret.yml @@ -0,0 +1,109 @@ +patterns: + - pattern: $<...>char[] $ = $.toCharArray() + filters: + - variable: NAME + detection: java_lang_hardcoded_secret_name + scope: cursor_strict + - variable: STRING_LITERAL + detection: java_lang_hardcoded_secret_literal + scope: cursor + - pattern: | + class $<...>$<_> $<...> { + $$<...>char[] $ = $.toCharArray() + } + filters: + - variable: NAME + detection: java_lang_hardcoded_secret_name + scope: cursor_strict + - variable: STRING_LITERAL + detection: java_lang_hardcoded_secret_literal + scope: cursor + - pattern: $<...>char[] $ = {}; + filters: + - variable: NAME + detection: java_lang_hardcoded_secret_name + scope: cursor_strict + - pattern: | + class $<...>$<_> $<...> { + $$<...>char[] $ = {}; + } + filters: + - variable: NAME + detection: java_lang_hardcoded_secret_name + scope: cursor_strict + - pattern: $<...>byte[] $ = new byte[] {}; + filters: + - variable: NAME + detection: java_lang_hardcoded_secret_name + scope: cursor_strict + - pattern: | + class $<...>$<_> $<...> { + $$<...>byte[] $ = new byte[] {}; + } + filters: + - variable: NAME + detection: java_lang_hardcoded_secret_name + scope: cursor_strict + - pattern: $<...>String $ = $; + filters: + - variable: NAME + detection: java_lang_hardcoded_secret_name + scope: cursor_strict + - variable: STRING_LITERAL + detection: java_lang_hardcoded_secret_literal + scope: cursor + - pattern: | + class $<...>$<_> $<...> { + $$<...>String $ = $; + } + filters: + - variable: NAME + detection: java_lang_hardcoded_secret_name + scope: cursor_strict + - variable: STRING_LITERAL + detection: java_lang_hardcoded_secret_literal + scope: cursor +auxiliary: + - id: java_lang_hardcoded_secret_name + patterns: + - pattern: $; + filters: + - either: + - variable: NAME + regex: (?i)(password|api_?key|api?key|secret)\b + - variable: NAME + regex: (?i)(pass|pwd|psw|cipher|crypt|des|aes|mac|private|secret|sign|cert).* + - id: java_lang_hardcoded_secret_literal + patterns: + - pattern: $; + filters: + - variable: STRING + detection: string_literal + scope: cursor_strict + - not: + variable: STRING + string_regex: \A[*•]+\z + - variable: STRING + entropy_greater_than: 3.5 +languages: + - java +severity: high +metadata: + description: "Hard-coded secret detected." + remediation_message: | + ## Description + + Applications should store secret values securely and not as literal values + in the source code. + + ## Remediations + + ✅ Retrieve secrets from a secure location at runtime + + ## Resources + - [OWASP hardcoded passwords](https://owasp.org/www-community/vulnerabilities/Use_of_hard-coded_password) + - [OWASP secrets management cheat sheet](https://cheatsheetseries.owasp.org/cheatsheets/Secrets_Management_Cheat_Sheet.html#21-high-availability) + cwe_id: + - 798 + id: java_lang_hardcoded_secret + documentation_url: https://docs.bearer.com/reference/rules/java_lang_hardcoded_secret diff --git a/tests/java/lang/hardcoded_secret/test.js b/tests/java/lang/hardcoded_secret/test.js new file mode 100644 index 000000000..f4432d372 --- /dev/null +++ b/tests/java/lang/hardcoded_secret/test.js @@ -0,0 +1,18 @@ +const { + createNewInvoker, + getEnvironment, +} = require("../../../helper.js") +const { ruleId, ruleFile, testBase } = getEnvironment(__dirname) + +describe(ruleId, () => { + const invoke = createNewInvoker(ruleId, ruleFile, testBase) + + test("hardcoded_secret", () => { + const testCase = "main.java" + + const results = invoke(testCase) + + expect(results.Missing).toEqual([]) + expect(results.Extra).toEqual([]) + }) +}) \ No newline at end of file diff --git a/tests/java/lang/hardcoded_secret/testdata/main.java b/tests/java/lang/hardcoded_secret/testdata/main.java new file mode 100644 index 000000000..e0ed17d9e --- /dev/null +++ b/tests/java/lang/hardcoded_secret/testdata/main.java @@ -0,0 +1,46 @@ +package password; +import java.util.Arrays; + +public class ShareTheSecrets { + // ok + private static final byte[] PUBLIC_KEY = new byte[] { 1, 2, 3, 4, 5, 6, 7 }; + // bearer:expected java_lang_hardcoded_secret + final String pass2 = "f#a};!y~7VBcu<&F@[%,{b"; + // bearer:expected java_lang_hardcoded_secret + private static final byte[] API_KEY = new byte[] { 1, 2, 3, 4, 5, 6, 7 }; + // bearer:expected java_lang_hardcoded_secret + private static final String PWD = "hV#;N.F9j}'v5Y-XJc])P*"; + // bearer:expected java_lang_hardcoded_secret + private static final char[] password = { 's', 'e', 'c', 'r', 'e', 't', '5' }; + // bearer:expected java_lang_hardcoded_secret + public static final String API_KEY = ".uYikE-os3cM23rz.i6Q"; + + public static void bad() throws Exception { + // bearer:expected java_lang_hardcoded_secret + final String pass2 = "f#a};!y~7VBcu<&F@[%,{b"; + // bearer:expected java_lang_hardcoded_secret + char[] ciphertext = "gSbDu-wAE7ZL#[tG4'jfx>