Skip to content

Commit

Permalink
feat: add score system (#260)
Browse files Browse the repository at this point in the history
  • Loading branch information
LeonardoLordelloFontes authored Dec 3, 2024
1 parent f5a5cb4 commit 184e893
Show file tree
Hide file tree
Showing 11 changed files with 587 additions and 180 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ This application is written in Go language and is based on the framework provide

The tool checks the content using a series of rules that are designed to identify a wide range of sensitive items such as AWS access token, Bitbucket Client ID, GitHub PAT etc. For a complete list of rules, see [docs/list-of-rules.md](docs/list-of-rules.md).

Additionally, the tool incorporates a scoring system based on the Common Vulnerability Scoring System (CVSS) to help prioritize remediation efforts.

# Installation

The following sections explain how to install 2ms using the following methods:
Expand Down Expand Up @@ -397,6 +399,8 @@ The result of the validation can be:

If the `--validate` flag is not provided, the validation field will be omitted from the output, or its value will be an empty string.

> **Note:** The validity check also impacts the score field. If the flag is not provided, the validity is assumed to be "unknown" in the score formula.

### Special Rules

Special rules are rules that are configured in 2ms but are not run as part of the default ruleset, usually because they are too noisy or too specific. You can use the `--add-special-rule` flag to add special rules by rule ID.
Expand Down
6 changes: 5 additions & 1 deletion cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ var report = reporting.Init()
var secretsChan = make(chan *secrets.Secret)
var secretsExtrasChan = make(chan *secrets.Secret)
var validationChan = make(chan *secrets.Secret)
var cvssScoreWithoutValidationChan = make(chan *secrets.Secret)

func Execute() (int, error) {
vConfig.SetEnvPrefix(envPrefix)
Expand Down Expand Up @@ -149,9 +150,12 @@ func preRun(pluginName string, cmd *cobra.Command, args []string) error {

if validateVar {
channels.WaitGroup.Add(1)
go processValidation(engine)
go processValidationAndScoreWithValidation(engine)
}

channels.WaitGroup.Add(1)
go processScoreWithoutValidation(engine)

return nil
}

Expand Down
24 changes: 21 additions & 3 deletions cmd/workers.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package cmd

import (
"github.com/checkmarx/2ms/lib/secrets"
"sync"

"github.com/checkmarx/2ms/engine"
Expand Down Expand Up @@ -28,11 +29,14 @@ func processSecrets() {
secretsExtrasChan <- secret
if validateVar {
validationChan <- secret
} else {
cvssScoreWithoutValidationChan <- secret
}
report.Results[secret.ID] = append(report.Results[secret.ID], secret)
}
close(secretsExtrasChan)
close(validationChan)
close(cvssScoreWithoutValidationChan)
}

func processSecretsExtras() {
Expand All @@ -46,15 +50,29 @@ func processSecretsExtras() {
wgExtras.Wait()
}

func processValidation(engine *engine.Engine) {
func processValidationAndScoreWithValidation(engine *engine.Engine) {
defer channels.WaitGroup.Done()

wgValidation := &sync.WaitGroup{}
for secret := range validationChan {
wgValidation.Add(1)
go engine.RegisterForValidation(secret, wgValidation)
wgValidation.Add(2)
go func(secret *secrets.Secret, wg *sync.WaitGroup) {
engine.RegisterForValidation(secret, wg)
engine.Score(secret, true, wg)
}(secret, wgValidation)
}
wgValidation.Wait()

engine.Validate()
}

func processScoreWithoutValidation(engine *engine.Engine) {
defer channels.WaitGroup.Done()

wgScore := &sync.WaitGroup{}
for secret := range cvssScoreWithoutValidationChan {
wgScore.Add(1)
go engine.Score(secret, false, wgScore)
}
wgScore.Wait()
}
30 changes: 24 additions & 6 deletions engine/engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package engine
import (
"crypto/sha1"
"fmt"
"github.com/checkmarx/2ms/engine/score"
"os"
"regexp"
"strings"
Expand All @@ -21,9 +22,10 @@ import (
)

type Engine struct {
rules map[string]config.Rule
detector detect.Detector
validator validation.Validator
rules map[string]config.Rule
rulesBaseRiskScore map[string]float64
detector detect.Detector
validator validation.Validator

ignoredIds []string
allowedValues []string
Expand All @@ -49,9 +51,11 @@ func Init(engineConfig EngineConfig) (*Engine, error) {
}

rulesToBeApplied := make(map[string]config.Rule)
rulesBaseRiskScore := make(map[string]float64)
keywords := []string{}
for _, rule := range *selectedRules {
rulesToBeApplied[rule.Rule.RuleID] = rule.Rule
rulesBaseRiskScore[rule.Rule.RuleID] = score.GetBaseRiskScore(rule.ScoreParameters.Category, rule.ScoreParameters.RuleType)
for _, keyword := range rule.Rule.Keywords {
keywords = append(keywords, strings.ToLower(keyword))
}
Expand All @@ -63,9 +67,10 @@ func Init(engineConfig EngineConfig) (*Engine, error) {
detector.MaxTargetMegaBytes = engineConfig.MaxTargetMegabytes

return &Engine{
rules: rulesToBeApplied,
detector: *detector,
validator: *validation.NewValidator(),
rules: rulesToBeApplied,
rulesBaseRiskScore: rulesBaseRiskScore,
detector: *detector,
validator: *validation.NewValidator(),

ignoredIds: engineConfig.IgnoredIds,
allowedValues: engineConfig.AllowedValues,
Expand Down Expand Up @@ -131,6 +136,15 @@ func (s *Engine) RegisterForValidation(secret *secrets.Secret, wg *sync.WaitGrou
s.validator.RegisterForValidation(secret)
}

func (s *Engine) Score(secret *secrets.Secret, validateFlag bool, wg *sync.WaitGroup) {
defer wg.Done()
validationStatus := secrets.UnknownResult // default validity
if validateFlag {
validationStatus = secret.ValidationStatus
}
secret.CvssScore = score.GetCvssScore(s.GetRuleBaseRiskScore(secret.RuleID), validationStatus)
}

func (s *Engine) Validate() {
s.validator.Validate()
}
Expand Down Expand Up @@ -191,3 +205,7 @@ func GetRulesCommand(engineConfig *EngineConfig) *cobra.Command {
},
}
}

func (s *Engine) GetRuleBaseRiskScore(ruleId string) float64 {
return s.rulesBaseRiskScore[ruleId]
}
10 changes: 8 additions & 2 deletions engine/rules/rule.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,15 @@ import (
"github.com/zricethezav/gitleaks/v8/detect"
)

type ScoreParameters struct {
Category RuleCategory
RuleType uint8
}

type Rule struct {
Rule config.Rule
Tags []string
Rule config.Rule
Tags []string
ScoreParameters ScoreParameters
}

// Copied from https://github.com/gitleaks/gitleaks/blob/463d24618fa42fc7629dc30c9744ebe36c5df1ab/cmd/generate/config/rules/rule.go
Expand Down
Loading

0 comments on commit 184e893

Please sign in to comment.