Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@ayham291
Copy link

@ayham291 ayham291 commented Aug 1, 2025

Fix CPE update field handling for non-JVM packages

Problem

The CPE matching logic was only considering the update field for JVM packages, but it should also handle other packages where the update field contains important version information. For example, with NTP and OpenSSH:

cpe:2.3:a:ntp:ntp:4.2.8:p18:*:*:*:*:*:*

The current code would only use 4.2.8 for version matching, ignoring the p18 update field, which should be combined to form the complete version 4.2.8p18.

Solution

  • Created a general combineVersionAndUpdate function that handles CPE version and update field combinations for all package types
  • Updated MatchPackageByCPEs and filterCPEsByVersion functions to use the new general function
  • Maintained existing JVM-specific behavior using the original transformJvmVersion function
  • Added proper handling for wildcard/empty values to prevent incorrect combinations

Changes

  • Added: combineVersionAndUpdate function in grype/matcher/internal/cpe.go
  • Updated: CPE matching logic to use the new function for all package types

Testing

  • All existing tests pass
  • Added new test cases to verify correct behavior for non-JVM packages
  • Verified that JVM package behavior remains unchanged

Before

ntp                                            4.2.8p18                                  *4.2.8p9, 4.3.94  UnknownPackage  CVE-2016-7434     High      61.2% (98th)   41.0
ntp                                            4.2.8p18                                  4.2.8, *4.3.77    UnknownPackage  CVE-2015-7704     High      57.0% (98th)   39.2
ntp                                            4.2.8p18                                  4.2.8, *4.3.94    UnknownPackage  CVE-2016-7426     High      47.2% (97th)   31.6
ntp                                            4.2.8p18                                  4.2.8, *4.3.77    UnknownPackage  CVE-2015-7855     Medium    48.4% (97th)   24.8
ntp                                            4.2.8p18                                                    UnknownPackage  CVE-2015-7978     High      33.4% (96th)   23.0
ntp                                            4.2.8p18                                  4.2.8, *4.3.77    UnknownPackage  CVE-2015-7705     Critical  25.7% (96th)   22.7
ntp                                            4.2.8p18                                                    UnknownPackage  CVE-2015-7979     High      22.5% (95th)   15.4
ntp                                            4.2.8p18                                                    UnknownPackage  CVE-2016-7433     Medium    28.3% (96th)   14.4
ntp                                            4.2.8p18                                  4.2.8, *4.3.93    UnknownPackage  CVE-2016-4953     High      19.2% (95th)   13.2
ntp                                            4.2.8p18                                                    UnknownPackage  CVE-2016-2516     Medium    23.4% (95th)   13.1
ntp                                            4.2.8p18                                                    UnknownPackage  CVE-2015-5300     High      17.8% (94th)   12.2
ntp                                            4.2.8p18                                                    UnknownPackage  CVE-2015-8140     Medium    23.5% (95th)   12.1
ntp                                            4.2.8p18                                  4.2.8, *4.3.77    UnknownPackage  CVE-2015-7853     Critical  12.8% (93rd)   11.3
ntp                                            4.2.8p18                                                    UnknownPackage  CVE-2016-9311     Medium    19.4% (95th)   11.2
ntp                                            4.2.8p18                                                    UnknownPackage  CVE-2016-7429     Low       28.5% (96th)   10.0
ntp                                            4.2.8p18                                                    UnknownPackage  CVE-2015-8139     Medium    17.9% (94th)   9.1
ntp                                            4.2.8p18                                                    UnknownPackage  CVE-2015-8158     Medium    17.9% (94th)   9.1
ntp                                            4.2.8p18                                  4.2.8             UnknownPackage  CVE-2014-9750     Medium    11.5% (93rd)   6.2
ntp                                            4.2.8p18                                  4.2.8             UnknownPackage  CVE-2018-7185     High      8.8% (92nd)    6.1
ntp                                            4.2.8p18                                  4.2.8             UnknownPackage  CVE-2019-8936     High      8.7% (92nd)    6.0
ntp                                            4.2.8p18                                  4.3.90            UnknownPackage  CVE-2015-7977     Medium    11.6% (93rd)   5.9
ntp                                            4.2.8p18                                  4.2.8             UnknownPackage  CVE-2014-9751     Medium    9.7% (92nd)    5.7
ntp                                            4.2.8p18                                  4.2.8, *4.3.93    UnknownPackage  CVE-2016-4954     High      8.0% (91st)    5.5
ntp                                            4.2.8p18                                                    UnknownPackage  CVE-2016-9310     Medium    8.7% (92nd)    5.0
ntp                                            4.2.8p18                                  4.2.8, *4.3.77    UnknownPackage  CVE-2015-7701     High      6.3% (90th)    4.3
ntp                                            4.2.8p18                                  4.2.8, *4.3.90    UnknownPackage  CVE-2015-7973     Medium    7.6% (91st)    4.2
ntp                                            4.2.8p18                                  4.2.8, *4.3.77    UnknownPackage  CVE-2015-7691     High      5.7% (90th)    3.9
ntp                                            4.2.8p18                                                    UnknownPackage  CVE-2016-9312     High      5.7% (90th)    3.9
ntp                                            4.2.8p18                                  4.2.8, *4.3.94    UnknownPackage  CVE-2017-6458     High      4.9% (89th)    3.7
ntp                                            4.2.8p18                                                    UnknownPackage  CVE-2016-2519     Medium    7.1% (91st)    3.7
ntp                                            4.2.8p18                                  4.2.8, *4.3.90    UnknownPackage  CVE-2015-7974     High      5.1% (89th)    3.4
ntp                                            4.2.8p18                                  4.2.8, *4.3.77    UnknownPackage  CVE-2015-7849     High      4.4% (88th)    3.3
ntp                                            4.2.8p18                                                    UnknownPackage  CVE-2015-8138     Medium    6.1% (90th)    3.1
ntp                                            4.2.8p18                                  4.2.8, *4.3.77    UnknownPackage  CVE-2015-7692     High      4.2% (88th)    2.9
ntp                                            4.2.8p18                                  4.2.8, *4.3.77    UnknownPackage  CVE-2015-7854     High      3.6% (87th)    2.7
ntp                                            4.2.8p18                                  4.2.8, *4.3.93    UnknownPackage  CVE-2016-4955     Medium    4.7% (88th)    2.4
ntp                                            4.2.8p18                                  4.2.8, *4.3.77    UnknownPackage  CVE-2015-7703     High      3.2% (86th)    2.1
ntp                                            4.2.8p18                                                    UnknownPackage  CVE-2016-2517     Medium    3.8% (87th)    1.9
ntp                                            4.2.8p18                                                    UnknownPackage  CVE-2015-7976     Medium    4.2% (88th)    1.9
ntp                                            4.2.8p18                                  4.2.8, *4.3.77    UnknownPackage  CVE-2015-7852     Medium    3.2% (86th)    1.6
ntp                                            4.2.8p18                                  4.2.8, *4.3.77    UnknownPackage  CVE-2015-7850     Medium    2.6% (85th)    1.3
ntp                                            4.2.8p18                                                    UnknownPackage  CVE-2019-11331    High      1.4% (79th)    1.0
ntp                                            4.2.8p18                                  4.2.8, *4.3.93    UnknownPackage  CVE-2016-4956     Medium    2.0% (83rd)    1.0
ntp                                            4.2.8p18                                                    UnknownPackage  CVE-2015-5146     Medium    1.9% (82nd)    0.9
ntp                                            4.2.8p18                                                    UnknownPackage  CVE-2016-1547     Medium    1.3% (78th)    0.6
ntp                                            4.2.8p18                                  4.2.8, *4.3.92    UnknownPackage  CVE-2018-7170     Medium    1.3% (78th)    0.6
ntp                                            4.2.8p18                                  4.2.8, *4.3.77    UnknownPackage  CVE-2015-7848     High      0.9% (74th)    0.6
ntp                                            4.2.8p18                                  4.2.8, *4.3.77    UnknownPackage  CVE-2015-7702     Medium    1.0% (75th)    0.5
ntp                                            4.2.8p18                                  4.3.100           UnknownPackage  CVE-2020-11868    High      0.6% (68th)    0.4
ntp                                            4.2.8p18                                  4.2.8, *4.3.92    UnknownPackage  CVE-2016-2518     Medium    0.8% (72nd)    0.4
ntp                                            4.2.8p18                                                    UnknownPackage  CVE-2015-7975     Medium    0.6% (69th)    0.3
ntp                                            4.2.8p18                                  4.2.8, *4.3.100   UnknownPackage  CVE-2020-13817    High      0.4% (58th)    0.3

After

ntp                                            4.2.8p18                                  *4.2.8p9, 4.3.94  UnknownPackage  CVE-2016-7434     High      61.2% (98th)   41.0
ntp                                            4.2.8p18                                                    UnknownPackage  CVE-2019-11331    High      1.4% (79th)    1.0

@ayham291 ayham291 force-pushed the fix/cpe-update-field-handling-for-non-jvm-packages branch from 17efd5c to e51a35f Compare August 1, 2025 21:20
- Added a new function `combineVersionAndUpdate` to handle the combination of version and update fields for various package types.
- Updated the `MatchPackageByCPEs` and `filterCPEsByVersion` functions to utilize the new logic, ensuring consistent version formatting across non-JVM and JVM packages.

Signed-off-by: [email protected] <[email protected]>
Signed-off-by: ayham291 <[email protected]>
@kzantow kzantow force-pushed the fix/cpe-update-field-handling-for-non-jvm-packages branch from d9be337 to 63efc89 Compare December 19, 2025 18:09
@kzantow
Copy link
Contributor

kzantow commented Dec 19, 2025

Hi @ayham291, I've been doing some verification about the "right" behavior here before we make a change to version comparison -- we don't want to introduce behavior that would result in missed vulnerabilities. I think by only concatenating these values together, it will not work quite as we want, however I see a number of examples where using a dash might be the right thing.

I wrote a small program to look at the CPE database for entries with updates, to inspect how some of these are represented in our database.

One example is cpe:2.3:a:adobe:coldfusion:2021:update21:*:*:*:*:*:* which can be found in CVE-2025-64898, we can see the versions in our constraints are <version>-<update>.

% grype db search CVE-2025-64898
VULNERABILITY   PACKAGE                                     NAMESPACE  VERSION CONSTRAINT                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  
CVE-2025-64898  cpe:2.3:a:adobe:coldfusion:*:*:*:*:*:*:*:*  nvd:cpe    = 2021 || = 2021-update1 || = 2021-update10 || = 2021-update11 || = 2021-update12 || = 2021-update13 || = 2021-update14 ...

And cpe:2.3:a:nextcloud:nextcloud_server:28.0.7:rc4:*:*:-:*:*:* with CVE-2025-47791, version constraints are semver:

% grype db search CVE-2025-47791
VULNERABILITY   PACKAGE                                               NAMESPACE  VERSION CONSTRAINT                                                   
CVE-2025-47791  cpe:2.3:a:nextcloud:nextcloud_server:*:*:*:*:*:*:*:*  nvd:cpe    >= 28.0.0, < 28.0.13 || >= 29.0.0, < 29.0.10 || >= 30.0.0, < 30.0.3

So this should actually work correctly, too, since with a semver comparison the -rc4 would be treated as a prerelease.

Would you agree with this assessment, would this cause a problem for the issue you're trying to fix?

@ayham291
Copy link
Author

Hi @kzantow,

Thank you for the thorough investigation and the examples you provided. Your observation is absolutely correct - there is indeed inconsistency in how versions are represented in the database, even within the same package.

Looking at the NTP vulnerabilities, I can see that the database itself uses both formats:

  • Concatenated format: 4.2.4p4, 4.2.5p18, 4.2.7p22, 4.2.7p444
  • Dash-separated format: 4.2.8-p1, 4.2.8-p9, 4.2.8-p10

Similarly, for Adobe ColdFusion and for Nextcloud with semver.

  1. For NTP entries that use concatenated format (like 4.2.4p4, 4.2.5p18, 4.2.7p22), my fix will correctly match them, which addresses the core issue where the update field was being ignored entirely
  2. For entries that use dash-separated format (like 4.2.8-p1), the version comparison may not match exactly since 4.2.8p1 and 4.2.8-p1 are different strings, but this is a limitation we accept given the database inconsistency

The fix is still valuable because it addresses the core problem of ignoring the update field, which was causing missed matches for the many entries that do use the concatenated format. The inconsistency in the data in the database itself means that no single approach will work perfectly for all entries. 🤷

Thanks again for the verification!

@kzantow
Copy link
Contributor

kzantow commented Dec 22, 2025

I finally tracked down what's going on and it's a bit of a mess. The most important bit to note is that we are concatenating the update field with a dash when we build the db for CPE versions with updates. I see that we have one potentially incorrect record in our overrides data, given the NVD record specifies this as an update rather than part of the version. We'll get this data fixed. Because of this, I think the behavior in Grype should be to include a dash.

There is a complication that some NVD records include the p# directly in the version string, too. These are older records, mostly from 2009, I hope people aren't running software that old; we should probably correct these records, too. (CVE-2009-0159, CVE-2009-3563, CVE-2009-0021, CVE-2009-0159, CVE-2009-1252, CVE-2009-1252, CVE-2015-1798, CVE-2015-1799).

It's possible this concatenation is more ideal, since -<something> typically makes this fall into semver comparison, where the <something> is treated as a prerelease, which isn't usually what we want here and we added handling for the <version>p# not long ago, in which case we will have to update the db build process to remove the dash. But as it stands, concatenating without the dash is a lot more problematic, I think. We can see the behavior with records today:

grype 'cpe:2.3:a:adobe:coldfusion:2023update4:*:*:*:*:*:*'

vs.

grype 'cpe:2.3:a:adobe:coldfusion:2023-update4:*:*:*:*:*:*'

... the latter returns correct results, whereas we have many false negatives from the former.

Additionally, it would be great to have some test cases that actually exercise matching with package(s) with updates in the CPE, rather than just testing the utility function. If you're able to add that, it would be great and would help expedite this fix. Otherwise, I'll look into getting this wrapped up after the new year.

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.

5 participants