Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions vulnfeeds/cmd/combine-to-osv/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,10 @@ func combineTwoOSVRecords(cve5 *osvschema.Vulnerability, nvd *osvschema.Vulnerab
}
}

if len(nvd.GetSeverity()) > 0 {
baseOSV.Severity = nvd.GetSeverity()
}

return baseOSV
}

Expand Down
18 changes: 18 additions & 0 deletions vulnfeeds/cmd/combine-to-osv/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,12 @@ func TestCombineTwoOSVRecords(t *testing.T) {
Package: &osvschema.Package{Name: "package-a"},
},
},
Severity: []*osvschema.Severity{
{
Type: osvschema.Severity_CVSS_V3,
Score: "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:N",
},
},
}

nvd := &osvschema.Vulnerability{
Expand All @@ -398,6 +404,12 @@ func TestCombineTwoOSVRecords(t *testing.T) {
Package: &osvschema.Package{Name: "package-b"},
},
},
Severity: []*osvschema.Severity{
{
Type: osvschema.Severity_CVSS_V3,
Score: "CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:L/A:N",
},
},
}

expected := &osvschema.Vulnerability{
Expand All @@ -411,6 +423,12 @@ func TestCombineTwoOSVRecords(t *testing.T) {
},
// pickAffectedInformation prefers nvd if it has more packages
Affected: nvd.GetAffected(),
Severity: []*osvschema.Severity{ // Should take severity from NVD
{
Type: osvschema.Severity_CVSS_V3,
Score: "CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:L/A:N",
},
},
}

got := combineTwoOSVRecords(cve5, nvd)
Expand Down
2 changes: 1 addition & 1 deletion vulnfeeds/cmd/converters/alpine/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ func generateAlpineOSV(allAlpineSecDb map[string][]VersionAndPkg, allCVEs map[mo
continue
}
if cve.CVE.Metrics != nil {
v.AddSeverity(cve.CVE.Metrics)
v.AddSingleSeverity(cve.CVE.Metrics)
}

osvVulnerabilities = append(osvVulnerabilities, v)
Expand Down
2 changes: 1 addition & 1 deletion vulnfeeds/cmd/converters/debian/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ func generateOSVFromDebianTracker(debianData DebianSecurityTrackerData, debianRe
},
}
if currentNVDCVE.CVE.Metrics != nil {
v.AddSeverity(currentNVDCVE.CVE.Metrics)
v.AddSingleSeverity(currentNVDCVE.CVE.Metrics)
}

osvCves[cveID] = v
Expand Down
4 changes: 2 additions & 2 deletions vulnfeeds/cmd/converters/debian/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ func TestGenerateOSVFromDebianTracker(t *testing.T) {
},
},
References: []*osvschema.Reference{{Type: osvschema.Reference_ADVISORY, Url: "https://security-tracker.debian.org/tracker/CVE-2016-1585"}},
Severity: []*osvschema.Severity{{Type: osvschema.Severity_CVSS_V3, Score: "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H"}},
Severity: []*osvschema.Severity{{Type: osvschema.Severity_CVSS_V3, Score: "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", Source: "nvd@nist.gov"}},
},
},
"CVE-2017-6507": {
Expand Down Expand Up @@ -192,7 +192,7 @@ func TestGenerateOSVFromDebianTracker(t *testing.T) {
},
},
References: []*osvschema.Reference{{Type: osvschema.Reference_ADVISORY, Url: "https://security-tracker.debian.org/tracker/CVE-2017-6507"}},
Severity: []*osvschema.Severity{{Type: osvschema.Severity_CVSS_V3, Score: "CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:H/A:N"}},
Severity: []*osvschema.Severity{{Type: osvschema.Severity_CVSS_V3, Score: "CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:H/A:N", Source: "nvd@nist.gov"}},
},
},
}
Expand Down
56 changes: 44 additions & 12 deletions vulnfeeds/vulns/vulns.go
Original file line number Diff line number Diff line change
Expand Up @@ -323,45 +323,77 @@ func (v *Vulnerability) AddPkgInfo(pkgInfo PackageInfo) {

// getBestSeverity finds the best CVSS severity vector from the provided metrics data.
// It prioritizes newer CVSS versions and "Primary" sources.
func getBestSeverity(metricsData *models.CVEItemMetrics) (string, string) {
func getBestSeverity(metricsData *models.CVEItemMetrics) (string, string, string) {
if metricsData == nil {
return "", "", ""
}
// Define search passes. First pass for "Primary", second for any.
for _, primaryOnly := range []bool{true, false} {
// Inside each pass, prioritize v4.0 over v3.1 over v3.0.
for _, metric := range metricsData.CVSSMetricV40 {
if (!primaryOnly || metric.Type == "Primary") && metric.CVSSData.VectorString != "" {
return metric.CVSSData.VectorString, "CVSS_V4"
return metric.CVSSData.VectorString, "CVSS_V4", metric.Source
}
}
for _, metric := range metricsData.CVSSMetricV31 {
if (!primaryOnly || metric.Type == "Primary") && metric.CVSSData.VectorString != "" {
return metric.CVSSData.VectorString, "CVSS_V3"
return metric.CVSSData.VectorString, "CVSS_V3", metric.Source
}
}
for _, metric := range metricsData.CVSSMetricV30 {
if (!primaryOnly || metric.Type == "Primary") && metric.CVSSData.VectorString != "" {
return metric.CVSSData.VectorString, "CVSS_V3"
return metric.CVSSData.VectorString, "CVSS_V3", metric.Source
}
}
}

return "", ""
return "", "", ""
}

// AddSeverity adds CVSS severity information to the OSV vulnerability object.
// It uses the highest available CVSS score from the underlying CVE record.
func (v *Vulnerability) AddSeverity(metricsData *models.CVEItemMetrics) {
bestVectorString, severityType := getBestSeverity(metricsData)
// AddSingleSeverity adds CVSS severity information to the OSV vulnerability object.
// It uses the getBestSeverity function to determine the best severity.
func (v *Vulnerability) AddSingleSeverity(metricsData *models.CVEItemMetrics) {
bestVectorString, severityType, source := getBestSeverity(metricsData)

if bestVectorString == "" {
return
}

v.Severity = append(v.Severity, &osvschema.Severity{
Type: osvschema.Severity_Type(osvschema.Severity_Type_value[severityType]),
Score: bestVectorString,
Type: osvschema.Severity_Type(osvschema.Severity_Type_value[severityType]),
Score: bestVectorString,
Source: source,
})
}

// AddAllSeverities adds all the CVSS severity information from NVD to the OSV vulnerability object.
func (v *Vulnerability) AddAllSeverities(metricsData *models.CVEItemMetrics) {
if metricsData == nil {
return
}

addSeverity := func(severityType osvschema.Severity_Type, vectorString, source string) {
if vectorString == "" {
return
}
v.Severity = append(v.Severity, &osvschema.Severity{
Type: severityType,
Score: vectorString,
Source: source,
})
}

for _, metric := range metricsData.CVSSMetricV40 {
addSeverity(osvschema.Severity_CVSS_V4, metric.CVSSData.VectorString, metric.Source)
}
for _, metric := range metricsData.CVSSMetricV31 {
addSeverity(osvschema.Severity_CVSS_V3, metric.CVSSData.VectorString, metric.Source)
}
for _, metric := range metricsData.CVSSMetricV30 {
addSeverity(osvschema.Severity_CVSS_V3, metric.CVSSData.VectorString, metric.Source)
}
}

// ToJSON serializes the Vulnerability to JSON.
func (v *Vulnerability) ToJSON(w io.Writer) error {
unstableJSON, err := protojson.Marshal(v.Vulnerability)
Expand Down Expand Up @@ -717,7 +749,7 @@ func FromNVDCVE(id models.CVEID, cve models.NVDCVE) *Vulnerability {
References: ClassifyReferences(cve.References),
},
}
v.AddSeverity(cve.Metrics)
v.AddAllSeverities(cve.Metrics)

return v
}
Expand Down
26 changes: 22 additions & 4 deletions vulnfeeds/vulns/vulns_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -414,8 +414,9 @@ func TestAddSeverity(t *testing.T) {
inputCVE: loadTestData2("CVE-2022-34668"),
expectedResult: []*osvschema.Severity{
{
Type: osvschema.Severity_CVSS_V3,
Score: "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
Type: osvschema.Severity_CVSS_V3,
Score: "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
Source: "psirt@nvidia.com",
},
},
},
Expand All @@ -424,8 +425,25 @@ func TestAddSeverity(t *testing.T) {
inputCVE: loadTestData2("CVE-2023-5341"),
expectedResult: []*osvschema.Severity{
{
Type: osvschema.Severity_CVSS_V3,
Score: "CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H",
Type: osvschema.Severity_CVSS_V3,
Score: "CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H",
Source: "secalert@redhat.com",
},
},
},
{
description: "CVE with Primary and Secondary CVSS information",
inputCVE: loadTestData2("CVE-2022-36037"),
expectedResult: []*osvschema.Severity{
{
Type: osvschema.Severity_CVSS_V3,
Score: "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:N",
Source: "nvd@nist.gov",
},
{
Type: osvschema.Severity_CVSS_V3,
Score: "CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:L/A:N",
Source: "security-advisories@github.com",
},
},
},
Expand Down