Skip to content
savoirfairelinuxPublic

About

SBOM Vulnerability Scanning & Assessment tool

Resources

Code of conduct

Contributing

Stars

84 stars

Watchers

3 watching

Forks

Repository files navigation

VulnScout

vulnscout logo
License

🔹 Introduction

VulnScout is designed to analyse and identify vulnerabilities in their software components and dependencies using an SBOM (Software Bill Of Materials).

It pulls known vulnerabilities from public sources like the NVD, EPSS, and Grype to figure out which parts of a codebase might be affected by security issues (CVE).

VulnScout also provides a web interface for visualisation and a command line to generate enriched output files.

VulnScout Features

  • Analyse SBOMs (SPDX 2/3, CycloneDX, Yocto CVE check, OpenVEX, Grype)

  • Detect and enrich vulnerabilities from NVD, EPSS, and Grype

  • Manage projects and variants for multi-target builds

  • Web interface for visualisation, triage, and assessment

  • Non-interactive / CI mode with configurable match conditions

  • Generate customisable reports (AsciiDoc, HTML, PDF, CSV)

  • Export enriched SBOMs (SPDX 3.0, CycloneDX 1.6, OpenVEX)

  • Custom CVSS scoring per vulnerability

  • Time estimation tracking for remediation effort

🔧 Setting up VulnScout

Requirements & Installation

VulnScout is designed to run locally in a Docker container. It only requires docker to be installed and running on your host.

To install VulnScout, you only need to clone the repository:

git clone https://github.com/savoirfairelinux/vulnscout.git
cd vulnscout

🐧 Using VulnScout

Run VulnScout in interactive mode

This project contains default examples of VulnScout.

To run VulnScout demo in interactive mode, you can simply run the command:

./vulnscout --serve --add-spdx $(pwd)/example/spdx3/core-image-minimal-qemux86-64.rootfs.spdx.json \
--add-cve-check $(pwd)/example/spdx3/core-image-minimal-qemux86-64.rootfs.json

Then open your browser to view the results:

http://localhost:7275

If you don’t need additional source files, VulnScout can be rerun directly without any additional arguments:

./vulnscout --serve

It is also possible to add sources files on a specific project and variant with the --project and --variant arguments:

./vulnscout --project demo --variant x86 --add-spdx $(pwd)/example/spdx3/core-image-minimal-qemux86-64.rootfs.spdx.json \
--add-cve-check $(pwd)/example/spdx3/core-image-minimal-qemux86-64.rootfs.json

📖 Documentation

Full documentation is available at https://vulnscout.readthedocs.io/

Container Lifecycle

The vulnscout script manages the container lifecycle. The container runs in the background and accepts commands via docker exec.

# Start the container (done automatically by most commands)
./vulnscout start

# Stop and remove the container
./vulnscout stop

# Restart the container (useful after changing config)
./vulnscout restart

Projects and Variants

VulnScout organises data into projects and variants. A project typically maps to a product, and variants represent different builds or architectures (e.g. x86_64, aarch64).

Both flags are optional and default to default if not provided.

./vulnscout --project <name> --variant <name> <command>

Adding Input Files to the Database

VulnScout accepts multiple input file types. Commands can be chained and will automatically trigger a scan.

# SPDX 2/3 SBOM (JSON, tag-value, or .tar/.tar.gz/.tar.zst archive)
./vulnscout --add-spdx <path>

# Yocto CVE check JSON output
./vulnscout --add-cve-check <path>

# Yocto VEX JSON output (from vex.bbclass)
./vulnscout --add-yocto-vex <path>

# CycloneDX file
./vulnscout --add-cdx <path>

# OpenVEX file
./vulnscout --add-openvex <path>

# Grype file
./vulnscout --add-grype <path>

Multiple inputs can be chained in a single command:

./vulnscout --project demo --variant x86 \
  --add-spdx /path/to/sbom.spdx.json \
  --add-cve-check /path/to/cve-check.json \
  --add-openvex /path/to/assessments.openvex.json
Tip
  • .tar, .tar.gz, .tar.zst archives are supported as SPDX 2 input.

  • .spdx files (tag-value format) are supported as SPDX 2 input.

  • .spdx.json is supported as SPDX 3 input.

  • Grype scan files should end with .grype.json.

  • To ignore parsing errors for malformed SBOMs, set: IGNORE_PARSING_ERRORS=true

Run VulnScout with Yocto

We have a dedicated layer for VulnScout integration in Yocto.

To be short, a simple inherit vulnscout in your image recipe will be enough to configure vulnscout for your project.

The vulnscout web interface can be started with a bitbake <image-recipe> -c vulnscout command.

Web Interface Settings

The web interface includes a Settings tab that provides:

  • Rename Project — Select a project and give it a new name (must be unique across all projects).

  • Rename Variant — Select a variant within a project and rename it (must be unique within the project).

  • Import SBOM — Upload an SBOM file directly from the browser instead of using CLI flags like --add-spdx or --add-cve-check. When importing, you must select (or create) the target project and variant. Supported formats are auto-detected or can be specified explicitly: SPDX (2/3), CycloneDX, OpenVEX, Yocto CVE check, and Grype.

Run VulnScout in non-interactive mode

If you want to use the non-interactive mode, without the web interface, you can use the command with the --match-condition argument:

./vulnscout --project demo --match-condition "((cvss >= 9.0 or (cvss >= 7.0 and epss >= 30%)) and (pending or affected))"

The command exits with code 2 if any vulnerability matches the condition, enabling use in CI pipelines.

Match conditions evaluate vulnerability data already stored by VulnScout. They do not automatically refresh EPSS or other provider data. Add --refresh-vulnerability-data to the same command when the condition must use current enrichment data.

See the match conditions documentation for the full condition syntax and token reference.

You can combine inputs with a match condition in a single invocation:

./vulnscout --project demo \
  --add-spdx /path/to/sbom.spdx.json \
  --add-cve-check /path/to/cve-check.json \
  --match-condition "((cvss >= 9.0) and (pending or affected)) "

Refreshing Vulnerability Data

Use --refresh-vulnerability-data with an input command to enrich vulnerabilities imported by that run with current EPSS, NVD, ENISA EUVD, and GitHub Advisory data:

./vulnscout --add-spdx /path/to/sbom.spdx.json --refresh-vulnerability-data

The option can also refresh vulnerabilities already in the database. Without a project it refreshes all vulnerabilities; project and variant options restrict the scope:

./vulnscout --refresh-vulnerability-data
./vulnscout --project demo --refresh-vulnerability-data
./vulnscout --project demo --variant x86 --refresh-vulnerability-data

The refresh enriches existing CVE and GHSA records; it does not discover new findings. A variant requires its project because variant names are project-local.

Performing a Grype Scan

VulnScout can run Grype on the current database contents. This exports the current state as a CycloneDX SBOM, runs Grype against it, and merges the results back:

./vulnscout --project demo --variant x86 --perform-grype-scan

This can be chained with other inputs to scan newly added files immediately:

./vulnscout --project demo --add-spdx example/spdx3/core-image-minimal-qemux86-64.rootfs.spdx.json --perform-grype-scan

--perform-grype-scan can consume significant RAM when the SBOM contains many packages. By default VulnScout caps Grype’s memory at ~80 % of the container/cgroup limit. Override with the GRYPE_MEMLIMIT environment variable (see the Environment Variables table above).

# Persistent: keep Grype below 6 GiB across all future scans in this container
./vulnscout --config GRYPE_MEMLIMIT 6GiB

# One-off: override via the host environment before starting the container
export GRYPE_MEMLIMIT=24GiB
./vulnscout --project demo --variant x86 --perform-grype-scan

Generating Reports

Reports are generated from AsciiDoc templates. VulnScout ships with built-in templates and also supports custom ones. Use --project to select the report scope; when omitted, the default project is used. A project report includes all its variants. Add --variant to restrict the report to one variant in that project. Unknown project or variant names fail instead of broadening the report scope.

# Generate a report from a built-in template
./vulnscout --project demo --report summary.adoc

# Generate a report for one variant only
./vulnscout --project demo --variant x86 --report summary.adoc

# Generate a match-condition report (lists vulnerabilities that triggered the condition)
./vulnscout --project demo --match-condition "cvss >= 9.0" --report match_condition.adoc

# Register a custom template permanently in the container and generate a report
./vulnscout --project demo --report /path/to/my-custom-report.adoc

# Then generate a report from it by name
./vulnscout --project demo --report my-custom-report.adoc

# Or pass the file path directly — registers and runs it in one step
./vulnscout --project demo --report /path/to/my-custom-report.adoc

Multiple reports can be generated in one command:

./vulnscout --project demo --report summary.adoc --report all_assessments.adoc

Reports are written to the outputs directory (default: .vulnscout/outputs/).

See the report templates documentation for documentation on writing custom report templates.

Exporting SBOM Files

VulnScout can export the enriched project data as standard SBOM formats. Exported files are written to the outputs directory (default: .vulnscout/outputs/).

# Export as SPDX 3.0 SBOM
./vulnscout --project demo --export-spdx

# Export as CycloneDX 1.6 SBOM
./vulnscout --project demo --export-cdx

# Export as OpenVEX document (vulnerabilities + assessments)
./vulnscout --project demo --export-openvex

Export commands can be chained with inputs and reports in a single invocation:

./vulnscout --project demo \
  --add-spdx /path/to/sbom.spdx.json \
  --add-cve-check /path/to/cve-check.json \
  --export-spdx --export-cdx --export-openvex \
  --report summary.adoc

Exporting and Importing Custom Assessments

VulnScout lets you export and re-import the assessments you have manually created through the web interface (review / triage decisions). This is useful for:

  • Backing up your review work before re-importing SBOMs.

  • Sharing assessment decisions across different VulnScout instances.

  • Restoring triage state in CI pipelines after a database reset.

VulnScout JSON

The --export-custom-vulnscout-data flag exports custom assessments, CVSS scores, and time estimates as one VulnScout JSON file. It includes every variant in the selected project unless --variant is provided.

# Export all project variants
./vulnscout --project demo --export-custom-vulnscout-data

# Export one variant
./vulnscout --project demo --variant x86 --export-custom-vulnscout-data

# Update the existing export with current review data
./vulnscout --project demo --export-custom-vulnscout-data --amend

Add --amend to reconcile current review data with the existing file in the output directory. The file must already exist at the path produced by the same export scope. Existing records retain stable ordering and extension fields while updated and new records are incorporated.

The --import-custom-vulnscout-data command restores entries according to the variant metadata in the file. Imported assessments use the current system time by default. Add --use-original-timestamps to preserve assessment timestamps from the file. --use-current-timestamps is also accepted to select the default explicitly.

Current version 2 exports identify assessment targets by variant name and package, without instance-local variant UUIDs, so they can be shared between VulnScout installations. Legacy version 1 files remain importable; unsupported future versions are rejected explicitly.

./vulnscout --project demo --import-custom-vulnscout-data /path/to/custom_vulnscout_data_all.json

./vulnscout --project demo --import-custom-vulnscout-data /path/to/custom_vulnscout_data_all.json --use-original-timestamps

OpenVEX

The OpenVEX custom-assessment commands operate on one JSON document and require --variant for both import and export.

# Export a variant
./vulnscout --project demo --variant x86 --export-custom-openvex-assessments

# Update the existing OpenVEX export
./vulnscout --project demo --variant x86 --export-custom-openvex-assessments --amend

# Import into a variant
./vulnscout --project demo --variant x86 --import-custom-openvex-assessments /path/to/custom_openvex_x86.json

# Ignore OpenVEX statement timestamps and use the current system time
./vulnscout --project demo --variant x86 --import-custom-openvex-assessments /path/to/custom_openvex_x86.json --use-current-timestamps

For OpenVEX exports, --amend preserves the document ID and statement ordering from the existing output file and increments its version.

OpenVEX imports preserve statement timestamps by default. Add --use-current-timestamps to use the current system time, or use --use-original-timestamps to select the default explicitly.

Both commands can be combined with other flags:

./vulnscout --project demo \
  --add-spdx /path/to/sbom.spdx.json \
  --import-custom-vulnscout-data /path/to/custom_vulnscout_data_all.json \
  --export-spdx --report summary.adoc

Configuration

Configuration Commands

Persistent configuration is stored in .vulnscout/cache/config.env and is automatically loaded on each run.

# Set a config value
./vulnscout config <key> <value>

# List current configuration (sensitive values masked)
./vulnscout config-list

# Remove a config key
./vulnscout config-clear <key>

Example — set an NVD API key for higher rate limits:

./vulnscout config NVD_API_KEY abc123

Environment Variables

The following environment variables can be set via vulnscout config or exported before running:

Table 1. Container & runtime
Variable Description Default

VULNSCOUT_CONTAINER

Name of the Docker container

vulnscout

VULNSCOUT_IMAGE

Docker image to use

docker.io/sflinux/vulnscout:v0.22

VULNSCOUT_BUILD_DIR

Root build directory on the host (parent of cache/ and outputs/)

./.vulnscout

VULNSCOUT_OUTPUTS_DIR

Directory for output files on the host

$VULNSCOUT_BUILD_DIR/outputs

VULNSCOUT_CACHE_DIR

Cache directory on the host (holds the SQLite database and config)

$VULNSCOUT_BUILD_DIR/cache

FLASK_RUN_PORT

Port the web UI listens on

7275

FLASK_RUN_HOST

Host address for the web UI

0.0.0.0

VITE_API_URL

Backend API URL used by the dev frontend

http://localhost:7275

USER_UID

UID used to write output files (avoids permission issues)

current user

USER_GID

GID used to write output files

current group

Table 2. Scan & enrichment
Variable Description Default

NVD_API_KEY

NVD API key for higher rate limits (https://nvd.nist.gov/developers/request-an-api-key)

(none)

GRYPE_MEMLIMIT

Cap the RAM used by the grype binary (Go soft memory limit, GOMEMLIMIT). Accepts the same unit strings as Go: 4GiB, 8192MiB, plain bytes. Set to off to disable. Default (unset): auto (~80 % of the container/cgroup memory limit, recommended for CI).

(auto)

IGNORE_PARSING_ERRORS

Continue scanning even if input files contain errors

false

VERBOSE_MODE

Enable verbose logging in the container

false

Table 3. Report metadata
Variable Description Default

PRODUCT_NAME

Product name embedded in generated reports and SBOMs

(none)

PRODUCT_VERSION

Product version embedded in generated reports

(none)

AUTHOR_NAME

Author/company name embedded in reports

(none)

CLIENT_NAME

Customer/client company name embedded in reports (optional, may be empty)

(none)

CONTACT_EMAIL

Contact email embedded in reports

(none)

DOCUMENT_URL

URL embedded in exported SBOM documents

(none)

HTTP Proxy Configuration

If you want to run VulnScout with an HTTP proxy, set variables in the config:

./vulnscout config HTTP_PROXY http://proxy.example.com:8080
./vulnscout config HTTPS_PROXY http://proxy.example.com:8080
./vulnscout config NO_PROXY localhost,127.0.0.1

Or pass them directly as environment variables when calling vulnscout.

🔎 Architecture

An architecture diagram showing different components of the VulnScout app

📥 Supported input files

  • SPDX 2.3 (Packages) - JSON and tag-value formats

  • SPDX 3.0 (Packages + vulnerabilities)

  • Cyclone DX 1.4, 1.5, 1.6 (Packages + vulnerabilities)

  • Grype native JSON format (Packages + vulnerabilities)

  • Yocto JSON output of cve-check module (Packages + vulnerabilities)

📤 Supported output files

  • SPDX 2.3 (Packages)

  • SPDX 3.0 (Packages + vulnerabilities)

  • Cyclone DX 1.4, 1.5, 1.6 (Packages + vulnerabilities)

  • openVex (vulnerabilities + assessments)

  • All reports: Asciidoc, HTML, PDF

  • Summary: Asciidoc, HTML, PDF

  • Time estimates: csv

  • Vulnerabilities: csv, txt

📊 Vulnerability Data Sources

The tool pulls vulnerability and risk data from multiple trusted sources:
  • NVD (National Vulnerability Database)

  • All data sources supported by Grype

  • EPSS (Exploit Prediction Scoring System)

  • Information embedded in input files

📝 Custom CVSS Scoring

VulnScout allows you to add a custom CVSS vector string to a vulnerability, enabling organisation-specific vulnerability scoring.

📋 Licence

Copyright © 2017-2026 Savoir-faire Linux, Inc.
VulnScout is released under the GPL-3.0 license.

fit

About

SBOM Vulnerability Scanning & Assessment tool

Resources

Code of conduct

Contributing

Stars

84 stars

Watchers

3 watching

Forks

Releases

Packages

Contributors

Languages