Files
Dante Catalfamo e90bcfeaae Add rules to deal with some python CVE false positives (#46673)
**Related issue:** Resolves #35148

## What was added

| CVE | Rule | Reason |
|-----|------|--------|
| **CVE-2017-17522** | `IgnoreAll` | DISPUTED by Python maintainers; not
exploitable (`webbrowser.py` uses `subprocess.Popen` with
`shell=False`). Broad NVD CPE matched modern Python. |
| **CVE-2023-36632** | `IgnoreAll` | NVD-DISPUTED — Python states it's
"neither a vulnerability nor a bug" (intentional `RecursionError` in
`email.utils.parseaddr`). |
| **CVE-2024-3219** | `IgnoreIf target_sw != "windows"` | Only affects
platforms lacking AF_UNIX (Windows). Linux/macOS unaffected, but
NVD/VulnCheck CPE uses `target_sw=*`. |

**Files touched:**
- `cpe_matching_rules.go` — three new rules
- `cpe_matching_rule_test.go` — assertions covering all three (incl.
Windows-vs-macOS/Linux distinction for CVE-2024-3219)
- `changes/35148-python-cve-false-positives` — changelog

**Correctness note:** `target_sw` derives from software *source*
(`apps`/`homebrew_packages` → `macos`, `programs` → `windows`), so the
CVE-2024-3219 rule suppresses on macOS while preserving the genuine
Windows
positive.

## What was skipped, and why

| CVE | Why skipped |
|-----|-------------|
| **CVE-2024-12718** | Conflicting evidence: getvictor confirmed it's a
**true positive** (3.9.22 < fixed 3.9.23), contradicting the customer's
"only 3.12+ affected" reasoning. Needs a product/security ruling, not a
code change. |
| **CVE-2025-1795** | Likely a VulnCheck patch-level miss (customer says
3.10.17 has the backported fix). Needs the actual VulnCheck version
range to fix safely. |
| **CVE-2023-32681** | Affects `python:requests` and is **correctly
matched**; the customer dismissed it on deployment grounds ("corporate
servers only"). Not a detection bug. |
| **CVE-2007-4559** | Real tarfile path-traversal (CVSS 9.8, **not
disputed**); the customer labeled it "Other issue," not a false
positive. Suppressing it would hide a genuine vulnerability. |
2026-06-05 16:21:09 -04:00

475 lines
13 KiB
Go

package nvd
import (
"fmt"
"strconv"
"strings"
"github.com/fleetdm/fleet/v4/server/vulnerabilities/nvd/tools/wfn"
)
type CPEMatchingRules []CPEMatchingRule
// GetKnownNVDBugRules returns a list of CPEMatchingRules used for
// ignoring false positives detected during the NVD vuln. detection process.
func GetKnownNVDBugRules() (CPEMatchingRules, error) {
rules := CPEMatchingRules{
CPEMatchingRule{
CPESpecs: []CPEMatchingRuleSpec{
{
Vendor: "apple",
Product: "icloud",
TargetSW: "windows",
SemVerConstraint: "< 7.1",
},
},
CVEs: map[string]struct{}{
"CVE-2017-13797": {},
},
},
CPEMatchingRule{
CPESpecs: []CPEMatchingRuleSpec{
{
Vendor: "apple",
Product: "icloud",
TargetSW: "windows",
SemVerConstraint: "<= 6.1.1",
},
},
CVEs: map[string]struct{}{
"CVE-2016-4613": {},
"CVE-2017-2383": {},
},
},
CPEMatchingRule{
CPESpecs: []CPEMatchingRuleSpec{
{
Vendor: "apple",
Product: "icloud",
TargetSW: "windows",
SemVerConstraint: "<= 6.1.0",
},
},
CVEs: map[string]struct{}{
"CVE-2017-2366": {},
},
},
CPEMatchingRule{
CPESpecs: []CPEMatchingRuleSpec{
{
Vendor: "apple",
Product: "icloud",
TargetSW: "windows",
SemVerConstraint: "<= 6.0.0",
},
},
CVEs: map[string]struct{}{
"CVE-2016-4613": {},
"CVE-2016-7583": {},
},
},
CPEMatchingRule{
CPESpecs: []CPEMatchingRuleSpec{
{
Vendor: "apple",
Product: "icloud",
TargetSW: "windows",
SemVerConstraint: "<= 6.0.1",
},
},
CVEs: map[string]struct{}{
"CVE-2016-4692": {},
"CVE-2016-4743": {},
"CVE-2016-7578": {},
"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": {},
},
},
// The NVD dataset contains an invalid rule for CVE-2020-10146 that matches all versions of
// Microsoft Teams.
//
// "cve" : {
// "data_type" : "CVE",
// "data_format" : "MITRE",
// "data_version" : "4.0",
// "CVE_data_meta" : {
// "ID" : "CVE-2020-10146",
// "ASSIGNER" : "cert@cert.org"
// },
// [...]
// "configurations" : {
// "CVE_data_version" : "4.0",
// "nodes" : [ {
// "operator" : "OR",
// "children" : [ ],
// "cpe_match" : [ {
// "vulnerable" : true,
// "cpe23Uri" : "cpe:2.3:a:microsoft:teams:*:*:*:*:*:*:*:*", <<<<<<
// "versionEndExcluding" : "2020-10-29",
// "cpe_name" : [ ]
// } ]
// } ]
// },
//
// Such CVE corresponds to a vulnerability on Microsoft's online service
// that has been patched since October 2020.
CPEMatchingRule{
IgnoreAll: true,
CVEs: map[string]struct{}{
"CVE-2020-10146": {},
},
},
// #9835 Python expat 2.1.0 CVE recommends rejecting the report, no CVSS score, broad CPE criteria
CPEMatchingRule{
IgnoreAll: true,
CVEs: map[string]struct{}{
"CVE-2013-0340": {},
},
},
// CVE-2022-42919 only affects Python on Linux but the NVD dataset doesn't set target_sw=linux.
// For instance, here's an invalid CPE sample from the NVD dataset from this vulnerability as of Oct 13th 2023:
// `cpe:2.3:a:python:python:3.7.3:-:*:*:*:*:*:*`.
CPEMatchingRule{
CVEs: map[string]struct{}{
"CVE-2022-42919": {},
},
CPESpecs: []CPEMatchingRuleSpec{
{
Vendor: "python",
Product: "python",
TargetSW: "linux",
SemVerConstraint: ">= 3.9.0, < 3.9.16",
},
{
Vendor: "python",
Product: "python",
TargetSW: "linux",
SemVerConstraint: ">= 3.10.0, < 3.10.9",
},
{
Vendor: "python",
Product: "python",
TargetSW: "linux",
SemVerConstraint: ">= 3.8.3, <= 3.8.15",
},
{
Vendor: "python",
Product: "python",
TargetSW: "linux",
SemVerConstraint: ">= 3.7.3, <= 3.7.15",
},
},
},
// CVE-2017-17522 is DISPUTED. NVD lists python:python up to (and including) 3.6.3 as
// vulnerable, but the CPE criteria is broad and matches modern Python installs (e.g. it was
// reported against Python 3.9.6). Python maintainers reject the report: exploitation is
// impossible because webbrowser.py relies on subprocess.Popen with the default shell=False.
// Following the same approach as CVE-2013-0340, we ignore it entirely. See #35148.
CPEMatchingRule{
IgnoreAll: true,
CVEs: map[string]struct{}{
"CVE-2017-17522": {},
},
},
// CVE-2023-36632 is DISPUTED. NVD/Python state it is "neither a vulnerability nor a bug": the
// legacy email.utils.parseaddr function raises a RecursionError on crafted input, which is
// the email package's intended behavior of throwing an exception when size limits are
// exceeded. It matches python:python up to 3.11.4 with a 7.5 score. Following the same
// approach as CVE-2013-0340, we ignore it entirely. See #35148.
CPEMatchingRule{
IgnoreAll: true,
CVEs: map[string]struct{}{
"CVE-2023-36632": {},
},
},
// CVE-2024-3219 affects CPython's pure-Python socket.socketpair() implementation, which is
// only used on platforms lacking AF_UNIX support (Windows). Linux and macOS use the native
// AF_UNIX implementation and are not affected, but the NVD/VulnCheck CPE data uses
// target_sw=* causing false positives on macOS and Linux. See #35148.
CPEMatchingRule{
CVEs: map[string]struct{}{
"CVE-2024-3219": {},
},
IgnoreIf: func(cpeMeta *wfn.Attributes) bool {
return cpeMeta.TargetSW != "windows"
},
},
// These vulnerabilities in the MongoDB client incorrectly match
// the VS Code extension.
CPEMatchingRule{
CVEs: map[string]struct{}{
"CVE-2012-6619": {},
"CVE-2013-1892": {},
"CVE-2013-2132": {},
"CVE-2015-1609": {},
"CVE-2016-6494": {},
},
IgnoreIf: func(cpeMeta *wfn.Attributes) bool {
return cpeMeta.TargetSW == "visual_studio_code"
},
},
// When we're inventorying the Steam launcher for Dota, version recorded is 1.0,
// which shows a bunch of false positive CVEs. See #34323.
CPEMatchingRule{
CVEs: map[string]struct{}{
"CVE-2020-7949": {},
"CVE-2020-7950": {},
"CVE-2020-7951": {},
"CVE-2020-7952": {},
"CVE-2020-9005": {},
},
IgnoreIf: func(cpeMeta *wfn.Attributes) bool {
return cpeMeta.Vendor == "valvesoftware" && cpeMeta.Product == "dota_2" &&
cpeMeta.TargetSW == "macos" && (cpeMeta.Version == "1\\.0" || cpeMeta.Version == "1\\.0\\.0")
},
},
// Issue #18733 incorrect CPEs that should be matching
// visual studio code extensions
CPEMatchingRule{
CVEs: map[string]struct{}{
"CVE-2021-28967": {},
"CVE-2020-1192": {},
"CVE-2020-1171": {},
},
IgnoreIf: func(cpeMeta *wfn.Attributes) bool {
return cpeMeta.Product == "visual_studio_code" && cpeMeta.TargetSW == wfn.Any
},
},
// CVE-2023-48795 in NVD incorrectly mentions PowerShell as vulnerable when the issue is actually with OpenSSH,
// which is packaged separately. It also includes a bogus resolved-in version number. See #26073.
CPEMatchingRule{
CVEs: map[string]struct{}{
"CVE-2023-48795": {},
},
IgnoreIf: func(cpeMeta *wfn.Attributes) bool {
return cpeMeta.Vendor == "microsoft" && cpeMeta.Product == "powershell"
},
},
// Old macos CPEs without version constraints that should be ignored
CPEMatchingRule{
CVEs: map[string]struct{}{
"CVE-2001-0102": {},
"CVE-1999-0590": {},
"CVE-1999-0524": {},
},
IgnoreAll: true,
},
// Windows OS vulnerabilities without version constraints that should be ignored
// TODO(tim): This rule is too specific and should be generalized to ignore all
// Windows OS vulnerabilities in NVD
CPEMatchingRule{
CVEs: map[string]struct{}{
"CVE-2010-3143": {},
"CVE-2011-5049": {},
"CVE-2012-2972": {},
"CVE-2018-0598": {},
"CVE-2010-3888": {},
"CVE-2010-3139": {},
"CVE-2021-36958": {},
"CVE-2008-6194": {},
"CVE-2010-2157": {},
"CVE-2011-3389": {},
"CVE-2012-2971": {},
"CVE-2018-0599": {},
"CVE-2010-3889": {},
"CVE-2011-0638": {},
},
IgnoreAll: true,
},
// CVE-2024-4030 and CVE-2024-6286 only target windows operating systems
CPEMatchingRule{
CVEs: map[string]struct{}{
"CVE-2024-4030": {},
"CVE-2024-6286": {},
},
IgnoreIf: func(cpeMeta *wfn.Attributes) bool {
return cpeMeta.TargetSW != "windows"
},
},
// CVE-2024-12254 only targets Mac/Linux operating systems
CPEMatchingRule{
CVEs: map[string]struct{}{
"CVE-2024-12254": {},
},
IgnoreIf: func(cpeMeta *wfn.Attributes) bool {
return cpeMeta.TargetSW == "windows"
},
},
// CVE-2024-7006 only targets Linux operating systems (libtiff vulnerability)
CPEMatchingRule{
CVEs: map[string]struct{}{
"CVE-2024-7006": {},
},
IgnoreIf: func(cpeMeta *wfn.Attributes) bool {
return cpeMeta.TargetSW != "linux"
},
},
// these CVEs only target iOS, and we don't yet support iOS vuln scanning (and can't tell iOS/Mac CPEs apart yet)
CPEMatchingRule{
CVEs: map[string]struct{}{
"CVE-2024-10004": {},
"CVE-2024-10327": {}, // also missing a CPE as of 2025-01-01
},
IgnoreAll: true,
},
// Gitk and Git GUI CVEs should not match the base git package
// These CVEs affect gitk/git-gui which is git-gui on Homebrew
CPEMatchingRule{
CVEs: map[string]struct{}{
"CVE-2025-27613": {}, // Gitk file creation/truncation via OS command injection
"CVE-2025-27614": {}, // Gitk arbitrary command execution
"CVE-2025-46835": {}, // Git GUI arbitrary file overwrite
},
IgnoreIf: func(cpeMeta *wfn.Attributes) bool {
return cpeMeta.Vendor == "git" && cpeMeta.Product == "git"
},
},
// CVE-2019-17201 and CVE-2019-17202 are Windows-only privilege escalation vulnerabilities
// in Admin By Request (named pipe bypass and PIN challenge-response bypass).
// The NVD CPE data uses target_sw=* with no platform differentiation, causing false positives
// on macOS and Linux where the software uses independent version numbering. See #41586.
CPEMatchingRule{
CVEs: map[string]struct{}{
"CVE-2019-17201": {},
"CVE-2019-17202": {},
},
IgnoreIf: func(cpeMeta *wfn.Attributes) bool {
return cpeMeta.TargetSW != "windows"
},
},
// CVE-2023-28205 WebKit vulnerability
// Apple released fixes via:
// - Safari 16.4.1 standalone update for Big Sur/Monterey (HT213722)
// - macOS Ventura 13.3.1 system update (HT213721)
//
// - Safari 16.0-16.4.0 are vulnerable
// - Safari < 16.0 not vulnerable
// - macOS Ventura < 13.3.1 is vulnerable
// - macOS < 13.0 ignore for macOS matches, no system-level fix, rely on Safari version matching
CPEMatchingRule{
CVEs: map[string]struct{}{
"CVE-2023-28205": {},
},
IgnoreIf: func(cpeMeta *wfn.Attributes) bool {
// For Safari CPE matches, only match versions 16.x
if cpeMeta.Vendor == "apple" && cpeMeta.Product == "safari" {
version := wfn.StripSlashes(cpeMeta.Version)
parts := strings.Split(version, ".")
if len(parts) > 0 {
majorVer, err := strconv.Atoi(parts[0])
if err != nil {
return false
}
if majorVer < 16 || majorVer > 16 {
return true
}
if majorVer == 16 && len(parts) >= 2 {
minorVer, _ := strconv.Atoi(parts[1])
// Safari 16.5+
if minorVer > 4 {
return true
}
// Safari 16.4.x
if minorVer == 4 && len(parts) >= 3 {
patchVer, _ := strconv.Atoi(parts[2])
if patchVer >= 1 {
return true
}
}
}
}
}
// For macOS CPE matches, only match Ventura < 13.3.1
if cpeMeta.Vendor == "apple" && cpeMeta.Product == "macos" {
version := wfn.StripSlashes(cpeMeta.Version)
parts := strings.Split(version, ".")
if len(parts) > 0 {
majorVer, err := strconv.Atoi(parts[0])
if err != nil {
return false
}
// Ignore non-Ventura
if majorVer != 13 {
return true
}
// For Ventura, check if >= 13.3.1
if len(parts) >= 2 {
minorVer, _ := strconv.Atoi(parts[1])
if minorVer > 3 {
return true
}
if minorVer == 3 {
if len(parts) == 2 {
return false
}
if len(parts) >= 3 {
patchVer, _ := strconv.Atoi(parts[2])
if patchVer >= 1 {
return true
}
}
}
}
}
}
return false
},
},
}
for i, rule := range rules {
if err := rule.Validate(); err != nil {
return nil, fmt.Errorf("invalid rule %d: %w", i, err)
}
}
return rules, nil
}
// FindMatch returns the first matching rule
func (rules CPEMatchingRules) FindMatch(cve string) (*CPEMatchingRule, bool) {
for _, rule := range rules {
if _, ok := rule.CVEs[cve]; ok {
return &rule, true
}
}
return nil, false
}