Metadata-Version: 2.4
Name: gcve-sbom-analyzer
Version: 0.2.1
Summary: CLI tool that cross-references SBOM components against the GCVE vulnerability database.
Author-email: Samy DIFALLAH <samy.dflh@gmail.com>
License-Expression: GPL-3.0-or-later
Project-URL: Homepage, https://github.com/samy-difallah/gcve-sbom-analyzer
Project-URL: Source, https://github.com/samy-difallah/gcve-sbom-analyzer
Project-URL: Issues, https://github.com/samy-difallah/gcve-sbom-analyzer/issues
Project-URL: Changelog, https://github.com/samy-difallah/gcve-sbom-analyzer/blob/main/CHANGELOG.md
Keywords: sbom,cyclonedx,spdx,vulnerability,cve,gcve,osv,kev,epss,security,supply-chain
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Information Technology
Classifier: Intended Audience :: System Administrators
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Security
Classifier: Topic :: Software Development :: Quality Assurance
Classifier: Typing :: Typed
Requires-Python: >=3.12
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: pydantic<3.0.0,>=2.13.5
Requires-Dist: packageurl-python<0.18.0,>=0.17.6
Requires-Dist: cpe<2.0.0,>=1.3.1
Requires-Dist: pyvulnerabilitylookup<5.0.0,>=4.5.0
Requires-Dist: cyclonedx-python-lib<12.0.0,>=11.12.0
Requires-Dist: spdx-tools<0.9.0,>=0.8.5
Requires-Dist: packaging<27.0,>=26.3
Requires-Dist: typer<0.28.0,>=0.27.2
Requires-Dist: rich<16.0.0,>=15.0.0
Requires-Dist: requests<3.0.0,>=2.34.2
Provides-Extra: test
Requires-Dist: pytest<10.0.0,>=9.1.1; extra == "test"
Requires-Dist: pytest-cov<8.0.0,>=7.1.0; extra == "test"
Provides-Extra: lint
Requires-Dist: ruff<0.17.0,>=0.16.8; extra == "lint"
Requires-Dist: pre-commit<5.0.0,>=4.0.0; extra == "lint"
Requires-Dist: import-linter<3.0.0,>=2.15; extra == "lint"
Provides-Extra: release
Requires-Dist: git-cliff<3.0.0,>=2.14.2; extra == "release"
Provides-Extra: dev
Requires-Dist: gcve-sbom-analyzer[lint,release,test]; extra == "dev"
Dynamic: license-file

# gcve-sbom-analyzer

[![CI](https://github.com/samy-difallah/gcve-sbom-analyzer/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/samy-difallah/gcve-sbom-analyzer/actions/workflows/ci.yml) [![PyPI](https://img.shields.io/pypi/v/gcve-sbom-analyzer)](https://pypi.org/project/gcve-sbom-analyzer/) [![Python](https://img.shields.io/badge/python-3.12%2B-3776AB?logo=python&logoColor=white)](https://www.python.org/) [![License: GPL-3.0-or-later](https://img.shields.io/badge/license-GPL--3.0--or--later-blue)](https://github.com/samy-difallah/gcve-sbom-analyzer/blob/main/LICENSE)

[![CycloneDX](https://img.shields.io/badge/CycloneDX-1.x_JSON-4E4E4E)](https://cyclonedx.org/) [![SPDX](https://img.shields.io/badge/SPDX-2.x_JSON-4398CC)](https://spdx.dev/) [![GCVE](https://img.shields.io/badge/data-GCVE-1F6FEB)](https://gcve.eu/) [![OSV](https://img.shields.io/badge/data-OSV-6F42C1)](https://osv.dev/) [![Pydantic v2](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/pydantic/pydantic/main/docs/badge/v2.json)](https://docs.pydantic.dev/) [![Typer](https://img.shields.io/badge/CLI-Typer-009485?logo=typer&logoColor=white)](https://typer.tiangolo.com/) [![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)

## Overview

GCVE-powered SBOM vulnerability analyzer.

`gcve-sbom-analyzer` reads a Software Bill of Materials (CycloneDX or SPDX), looks up every component in the [GCVE](https://gcve.eu/) vulnerability database, and reports which components are vulnerable. It ranks what to fix first by known exploitation ([CISA KEV](https://www.cisa.gov/known-exploited-vulnerabilities-catalog)), exploit likelihood ([EPSS](https://www.first.org/epss/)) and severity, and its exit code can gate a CI pipeline.

- **Formats**: CycloneDX and SPDX 2.x JSON, detected from the file content.
- **Components**: language packages (Maven, npm, PyPI, Go, Cargo, NuGet…), Debian, Ubuntu, Alpine, Red Hat, Rocky Linux and AlmaLinux packages, and anything identified by a CPE.
- **Version-aware**: only vulnerabilities affecting the component's version are reported.
- **Prioritized**: every vulnerability gets a priority tier, from P1 (known exploited) to P4.
- **No account or API key**: GCVE and OSV are queried anonymously.

## Installation

Requires Python 3.12 or later.

```sh
pipx install gcve-sbom-analyzer
```

or, in a virtual environment:

```sh
pip install gcve-sbom-analyzer
```

## Quick start

```sh
gcve-sbom-analyzer scan bom.json
```

```text
 GCVE SBOM Analyzer
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

 File    : cyclonedx-java.json
 Format  : cyclonedx
 Scanned : 2026-09-29 20:32:06 UTC

 Components scanned : 4
 Vulnerable         : 4
 Clean              : 0

 Vulnerabilities found : 57
     CRITICAL          : 10
     HIGH              : 36
     MEDIUM            : 10
     LOW               : 1

 P1  Known exploited  : 2
 P2  EPSS ≥ 10%       : 8
 P3  Critical or high : 38
 P4  Other            : 9

────────────────────────────────────────────────────────────────────────────────

 jackson-databind  2.9.10  47 vulnerabilities  ·  CRITICAL
 log4j-api         2.14.1  1 vulnerability     ·  MEDIUM
 log4j-core        2.14.1  7 vulnerabilities   ·  CRITICAL
 spring-core       5.3.17  2 vulnerabilities   ·  HIGH
```

Results come from live GCVE data, so the counts change over time.

### Example SBOMs

The [`examples/`](https://github.com/samy-difallah/gcve-sbom-analyzer/tree/main/examples) directory holds small SBOMs of known-vulnerable components to try the tool on:

| File | Format | Components |
|---|---|---|
| [`cyclonedx-java.json`](https://github.com/samy-difallah/gcve-sbom-analyzer/blob/main/examples/cyclonedx-java.json) | CycloneDX 1.5 | Maven packages: Log4j 2.14.1 (Log4Shell), Spring, Jackson |
| [`spdx-python.json`](https://github.com/samy-difallah/gcve-sbom-analyzer/blob/main/examples/spdx-python.json) | SPDX 2.3 | PyPI packages: Django, requests, urllib3, PyYAML, Jinja2 |
| [`cyclonedx-debian.json`](https://github.com/samy-difallah/gcve-sbom-analyzer/blob/main/examples/cyclonedx-debian.json) | CycloneDX 1.5 | Debian 11 packages as Trivy records them: OpenSSL, zlib, curl, bash |
| [`spdx-debian.json`](https://github.com/samy-difallah/gcve-sbom-analyzer/blob/main/examples/spdx-debian.json) | SPDX 2.3 | The same Debian 11 packages, as Trivy records them in SPDX |
| [`cyclonedx-cpe.json`](https://github.com/samy-difallah/gcve-sbom-analyzer/blob/main/examples/cyclonedx-cpe.json) | CycloneDX 1.5 | Components identified by CPE only: Apache HTTP Server, nginx |
| [`cyclonedx-github.json`](https://github.com/samy-difallah/gcve-sbom-analyzer/blob/main/examples/cyclonedx-github.json) | CycloneDX 1.5 | C libraries identified by their GitHub repository, through `github` and `generic` PURLs: zlib, Expat, curl, libarchive |

## Usage

```text
gcve-sbom-analyzer scan [OPTIONS] SBOM_PATH
```

| Option | Description |
|---|---|
| `-f`, `--format FORMAT` | Format of the report: `text` (default) or `json`. |
| `-o`, `--output-file PATH` | Write the report to this file instead of stdout, in the format its extension sets. |
| `-d`, `--detailed` | List every CVE of each component. Ignored with `--format json`, `--prioritized` or `--top`. |
| `-V`, `--only-vulnerable` | Only list components with at least one vulnerability. The summary still counts every component. |
| `-p`, `--prioritized` | List the most urgent vulnerabilities across all components instead of the components. Ignored with `--format json`. |
| `--top N` | Number of vulnerabilities to list (default: 10). Implies `--prioritized`. |
| `--fail-on LEVEL` | Exit with 1 only for vulnerabilities at least this urgent: `kev`, `p2`, `p3` or `any` (default). |
| `-v`, `--verbose` | Print each component as it is scanned instead of a progress bar. |

Progress and errors go to stderr, so stdout only ever carries the report, or its summary when the report goes to a file.

### Listing every vulnerability

```sh
gcve-sbom-analyzer scan bom.json --detailed --only-vulnerable
```

```text
 nginx  1.20.0  ·  CVE-2025-23419  MEDIUM    5.3
                ·  CVE-2024-35200  MEDIUM    5.3  unverified
                ·  CVE-2023-44487  HIGH      7.5
                ·  CVE-2022-41742  HIGH      7.1
```

A vulnerability marked **unverified** was found for the component's product, but neither its record nor the NVD says whether the component's version is affected. It is kept rather than dropped, and counted like any other.

### Ranking what to fix first

```sh
gcve-sbom-analyzer scan bom.json --top 5
```

```text
 #  Tier  CVE             Component                KEV   EPSS  Severity  Score
 1  P1    CVE-2021-44228  log4j-core 2.14.1        ●    99.9%  CRITICAL   10.0
 2  P1    CVE-2021-45046  log4j-core 2.14.1        ●    99.9%  CRITICAL    9.0
 3  P2    CVE-2021-45105  log4j-core 2.14.1             99.9%  MEDIUM      5.9
 4  P2    CVE-2021-44832  log4j-core 2.14.1             97.9%  MEDIUM      6.6
 5  P2    CVE-2020-8840   jackson-databind 2.9.10       26.5%  CRITICAL      —
```

Each vulnerability falls into the first tier it qualifies for:

| Tier | Meaning |
|---|---|
| P1 | Known exploited: listed in the CISA KEV catalog. |
| P2 | Likely to be exploited: EPSS probability of 10% or more. |
| P3 | Critical or high severity. |
| P4 | Everything else. |

Within a tier, vulnerabilities are sorted by EPSS, then severity, then CVSS score. The EPSS column is the probability of exploitation in the next 30 days, rounded down to 0.1%.

### Writing the report to a file

```sh
gcve-sbom-analyzer scan bom.json -o report.txt
```

The report goes to the file, and the terminal still shows its summary. The file's extension sets the format: `.txt` for text, `.json` for JSON. Any other extension needs `--format`, and a `--format` that contradicts the extension stops the scan. Both, and the path itself, are checked before the scan starts, and the file is only written once the scan succeeds, so a failed scan leaves a previous report untouched. Text files are written without colors and 80 columns wide.

### JSON output

```sh
gcve-sbom-analyzer scan bom.json --format json | jq '.vulnerabilities_by_priority'
```

The report holds the summary counts (`total_vulnerabilities_count`, `vulnerabilities_by_severity`, `vulnerabilities_by_priority`, `known_exploited_count`…) and one entry per component under `findings`. Each entry lists its vulnerabilities with their CVE id, description, CVSS, severity, references, `version_status` (`affected` or `unknown`), KEV entry, EPSS score and priority tier. The JSON layout may still change before version 1.0.

### Exit codes and CI

| Code | Meaning |
|---|---|
| 0 | No vulnerability matching `--fail-on` was found. |
| 1 | At least one vulnerability matching `--fail-on` was found. |
| 2 | The scan could not complete: the SBOM cannot be read, GCVE or OSV cannot be queried, or the report file cannot be written. |

`--fail-on` only changes the exit code, never what is reported. For example, to fail a pipeline on known-exploited vulnerabilities only:

```sh
gcve-sbom-analyzer scan bom.json --fail-on kev
```

## How it works

1. The SBOM is parsed, and each component is identified by its [Package URL](https://github.com/package-url/purl-spec) (PURL) or its CPE.
2. Packages from a known ecosystem are looked up in [OSV](https://osv.dev/), which indexes advisories by package and version. OS packages are looked up by source package and distribution release, the way Debian, Ubuntu, Alpine and Red Hat publish their advisories. Components identified by a GitHub repository, through a `github` PURL or a `generic` PURL whose `vcs_url` or `download_url` qualifier points at GitHub, are looked up by repository and release tag. Each advisory found is then fetched from GCVE, under its CVE id when it has one.
3. Other components, and repositories OSV finds nothing for, are searched in GCVE by vendor and product, taken from their CPE or PURL. The affected version ranges of each CVE record are checked against the component's version, and when a record leaves that undecided, the NVD configurations stored in GCVE settle it where they can.
4. GCVE also supplies each CVE's CISA KEV entry and EPSS score, which set its priority tier.

Every lookup goes to the public [db.gcve.eu](https://db.gcve.eu/) and [api.osv.dev](https://api.osv.dev/) APIs. The scan therefore needs network access, and it sends the names and versions of the SBOM's components to both services.

## Known limitations

- **JSON input only**: SPDX tag-value, YAML and RDF, and CycloneDX XML are not read yet.
- **SPDX 2.x only**: SPDX 3.0 documents are not supported.
- **Slow on large SBOMs**: components are looked up one at a time, about 0.2 s each for packages and longer for CPE-identified components with many CVEs. An SBOM of several hundred components takes a few minutes.
- **PURLs with no package ecosystem**: `generic` PURLs that point at no GitHub repository, and other PURL types OSV does not index, fall back to the vendor/product search, which often finds nothing for them unless the component also has a CPE. Repositories hosted elsewhere than GitHub (GitLab, Bitbucket) are not looked up by repository yet.
- **Unknown release tags**: OSV reports nothing for a version matching none of a repository's tags, just as for a version no advisory affects, so such a component falls back to the vendor/product search.
- **Red Hat**: Red Hat's advisories only cover vulnerabilities it has fixed, so vulnerabilities still unfixed in a RHEL package are not reported.
- **Other distributions**: SUSE, Wolfi, Chainguard, Amazon Linux, Oracle Linux and Azure Linux packages are not matched to their advisories. For a supported distribution whose release is missing from the PURL or cannot be mapped, advisories from every release are used and the results are marked unverified. Alpine has no such release-less advisories, so those packages fall back to the vendor/product search.

## Contributing

Bug reports, ideas and pull requests are welcome: see the [contributing guide](https://github.com/samy-difallah/gcve-sbom-analyzer/blob/main/CONTRIBUTING.md).

## License

[GNU General Public License v3.0 or later](https://github.com/samy-difallah/gcve-sbom-analyzer/blob/main/LICENSE).
