github.com/devseccon/trivy@v0.47.1-0.20231123133102-bd902a0bd996/pkg/vulnerability/vulnerability.go (about) 1 package vulnerability 2 3 import ( 4 "strings" 5 6 "github.com/google/wire" 7 8 "github.com/aquasecurity/trivy-db/pkg/db" 9 dbTypes "github.com/aquasecurity/trivy-db/pkg/types" 10 "github.com/aquasecurity/trivy-db/pkg/vulnsrc/vulnerability" 11 "github.com/devseccon/trivy/pkg/log" 12 "github.com/devseccon/trivy/pkg/types" 13 ) 14 15 var ( 16 primaryURLPrefixes = map[dbTypes.SourceID][]string{ 17 vulnerability.Debian: { 18 "http://www.debian.org", 19 "https://www.debian.org", 20 }, 21 vulnerability.Ubuntu: { 22 "http://www.ubuntu.com", 23 "https://usn.ubuntu.com", 24 }, 25 vulnerability.RedHat: {"https://access.redhat.com"}, 26 vulnerability.SuseCVRF: { 27 "http://lists.opensuse.org", 28 "https://lists.opensuse.org", 29 }, 30 vulnerability.OracleOVAL: { 31 "http://linux.oracle.com/errata", 32 "https://linux.oracle.com/errata", 33 }, 34 vulnerability.NodejsSecurityWg: { 35 "https://www.npmjs.com", 36 "https://hackerone.com", 37 }, 38 vulnerability.RubySec: {"https://groups.google.com"}, 39 } 40 ) 41 42 // SuperSet binds the dependencies 43 var SuperSet = wire.NewSet( 44 wire.Struct(new(db.Config)), 45 wire.Bind(new(db.Operation), new(db.Config)), 46 NewClient, 47 ) 48 49 // Client manipulates vulnerabilities 50 type Client struct { 51 dbc db.Operation 52 } 53 54 // NewClient is the factory method for Client 55 func NewClient(dbc db.Operation) Client { 56 return Client{dbc: dbc} 57 } 58 59 // FillInfo fills extra info in vulnerability objects 60 func (c Client) FillInfo(vulns []types.DetectedVulnerability) { 61 for i := range vulns { 62 // Add the vulnerability status 63 // Some vendors such as Red Hat have their own vulnerability status, and we use it. 64 // Otherwise, we put "fixed" or "affected" according to the fixed version. 65 if vulns[i].FixedVersion != "" { 66 vulns[i].Status = dbTypes.StatusFixed 67 } else if vulns[i].Status == dbTypes.StatusUnknown { 68 vulns[i].Status = dbTypes.StatusAffected 69 } 70 71 // Get the vulnerability detail 72 vulnID := vulns[i].VulnerabilityID 73 vuln, err := c.dbc.GetVulnerability(vulnID) 74 if err != nil { 75 log.Logger.Warnf("Error while getting vulnerability details: %s", err) 76 continue 77 } 78 79 // Detect the data source 80 var source dbTypes.SourceID 81 if vulns[i].DataSource != nil { 82 source = vulns[i].DataSource.ID 83 } 84 85 // Select the severity according to the detected source. 86 severity, severitySource := c.getVendorSeverity(vulnID, &vuln, source) 87 88 // The vendor might provide package-specific severity like Debian. 89 // For example, CVE-2015-2328 in Debian has "unimportant" for mongodb and "low" for pcre3. 90 // In that case, we keep the severity as is. 91 if vulns[i].SeveritySource != "" { 92 severity = vulns[i].Severity 93 severitySource = vulns[i].SeveritySource 94 95 // Store package-specific severity in vendor severities 96 if vuln.VendorSeverity == nil { 97 vuln.VendorSeverity = make(dbTypes.VendorSeverity) 98 } 99 s, _ := dbTypes.NewSeverity(severity) // skip error handling because `SeverityUnknown` will be returned in case of error 100 vuln.VendorSeverity[severitySource] = s 101 } 102 103 // Add the vulnerability detail 104 vulns[i].Vulnerability = vuln 105 106 vulns[i].Severity = severity 107 vulns[i].SeveritySource = severitySource 108 vulns[i].PrimaryURL = c.getPrimaryURL(vulnID, vuln.References, source) 109 } 110 } 111 112 func (c Client) getVendorSeverity(vulnID string, vuln *dbTypes.Vulnerability, source dbTypes.SourceID) (string, dbTypes.SourceID) { 113 if vs, ok := vuln.VendorSeverity[source]; ok { 114 return vs.String(), source 115 } 116 117 // use severity from GitHub for all GHSA-xxx vulnerabilities 118 if strings.HasPrefix(vulnID, "GHSA-") { 119 if vs, ok := vuln.VendorSeverity[vulnerability.GHSA]; ok { 120 return vs.String(), vulnerability.GHSA 121 } 122 } 123 124 // Try NVD as a fallback if it exists 125 if vs, ok := vuln.VendorSeverity[vulnerability.NVD]; ok { 126 return vs.String(), vulnerability.NVD 127 } 128 129 if vuln.Severity == "" { 130 return dbTypes.SeverityUnknown.String(), "" 131 } 132 133 return vuln.Severity, "" 134 } 135 136 func (c Client) getPrimaryURL(vulnID string, refs []string, source dbTypes.SourceID) string { 137 switch { 138 case strings.HasPrefix(vulnID, "CVE-"): 139 return "https://avd.aquasec.com/nvd/" + strings.ToLower(vulnID) 140 case strings.HasPrefix(vulnID, "RUSTSEC-"): 141 return "https://osv.dev/vulnerability/" + vulnID 142 case strings.HasPrefix(vulnID, "GHSA-"): 143 return "https://github.com/advisories/" + vulnID 144 case strings.HasPrefix(vulnID, "TEMP-"): 145 return "https://security-tracker.debian.org/tracker/" + vulnID 146 } 147 148 prefixes := primaryURLPrefixes[source] 149 for _, pre := range prefixes { 150 for _, ref := range refs { 151 if strings.HasPrefix(ref, pre) { 152 return ref 153 } 154 } 155 } 156 return "" 157 }