grype
grype copied to clipboard
False positives caused by mishandling CPE configuration logical operators
What happened:
Grype doesn't appear to be procesing CPE configurations correctly in the case where logical operators are used in NVD's CPE data. Specifically, when a CPE configuration has "AND"-ed nodes, Grype isn't respecting the "AND" requirement.
For example, we're seeing Grype match a private tomcat package to CVE-2016-5425, which looks like a false positive.
Here are the CPE match details from Grype's JSON output:
"matchDetails": [
{
"type": "cpe-match",
"matcher": "java-matcher",
"searchedBy": {
"namespace": "nvd:cpe",
"cpes": [
"cpe:2.3:a:apache:tomcat:8.5.87:*:*:*:*:*:*:*"
]
},
"found": {
"vulnerabilityID": "CVE-2016-5425",
"versionConstraint": "none (unknown)",
"cpes": [
"cpe:2.3:a:apache:tomcat:-:*:*:*:*:*:*:*"
]
}
}
],
Grype cites NVD as its data source for this match. But here's what the NVD data actually says:
"configurations": [
{
"operator": "AND",
"nodes": [
{
// ...
"criteria": "cpe:2.3:a:apache:tomcat:-:*:*:*:*:*:*:*",
// ...
},
{
"operator": "OR",
"negate": false,
"cpeMatch": [
{
"vulnerable": false,
"criteria": "cpe:2.3:a:oracle:instantis_enterprisetrack:17.1:*:*:*:*:*:*:*",
"matchCriteriaId": "82EA4BA7-C38B-4AF3-8914-9E3D089EBDD4"
},
{
"vulnerable": false,
"criteria": "cpe:2.3:a:oracle:instantis_enterprisetrack:17.2:*:*:*:*:*:*:*",
"matchCriteriaId": "B9C9BC66-FA5F-4774-9BDA-7AB88E2839C4"
(You can see the full data record at https://services.nvd.nist.gov/rest/json/cves/2.0?cveId=CVE-2016-5425.)
In other words, NVD isn't saying this vulnerability applies to any package with a CPE that matches cpe:2.3:a:apache:tomcat:-:*:*:*:*:*:*:*
— it's saying to match to this CPE only if one of these other CPEs applies to the scan target as well. In this case, all of these other CPEs refer to Red Hat or Oracle software, neither of which apply to the Wolfi/Chainguard distros.
What you expected to happen:
Grype shouldn't be reporting these kinds of matches, since they are provably false postives.
Environment:
- Output of
grype version
:
Application: grype
Version: 0.62.3
Syft Version: v0.83.0
BuildDate: 2023-06-05T21:34:29Z
GitCommit: 3865f4cc1dfcdcefbb7009400df153f24b18c772
GitDescription: v0.62.3
Platform: darwin/arm64
GoVersion: go1.19.9
Compiler: gc
Supported DB Schema: 5
- OS (e.g:
cat /etc/os-release
or similar): macOS
@westonsteimel curious if you have any thoughts here 😃
@luhring, we just recently added the platform-cpe package qualifer to help deselect these in specific simple cases though this one seems to fall outside that case. I think it's probably additional os that need handling in the conditions, but also changes to parsing necessary in the build of grype-db https://github.com/anchore/grype-db/blob/main/pkg/process/v5/transformers/nvd/unique_pkg.go#L66
I left it to a very narrow well-understood set of cases for the initial implementation
So for instance with CVE-2022-26488, we should now properly exclude this on anything that isn't windows. Here is the extract from the sqlite vulnerability table:
pk = 207153
id = CVE-2022-26488
package_name = python
namespace = nvd:cpe
package_qualifiers = [{"kind":"platform-cpe","cpe":"cpe:2.3:o:microsoft:windows:-:*:*:*:*:*:*:*"}]
version_constraint = <= 3.7.12 || >= 3.8.0, <= 3.8.12 || >= 3.9.0, <= 3.9.10 || >= 3.10.0, <= 3.10.2 || = 3.11.0 || = 3.11.0 || = 3.11.0 || = 3.11.0 || = 3.11.0 || = 3.11.0
version_format = unknown
cpes = ["cpe:2.3:a:python:python:*:*:*:*:*:*:*:*","cpe:2.3:a:python:python:3.11.0:alpha1:*:*:*:*:*:*","cpe:2.3:a:python:python:3.11.0:alpha2:*:*:*:*:*:*","cpe:2.3:a:python:python:3.11.0:alpha3:*:*:*:*:*:*","cpe:2.3:a:python:python:3.11.0:alpha4:*:*:*:*:*:*","cpe:2.3:a:python:python:3.11.0:alpha5:*:*:*:*:*:*","cpe:2.3:a:python:python:3.11.0:alpha6:*:*:*:*:*:*"]
related_vulnerabilities =
fixed_in_versions =
fix_state = unknown
advisories =
So for CVE-2016-5425 we'd need to split it into multiple vulnerability rows each with a different platform-cpe qualifier from the list on the entry, so that should be a change somewhere in https://github.com/anchore/grype-db/blob/main/pkg/process/v5/transformers/nvd/unique_pkg.go#L66
Hopefully that helps some. Here are the PR's for the original feature:
- https://github.com/anchore/grype/pull/1291
- https://github.com/anchore/grype-db/pull/103
That's cool! I hadn't seen the qualifier stuff.
And what you're saying makes sense, this needs to be accounted for in the Grype DB build.
We took at step in the direction @westonsteimel mentioned above with https://github.com/anchore/grype-db/pull/203, but I don't think it would fix this particular issue.
@luhring can you able to post a Dockerfile or SBOM or something that exhibits this particular false positive?
This was generated with wolfictl
which uses Syft. Piping this into grype
with GRYPE_MATCH_JAVA_USING_CPES=true
set seems to still exhibit this kind of false positive.
$ grype version
Application: grype
Version: 0.77.0
BuildDate: 2024-04-18T19:14:37Z
GitCommit: b7ffbeee53105478e699290aeac238a0ead28962
GitDescription: v0.77.0
Platform: darwin/arm64
GoVersion: go1.21.9
Compiler: gc
Syft Version: v1.2.0
Supported DB Schema: 5
A snippet from the DB for someone trying to grok this:
sqlite3 -header -column /Users/wagoodman/Library/Caches/grype/db/5/vulnerability.db 'select package_qualifiers,cpes from vulnerability where id == "CVE-2016-5425" and namespace LIKE "%cpe%";'
package_qualifiers cpes
------------------------------------------------------------------------------------------------- -------------------------------------------
[{"kind":"platform-cpe","cpe":"cpe:2.3:a:oracle:instantis_enterprisetrack:17.1:*:*:*:*:*:*:*"}] ["cpe:2.3:a:apache:tomcat:-:*:*:*:*:*:*:*"]
[{"kind":"platform-cpe","cpe":"cpe:2.3:a:oracle:instantis_enterprisetrack:17.2:*:*:*:*:*:*:*"}] ["cpe:2.3:a:apache:tomcat:-:*:*:*:*:*:*:*"]
[{"kind":"platform-cpe","cpe":"cpe:2.3:a:oracle:instantis_enterprisetrack:17.3:*:*:*:*:*:*:*"}] ["cpe:2.3:a:apache:tomcat:-:*:*:*:*:*:*:*"]
[{"kind":"platform-cpe","cpe":"cpe:2.3:o:oracle:linux:7:-:*:*:*:*:*:*"}] ["cpe:2.3:a:apache:tomcat:-:*:*:*:*:*:*:*"]
[{"kind":"platform-cpe","cpe":"cpe:2.3:o:redhat:enterprise_linux_desktop:7.0:*:*:*:*:*:*:*"}] ["cpe:2.3:a:apache:tomcat:-:*:*:*:*:*:*:*"]
[{"kind":"platform-cpe","cpe":"cpe:2.3:o:redhat:enterprise_linux_server:7.0:*:*:*:*:*:*:*"}] ["cpe:2.3:a:apache:tomcat:-:*:*:*:*:*:*:*"]
[{"kind":"platform-cpe","cpe":"cpe:2.3:o:redhat:enterprise_linux_server_aus:7.2:*:*:*:*:*:*:*"}] ["cpe:2.3:a:apache:tomcat:-:*:*:*:*:*:*:*"]
[{"kind":"platform-cpe","cpe":"cpe:2.3:o:redhat:enterprise_linux_server_aus:7.3:*:*:*:*:*:*:*"}] ["cpe:2.3:a:apache:tomcat:-:*:*:*:*:*:*:*"]
[{"kind":"platform-cpe","cpe":"cpe:2.3:o:redhat:enterprise_linux_server_aus:7.4:*:*:*:*:*:*:*"}] ["cpe:2.3:a:apache:tomcat:-:*:*:*:*:*:*:*"]
[{"kind":"platform-cpe","cpe":"cpe:2.3:o:redhat:enterprise_linux_server_aus:7.6:*:*:*:*:*:*:*"}] ["cpe:2.3:a:apache:tomcat:-:*:*:*:*:*:*:*"]
[{"kind":"platform-cpe","cpe":"cpe:2.3:o:redhat:enterprise_linux_server_aus:7.7:*:*:*:*:*:*:*"}] ["cpe:2.3:a:apache:tomcat:-:*:*:*:*:*:*:*"]
[{"kind":"platform-cpe","cpe":"cpe:2.3:o:redhat:enterprise_linux_server_eus:7.2:*:*:*:*:*:*:*"}] ["cpe:2.3:a:apache:tomcat:-:*:*:*:*:*:*:*"]
[{"kind":"platform-cpe","cpe":"cpe:2.3:o:redhat:enterprise_linux_server_eus:7.3:*:*:*:*:*:*:*"}] ["cpe:2.3:a:apache:tomcat:-:*:*:*:*:*:*:*"]
[{"kind":"platform-cpe","cpe":"cpe:2.3:o:redhat:enterprise_linux_server_eus:7.4:*:*:*:*:*:*:*"}] ["cpe:2.3:a:apache:tomcat:-:*:*:*:*:*:*:*"]
[{"kind":"platform-cpe","cpe":"cpe:2.3:o:redhat:enterprise_linux_server_eus:7.5:*:*:*:*:*:*:*"}] ["cpe:2.3:a:apache:tomcat:-:*:*:*:*:*:*:*"]
[{"kind":"platform-cpe","cpe":"cpe:2.3:o:redhat:enterprise_linux_server_eus:7.6:*:*:*:*:*:*:*"}] ["cpe:2.3:a:apache:tomcat:-:*:*:*:*:*:*:*"]
[{"kind":"platform-cpe","cpe":"cpe:2.3:o:redhat:enterprise_linux_server_eus:7.7:*:*:*:*:*:*:*"}] ["cpe:2.3:a:apache:tomcat:-:*:*:*:*:*:*:*"]
[{"kind":"platform-cpe","cpe":"cpe:2.3:o:redhat:enterprise_linux_server_tus:7.2:*:*:*:*:*:*:*"}] ["cpe:2.3:a:apache:tomcat:-:*:*:*:*:*:*:*"]
[{"kind":"platform-cpe","cpe":"cpe:2.3:o:redhat:enterprise_linux_server_tus:7.3:*:*:*:*:*:*:*"}] ["cpe:2.3:a:apache:tomcat:-:*:*:*:*:*:*:*"]
[{"kind":"platform-cpe","cpe":"cpe:2.3:o:redhat:enterprise_linux_server_tus:7.6:*:*:*:*:*:*:*"}] ["cpe:2.3:a:apache:tomcat:-:*:*:*:*:*:*:*"]
[{"kind":"platform-cpe","cpe":"cpe:2.3:o:redhat:enterprise_linux_server_tus:7.7:*:*:*:*:*:*:*"}] ["cpe:2.3:a:apache:tomcat:-:*:*:*:*:*:*:*"]
[{"kind":"platform-cpe","cpe":"cpe:2.3:o:redhat:enterprise_linux_workstation:7.0:*:*:*:*:*:*:*"}] ["cpe:2.3:a:apache:tomcat:-:*:*:*:*:*:*:*"]
Agreed there are a couple things wrong:
- we have platform CPEs for
a
CPE types (applications) - there are application CPEs in the node configuration that is not present in the CPEs column in the DB