mirror of
https://github.com/aquasecurity/trivy.git
synced 2025-12-12 15:50:15 -08:00
Signed-off-by: knqyf263 <knqyf263@gmail.com> Co-authored-by: knqyf263 <knqyf263@gmail.com>
158 lines
4.5 KiB
Go
158 lines
4.5 KiB
Go
package vulnerability
|
|
|
|
import (
|
|
"strings"
|
|
|
|
"github.com/google/wire"
|
|
|
|
"github.com/aquasecurity/trivy-db/pkg/db"
|
|
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
|
|
"github.com/aquasecurity/trivy-db/pkg/vulnsrc/vulnerability"
|
|
"github.com/aquasecurity/trivy/pkg/log"
|
|
"github.com/aquasecurity/trivy/pkg/types"
|
|
)
|
|
|
|
var (
|
|
primaryURLPrefixes = map[dbTypes.SourceID][]string{
|
|
vulnerability.Debian: {
|
|
"http://www.debian.org",
|
|
"https://www.debian.org",
|
|
},
|
|
vulnerability.Ubuntu: {
|
|
"http://www.ubuntu.com",
|
|
"https://usn.ubuntu.com",
|
|
},
|
|
vulnerability.RedHat: {"https://access.redhat.com"},
|
|
vulnerability.SuseCVRF: {
|
|
"http://lists.opensuse.org",
|
|
"https://lists.opensuse.org",
|
|
},
|
|
vulnerability.OracleOVAL: {
|
|
"http://linux.oracle.com/errata",
|
|
"https://linux.oracle.com/errata",
|
|
},
|
|
vulnerability.NodejsSecurityWg: {
|
|
"https://www.npmjs.com",
|
|
"https://hackerone.com",
|
|
},
|
|
vulnerability.RubySec: {"https://groups.google.com"},
|
|
}
|
|
)
|
|
|
|
// SuperSet binds the dependencies
|
|
var SuperSet = wire.NewSet(
|
|
wire.Struct(new(db.Config)),
|
|
wire.Bind(new(db.Operation), new(db.Config)),
|
|
NewClient,
|
|
)
|
|
|
|
// Client manipulates vulnerabilities
|
|
type Client struct {
|
|
dbc db.Operation
|
|
}
|
|
|
|
// NewClient is the factory method for Client
|
|
func NewClient(dbc db.Operation) Client {
|
|
return Client{dbc: dbc}
|
|
}
|
|
|
|
// FillInfo fills extra info in vulnerability objects
|
|
func (c Client) FillInfo(vulns []types.DetectedVulnerability) {
|
|
for i := range vulns {
|
|
// Add the vulnerability status
|
|
// Some vendors such as Red Hat have their own vulnerability status, and we use it.
|
|
// Otherwise, we put "fixed" or "affected" according to the fixed version.
|
|
if vulns[i].FixedVersion != "" {
|
|
vulns[i].Status = dbTypes.StatusFixed
|
|
} else if vulns[i].Status == dbTypes.StatusUnknown {
|
|
vulns[i].Status = dbTypes.StatusAffected
|
|
}
|
|
|
|
// Get the vulnerability detail
|
|
vulnID := vulns[i].VulnerabilityID
|
|
vuln, err := c.dbc.GetVulnerability(vulnID)
|
|
if err != nil {
|
|
log.Warn("Unable to get vulnerability details (CVE may be rejected)", log.Err(err))
|
|
continue
|
|
}
|
|
|
|
// Detect the data source
|
|
var source dbTypes.SourceID
|
|
if vulns[i].DataSource != nil {
|
|
source = vulns[i].DataSource.ID
|
|
}
|
|
|
|
// Select the severity according to the detected source.
|
|
severity, severitySource := c.getVendorSeverity(vulnID, &vuln, source)
|
|
|
|
// The vendor might provide package-specific severity like Debian.
|
|
// For example, CVE-2015-2328 in Debian has "unimportant" for mongodb and "low" for pcre3.
|
|
// In that case, we keep the severity as is.
|
|
if vulns[i].SeveritySource != "" {
|
|
severity = vulns[i].Severity
|
|
severitySource = vulns[i].SeveritySource
|
|
|
|
// Store package-specific severity in vendor severities
|
|
if vuln.VendorSeverity == nil {
|
|
vuln.VendorSeverity = make(dbTypes.VendorSeverity)
|
|
}
|
|
s, _ := dbTypes.NewSeverity(severity) // skip error handling because `SeverityUnknown` will be returned in case of error
|
|
vuln.VendorSeverity[severitySource] = s
|
|
}
|
|
|
|
// Add the vulnerability detail
|
|
vulns[i].Vulnerability = vuln
|
|
|
|
vulns[i].Severity = severity
|
|
vulns[i].SeveritySource = severitySource
|
|
vulns[i].PrimaryURL = c.getPrimaryURL(vulnID, vuln.References, source)
|
|
}
|
|
}
|
|
|
|
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
|
|
}
|
|
|
|
// use severity from GitHub for all GHSA-xxx vulnerabilities
|
|
if strings.HasPrefix(vulnID, "GHSA-") {
|
|
if vs, ok := vuln.VendorSeverity[vulnerability.GHSA]; ok {
|
|
return vs.String(), vulnerability.GHSA
|
|
}
|
|
}
|
|
|
|
// Try NVD as a fallback if it exists
|
|
if vs, ok := vuln.VendorSeverity[vulnerability.NVD]; ok {
|
|
return vs.String(), vulnerability.NVD
|
|
}
|
|
|
|
if vuln.Severity == "" {
|
|
return dbTypes.SeverityUnknown.String(), ""
|
|
}
|
|
|
|
return vuln.Severity, ""
|
|
}
|
|
|
|
func (c Client) getPrimaryURL(vulnID string, refs []string, source dbTypes.SourceID) string {
|
|
switch {
|
|
case strings.HasPrefix(vulnID, "CVE-"):
|
|
return "https://avd.aquasec.com/nvd/" + strings.ToLower(vulnID)
|
|
case strings.HasPrefix(vulnID, "RUSTSEC-"):
|
|
return "https://osv.dev/vulnerability/" + vulnID
|
|
case strings.HasPrefix(vulnID, "GHSA-"):
|
|
return "https://github.com/advisories/" + vulnID
|
|
case strings.HasPrefix(vulnID, "TEMP-"):
|
|
return "https://security-tracker.debian.org/tracker/" + vulnID
|
|
}
|
|
|
|
prefixes := primaryURLPrefixes[source]
|
|
for _, pre := range prefixes {
|
|
for _, ref := range refs {
|
|
if strings.HasPrefix(ref, pre) {
|
|
return ref
|
|
}
|
|
}
|
|
}
|
|
return ""
|
|
}
|