From be3993b60a7f6553f66f1bafb1c3f04e72e70b36 Mon Sep 17 00:00:00 2001 From: DmitriyLewen <91113035+DmitriyLewen@users.noreply.github.com> Date: Thu, 12 May 2022 12:21:42 +0600 Subject: [PATCH] fix(secrets): skip aws secrets of greater length (fanal#514) --- secret/builtin-rules.go | 29 +++++++++++++++------- secret/scanner_test.go | 32 +++++++++++++++++++++++++ secret/testdata/aws-secrets.txt | 3 +++ secret/testdata/invalid-aws-secrets.txt | 6 +++++ 4 files changed, 62 insertions(+), 8 deletions(-) create mode 100644 secret/testdata/aws-secrets.txt create mode 100644 secret/testdata/invalid-aws-secrets.txt diff --git a/secret/builtin-rules.go b/secret/builtin-rules.go index 4ba0695d30..1f9df915a6 100644 --- a/secret/builtin-rules.go +++ b/secret/builtin-rules.go @@ -1,6 +1,8 @@ package secret import ( + "fmt" + "github.com/aquasecurity/fanal/types" ) @@ -64,21 +66,32 @@ var ( CategoryTypeform = types.SecretRuleCategory("Typeform") ) +// Reusable regex patterns +const ( + quote = `["']?` + connect = `\s*(:|=>|=)\s*` + startSecret = `(^|\s+)` + endSecret = `(\s+|$)` + + aws = `(aws)?_?` +) + var builtinRules = []Rule{ { - ID: "aws-access-key-id", - Category: CategoryAWS, - Severity: "CRITICAL", - Title: "AWS Access Key ID", - Regex: MustCompile(`(A3T[A-Z0-9]|AKIA|AGPA|AIDA|AROA|AIPA|ANPA|ANVA|ASIA)[A-Z0-9]{16}`), - Keywords: []string{"AKIA", "AGPA", "AIDA", "AROA", "AIPA", "ANPA", "ANVA", "ASIA"}, + ID: "aws-access-key-id", + Category: CategoryAWS, + Severity: "CRITICAL", + Title: "AWS Access Key ID", + Regex: MustCompile(fmt.Sprintf(`(?P(A3T[A-Z0-9]|AKIA|AGPA|AIDA|AROA|AIPA|ANPA|ANVA|ASIA)[A-Z0-9]{16})%s`, endSecret)), + SecretGroupName: "secret", + Keywords: []string{"AKIA", "AGPA", "AIDA", "AROA", "AIPA", "ANPA", "ANVA", "ASIA"}, }, { ID: "aws-secret-access-key", Category: CategoryAWS, Severity: "CRITICAL", Title: "AWS Secret Access Key", - Regex: MustCompile(`(?i)["']?(aws)?_?(secret)?_?(access)?_?key["']?\s*(:|=>|=)\s*(?P["']?[A-Za-z0-9\/\+=]{40})["']?`), + Regex: MustCompile(fmt.Sprintf(`(?i)%s%s%s(secret)?_?(access)?_?key%s%s%s(?P[A-Za-z0-9\/\+=]{40})%s%s`, startSecret, quote, aws, quote, connect, quote, quote, endSecret)), SecretGroupName: "secret", Keywords: []string{"key"}, }, @@ -87,7 +100,7 @@ var builtinRules = []Rule{ Category: CategoryAWS, Severity: "HIGH", Title: "AWS Account ID", - Regex: MustCompile(`(?i)["']?(aws)?_?account_?(id)?["']?\s*(:|=>|=)\s*['"]?(?P[0-9]{4}\-?[0-9]{4}\-?[0-9]{4})['"]?`), + Regex: MustCompile(fmt.Sprintf(`(?i)%s%s%saccount_?(id)?%s%s%s(?P[0-9]{4}\-?[0-9]{4}\-?[0-9]{4})%s%s`, startSecret, quote, aws, quote, connect, quote, quote, endSecret)), SecretGroupName: "secret", Keywords: []string{"account"}, }, diff --git a/secret/scanner_test.go b/secret/scanner_test.go index bf604b2502..ecedd782f7 100644 --- a/secret/scanner_test.go +++ b/secret/scanner_test.go @@ -94,6 +94,24 @@ func TestSecretScanner(t *testing.T) { EndLine: 2, Match: "generic secret line secret=\"*****\"", } + wantFinding9 := types.SecretFinding{ + RuleID: "aws-secret-access-key", + Category: secret.CategoryAWS, + Title: "AWS Secret Access Key", + Severity: "CRITICAL", + StartLine: 1, + EndLine: 1, + Match: `'AWS_secret_KEY'="*****"`, + } + wantFinding10 := types.SecretFinding{ + RuleID: "aws-account-id", + Category: secret.CategoryAWS, + Title: "AWS Account ID", + Severity: "HIGH", + StartLine: 3, + EndLine: 3, + Match: `"aws_account_ID":'*****'`, + } tests := []struct { name string @@ -110,6 +128,15 @@ func TestSecretScanner(t *testing.T) { Findings: []types.SecretFinding{wantFinding1, wantFinding2}, }, }, + { + name: "find aws secrets", + configPath: "testdata/config.yaml", + inputFilePath: "testdata/aws-secrets.txt", + want: types.Secret{ + FilePath: "testdata/aws-secrets.txt", + Findings: []types.SecretFinding{wantFinding5, wantFinding9, wantFinding10}, + }, + }, { name: "include when keyword found", configPath: "testdata/config-happy-keywords.yaml", @@ -258,6 +285,11 @@ func TestSecretScanner(t *testing.T) { Findings: []types.SecretFinding{wantFinding8}, }, }, + { + name: "invalid aws secrets", + inputFilePath: "testdata/invalid-aws-secrets.txt", + want: types.Secret{}, + }, } for _, tt := range tests { diff --git a/secret/testdata/aws-secrets.txt b/secret/testdata/aws-secrets.txt new file mode 100644 index 0000000000..2ef5934dd2 --- /dev/null +++ b/secret/testdata/aws-secrets.txt @@ -0,0 +1,3 @@ +'AWS_secret_KEY'="12ASD34qwe56CXZ78tyH10Tna543VBokN85RHCas" +AWS_ACCESS_KEY_ID=AKIA0123456789ABCDEF +"aws_account_ID":'1234-5678-9123' \ No newline at end of file diff --git a/secret/testdata/invalid-aws-secrets.txt b/secret/testdata/invalid-aws-secrets.txt new file mode 100644 index 0000000000..4549e696d7 --- /dev/null +++ b/secret/testdata/invalid-aws-secrets.txt @@ -0,0 +1,6 @@ +base64: +YXdzLWFjY2AIPA1rZXktaWQgdGVzdCBzdHJpbmc= +web.config file in windows containers: +publicKey="F1645C4C0C93C1AB99285D622CAA652C1DFAD63D745D6F2DE5F17E5EAF0FC4963D261C8A12436518206DC093344D5AD293" +length is too long: +"AWS_key":HGM724ngha9785NGKbbar6jk76mnLL80BHJnabyhdngha9785NGKbb6jk76mnLL8 \ No newline at end of file