Out-of-bounds Read in go-cvss
Description
go-cvss Go module has an out-of-bounds read vulnerability when parsing a full CVSS v2.0 vector, causing a panic; fixed in v0.4.0.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
go-cvss Go module has an out-of-bounds read vulnerability when parsing a full CVSS v2.0 vector, causing a panic; fixed in v0.4.0.
Vulnerability
Description
The go-cvss Go module, designed for parsing and manipulating CVSS vectors, contains an out-of-bounds read vulnerability in its ParseVector function when processing a complete CVSS v2.0 vector string. The issue arises from insufficient input validation, specifically when the vector includes all defined attributes (e.g., base, temporal, environmental, and supplemental metrics). This flaw can cause the Go runtime to panic, leading to a denial of service [1][2].
Exploitation
Conditions
An attacker can exploit this vulnerability by providing a crafted full CVSS v2.0 vector string to any application that uses the go-cvss library to parse user-supplied vectors. No authentication or special network position is required if the application exposes this functionality. The out-of-bounds read occurs during parsing, immediately triggering a panic and crashing the application [2][4].
Impact
The primary impact is denial of service through application termination. The advisory does not indicate that memory corruption leads to code execution or information disclosure. The vulnerability is specific to CVSS v2.0 parsing; other supported CVSS versions (3.0, 3.1, 4.0) are not affected [1].
Mitigation
The issue is patched in go-cvss version v0.4.0, with the fix committed in d9d478ff0c13b8b09ace030db9262f3c2fe031f4 [3]. Users are strongly advised to upgrade. For those unable to upgrade, a workaround is to only parse CVSS v2.0 vectors that do not contain all attributes (e.g., omit environmental or temporal metrics) [2]. The vulnerability is also tracked as GO-2022-1002 in the Go vulnerability database [4].
AI Insight generated on May 21, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
github.com/pandatix/go-cvssGo | >= 0.2.0, < 0.4.0 | 0.4.0 |
Affected products
2Patches
1d9d478ff0c13Improve CVSS v2.0 implementation (0/1 allocs/op)
6 files changed · +468 −248
20/cvss20_bench_test.go+100 −0 added@@ -0,0 +1,100 @@ +package gocvss20_test + +import ( + "testing" + + gocvss20 "github.com/pandatix/go-cvss/20" +) + +var Gcvss20 *gocvss20.CVSS20 +var Gerr error + +func BenchmarkParseVector_Base(b *testing.B) { + benchmarkParseVector("AV:N/AC:L/Au:N/C:P/I:P/A:C", b) +} + +func BenchmarkParseVector_WithTempAndEnv(b *testing.B) { + benchmarkParseVector("AV:N/AC:L/Au:N/C:P/I:P/A:C/E:U/RL:OF/RC:C/CDP:MH/TD:H/CR:M/IR:M/AR:M", b) +} + +func benchmarkParseVector(vector string, b *testing.B) { + var cvss20 *gocvss20.CVSS20 + var err error + b.ResetTimer() + for i := 0; i < b.N; i++ { + cvss20, err = gocvss20.ParseVector(vector) + } + Gcvss20 = cvss20 + Gerr = err +} + +var Gstr string + +func BenchmarkCVSS20Vector(b *testing.B) { + cvss20, _ := gocvss20.ParseVector("AV:N/AC:L/Au:N/C:P/I:P/A:C/E:U/RL:OF/RC:C/CDP:MH/TD:H/CR:M/IR:M/AR:M") + var str string + b.ResetTimer() + for i := 0; i < b.N; i++ { + str = cvss20.Vector() + } + Gstr = str +} + +var Gget string + +func BenchmarkCVSS20Get(b *testing.B) { + const abv = "Au" + cvss20, _ := gocvss20.ParseVector("AV:N/AC:L/Au:N/C:P/I:P/A:C/E:U/RL:OF/RC:C/CDP:MH/TD:H/CR:M/IR:M/AR:M") + var get string + var err error + b.ResetTimer() + for i := 0; i < b.N; i++ { + get, err = cvss20.Get(abv) + } + Gget = get + Gerr = err +} + +func BenchmarkCVSS20Set(b *testing.B) { + const abv = "Au" + const value = "S" + cvss20, _ := gocvss20.ParseVector("AV:N/AC:L/Au:N/C:P/I:P/A:C/E:U/RL:OF/RC:C/CDP:MH/TD:H/CR:M/IR:M/AR:M") + var err error + b.ResetTimer() + for i := 0; i < b.N; i++ { + err = cvss20.Set(abv, value) + } + Gerr = err +} + +var Gscore float64 + +func BenchmarkCVSS20BaseScore(b *testing.B) { + var score float64 + cvss20, _ := gocvss20.ParseVector("AV:N/AC:L/Au:N/C:P/I:P/A:C/E:U/RL:OF/RC:C/CDP:MH/TD:H/CR:M/IR:M/AR:M") + b.ResetTimer() + for i := 0; i < b.N; i++ { + score = cvss20.BaseScore() + } + Gscore = score +} + +func BenchmarkCVSS20TemporalScore(b *testing.B) { + var score float64 + cvss20, _ := gocvss20.ParseVector("AV:N/AC:L/Au:N/C:P/I:P/A:C/E:U/RL:OF/RC:C/CDP:MH/TD:H/CR:M/IR:M/AR:M") + b.ResetTimer() + for i := 0; i < b.N; i++ { + score = cvss20.TemporalScore() + } + Gscore = score +} + +func BenchmarkCVSS20EnvironmentalScore(b *testing.B) { + var score float64 + cvss20, _ := gocvss20.ParseVector("AV:N/AC:L/Au:N/C:P/I:P/A:C/E:U/RL:OF/RC:C/CDP:MH/TD:H/CR:M/IR:M/AR:M") + b.ResetTimer() + for i := 0; i < b.N; i++ { + score = cvss20.EnvironmentalScore() + } + Gscore = score +}
20/cvss20_fuzz_test.go+2 −4 modified@@ -1,9 +1,7 @@ -package gocvss20_test +package gocvss20 import ( "testing" - - gocvss20 "github.com/pandatix/go-cvss/20" ) func FuzzParseVector(f *testing.F) { @@ -12,7 +10,7 @@ func FuzzParseVector(f *testing.F) { } f.Fuzz(func(t *testing.T, vector string) { - cvss20, err := gocvss20.ParseVector(vector) + cvss20, err := ParseVector(vector) if err != nil { if cvss20 != nil {
20/cvss20.go+187 −101 modified@@ -3,172 +3,250 @@ package gocvss20 import ( "math" "strings" + "sync" + "unsafe" ) +var order = [][]string{ + {"AV", "AC", "Au", "C", "I", "A"}, // Base metrics + {"E", "RL", "RC"}, // Temporal metrics + {"CDP", "TD", "CR", "IR", "AR"}, // Environmental metrics +} + // ParseVector parses a CVSS v2.0 vector. func ParseVector(vector string) (*CVSS20, error) { // Split parts - pts := strings.Split(vector, "/") - if len(pts) != 6 && len(pts) != 9 && len(pts) != 14 { + pts, l := split(vector) + if l != 6 && l != 9 && l != 14 { return nil, ErrTooShortVector } + pts = pts[:l] // Work on each CVSS part cvss20 := &CVSS20{ - Base: Base{}, - Temporal: Temporal{ - Exploitability: "ND", - RemediationLevel: "ND", - ReportConfidence: "ND", + base: base{}, + temporal: temporal{ + exploitability: "ND", + remediationLevel: "ND", + reportConfidence: "ND", }, - Environmental: Environmental{ - CollateralDamagePotential: "ND", - TargetDistribution: "ND", - ConfidentialityRequirement: "ND", - IntegrityRequirement: "ND", - AvailabilityRequirement: "ND", + environmental: environmental{ + collateralDamagePotential: "ND", + targetDistribution: "ND", + confidentialityRequirement: "ND", + integrityRequirement: "ND", + availabilityRequirement: "ND", }, } - // Parse metrics in order - slcs := [][]string{ - {"AV", "AC", "Au", "C", "I", "A"}, // Base metrics - {"E", "RL", "RC"}, // Temporal metrics - {"CDP", "TD", "CR", "IR", "AR"}, // Environmental metrics - } slci := 0 - currSlc := slcs[slci] i := 0 for _, pt := range pts { abv, v, _ := strings.Cut(pt, ":") - if abv != currSlc[i] { + if slci == 4 { + return nil, &ErrDefinedN{Abv: abv} + } + if abv != order[slci][i] { return nil, ErrInvalidMetricOrder } + if err := cvss20.Set(abv, v); err != nil { return nil, err } + // Go to next element in slice, or next slice if fully consumed i++ - if i == len(currSlc) { + if i == len(order[slci]) { slci++ - currSlc = slcs[slci] i = 0 } } return cvss20, nil } +var splitPool = sync.Pool{ + New: func() any { + return make([]string, 14) + }, +} + +func split(vector string) ([]string, int) { + partsPtr := splitPool.Get() + defer splitPool.Put(partsPtr) + parts := partsPtr.([]string) + + start := 0 + curr := 0 + l := len(vector) + i := 0 + for ; i < l; i++ { + if vector[i] == '/' { + parts[curr] = vector[start:i] + + start = i + 1 + curr++ + + if curr == 13 { + break + } + } + } + parts[curr] = vector[start:] + return parts, curr + 1 +} + func (cvss20 CVSS20) Vector() string { - s := "" + l := lenVec(&cvss20) + b := make([]byte, 0, l) + // Base - s += "AV:" + cvss20.AccessVector - s += "/AC:" + cvss20.AccessComplexity - s += "/Au:" + cvss20.Authentication - s += "/C:" + cvss20.ConfidentialityImpact - s += "/I:" + cvss20.IntegrityImpact - s += "/A:" + cvss20.AvailabilityImpact - // Temporal, if any is defined - if cvss20.Exploitability != "ND" || cvss20.RemediationLevel != "ND" || cvss20.ReportConfidence != "ND" { - s += "/E:" + cvss20.Exploitability - s += "/RL:" + cvss20.RemediationLevel - s += "/RC:" + cvss20.ReportConfidence + app(&b, "AV:", cvss20.accessVector) + app(&b, "/AC:", cvss20.accessComplexity) + app(&b, "/Au:", cvss20.authentication) + app(&b, "/C:", cvss20.confidentialityImpact) + app(&b, "/I:", cvss20.integrityImpact) + app(&b, "/A:", cvss20.availabilityImpact) + + // Temporal + if cvss20.exploitability != "ND" || cvss20.remediationLevel != "ND" || cvss20.reportConfidence != "ND" { + app(&b, "/E:", cvss20.exploitability) + app(&b, "/RL:", cvss20.remediationLevel) + app(&b, "/RC:", cvss20.reportConfidence) } - // Environmental, if any is defined - if cvss20.CollateralDamagePotential != "ND" || cvss20.TargetDistribution != "ND" || cvss20.ConfidentialityRequirement != "ND" || cvss20.IntegrityRequirement != "ND" || cvss20.AvailabilityRequirement != "ND" { - s += "/CDP:" + cvss20.CollateralDamagePotential - s += "/TD:" + cvss20.TargetDistribution - s += "/CR:" + cvss20.ConfidentialityRequirement - s += "/IR:" + cvss20.IntegrityRequirement - s += "/AR:" + cvss20.AvailabilityRequirement + + // Environmental + if cvss20.collateralDamagePotential != "ND" || cvss20.targetDistribution != "ND" || cvss20.confidentialityRequirement != "ND" || cvss20.integrityRequirement != "ND" || cvss20.availabilityRequirement != "ND" { + app(&b, "/CDP:", cvss20.collateralDamagePotential) + app(&b, "/TD:", cvss20.targetDistribution) + app(&b, "/CR:", cvss20.confidentialityRequirement) + app(&b, "/IR:", cvss20.integrityRequirement) + app(&b, "/AR:", cvss20.availabilityRequirement) } - return s + + return *(*string)(unsafe.Pointer(&b)) +} + +func lenVec(cvss20 *CVSS20) int { + // Base: + // - AV, AC, Au: 4 + // - C, I, A: 3 + // - separators: 5 + // Total: 3*4 + 3*3 + 5 = 30 + l := 26 + + // Temporal: + // - E: 2 + len(v) + // - RL: 3 + len(v) + // - RC: 3 + len(v) + // - separators: 3 + // Total: 11 + 3*len(v) + if cvss20.exploitability != "ND" || cvss20.remediationLevel != "ND" || cvss20.reportConfidence != "ND" { + l += 11 + len(cvss20.exploitability) + len(cvss20.remediationLevel) + len(cvss20.reportConfidence) + } + + // Environmental: + // - CDP: 4 + len(v) + // - TD: 3 + len(v) + // - CR, IR, AR: 3 + len(v) + // - separators: 5 + // Total: 21 + 5*len(v) + if cvss20.collateralDamagePotential != "ND" || cvss20.targetDistribution != "ND" || cvss20.confidentialityRequirement != "ND" || cvss20.integrityRequirement != "ND" || cvss20.availabilityRequirement != "ND" { + l += 21 + len(cvss20.collateralDamagePotential) + len(cvss20.targetDistribution) + len(cvss20.confidentialityRequirement) + len(cvss20.integrityRequirement) + len(cvss20.availabilityRequirement) + } + + return l +} + +func app(b *[]byte, pre, v string) { + *b = append(*b, pre...) + *b = append(*b, v...) } // CVSS20 embeds all the metric values defined by the CVSS v2.0 // rev2 specification. // Attributes values must not be manipulated directly. Use Get // and Set methods. type CVSS20 struct { - Base - Temporal - Environmental + base + temporal + environmental } -// Base is the group of metrics defined with such name by the +// base is the group of metrics defined with such name by the // first.org CVSS v2.0 rev2 specification. // Mandatory. -type Base struct { +type base struct { // AV -> [L,A,N] - AccessVector string + accessVector string // AC -> [H,M,L] - AccessComplexity string + accessComplexity string // Au -> [M,S,N] - Authentication string + authentication string // C -> [N,P,C] - ConfidentialityImpact string + confidentialityImpact string // I -> [N,P,C] - IntegrityImpact string + integrityImpact string // A -> [N,P,C] - AvailabilityImpact string + availabilityImpact string } -// Temporal is the group of metrics defined with such name by the +// temporal is the group of metrics defined with such name by the // first.org CVSS v2.0 rev2 specification. // Not mandatory. -type Temporal struct { +type temporal struct { // E -> [U,POC,F,F,H,ND] - Exploitability string + exploitability string // RL -> [OF,TF,W,U,ND] - RemediationLevel string + remediationLevel string // RC -> [UC,UR,C,ND] - ReportConfidence string + reportConfidence string } -// Environmental is the group of metrics defined with such name by the +// environmental is the group of metrics defined with such name by the // first.org CVSS v2.0 rev2 specification. // Not mandatory. -type Environmental struct { +type environmental struct { // CDP -> [N,L,LM,MH,H,ND] - CollateralDamagePotential string + collateralDamagePotential string // TD -> [N,L,M,H,ND] - TargetDistribution string + targetDistribution string // CR,IR,AR -> [L,M,H,ND] - ConfidentialityRequirement string - IntegrityRequirement string - AvailabilityRequirement string + confidentialityRequirement string + integrityRequirement string + availabilityRequirement string } func (cvss20 CVSS20) Get(abv string) (string, error) { switch abv { case "AV": - return cvss20.AccessVector, nil + return cvss20.accessVector, nil case "AC": - return cvss20.AccessComplexity, nil + return cvss20.accessComplexity, nil case "Au": - return cvss20.Authentication, nil + return cvss20.authentication, nil case "C": - return cvss20.ConfidentialityImpact, nil + return cvss20.confidentialityImpact, nil case "I": - return cvss20.IntegrityImpact, nil + return cvss20.integrityImpact, nil case "A": - return cvss20.AvailabilityImpact, nil + return cvss20.availabilityImpact, nil case "E": - return cvss20.Exploitability, nil + return cvss20.exploitability, nil case "RL": - return cvss20.RemediationLevel, nil + return cvss20.remediationLevel, nil case "RC": - return cvss20.ReportConfidence, nil + return cvss20.reportConfidence, nil case "CDP": - return cvss20.CollateralDamagePotential, nil + return cvss20.collateralDamagePotential, nil case "TD": - return cvss20.TargetDistribution, nil + return cvss20.targetDistribution, nil case "CR": - return cvss20.ConfidentialityRequirement, nil + return cvss20.confidentialityRequirement, nil case "IR": - return cvss20.IntegrityRequirement, nil + return cvss20.integrityRequirement, nil case "AR": - return cvss20.AvailabilityRequirement, nil + return cvss20.availabilityRequirement, nil default: return "", &ErrInvalidMetric{Abv: abv} } @@ -181,74 +259,74 @@ func (cvss20 *CVSS20) Set(abv string, value string) error { if err := validate(value, []string{"L", "A", "N"}); err != nil { return err } - cvss20.AccessVector = value + cvss20.accessVector = value case "AC": if err := validate(value, []string{"H", "M", "L"}); err != nil { return err } - cvss20.AccessComplexity = value + cvss20.accessComplexity = value case "Au": if err := validate(value, []string{"M", "S", "N"}); err != nil { return err } - cvss20.Authentication = value + cvss20.authentication = value case "C": if err := validate(value, []string{"N", "P", "C"}); err != nil { return err } - cvss20.ConfidentialityImpact = value + cvss20.confidentialityImpact = value case "I": if err := validate(value, []string{"N", "P", "C"}); err != nil { return err } - cvss20.IntegrityImpact = value + cvss20.integrityImpact = value case "A": if err := validate(value, []string{"N", "P", "C"}); err != nil { return err } - cvss20.AvailabilityImpact = value + cvss20.availabilityImpact = value // Temporal case "E": if err := validate(value, []string{"U", "POC", "F", "H", "ND"}); err != nil { return err } - cvss20.Exploitability = value + cvss20.exploitability = value case "RL": if err := validate(value, []string{"OF", "TF", "W", "U", "ND"}); err != nil { return err } - cvss20.RemediationLevel = value + cvss20.remediationLevel = value case "RC": if err := validate(value, []string{"UC", "UR", "C", "ND"}); err != nil { return err } - cvss20.ReportConfidence = value + cvss20.reportConfidence = value // Environmental case "CDP": if err := validate(value, []string{"N", "L", "LM", "MH", "H", "ND"}); err != nil { return err } - cvss20.CollateralDamagePotential = value + cvss20.collateralDamagePotential = value case "TD": if err := validate(value, []string{"N", "L", "M", "H", "ND"}); err != nil { return err } - cvss20.TargetDistribution = value + cvss20.targetDistribution = value case "CR": if err := validate(value, []string{"L", "M", "H", "ND"}); err != nil { return err } - cvss20.ConfidentialityRequirement = value + cvss20.confidentialityRequirement = value case "IR": if err := validate(value, []string{"L", "M", "H", "ND"}); err != nil { return err } - cvss20.IntegrityRequirement = value + cvss20.integrityRequirement = value case "AR": if err := validate(value, []string{"L", "M", "H", "ND"}); err != nil { return err } - cvss20.AvailabilityRequirement = value + cvss20.availabilityRequirement = value default: return &ErrInvalidMetric{Abv: abv} } @@ -267,32 +345,40 @@ func validate(value string, enabled []string) error { // BaseScore returns the CVSS v2.0's base score. func (cvss20 CVSS20) BaseScore() float64 { - impact := 10.41 * (1 - (1-cia(cvss20.ConfidentialityImpact))*(1-cia(cvss20.IntegrityImpact))*(1-cia(cvss20.AvailabilityImpact))) + impact := cvss20.Impact() fimpact := 0.0 if impact != 0 { fimpact = 1.176 } - exploitability := 20 * accessVector(cvss20.AccessVector) * accessComplexity(cvss20.AccessComplexity) * authentication(cvss20.Authentication) + exploitability := cvss20.Exploitability() return roundTo1Decimal(((0.6 * impact) + (0.4 * exploitability) - 1.5) * fimpact) } +func (cvss20 CVSS20) Impact() float64 { + return 10.41 * (1 - (1-cia(cvss20.confidentialityImpact))*(1-cia(cvss20.integrityImpact))*(1-cia(cvss20.availabilityImpact))) +} + +func (cvss20 CVSS20) Exploitability() float64 { + return 20 * accessVector(cvss20.accessVector) * accessComplexity(cvss20.accessComplexity) * authentication(cvss20.authentication) +} + // TemporalScore returns the CVSS v2.0's temporal score. func (cvss20 CVSS20) TemporalScore() float64 { - return roundTo1Decimal(cvss20.BaseScore() * exploitability(cvss20.Exploitability) * remediationLevel(cvss20.RemediationLevel) * reportConfidence(cvss20.ReportConfidence)) + return roundTo1Decimal(cvss20.BaseScore() * exploitability(cvss20.exploitability) * remediationLevel(cvss20.remediationLevel) * reportConfidence(cvss20.reportConfidence)) } // EnvironmentalScore returns the CVSS v2.0's environmental score. func (cvss20 CVSS20) EnvironmentalScore() float64 { // Recompute base score - adjustedImpact := math.Min(10, 10.41*(1-(1-cia(cvss20.ConfidentialityImpact)*ciar(cvss20.ConfidentialityRequirement))*(1-cia(cvss20.IntegrityImpact)*ciar(cvss20.IntegrityRequirement))*(1-cia(cvss20.AvailabilityImpact)*ciar(cvss20.AvailabilityRequirement)))) + adjustedImpact := math.Min(10, 10.41*(1-(1-cia(cvss20.confidentialityImpact)*ciar(cvss20.confidentialityRequirement))*(1-cia(cvss20.integrityImpact)*ciar(cvss20.integrityRequirement))*(1-cia(cvss20.availabilityImpact)*ciar(cvss20.availabilityRequirement)))) fimpactBase := 0.0 if adjustedImpact != 0 { fimpactBase = 1.176 } - expltBase := 20 * accessVector(cvss20.AccessVector) * accessComplexity(cvss20.AccessComplexity) * authentication(cvss20.Authentication) + expltBase := 20 * accessVector(cvss20.accessVector) * accessComplexity(cvss20.accessComplexity) * authentication(cvss20.authentication) recBase := roundTo1Decimal(((0.6 * adjustedImpact) + (0.4 * expltBase) - 1.5) * fimpactBase) - adjustedTemporal := roundTo1Decimal(recBase * exploitability(cvss20.Exploitability) * remediationLevel(cvss20.RemediationLevel) * reportConfidence(cvss20.ReportConfidence)) - return roundTo1Decimal((adjustedTemporal + (10-adjustedTemporal)*collateralDamagePotential(cvss20.CollateralDamagePotential)) * targetDistribution(cvss20.TargetDistribution)) + adjustedTemporal := roundTo1Decimal(recBase * exploitability(cvss20.exploitability) * remediationLevel(cvss20.remediationLevel) * reportConfidence(cvss20.reportConfidence)) + return roundTo1Decimal((adjustedTemporal + (10-adjustedTemporal)*collateralDamagePotential(cvss20.collateralDamagePotential)) * targetDistribution(cvss20.targetDistribution)) } // Helpers to compute CVSS v2.0 scores.
20/cvss20_test.go+146 −113 modified@@ -1,95 +1,128 @@ -package gocvss20_test +package gocvss20 import ( "testing" - gocvss20 "github.com/pandatix/go-cvss/20" "github.com/stretchr/testify/assert" ) var testsParseVector = map[string]struct { Vector string - ExpectedCVSS20 *gocvss20.CVSS20 + ExpectedCVSS20 *CVSS20 ExpectedErr error }{ "CVSS v2.0 Guide Section 3.3.1 CVE-2002-0392": { Vector: "AV:N/AC:L/Au:N/C:N/I:N/A:C/E:F/RL:OF/RC:C", - ExpectedCVSS20: &gocvss20.CVSS20{ - Base: gocvss20.Base{ - AccessVector: "N", - AccessComplexity: "L", - Authentication: "N", - ConfidentialityImpact: "N", - IntegrityImpact: "N", - AvailabilityImpact: "C", + ExpectedCVSS20: &CVSS20{ + base: base{ + accessVector: "N", + accessComplexity: "L", + authentication: "N", + confidentialityImpact: "N", + integrityImpact: "N", + availabilityImpact: "C", }, - Temporal: gocvss20.Temporal{ - Exploitability: "F", - RemediationLevel: "OF", - ReportConfidence: "C", + temporal: temporal{ + exploitability: "F", + remediationLevel: "OF", + reportConfidence: "C", }, - Environmental: gocvss20.Environmental{ - CollateralDamagePotential: "ND", - TargetDistribution: "ND", - ConfidentialityRequirement: "ND", - IntegrityRequirement: "ND", - AvailabilityRequirement: "ND", + environmental: environmental{ + collateralDamagePotential: "ND", + targetDistribution: "ND", + confidentialityRequirement: "ND", + integrityRequirement: "ND", + availabilityRequirement: "ND", }, }, ExpectedErr: nil, }, "CVSS v2.0 Guide Section 3.3.2 CVE-2003-0818": { Vector: "AV:N/AC:L/Au:N/C:C/I:C/A:C/E:F/RL:OF/RC:C", - ExpectedCVSS20: &gocvss20.CVSS20{ - Base: gocvss20.Base{ - AccessVector: "N", - AccessComplexity: "L", - Authentication: "N", - ConfidentialityImpact: "C", - IntegrityImpact: "C", - AvailabilityImpact: "C", + ExpectedCVSS20: &CVSS20{ + base: base{ + accessVector: "N", + accessComplexity: "L", + authentication: "N", + confidentialityImpact: "C", + integrityImpact: "C", + availabilityImpact: "C", }, - Temporal: gocvss20.Temporal{ - Exploitability: "F", - RemediationLevel: "OF", - ReportConfidence: "C", + temporal: temporal{ + exploitability: "F", + remediationLevel: "OF", + reportConfidence: "C", }, - Environmental: gocvss20.Environmental{ - CollateralDamagePotential: "ND", - TargetDistribution: "ND", - ConfidentialityRequirement: "ND", - IntegrityRequirement: "ND", - AvailabilityRequirement: "ND", + environmental: environmental{ + collateralDamagePotential: "ND", + targetDistribution: "ND", + confidentialityRequirement: "ND", + integrityRequirement: "ND", + availabilityRequirement: "ND", }, }, ExpectedErr: nil, }, "CVSS v2.0 Guide Section 3.3.3 CVE-2003-0062": { Vector: "AV:L/AC:H/Au:N/C:C/I:C/A:C/E:POC/RL:OF/RC:C", - ExpectedCVSS20: &gocvss20.CVSS20{ - Base: gocvss20.Base{ - AccessVector: "L", - AccessComplexity: "H", - Authentication: "N", - ConfidentialityImpact: "C", - IntegrityImpact: "C", - AvailabilityImpact: "C", + ExpectedCVSS20: &CVSS20{ + base: base{ + accessVector: "L", + accessComplexity: "H", + authentication: "N", + confidentialityImpact: "C", + integrityImpact: "C", + availabilityImpact: "C", }, - Temporal: gocvss20.Temporal{ - Exploitability: "POC", - RemediationLevel: "OF", - ReportConfidence: "C", + temporal: temporal{ + exploitability: "POC", + remediationLevel: "OF", + reportConfidence: "C", }, - Environmental: gocvss20.Environmental{ - CollateralDamagePotential: "ND", - TargetDistribution: "ND", - ConfidentialityRequirement: "ND", - IntegrityRequirement: "ND", - AvailabilityRequirement: "ND", + environmental: environmental{ + collateralDamagePotential: "ND", + targetDistribution: "ND", + confidentialityRequirement: "ND", + integrityRequirement: "ND", + availabilityRequirement: "ND", }, }, ExpectedErr: nil, }, + "all-defined": { + Vector: "AV:N/AC:L/Au:N/C:P/I:P/A:C/E:U/RL:OF/RC:C/CDP:MH/TD:H/CR:M/IR:M/AR:M", + ExpectedCVSS20: &CVSS20{ + base: base{ + accessVector: "N", + accessComplexity: "L", + authentication: "N", + confidentialityImpact: "P", + integrityImpact: "P", + availabilityImpact: "C", + }, + temporal: temporal{ + exploitability: "U", + remediationLevel: "OF", + reportConfidence: "C", + }, + environmental: environmental{ + collateralDamagePotential: "MH", + targetDistribution: "H", + confidentialityRequirement: "M", + integrityRequirement: "M", + availabilityRequirement: "M", + }, + }, + ExpectedErr: nil, + }, + "Fuzz_50620a37c4a7716a77a14602b4bcc7b02e6f751d0a714ed796d9b04402c745ac": { + // This fuzz crasher enabled detecting that the split function + // (comming from the optimization step) was doing an Out-Of-Bounds + // Write (CWE-787) if the vector was only composed of '/'. + Vector: "//////////////", + ExpectedCVSS20: nil, + ExpectedErr: ErrInvalidMetricOrder, + }, } func TestParseVector(t *testing.T) { @@ -99,7 +132,7 @@ func TestParseVector(t *testing.T) { t.Run(testname, func(t *testing.T) { assert := assert.New(t) - cvss20, err := gocvss20.ParseVector(tt.Vector) + cvss20, err := ParseVector(tt.Vector) assert.Equal(tt.ExpectedCVSS20, cvss20) assert.Equal(tt.ExpectedErr, err) @@ -111,86 +144,86 @@ func TestScores(t *testing.T) { t.Parallel() var tests = map[string]struct { - CVSS20 *gocvss20.CVSS20 + CVSS20 *CVSS20 ExpectedBaseScore float64 ExpectedTemporalScore float64 ExpectedEnvironmentalScore float64 }{ "CVSS v2.0 Guide Section 3.3.1 CVE-2002-0392": { - CVSS20: &gocvss20.CVSS20{ - Base: gocvss20.Base{ - AccessVector: "N", - AccessComplexity: "L", - Authentication: "N", - ConfidentialityImpact: "N", - IntegrityImpact: "N", - AvailabilityImpact: "C", + CVSS20: &CVSS20{ + base: base{ + accessVector: "N", + accessComplexity: "L", + authentication: "N", + confidentialityImpact: "N", + integrityImpact: "N", + availabilityImpact: "C", }, - Temporal: gocvss20.Temporal{ - Exploitability: "F", - RemediationLevel: "OF", - ReportConfidence: "C", + temporal: temporal{ + exploitability: "F", + remediationLevel: "OF", + reportConfidence: "C", }, - Environmental: gocvss20.Environmental{ - CollateralDamagePotential: "ND", - TargetDistribution: "ND", - ConfidentialityRequirement: "ND", - IntegrityRequirement: "ND", - AvailabilityRequirement: "ND", + environmental: environmental{ + collateralDamagePotential: "ND", + targetDistribution: "ND", + confidentialityRequirement: "ND", + integrityRequirement: "ND", + availabilityRequirement: "ND", }, }, ExpectedBaseScore: 7.8, ExpectedTemporalScore: 6.4, ExpectedEnvironmentalScore: 6.4, }, "CVSS v2.0 Guide Section 3.3.2 CVE-2003-0818": { - CVSS20: &gocvss20.CVSS20{ - Base: gocvss20.Base{ - AccessVector: "N", - AccessComplexity: "L", - Authentication: "N", - ConfidentialityImpact: "C", - IntegrityImpact: "C", - AvailabilityImpact: "C", + CVSS20: &CVSS20{ + base: base{ + accessVector: "N", + accessComplexity: "L", + authentication: "N", + confidentialityImpact: "C", + integrityImpact: "C", + availabilityImpact: "C", }, - Temporal: gocvss20.Temporal{ - Exploitability: "F", - RemediationLevel: "OF", - ReportConfidence: "C", + temporal: temporal{ + exploitability: "F", + remediationLevel: "OF", + reportConfidence: "C", }, - Environmental: gocvss20.Environmental{ - CollateralDamagePotential: "ND", - TargetDistribution: "ND", - ConfidentialityRequirement: "ND", - IntegrityRequirement: "ND", - AvailabilityRequirement: "ND", + environmental: environmental{ + collateralDamagePotential: "ND", + targetDistribution: "ND", + confidentialityRequirement: "ND", + integrityRequirement: "ND", + availabilityRequirement: "ND", }, }, ExpectedBaseScore: 10.0, ExpectedTemporalScore: 8.3, ExpectedEnvironmentalScore: 8.3, }, "CVSS v2.0 Guide Section 3.3.3 CVE-2003-0062": { - CVSS20: &gocvss20.CVSS20{ - Base: gocvss20.Base{ - AccessVector: "L", - AccessComplexity: "H", - Authentication: "N", - ConfidentialityImpact: "C", - IntegrityImpact: "C", - AvailabilityImpact: "C", + CVSS20: &CVSS20{ + base: base{ + accessVector: "L", + accessComplexity: "H", + authentication: "N", + confidentialityImpact: "C", + integrityImpact: "C", + availabilityImpact: "C", }, - Temporal: gocvss20.Temporal{ - Exploitability: "POC", - RemediationLevel: "OF", - ReportConfidence: "C", + temporal: temporal{ + exploitability: "POC", + remediationLevel: "OF", + reportConfidence: "C", }, - Environmental: gocvss20.Environmental{ - CollateralDamagePotential: "ND", - TargetDistribution: "ND", - ConfidentialityRequirement: "ND", - IntegrityRequirement: "ND", - AvailabilityRequirement: "ND", + environmental: environmental{ + collateralDamagePotential: "ND", + targetDistribution: "ND", + confidentialityRequirement: "ND", + integrityRequirement: "ND", + availabilityRequirement: "ND", }, }, ExpectedBaseScore: 6.2,
20/errors.go+2 −14 modified@@ -11,26 +11,14 @@ var ( ErrInvalidMetricValue = errors.New("invalid metric value") ) -// ErrBaseScore is an error returned by ParseVector when the -// given vector have missing base score attributes. -type ErrBaseScore struct { - Missings []string -} - -func (err ErrBaseScore) Error() string { - return fmt.Sprintf("base score is missing metrics %v", err.Missings) -} - -var _ error = (*ErrBaseScore)(nil) - // ErrDefinedN is an error return by ParseVector when the // given vector has metrics abbreviations defined multiple times. type ErrDefinedN struct { - Abv []string + Abv string } func (err ErrDefinedN) Error() string { - return fmt.Sprintf("given CVSS v3.1 vector has %v metric abbreviations defined multiple times", err.Abv) + return fmt.Sprintf("given CVSS v3.1 vector has %s metric abbreviation defined after vector end", err.Abv) } var _ error = (*ErrDefinedN)(nil)
README.md+31 −16 modified@@ -74,21 +74,36 @@ We challenge any other Go implementation to do better :stuck_out_tongue_winking_ ### CVSS v2.0 +``` +goos: linux +goarch: amd64 +pkg: github.com/pandatix/go-cvss/20 +cpu: Intel(R) Core(TM) i5-2450M CPU @ 2.50GHz +BenchmarkParseVector_Base-4 2089275 572.9 ns/op 224 B/op 1 allocs/op +BenchmarkParseVector_WithTempAndEnv-4 1000000 1118 ns/op 224 B/op 1 allocs/op +BenchmarkCVSS20Vector-4 6806152 176.3 ns/op 80 B/op 1 allocs/op +BenchmarkCVSS20Get-4 46162280 26.50 ns/op 0 B/op 0 allocs/op +BenchmarkCVSS20Set-4 42365036 27.50 ns/op 0 B/op 0 allocs/op +BenchmarkCVSS20BaseScore-4 20117143 57.68 ns/op 0 B/op 0 allocs/op +BenchmarkCVSS20TemporalScore-4 14383033 83.66 ns/op 0 B/op 0 allocs/op +BenchmarkCVSS20EnvironmentalScore-4 15307656 79.48 ns/op 0 B/op 0 allocs/op +``` + ### CVSS v3.0 ``` goos: linux goarch: amd64 pkg: github.com/pandatix/go-cvss/30 cpu: Intel(R) Core(TM) i5-2450M CPU @ 2.50GHz -BenchmarkParseVector_Base-4 1443836 808.4 ns/op 352 B/op 1 allocs/op -BenchmarkParseVector_WithTempAndEnv-4 701901 1711 ns/op 352 B/op 1 allocs/op -BenchmarkCVSS30Vector-4 5593758 215.8 ns/op 96 B/op 1 allocs/op -BenchmarkCVSS30Get-4 27306528 41.66 ns/op 0 B/op 0 allocs/op -BenchmarkCVSS30Set-4 31862641 37.94 ns/op 0 B/op 0 allocs/op -BenchmarkCVSS30BaseScore-4 7769804 139.2 ns/op 0 B/op 0 allocs/op -BenchmarkCVSS30TemporalScore-4 5814230 189.1 ns/op 0 B/op 0 allocs/op -BenchmarkCVSS30EnvironmentalScore-4 6402489 188.7 ns/op 0 B/op 0 allocs/op +BenchmarkParseVector_Base-4 1458514 843.4 ns/op 352 B/op 1 allocs/op +BenchmarkParseVector_WithTempAndEnv-4 703789 2067 ns/op 352 B/op 1 allocs/op +BenchmarkCVSS30Vector-4 4587404 237.0 ns/op 96 B/op 1 allocs/op +BenchmarkCVSS30Get-4 26877397 51.38 ns/op 0 B/op 0 allocs/op +BenchmarkCVSS30Set-4 32284153 38.53 ns/op 0 B/op 0 allocs/op +BenchmarkCVSS30BaseScore-4 8275440 145.4 ns/op 0 B/op 0 allocs/op +BenchmarkCVSS30TemporalScore-4 6054021 195.7 ns/op 0 B/op 0 allocs/op +BenchmarkCVSS30EnvironmentalScore-4 6230708 191.2 ns/op 0 B/op 0 allocs/op ``` ### CVSS v3.1 @@ -98,14 +113,14 @@ goos: linux goarch: amd64 pkg: github.com/pandatix/go-cvss/31 cpu: Intel(R) Core(TM) i5-2450M CPU @ 2.50GHz -BenchmarkParseVector_Base-4 1312525 895.0 ns/op 352 B/op 1 allocs/op -BenchmarkParseVector_WithTempAndEnv-4 685629 2232 ns/op 352 B/op 1 allocs/op -BenchmarkCVSS31Vector-4 4867528 223.2 ns/op 96 B/op 1 allocs/op -BenchmarkCVSS31Get-4 31498058 36.37 ns/op 0 B/op 0 allocs/op -BenchmarkCVSS31Set-4 30187612 38.73 ns/op 0 B/op 0 allocs/op -BenchmarkCVSS31BaseScore-4 11144173 101.2 ns/op 0 B/op 0 allocs/op -BenchmarkCVSS31TemporalScore-4 7856455 154.4 ns/op 0 B/op 0 allocs/op -BenchmarkCVSS31EnvironmentalScore-4 6310815 169.4 ns/op 0 B/op 0 allocs/op +BenchmarkParseVector_Base-4 1445559 825.3 ns/op 352 B/op 1 allocs/op +BenchmarkParseVector_WithTempAndEnv-4 658578 1836 ns/op 352 B/op 1 allocs/op +BenchmarkCVSS31Vector-4 5087984 244.1 ns/op 96 B/op 1 allocs/op +BenchmarkCVSS31Get-4 28350058 41.40 ns/op 0 B/op 0 allocs/op +BenchmarkCVSS31Set-4 30340425 40.16 ns/op 0 B/op 0 allocs/op +BenchmarkCVSS31BaseScore-4 8535666 139.3 ns/op 0 B/op 0 allocs/op +BenchmarkCVSS31TemporalScore-4 6004561 189.7 ns/op 0 B/op 0 allocs/op +BenchmarkCVSS31EnvironmentalScore-4 5937879 184.5 ns/op 0 B/op 0 allocs/op ``` ## Feedbacks
Vulnerability mechanics
Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
6- github.com/advisories/GHSA-xhmf-mmv2-4hhxghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2022-39213ghsaADVISORY
- github.com/pandatix/go-cvss/blob/master/SECURITY.mdghsax_refsource_MISCWEB
- github.com/pandatix/go-cvss/commit/d9d478ff0c13b8b09ace030db9262f3c2fe031f4ghsax_refsource_MISCWEB
- github.com/pandatix/go-cvss/security/advisories/GHSA-xhmf-mmv2-4hhxghsax_refsource_CONFIRMWEB
- pkg.go.dev/vuln/GO-2022-1002ghsaWEB
News mentions
0No linked articles in our index yet.