mirror of
https://github.com/fleetdm/fleet
synced 2026-05-23 08:58:41 +00:00
Include known_vulnerability field when query is a CVE. (#21363)
Update to #19857 after customer feedback. If the search query is in CVE format (CVE-YYYY-<4+digits>), we always return if that exact match is a CVE known to Fleet. # Checklist for submitter - [x] Added/updated tests - [x] Manual QA for all new/changed functionality
This commit is contained in:
parent
1fef99af47
commit
84ee756b1b
2 changed files with 48 additions and 19 deletions
|
|
@ -8661,7 +8661,7 @@ func (s *integrationTestSuite) TestListVulnerabilities() {
|
|||
|
||||
_, err = s.ds.InsertOSVulnerability(context.Background(), fleet.OSVulnerability{
|
||||
OSID: os.ID,
|
||||
CVE: "CVE-2021-1234",
|
||||
CVE: "CVE-2021-12345",
|
||||
ResolvedInVersion: *ptr.StringPtr("10.0.19043.2013"),
|
||||
}, fleet.MSRCSource)
|
||||
require.NoError(t, err)
|
||||
|
|
@ -8718,17 +8718,17 @@ func (s *integrationTestSuite) TestListVulnerabilities() {
|
|||
require.NoError(t, err)
|
||||
|
||||
// insert CVEMeta
|
||||
knownCVEWoPrefix := "2021-1299"
|
||||
knownCVEWoPrefix := "2021-12999"
|
||||
knownCVE := "cve-" + knownCVEWoPrefix
|
||||
mockTime := time.Date(2021, 1, 1, 0, 0, 0, 0, time.UTC)
|
||||
err = s.ds.InsertCVEMeta(context.Background(), []fleet.CVEMeta{
|
||||
{
|
||||
CVE: "CVE-2021-1234",
|
||||
CVE: "CVE-2021-12345",
|
||||
CVSSScore: ptr.Float64(7.5),
|
||||
EPSSProbability: ptr.Float64(0.5),
|
||||
CISAKnownExploit: ptr.Bool(true),
|
||||
Published: ptr.Time(mockTime),
|
||||
Description: "Test CVE 2021-1234",
|
||||
Description: "Test CVE 2021-12345",
|
||||
},
|
||||
{
|
||||
CVE: "CVE-2021-1235",
|
||||
|
|
@ -8775,9 +8775,9 @@ func (s *integrationTestSuite) TestListVulnerabilities() {
|
|||
DetailsLink string
|
||||
Source fleet.VulnerabilitySource
|
||||
}{
|
||||
"CVE-2021-1234": {
|
||||
"CVE-2021-12345": {
|
||||
HostCount: 1,
|
||||
DetailsLink: "https://nvd.nist.gov/vuln/detail/CVE-2021-1234",
|
||||
DetailsLink: "https://nvd.nist.gov/vuln/detail/CVE-2021-12345",
|
||||
},
|
||||
"CVE-2021-1235": {
|
||||
HostCount: 1,
|
||||
|
|
@ -8791,7 +8791,7 @@ func (s *integrationTestSuite) TestListVulnerabilities() {
|
|||
|
||||
for _, vuln := range resp.Vulnerabilities {
|
||||
expectedVuln, ok := expected[vuln.CVE.CVE]
|
||||
require.True(t, ok)
|
||||
require.True(t, ok, vuln.CVE.CVE)
|
||||
require.Equal(t, expectedVuln.HostCount, vuln.HostsCount)
|
||||
require.Equal(t, expectedVuln.DetailsLink, vuln.DetailsLink)
|
||||
require.Empty(t, vuln.CVSSScore)
|
||||
|
|
@ -8813,9 +8813,9 @@ func (s *integrationTestSuite) TestListVulnerabilities() {
|
|||
DetailsLink string
|
||||
Source fleet.VulnerabilitySource
|
||||
}{
|
||||
"CVE-2021-1234": {
|
||||
"CVE-2021-12345": {
|
||||
HostCount: 1,
|
||||
DetailsLink: "https://nvd.nist.gov/vuln/detail/CVE-2021-1234",
|
||||
DetailsLink: "https://nvd.nist.gov/vuln/detail/CVE-2021-12345",
|
||||
},
|
||||
"CVE-2021-1235": {
|
||||
HostCount: 1,
|
||||
|
|
@ -8859,6 +8859,24 @@ func (s *integrationTestSuite) TestListVulnerabilities() {
|
|||
assert.False(t, resp.Meta.HasNextResults)
|
||||
assert.Equal(t, ptr.Bool(true), resp.KnownVulnerability)
|
||||
|
||||
// test with a substring of a known CVE -- results are returned but the exact match is not known to Fleet
|
||||
s.DoJSON("GET", "/api/latest/fleet/vulnerabilities", nil, http.StatusOK, &resp, "query", "CVE-2021-1234")
|
||||
require.Empty(t, resp.Err)
|
||||
assert.Len(s.T(), resp.Vulnerabilities, 1)
|
||||
assert.Equal(t, resp.Count, uint(1))
|
||||
assert.False(t, resp.Meta.HasPreviousResults)
|
||||
assert.False(t, resp.Meta.HasNextResults)
|
||||
assert.Equal(t, ptr.Bool(false), resp.KnownVulnerability)
|
||||
|
||||
// test with exact match of a known CVE -- results are returned and CVE is known to Fleet
|
||||
s.DoJSON("GET", "/api/latest/fleet/vulnerabilities", nil, http.StatusOK, &resp, "query", "2021-12345")
|
||||
require.Empty(t, resp.Err)
|
||||
assert.Len(s.T(), resp.Vulnerabilities, 1)
|
||||
assert.Equal(t, resp.Count, uint(1))
|
||||
assert.False(t, resp.Meta.HasPreviousResults)
|
||||
assert.False(t, resp.Meta.HasNextResults)
|
||||
assert.Equal(t, ptr.Bool(true), resp.KnownVulnerability)
|
||||
|
||||
// test with a unknown CVE that does not match on software/OS
|
||||
s.DoJSON("GET", "/api/latest/fleet/vulnerabilities", nil, http.StatusOK, &resp, "query", knownCVE+"1")
|
||||
require.Empty(t, resp.Err)
|
||||
|
|
@ -8924,17 +8942,17 @@ func (s *integrationTestSuite) TestListVulnerabilities() {
|
|||
s.DoJSON("GET", "/api/latest/fleet/vulnerabilities/CVE-2021-1246", nil, http.StatusOK, &gResp, "team_id", "0")
|
||||
|
||||
// Valid CVD not in "no team" scope
|
||||
s.DoJSON("GET", "/api/latest/fleet/vulnerabilities/CVE-2021-1234", nil, http.StatusNotFound, &gResp, "team_id", "0")
|
||||
s.DoJSON("GET", "/api/latest/fleet/vulnerabilities/CVE-2021-12345", nil, http.StatusNotFound, &gResp, "team_id", "0")
|
||||
|
||||
// Invalid TeamID
|
||||
s.DoJSON("GET", "/api/latest/fleet/vulnerabilities/CVE-2021-1234", nil, http.StatusForbidden, &gResp, "team_id", "100")
|
||||
s.DoJSON("GET", "/api/latest/fleet/vulnerabilities/CVE-2021-12345", nil, http.StatusForbidden, &gResp, "team_id", "100")
|
||||
|
||||
// Valid Global Request
|
||||
s.DoJSON("GET", "/api/latest/fleet/vulnerabilities/CVE-2021-1234", nil, http.StatusOK, &gResp)
|
||||
s.DoJSON("GET", "/api/latest/fleet/vulnerabilities/CVE-2021-12345", nil, http.StatusOK, &gResp)
|
||||
require.Empty(t, gResp.Err)
|
||||
require.Equal(t, "CVE-2021-1234", gResp.Vulnerability.CVE.CVE)
|
||||
require.Equal(t, "CVE-2021-12345", gResp.Vulnerability.CVE.CVE)
|
||||
require.Equal(t, uint(1), gResp.Vulnerability.HostsCount)
|
||||
require.Equal(t, "https://nvd.nist.gov/vuln/detail/CVE-2021-1234", gResp.Vulnerability.DetailsLink)
|
||||
require.Equal(t, "https://nvd.nist.gov/vuln/detail/CVE-2021-12345", gResp.Vulnerability.DetailsLink)
|
||||
require.Empty(t, gResp.Vulnerability.Description)
|
||||
require.Empty(t, gResp.Vulnerability.CVSSScore)
|
||||
require.Empty(t, gResp.Vulnerability.CISAKnownExploit)
|
||||
|
|
|
|||
|
|
@ -55,9 +55,9 @@ func listVulnerabilitiesEndpoint(ctx context.Context, req interface{}, svc fleet
|
|||
}
|
||||
}
|
||||
|
||||
// Check whether the query was for a vulnerability known to fleet
|
||||
var knownVulnerability *bool
|
||||
if len(vulns) == 0 && len(request.ListOptions.MatchQuery) > 0 {
|
||||
// If no vulnerabilities are returned, we need to check if the query was for a vulnerability known to fleet
|
||||
if len(request.ListOptions.MatchQuery) > 0 {
|
||||
query := request.ListOptions.MatchQuery
|
||||
matches := cveRegex.FindStringSubmatch(query)
|
||||
if matches != nil {
|
||||
|
|
@ -66,9 +66,20 @@ func listVulnerabilitiesEndpoint(ctx context.Context, req interface{}, svc fleet
|
|||
// If CVE prefix was missing, we add it
|
||||
query = cvePrefix + query
|
||||
}
|
||||
known, err := svc.IsCVEKnownToFleet(ctx, query)
|
||||
if err != nil {
|
||||
return listVulnerabilitiesResponse{Err: err}, nil
|
||||
// As an optimization, we first check if the CVE was one of the ones returned
|
||||
// by the query. If it was, we already know it's known to Fleet.
|
||||
var known bool
|
||||
for _, vuln := range vulns {
|
||||
if vuln.CVE.CVE == query {
|
||||
known = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !known {
|
||||
known, err = svc.IsCVEKnownToFleet(ctx, query)
|
||||
if err != nil {
|
||||
return listVulnerabilitiesResponse{Err: err}, nil
|
||||
}
|
||||
}
|
||||
knownVulnerability = &known
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue