From 135b932c9c612eebcf78abb6fce2d3ae2b6d1c58 Mon Sep 17 00:00:00 2001 From: David Roe Date: Mon, 2 Oct 2023 12:07:09 +0100 Subject: [PATCH] feat: add hardcoded secret rule --- rules/php/lang/hardcoded_secret.yml | 67 ++++++++ .../__snapshots__/test.js.snap | 146 ++++++++++++++++++ tests/php/lang/hardcoded_secret/test.js | 16 ++ .../lang/hardcoded_secret/testdata/bad.php | 10 ++ .../php/lang/hardcoded_secret/testdata/ok.php | 12 ++ 5 files changed, 251 insertions(+) create mode 100644 rules/php/lang/hardcoded_secret.yml create mode 100644 tests/php/lang/hardcoded_secret/__snapshots__/test.js.snap create mode 100644 tests/php/lang/hardcoded_secret/test.js create mode 100644 tests/php/lang/hardcoded_secret/testdata/bad.php create mode 100644 tests/php/lang/hardcoded_secret/testdata/ok.php diff --git a/rules/php/lang/hardcoded_secret.yml b/rules/php/lang/hardcoded_secret.yml new file mode 100644 index 000000000..127e20a6e --- /dev/null +++ b/rules/php/lang/hardcoded_secret.yml @@ -0,0 +1,67 @@ +patterns: + - pattern: | + $$ = $ + filters: + - variable: NAME + regex: (?i)(password|api_?key|secret)\b + - variable: STRING_LITERAL + detection: string_literal + scope: cursor + - not: + variable: STRING_LITERAL + string_regex: \A[*•]+\z + - pattern: | + const $ = $ + filters: + - variable: NAME + regex: (?i)(password|api_?key|secret)\b + - variable: STRING_LITERAL + detection: string_literal + scope: cursor + - not: + variable: STRING_LITERAL + string_regex: \A[*•]+\z + - pattern: | + array($ => $) + filters: + - variable: NAME + string_regex: (?i)(password|api_?key|secret)\b + - variable: STRING_LITERAL + detection: string_literal + scope: cursor + - not: + variable: STRING_LITERAL + string_regex: \A[*•]+\z + - pattern: | + define($, $); + filters: + - variable: NAME + string_regex: (?i)(password|api_?key|secret)\b + - variable: STRING_LITERAL + detection: string_literal + scope: cursor + - not: + variable: STRING_LITERAL + string_regex: \A[*•]+\z +languages: + - php +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: php_lang_hardcoded_secret + documentation_url: https://docs.bearer.com/reference/rules/php_lang_hardcoded_secret diff --git a/tests/php/lang/hardcoded_secret/__snapshots__/test.js.snap b/tests/php/lang/hardcoded_secret/__snapshots__/test.js.snap new file mode 100644 index 000000000..632eaaba5 --- /dev/null +++ b/tests/php/lang/hardcoded_secret/__snapshots__/test.js.snap @@ -0,0 +1,146 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`php_lang_hardcoded_secret bad 1`] = ` +"{ + "high": [ + { + "cwe_ids": [ + "798" + ], + "id": "php_lang_hardcoded_secret", + "title": "Hard-coded secret detected.", + "description": "## Description\\n\\nApplications should store secret values securely and not as literal values\\nin the source code.\\n\\n## Remediations\\n\\n✅ Retrieve secrets from a secure location at runtime\\n\\n## Resources\\n- [OWASP hardcoded passwords](https://owasp.org/www-community/vulnerabilities/Use_of_hard-coded_password)\\n- [OWASP secrets management cheat sheet](https://cheatsheetseries.owasp.org/cheatsheets/Secrets_Management_Cheat_Sheet.html#21-high-availability)\\n", + "documentation_url": "https://docs.bearer.com/reference/rules/php_lang_hardcoded_secret", + "line_number": 3, + "full_filename": "/tmp/bearer-scan/bad.php", + "filename": ".", + "source": { + "start": 3, + "end": 3, + "column": { + "start": 1, + "end": 19 + } + }, + "sink": { + "start": 3, + "end": 3, + "column": { + "start": 1, + "end": 19 + }, + "content": "$password = \\"oops\\"" + }, + "parent_line_number": 3, + "snippet": "$password = \\"oops\\"", + "fingerprint": "ba37e9f182eb13db954d2068c1b17529_0", + "old_fingerprint": "aa5a00908c71041045b4f43d3f0489f2_0", + "code_extract": "$password = \\"oops\\";" + }, + { + "cwe_ids": [ + "798" + ], + "id": "php_lang_hardcoded_secret", + "title": "Hard-coded secret detected.", + "description": "## Description\\n\\nApplications should store secret values securely and not as literal values\\nin the source code.\\n\\n## Remediations\\n\\n✅ Retrieve secrets from a secure location at runtime\\n\\n## Resources\\n- [OWASP hardcoded passwords](https://owasp.org/www-community/vulnerabilities/Use_of_hard-coded_password)\\n- [OWASP secrets management cheat sheet](https://cheatsheetseries.owasp.org/cheatsheets/Secrets_Management_Cheat_Sheet.html#21-high-availability)\\n", + "documentation_url": "https://docs.bearer.com/reference/rules/php_lang_hardcoded_secret", + "line_number": 5, + "full_filename": "/tmp/bearer-scan/bad.php", + "filename": ".", + "source": { + "start": 5, + "end": 5, + "column": { + "start": 1, + "end": 24 + } + }, + "sink": { + "start": 5, + "end": 5, + "column": { + "start": 1, + "end": 24 + }, + "content": "const API_KEY = \\"oops\\";" + }, + "parent_line_number": 5, + "snippet": "const API_KEY = \\"oops\\";", + "fingerprint": "ba37e9f182eb13db954d2068c1b17529_1", + "old_fingerprint": "aa5a00908c71041045b4f43d3f0489f2_1", + "code_extract": "const API_KEY = \\"oops\\";" + }, + { + "cwe_ids": [ + "798" + ], + "id": "php_lang_hardcoded_secret", + "title": "Hard-coded secret detected.", + "description": "## Description\\n\\nApplications should store secret values securely and not as literal values\\nin the source code.\\n\\n## Remediations\\n\\n✅ Retrieve secrets from a secure location at runtime\\n\\n## Resources\\n- [OWASP hardcoded passwords](https://owasp.org/www-community/vulnerabilities/Use_of_hard-coded_password)\\n- [OWASP secrets management cheat sheet](https://cheatsheetseries.owasp.org/cheatsheets/Secrets_Management_Cheat_Sheet.html#21-high-availability)\\n", + "documentation_url": "https://docs.bearer.com/reference/rules/php_lang_hardcoded_secret", + "line_number": 7, + "full_filename": "/tmp/bearer-scan/bad.php", + "filename": ".", + "source": { + "start": 7, + "end": 7, + "column": { + "start": 5, + "end": 41 + } + }, + "sink": { + "start": 7, + "end": 7, + "column": { + "start": 5, + "end": 41 + }, + "content": "[ \\"secret\\" => \\"oops\\", \\"other\\" => 42]" + }, + "parent_line_number": 7, + "snippet": "[ \\"secret\\" => \\"oops\\", \\"other\\" => 42]", + "fingerprint": "ba37e9f182eb13db954d2068c1b17529_2", + "old_fingerprint": "aa5a00908c71041045b4f43d3f0489f2_2", + "code_extract": "foo([ \\"secret\\" => \\"oops\\", \\"other\\" => 42]);" + }, + { + "cwe_ids": [ + "798" + ], + "id": "php_lang_hardcoded_secret", + "title": "Hard-coded secret detected.", + "description": "## Description\\n\\nApplications should store secret values securely and not as literal values\\nin the source code.\\n\\n## Remediations\\n\\n✅ Retrieve secrets from a secure location at runtime\\n\\n## Resources\\n- [OWASP hardcoded passwords](https://owasp.org/www-community/vulnerabilities/Use_of_hard-coded_password)\\n- [OWASP secrets management cheat sheet](https://cheatsheetseries.owasp.org/cheatsheets/Secrets_Management_Cheat_Sheet.html#21-high-availability)\\n", + "documentation_url": "https://docs.bearer.com/reference/rules/php_lang_hardcoded_secret", + "line_number": 10, + "full_filename": "/tmp/bearer-scan/bad.php", + "filename": ".", + "source": { + "start": 10, + "end": 10, + "column": { + "start": 1, + "end": 22 + } + }, + "sink": { + "start": 10, + "end": 10, + "column": { + "start": 1, + "end": 22 + }, + "content": "define($name, \\"oops\\")" + }, + "parent_line_number": 10, + "snippet": "define($name, \\"oops\\")", + "fingerprint": "ba37e9f182eb13db954d2068c1b17529_3", + "old_fingerprint": "aa5a00908c71041045b4f43d3f0489f2_3", + "code_extract": "define($name, \\"oops\\");" + } + ] +}" +`; + +exports[`php_lang_hardcoded_secret ok 1`] = `"{}"`; diff --git a/tests/php/lang/hardcoded_secret/test.js b/tests/php/lang/hardcoded_secret/test.js new file mode 100644 index 000000000..bca0fa61e --- /dev/null +++ b/tests/php/lang/hardcoded_secret/test.js @@ -0,0 +1,16 @@ +const { createInvoker, getEnvironment } = require("../../../helper.js") +const { ruleId, ruleFile, testBase } = getEnvironment(__dirname) + +describe(ruleId, () => { + const invoke = createInvoker(ruleId, ruleFile, testBase) + + test("bad", () => { + const testCase = "bad.php" + expect(invoke(testCase)).toMatchSnapshot() + }) + + test("ok", () => { + const testCase = "ok.php" + expect(invoke(testCase)).toMatchSnapshot() + }) +}) diff --git a/tests/php/lang/hardcoded_secret/testdata/bad.php b/tests/php/lang/hardcoded_secret/testdata/bad.php new file mode 100644 index 000000000..0c062529f --- /dev/null +++ b/tests/php/lang/hardcoded_secret/testdata/bad.php @@ -0,0 +1,10 @@ + "oops", "other" => 42]); + +$name = "SECRET_PASSWORD"; +define($name, "oops"); diff --git a/tests/php/lang/hardcoded_secret/testdata/ok.php b/tests/php/lang/hardcoded_secret/testdata/ok.php new file mode 100644 index 000000000..421a36723 --- /dev/null +++ b/tests/php/lang/hardcoded_secret/testdata/ok.php @@ -0,0 +1,12 @@ + $ok, "other" => 42]); + +$name = "SECRET_PASSWORD"; +define($name, $ok); +define($name, "**"); +define($name, "•••••");