|
|
@@ -77,13 +77,14 @@ type Options struct {
|
|
|
OwnerPath string `long:"owner-path" description:"Path to owner directory (repos discovered)"`
|
|
|
|
|
|
// Process options
|
|
|
- Threads int `long:"threads" description:"Maximum number of threads gitleaks spawns"`
|
|
|
- Disk bool `long:"disk" description:"Clones repo(s) to disk"`
|
|
|
- SingleSearch string `long:"single-search" description:"single regular expression to search for"`
|
|
|
- ConfigPath string `long:"config" description:"path to gitleaks config"`
|
|
|
- SSHKey string `long:"ssh-key" description:"path to ssh key"`
|
|
|
- ExcludeForks bool `long:"exclude-forks" description:"exclude forks for organization/user audits"`
|
|
|
- Entropy float64 `long:"entropy" short:"e" description:"Include entropy checks during audit. Entropy scale: 0.0(no entropy) - 8.0(max entropy)"`
|
|
|
+ Threads int `long:"threads" description:"Maximum number of threads gitleaks spawns"`
|
|
|
+ Disk bool `long:"disk" description:"Clones repo(s) to disk"`
|
|
|
+ SingleSearch string `long:"single-search" description:"single regular expression to search for"`
|
|
|
+ ConfigPath string `long:"config" description:"path to gitleaks config"`
|
|
|
+ SSHKey string `long:"ssh-key" description:"path to ssh key"`
|
|
|
+ ExcludeForks bool `long:"exclude-forks" description:"exclude forks for organization/user audits"`
|
|
|
+ Entropy float64 `long:"entropy" short:"e" description:"Include entropy checks during audit. Entropy scale: 0.0(no entropy) - 8.0(max entropy)"`
|
|
|
+ NoiseReduction bool `long:"noise-reduction" description:"Reduce the number of finds when entropy checks are enabled"`
|
|
|
// TODO: IncludeMessages string `long:"messages" description:"include commit messages in audit"`
|
|
|
|
|
|
// Output options
|
|
|
@@ -101,6 +102,9 @@ type Config struct {
|
|
|
Description string
|
|
|
Regex string
|
|
|
}
|
|
|
+ Entropy struct {
|
|
|
+ LineRegexes []string
|
|
|
+ }
|
|
|
Whitelist struct {
|
|
|
Files []string
|
|
|
Regexes []string
|
|
|
@@ -169,6 +173,21 @@ regex = '''(?i)github(.{0,4})?['\"][0-9a-zA-Z]{35,40}['\"]'''
|
|
|
description = "Slack"
|
|
|
regex = '''xox[baprs]-([0-9a-zA-Z]{10,48})?'''
|
|
|
|
|
|
+[entropy]
|
|
|
+lineregexes = [
|
|
|
+ "api",
|
|
|
+ "key",
|
|
|
+ "signature",
|
|
|
+ "secret",
|
|
|
+ "password",
|
|
|
+ "pass",
|
|
|
+ "pwd",
|
|
|
+ "token",
|
|
|
+ "curl",
|
|
|
+ "wget",
|
|
|
+ "https?",
|
|
|
+]
|
|
|
+
|
|
|
[whitelist]
|
|
|
files = [
|
|
|
"(.*?)(jpg|gif|doc|pdf|bin)$"
|
|
|
@@ -196,6 +215,7 @@ var (
|
|
|
whiteListCommits map[string]bool
|
|
|
whiteListRepos []*regexp.Regexp
|
|
|
entropyRanges []entropyRange
|
|
|
+ entropyRegexes []*regexp.Regexp
|
|
|
fileDiffRegex *regexp.Regexp
|
|
|
sshAuth *ssh.PublicKeys
|
|
|
dir string
|
|
|
@@ -630,23 +650,12 @@ func inspect(diff gitDiff) []Leak {
|
|
|
}
|
|
|
|
|
|
if opts.Entropy > 0 || len(entropyRanges) != 0 {
|
|
|
- entropyLeak := false
|
|
|
words := strings.Fields(line)
|
|
|
for _, word := range words {
|
|
|
entropy := getShannonEntropy(word)
|
|
|
- if entropy >= opts.Entropy && len(entropyRanges) == 0 {
|
|
|
- entropyLeak = true
|
|
|
- }
|
|
|
- if len(entropyRanges) != 0 {
|
|
|
- for _, eR := range entropyRanges {
|
|
|
- if entropy > eR.v1 && entropy < eR.v2 {
|
|
|
- entropyLeak = true
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- if entropyLeak {
|
|
|
+
|
|
|
+ if entropyIsHighEnough(entropy) && highEntropyLineIsALeak(line) {
|
|
|
leaks = addLeak(leaks, line, word, fmt.Sprintf("Entropy: %.2f", entropy), diff)
|
|
|
- entropyLeak = false
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
@@ -700,6 +709,36 @@ func getShannonEntropy(data string) (entropy float64) {
|
|
|
return entropy
|
|
|
}
|
|
|
|
|
|
+func entropyIsHighEnough(entropy float64) bool {
|
|
|
+ if entropy >= opts.Entropy && len(entropyRanges) == 0 {
|
|
|
+ return true
|
|
|
+ }
|
|
|
+
|
|
|
+ if len(entropyRanges) != 0 {
|
|
|
+ for _, eR := range entropyRanges {
|
|
|
+ if entropy > eR.v1 && entropy < eR.v2 {
|
|
|
+ return true
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return false
|
|
|
+}
|
|
|
+
|
|
|
+func highEntropyLineIsALeak(line string) bool {
|
|
|
+ if !opts.NoiseReduction {
|
|
|
+ return true
|
|
|
+ }
|
|
|
+
|
|
|
+ for _, re := range entropyRegexes {
|
|
|
+ if re.FindString(line) != "" {
|
|
|
+ return true
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return false
|
|
|
+}
|
|
|
+
|
|
|
// discoverRepos walks all the children of `path`. If a child directory
|
|
|
// contain a .git file then that repo will be added to the list of repos returned
|
|
|
func discoverRepos(ownerPath string) ([]*RepoDescriptor, error) {
|
|
|
@@ -842,6 +881,10 @@ func loadToml() error {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ for _, regex := range config.Entropy.LineRegexes {
|
|
|
+ entropyRegexes = append(entropyRegexes, regexp.MustCompile(regex))
|
|
|
+ }
|
|
|
+
|
|
|
if singleSearchRegex != nil {
|
|
|
regexes["singleSearch"] = singleSearchRegex
|
|
|
} else {
|