diff --git a/docs/docs/scanner/vulnerability.md b/docs/docs/scanner/vulnerability.md index ee76a8e6844c..57cb6d79c1c3 100644 --- a/docs/docs/scanner/vulnerability.md +++ b/docs/docs/scanner/vulnerability.md @@ -66,7 +66,44 @@ If the data source does not provide a severity, the severity is determined based | 7.0-8.9 | High | | 9.0-10.0 | Critical | -If the CVSS score is also not provided, it falls back to [NVD][nvd], and if NVD does not have severity, it will be UNKNOWN. +If the CVSS score is also not provided, it falls back to [NVD][nvd]. + +NVD and some vendors may delay severity analysis, while other vendors, such as Red Hat, are able to quickly evaluate and announce the severity of vulnerabilities. +To avoid marking too many vulnerabilities as "UNKNOWN" severity, Trivy uses severity ratings from other vendors when the NVD information is not yet available. +The order of preference for vendor severity data can be found [here](https://github.com/aquasecurity/trivy-db/blob/79d0fbd1e246f3c77eef4b9826fe4bf65940b221/pkg/vulnsrc/vulnerability/vulnerability.go#L17-L19). + +You can reference `SeveritySource` in the [JSON reporting format](../configuration/reporting.md#json) to see from where the severity is taken for a given vulnerability. + +```shell +"SeveritySource": "debian", +``` + + +In addition, you can see all the vendor severity ratings. + +```json +"VendorSeverity": { + "amazon": 2, + "cbl-mariner": 4, + "ghsa": 4, + "nvd": 4, + "photon": 4, + "redhat": 2, + "ubuntu": 2 +} +``` + +Here is the severity mapping in Trivy: + +| Number | Severity | +|:------:|----------| +| 0 | Unknown | +| 1 | Low | +| 2 | Medium | +| 3 | High | +| 4 | Critical | + +If no vendor has a severity, the `UNKNOWN` severity will be used. ### Unfixed Vulnerabilities The unfixed/unfixable vulnerabilities mean that the patch has not yet been provided on their distribution. diff --git a/pkg/vulnerability/vulnerability.go b/pkg/vulnerability/vulnerability.go index 8e27ee4733fc..a77c93a87a1a 100644 --- a/pkg/vulnerability/vulnerability.go +++ b/pkg/vulnerability/vulnerability.go @@ -2,8 +2,10 @@ package vulnerability import ( "strings" + "sync" "github.com/google/wire" + "github.com/samber/lo" "github.com/aquasecurity/trivy-db/pkg/db" dbTypes "github.com/aquasecurity/trivy-db/pkg/types" @@ -46,6 +48,12 @@ var SuperSet = wire.NewSet( NewClient, ) +// Show warning if we use severity from another vendor +// cf. https://github.com/aquasecurity/trivy/issues/6714 +var onceWarn = sync.OnceFunc(func() { + log.Warn("Using severities from other vendors for some vulnerabilities. Read https://aquasecurity.github.io/trivy/latest/docs/scanner/vulnerability/#severity-selection for details.") +}) + // Client manipulates vulnerabilities type Client struct { dbc db.Operation @@ -77,13 +85,10 @@ func (c Client) FillInfo(vulns []types.DetectedVulnerability) { } // Detect the data source - var source dbTypes.SourceID - if vulns[i].DataSource != nil { - source = vulns[i].DataSource.ID - } + dataSource := lo.FromPtr(vulns[i].DataSource) - // Select the severity according to the detected source. - severity, severitySource := c.getVendorSeverity(vulnID, &vuln, source) + // Select the severity according to the detected sourceID. + severity, severitySource := c.getVendorSeverity(vulnID, &vuln, dataSource) // The vendor might provide package-specific severity like Debian. // For example, CVE-2015-2328 in Debian has "unimportant" for mongodb and "low" for pcre3. @@ -105,13 +110,13 @@ func (c Client) FillInfo(vulns []types.DetectedVulnerability) { vulns[i].Severity = severity vulns[i].SeveritySource = severitySource - vulns[i].PrimaryURL = c.getPrimaryURL(vulnID, vuln.References, source) + vulns[i].PrimaryURL = c.getPrimaryURL(vulnID, vuln.References, dataSource.ID) } } -func (c Client) getVendorSeverity(vulnID string, vuln *dbTypes.Vulnerability, source dbTypes.SourceID) (string, dbTypes.SourceID) { - if vs, ok := vuln.VendorSeverity[source]; ok { - return vs.String(), source +func (c Client) getVendorSeverity(vulnID string, vuln *dbTypes.Vulnerability, dataSource dbTypes.DataSource) (string, dbTypes.SourceID) { + if vs, ok := vuln.VendorSeverity[dataSource.ID]; ok { + return vs.String(), dataSource.ID } // use severity from GitHub for all GHSA-xxx vulnerabilities @@ -130,6 +135,7 @@ func (c Client) getVendorSeverity(vulnID string, vuln *dbTypes.Vulnerability, so return dbTypes.SeverityUnknown.String(), "" } + onceWarn() return vuln.Severity, "" }