Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(java): add hardcoded secret rule (CWE-798) #206

Merged
merged 1 commit into from
Jan 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
109 changes: 109 additions & 0 deletions rules/java/lang/hardcoded_secret.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
patterns:
- pattern: $<...>char[] $<NAME> = $<STRING_LITERAL>.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[] $<NAME> = $<STRING_LITERAL>.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[] $<NAME> = {};
filters:
- variable: NAME
detection: java_lang_hardcoded_secret_name
scope: cursor_strict
- pattern: |
class $<...>$<_> $<...> {
$<!>$<...>char[] $<NAME> = {};
}
filters:
- variable: NAME
detection: java_lang_hardcoded_secret_name
scope: cursor_strict
- pattern: $<...>byte[] $<NAME> = new byte[] {};
filters:
- variable: NAME
detection: java_lang_hardcoded_secret_name
scope: cursor_strict
- pattern: |
class $<...>$<_> $<...> {
$<!>$<...>byte[] $<NAME> = new byte[] {};
}
filters:
- variable: NAME
detection: java_lang_hardcoded_secret_name
scope: cursor_strict
- pattern: $<...>String $<NAME> = $<STRING_LITERAL>;
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 $<NAME> = $<STRING_LITERAL>;
}
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: $<NAME>;
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: $<STRING>;
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
18 changes: 18 additions & 0 deletions tests/java/lang/hardcoded_secret/test.js
Original file line number Diff line number Diff line change
@@ -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([])
})
})
46 changes: 46 additions & 0 deletions tests/java/lang/hardcoded_secret/testdata/main.java
Original file line number Diff line number Diff line change
@@ -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";
cfabianski marked this conversation as resolved.
Show resolved Hide resolved

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><HFdVk;5a".toCharArray();
// bearer:expected java_lang_hardcoded_secret
char[] secret = { 's', 'e', 'c', 'r', 'e', 't' };
}

public void alsoBad() throws Exception {
// bearer:expected java_lang_hardcoded_secret
char[] pwd1 = PWD.toCharArray();
// bearer:expected java_lang_hardcoded_secret
public char[] apiKey = {"s", "e", "c", "r", "e", "t"};
// bearer:expected java_lang_hardcoded_secret
char[] pwd = ".uYikE-os3cM23rz.i6Q".toCharArray();
}

public void good() throws Exception {
// test-like data
char[] apiKey = "my-secret-key";
final String API_KEY = "Enter API";
final String pwd = "testing";

// null data
public String password = null;
char[] apiKey =
}
}
Loading