I’m encountering an issue with Grype where the database entry for certain CVEs doesn’t align with the artifact details returned by Grype. For example, in CVE-2023-2953, the package name is listed as libldap-2_4-2 in the database, but the artifact Grype returns looks like this:
As you can see, the database uses libldap-2_4-2 while Grype returns libldap-2.4-2. This discrepancy is causing issues when I try to match records. Does anyone know why this mismatch is occurring or have any suggestions on how to handle it?
Grype gets artifacts by invoking Syft, which inspects the source being scanned (a container image, directory, archive, etc). So if the artifact’s name is libldap-2.4-2 in the scan results, it’s because in the image that’s what RPM or dpkg or whatever list as the name of the thing installed. libldap-2_4-2 is the name in the database because that’s the name that some vulnerability provider published. It’s possible for the people who published the CVE and the people who published the software to disagree on how to name it.
This situation is one of the reasons that we consider the best source for vulnerability matching to be the distro-specific vulnerability feed for the image being scanned. For example, if Debian or Ubuntu or Red Hat publish CVE-2023-2953 in their vulnerability data, and also publish a libldab dpkg or rpm, they are likely to use the same package name for in both places. One of the challenges with NVD’s data is that the strings in the CPE are made up by NVD or whoever submitted the CVE there, and so might have this sort of name mismatch.
(It’s also possible we have a bug somewhere, but I don’t have enough information yet to speak to that.)
Are you scanning an image? If so, make sure Grype is identifying the Linux distro it is built from correctly. For example:
Which looks right. If Grype is wrong about the distro, you can try passing --distro name:version to it, which will help it compare the right package names. (Also, if that fixes your issue, please open an issue against Syft that we’re mis-identifying a distro).
Beyond that, I don’t really have any suggestions without more information about the scan being performed. Can you share a minimal Dockerfile that reproduces the issue? Can you tell me what kind of artifact you are scanning (I assume an image)? Can you tell me what distro the image is built from?
Right now, I’m working with the Grype database directly rather than scanning a specific image. I’ve set up a database from Grype’s data and am using package names in the database to match and display vulnerability information based on the artifact object. While working on this, I noticed the inconsistency between package names in the database (like libldap-2_4-2) and what Grype identifies in the artifact object (libldap-2.4-2), so I wanted to understand if there was an underlying reason for this mismatch.
I don’t currently have a specific Docker image or real-world case to reproduce this issue in a scan context, though I may look into finding one to test. For now, though, this is just based on what I observed in the Grype DB.
Thanks again for helping clarify how these names might differ due to data sources and package naming.
Can I ask one more question related to this thread?
I’ve noticed that some results from Grype include CVEs and package names that don’t appear in the main vulnerability table. Is it possible for Grype to return matches like this? If so, could you explain the logic or matching process behind it? Feel free to point me to the relevant code or just give a brief explanation.
Thanks!
Update:
I think i found the missing info it’s in Syft, it’s the upstream matching, can i still get more info about it?
You’re right, this is probably upstream matching. Many vulnerability providers report vulnerabilities against a source RPM for example. This match type will be listed as exact-indirect-match in Grype’s JSON output: this means that the package Syft found has as its source RPM a vulnerable package.
You can see more information about these matches by piping Grype’s JSON output into grype explain like this:
Thank you that really helped understand the process
Another case i have is with cves like CVE-2024-24787 which have upstream set as empty in Syft and is still looking for package stdlib however there is no such package assigned to that CVE in Grype DB this causes a mismatch for me
Is that normal? should Syft perhaps skip cves where the status is awaiting? should Grype perhaps not include cves which are awaiting in it’s vulnerability table?
I’m not sure I understand your question. I think what you’re saying is this:
I did a Grype scan and it found CVE-2024-24787 against a package called stdlib
But Syft doesn’t list an upstream package on the stdlib package, so this not one of the exact-indirect-match situations we talked about previuosly
The database doesn’t have a package called stdlib, so how is Grype making this match?
I’m going to assume that’s the question you’re asking and answer it. Please let me know if I answered the wrong question
CVE-2024-24787 is a reported against Go itself. Whenever Go builds a binary, there is a copy of the Go runtime in that library. Syft represents this as a package called stdlib.
This Go stdlib package is, by default, matched against NVD data via CPE. The reason for this is that vulnerabilities reported against the language itself are not reported in GHSA, and it is likely not possible to associate any distro feed with this Go runtime, so we have to fall back to CPE matching.
In this particular case, by running the query select id, package_name, cpes, version_constraint from vulnerability where id = "CVE-2024-24787" and namespace = "nvd:cpe" against today’s grype db, we can see the match we’re getting is against this row:
id
package_name
cpes
version_constraint
CVE-2024-24787
go
[“cpe:2.3:a:golang:go::::::::”]
< 1.21.10
I believe if you look on your Syft JSON for the CPE on the package called “stdlib”, you’ll see a CPE like "cpe:2.3:a:golang:go:*:*:*:*:*:*:*:*". So the stdlib is the runtime component of the Go toolchain copied into the binary, and the vulnerability is against the Go tool chain.
Thanks to your explanation and the details provided, I realized that the default configuration for Golang has always-use-cpe-for-stdlib set to true. This was the root cause of the issue I faced with the package. Specifically, for the CVE I mentioned, I provided the artifact as stdlib instead of go. After changing the setting to false, it now behaves as expected.
I do have one remaining question: all other languages have this setting defaulted to false. Why is Golang treated differently, with this default set to true?
This is not quite correct. Every language, including Go, has match.<language>.using-cpes default to false. However, Go has an additional setting always-use-cpes-for-stdlib which defaults to true. In other words, Grype, by default, will use GHSA name+version matching for all Go packages except the standard library, and will use CPE matching for the standard library.
There are a few reasons for this:
The Go compiler statically links a copy of the Go standard library into every executable compiled with Go. Additionally, Go binaries include metadata about which packages are linked into them. This means that whenever Syft/Grype find a Go binary, they find a copy of the go stdlib at a particular version.
GHSA doesn’t report advisories that affect the Go toolchain and stdlib themselves, because GHSA only reports language libraries, not binaries, and so vulnerabilities are not reported against the Go toolchain.
The combined effect of these two situations is that Syft/Grype often find a package that’s the Go stdlib in an image, and have no source for vulns against this package besides CPE matching against NVD data.
The situation is sort of similar to scanning JARs and Java runtimes. By default, Grype with match JARs against GHSA data, because language libraries are well supported by this data. However, if we find a Java runtime environment, we cannot match it against GHSA, and have to match it against CPEs. The difference is that the Java runtime is a binary package, and so is matched against CPEs by default anyway, whereas the Go stdlib is a Go package, and so needs to be special cased in Grype’s config.
Turning always-use-cpe-for-stdlib will stop matches where packages named stdlib match against CVEs against Go, but please know that turning this setting off will cause some false negatives. If there’s a CPE reported against the Go project, that is a bug in the runtime library, Grype will not be able to find it if this setting is false, which is why it defaults to true.