Просмотр исходного кода

adding stopwords (#849)

* adding stopwords

* format readme, update default config
Zachary Rice 3 лет назад
Родитель
Сommit
8481f0e9cd
64 измененных файлов с 181 добавлено и 109 удалено
  1. 25 12
      README.md
  2. 3 0
      cmd/generate/config/main.go
  3. 2 2
      cmd/generate/config/rules/adobe.go
  4. 1 1
      cmd/generate/config/rules/age.go
  5. 2 2
      cmd/generate/config/rules/alibaba.go
  6. 2 2
      cmd/generate/config/rules/asana.go
  7. 1 1
      cmd/generate/config/rules/atlassian.go
  8. 1 1
      cmd/generate/config/rules/aws.go
  9. 1 1
      cmd/generate/config/rules/beamer.go
  10. 2 2
      cmd/generate/config/rules/bitbucket.go
  11. 1 1
      cmd/generate/config/rules/clojars.go
  12. 3 0
      cmd/generate/config/rules/config.tmpl
  13. 1 1
      cmd/generate/config/rules/contentful.go
  14. 1 1
      cmd/generate/config/rules/databricks.go
  15. 3 3
      cmd/generate/config/rules/discord.go
  16. 1 1
      cmd/generate/config/rules/doppler.go
  17. 1 1
      cmd/generate/config/rules/dropbox.go
  18. 1 1
      cmd/generate/config/rules/duffel.go
  19. 1 1
      cmd/generate/config/rules/dynatrace.go
  20. 2 2
      cmd/generate/config/rules/easypost.go
  21. 1 1
      cmd/generate/config/rules/facebook.go
  22. 1 1
      cmd/generate/config/rules/fastly.go
  23. 2 2
      cmd/generate/config/rules/finicity.go
  24. 3 3
      cmd/generate/config/rules/flutterwave.go
  25. 1 1
      cmd/generate/config/rules/frameio.go
  26. 1 1
      cmd/generate/config/rules/gcp.go
  27. 4 1
      cmd/generate/config/rules/generic.go
  28. 4 4
      cmd/generate/config/rules/github.go
  29. 1 1
      cmd/generate/config/rules/gitlab.go
  30. 1 1
      cmd/generate/config/rules/gocardless.go
  31. 1 1
      cmd/generate/config/rules/hashicorp.go
  32. 1 1
      cmd/generate/config/rules/heroku.go
  33. 1 1
      cmd/generate/config/rules/hubspot.go
  34. 1 1
      cmd/generate/config/rules/intercom.go
  35. 2 2
      cmd/generate/config/rules/linear.go
  36. 2 2
      cmd/generate/config/rules/linkedin.go
  37. 2 2
      cmd/generate/config/rules/lob.go
  38. 1 1
      cmd/generate/config/rules/mailchimp.go
  39. 3 3
      cmd/generate/config/rules/mailgun.go
  40. 1 1
      cmd/generate/config/rules/mapbox.go
  41. 2 2
      cmd/generate/config/rules/messagebird.go
  42. 3 3
      cmd/generate/config/rules/newrelic.go
  43. 1 1
      cmd/generate/config/rules/npm.go
  44. 2 2
      cmd/generate/config/rules/planetscale.go
  45. 1 1
      cmd/generate/config/rules/postman.go
  46. 1 1
      cmd/generate/config/rules/privatekey.go
  47. 1 1
      cmd/generate/config/rules/pulumi.go
  48. 1 1
      cmd/generate/config/rules/pypi.go
  49. 1 1
      cmd/generate/config/rules/rubygems.go
  50. 18 2
      cmd/generate/config/rules/rule.go
  51. 1 1
      cmd/generate/config/rules/sendgrid.go
  52. 1 1
      cmd/generate/config/rules/sendinblue.go
  53. 1 1
      cmd/generate/config/rules/shippo.go
  54. 4 4
      cmd/generate/config/rules/shopify.go
  55. 2 2
      cmd/generate/config/rules/slack.go
  56. 1 1
      cmd/generate/config/rules/stripe.go
  57. 1 1
      cmd/generate/config/rules/twilio.go
  58. 1 1
      cmd/generate/config/rules/twitch.go
  59. 1 1
      cmd/generate/config/rules/twitter.go
  60. 1 1
      cmd/generate/config/rules/typeform.go
  61. 18 1
      config/allowlist.go
  62. 16 12
      config/config.go
  63. 7 0
      config/gitleaks.toml
  64. 6 0
      detect/detect.go

+ 25 - 12
README.md

@@ -233,9 +233,9 @@ entropy = 3.5
 # either be part of the idenitifer or unique strings specific to the rule's regex
 # (introduced in v8.6.0)
 keywords = [
-    "auth",
-    "password",
-    "token",
+  "auth",
+  "password",
+  "token",
 ]
 
 # You can include an allowlist table for a single rule to reduce false positives or ignore commits
@@ -244,13 +244,20 @@ keywords = [
 description = "ignore commit A"
 commits = [ "commit-A", "commit-B"]
 paths = [
-	'''go\.mod''',
-	'''go\.sum'''
+  '''go\.mod''',
+  '''go\.sum'''
 ]
 regexes = [
-   	'''process''',
-	'''getenv''',
+  '''process''',
+  '''getenv''',
 ]
+# note: stopwords targets the extracted secret, not the entire regex match
+# like 'regexes' does. (stopwords introduced in 8.8.0)
+stopwords = [
+  '''client''',
+  '''endpoint''',
+]
+
 
 # This is a global allowlist which has a higher order of precedence than rule-specific allowlists.
 # If a commit listed in the `commits` field below is encountered then that commit will be skipped and no
@@ -259,13 +266,19 @@ regexes = [
 description = "global allow list"
 commits = [ "commit-A", "commit-B", "commit-C"]
 paths = [
-	'''gitleaks\.toml''',
-	'''(.*?)(jpg|gif|doc)'''
+  '''gitleaks\.toml''',
+  '''(.*?)(jpg|gif|doc)'''
 ]
 regexes = [
-    	'''219-09-9999''',
-    	'''078-05-1120''',
-    	'''(9[0-9]{2}|666)-\d{2}-\d{4}''',
+  '''219-09-9999''',
+  '''078-05-1120''',
+  '''(9[0-9]{2}|666)-\d{2}-\d{4}''',
+]
+# note: stopwords targets the extracted secret, not the entire regex match
+# like 'regexes' does. (stopwords introduced in 8.8.0)
+stopwords = [
+  '''client''',
+  '''endpoint''',
 ]
 ```
 Refer to the default [gitleaks config](https://github.com/zricethezav/gitleaks/blob/master/config/gitleaks.toml) for examples and advice on writing regular expressions for secret detection.

+ 3 - 0
cmd/generate/config/main.go

@@ -104,6 +104,9 @@ func main() {
 
 	config := config.Config{
 		Rules: configRules,
+		Allowlist: config.Allowlist{
+			StopWords: rules.DefaultStopWords,
+		},
 	}
 	tmpl, err := template.ParseFiles(templatePath)
 	if err != nil {

+ 2 - 2
cmd/generate/config/rules/adobe.go

@@ -19,7 +19,7 @@ func AdobeClientID() *config.Rule {
 	tps := []string{
 		generateSampleSecret("adobe", secrets.NewSecret(hex("32"))),
 	}
-	return validate(r, tps)
+	return validate(r, tps, nil)
 }
 
 func AdobeClientSecret() *config.Rule {
@@ -35,5 +35,5 @@ func AdobeClientSecret() *config.Rule {
 	tps := []string{
 		"adobeClient := \"p8e-" + secrets.NewSecret(hex("32")) + "\"",
 	}
-	return validate(r, tps)
+	return validate(r, tps, nil)
 }

+ 1 - 1
cmd/generate/config/rules/age.go

@@ -19,5 +19,5 @@ func AgeSecretKey() *config.Rule {
 	tps := []string{
 		`apiKey := "AGE-SECRET-KEY-1QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ`, // gitleaks:allow
 	}
-	return validate(r, tps)
+	return validate(r, tps, nil)
 }

+ 2 - 2
cmd/generate/config/rules/alibaba.go

@@ -18,7 +18,7 @@ func AlibabaAccessKey() *config.Rule {
 	tps := []string{
 		"alibabaKey := \"LTAI" + secrets.NewSecret(hex("20")) + "\"",
 	}
-	return validate(r, tps)
+	return validate(r, tps, nil)
 }
 
 // TODO
@@ -37,5 +37,5 @@ func AlibabaSecretKey() *config.Rule {
 	tps := []string{
 		generateSampleSecret("alibaba", secrets.NewSecret(alphaNumeric("30"))),
 	}
-	return validate(r, tps)
+	return validate(r, tps, nil)
 }

+ 2 - 2
cmd/generate/config/rules/asana.go

@@ -19,7 +19,7 @@ func AsanaClientID() *config.Rule {
 	tps := []string{
 		generateSampleSecret("asana", secrets.NewSecret(numeric("16"))),
 	}
-	return validate(r, tps)
+	return validate(r, tps, nil)
 }
 
 func AsanaClientSecret() *config.Rule {
@@ -35,5 +35,5 @@ func AsanaClientSecret() *config.Rule {
 	tps := []string{
 		generateSampleSecret("asana", secrets.NewSecret(alphaNumeric("32"))),
 	}
-	return validate(r, tps)
+	return validate(r, tps, nil)
 }

+ 1 - 1
cmd/generate/config/rules/atlassian.go

@@ -20,5 +20,5 @@ func Atlassian() *config.Rule {
 		generateSampleSecret("atlassian", secrets.NewSecret(alphaNumeric("24"))),
 		generateSampleSecret("confluence", secrets.NewSecret(alphaNumeric("24"))),
 	}
-	return validate(r, tps)
+	return validate(r, tps, nil)
 }

+ 1 - 1
cmd/generate/config/rules/aws.go

@@ -27,5 +27,5 @@ func AWS() *config.Rule {
 
 	// validate
 	tps := []string{generateSampleSecret("AWS", "AKIALALEMEL33243OLIB")} // gitleaks:allow
-	return validate(r, tps)
+	return validate(r, tps, nil)
 }

+ 1 - 1
cmd/generate/config/rules/beamer.go

@@ -20,5 +20,5 @@ func Beamer() *config.Rule {
 	tps := []string{
 		generateSampleSecret("beamer", "b_"+secrets.NewSecret(alphaNumericExtended("44"))),
 	}
-	return validate(r, tps)
+	return validate(r, tps, nil)
 }

+ 2 - 2
cmd/generate/config/rules/bitbucket.go

@@ -19,7 +19,7 @@ func BitBucketClientID() *config.Rule {
 	tps := []string{
 		generateSampleSecret("bitbucket", secrets.NewSecret(alphaNumeric("32"))),
 	}
-	return validate(r, tps)
+	return validate(r, tps, nil)
 }
 
 func BitBucketClientSecret() *config.Rule {
@@ -36,5 +36,5 @@ func BitBucketClientSecret() *config.Rule {
 	tps := []string{
 		generateSampleSecret("bitbucket", secrets.NewSecret(alphaNumeric("64"))),
 	}
-	return validate(r, tps)
+	return validate(r, tps, nil)
 }

+ 1 - 1
cmd/generate/config/rules/clojars.go

@@ -20,5 +20,5 @@ func Clojars() *config.Rule {
 	tps := []string{
 		generateSampleSecret("clojars", "CLOJARS_"+secrets.NewSecret(alphaNumeric("60"))),
 	}
-	return validate(r, tps)
+	return validate(r, tps, nil)
 }

+ 3 - 0
cmd/generate/config/rules/config.tmpl

@@ -16,6 +16,9 @@ paths = [
     '''(.*?)(jpg|gif|doc|pdf|bin|svg|socket)$''',
     '''(go.mod|go.sum)$'''
 ]
+stopwords = [{{ range $i, $stopword := .Allowlist.StopWords }}
+    '''{{ $stopword }}''',{{ end }}
+]
 
 {{ range $i, $rule := .Rules }}[[rules]]
 {{ if and $rule.SecretGroup $rule.Entropy }}description = "{{$rule.Description}}"

+ 1 - 1
cmd/generate/config/rules/contentful.go

@@ -20,5 +20,5 @@ func Contentful() *config.Rule {
 	tps := []string{
 		generateSampleSecret("contentful", secrets.NewSecret(alphaNumeric("43"))),
 	}
-	return validate(r, tps)
+	return validate(r, tps, nil)
 }

+ 1 - 1
cmd/generate/config/rules/databricks.go

@@ -18,5 +18,5 @@ func Databricks() *config.Rule {
 	tps := []string{
 		generateSampleSecret("databricks", "dapi"+secrets.NewSecret(hex("32"))),
 	}
-	return validate(r, tps)
+	return validate(r, tps, nil)
 }

+ 3 - 3
cmd/generate/config/rules/discord.go

@@ -19,7 +19,7 @@ func DiscordAPIToken() *config.Rule {
 	tps := []string{
 		generateSampleSecret("discord", secrets.NewSecret(hex("64"))),
 	}
-	return validate(r, tps)
+	return validate(r, tps, nil)
 }
 
 func DiscordClientID() *config.Rule {
@@ -36,7 +36,7 @@ func DiscordClientID() *config.Rule {
 	tps := []string{
 		generateSampleSecret("discord", secrets.NewSecret(numeric("18"))),
 	}
-	return validate(r, tps)
+	return validate(r, tps, nil)
 }
 
 func DiscordClientSecret() *config.Rule {
@@ -53,5 +53,5 @@ func DiscordClientSecret() *config.Rule {
 	tps := []string{
 		generateSampleSecret("discord", secrets.NewSecret(numeric("32"))),
 	}
-	return validate(r, tps)
+	return validate(r, tps, nil)
 }

+ 1 - 1
cmd/generate/config/rules/doppler.go

@@ -20,7 +20,7 @@ func Doppler() *config.Rule {
 	tps := []string{
 		generateSampleSecret("doppler", "dp.pt."+secrets.NewSecret(alphaNumeric("43"))),
 	}
-	return validate(r, tps)
+	return validate(r, tps, nil)
 }
 
 // TODO add additional doppler formats:

+ 1 - 1
cmd/generate/config/rules/dropbox.go

@@ -19,7 +19,7 @@ func DropBoxAPISecret() *config.Rule {
 	tps := []string{
 		generateSampleSecret("dropbox", secrets.NewSecret(alphaNumeric("15"))),
 	}
-	return validate(r, tps)
+	return validate(r, tps, nil)
 }
 
 func DropBoxShortLivedAPIToken() *config.Rule {

+ 1 - 1
cmd/generate/config/rules/duffel.go

@@ -20,5 +20,5 @@ func Duffel() *config.Rule {
 	tps := []string{
 		generateSampleSecret("duffel", "duffel_test_"+secrets.NewSecret(alphaNumericExtended("43"))),
 	}
-	return validate(r, tps)
+	return validate(r, tps, nil)
 }

+ 1 - 1
cmd/generate/config/rules/dynatrace.go

@@ -20,5 +20,5 @@ func Dynatrace() *config.Rule {
 	tps := []string{
 		generateSampleSecret("dynatrace", "dt0c01."+secrets.NewSecret(alphaNumeric("24"))+"."+secrets.NewSecret(alphaNumeric("64"))),
 	}
-	return validate(r, tps)
+	return validate(r, tps, nil)
 }

+ 2 - 2
cmd/generate/config/rules/easypost.go

@@ -20,7 +20,7 @@ func EasyPost() *config.Rule {
 	tps := []string{
 		generateSampleSecret("EZAK", "EZAK"+secrets.NewSecret(alphaNumeric("54"))),
 	}
-	return validate(r, tps)
+	return validate(r, tps, nil)
 }
 
 func EasyPostTestAPI() *config.Rule {
@@ -36,5 +36,5 @@ func EasyPostTestAPI() *config.Rule {
 	tps := []string{
 		generateSampleSecret("EZTK", "EZTK"+secrets.NewSecret(alphaNumeric("54"))),
 	}
-	return validate(r, tps)
+	return validate(r, tps, nil)
 }

+ 1 - 1
cmd/generate/config/rules/facebook.go

@@ -19,5 +19,5 @@ func Facebook() *config.Rule {
 	tps := []string{
 		generateSampleSecret("facebook", secrets.NewSecret(hex("32"))),
 	}
-	return validate(r, tps)
+	return validate(r, tps, nil)
 }

+ 1 - 1
cmd/generate/config/rules/fastly.go

@@ -19,5 +19,5 @@ func FastlyAPIToken() *config.Rule {
 	tps := []string{
 		generateSampleSecret("fastly", secrets.NewSecret(alphaNumericExtended("32"))),
 	}
-	return validate(r, tps)
+	return validate(r, tps, nil)
 }

+ 2 - 2
cmd/generate/config/rules/finicity.go

@@ -19,7 +19,7 @@ func FinicityClientSecret() *config.Rule {
 	tps := []string{
 		generateSampleSecret("finicity", secrets.NewSecret(alphaNumeric("20"))),
 	}
-	return validate(r, tps)
+	return validate(r, tps, nil)
 }
 
 func FinicityAPIToken() *config.Rule {
@@ -36,5 +36,5 @@ func FinicityAPIToken() *config.Rule {
 	tps := []string{
 		generateSampleSecret("finicity", secrets.NewSecret(hex("32"))),
 	}
-	return validate(r, tps)
+	return validate(r, tps, nil)
 }

+ 3 - 3
cmd/generate/config/rules/flutterwave.go

@@ -20,7 +20,7 @@ func FlutterwavePublicKey() *config.Rule {
 	tps := []string{
 		generateSampleSecret("flutterwavePubKey", "FLWPUBK_TEST-"+secrets.NewSecret(hex("32"))+"-X"),
 	}
-	return validate(r, tps)
+	return validate(r, tps, nil)
 }
 
 func FlutterwaveSecretKey() *config.Rule {
@@ -36,7 +36,7 @@ func FlutterwaveSecretKey() *config.Rule {
 	tps := []string{
 		generateSampleSecret("flutterwavePubKey", "FLWSECK_TEST-"+secrets.NewSecret(hex("32"))+"-X"),
 	}
-	return validate(r, tps)
+	return validate(r, tps, nil)
 }
 
 func FlutterwaveEncKey() *config.Rule {
@@ -52,5 +52,5 @@ func FlutterwaveEncKey() *config.Rule {
 	tps := []string{
 		generateSampleSecret("flutterwavePubKey", "FLWSECK_TEST-"+secrets.NewSecret(hex("12"))),
 	}
-	return validate(r, tps)
+	return validate(r, tps, nil)
 }

+ 1 - 1
cmd/generate/config/rules/frameio.go

@@ -20,5 +20,5 @@ func FrameIO() *config.Rule {
 	tps := []string{
 		generateSampleSecret("frameio", "fio-u-"+secrets.NewSecret(alphaNumericExtended("64"))),
 	}
-	return validate(r, tps)
+	return validate(r, tps, nil)
 }

+ 1 - 1
cmd/generate/config/rules/gcp.go

@@ -20,5 +20,5 @@ func GCPServiceAccount() *config.Rule {
 	tps := []string{
 		`"type": "service_account"`,
 	}
-	return validate(r, tps)
+	return validate(r, tps, nil)
 }

+ 4 - 1
cmd/generate/config/rules/generic.go

@@ -41,5 +41,8 @@ func GenericCredential() *config.Rule {
 		`"client_secret" : "6da89121079f83b2eb6acccf8219ea982c3d79bccc3e9c6a85856480661f8fde",`,
 		// TODO add more
 	}
-	return validate(r, tps)
+	fps := []string{
+		`client_vpn_endpoint_id = aws_ec2_client_vpn_endpoint.client-vpn-endpoint.id`,
+	}
+	return validate(r, tps, fps)
 }

+ 4 - 4
cmd/generate/config/rules/github.go

@@ -20,7 +20,7 @@ func GitHubPat() *config.Rule {
 	tps := []string{
 		generateSampleSecret("github", "ghp_"+secrets.NewSecret(alphaNumeric("36"))),
 	}
-	return validate(r, tps)
+	return validate(r, tps, nil)
 }
 
 func GitHubOauth() *config.Rule {
@@ -36,7 +36,7 @@ func GitHubOauth() *config.Rule {
 	tps := []string{
 		generateSampleSecret("github", "gho_"+secrets.NewSecret(alphaNumeric("36"))),
 	}
-	return validate(r, tps)
+	return validate(r, tps, nil)
 }
 
 func GitHubApp() *config.Rule {
@@ -53,7 +53,7 @@ func GitHubApp() *config.Rule {
 		generateSampleSecret("github", "ghu_"+secrets.NewSecret(alphaNumeric("36"))),
 		generateSampleSecret("github", "ghs_"+secrets.NewSecret(alphaNumeric("36"))),
 	}
-	return validate(r, tps)
+	return validate(r, tps, nil)
 }
 
 func GitHubRefresh() *config.Rule {
@@ -69,5 +69,5 @@ func GitHubRefresh() *config.Rule {
 	tps := []string{
 		generateSampleSecret("github", "ghr_"+secrets.NewSecret(alphaNumeric("36"))),
 	}
-	return validate(r, tps)
+	return validate(r, tps, nil)
 }

+ 1 - 1
cmd/generate/config/rules/gitlab.go

@@ -20,5 +20,5 @@ func Gitlab() *config.Rule {
 	tps := []string{
 		generateSampleSecret("gitlab", "glpat-"+secrets.NewSecret(alphaNumeric("20"))),
 	}
-	return validate(r, tps)
+	return validate(r, tps, nil)
 }

+ 1 - 1
cmd/generate/config/rules/gocardless.go

@@ -21,5 +21,5 @@ func GoCardless() *config.Rule {
 	tps := []string{
 		generateSampleSecret("gocardless", "live_"+secrets.NewSecret(alphaNumericExtended("40"))),
 	}
-	return validate(r, tps)
+	return validate(r, tps, nil)
 }

+ 1 - 1
cmd/generate/config/rules/hashicorp.go

@@ -20,5 +20,5 @@ func Hashicorp() *config.Rule {
 	tps := []string{
 		generateSampleSecret("hashicorpToken", secrets.NewSecret(hex("14"))+".atlasv1."+secrets.NewSecret(alphaNumericExtended("60,70"))),
 	}
-	return validate(r, tps)
+	return validate(r, tps, nil)
 }

+ 1 - 1
cmd/generate/config/rules/heroku.go

@@ -19,5 +19,5 @@ func Heroku() *config.Rule {
 	tps := []string{
 		`const HEROKU_KEY = "12345678-ABCD-ABCD-ABCD-1234567890AB"`, // gitleaks:allow
 	}
-	return validate(r, tps)
+	return validate(r, tps, nil)
 }

+ 1 - 1
cmd/generate/config/rules/hubspot.go

@@ -19,5 +19,5 @@ func HubSpot() *config.Rule {
 	tps := []string{
 		`const hubspotKey = "12345678-ABCD-ABCD-ABCD-1234567890AB"`, // gitleaks:allow
 	}
-	return validate(r, tps)
+	return validate(r, tps, nil)
 }

+ 1 - 1
cmd/generate/config/rules/intercom.go

@@ -19,5 +19,5 @@ func Intercom() *config.Rule {
 	tps := []string{
 		generateSampleSecret("intercom", secrets.NewSecret(alphaNumericExtended("60"))),
 	}
-	return validate(r, tps)
+	return validate(r, tps, nil)
 }

+ 2 - 2
cmd/generate/config/rules/linear.go

@@ -20,7 +20,7 @@ func LinearAPIToken() *config.Rule {
 	tps := []string{
 		generateSampleSecret("linear", "lin_api_"+secrets.NewSecret(alphaNumeric("40"))),
 	}
-	return validate(r, tps)
+	return validate(r, tps, nil)
 }
 
 func LinearClientSecret() *config.Rule {
@@ -36,5 +36,5 @@ func LinearClientSecret() *config.Rule {
 	tps := []string{
 		generateSampleSecret("linear", secrets.NewSecret(hex("32"))),
 	}
-	return validate(r, tps)
+	return validate(r, tps, nil)
 }

+ 2 - 2
cmd/generate/config/rules/linkedin.go

@@ -25,7 +25,7 @@ func LinkedinClientSecret() *config.Rule {
 	tps := []string{
 		generateSampleSecret("linkedin", secrets.NewSecret(alphaNumeric("16"))),
 	}
-	return validate(r, tps)
+	return validate(r, tps, nil)
 }
 
 func LinkedinClientID() *config.Rule {
@@ -48,5 +48,5 @@ func LinkedinClientID() *config.Rule {
 	tps := []string{
 		generateSampleSecret("linkedin", secrets.NewSecret(alphaNumeric("14"))),
 	}
-	return validate(r, tps)
+	return validate(r, tps, nil)
 }

+ 2 - 2
cmd/generate/config/rules/lob.go

@@ -22,7 +22,7 @@ func LobPubAPIToken() *config.Rule {
 	tps := []string{
 		generateSampleSecret("lob", "test_pub_"+secrets.NewSecret(hex("31"))),
 	}
-	return validate(r, tps)
+	return validate(r, tps, nil)
 }
 
 func LobAPIToken() *config.Rule {
@@ -41,5 +41,5 @@ func LobAPIToken() *config.Rule {
 	tps := []string{
 		generateSampleSecret("lob", "test_"+secrets.NewSecret(hex("35"))),
 	}
-	return validate(r, tps)
+	return validate(r, tps, nil)
 }

+ 1 - 1
cmd/generate/config/rules/mailchimp.go

@@ -21,5 +21,5 @@ func MailChimp() *config.Rule {
 	tps := []string{
 		generateSampleSecret("mailchimp", secrets.NewSecret(hex("32"))+"-us20"),
 	}
-	return validate(r, tps)
+	return validate(r, tps, nil)
 }

+ 3 - 3
cmd/generate/config/rules/mailgun.go

@@ -21,7 +21,7 @@ func MailGunPrivateAPIToken() *config.Rule {
 	tps := []string{
 		generateSampleSecret("mailgun", "key-"+secrets.NewSecret(hex("32"))),
 	}
-	return validate(r, tps)
+	return validate(r, tps, nil)
 }
 
 func MailGunPubAPIToken() *config.Rule {
@@ -40,7 +40,7 @@ func MailGunPubAPIToken() *config.Rule {
 	tps := []string{
 		generateSampleSecret("mailgun", "pubkey-"+secrets.NewSecret(hex("32"))),
 	}
-	return validate(r, tps)
+	return validate(r, tps, nil)
 }
 
 func MailGunSigningKey() *config.Rule {
@@ -59,5 +59,5 @@ func MailGunSigningKey() *config.Rule {
 	tps := []string{
 		generateSampleSecret("mailgun", secrets.NewSecret(hex("32"))+"-00001111-22223333"),
 	}
-	return validate(r, tps)
+	return validate(r, tps, nil)
 }

+ 1 - 1
cmd/generate/config/rules/mapbox.go

@@ -19,5 +19,5 @@ func MapBox() *config.Rule {
 	tps := []string{
 		generateSampleSecret("mapbox", "pk."+secrets.NewSecret(alphaNumeric("60"))+"."+secrets.NewSecret(alphaNumeric("22"))),
 	}
-	return validate(r, tps)
+	return validate(r, tps, nil)
 }

+ 2 - 2
cmd/generate/config/rules/messagebird.go

@@ -29,7 +29,7 @@ func MessageBirdAPIToken() *config.Rule {
 		generateSampleSecret("message-bird", secrets.NewSecret(alphaNumeric("25"))),
 		generateSampleSecret("message_bird", secrets.NewSecret(alphaNumeric("25"))),
 	}
-	return validate(r, tps)
+	return validate(r, tps, nil)
 }
 
 func MessageBirdClientID() *config.Rule {
@@ -54,5 +54,5 @@ func MessageBirdClientID() *config.Rule {
 	tps := []string{
 		`const MessageBirdClientID = "12345678-ABCD-ABCD-ABCD-1234567890AB"`, // gitleaks:allow
 	}
-	return validate(r, tps)
+	return validate(r, tps, nil)
 }

+ 3 - 3
cmd/generate/config/rules/newrelic.go

@@ -25,7 +25,7 @@ func NewRelicUserID() *config.Rule {
 	tps := []string{
 		generateSampleSecret("new-relic", "NRAK-"+secrets.NewSecret(alphaNumeric("27"))),
 	}
-	return validate(r, tps)
+	return validate(r, tps, nil)
 }
 
 func NewRelicUserKey() *config.Rule {
@@ -50,7 +50,7 @@ func NewRelicUserKey() *config.Rule {
 	tps := []string{
 		generateSampleSecret("new-relic", secrets.NewSecret(alphaNumeric("64"))),
 	}
-	return validate(r, tps)
+	return validate(r, tps, nil)
 }
 
 func NewRelicBrowserAPIKey() *config.Rule {
@@ -73,5 +73,5 @@ func NewRelicBrowserAPIKey() *config.Rule {
 	tps := []string{
 		generateSampleSecret("new-relic", "NRJS-"+secrets.NewSecret(hex("19"))),
 	}
-	return validate(r, tps)
+	return validate(r, tps, nil)
 }

+ 1 - 1
cmd/generate/config/rules/npm.go

@@ -21,5 +21,5 @@ func NPM() *config.Rule {
 	tps := []string{
 		generateSampleSecret("npmAccessToken", "npm_"+secrets.NewSecret(alphaNumeric("36"))),
 	}
-	return validate(r, tps)
+	return validate(r, tps, nil)
 }

+ 2 - 2
cmd/generate/config/rules/planetscale.go

@@ -21,7 +21,7 @@ func PlanetScalePassword() *config.Rule {
 	tps := []string{
 		generateSampleSecret("planetScalePassword", "pscale_pw_"+secrets.NewSecret(alphaNumericExtended("43"))),
 	}
-	return validate(r, tps)
+	return validate(r, tps, nil)
 }
 
 func PlanetScaleToken() *config.Rule {
@@ -40,5 +40,5 @@ func PlanetScaleToken() *config.Rule {
 	tps := []string{
 		generateSampleSecret("planetScalePassword", "pscale_tkn_"+secrets.NewSecret(alphaNumericExtended("43"))),
 	}
-	return validate(r, tps)
+	return validate(r, tps, nil)
 }

+ 1 - 1
cmd/generate/config/rules/postman.go

@@ -21,5 +21,5 @@ func PostManAPI() *config.Rule {
 	tps := []string{
 		generateSampleSecret("postmanAPItoken", "PMAK-"+secrets.NewSecret(hex("24"))+"-"+secrets.NewSecret(hex("34"))),
 	}
-	return validate(r, tps)
+	return validate(r, tps, nil)
 }

+ 1 - 1
cmd/generate/config/rules/privatekey.go

@@ -19,5 +19,5 @@ func PrivateKey() *config.Rule {
 	tps := []string{`-----BEGIN PRIVATE KEY-----
 anything
 -----END PRIVATE KEY-----`} // gitleaks:allow
-	return validate(r, tps)
+	return validate(r, tps, nil)
 }

+ 1 - 1
cmd/generate/config/rules/pulumi.go

@@ -21,5 +21,5 @@ func PulumiAPIToken() *config.Rule {
 	tps := []string{
 		generateSampleSecret("pulumi-api-token", "pul-"+secrets.NewSecret(hex("40"))),
 	}
-	return validate(r, tps)
+	return validate(r, tps, nil)
 }

+ 1 - 1
cmd/generate/config/rules/pypi.go

@@ -22,5 +22,5 @@ func PyPiUploadToken() *config.Rule {
 	// validate
 	tps := []string{"pypiToken := \"pypi-AgEIcHlwaS5vcmc" + secrets.NewSecret(hex("32")) +
 		secrets.NewSecret(hex("32")) + "\""}
-	return validate(r, tps)
+	return validate(r, tps, nil)
 }

+ 1 - 1
cmd/generate/config/rules/rubygems.go

@@ -21,5 +21,5 @@ func RubyGemsAPIToken() *config.Rule {
 	tps := []string{
 		generateSampleSecret("rubygemsAPIToken", "rubygems_"+secrets.NewSecret(hex("48"))),
 	}
-	return validate(r, tps)
+	return validate(r, tps, nil)
 }

+ 18 - 2
cmd/generate/config/rules/rule.go

@@ -28,6 +28,14 @@ const (
 	secretSuffix       = `)(?:['|\"|\n|\r|\s|\x60]|$)`
 )
 
+var DefaultStopWords = []string{
+	"client",
+	"endpoint",
+	"vpn",
+	"_ec2_",
+	"aws_",
+}
+
 func generateSemiGenericRegex(identifiers []string, secretRegex string) *regexp.Regexp {
 	var sb strings.Builder
 	sb.WriteString(caseInsensitive)
@@ -54,7 +62,7 @@ func generateSampleSecret(identifier string, secret string) string {
 	return fmt.Sprintf("%s_api_token = \"%s\"", identifier, secret)
 }
 
-func validate(r config.Rule, truePositives []string) *config.Rule {
+func validate(r config.Rule, truePositives []string, falsePositives []string) *config.Rule {
 	// normalize keywords like in the config package
 	var keywords []string
 	for _, k := range r.Keywords {
@@ -65,10 +73,18 @@ func validate(r config.Rule, truePositives []string) *config.Rule {
 	d := detect.NewDetector(config.Config{
 		Rules:    []*config.Rule{&r},
 		Keywords: keywords,
+		Allowlist: config.Allowlist{
+			StopWords: DefaultStopWords,
+		},
 	})
 	for _, tp := range truePositives {
 		if len(d.DetectString(tp)) != 1 {
-			log.Fatal().Msgf("Failed to validate %s", r.RuleID)
+			log.Fatal().Msgf("Failed to validate (tp) %s", r.RuleID)
+		}
+	}
+	for _, fp := range falsePositives {
+		if len(d.DetectString(fp)) != 0 {
+			log.Fatal().Msgf("Failed to validate (fp) %s", r.RuleID)
 		}
 	}
 	return &r

+ 1 - 1
cmd/generate/config/rules/sendgrid.go

@@ -21,5 +21,5 @@ func SendGridAPIToken() *config.Rule {
 	tps := []string{
 		generateSampleSecret("sengridAPIToken", "SG."+secrets.NewSecret(alphaNumericExtended("66"))),
 	}
-	return validate(r, tps)
+	return validate(r, tps, nil)
 }

+ 1 - 1
cmd/generate/config/rules/sendinblue.go

@@ -21,5 +21,5 @@ func SendInBlueAPIToken() *config.Rule {
 	tps := []string{
 		generateSampleSecret("sendinblue", "xkeysib-"+secrets.NewSecret(hex("64"))+"-"+secrets.NewSecret(alphaNumeric("16"))),
 	}
-	return validate(r, tps)
+	return validate(r, tps, nil)
 }

+ 1 - 1
cmd/generate/config/rules/shippo.go

@@ -22,5 +22,5 @@ func ShippoAPIToken() *config.Rule {
 		generateSampleSecret("shippo", "shippo_live_"+secrets.NewSecret(hex("40"))),
 		generateSampleSecret("shippo", "shippo_test_"+secrets.NewSecret(hex("40"))),
 	}
-	return validate(r, tps)
+	return validate(r, tps, nil)
 }

+ 4 - 4
cmd/generate/config/rules/shopify.go

@@ -18,7 +18,7 @@ func ShopifySharedSecret() *config.Rule {
 
 	// validate
 	tps := []string{"shopifySecret := \"shpss_" + secrets.NewSecret(hex("32")) + "\""}
-	return validate(r, tps)
+	return validate(r, tps, nil)
 }
 
 func ShopifyAccessToken() *config.Rule {
@@ -32,7 +32,7 @@ func ShopifyAccessToken() *config.Rule {
 
 	// validate
 	tps := []string{"shopifyToken := \"shpat_" + secrets.NewSecret(hex("32")) + "\""}
-	return validate(r, tps)
+	return validate(r, tps, nil)
 }
 
 func ShopifyCustomAccessToken() *config.Rule {
@@ -46,7 +46,7 @@ func ShopifyCustomAccessToken() *config.Rule {
 
 	// validate
 	tps := []string{"shopifyToken := \"shpca_" + secrets.NewSecret(hex("32")) + "\""}
-	return validate(r, tps)
+	return validate(r, tps, nil)
 }
 
 func ShopifyPrivateAppAccessToken() *config.Rule {
@@ -60,5 +60,5 @@ func ShopifyPrivateAppAccessToken() *config.Rule {
 
 	// validate
 	tps := []string{"shopifyToken := \"shppa_" + secrets.NewSecret(hex("32")) + "\""}
-	return validate(r, tps)
+	return validate(r, tps, nil)
 }

+ 2 - 2
cmd/generate/config/rules/slack.go

@@ -27,7 +27,7 @@ func SlackAccessToken() *config.Rule {
 	tps := []string{
 		"\"slackToken\": \"xoxb-" + secrets.NewSecret(alphaNumeric("30")) + "\"",
 	}
-	return validate(r, tps)
+	return validate(r, tps, nil)
 }
 
 func SlackWebHook() *config.Rule {
@@ -46,5 +46,5 @@ func SlackWebHook() *config.Rule {
 	tps := []string{
 		"https://hooks.slack.com/services/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", // gitleaks:allow
 	}
-	return validate(r, tps)
+	return validate(r, tps, nil)
 }

+ 1 - 1
cmd/generate/config/rules/stripe.go

@@ -23,5 +23,5 @@ func StripeAccessToken() *config.Rule {
 
 	// validate
 	tps := []string{"stripeToken := \"sk_test_" + secrets.NewSecret(alphaNumeric("30")) + "\""}
-	return validate(r, tps)
+	return validate(r, tps, nil)
 }

+ 1 - 1
cmd/generate/config/rules/twilio.go

@@ -20,5 +20,5 @@ func Twilio() *config.Rule {
 	tps := []string{
 		"twilioAPIKey := \"SK" + secrets.NewSecret(hex("32")) + "\"",
 	}
-	return validate(r, tps)
+	return validate(r, tps, nil)
 }

+ 1 - 1
cmd/generate/config/rules/twitch.go

@@ -21,5 +21,5 @@ func TwitchAPIToken() *config.Rule {
 	tps := []string{
 		generateSampleSecret("twitch", secrets.NewSecret(alphaNumeric("30"))),
 	}
-	return validate(r, tps)
+	return validate(r, tps, nil)
 }

+ 1 - 1
cmd/generate/config/rules/twitter.go

@@ -20,5 +20,5 @@ func Twitter() *config.Rule {
 		"twitterToken := \"" + secrets.NewSecret(hex("36")) + "aaaa\"",
 		"twitterToken := `" + secrets.NewSecret(hex("36")) + "aaaa`",
 	}
-	return validate(r, tps)
+	return validate(r, tps, nil)
 }

+ 1 - 1
cmd/generate/config/rules/typeform.go

@@ -22,5 +22,5 @@ func Typeform() *config.Rule {
 	tps := []string{
 		generateSampleSecret("typeformAPIToken", "tfp_"+secrets.NewSecret(alphaNumericExtended("59"))),
 	}
-	return validate(r, tps)
+	return validate(r, tps, nil)
 }

+ 18 - 1
config/allowlist.go

@@ -1,6 +1,9 @@
 package config
 
-import "regexp"
+import (
+	"regexp"
+	"strings"
+)
 
 // Allowlist allows a rule to be ignored for specific
 // regexes, paths, and/or commits
@@ -16,6 +19,11 @@ type Allowlist struct {
 
 	// Commits is a slice of commit SHAs that are allowed to be ignored.
 	Commits []string
+
+	// StopWords is a slice of stop words that are allowed to be ignored.
+	// This targets the _secret_, not the content of the regex match like the
+	// Regexes slice.
+	StopWords []string
 }
 
 // CommitAllowed returns true if the commit is allowed to be ignored.
@@ -40,3 +48,12 @@ func (a *Allowlist) PathAllowed(path string) bool {
 func (a *Allowlist) RegexAllowed(s string) bool {
 	return anyRegexMatch(s, a.Regexes)
 }
+
+func (a *Allowlist) ContainsStopWord(s string) bool {
+	for _, stopWord := range a.StopWords {
+		if strings.Contains(s, stopWord) {
+			return true
+		}
+	}
+	return false
+}

+ 16 - 12
config/config.go

@@ -26,15 +26,17 @@ type ViperConfig struct {
 		Tags        []string
 
 		Allowlist struct {
-			Regexes []string
-			Paths   []string
-			Commits []string
+			Regexes   []string
+			Paths     []string
+			Commits   []string
+			StopWords []string
 		}
 	}
 	Allowlist struct {
-		Regexes []string
-		Paths   []string
-		Commits []string
+		Regexes   []string
+		Paths     []string
+		Commits   []string
+		StopWords []string
 	}
 }
 
@@ -96,9 +98,10 @@ func (vc *ViperConfig) Translate() (Config, error) {
 			Tags:        r.Tags,
 			Keywords:    r.Keywords,
 			Allowlist: Allowlist{
-				Regexes: allowlistRegexes,
-				Paths:   allowlistPaths,
-				Commits: r.Allowlist.Commits,
+				Regexes:   allowlistRegexes,
+				Paths:     allowlistPaths,
+				Commits:   r.Allowlist.Commits,
+				StopWords: r.Allowlist.StopWords,
 			},
 		}
 		if r.Regex != nil && r.SecretGroup > r.Regex.NumSubexp() {
@@ -118,9 +121,10 @@ func (vc *ViperConfig) Translate() (Config, error) {
 		Description: vc.Description,
 		Rules:       rules,
 		Allowlist: Allowlist{
-			Regexes: allowlistRegexes,
-			Paths:   allowlistPaths,
-			Commits: vc.Allowlist.Commits,
+			Regexes:   allowlistRegexes,
+			Paths:     allowlistPaths,
+			Commits:   vc.Allowlist.Commits,
+			StopWords: vc.Allowlist.StopWords,
 		},
 		Keywords: keywords,
 	}, nil

+ 7 - 0
config/gitleaks.toml

@@ -16,6 +16,13 @@ paths = [
     '''(.*?)(jpg|gif|doc|pdf|bin|svg|socket)$''',
     '''(go.mod|go.sum)$'''
 ]
+stopwords = [
+    '''client''',
+    '''endpoint''',
+    '''vpn''',
+    '''_ec2_''',
+    '''aws_''',
+]
 
 [[rules]]
 description = "Adobe Client ID (Oauth Web)"

+ 6 - 0
detect/detect.go

@@ -217,6 +217,12 @@ func (d *Detector) detectRule(fragment Fragment, rule *config.Rule) []report.Fin
 			finding.Secret = secret
 		}
 
+		// check if the secret is in the list of stopwords
+		if rule.Allowlist.ContainsStopWord(finding.Secret) ||
+			d.Config.Allowlist.ContainsStopWord(finding.Secret) {
+			continue
+		}
+
 		// check entropy
 		entropy := shannonEntropy(finding.Secret)
 		finding.Entropy = float32(entropy)