Skip to content

Commit 184e893

Browse files
feat: add score system (#260)
1 parent f5a5cb4 commit 184e893

File tree

11 files changed

+587
-180
lines changed

11 files changed

+587
-180
lines changed

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ This application is written in Go language and is based on the framework provide
1010

1111
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).
1212

13+
Additionally, the tool incorporates a scoring system based on the Common Vulnerability Scoring System (CVSS) to help prioritize remediation efforts.
14+
1315
# Installation
1416

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

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

402+
> **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.
403+
400404
### Special Rules
401405

402406
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.

cmd/main.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ var report = reporting.Init()
7676
var secretsChan = make(chan *secrets.Secret)
7777
var secretsExtrasChan = make(chan *secrets.Secret)
7878
var validationChan = make(chan *secrets.Secret)
79+
var cvssScoreWithoutValidationChan = make(chan *secrets.Secret)
7980

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

150151
if validateVar {
151152
channels.WaitGroup.Add(1)
152-
go processValidation(engine)
153+
go processValidationAndScoreWithValidation(engine)
153154
}
154155

156+
channels.WaitGroup.Add(1)
157+
go processScoreWithoutValidation(engine)
158+
155159
return nil
156160
}
157161

cmd/workers.go

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package cmd
22

33
import (
4+
"github.com/checkmarx/2ms/lib/secrets"
45
"sync"
56

67
"github.com/checkmarx/2ms/engine"
@@ -28,11 +29,14 @@ func processSecrets() {
2829
secretsExtrasChan <- secret
2930
if validateVar {
3031
validationChan <- secret
32+
} else {
33+
cvssScoreWithoutValidationChan <- secret
3134
}
3235
report.Results[secret.ID] = append(report.Results[secret.ID], secret)
3336
}
3437
close(secretsExtrasChan)
3538
close(validationChan)
39+
close(cvssScoreWithoutValidationChan)
3640
}
3741

3842
func processSecretsExtras() {
@@ -46,15 +50,29 @@ func processSecretsExtras() {
4650
wgExtras.Wait()
4751
}
4852

49-
func processValidation(engine *engine.Engine) {
53+
func processValidationAndScoreWithValidation(engine *engine.Engine) {
5054
defer channels.WaitGroup.Done()
5155

5256
wgValidation := &sync.WaitGroup{}
5357
for secret := range validationChan {
54-
wgValidation.Add(1)
55-
go engine.RegisterForValidation(secret, wgValidation)
58+
wgValidation.Add(2)
59+
go func(secret *secrets.Secret, wg *sync.WaitGroup) {
60+
engine.RegisterForValidation(secret, wg)
61+
engine.Score(secret, true, wg)
62+
}(secret, wgValidation)
5663
}
5764
wgValidation.Wait()
5865

5966
engine.Validate()
6067
}
68+
69+
func processScoreWithoutValidation(engine *engine.Engine) {
70+
defer channels.WaitGroup.Done()
71+
72+
wgScore := &sync.WaitGroup{}
73+
for secret := range cvssScoreWithoutValidationChan {
74+
wgScore.Add(1)
75+
go engine.Score(secret, false, wgScore)
76+
}
77+
wgScore.Wait()
78+
}

engine/engine.go

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package engine
33
import (
44
"crypto/sha1"
55
"fmt"
6+
"github.com/checkmarx/2ms/engine/score"
67
"os"
78
"regexp"
89
"strings"
@@ -21,9 +22,10 @@ import (
2122
)
2223

2324
type Engine struct {
24-
rules map[string]config.Rule
25-
detector detect.Detector
26-
validator validation.Validator
25+
rules map[string]config.Rule
26+
rulesBaseRiskScore map[string]float64
27+
detector detect.Detector
28+
validator validation.Validator
2729

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

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

6569
return &Engine{
66-
rules: rulesToBeApplied,
67-
detector: *detector,
68-
validator: *validation.NewValidator(),
70+
rules: rulesToBeApplied,
71+
rulesBaseRiskScore: rulesBaseRiskScore,
72+
detector: *detector,
73+
validator: *validation.NewValidator(),
6974

7075
ignoredIds: engineConfig.IgnoredIds,
7176
allowedValues: engineConfig.AllowedValues,
@@ -131,6 +136,15 @@ func (s *Engine) RegisterForValidation(secret *secrets.Secret, wg *sync.WaitGrou
131136
s.validator.RegisterForValidation(secret)
132137
}
133138

139+
func (s *Engine) Score(secret *secrets.Secret, validateFlag bool, wg *sync.WaitGroup) {
140+
defer wg.Done()
141+
validationStatus := secrets.UnknownResult // default validity
142+
if validateFlag {
143+
validationStatus = secret.ValidationStatus
144+
}
145+
secret.CvssScore = score.GetCvssScore(s.GetRuleBaseRiskScore(secret.RuleID), validationStatus)
146+
}
147+
134148
func (s *Engine) Validate() {
135149
s.validator.Validate()
136150
}
@@ -191,3 +205,7 @@ func GetRulesCommand(engineConfig *EngineConfig) *cobra.Command {
191205
},
192206
}
193207
}
208+
209+
func (s *Engine) GetRuleBaseRiskScore(ruleId string) float64 {
210+
return s.rulesBaseRiskScore[ruleId]
211+
}

engine/rules/rule.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,15 @@ import (
88
"github.com/zricethezav/gitleaks/v8/detect"
99
)
1010

11+
type ScoreParameters struct {
12+
Category RuleCategory
13+
RuleType uint8
14+
}
15+
1116
type Rule struct {
12-
Rule config.Rule
13-
Tags []string
17+
Rule config.Rule
18+
Tags []string
19+
ScoreParameters ScoreParameters
1420
}
1521

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

0 commit comments

Comments
 (0)