8000 feat: add `--vuln-severity-source` flag by DmitriyLewen · Pull Request #8269 · aquasecurity/trivy · GitHub
[go: up one dir, main page]

Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add --vuln-severity-source flag #8269

Merged
merged 24 commits into from
Mar 3, 2025

Conversation

DmitriyLewen
Copy link
Contributor
@DmitriyLewen DmitriyLewen commented Jan 21, 2025

Description

Add --vuln-severity-source flag to set db sources order for vulnerability severity.

If severities didn't found in this list - use UNKNOWN severity + show Warning about that.

Examples:

  "VendorSeverity": {
    "azure": 2,
    "cbl-mariner": 2,
    "nvd": 2,
    "redhat": 2,
    "ubuntu": 1
  },

auto (default) mode:

➜ ./trivy -q --vuln-severity-source auto image ubuntu -f json  | jq '.Results[].Vulnerabilities[] | select(.VulnerabilityID=="CVE-2016-2781") | "SeveritySource: \(.SeveritySource); Severity \(.Severity)"'
"SeveritySource: ubuntu; Severity LOW"

severity from another source (nvd):

➜  ./trivy -q --vuln-severity-source alpine,nvd image ubuntu -f json  | jq '.Results[].Vulnerabilities[] | select(.VulnerabilityID=="CVE-2016-2781") | "SeveritySource: \(.SeveritySource); Severity \(.Severity)"'
"SeveritySource: nvd; Severity MEDIUM"

severity didn't found:

➜ ./trivy --vuln-severity-source alpine,alma image ubuntu -f json  | jq '.Results[].Vulnerabilities[] | select(.VulnerabilityID=="CVE-2016-2781") | "SeveritySource: \(.SeveritySource); Severity \(.Severity)"'
...
2025-02-25T16:20:15+06:00       WARN    No severity found in specified sources  vulnerability-ids=[CVE-2016-2781 CVE-2022-3219 CVE-2016-20013 CVE-2025-0395 CVE-2016-20013 CVE-2025-0395 CVE-2025-1390 CVE-2024-12243 CVE-2024-9143 CVE-2024-41996 CVE-2024-13176 CVE-2024-12133 CVE-2024-56433 CVE-2024-56433] severity-sources=[alpine alma]
"SeveritySource: null; Severity UNKNOWN"

Related issues

Related PRs

Checklist

  • I've read the guidelines for contributing to this repository.
  • I've followed the conventions in the PR title.
  • I've added tests that prove my fix is effective or that my feature works.
  • I've updated the documentation with the relevant information (if needed).
  • I've added usage information (if the PR introduces new options)
  • I've included a "before" and "after" example to the description (if the PR is a user interface change).

@DmitriyLewen DmitriyLewen self-assigned this Jan 21, 2025
}
}
if len(severitySrc) != 1 || severitySrc[0] != "auto" {
log.Warn("No severity found in specified sources",
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know these logs may be noise, but warnings should be rare occurrences and we should draw the user's attention to each vulnerability.

But we can also show the warning once and use debug logs for each vulnerability:

2025-01-22T15:47:14+06:00       WARN    For one or more vulnerabilities, the severity level is not found in the specified sources
2025-01-22T15:47:14+06:00       DEBUG   No severity found in specified sources  vulnID="CVE-2016-2781" severity sources="alpine,alma"
2025-01-22T15:47:14+06:00       DEBUG   No severity found in specified sources  vulnID="CVE-2022-3219" severity sources="alpine,alma"
2025-01-22T15:47:14+06:00       DEBUG   No severity found in specified sources  vulnID="CVE-2016-20013" severity sources="alpine,alma"
2025-01-22T15:47:14+06:00       DEBUG   No severity found in specified sources  vulnID="CVE-2016-20013" severity sources="alpine,alma"
2025-01-22T15:47:14+06:00       DEBUG   No severity found in specified sources  vulnID="CVE-2024-41996" severity sources="alpine,alma"
2025-01-22T15:47:14+06:00       DEBUG   No severity found in specified sources  vulnID="CVE-2024-56433" severity sources="alpine,alma"
2025-01-22T15:47:14+06:00       DEBUG   No severity found in specified sources  vulnID="CVE-2024-56433" severity sources="alpine,alma"

@@ -105,6 +105,7 @@ trivy image [flags] IMAGE_NAME
--secret-config string specify a path to config file for secret scanning (default "trivy-secret.yaml")
--server string server address in client mode
-s, --severity strings severities of security issues to be displayed (UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL) (default [UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL])
--severity-src strings order of data sources for selecting vulnerability severity level (nvd,redhat,redhat-oval,debian,ubuntu,alpine,amazon,oracle-oval,suse-cvrf,photon,arch-linux,alma,rocky,cbl-mariner,azure,ruby-advisory-db,php-security-advisories,nodejs-security-wg,ghsa,glad,aqua,osv,k8s,wolfi,chainguard,bitnami,govulndb,auto) (default [auto])
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line is very long, but I wanted to immediately stop Trivy for the incorrect sourceID.

@DmitriyLewen
Copy link
Contributor Author

@knqyf263 I think this PR is ready for review.
Take a look when you have time.

If you don't have comments about trivy-db changes - we can merge aquasecurity/trivy-db#485.
After merging aquasecurity/trivy-db#485 - I will change the status of this PR to ready for review

@DmitriyLewen DmitriyLewen marked this pull request as ready for review January 24, 2025 07:31
@@ -30,19 +32,30 @@ var (
ConfigName: "vulnerability.skip-vex-repo-update",
Usage: `[EXPERIMENTAL] Skip VEX Repository update`,
}
SeveritySrcFlag = Flag[[]string]{
Name: "severity-src",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, we have several types of findings, like misconfigurations, while this flag is dedicated to vulnerabilities. Is --vuln-severity-src better? Do you have any other ideas?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for non-vuln findings only one source is available.
So I think you are right. We should use the vuln prefix to avoid confusion for the user.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changed in 0f42477

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We also need to update the PR title and description.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm kind of absent-minded today...
thanks! I updated!

}

type VulnerabilityOptions struct {
IgnoreStatuses []dbTypes.Status
VEXSources []vex.Source
SkipVEXRepoUpdate bool
SeveritySrc []string
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
SeveritySrc []string
SeveritySources []dbTypes.SourceID

@@ -101,5 +116,6 @@ func (f *VulnerabilityFlagGroup) ToOptions() (VulnerabilityOptions, error) {
return vex.NewSource(s)
}),
SkipVEXRepoUpdate: f.SkipVEXRepoUpdate.Value(),
SeveritySrc: f.SeveritySrc.Value(),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer using the explicit type. Is there any advantage of using string?

Suggested change
SeveritySrc: f.SeveritySrc.Value(),
SeveritySources: xstrings.ToTSlice[dbTypes.SourceID](f.SeveritySources.Value()),

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also tried to use dbTypes.SourceID.

But we are using auto value. I think using auto for SourceID is wrong because it is logic and not source.

Copy link
Collaborator
@knqyf263 knqyf263 Feb 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's fine. Most of them are source ids. Also, auto can be passed as an argumet of --severity-src.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

okay, i will update logic 👍

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done - 2999049

return dbTypes.SeverityUnknown.String(), ""
}

func (c Client) severityInAutoMode(vulnID string, vuln *dbTypes.Vulnerability, dataSource dbTypes.DataSource) (string, dbTypes.SourceID) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think of re-using getSeverity for auto-detection?

diff --git a/pkg/vulnerability/vulnerability.go b/pkg/vulnerability/vulnerability.go
index 5391419b5..710243400 100644
--- a/pkg/vulnerability/vulnerability.go
+++ b/pkg/vulnerability/vulnerability.go
@@ -1,6 +1,7 @@

9E81
 package vulnerability
 
 import (
+	"slices"
 	"strings"
 	"sync"
 
@@ -67,7 +68,8 @@ func NewClient(dbc db.Operation) Client {
 }
 
 // FillInfo fills extra info in vulnerability objects
-func (c Client) FillInfo(vulns []types.DetectedVulnerability, severitySrc []string) {
+func (c Client) FillInfo(vulns []types.DetectedVulnerability, severitySources []dbTypes.SourceID) {
+	var noSeverityIDs []string
 	for i := range vulns {
 		// Add the vulnerability status
 		// Some vendors such as Red Hat have their own vulnerability status, and we use it.
@@ -90,7 +92,10 @@ func (c Client) FillInfo(vulns []types.DetectedVulnerability, severitySrc []stri
 		dataSource := lo.FromPtr(vulns[i].DataSource)
 
 		// Select the severity according to the detected sourceID.
-		severity, severitySource := c.getSeverity(vulnID, &vuln, dataSource, severitySrc)
+		severity, severitySource := c.getSeverity(vulnID, &vuln, dataSource, severitySources)
+		if severity == dbTypes.SeverityUnknown.String() {
+			noSeverityIDs = append(noSeverityIDs, vulnID)
+		}
 
 		// The vendor might provide package-specific severity like Debian.
 		// For example, CVE-2015-2328 in Debian has "unimportant" for mongodb and "low" for pcre3.
@@ -114,42 +119,43 @@ func (c Client) FillInfo(vulns []types.DetectedVulnerability, severitySrc []stri
 		vulns[i].SeveritySource = severitySource
 		vulns[i].PrimaryURL = c.getPrimaryURL(vulnID, vuln.References, dataSource.ID)
 	}
+
+	if !slices.Contains(severitySources, "auto") && len(noSeverityIDs) > 0 {
+		log.Warn("No severity found in specified sources",
+			log.Any("vulnerability-ids", noSeverityIDs), log.Any("severity-sources", severitySources))
+	}
 }
 
-func (c Client) getSeverity(vulnID string, vuln *dbTypes.Vulnerability, dataSource dbTypes.DataSource, severitySrc []string) (string, dbTypes.SourceID) {
-	for _, source := range severitySrc {
+func (c Client) getSeverity(vulnID string, vuln *dbTypes.Vulnerability, dataSource dbTypes.DataSource, severitySources []dbTypes.SourceID) (string, dbTypes.SourceID) {
+	for _, source := range severitySources {
 		if source == "auto" {
-			return c.severityInAutoMode(vulnID, vuln, dataSource)
+			return c.autoDetectSeverity(vulnID, vuln, dataSource)
 		}
 
-		sourceID := dbTypes.SourceID(source)
-
-		if severity, ok := vuln.VendorSeverity[sourceID]; ok {
-			return severity.String(), sourceID
+		if severity, ok := vuln.VendorSeverity[source]; ok {
+			return severity.String(), source
 		}
 	}
-	if len(severitySrc) != 1 || severitySrc[0] != "auto" {
-		log.Warn("No severity found in specified sources",
-			log.String("vulnID", vulnID), log.String("severity sources", strings.Join(severitySrc, ",")))
-	}
 	return dbTypes.SeverityUnknown.String(), ""
 }
 
-func (c Client) severityInAutoMode(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
+// autoDetectSeverity detects the severity from the vulnerability ID and data source.
+//
+// The severity is determined in the following order:
+//  1. If the vulnerability is from a specific data source (e.g., Red Hat advisories for Red Hat distributions),
+//     use the severity from that data source.
+//  2. For GHSA-IDs, also consider the severity from GitHub Advisory Database.
+//  3. Use the severity from NVD as a fallback.
+//  4. Try severities from other data sources (e.g., Debian severity for Red Hat distributions).
+//  5. If no severity is found from any data source, return "UNKNOWN".
+func (c Client) autoDetectSeverity(vulnID string, vuln *dbTypes.Vulnerability, dataSource dbTypes.DataSource) (string, dbTypes.SourceID) {
+	autoSeveritySrcs := []dbTypes.SourceID{dataSource.ID, vulnerability.NVD}
 	if strings.HasPrefix(vulnID, "GHSA-") {
-		if vs, ok := vuln.VendorSeverity[vulnerability.GHSA]; ok {
-			return vs.String(), vulnerability.GHSA
-		}
+		// use severity from GitHub for all GHSA-IDs
+		autoSeveritySrcs = append(autoSeveritySrcs, vulnerability.GHSA, vulnerability.NVD)
 	}
-
-	// Try NVD as a fallback if it exists
-	if vs, ok := vuln.VendorSeverity[vulnerability.NVD]; ok {
-		return vs.String(), vulnerability.NVD
+	if severity, severitySource := c.getSeverity(vulnID, vuln, dataSource, autoSeveritySrcs); severity != dbTypes.SeverityUnknown.String() {
+		return severity, severitySource
 	}
 
 	if vuln.Severity == "" {

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks good.
I used your changes - 413b047
But fixed priority for GHSA

@DmitriyLewen DmitriyLewen changed the title feat: add --severity-src flag feat: add --vuln-severity-src flag Feb 25, 2025
@knqyf263
Copy link
Collaborator

It might be necessary to establish clear guidelines for naming CLI flags. When we want to explicitly indicate that multiple values can be passed, we tend to use the plural form. However, there are cases where this convention isn’t followed consistently.

For example, consider the following flags, which accept multiple values, yet one is named in the plural and the other in the singular. This presents a good opportunity to standardize our naming:

      --sbom-sources strings        [EXPERIMENTAL] try to retrieve SBOM from the specified sources (oci,rekor)
      --image-src strings               image source(s) to use, in priority order (docker,containerd,podman,remote) (default [docker,containerd,podman,remote])

There are several options:

  • --vuln-severity-src
  • --vuln-severity-srcs
  • --vuln-severity-source
  • --vuln-severity-sources

I examined other tools, and the conventions vary between them. For instance, Docker consistently uses the singular form:

  -e, --env list                         Set environment variables
      --cap-add list                     Add Linux capabilities
      --cap-drop list                    Drop Linux capabilities

In contrast, the AWS CLI always uses the plural form for list inputs:

       --instance-ids (list)
          The instance IDs.

Kubectl shows mixed usage; for example, although the --filename flag accepts multiple values, it is named in the singular form:

    -f, --filename=[]:
    -L, --label-columns=[]:

Personally, I don't have a strong preference either way, but I believe it would be beneficial to have a consistent rule within our project. For example, between --severity and --severities, --severity might initially seem preferable to me, though that might simply be due to the visual impact of the "ies" ending. Both --pkg-type and --pkg-types appear acceptable. Since these choices are entirely subjective, I’d like to hear your opinions on this matter.

@DmitriyLewen
Copy link
Contributor Author

only after seeing your message I noticed that we use the full and shortened suffix (source|src).
I think that this case should also be considered and one "standard" should be used, because it can be more confusing than the plural form (I mean source|sources).


I think plural is more clear. User immediately understands that flag can have multiple values.
But I didn't think about it until your question (e.g., I used --db-repository with multiple repositories without thinking). So I wouldn't say that plural is better form for me.

On the other hand (I could be wrong) - when you use multiple flags - you want the flag names to be as short as possible, so they are easier to paste into the terminal and take up less space (easier to read/check). (But Trivy has config file for case, when user uses many flags)

But regardless of form - I like idea of ​​adding standard for flag names.
It will make flags more convenient and readable. And I also like consistency and order.
It may also reduce some of the hesitation about the new flag name.

@knqyf263
Copy link
Collaborator

Opened #8446

@knqyf263
Copy link
Collaborator
knqyf263 commented Feb 27, 2025

Following #8453 I proposed, --vuln-severity-sources is better. We still need to discuss --vuln-severity-source and --vuln-severity-sources, though (cf. #8446 (comment)).

@knqyf263
Copy link
Collaborator
knqyf263 commented Mar 3, 2025

I suppose our team doesn't have a strong opinion on that and will agree on the proposal. Can you please update the flag to --vuln-severity-source? Even if we don't agree on that and prefer plural, it's not the end of the world 😄 Note that I like using plural in source code, like VulnSeveritySource"s".

@knqyf263 knqyf263 changed the title feat: add --vuln-severity-src flag feat: add --vuln-severity-source flag Mar 3, 2025
Copy link
Collaborator
@knqyf263 knqyf263 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, need to update the PR description.

@DmitriyLewen
Copy link
Contributor Author

Thanks, updated 👍

@DmitriyLewen DmitriyLewen added this pull request to the merge queue Mar 3, 2025
Merged via the queue into aquasecurity:main with commit d464807 Mar 3, 2025
19 checks passed
@DmitriyLewen DmitriyLewen deleted the feat/severity-src branch March 3, 2025 11:15
@aqua-bot aqua-bot mentioned this pull request Mar 3, 2025
dstrelbytskyi pushed a commit to datarobot/trivy that referenced this pull request Mar 5, 2025
dstrelbytskyi pushed a commit to datarobot/trivy that referenced this pull request Mar 10, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

feat: add --vuln-severity-source flag to customize vulnerability severity selection
2 participants
0