rule.go 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. package rules
  2. import (
  3. "fmt"
  4. "regexp"
  5. "strings"
  6. "github.com/rs/zerolog/log"
  7. "github.com/zricethezav/gitleaks/v8/config"
  8. "github.com/zricethezav/gitleaks/v8/detect"
  9. )
  10. const (
  11. // case insensitive prefix
  12. caseInsensitive = `(?i)`
  13. // identifier prefix (just an ignore group)
  14. identifierPrefix = `(?:`
  15. identifierSuffix = `)(?:[0-9a-z\-_\s.]{0,20})(?:[\s|']|[\s|"]){0,3}`
  16. // commonly used assignment operators or function call
  17. operator = `(?:=|>|:=|\|\|:|<=|=>|:)`
  18. // boundaries for the secret
  19. // \x60 = `
  20. secretPrefixUnique = `\b(`
  21. secretPrefix = `(?:'|\"|\s|=|\x60){0,5}(`
  22. secretSuffix = `)(?:['|\"|\n|\r|\s|\x60]|$)`
  23. )
  24. var DefaultStopWords = []string{
  25. "client",
  26. "endpoint",
  27. "vpn",
  28. "_ec2_",
  29. "aws_",
  30. }
  31. func generateSemiGenericRegex(identifiers []string, secretRegex string) *regexp.Regexp {
  32. var sb strings.Builder
  33. sb.WriteString(caseInsensitive)
  34. sb.WriteString(identifierPrefix)
  35. sb.WriteString(strings.Join(identifiers, "|"))
  36. sb.WriteString(identifierSuffix)
  37. sb.WriteString(operator)
  38. sb.WriteString(secretPrefix)
  39. sb.WriteString(secretRegex)
  40. sb.WriteString(secretSuffix)
  41. return regexp.MustCompile(sb.String())
  42. }
  43. func generateUniqueTokenRegex(secretRegex string) *regexp.Regexp {
  44. var sb strings.Builder
  45. sb.WriteString(caseInsensitive)
  46. sb.WriteString(secretPrefixUnique)
  47. sb.WriteString(secretRegex)
  48. sb.WriteString(secretSuffix)
  49. return regexp.MustCompile(sb.String())
  50. }
  51. func generateSampleSecret(identifier string, secret string) string {
  52. return fmt.Sprintf("%s_api_token = \"%s\"", identifier, secret)
  53. }
  54. func validate(r config.Rule, truePositives []string, falsePositives []string) *config.Rule {
  55. // normalize keywords like in the config package
  56. var keywords []string
  57. for _, k := range r.Keywords {
  58. keywords = append(keywords, strings.ToLower(k))
  59. }
  60. r.Keywords = keywords
  61. d := detect.NewDetector(config.Config{
  62. Rules: []*config.Rule{&r},
  63. Keywords: keywords,
  64. Allowlist: config.Allowlist{
  65. StopWords: DefaultStopWords,
  66. },
  67. })
  68. for _, tp := range truePositives {
  69. if len(d.DetectString(tp)) != 1 {
  70. log.Fatal().Msgf("Failed to validate (tp) %s", r.RuleID)
  71. }
  72. }
  73. for _, fp := range falsePositives {
  74. if len(d.DetectString(fp)) != 0 {
  75. log.Fatal().Msgf("Failed to validate (fp) %s", r.RuleID)
  76. }
  77. }
  78. return &r
  79. }
  80. func numeric(size string) string {
  81. return fmt.Sprintf(`[0-9]{%s}`, size)
  82. }
  83. func hex(size string) string {
  84. return fmt.Sprintf(`[a-f0-9]{%s}`, size)
  85. }
  86. func alphaNumeric(size string) string {
  87. return fmt.Sprintf(`[a-z0-9]{%s}`, size)
  88. }
  89. func alphaNumericExtended(size string) string {
  90. return fmt.Sprintf(`[a-z0-9=_\-]{%s}`, size)
  91. }