mirror of
https://github.com/fleetdm/fleet
synced 2026-05-24 09:28:54 +00:00
**Related issue:** Resolves #35194 The NVD database for CVE-2023-28205 contains two broad CPE match rules: Safari: Any version < 16.4.1 is vulnerable macOS: Any version < 13.3.1 is vulnerable The problem is Safari versions 13.x, 14.x, and 15.x were never actually vulnerable to this CVE and macOS versions 10.x, 11.x, and 12.x never received a system-level fix for this CVE. Apple fixed the cve in two ways 1. Safari 16.4.1 standalone update 2. macOS Ventura 13.3.1 system update fix at the OS level This is why there is such a complicated `IgnoreIf` for the `CPEMatchingRule`. If some of the following don't apply, delete the relevant line. - [x] Changes file added for user-visible changes in `changes/`, `orbit/changes/` or `ee/fleetd-chrome/changes`. See [Changes files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/guides/committing-changes.md#changes-files) for more information. ## Testing - [x] Added/updated automated tests - [ ] QA'd all new/changed functionality manually <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit ## Release Notes * **Bug Fixes** * Improved accuracy of Safari CVE-2023-28205 vulnerability detection with version-specific filtering for Safari 16.0-16.4.0 and macOS Ventura. * **Tests** * Added comprehensive test coverage for CVE-2023-28205 across multiple Safari versions and macOS releases. <sub>✏️ Tip: You can customize this high-level summary in your review settings.</sub> <!-- end of auto-generated comment: release notes by coderabbit.ai -->
1326 lines
40 KiB
Go
1326 lines
40 KiB
Go
package nvd
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"os"
|
|
"strings"
|
|
"sync"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/fleetdm/fleet/v4/pkg/nettest"
|
|
"github.com/fleetdm/fleet/v4/server/fleet"
|
|
"github.com/fleetdm/fleet/v4/server/mock"
|
|
"github.com/fleetdm/fleet/v4/server/vulnerabilities/nvd/tools/cvefeed"
|
|
"github.com/fleetdm/fleet/v4/server/vulnerabilities/nvd/tools/wfn"
|
|
"github.com/go-kit/log"
|
|
kitlog "github.com/go-kit/log"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
// firefox93WindowsVulnerabilities was manually generated by visiting:
|
|
// https://nvd.nist.gov/vuln/search/results?form_type=Advanced&results_type=overview&isCpeNameSearch=true&seach_type=all&query=cpe:2.3:a:mozilla:firefox:93.0:*:*:*:*:*:*:*
|
|
type cve struct {
|
|
ID string
|
|
resolvedInVersion string
|
|
}
|
|
|
|
var firefox93WindowsVulnerabilities = []cve{
|
|
{ID: "CVE-2021-43540", resolvedInVersion: "95.0"},
|
|
{ID: "CVE-2021-38503", resolvedInVersion: "94.0"},
|
|
{ID: "CVE-2021-38504", resolvedInVersion: "94.0"},
|
|
{ID: "CVE-2021-38506", resolvedInVersion: "94.0"},
|
|
{ID: "CVE-2021-38507", resolvedInVersion: "94.0"},
|
|
{ID: "CVE-2021-38508", resolvedInVersion: "94.0"},
|
|
{ID: "CVE-2021-38509", resolvedInVersion: "94.0"},
|
|
{ID: "CVE-2021-43534", resolvedInVersion: "94.0"},
|
|
{ID: "CVE-2021-43532", resolvedInVersion: "94.0"},
|
|
{ID: "CVE-2021-43531", resolvedInVersion: "94.0"},
|
|
{ID: "CVE-2021-43533", resolvedInVersion: "94.0"},
|
|
{ID: "CVE-2021-43538", resolvedInVersion: "95.0"},
|
|
{ID: "CVE-2021-43542", resolvedInVersion: "95.0"},
|
|
{ID: "CVE-2021-43543", resolvedInVersion: "95.0"},
|
|
{ID: "CVE-2021-30547"},
|
|
{ID: "CVE-2021-43546", resolvedInVersion: "95.0"},
|
|
{ID: "CVE-2021-43537", resolvedInVersion: "95.0"},
|
|
{ID: "CVE-2021-43541", resolvedInVersion: "95.0"},
|
|
{ID: "CVE-2021-43536", resolvedInVersion: "95.0"},
|
|
{ID: "CVE-2021-43545", resolvedInVersion: "95.0"},
|
|
{ID: "CVE-2021-43539", resolvedInVersion: "95.0"},
|
|
{ID: "CVE-2022-34480", resolvedInVersion: "102.0"},
|
|
{ID: "CVE-2022-26387", resolvedInVersion: "98.0"},
|
|
{ID: "CVE-2022-22759", resolvedInVersion: "97.0"},
|
|
{ID: "CVE-2022-28281", resolvedInVersion: "99.0"},
|
|
{ID: "CVE-2022-45415", resolvedInVersion: "107.0"},
|
|
{ID: "CVE-2022-42930", resolvedInVersion: "106.0"},
|
|
{ID: "CVE-2022-0511", resolvedInVersion: "97.0"},
|
|
{ID: "CVE-2022-22763", resolvedInVersion: "96.0"},
|
|
{ID: "CVE-2022-22737", resolvedInVersion: "96.0"},
|
|
{ID: "CVE-2022-22751", resolvedInVersion: "96.0"},
|
|
{ID: "CVE-2022-38478", resolvedInVersion: "104.0"},
|
|
{ID: "CVE-2022-22761", resolvedInVersion: "97.0"},
|
|
{ID: "CVE-2022-34482", resolvedInVersion: "102.0"},
|
|
{ID: "CVE-2022-26486", resolvedInVersion: "97.0.2"},
|
|
{ID: "CVE-2022-22739", resolvedInVersion: "96.0"},
|
|
{ID: "CVE-2022-22755", resolvedInVersion: "97.0"},
|
|
{ID: "CVE-2022-22757", resolvedInVersion: "97.0"},
|
|
{ID: "CVE-2022-1097", resolvedInVersion: "99.0"},
|
|
{ID: "CVE-2022-22754", resolvedInVersion: "97.0"},
|
|
{ID: "CVE-2022-22748", resolvedInVersion: "96.0"},
|
|
{ID: "CVE-2022-22736", resolvedInVersion: "96.0"},
|
|
{ID: "CVE-2022-22745", resolvedInVersion: "96.0"},
|
|
{ID: "CVE-2022-26385", resolvedInVersion: "98.0"},
|
|
{ID: "CVE-2022-26383", resolvedInVersion: "98.0"},
|
|
{ID: "CVE-2022-3266", resolvedInVersion: "105.0"},
|
|
{ID: "CVE-2022-34468", resolvedInVersion: "102.0"},
|
|
{ID: "CVE-2022-34481", resolvedInVersion: "102.0"},
|
|
{ID: "CVE-2022-28289", resolvedInVersion: "99.0"},
|
|
{ID: "CVE-2022-22741", resolvedInVersion: "96.0"},
|
|
{ID: "CVE-2022-28284", resolvedInVersion: "99.0"},
|
|
{ID: "CVE-2022-34484", resolvedInVersion: "102.0"},
|
|
{ID: "CVE-2022-22752", resolvedInVersion: "96.0"},
|
|
{ID: "CVE-2022-26485", resolvedInVersion: "97.0.2"},
|
|
{ID: "CVE-2022-28286", resolvedInVersion: "99.0"},
|
|
{ID: "CVE-2022-28283", resolvedInVersion: "99.0"},
|
|
{ID: "CVE-2022-28285", resolvedInVersion: "99.0"},
|
|
{ID: "CVE-2022-0843", resolvedInVersion: "97.0"},
|
|
{ID: "CVE-2022-29909", resolvedInVersion: "100.0"},
|
|
{ID: "CVE-2022-22749", resolvedInVersion: "96.0"},
|
|
{ID: "CVE-2022-26384", resolvedInVersion: "98.0"},
|
|
{ID: "CVE-2022-28282", resolvedInVersion: "99.0"},
|
|
{ID: "CVE-2022-28287", resolvedInVersion: "99.0"},
|
|
{ID: "CVE-2022-40956", resolvedInVersion: "105.0"},
|
|
{ID: "CVE-2022-22740", resolvedInVersion: "96.0"},
|
|
{ID: "CVE-2022-22743", resolvedInVersion: "96.0"},
|
|
{ID: "CVE-2022-22764", resolvedInVersion: "97.0"},
|
|
{ID: "CVE-2022-22738", resolvedInVersion: "96.0"},
|
|
{ID: "CVE-2022-1529", resolvedInVersion: "100.0.2"},
|
|
{ID: "CVE-2022-22760", resolvedInVersion: "97.0"},
|
|
{ID: "CVE-2022-29916", resolvedInVersion: "100.0"},
|
|
{ID: "CVE-2022-29917", resolvedInVersion: "100.0"},
|
|
{ID: "CVE-2022-22747", resolvedInVersion: "96.0"},
|
|
{ID: "CVE-2022-26382", resolvedInVersion: "98.0"},
|
|
{ID: "CVE-2022-22742", resolvedInVersion: "96.0"},
|
|
{ID: "CVE-2022-28288", resolvedInVersion: "99.0"},
|
|
{ID: "CVE-2022-22756", resolvedInVersion: "97.0"},
|
|
{ID: "CVE-2022-26381", resolvedInVersion: "98.0"},
|
|
{ID: "CVE-2022-1802", resolvedInVersion: "100.0.2"},
|
|
{ID: "CVE-2022-34483", resolvedInVersion: "102.0"},
|
|
{ID: "CVE-2022-29915", resolvedInVersion: "100.0"},
|
|
}
|
|
|
|
type threadSafeDSMock struct {
|
|
mu sync.Mutex
|
|
*mock.Store
|
|
}
|
|
|
|
func (d *threadSafeDSMock) ListSoftwareCPEs(ctx context.Context) ([]fleet.SoftwareCPE, error) {
|
|
d.mu.Lock()
|
|
defer d.mu.Unlock()
|
|
return d.Store.ListSoftwareCPEs(ctx)
|
|
}
|
|
|
|
func (d *threadSafeDSMock) InsertSoftwareVulnerability(ctx context.Context, vuln fleet.SoftwareVulnerability, src fleet.VulnerabilitySource) (bool, error) {
|
|
d.mu.Lock()
|
|
defer d.mu.Unlock()
|
|
return d.Store.InsertSoftwareVulnerability(ctx, vuln, src)
|
|
}
|
|
|
|
func TestTranslateCPEToCVE(t *testing.T) {
|
|
t.Parallel()
|
|
ctx := context.Background()
|
|
|
|
// NVD_TEST_VULNDB_DIR can be used to speed up development (sync vulnerability data only once).
|
|
tempDir := os.Getenv("NVD_TEST_VULNDB_DIR")
|
|
if tempDir == "" {
|
|
// download the CVEs once for all sub-tests, and then disable syncing
|
|
tempDir = t.TempDir()
|
|
err := nettest.RunWithNetRetry(t, func() error {
|
|
return DownloadCVEFeed(tempDir, "", false, log.NewNopLogger())
|
|
})
|
|
require.NoError(t, err)
|
|
} else {
|
|
require.DirExists(t, tempDir)
|
|
t.Logf("Using %s as database path", tempDir)
|
|
}
|
|
|
|
cveTests := map[string]struct {
|
|
cpe string
|
|
excludedCVEs []string
|
|
includedCVEs []cve
|
|
// continuesToUpdate indicates if the product/software
|
|
// continues to register new CVE vulnerabilities.
|
|
continuesToUpdate bool
|
|
}{
|
|
"cpe:2.3:a:1password:1password:3.9.9:*:*:*:*:macos:*:*": {
|
|
includedCVEs: []cve{
|
|
{ID: "CVE-2012-6369"},
|
|
},
|
|
continuesToUpdate: false,
|
|
},
|
|
"cpe:2.3:a:1password:1password:3.9.9:*:*:*:*:*:*:*": {
|
|
includedCVEs: []cve{
|
|
{ID: "CVE-2012-6369"},
|
|
},
|
|
continuesToUpdate: false,
|
|
},
|
|
"cpe:2.3:a:pypa:pip:9.0.3:*:*:*:*:python:*:*": {
|
|
includedCVEs: []cve{
|
|
{ID: "CVE-2019-20916", resolvedInVersion: "19.2"},
|
|
{ID: "CVE-2021-3572", resolvedInVersion: "21.1"},
|
|
{ID: "CVE-2025-8869", resolvedInVersion: "25.3"},
|
|
{ID: "CVE-2023-5752", resolvedInVersion: "23.3"},
|
|
},
|
|
continuesToUpdate: false,
|
|
},
|
|
"cpe:2.3:a:mozilla:firefox:93.0:*:*:*:*:windows:*:*": {
|
|
includedCVEs: firefox93WindowsVulnerabilities,
|
|
continuesToUpdate: true,
|
|
},
|
|
"cpe:2.3:a:mozilla:firefox:93.0.100:*:*:*:*:windows:*:*": {
|
|
includedCVEs: firefox93WindowsVulnerabilities,
|
|
continuesToUpdate: true,
|
|
},
|
|
"cpe:2.3:a:apple:icloud:1.0:*:*:*:*:macos:*:*": {
|
|
excludedCVEs: []string{
|
|
"CVE-2017-13797",
|
|
"CVE-2017-2383",
|
|
"CVE-2017-2366",
|
|
"CVE-2016-4613",
|
|
"CVE-2016-4692",
|
|
"CVE-2016-4743",
|
|
"CVE-2016-7578",
|
|
"CVE-2016-7583",
|
|
"CVE-2016-7586",
|
|
"CVE-2016-7587",
|
|
"CVE-2016-7589",
|
|
"CVE-2016-7592",
|
|
"CVE-2016-7598",
|
|
"CVE-2016-7599",
|
|
"CVE-2016-7610",
|
|
"CVE-2016-7611",
|
|
"CVE-2016-7614",
|
|
"CVE-2016-7632",
|
|
"CVE-2016-7635",
|
|
"CVE-2016-7639",
|
|
"CVE-2016-7640",
|
|
"CVE-2016-7641",
|
|
"CVE-2016-7642",
|
|
"CVE-2016-7645",
|
|
"CVE-2016-7646",
|
|
"CVE-2016-7648",
|
|
"CVE-2016-7649",
|
|
"CVE-2016-7652",
|
|
"CVE-2016-7654",
|
|
"CVE-2016-7656",
|
|
"CVE-2017-2383",
|
|
},
|
|
continuesToUpdate: true,
|
|
},
|
|
"cpe:2.3:a:clickstudios:passwordstate:9.5.8.4:*:*:*:*:chrome:*:*": {
|
|
includedCVEs: []cve{
|
|
{ID: "CVE-2022-4610", resolvedInVersion: ""},
|
|
{ID: "CVE-2022-4611", resolvedInVersion: ""},
|
|
{ID: "CVE-2022-4613", resolvedInVersion: ""},
|
|
{ID: "CVE-2022-4612", resolvedInVersion: ""},
|
|
},
|
|
continuesToUpdate: true,
|
|
},
|
|
"cpe:2.3:a:apple:garageband:10.4.11:*:*:*:*:macos:*:*": {
|
|
excludedCVEs: []string{"CVE-2024-54559"},
|
|
continuesToUpdate: true,
|
|
},
|
|
"cpe:2.3:o:apple:macos:15.1.1:*:*:*:*:*:*:*": {
|
|
includedCVEs: []cve{{ID: "CVE-2024-54559", resolvedInVersion: "15.2"}},
|
|
continuesToUpdate: true,
|
|
},
|
|
"cpe:2.3:a:avira:password_manager:2.18.4.38471:*:*:*:*:firefox:*:*": {
|
|
includedCVEs: []cve{
|
|
{ID: "CVE-2022-28795"},
|
|
},
|
|
continuesToUpdate: true,
|
|
},
|
|
"cpe:2.3:a:zoom:zoom:5.0.4301.0407:*:*:*:*:chrome:*:*": {
|
|
excludedCVEs: []string{"CVE-2021-28133"}, // CVE-2021-28133 is a vulnerability in the Zoom application, not the extension.
|
|
continuesToUpdate: true,
|
|
},
|
|
"cpe:2.3:a:bitwarden:bitwarden:1.55.0:*:*:*:*:firefox:*:*": {
|
|
excludedCVEs: []string{"CVE-2023-38840"}, // CVE-2023-38840 is a vulnerability in the Bitwarden application, not the extension.
|
|
continuesToUpdate: true,
|
|
},
|
|
// No Version Start
|
|
"cpe:2.3:a:python:setuptools:64:*:*:*:*:*:*:*": {
|
|
includedCVEs: []cve{
|
|
{ID: "CVE-2022-40897", resolvedInVersion: "65.5.1"},
|
|
},
|
|
continuesToUpdate: true,
|
|
},
|
|
"cpe:2.3:a:mozilla:firefox:93.0.100:*:*:*:*:*:*:*": {
|
|
includedCVEs: []cve{
|
|
// CVE matches multiple products
|
|
{ID: "CVE-2022-40956", resolvedInVersion: "105.0"},
|
|
},
|
|
continuesToUpdate: true,
|
|
},
|
|
// Multiple product matches with different version ranges
|
|
"cpe:2.3:o:apple:macos:14.1:*:*:*:*:*:*:*": {
|
|
includedCVEs: []cve{
|
|
{ID: "CVE-2023-42919", resolvedInVersion: "14.2"},
|
|
},
|
|
continuesToUpdate: true,
|
|
},
|
|
"cpe:2.3:a:microsoft:windows_subsystem_for_linux:0.63.10:*:*:*:*:visual_studio_code:*:*": {
|
|
includedCVEs: []cve{
|
|
{ID: "CVE-2021-43907", resolvedInVersion: "0.63.11"},
|
|
},
|
|
continuesToUpdate: false,
|
|
},
|
|
"cpe:2.3:a:github:pull_requests_and_issues:0.66.1:*:*:*:*:visual_studio_code:*:*": {
|
|
includedCVEs: []cve{
|
|
{ID: "CVE-2023-36867", resolvedInVersion: "0.66.2"},
|
|
},
|
|
continuesToUpdate: false,
|
|
},
|
|
/*"cpe:2.3:a:microsoft:python_extension:2020.9.1:*:*:*:*:visual_studio_code:*:*": {
|
|
includedCVEs: []cve{
|
|
{ID: "CVE-2020-17163", resolvedInVersion: "2020.9.2"},
|
|
{ID: "CVE-2024-49050", resolvedInVersion: "2024.18.2"},
|
|
},
|
|
continuesToUpdate: false,
|
|
},*/
|
|
"cpe:2.3:a:microsoft:jupyter:2023.10.10:*:*:*:*:visual_studio_code:*:*": {
|
|
includedCVEs: []cve{
|
|
{ID: "CVE-2023-36018", resolvedInVersion: "2023.10.1100000000"},
|
|
},
|
|
continuesToUpdate: false,
|
|
},
|
|
"cpe:2.3:a:microsoft:jupyter:2024.2.0:*:*:*:*:visual_studio_code:*:*": {
|
|
includedCVEs: []cve{},
|
|
continuesToUpdate: false,
|
|
},
|
|
"cpe:2.3:a:microsoft:eslint:2.0.0:*:*:*:*:visual_studio_code:*:*": {
|
|
includedCVEs: []cve{
|
|
{ID: "CVE-2020-1481", resolvedInVersion: "2.1.7"},
|
|
},
|
|
continuesToUpdate: false,
|
|
},
|
|
/*"cpe:2.3:a:microsoft:python_extension:2020.4.0:*:*:*:*:visual_studio_code:*:*": {
|
|
includedCVEs: []cve{
|
|
{ID: "CVE-2020-1171", resolvedInVersion: "2020.5.0"},
|
|
{ID: "CVE-2020-1192", resolvedInVersion: "2020.5.0"},
|
|
{ID: "CVE-2020-17163", resolvedInVersion: "2020.9.2"},
|
|
{ID: "CVE-2024-49050", resolvedInVersion: "2024.18.2"},
|
|
},
|
|
continuesToUpdate: false,
|
|
},*/
|
|
// #34323
|
|
"cpe:2.3:a:valvesoftware:dota_2:1.0:*:*:*:*:macos:*:*": {
|
|
excludedCVEs: []string{
|
|
"CVE-2020-7949",
|
|
"CVE-2020-7950",
|
|
"CVE-2020-7951",
|
|
"CVE-2020-7952",
|
|
"CVE-2020-9005",
|
|
},
|
|
},
|
|
"cpe:2.3:a:valvesoftware:dota_2:1.0.0:*:*:*:*:macos:*:*": {
|
|
excludedCVEs: []string{
|
|
"CVE-2020-7949",
|
|
"CVE-2020-7950",
|
|
"CVE-2020-7951",
|
|
"CVE-2020-7952",
|
|
"CVE-2020-9005",
|
|
},
|
|
},
|
|
"cpe:2.3:a:valvesoftware:dota_2:1.337:*:*:*:*:macos:*:*": {
|
|
includedCVEs: []cve{
|
|
{ID: "CVE-2020-9005" /*resolvedInVersion: "2020-02-17"*/}, // we don't do non-semver resolved-in
|
|
{ID: "CVE-2020-7950", resolvedInVersion: "7.23f"},
|
|
},
|
|
continuesToUpdate: true,
|
|
},
|
|
// end of #34323
|
|
"cpe:2.3:a:adobe:animate:*:*:*:*:*:macos:*:*": {
|
|
includedCVEs: []cve{
|
|
{ID: "CVE-2023-44325"},
|
|
},
|
|
continuesToUpdate: true,
|
|
},
|
|
"cpe:2.3:a:apple:safari:17.0:*:*:*:*:macos:*:*": {
|
|
includedCVEs: []cve{
|
|
{ID: "CVE-2023-42852", resolvedInVersion: "17.1"},
|
|
{ID: "CVE-2023-42950", resolvedInVersion: "17.2"},
|
|
{ID: "CVE-2024-23273", resolvedInVersion: "17.4"},
|
|
},
|
|
excludedCVEs: []string{
|
|
"CVE-2023-28205", // This vulnerability is for Safari 16.4.0
|
|
"CVE-2024-23252", // Rejected CVE
|
|
},
|
|
continuesToUpdate: true,
|
|
},
|
|
"cpe:2.3:a:apple:safari:16.4.0:*:*:*:*:macos:*:*": {
|
|
includedCVEs: []cve{
|
|
{ID: "CVE-2023-28205", resolvedInVersion: "16.4.1"},
|
|
},
|
|
continuesToUpdate: true,
|
|
},
|
|
"cpe:2.3:a:apple:safari:16.2:*:*:*:*:macos:*:*": {
|
|
includedCVEs: []cve{
|
|
{ID: "CVE-2023-28205", resolvedInVersion: "16.4.1"},
|
|
},
|
|
continuesToUpdate: true,
|
|
},
|
|
"cpe:2.3:a:apple:safari:16.4.1:*:*:*:*:macos:*:*": {
|
|
excludedCVEs: []string{
|
|
"CVE-2023-28205",
|
|
},
|
|
continuesToUpdate: true,
|
|
},
|
|
"cpe:2.3:a:apple:safari:16.5:*:*:*:*:macos:*:*": {
|
|
excludedCVEs: []string{
|
|
"CVE-2023-28205",
|
|
},
|
|
continuesToUpdate: true,
|
|
},
|
|
"cpe:2.3:a:apple:safari:16.6:*:*:*:*:macos:*:*": {
|
|
excludedCVEs: []string{
|
|
"CVE-2023-28205",
|
|
},
|
|
continuesToUpdate: true,
|
|
},
|
|
"cpe:2.3:a:apple:safari:15.6.1:*:*:*:*:macos:*:*": {
|
|
excludedCVEs: []string{
|
|
"CVE-2023-28205",
|
|
},
|
|
continuesToUpdate: true,
|
|
},
|
|
"cpe:2.3:a:apple:safari:14.1.2:*:*:*:*:macos:*:*": {
|
|
excludedCVEs: []string{
|
|
"CVE-2023-28205",
|
|
},
|
|
continuesToUpdate: true,
|
|
},
|
|
"cpe:2.3:a:apple:safari:13.1.3:*:*:*:*:macos:*:*": {
|
|
excludedCVEs: []string{
|
|
"CVE-2023-28205",
|
|
},
|
|
continuesToUpdate: true,
|
|
},
|
|
"cpe:2.3:a:microsoft:365_apps:16.0.17628.20144:*:*:*:*:windows:*:*": {
|
|
includedCVEs: []cve{
|
|
{ID: "CVE-2024-21402"},
|
|
},
|
|
excludedCVEs: []string{"CVE-2011-5049"}, // OS vulnerability
|
|
continuesToUpdate: true,
|
|
},
|
|
"cpe:2.3:a:citrix:workspace:2309.0:*:*:*:*:macos:*:*": {
|
|
excludedCVEs: []string{"CVE-2024-6286"},
|
|
continuesToUpdate: true,
|
|
},
|
|
// FIXME: https://github.com/fleetdm/fleet/issues/31303
|
|
// "cpe:2.3:a:citrix:workspace:2309.0:*:*:*:*:windows:*:*": {
|
|
// includedCVEs: []cve{
|
|
// {ID: "CVE-2024-6286", resolvedInVersion: "2402"},
|
|
// },
|
|
// continuesToUpdate: true,
|
|
// },
|
|
"cpe:2.3:a:python:python:3.9.6:*:*:*:*:macos:*:*": {
|
|
excludedCVEs: []string{"CVE-2024-4030"},
|
|
continuesToUpdate: true,
|
|
},
|
|
// Skipping test while troubleshooting https://github.com/fleetdm/fleet/issues/24286
|
|
//
|
|
// "cpe:2.3:a:python:python:3.9.6:*:*:*:*:windows:*:*": {
|
|
// includedCVEs: []cve{
|
|
// {ID: "CVE-2024-4030", resolvedInVersion: "3.9.20"},
|
|
// },
|
|
// continuesToUpdate: true,
|
|
// },
|
|
// Tests the expandCPEAliases rule for virtualbox on macOS
|
|
"cpe:2.3:a:oracle:virtualbox:7.0.6:*:*:*:*:macos:*:*": {
|
|
includedCVEs: []cve{
|
|
{ID: "CVE-2023-21989", resolvedInVersion: "7.0.8"},
|
|
{ID: "CVE-2024-21141", resolvedInVersion: "7.0.20"},
|
|
},
|
|
continuesToUpdate: true,
|
|
},
|
|
"cpe:2.3:a:mozilla:firefox:*:*:*:*:*:*:*:*": {
|
|
excludedCVEs: []string{"CVE-2024-10004"},
|
|
continuesToUpdate: true,
|
|
},
|
|
"cpe:2.3:a:okta:verify:9.27.0:*:*:*:*:macos:*:*": {
|
|
excludedCVEs: []string{"CVE-2024-10327"},
|
|
continuesToUpdate: true,
|
|
},
|
|
// CVE-2023-48795 false positive and true positive checks (see #26073)
|
|
"cpe:2.3:a:microsoft:powershell:7.4.3:*:*:*:*:*:*:*": {
|
|
excludedCVEs: []string{"CVE-2023-48795", "CVE-2025-21171"},
|
|
continuesToUpdate: true,
|
|
},
|
|
"cpe:2.3:a:openbsd:openssh:9.5:p1:*:*:*:*:*:*": {
|
|
includedCVEs: []cve{{ID: "CVE-2023-48795", resolvedInVersion: "9.6"}},
|
|
continuesToUpdate: true,
|
|
},
|
|
"cpe:2.3:a:openbsd:openssh:9.6:*:*:*:*:*:*": {
|
|
excludedCVEs: []string{"CVE-2023-48795"},
|
|
continuesToUpdate: true,
|
|
},
|
|
// end of CVE-2023-48795 checks
|
|
// CVE-2025-21171 handling
|
|
// https://github.com/fleetdm/fleet/pull/30767
|
|
// NVD lists this CVE for version 7.5 and not 7.5.0
|
|
"cpe:2.3:a:microsoft:powershell:7.5.0:*:*:*:*:macos:*:*": {
|
|
excludedCVEs: []string{"CVE-2025-21171"},
|
|
continuesToUpdate: true,
|
|
},
|
|
"cpe:2.3:a:microsoft:powershell:7.5.0:*:*:*:*:windows:*:*": {
|
|
excludedCVEs: []string{"CVE-2025-21171"},
|
|
includedCVEs: []cve{{ID: "CVE-2025-30399"}},
|
|
continuesToUpdate: true,
|
|
},
|
|
"cpe:2.3:a:microsoft:powershell:7.5.2:*:*:*:*:windows:*:*": {
|
|
excludedCVEs: []string{"CVE-2025-21171", "CVE-2025-30399"},
|
|
continuesToUpdate: true,
|
|
},
|
|
"cpe:2.3:a:microsoft:powershell:7.5:*:*:*:*:macos:*:*": {
|
|
includedCVEs: []cve{{ID: "CVE-2025-21171"}},
|
|
continuesToUpdate: true,
|
|
},
|
|
"cpe:2.3:a:microsoft:powershell:7.5:*:*:*:*:windows:*:*": {
|
|
includedCVEs: []cve{{ID: "CVE-2025-21171"}},
|
|
continuesToUpdate: true,
|
|
},
|
|
// end of CVE-2025-21171 checks
|
|
"cpe:2.3:a:jetbrains:goland:2022.3.99.123.456:*:*:*:*:macos:*:*": {
|
|
includedCVEs: []cve{{ID: "CVE-2024-37051", resolvedInVersion: "2023.1.6"}},
|
|
continuesToUpdate: true,
|
|
},
|
|
"cpe:2.3:a:jetbrains:goland:2024.3:*:*:*:*:macos:*:*": {
|
|
excludedCVEs: []string{"CVE-2024-37051"},
|
|
continuesToUpdate: true,
|
|
},
|
|
"cpe:2.3:a:iterm2:iterm2:3.5.1:*:*:*:*:*:*:*": {
|
|
includedCVEs: []cve{
|
|
{ID: "CVE-2024-38395", resolvedInVersion: "3.5.2"},
|
|
// NVD is being flakey so may not show this // {ID: "CVE-2024-38396", resolvedInVersion: "3.5.2"},
|
|
},
|
|
continuesToUpdate: true,
|
|
},
|
|
"cpe:2.3:a:simple_password_store_project:simple_password_store:1.7.0:*:*:*:*:macos:*:*": {
|
|
includedCVEs: []cve{{ID: "CVE-2018-12356", resolvedInVersion: "1.7.2"}},
|
|
},
|
|
"cpe:2.3:a:python:python:3.12.0:*:*:*:*:windows:*:*": {
|
|
excludedCVEs: []string{"CVE-2024-12254"},
|
|
continuesToUpdate: true,
|
|
},
|
|
"cpe:2.3:a:python:python:3.13.0:*:*:*:*:windows:*:*": {
|
|
excludedCVEs: []string{"CVE-2024-12254"},
|
|
continuesToUpdate: true,
|
|
},
|
|
"cpe:2.3:a:python:python:3.14.0:alpha1:*:*:*:windows:*:*": {
|
|
excludedCVEs: []string{"CVE-2024-12254"},
|
|
continuesToUpdate: true,
|
|
},
|
|
"cpe:2.3:a:python:python:3.14.0:alpha2:*:*:*:windows:*:*": {
|
|
excludedCVEs: []string{"CVE-2024-12254"},
|
|
continuesToUpdate: true,
|
|
},
|
|
"cpe:2.3:a:python:python:3.12.0:-:*:*:*:macos:*:*": {
|
|
includedCVEs: []cve{
|
|
{
|
|
ID: "CVE-2025-1795",
|
|
resolvedInVersion: "3.12.3",
|
|
},
|
|
{
|
|
ID: "CVE-2024-7592",
|
|
resolvedInVersion: "3.12.6",
|
|
},
|
|
{
|
|
ID: "CVE-2024-6923",
|
|
resolvedInVersion: "3.12.5",
|
|
},
|
|
{
|
|
ID: "CVE-2024-0397",
|
|
resolvedInVersion: "3.12.3",
|
|
},
|
|
{
|
|
ID: "CVE-2024-12254",
|
|
resolvedInVersion: "3.12.9",
|
|
},
|
|
{
|
|
ID: "CVE-2024-9287",
|
|
resolvedInVersion: "3.12.8",
|
|
},
|
|
{
|
|
ID: "CVE-2025-0938",
|
|
resolvedInVersion: "3.12.9",
|
|
},
|
|
{
|
|
ID: "CVE-2023-6507",
|
|
// TODO: fix missing version here (according to vulncheck it was fixed in
|
|
// 3.12.1, but the generated feed data doesn't have this value)
|
|
resolvedInVersion: "",
|
|
},
|
|
{
|
|
ID: "CVE-2024-8088",
|
|
resolvedInVersion: "3.12.6",
|
|
},
|
|
{
|
|
ID: "CVE-2024-4032",
|
|
resolvedInVersion: "3.12.4",
|
|
},
|
|
{
|
|
ID: "CVE-2024-3219",
|
|
resolvedInVersion: "3.12.5",
|
|
},
|
|
{
|
|
ID: "CVE-2024-0450",
|
|
resolvedInVersion: "3.12.2",
|
|
},
|
|
{
|
|
ID: "CVE-2023-6597",
|
|
resolvedInVersion: "3.12.1",
|
|
},
|
|
{
|
|
ID: "CVE-2024-3220",
|
|
resolvedInVersion: "3.14.0",
|
|
},
|
|
{
|
|
ID: "CVE-2024-6232",
|
|
resolvedInVersion: "3.12.6",
|
|
},
|
|
},
|
|
continuesToUpdate: true,
|
|
},
|
|
"cpe:2.3:a:python:python:3.14.0:alpha1:*:*:*:macos:*:*": {
|
|
includedCVEs: []cve{
|
|
{
|
|
ID: "CVE-2024-12254",
|
|
resolvedInVersion: "3.14.0a3",
|
|
},
|
|
{
|
|
ID: "CVE-2024-9287",
|
|
resolvedInVersion: "",
|
|
},
|
|
{
|
|
ID: "CVE-2025-0938",
|
|
resolvedInVersion: "3.14.0a5",
|
|
},
|
|
},
|
|
continuesToUpdate: true,
|
|
},
|
|
"cpe:2.3:a:python:python:3.14.0:alpha2:*:*:*:macos:*:*": {
|
|
includedCVEs: []cve{
|
|
{
|
|
ID: "CVE-2024-12254",
|
|
resolvedInVersion: "3.14.0a3",
|
|
},
|
|
{
|
|
ID: "CVE-2025-0938",
|
|
resolvedInVersion: "3.14.0a5",
|
|
},
|
|
},
|
|
continuesToUpdate: true,
|
|
},
|
|
"cpe:2.3:a:python:python:3.14.0:alpha3:*:*:*:macos:*:*": {
|
|
excludedCVEs: []string{"CVE-2024-12254"},
|
|
includedCVEs: []cve{
|
|
{
|
|
ID: "CVE-2025-0938",
|
|
resolvedInVersion: "3.14.0a5",
|
|
},
|
|
},
|
|
continuesToUpdate: true,
|
|
},
|
|
"cpe:2.3:a:google:chrome:138.0.7204.91:*:*:*:*:linux:*:*": {
|
|
excludedCVEs: []string{"CVE-2025-6554"},
|
|
continuesToUpdate: true,
|
|
},
|
|
"cpe:2.3:a:google:chrome:138.0.7204.92:*:*:*:*:macos:*:*": {
|
|
excludedCVEs: []string{"CVE-2025-6554"},
|
|
continuesToUpdate: true,
|
|
},
|
|
"cpe:2.3:a:docker:desktop:4.43.2:*:*:*:*:macos:*:*": {
|
|
includedCVEs: []cve{{ID: "CVE-2025-9074", resolvedInVersion: "4.44.3"}},
|
|
continuesToUpdate: true,
|
|
},
|
|
"cpe:2.3:a:docker:desktop:4.39.0:*:*:*:*:windows:*:*": {
|
|
includedCVEs: []cve{{ID: "CVE-2025-9074", resolvedInVersion: "4.44.3"}},
|
|
continuesToUpdate: true,
|
|
},
|
|
}
|
|
|
|
cveOSTests := []struct {
|
|
platform string
|
|
version string
|
|
osID uint
|
|
includedCVEs []string
|
|
excludedCVEs []string
|
|
}{
|
|
{
|
|
platform: "darwin",
|
|
version: "14.1.2",
|
|
osID: 1,
|
|
includedCVEs: []string{
|
|
"CVE-2023-45866",
|
|
"CVE-2023-42886",
|
|
"CVE-2023-42891",
|
|
"CVE-2023-42906",
|
|
"CVE-2023-42910",
|
|
"CVE-2023-42924",
|
|
"CVE-2023-42883",
|
|
"CVE-2023-42894",
|
|
"CVE-2023-42926",
|
|
"CVE-2023-42932",
|
|
"CVE-2023-42907",
|
|
"CVE-2023-42922",
|
|
"CVE-2023-42904",
|
|
"CVE-2023-42901",
|
|
"CVE-2023-42898",
|
|
"CVE-2023-42903",
|
|
"CVE-2023-42902",
|
|
"CVE-2023-42909",
|
|
"CVE-2023-42914",
|
|
"CVE-2023-42874",
|
|
"CVE-2023-42882",
|
|
"CVE-2023-42912",
|
|
"CVE-2023-42911",
|
|
"CVE-2023-42890",
|
|
"CVE-2023-42905",
|
|
"CVE-2023-42919",
|
|
"CVE-2023-42900",
|
|
"CVE-2023-42899",
|
|
"CVE-2023-42908",
|
|
"CVE-2023-42884",
|
|
},
|
|
},
|
|
{
|
|
platform: "darwin",
|
|
version: "13.6.2",
|
|
osID: 2,
|
|
// This is a subset of vulnerabilities for macOS 13.6.2
|
|
includedCVEs: []string{
|
|
"CVE-2023-32361",
|
|
"CVE-2023-35990",
|
|
"CVE-2023-40541",
|
|
"CVE-2023-40400",
|
|
"CVE-2023-41980",
|
|
"CVE-2023-38615",
|
|
"CVE-2023-39233",
|
|
"CVE-2023-40402",
|
|
"CVE-2023-40450",
|
|
"CVE-2023-42891",
|
|
"CVE-2023-41079",
|
|
"CVE-2023-42932",
|
|
"CVE-2023-38586",
|
|
"CVE-2023-41067",
|
|
"CVE-2023-40407",
|
|
"CVE-2023-42924",
|
|
"CVE-2023-40395",
|
|
"CVE-2023-38596",
|
|
"CVE-2023-32396",
|
|
"CVE-2023-29497",
|
|
},
|
|
},
|
|
{
|
|
platform: "darwin",
|
|
version: "15.3",
|
|
osID: 3,
|
|
// This was resolved in 15.3, so it should be excluded. See https://github.com/fleetdm/fleet/issues/26561.
|
|
excludedCVEs: []string{"CVE-2025-24176"},
|
|
},
|
|
{
|
|
platform: "darwin",
|
|
version: "13.2",
|
|
osID: 4,
|
|
// macOS Ventura 13.2 < 13.3.1 is vulnerable to CVE-2023-28205
|
|
includedCVEs: []string{"CVE-2023-28205"},
|
|
},
|
|
{
|
|
platform: "darwin",
|
|
version: "13.3",
|
|
osID: 5,
|
|
// macOS Ventura 13.3.0 is vulnerable (< 13.3.1)
|
|
includedCVEs: []string{"CVE-2023-28205"},
|
|
},
|
|
{
|
|
platform: "darwin",
|
|
version: "13.3.1",
|
|
osID: 6,
|
|
// macOS Ventura 13.3.1 includes system-level WebKit patch for CVE-2023-28205
|
|
excludedCVEs: []string{"CVE-2023-28205"},
|
|
},
|
|
{
|
|
platform: "darwin",
|
|
version: "13.4",
|
|
osID: 7,
|
|
// macOS Ventura 13.4 is patched (>= 13.3.1)
|
|
excludedCVEs: []string{"CVE-2023-28205"},
|
|
},
|
|
{
|
|
platform: "darwin",
|
|
version: "13.5",
|
|
osID: 8,
|
|
// macOS Ventura 13.5 is patched (>= 13.3.1)
|
|
excludedCVEs: []string{"CVE-2023-28205"},
|
|
},
|
|
{
|
|
platform: "darwin",
|
|
version: "12.7.6",
|
|
osID: 9,
|
|
// macOS Monterey 12.7.6 did NOT receive system-level fix (rely on Safari matching)
|
|
excludedCVEs: []string{"CVE-2023-28205"},
|
|
},
|
|
{
|
|
platform: "darwin",
|
|
version: "12.6.5",
|
|
osID: 10,
|
|
// macOS Monterey 12.6.5 did NOT fix CVE-2023-28205 (only fixed CVE-2023-28206)
|
|
excludedCVEs: []string{"CVE-2023-28205"},
|
|
},
|
|
{
|
|
platform: "darwin",
|
|
version: "11.7.10",
|
|
osID: 11,
|
|
// macOS Big Sur 11.7.10 did NOT receive system-level fix (rely on Safari matching)
|
|
excludedCVEs: []string{"CVE-2023-28205"},
|
|
},
|
|
{
|
|
platform: "darwin",
|
|
version: "11.7.6",
|
|
osID: 12,
|
|
// macOS Big Sur 11.7.6 did NOT fix CVE-2023-28205 (only fixed CVE-2023-28206)
|
|
excludedCVEs: []string{"CVE-2023-28205"},
|
|
},
|
|
{
|
|
platform: "darwin",
|
|
version: "10.15.7",
|
|
osID: 13,
|
|
// macOS Catalina (10.x) should NOT match CVE-2023-28205 (pre-Big Sur)
|
|
excludedCVEs: []string{"CVE-2023-28205"},
|
|
},
|
|
}
|
|
|
|
t.Run("find_vulns_on_cpes", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
ds := new(mock.Store)
|
|
|
|
softwareIDToCPEs := make(map[uint]string)
|
|
ds.ListSoftwareCPEsFunc = func(ctx context.Context) ([]fleet.SoftwareCPE, error) {
|
|
var softwareCPEs []fleet.SoftwareCPE
|
|
i := uint(0)
|
|
for cpe := range cveTests {
|
|
softwareCPEs = append(softwareCPEs, fleet.SoftwareCPE{CPE: cpe, SoftwareID: i})
|
|
softwareIDToCPEs[i] = cpe
|
|
i++
|
|
}
|
|
return softwareCPEs, nil
|
|
}
|
|
|
|
var osIDs []uint
|
|
ds.ListOperatingSystemsForPlatformFunc = func(ctx context.Context, p string) ([]fleet.OperatingSystem, error) {
|
|
var oss []fleet.OperatingSystem
|
|
for _, os := range cveOSTests {
|
|
oss = append(oss, fleet.OperatingSystem{
|
|
ID: os.osID,
|
|
Platform: os.platform,
|
|
Version: os.version,
|
|
})
|
|
osIDs = append(osIDs, os.osID)
|
|
}
|
|
return oss, nil
|
|
}
|
|
|
|
cveLock := &sync.Mutex{}
|
|
cvesFound := make(map[string][]cve)
|
|
ds.InsertSoftwareVulnerabilityFunc = func(ctx context.Context, vuln fleet.SoftwareVulnerability, src fleet.VulnerabilitySource) (bool, error) {
|
|
cveLock.Lock()
|
|
defer cveLock.Unlock()
|
|
|
|
cpe, ok := softwareIDToCPEs[vuln.SoftwareID]
|
|
if !ok {
|
|
return false, fmt.Errorf("software id -> cpe not found: %d", vuln.SoftwareID)
|
|
}
|
|
cve := cve{
|
|
ID: vuln.CVE,
|
|
resolvedInVersion: *vuln.ResolvedInVersion,
|
|
}
|
|
cvesFound[cpe] = append(cvesFound[cpe], cve)
|
|
return false, nil
|
|
}
|
|
|
|
osCVELock := &sync.Mutex{}
|
|
osCVEsFound := make(map[uint][]string)
|
|
ds.InsertOSVulnerabilityFunc = func(ctx context.Context, vuln fleet.OSVulnerability, src fleet.VulnerabilitySource) (bool, error) {
|
|
osCVELock.Lock()
|
|
defer osCVELock.Unlock()
|
|
|
|
osCVEsFound[vuln.OSID] = append(osCVEsFound[vuln.OSID], vuln.CVE)
|
|
|
|
return false, nil
|
|
}
|
|
|
|
ds.DeleteOutOfDateVulnerabilitiesFunc = func(ctx context.Context, source fleet.VulnerabilitySource, olderThan time.Time) error {
|
|
return nil
|
|
}
|
|
ds.DeleteOutOfDateOSVulnerabilitiesFunc = func(ctx context.Context, source fleet.VulnerabilitySource, olderThan time.Time) error {
|
|
return nil
|
|
}
|
|
|
|
_, err := TranslateCPEToCVE(ctx, ds, tempDir, kitlog.NewNopLogger(), false, time.Now().UTC().Add(-time.Hour))
|
|
require.NoError(t, err)
|
|
|
|
require.True(t, ds.DeleteOutOfDateVulnerabilitiesFuncInvoked)
|
|
require.True(t, ds.DeleteOutOfDateOSVulnerabilitiesFuncInvoked)
|
|
|
|
for cpe, tc := range cveTests {
|
|
if tc.continuesToUpdate {
|
|
// Given that new vulnerabilities can be found on these
|
|
// packages/products, we check that at least the
|
|
// known ones are found.
|
|
for _, cve := range tc.includedCVEs {
|
|
require.Contains(t, cvesFound[cpe], cve, fmt.Sprintf("%s does not contain CVE %#v", cpe, cve))
|
|
}
|
|
} else {
|
|
// Check for exact match of CVEs found.
|
|
require.ElementsMatch(t, cvesFound[cpe], tc.includedCVEs, cpe)
|
|
}
|
|
|
|
for _, cve := range tc.excludedCVEs {
|
|
for _, cveFound := range cvesFound[cpe] {
|
|
require.NotEqual(t, cve, cveFound.ID, fmt.Sprintf("%s should not contain %s", cpe, cve))
|
|
}
|
|
}
|
|
}
|
|
|
|
for _, tc := range cveOSTests {
|
|
for _, cve := range tc.includedCVEs {
|
|
require.Contains(t, osCVEsFound[tc.osID], cve)
|
|
}
|
|
for _, cve := range tc.excludedCVEs {
|
|
require.NotContains(t, osCVEsFound[tc.osID], cve)
|
|
}
|
|
}
|
|
})
|
|
|
|
t.Run("recent_vulns", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
ds := new(mock.Store)
|
|
safeDS := &threadSafeDSMock{Store: ds}
|
|
|
|
softwareCPEs := []fleet.SoftwareCPE{
|
|
{CPE: "cpe:2.3:a:google:chrome:*:*:*:*:*:*:*:*", ID: 1, SoftwareID: 1},
|
|
{CPE: "cpe:2.3:a:mozilla:firefox:*:*:*:*:*:*:*:*", ID: 2, SoftwareID: 2},
|
|
{CPE: "cpe:2.3:a:haxx:curl:*:*:*:*:*:*:*:*", ID: 3, SoftwareID: 3},
|
|
}
|
|
ds.DeleteOutOfDateVulnerabilitiesFunc = func(ctx context.Context, source fleet.VulnerabilitySource, olderThan time.Time) error {
|
|
return nil
|
|
}
|
|
ds.ListSoftwareCPEsFunc = func(ctx context.Context) ([]fleet.SoftwareCPE, error) {
|
|
return softwareCPEs, nil
|
|
}
|
|
ds.InsertSoftwareVulnerabilityFunc = func(ctx context.Context, vuln fleet.SoftwareVulnerability, src fleet.VulnerabilitySource) (bool, error) {
|
|
return true, nil
|
|
}
|
|
ds.ListOperatingSystemsForPlatformFunc = func(ctx context.Context, p string) ([]fleet.OperatingSystem, error) {
|
|
return nil, nil
|
|
}
|
|
ds.DeleteOutOfDateOSVulnerabilitiesFunc = func(ctx context.Context, source fleet.VulnerabilitySource, olderThan time.Time) error {
|
|
return nil
|
|
}
|
|
|
|
recent, err := TranslateCPEToCVE(ctx, safeDS, tempDir, kitlog.NewNopLogger(), true, time.Now().Add(-time.Hour))
|
|
require.NoError(t, err)
|
|
|
|
byCPE := make(map[uint]int)
|
|
for _, cpe := range recent {
|
|
byCPE[cpe.Affected()]++
|
|
}
|
|
|
|
// even if it's somewhat far in the past, I've seen the exact numbers
|
|
// change a bit between runs with different downloads, so allow for a bit
|
|
// of wiggle room.
|
|
assert.Greater(t, byCPE[softwareCPEs[0].SoftwareID], 150, "google chrome CVEs")
|
|
assert.Greater(t, byCPE[softwareCPEs[1].SoftwareID], 280, "mozilla firefox CVEs")
|
|
assert.Greater(t, byCPE[softwareCPEs[2].SoftwareID], 10, "curl CVEs")
|
|
|
|
// call it again but now return false from this call, simulating CVE-CPE pairs
|
|
// that already existed in the DB.
|
|
ds.InsertSoftwareVulnerabilityFunc = func(ctx context.Context, vuln fleet.SoftwareVulnerability, src fleet.VulnerabilitySource) (bool, error) {
|
|
return false, nil
|
|
}
|
|
recent, err = TranslateCPEToCVE(ctx, safeDS, tempDir, kitlog.NewNopLogger(), true, time.Now().UTC().Add(-time.Hour))
|
|
require.NoError(t, err)
|
|
|
|
// no recent vulnerability should be reported
|
|
assert.Len(t, recent, 0)
|
|
})
|
|
}
|
|
|
|
func TestSyncsCVEFromURL(t *testing.T) {
|
|
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
if strings.HasSuffix(r.RequestURI, ".meta") {
|
|
fmt.Fprint(w, "lastModifiedDate:2021-08-04T11:10:30-04:00\r\n")
|
|
fmt.Fprint(w, "size:20967174\r\n")
|
|
fmt.Fprint(w, "zipSize:1453429\r\n")
|
|
fmt.Fprint(w, "gzSize:1453293\r\n")
|
|
fmt.Fprint(w, "sha256:10D7338A1E2D8DB344C381793110B67FCA7D729ADA21624EF089EBA78CCE7B53\r\n")
|
|
}
|
|
}))
|
|
defer ts.Close()
|
|
|
|
tempDir := t.TempDir()
|
|
cveFeedPrefixURL := ts.URL + "/feeds/json/cve/1.1/"
|
|
err := DownloadCVEFeed(tempDir, cveFeedPrefixURL, false, log.NewNopLogger())
|
|
require.Error(t, err)
|
|
require.Contains(t,
|
|
err.Error(),
|
|
fmt.Sprintf("1 synchronisation error:\n\tunexpected size for \"%s/feeds/json/cve/1.1/nvdcve-1.1-2002.json.gz\" (200 OK): want 1453293, have 0", ts.URL),
|
|
)
|
|
}
|
|
|
|
// This test is using real data from the 2022 NVD feed
|
|
func TestGetMatchingVersionEndExcluding(t *testing.T) {
|
|
ctx := context.Background()
|
|
testDict := loadDict(t, "../testdata/nvdcve-1.1-2022.json.gz")
|
|
|
|
tests := []struct {
|
|
name string
|
|
cve string
|
|
meta *wfn.Attributes
|
|
want string
|
|
wantErr bool
|
|
}{
|
|
{
|
|
name: "happy path with version with no Version Start",
|
|
cve: "CVE-2022-40897",
|
|
meta: &wfn.Attributes{
|
|
Vendor: "python",
|
|
Product: "setuptools",
|
|
Version: "64",
|
|
},
|
|
want: "65.5.1",
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "CVE matches multiple products",
|
|
cve: "CVE-2022-40956",
|
|
meta: &wfn.Attributes{
|
|
Vendor: "mozilla",
|
|
Product: "firefox",
|
|
Version: "93.0.100",
|
|
},
|
|
want: "105.0",
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "Nodes has nested Children",
|
|
cve: "CVE-2022-40961",
|
|
meta: &wfn.Attributes{
|
|
Vendor: "mozilla",
|
|
Product: "firefox",
|
|
Version: "93.0.100",
|
|
},
|
|
want: "105.0",
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "Multiple product matches with different version ranges",
|
|
cve: "CVE-2022-26697",
|
|
meta: &wfn.Attributes{
|
|
Vendor: "apple",
|
|
Product: "macos",
|
|
Version: "12.0",
|
|
},
|
|
want: "12.4",
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "No version end excluding",
|
|
cve: "CVE-2022-26834",
|
|
meta: &wfn.Attributes{
|
|
Vendor: "cybozu",
|
|
Product: "remote_service_manager",
|
|
Version: "3.1.2",
|
|
},
|
|
want: "",
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "Version exceeds version end excluding",
|
|
cve: "CVE-2022-4610",
|
|
meta: &wfn.Attributes{
|
|
Vendor: "clickstudios",
|
|
Product: "passwordstate",
|
|
Version: "9.5.8.4",
|
|
TargetSW: "chrome",
|
|
},
|
|
want: "",
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "Can compare 4th version part",
|
|
cve: "CVE-2022-45889",
|
|
meta: &wfn.Attributes{
|
|
Vendor: "planetestream",
|
|
Product: "planet_estream",
|
|
Version: "6.72.10.06",
|
|
},
|
|
want: "6.72.10.07",
|
|
wantErr: false,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got, err := getMatchingVersionEndExcluding(ctx, tt.cve, tt.meta, testDict, nil)
|
|
if (err != nil) != tt.wantErr {
|
|
t.Errorf("getMatchingVersionEndExcluding() error = %v, wantErr %v", err, tt.wantErr)
|
|
return
|
|
}
|
|
if got != tt.want {
|
|
t.Errorf("got %q, want %q", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestGetMacOSCPEs(t *testing.T) {
|
|
ctx := context.Background()
|
|
ds := new(mock.Store)
|
|
os := fleet.OperatingSystem{
|
|
ID: 1,
|
|
Name: "macOS",
|
|
Version: "11.6.2",
|
|
Arch: "x86_64",
|
|
KernelVersion: "20.6.0",
|
|
Platform: "darwin",
|
|
}
|
|
|
|
ds.ListOperatingSystemsForPlatformFunc = func(ctx context.Context, p string) ([]fleet.OperatingSystem, error) {
|
|
return []fleet.OperatingSystem{os}, nil
|
|
}
|
|
|
|
CVEs, err := GetMacOSCPEs(ctx, ds)
|
|
require.NoError(t, err)
|
|
require.Len(t, CVEs, 2)
|
|
|
|
expected := map[osCPEWithNVDMeta]struct{}{
|
|
{
|
|
OperatingSystem: os,
|
|
meta: &wfn.Attributes{
|
|
Part: "o",
|
|
Vendor: "apple",
|
|
Product: "mac_os_x",
|
|
Version: CVEs[0].Version,
|
|
Update: wfn.Any,
|
|
Edition: wfn.Any,
|
|
SWEdition: wfn.Any,
|
|
TargetSW: wfn.Any,
|
|
TargetHW: wfn.Any,
|
|
Other: wfn.Any,
|
|
Language: wfn.Any,
|
|
},
|
|
}: {},
|
|
{
|
|
OperatingSystem: os,
|
|
meta: &wfn.Attributes{
|
|
Part: "o",
|
|
Vendor: "apple",
|
|
Product: "macos",
|
|
Version: CVEs[0].Version,
|
|
Update: wfn.Any,
|
|
Edition: wfn.Any,
|
|
SWEdition: wfn.Any,
|
|
TargetSW: wfn.Any,
|
|
TargetHW: wfn.Any,
|
|
Other: wfn.Any,
|
|
Language: wfn.Any,
|
|
},
|
|
}: {},
|
|
}
|
|
|
|
for _, cve := range CVEs {
|
|
require.Contains(t, expected, cve)
|
|
}
|
|
}
|
|
|
|
// loadDict loads a cvefeed.Dictionary from a JSON NVD feed file.
|
|
func loadDict(t *testing.T, path string) cvefeed.Dictionary {
|
|
dict, err := cvefeed.LoadJSONDictionary(path)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
return dict
|
|
}
|
|
|
|
func TestExpandCPEAliases(t *testing.T) {
|
|
firefox := &wfn.Attributes{
|
|
Vendor: "mozilla",
|
|
Product: "firefox",
|
|
Version: "93.0.100",
|
|
}
|
|
chromePlugin := &wfn.Attributes{
|
|
Vendor: "google",
|
|
Product: "plugin foobar",
|
|
Version: "93.0.100",
|
|
TargetSW: "chrome",
|
|
}
|
|
|
|
vsCodeExtension := &wfn.Attributes{
|
|
Vendor: "Microsoft",
|
|
Product: "foo.extension",
|
|
Version: "2024.2.1",
|
|
TargetSW: "visual_studio_code",
|
|
}
|
|
vsCodeExtensionAlias := *vsCodeExtension
|
|
vsCodeExtensionAlias.TargetSW = "visual_studio"
|
|
|
|
pythonCodeExtension := &wfn.Attributes{
|
|
Vendor: "microsoft",
|
|
Product: "python_extension",
|
|
Version: "2024.2.1",
|
|
TargetSW: "visual_studio_code",
|
|
}
|
|
pythonCodeExtensionAlias1 := *pythonCodeExtension
|
|
pythonCodeExtensionAlias1.TargetSW = "visual_studio"
|
|
pythonCodeExtensionAlias2 := *pythonCodeExtension
|
|
pythonCodeExtensionAlias2.Product = "visual_studio_code"
|
|
pythonCodeExtensionAlias2.TargetSW = "python"
|
|
|
|
python3140Alpha2 := &wfn.Attributes{
|
|
Vendor: "python",
|
|
Product: "python",
|
|
Version: "3.14.0",
|
|
Update: "alpha2",
|
|
TargetSW: "windows",
|
|
}
|
|
python3140Alpha2Alias1 := *python3140Alpha2
|
|
python3140Alpha2Alias1.Version = "3.14.0a2"
|
|
python3140Alpha2Alias1.Update = ""
|
|
|
|
python3130Beta1 := &wfn.Attributes{
|
|
Vendor: "python",
|
|
Product: "python",
|
|
Version: "3.13.0",
|
|
Update: "beta2",
|
|
TargetSW: "windows",
|
|
}
|
|
python3130Beta1Alias := *python3130Beta1
|
|
python3130Beta1Alias.Version = "3.13.0b2"
|
|
python3130Beta1Alias.Update = ""
|
|
|
|
python3130RC1 := &wfn.Attributes{
|
|
Vendor: "python",
|
|
Product: "python",
|
|
Version: "3.13.0",
|
|
Update: "rc1",
|
|
TargetSW: "windows",
|
|
}
|
|
python3130RC1Alias := *python3130RC1
|
|
python3130RC1Alias.Version = "3.13.0rc1"
|
|
python3130RC1Alias.Update = ""
|
|
|
|
pgadminMacOS := &wfn.Attributes{
|
|
Vendor: "pgadmin",
|
|
Product: "pgadmin",
|
|
Version: "9.10",
|
|
TargetSW: "macos",
|
|
}
|
|
pgadminMacOSAliasPgadmin := *pgadminMacOS
|
|
pgadminMacOSAliasPgadmin.TargetSW = "postgresql"
|
|
pgadminMacOSAliasPgadmin_4 := *pgadminMacOS
|
|
pgadminMacOSAliasPgadmin_4.Product = "pgadmin_4"
|
|
pgadminMacOSAliasPgadmin_4.TargetSW = "postgresql"
|
|
pgadminMacOSAliasPgadmin4 := *pgadminMacOS
|
|
pgadminMacOSAliasPgadmin4.Product = "pgadmin4"
|
|
pgadminMacOSAliasPgadmin4.TargetSW = "postgresql"
|
|
|
|
pgadminWindows := &wfn.Attributes{
|
|
Vendor: "pgadmin",
|
|
Product: "pgadmin_4",
|
|
Version: "9.10",
|
|
TargetSW: "windows",
|
|
}
|
|
pgadminWindowsAliasPgadmin := *pgadminWindows
|
|
pgadminWindowsAliasPgadmin.Product = "pgadmin"
|
|
pgadminWindowsAliasPgadmin.TargetSW = "postgresql"
|
|
pgadminWindowsAliasPgadmin_4 := *pgadminWindows
|
|
pgadminWindowsAliasPgadmin_4.TargetSW = "postgresql"
|
|
pgadminWindowsAliasPgadmin4 := *pgadminWindows
|
|
pgadminWindowsAliasPgadmin4.Product = "pgadmin4"
|
|
pgadminWindowsAliasPgadmin4.TargetSW = "postgresql"
|
|
|
|
for _, tc := range []struct {
|
|
name string
|
|
cpeItem *wfn.Attributes
|
|
expectedAliases []*wfn.Attributes
|
|
}{
|
|
{
|
|
name: "no expansion without target_sw",
|
|
cpeItem: firefox,
|
|
expectedAliases: []*wfn.Attributes{firefox},
|
|
},
|
|
{
|
|
name: "no expansion with target_sw",
|
|
cpeItem: chromePlugin,
|
|
expectedAliases: []*wfn.Attributes{chromePlugin},
|
|
},
|
|
{
|
|
name: "visual studio code extension",
|
|
cpeItem: vsCodeExtension,
|
|
expectedAliases: []*wfn.Attributes{vsCodeExtension, &vsCodeExtensionAlias},
|
|
},
|
|
{
|
|
name: "python visual studio code extension",
|
|
cpeItem: pythonCodeExtension,
|
|
expectedAliases: []*wfn.Attributes{pythonCodeExtension, &pythonCodeExtensionAlias1, &pythonCodeExtensionAlias2},
|
|
},
|
|
{
|
|
name: "pre-release python: 3.14.0 alpha2",
|
|
cpeItem: python3140Alpha2,
|
|
expectedAliases: []*wfn.Attributes{python3140Alpha2, &python3140Alpha2Alias1},
|
|
},
|
|
{
|
|
name: "pre-release python: 3.13.0 beta1",
|
|
cpeItem: python3130Beta1,
|
|
expectedAliases: []*wfn.Attributes{python3130Beta1, &python3130Beta1Alias},
|
|
},
|
|
{
|
|
name: "pre-release python: 3.13.0 rc1",
|
|
cpeItem: python3130RC1,
|
|
expectedAliases: []*wfn.Attributes{python3130RC1, &python3130RC1Alias},
|
|
},
|
|
{
|
|
name: "pgadmin on macos",
|
|
cpeItem: pgadminMacOS,
|
|
expectedAliases: []*wfn.Attributes{
|
|
pgadminMacOS,
|
|
&pgadminMacOSAliasPgadmin,
|
|
&pgadminMacOSAliasPgadmin_4,
|
|
&pgadminMacOSAliasPgadmin4,
|
|
},
|
|
},
|
|
{
|
|
name: "pgadmin on windows",
|
|
cpeItem: pgadminWindows,
|
|
expectedAliases: []*wfn.Attributes{
|
|
pgadminWindows,
|
|
&pgadminWindowsAliasPgadmin,
|
|
&pgadminWindowsAliasPgadmin_4,
|
|
&pgadminWindowsAliasPgadmin4,
|
|
},
|
|
},
|
|
} {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
aliases := expandCPEAliases(tc.cpeItem)
|
|
require.Equal(t, tc.expectedAliases, aliases)
|
|
})
|
|
}
|
|
}
|