Skip to content

Commit

Permalink
Deduplicate affected versions (#1133)
Browse files Browse the repository at this point in the history
This adds some preliminary test coverage to `ExtractVersionInfo` and
avoids adding duplicates to`AffectedVersion`, preventing duplicate
commit hashes getting added further downstream when they are mapped.

This highlights the potential need to look more holistically at the
nodes when extracting versions, because each one could be for a
completely different CPE...
  • Loading branch information
andrewpollock committed Mar 17, 2023
1 parent 363c720 commit fc10056
Show file tree
Hide file tree
Showing 3 changed files with 257 additions and 3 deletions.
9 changes: 7 additions & 2 deletions vulnfeeds/cves/versions.go
Expand Up @@ -435,11 +435,16 @@ func ExtractVersionInfo(cve CVEItem, validVersions []string) (v VersionInfo, not
}

gotVersions = true
v.AffectedVersions = append(v.AffectedVersions, AffectedVersion{
possibleNewAffectedVersion := AffectedVersion{
Introduced: introduced,
Fixed: fixed,
LastAffected: lastaffected,
})
}
if slices.Contains(v.AffectedVersions, possibleNewAffectedVersion) {
// Avoid appending duplicates
continue
}
v.AffectedVersions = append(v.AffectedVersions, possibleNewAffectedVersion)
}
}
if !gotVersions {
Expand Down
96 changes: 96 additions & 0 deletions vulnfeeds/cves/versions_test.go
@@ -1,10 +1,32 @@
package cves

import (
"encoding/json"
"log"
"os"
"reflect"
"testing"

"github.com/go-test/deep"
)

// Helper function to load in a specific CVE from sample data.
func loadTestData(CVEID string) CVEItem {
file, err := os.Open("../test_data/nvdcve-1.1-test-data.json")
if err != nil {
log.Fatalf("Failed to load test data")
}
var nvdCves NVDCVE
json.NewDecoder(file).Decode(&nvdCves)
for _, item := range nvdCves.CVEItems {
if item.CVE.CVEDataMeta.ID == CVEID {
return item
}
}
log.Fatalf("test data doesn't contain specified %q", CVEID)
return CVEItem{}
}

func TestParseCPE(t *testing.T) {
tests := []struct {
description string
Expand Down Expand Up @@ -452,3 +474,77 @@ func TestNormalizeVersion(t *testing.T) {
}
}
}

func TestExtractVersionInfo(t *testing.T) {
tests := []struct {
description string
inputCVEItem CVEItem
inputValidVersions []string
expectedVersionInfo VersionInfo
expectedNotes []string
}{
{
description: "A CVE with multiple affected versions",
inputCVEItem: loadTestData("CVE-2022-32746"),
inputValidVersions: []string{},
expectedVersionInfo: VersionInfo{
FixCommits: []GitCommit(nil),
LimitCommits: []GitCommit(nil),
LastAffectedCommits: []GitCommit(nil),
AffectedVersions: []AffectedVersion{
AffectedVersion{
Introduced: "4.16.0",
Fixed: "4.16.4",
LastAffected: "",
},
AffectedVersion{
Introduced: "4.15.0",
Fixed: "4.15.9",
LastAffected: "",
},
AffectedVersion{
Introduced: "4.3.0",
Fixed: "4.14.14",
LastAffected: "",
},
},
},
expectedNotes: []string{},
},
{
description: "A CVE with duplicate affected versions squashed",
inputCVEItem: loadTestData("CVE-2022-0090"),
inputValidVersions: []string{},
expectedVersionInfo: VersionInfo{
FixCommits: []GitCommit(nil),
LimitCommits: []GitCommit(nil),
LastAffectedCommits: []GitCommit(nil),
AffectedVersions: []AffectedVersion{
AffectedVersion{
Introduced: "14.6.0",
Fixed: "14.6.1",
LastAffected: "",
},
AffectedVersion{
Introduced: "14.5.0",
Fixed: "14.5.3",
LastAffected: "",
},
AffectedVersion{
Introduced: "",
Fixed: "14.4.5",
LastAffected: "",
},
},
},
expectedNotes: []string{},
},
}

for _, tc := range tests {
gotVersionInfo, _ := ExtractVersionInfo(tc.inputCVEItem, tc.inputValidVersions)
if diff := deep.Equal(gotVersionInfo, tc.expectedVersionInfo); diff != nil {
t.Errorf("test %q: VersionInfo for %#v was incorrect: %s", tc.description, tc.inputCVEItem, diff)
}
}
}
155 changes: 154 additions & 1 deletion vulnfeeds/test_data/nvdcve-1.1-test-data.json
Expand Up @@ -5,6 +5,159 @@
"CVE_data_numberOfCVEs" : "660",
"CVE_data_timestamp" : "2022-08-31T05:00Z",
"CVE_Items" : [
{
"cve": {
"data_type": "CVE",
"data_format": "MITRE",
"data_version": "4.0",
"CVE_data_meta": {
"ID": "CVE-2022-0090",
"ASSIGNER": "cve@gitlab.com"
},
"problemtype": {
"problemtype_data": [
{
"description": [
{
"lang": "en",
"value": "CWE-269"
}
]
}
]
},
"references": {
"reference_data": [
{
"url": "https://hackerone.com/reports/1415964",
"name": "https://hackerone.com/reports/1415964",
"refsource": "MISC",
"tags": [
"Permissions Required"
]
},
{
"url": "https://gitlab.com/gitlab-org/cves/-/blob/master/2022/CVE-2022-0090.json",
"name": "https://gitlab.com/gitlab-org/cves/-/blob/master/2022/CVE-2022-0090.json",
"refsource": "CONFIRM",
"tags": [
"Third Party Advisory"
]
},
{
"url": "https://gitlab.com/gitlab-org/gitaly/-/issues/3948",
"name": "https://gitlab.com/gitlab-org/gitaly/-/issues/3948",
"refsource": "MISC",
"tags": [
"Broken Link"
]
}
]
},
"description": {
"description_data": [
{
"lang": "en",
"value": "An issue has been discovered affecting GitLab versions prior to 14.4.5, between 14.5.0 and 14.5.3, and between 14.6.0 and 14.6.1. GitLab is configured in a way that it doesn't ignore replacement references with git sub-commands, allowing a malicious user to spoof the contents of their commits in the UI."
}
]
}
},
"configurations": {
"CVE_data_version": "4.0",
"nodes": [
{
"operator": "OR",
"children": [],
"cpe_match": [
{
"vulnerable": true,
"cpe23Uri": "cpe:2.3:a:gitlab:gitlab:*:*:*:*:community:*:*:*",
"versionStartIncluding": "14.6.0",
"versionEndExcluding": "14.6.1",
"cpe_name": []
},
{
"vulnerable": true,
"cpe23Uri": "cpe:2.3:a:gitlab:gitlab:*:*:*:*:enterprise:*:*:*",
"versionStartIncluding": "14.6.0",
"versionEndExcluding": "14.6.1",
"cpe_name": []
},
{
"vulnerable": true,
"cpe23Uri": "cpe:2.3:a:gitlab:gitlab:*:*:*:*:community:*:*:*",
"versionStartIncluding": "14.5.0",
"versionEndExcluding": "14.5.3",
"cpe_name": []
},
{
"vulnerable": true,
"cpe23Uri": "cpe:2.3:a:gitlab:gitlab:*:*:*:*:enterprise:*:*:*",
"versionStartIncluding": "14.5.0",
"versionEndExcluding": "14.5.3",
"cpe_name": []
},
{
"vulnerable": true,
"cpe23Uri": "cpe:2.3:a:gitlab:gitlab:*:*:*:*:community:*:*:*",
"versionEndExcluding": "14.4.5",
"cpe_name": []
},
{
"vulnerable": true,
"cpe23Uri": "cpe:2.3:a:gitlab:gitlab:*:*:*:*:enterprise:*:*:*",
"versionEndExcluding": "14.4.5",
"cpe_name": []
}
]
}
]
},
"impact": {
"baseMetricV3": {
"cvssV3": {
"version": "3.1",
"vectorString": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:N",
"attackVector": "NETWORK",
"attackComplexity": "LOW",
"privilegesRequired": "LOW",
"userInteraction": "NONE",
"scope": "UNCHANGED",
"confidentialityImpact": "NONE",
"integrityImpact": "HIGH",
"availabilityImpact": "NONE",
"baseScore": 6.5,
"baseSeverity": "MEDIUM"
},
"exploitabilityScore": 2.8,
"impactScore": 3.6
},
"baseMetricV2": {
"cvssV2": {
"version": "2.0",
"vectorString": "AV:N/AC:L/Au:N/C:N/I:P/A:N",
"accessVector": "NETWORK",
"accessComplexity": "LOW",
"authentication": "NONE",
"confidentialityImpact": "NONE",
"integrityImpact": "PARTIAL",
"availabilityImpact": "NONE",
"baseScore": 5
},
"severity": "MEDIUM",
"exploitabilityScore": 10,
"impactScore": 2.9,
"acInsufInfo": false,
"obtainAllPrivilege": false,
"obtainUserPrivilege": false,
"obtainOtherPrivilege": false,
"userInteractionRequired": false
}
},
"publishedDate": "2022-01-18T17:15Z",
"lastModifiedDate": "2022-01-25T14:49Z"
},
{
"cve" : {
"data_type" : "CVE",
Expand Down Expand Up @@ -41183,4 +41336,4 @@
"publishedDate" : "2022-08-23T04:15Z",
"lastModifiedDate" : "2022-08-24T14:26Z"
} ]
}
}

0 comments on commit fc10056

Please sign in to comment.