Clarification about ELSA reports returned by Grype

Hi,

Grype is returning ELSA entries, but as I understand it, ELSA reports are not actual vulnerabilities themselves. Instead, they are advisories that may reference multiple vulnerabilities (CVEs) and may apply to multiple packages.
So, ELSA itself is not a CVE or a vulnerability.

Given that, how should we interpret CVEs that are referenced by an ELSA?
Does every CVE listed in an ELSA necessarily affect the package affected by that specific ELSA, or not?

Thanks in advance for your help!

1 Like

Hi @enzofrnt!

I think there’s a bit of nuance here that you astutely noticed. ELSA records are advisories, rather than the vulnerability disclosure – it’s specifying what is fixed. We put these records in Grype DB to have accurate fix information and this fix information is also used to determine that certain pacakges are, in fact vulnerable. Grype is returning ELSA IDs when this is the source used to determine a package is vulnerable, but each ELSA record can indicate that multiple CVEs have been fixed. For this, we don’t transform the record to indicate multiple CVEs but rather show the ELSA record as an indication that everything it references is applicable to the package in question.

In other words: yes, every CVE listed in the ELSA record does affect the package.

Hi,

Thanks for your response. I believe I understood everything you explained. In my case, I’m using Grype to populate a database with vulnerabilities affecting my products. Then, I establish relationships between packages and vulnerabilities—or more precisely, between packages and fixes, due to how ELSAs work.

However, I only want to include actual vulnerabilities in my database. Initially, I decided to retrieve every CVE listed in an ELSA and associate each CVE with the package affected by that ELSA. However, this approach resulted in approximately 7,000 relationships—essentially 7,000 “applicable vulnerabilities” for my product—which seemed excessive.

I believe this method (and this is where I disagree with your earlier explanation) creates associations between CVEs and packages that may not actually be affected by those specific CVEs. This issue is exacerbated by the fact that a single ELSA can appear multiple times across different packages in Grype’s output. Maybe I didn’t express myself clearly before, but what I meant is that not every CVE listed in an ELSA is relevant to every package referenced by that ELSA. Instead, each CVE listed within an ELSA likely relates to at least one affected package—but probably not to all of them. Would you agree with this assessment?

That’s why I suspect not every CVE included in an ELSA is directly relevant to every package marked as affected in Grype’s JSON output.

Does this clarify my point?

After our exchange, I did some further research and discovered the -by-cve option in Grype, which appears to resolve my issue. Now, I almost exclusively retrieve CVEs, which aligns precisely with my requirements. However, I’m concerned about potentially losing important data by using this option—specifically, I’m worried about missing actual vulnerabilities (not fixes or other types of data). The difference is significant: previously, my method identified around 7,000 applicable vulnerabilities, whereas now I’m seeing roughly 1,300.

Could you confirm whether I’m potentially missing important vulnerability data by using the -by-cve option or not ?

Thanks a lot!

To start with an answer to your question: we had a detailed look at what --by-cve is doing to make sure it was the right suggestion and, unfortunately, think it’s probably doing something wrong: only taking the first associated CVE and dropping the others, and you would be, in fact, losing data.

This is where things get a little unclear to me, and it’s the same question you have: if an ELSA fixes multiple CVEs, does it mean any package updated by the ELSA means they are vulnerable to every CVE? From the data we have in Grype DB, we can’t differentiate anything beyond this, and we have to assume that every CVE is, in fact, applicable. This probably isn’t what you wanted to hear, but this is the current state of ELSA processing, Grype DB, and Grype matching.

I think there are 2 potential things we could do to make this more accurate and granular:

1. adjust the provider to create multiple ELSA records at ingestion time, one for each package affected and only associate the appropriate CVE that would make the correct package, but this doesn’t seem as though it’s happening today.

The Vunnel provider responsible for reading the ELSA data is here: vunnel/src/vunnel/providers/oracle/parser.py at main · anchore/vunnel · GitHub

And if I look at some of the ELSA records, however, I don’t see how we can figure out anything more granular about CVE associations directly from this data; is there something I’m missing – maybe a different data source we should be using?

<definition id="oval:com.oracle.elsa:def:20252673" version="501" class="patch">
<metadata>
<title>
ELSA-2025-2673:  libxml2 security update (IMPORTANT)
</title>
<affected family="unix">
<platform>Oracle Linux 7</platform>

</affected>
<reference source="elsa" ref_id="ELSA-2025-2673" ref_url="https://linux.oracle.com/errata/ELSA-2025-2673.html"/>
<reference source="CVE" ref_id="CVE-2024-56171" ref_url="https://linux.oracle.com/cve/CVE-2024-56171.html"/>
<reference source="CVE" ref_id="CVE-2025-24928" ref_url="https://linux.oracle.com/cve/CVE-2025-24928.html"/>

<description>
[2.9.1-6.0.5]
- Fix CVE-2024-56171  [Orabug: 37694105]
- Fix CVE-2025-24928  [Orabug: 37694105]
...
[2.9.1-6.5]
- Fix CVE-2019-19956 (#1793000)
- Fix CVE-2019-20388 (#1810057)
- Fix CVE-2020-7595 (#1810073)
- Fix xsd:any schema validation (#1812145)
...
- upstream release 2.6.25 broken, do not ship !
</description>
<advisory>
<severity>IMPORTANT</severity>
<rights>Copyright 2025 Oracle, Inc.</rights>
<issued date="2025-03-20"/>
<cve cvss3="8.1/CVSS:3.1/AV:L/AC:H/PR:N/UI:N/S:C/C:H/I:H/A:H" href="https://linux.oracle.com/cve/CVE-2024-56171.html" public="20250218">CVE-2024-56171</cve>
<cve cvss3="7.8/CVSS:3.1/AV:L/AC:H/PR:N/UI:N/S:C/C:H/I:H/A:N" href="https://linux.oracle.com/cve/CVE-2025-24928.html" public="20250218">CVE-2025-24928</cve>

<affected_cpe_list>
<cpe>cpe:/a:oracle:linux:7:9:latest_ELS</cpe>
</affected_cpe_list>
</advisory>
</metadata>
<criteria operator="AND">
<criterion test_ref="oval:com.oracle.elsa:tst:20252673001" comment="Oracle Linux 7 is installed"/>
<criteria operator="AND">
<criterion test_ref="oval:com.oracle.elsa:tst:20252673002" comment="Oracle Linux arch is x86_64"/>
<criteria operator="OR">
<criteria operator="AND">
<criterion test_ref="oval:com.oracle.elsa:tst:20252673003" comment="libxml2 is earlier than 0:2.9.1-6.0.5.el7_9.6"/>
<criterion test_ref="oval:com.oracle.elsa:tst:20252673004" comment="libxml2 is signed with the Oracle Linux 7 key"/>
</criteria>
<criteria operator="AND">
<criterion test_ref="oval:com.oracle.elsa:tst:20252673005" comment="libxml2-devel is earlier than 0:2.9.1-6.0.5.el7_9.6"/>
<criterion test_ref="oval:com.oracle.elsa:tst:20252673006" comment="libxml2-devel is signed with the Oracle Linux 7 key"/>
</criteria>
<criteria operator="AND">
<criterion test_ref="oval:com.oracle.elsa:tst:20252673007" comment="libxml2-python is earlier than 0:2.9.1-6.0.5.el7_9.6"/>
<criterion test_ref="oval:com.oracle.elsa:tst:20252673008" comment="libxml2-python is signed with the Oracle Linux 7 key"/>
</criteria>
<criteria operator="AND">
<criterion test_ref="oval:com.oracle.elsa:tst:20252673009" comment="libxml2-static is earlier than 0:2.9.1-6.0.5.el7_9.6"/>
<criterion test_ref="oval:com.oracle.elsa:tst:20252673010" comment="libxml2-static is signed with the Oracle Linux 7 key"/>
</criteria>
</criteria>
</criteria>
</criteria>

</definition>
...
<rpminfo_test id="oval:com.oracle.elsa:tst:20252673009"  version="501" comment="libxml2-static is earlier than 0:2.9.1-6.0.5.el7_9.6" check="at least one" xmlns="http://oval.mitre.org/XMLSchema/oval-definitions-5#linux">

2. the second option which may not be mutually exclusive to option 1 is to adjust the matcher in Grype to only treat ELSA data as advisories, which they are, rather than vulnerability disclosures, and instead of using this to match, use NVD data to match, and then filter out fixed records based on the ELSA fix information, or something similar.

We try to avoid using NVD data to match with as there are some challenges, but it may work in this case.

We are currently in the process of making some changes to the matching process in Grype, so this is great input that can help inform what we do!

Then we’re not only losing data — we might also be getting incorrect data by using --by-cve. This option should probably not be used with ELSA data at all, as it risks omitting important information or associating the wrong CVEs, which is particularly problematic in such a sensitive context.

I’ve actually been wondering about this issue for quite some time, and I still have no clear idea how to reliably retrieve the correct CVEs.

Any news about that ?

Hi @enzofrnt,

I think you’re best bet for the full list of CVEs from an Oracle Linux match is to pass -o json and parse the output. For example, here’s a jq command that accomplishes this parsing:

grype -o json docker.io/anchore/test_images:appstreams-oraclelinux-8-1a287dd@sha256:c8d664b0e728d52f57eeb98ed1899c16d3b265f02ddfb41303d7a16c31e0b0f1 | jq . > /tmp/ol.json
cat /tmp/ol.json| jq -r '.matches[] | .relatedVulnerabilities // [] | .[] | .id' | sort | uniq 

This will give you a list of all the CVEs that are related to the vulnerabilities found in the grype scan. The JSON output has all the related vulnerabilities, not just the one summarized into the table when --by-cve is passed.

You can follow Improve behavior when `--by-cve` is passed · Issue #1454 · anchore/grype · GitHub for improvements to the behavior of the --by-cve flag.