Skip to content

fix: Missing CVEs owing to inconsistency between cve db data model and sql query specifying exact versions #5517

@tomdottom

Description

@tomdottom

Description

There is an inconsistency in generating product version information between:

  1. ingesting NVD data into the database; and
  2. Performing queries on the database that look for exact versions (query ranges appear to be working).

Specifically, patch/update information is not used in the db, but is used when constructing queries for exact versions.

Openssh 8.5p1 is used below as a concrete example to explain the issue

Ingesting NVD data and populating the db

The CPE of cpe:2.3:a:openbsd:openssh:8.5:p1:*:*:*:*:*:* will be decoded by the decode_cpe23 function into

vendor = openbsd
product = openssh
version = 8.5

Note that the cpe update value is discarded.

CVEs associated with this CPE (eg. CVE-2024-6387) will be stored in the sqlite db against the version 8.5 and not 8.5p1.

For example:

cve_number vendor product version versionStartIncluding versionStartExcluding versionEndIncluding versionEndExcluding data_source
CVE-2024-6387 openbsd openssh * 8.6 9.8 NVD
CVE-2024-6387 openbsd openssh 8.5 NVD
CVE-2024-6387 openbsd openssh * 4.4 NVD
CVE-2024-6387 openbsd openssh 4.4 NVD

Constructing the ProductInfo object and searching the db

The OpenSSH version header of OpenSSH_8.5p1 is parsed into

ProductInfo(vendor='openssh', product='openssh', version='8.5p1', location='NotFound', purl=None)

The query that should locate CVEs for exact versions is:

query = """
SELECT CVE_number FROM cve_range
WHERE vendor=? AND product=? AND version=?
"""
# Removing * from vendors that are guessed by the package list parser
vendor = product_info.vendor.replace("*", "")
# Use our Version class to do version compares
parsed_version = Version(product_info.version)
self.cursor.execute(query, [vendor, product_info.product, str(parsed_version)])

Note that str(Version("8.5p1")) == "8.5p1"

Which results in the query that returns 0 rows when we actually expect 1 row.

SELECT CVE_number FROM cve_range 
WHERE vendor='openbsd'
  AND product='openssh'
  AND version='8.5p1` 

Note that queries searching ranges work because all rows for a product are retrieved and the Version object is responsible for version comparisons and can deal with the patch/update component.

# Check for any ranges
query = """
SELECT
CVE_number,
versionStartIncluding,
versionStartExcluding,
versionEndIncluding,
versionEndExcluding
FROM cve_range
WHERE vendor=? AND product=? AND version=?
"""
self.cursor.execute(query, [vendor, product_info.product, "*"])

and parsed_version >= Version(version_start_including)

To reproduce

Steps to reproduce the behaviour:

  1. Download and install OpenSSH 8.5p1
  2. Scan cve-bin-tool /path/to/sshd
  3. Note CVE-2024-6387 is not reported in the output
  4. Confirm this version of OpenSSH is vulnerable https://nvd.nist.gov/vuln/detail/cve-2024-6387#config-div-32

Expected behaviour:

cve-bin-tool SHOULD report that OpenSSH 8.5p1 is vulnerable to CVE-2025-6387

Actual behaviour:

cve-bin-tool DOES NOT report that OpenSSH 8.5p1 is vulnerable to CVE-2025-6387

Version/platform info

Version of CVE-bin-tool:

$ cve-bin-tool --version
3.4

Installed from pypi

Operating system: Linux

$ uname -a
Linux foobar 6.12.67-1-lts #1 SMP PREEMPT_DYNAMIC Fri, 23 Jan 2026 12:42:41 +0000 x86_64 GNU/Linux

Python version:

$ python3 --version
Python 3.14.2

Anything else?

I should be able to create a PR but need guidance on what is actually considered the core issue to fix.

For example I can propose:

  • Option 1: The patch/update versions be stored in the db, and query functions & SQL updated to account for this.
  • Option 2: The Version object should be able to return a patch/update free string for use when searching for exact queries ( eg. Version("8.5p1").patchless == "8.5" ).
  • Option 3: Remove the SQL which searches for exact versions. Instead fetch all product rows and use the Version object to select the exact matches (similar to the ranged query).

Or you may have another preferred option.

Cheers,

Tom

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions