We maintain three popular command-line tools, some libraries, and supporting utilities. Most are written in Go, with a few in Python.
They are all released under the Apache-2.0 license. For the full list, see our GitHub org.
Anchore’s tools follow a simple workflow: search and raise up evidence in the form of a Software Bill of Materials (SBOM) using Syft,
then analyze that SBOM with Grype for security vulnerabilities and Grant for open source license compliance.
%%{init: {'theme':'base', 'themeVariables': { 'primaryColor':'#f8fafc','primaryTextColor':'#1e293b','primaryBorderColor':'#cbd5e1','lineColor':'#94a3b8','secondaryColor':'#f8fafc','tertiaryColor':'#f8fafc'}}}%%
graph LR
software["📦 Your Software<br/><small>Container Images<br/>Filesystems<br/>Archives</small>"]
syft["🔍 Syft<br/><small>SBOM Generator</small>"]
sbom@{ shape: doc, label: "📋 SBOM<br/><small>Software Bill<br/>of Materials</small>"}
grype["🛡️ Grype<br/><small>Vulnerability<br/>Scanner</small>"]
grant["⚖️ Grant<br/><small>License<br/>Scanner</small>"]
vulns@{ shape: doc, label: "Security Report<br/><small>CVE findings</small>"}
licenses@{ shape: doc, label: "License Report<br/><small>Compliance info</small>"}
software -.->|scan| syft
syft -->|generates| sbom
sbom -->|analyze| grype
sbom -->|analyze| grant
grype -->|produces| vulns
grant -->|produces| licenses
classDef inputStyle fill:#f8fafc,stroke:#cbd5e1,stroke-width:2px,stroke-dasharray: 5 5,color:#64748b
classDef syftStyle fill:#fdf4ff,stroke:#e879f9,stroke-width:2px,color:#6b21a8
classDef grypleStyle fill:#eff6ff,stroke:#3b82f6,stroke-width:2px,color:#1e3a8a
classDef grantStyle fill:#f0fdf4,stroke:#00b388,stroke-width:2px,color:#065f46
classDef docStyle fill:#ffffff,stroke:#cbd5e1,stroke-width:1px,color:#475569
class software inputStyle
class syft syftStyle
class grype grypleStyle
class grant grantStyle
class sbom,vulns,licenses docStyle
This modular approach lets you generate the SBOM once with Syft, then use Grype and Grant independently to scan for different types of risk.
Syft
SBOM Generator and library
Syft (pronounced like sift) is an open-source command-line tool and Go library. Its primary function is to scan container images, file systems, and archives to automatically generate a Software Bill of Materials, making it easier to understand the composition of software.
Grype
Vulnerability Scanner
Grype (rhymes with hype) is an open-source vulnerability scanner specifically designed to analyze container images and filesystems. It works by comparing the software components it finds against a database of known vulnerabilities, providing a report of potential risks so they can be addressed.
Grant
License Scanner
Grant is an open-source command-line tool designed to discover and report on the software licenses present in container images, SBOM documents, or filesystems. It helps users understand the licenses of their software dependencies and can check them against user-defined policies to ensure compliance.
2 - Installation
Official and community maintained packages of Anchore OSS Tools
Any of the tools can be installed with:
curl -sSfL https://get.anchore.io/TOOLNAME | sudo sh -s -- -b /usr/local/bin
However, there are additional installation options for each tool, so see the individual pages for more information.
2.1 - Installing Syft
Official builds
The Anchore OSS team publish official source archives and binary builds of Syft for Linux, macOS and Windows. There are also numerous community-maintained builds of the tools for different platforms.
Installer script
Syft binaries are provided for Linux, macOS and Windows.
curl -sSfL https://get.anchore.io/syft | sudo sh -s -- -b /usr/local/bin
Install script options:
-b: Specify a custom installation directory (defaults to ./bin)
-d: More verbose logging levels (-d for debug, -dd for trace)
-v: Verify the signature of the downloaded artifact before installation (requires cosign to be installed)
Updating Syft
Syft checks for new versions on launch. It will print a message at the end of the output if the version in use is not the latest.
A newer version of syft is available for download: 1.20.0 (installed version is 1.19.2)
Docker container
docker pull anchore/syft
GitHub releases
Download the file for your operating system and architecture from the GitHub releases page
In the case of .deb or .rpm, install them using your package manager
For compressed archives, unpack the file, and copy the syft binary to a folder in your path such as /usr/local/bin
The Anchore OSS team publish official source archives and binary builds of Grype for Linux, macOS and Windows. There are also numerous community-maintained builds of the tools for different platforms.
Installer script
Grype binaries are provided for Linux, macOS and Windows.
curl -sSfL https://get.anchore.io/grype | sudo sh -s -- -b /usr/local/bin
Install script options:
-b: Specify a custom installation directory (defaults to ./bin)
-d: More verbose logging levels (-d for debug, -dd for trace)
-v: Verify the signature of the downloaded artifact before installation (requires cosign to be installed)
Updating Grype
Grype checks for new versions on launch. It will print a message at the end of the output if the version in use is not the latest.
A newer version of grype is available for download: 0.92.0 (installed version is 0.91.2)
Docker container
docker pull anchore/grype
GitHub releases
Download the file for your operating system and architecture from the GitHub releases page
In the case of .deb or .rpm, install them using your package manager
For compressed archives, unpack the file, and copy the grype binary to a folder in your path such as /usr/local/bin
Community builds of Grype
Arch Linux
sudo pacman -S grype-bin
Homebrew
brew tap anchore/grype
brew install grype
MacPorts
sudo port install grype
Winget
winget install Anchore.Grype
Scoop
scoop bucket add main
scoop install main/grype
Snapcraft
snap install grype
2.3 - Installing Grant
Official builds
The Anchore OSS team publish official source archives and binary builds for Linux and macOS. There are also some community-maintained builds of the tools for different platforms.
Installer script
Grant binaries are provided for Linux and macOS.
curl -sSfL https://get.anchore.io/grant | sudo sh -s -- -b /usr/local/bin
Install script options:
-b: Specify a custom installation directory (defaults to ./bin)
-d: More verbose logging levels (-d for debug, -dd for trace)
-v: Verify the signature of the downloaded artifact before installation (requires cosign to be installed)
GitHub releases
Download the file for your operating system and architecture from the GitHub releases page
In the case of .deb or .rpm, install them using your package manager
For compressed archives, unpack the file, and copy the grant binary to a folder in your path such as /usr/local/bin
Community builds of grant
Homebrew
brew tap anchore/grant
brew install grant
2.4 - Verifying Downloads
Verifying release assets after downloading
Why verify downloads?
Verifying your downloads ensures that:
The files haven’t been tampered with during transit
You’re installing authentic Anchore software
Your supply chain is secure from the start
All release artifacts include checksums, and the checksum file itself is cryptographically signed using cosign for verification.
Note
Installation scripts support automatic verification using the -v flag if you have cosign installed. This performs the same verification steps outlined below.
If you can’t use cosign, you can verify checksums manually. This verifies file integrity but not authenticity.
Security Note
Checksum verification only confirms the file hasn’t been corrupted. It doesn’t verify that the file is authentic. Use cosign verification when possible for better security.
Step 1: Download the files
Download your tool binary and the checksums file:
# Example for Syft v1.23.1wget https://github.com/anchore/syft/releases/download/v1.23.1/syft_1.23.1_darwin_arm64.tar.gz
wget https://github.com/anchore/syft/releases/download/v1.23.1/syft_1.23.1_checksums.txt
Learn how to create a Software Bill of Materials (SBOMs) for container images, filesystems, and archives using Syft.
3.1.1 - Getting Started
Use Syft to generate your first SBOM from container images, directories, or archives.
What is an SBOM?
A Software Bill of Materials (SBOM) is a detailed list of all libraries and components that make up software.
For developers, it’s crucial for tracking dependencies, identifying vulnerabilities, and ensuring license compliance.
For organizations, it provides transparency into the software supply chain to assess security risks.
Syft is a CLI tool for generating an SBOM from container images and filesystems.
Installation
Syft is provided as a single compiled executable and requires no external dependencies to run.
Run the command for your platform to download the latest release.
curl -sSfL https://get.anchore.io/syft | sudo sh -s -- -b /usr/local/bin
brew install syft
nuget install Anchore.Syft
Check out installation guide for full list of official and community-maintained packaging options.
Find packages within a container image
Run syft against a small container image; the output will be a simple human-readable table of the installed packages found:
syft alpine:latest
NAME VERSION TYPE
alpine-baselayout 3.6.8-r1 apk
alpine-baselayout-data 3.6.8-r1 apk
alpine-keys 2.5-r0 apk
alpine-release 3.21.3-r0 apk
apk-tools 2.14.6-r3 apk
busybox 1.37.0-r12 apk
busybox-binsh 1.37.0-r12 apk
...
This command will display the human-readable table and write SBOMs in both SPDX and CycloneDX formats, the two primary industry standards.
syft alpine:latest \ # what we're scanning -o table \ # a human-readable table to stdout -o spdx-json=alpine.spdx.json \ # SPDX-JSON formatted SBOM to a file -o cyclonedx-json=alpine.cdx.json # CycloneDX-JSON formatted SBOM to a file
The same table will be displayed, and two SBOM files will be created in the current directory.
Learn more
Syft supports multiple SBOM output formats, find out more about Output Formats.
Examine the SBOM file contents
We can use jq to extract specific package data from the SBOM files (by default Syft outputs JSON on a single line,
but you can enable pretty-printing with the SYFT_FORMAT_PRETTY=true environment variable).
Both formats structure package information differently:
SPDX format:
jq '.packages[].name' alpine.spdx.json
CycloneDX format:
jq '.components[].name' alpine.cdx.json
Both commands show the packages that Syft found in the container image:
By default, Syft shows only software visible in the final container image (the “squashed” representation).
To include software from all image layers, regardless of its presence in the final image, use --scope all-layers:
syft <image> --scope all-layers
More JSON examples
For more examples of working with Syft’s JSON output using jq, see the jq recipes.
FAQ
Does Syft need internet access?
Only for downloading container images. By default, scanning works offline.
What about private container registries?
Syft supports authentication for private registries. See Private Registries.
Can I use Syft in CI/CD pipelines?
Absolutely! Syft is designed for automation. Generate SBOMs during builds and scan them for vulnerabilities.
What data does Syft send externally?
Nothing. Syft runs entirely locally and doesn’t send any data to external services.
Explore the different scan targets Syft supports including container images, OCI registries, directories, files, and archives.
TL;DR
Syft automatically detects scan target type, simply pass it as an argument: syft <target>
Supports container images (Docker/Podman/Containerd/registries), directories, files, and archives
Use --from <type> to explicitly specify scan target type (e.g., --from registry to bypass local daemons)
Syft can generate an SBOM from a variety of scan targets including container images, directories, files, and archives.
In most cases, you can simply point Syft at what you want to analyze and it will automatically detect and catalog it correctly.
Catalog a container image from your local daemon or a remote registry:
syft alpine:latest
Catalog a directory (useful for analyzing source code or installed applications):
syft /path/to/project
Catalog a container image archive:
syft image.tar
To explicitly specify the scan target type, use the --from flag:
--from ARG
Description
docker
Use images from the Docker daemon
podman
Use images from the Podman daemon
containerd
Use images from the Containerd daemon
docker-archive
Use a tarball from disk for archives created from docker save
oci-archive
Use a tarball from disk for OCI archives (from Skopeo or otherwise)
Read directly from a path on disk (any single file)
registry
Pull image directly from a registry (bypass any container runtimes)
Instead of using the --from flag explicitly, you can instead:
provide no hint and let Syft automatically detect the scan target type implicitly based on the input provided
provide the scan target type as a URI scheme in the target argument (e.g., docker:alpine:latest, oci-archive:/path/to/image.tar, dir:/path/to/dir)
Scan Target-Specific Behaviors
Container Image Scan Targets
When working with container images, Syft applies the following defaults and behaviors:
Registry: If no registry is specified in the image reference (e.g. alpine:latest instead of docker.io/alpine:latest), Syft assumes docker.io
Platform: For unspecific image references (tags) or multi-arch images pointing to an index (not a manifest), Syft analyzes the linux/amd64 manifest by default.
Use the --platform flag to target a different platform.
When you provide an image reference without specifying a scan target type (i.e. no --from flag), Syft attempts to resolve the image using the following scan targets in order:
Docker daemon
Podman daemon
Containerd daemon
Direct registry access
For example, when you run syft alpine:latest, Syft will first check your local Docker daemon for the image.
If Docker isn’t available, it tries Podman, then Containerd, and finally attempts to pull directly from the registry.
You can override this default behavior with the default-image-pull-source configuration option to always prefer a specific scan target.
See Configuration for more details.
Directory Scan Targets
When you provide a directory path as the scan target, Syft recursively scans the directory tree to catalog installed software packages and files.
When you point Syft at a directory (especially system directories like /), it automatically skips certain filesystem types to improve
scan performance and avoid indexing areas that don’t contain installed software packages.
Filesystems always skipped
proc / procfs - Virtual filesystem for process information
sysfs - Virtual filesystem for kernel and device information
devfs / devtmpfs / udev - Device filesystems
Filesystems conditionally skipped
tmpfs filesystems are only skipped when mounted at these specific locations:
/dev - Device files
/sys - System information
/run and /var/run - Runtime data and process IDs
/var/lock - Lock files
These paths are excluded because they contain virtual or temporary runtime data rather than installed software packages.
Skipping them significantly improves scan performance and enables you to catalog entire system root directories without getting stuck scanning thousands of irrelevant entries.
Syft identifies these filesystems by reading your system’s mount table (/proc/self/mountinfo on Linux).
When a directory matches one of these criteria, the entire directory tree under that mount point is skipped.
File types excluded
These file types are never indexed during directory scans:
Character devices
Block devices
Sockets
FIFOs (named pipes)
Irregular files
Regular files, directories, and symbolic links are always processed.
Archive Scan Targets
Syft automatically detects and unpacks common archive formats, then catalogs their contents.
If an archive is a container image archive (from docker save or skopeo copy), Syft treats it as a container image.
Supported archive formats:
Standard archives:
.zip
.tar (uncompressed)
.rar (read-only extraction)
Compressed tar variants:
.tar.gz / .tgz
.tar.bz2 / .tbz2
.tar.br / .tbr (brotli)
.tar.lz4 / .tlz4
.tar.sz / .tsz (snappy)
.tar.xz / .txz
.tar.zst / .tzst (zstandard)
Standalone compression formats (extracted if containing tar):
.gz (gzip)
.bz2 (bzip2)
.br (brotli)
.lz4
.sz (snappy)
.xz
.zst / .zstd (zstandard)
OCI Archives and Layout Scan Targets
Syft automatically detects OCI archive and directory structures (including OCI layouts and SIF files) and catalogs them accordingly.
OCI archives and layouts are particularly useful for CI/CD pipelines, as they allow you to catalog images, scan for vulnerabilities, or perform other checks without publishing to a registry. This provides a powerful pattern for build-time gating.
When using container runtime scan targets (Docker, Podman, or Containerd):
Missing images: If an image doesn’t exist locally in the container runtime, Syft attempts to pull it from the registry via the runtime
Private images: You must be logged in to the registry via the container runtime (e.g., docker login) or have credentials configured for direct registry access. See Authentication with Private Registries for more details.
Environment Variables
Syft respects the following environment variables for each container runtime:
Scan Target
Environment Variables
Description
Docker
DOCKER_HOST
Docker daemon socket/host address (supports ssh:// for remote connections)
DOCKER_TLS_VERIFY
Enable TLS verification (auto-sets DOCKER_CERT_PATH if not set)
DOCKER_CERT_PATH
Path to TLS certificates (defaults to ~/.docker if DOCKER_TLS_VERIFY is set)
DOCKER_CONFIG
Override default Docker config directory
Podman
CONTAINER_HOST
Podman socket/host address (e.g., unix:///run/podman/podman.sock or ssh://user@host/path/to/socket)
CONTAINER_SSHKEY
SSH identity file path for remote Podman connections
Configured via CONTAINER_HOST, CONTAINER_SSHKEY, and CONTAINER_PASSPHRASE environment variables
Used for remote Podman instances
Direct Registry Access
The registry scan target bypasses container runtimes entirely and pulls images directly from the registry.
Credentials are resolved in the following order:
Syft first attempts to use default Docker credentials from ~/.docker/config.json if they exist
If default credentials are not available, you can provide credentials via environment variables. See Authentication with Private Registries for more details.
Troubleshooting
Image not found in local daemon
If Syft reports an image doesn’t exist but you know it’s available:
Check which daemon has the image: Run docker images, podman images, or nerdctl images to see where the image exists
Specify the scan target type explicitly: Use --from docker, --from podman, or --from containerd to target the correct daemon
Pull from registry: Use --from registry to bypass local daemons and pull directly
Authentication failures with private registries
If you get authentication errors when scanning private images:
For daemon scan targets: Ensure you’re logged in via the daemon (e.g., docker login registry.example.com)
For registry scan target: Configure credentials in ~/.docker/config.json or use environment variables (see Private Registries)
Verify credentials: Check that your credentials haven’t expired and have appropriate permissions
Podman connection issues
If Syft can’t connect to Podman:
Start the service: Run podman system service to start the Podman socket
Check socket location: Verify the socket exists at $XDG_RUNTIME_DIR/podman/podman.sock or /run/podman/podman.sock
Use environment variable: Set CONTAINER_HOST to point to your Podman socket location
Slow directory scans
If scanning a directory takes too long:
Exclude unnecessary paths: Use file selection options to skip build artifacts, caches, or virtual environments (see File Selection)
Avoid system directories: Scanning / includes all mounted filesystems; consider scanning specific application directories instead
Check mount points: Ensure you’re not accidentally scanning network mounts or remote filesystems
Some output formats support multiple schema versions. Specify a version by appending @<version> to the format name:
syft <source> -o <format>@<version>
Examples:
# Use CycloneDX JSON version 1.4syft <source> -o cyclonedx-json@1.4
# Use SPDX JSON version 2.2syft <source> -o spdx-json@2.2
# Default to latest version if not specifiedsyft <source> -o cyclonedx-json
Formats with version support:
cyclonedx-json: 1.2, 1.3, 1.4, 1.5, 1.6
cyclonedx-xml: 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6
spdx-json: 2.2, 2.3
spdx-tag-value: 2.1, 2.2, 2.3
When no version is specified, Syft uses the latest supported version of the format.
You can both display to terminal and write to file:
syft <source> \
-o table \ # report to stdout -o json=sbom.json # write to file
FAQ
Which format should I use?
For human review: Use table (default) for quick package lists
For automation and queries: Use json to access all Syft data including file details, relationships, and metadata
For compliance and sharing: Use spdx-json or cyclonedx-json - both are widely supported industry standards
For custom formats: Use template to create your own output format
Can I convert between formats?
Yes! See the Format Conversion guide to convert existing SBOMs between formats without re-scanning.
Do all formats contain the same information?
No. Syft’s native json format contains the most complete information. Standard formats (SPDX, CycloneDX) contain package data but may not include all file details or Syft-specific metadata. Some data may be omitted or transformed to fit the target schema.
Which version should I use for SPDX or CycloneDX?
Use the latest version (default) unless you need compatibility with specific tools that require older versions. Check your downstream tools’ documentation for version requirements.
Learn how to work with Syft’s native JSON format including querying with jq, extracting metadata, and understanding the SBOM structure.
Syft’s native JSON format provides the most comprehensive view of discovered software components, capturing all package metadata, file details, relationships, and source information.
{
"artifacts": [], // Package nodes discovered
"artifactRelationships": [], // Edges between packages and files
"files": [], // File nodes discovered
"source": {}, // What was scanned (the image, directory, etc.)
"distro": {}, // Linux distribution discovered
"descriptor": {}, // Syft version and configuration that captured this SBOM
"schema": {} // Schema version
}
Package (artifacts)
A software package discovered by Syft (library, application, OS package, etc.).
{
"id": "74d9294c42941b37", // Unique identifier for this package that is content addressable
"name": "openssl",
"version": "1.1.1k",
"type": "apk", // Package ecosystem (apk, deb, npm, etc.)
"foundBy": "apk-cataloger",
"locations": [
// Paths used to populate information on this package object
{
"path": "/lib/apk/db/installed", // Always the real-path
"layerID": "sha256:...",
"accessPath": "/lib/apk/db/installed", // How Syft accessed the file (may be a symlink)
"annotations": {
"evidence": "primary"// Qualifies the kind of evidence extracted from this location (primary, supporting)
}
}
],
"licenses": [
{
"value": "Apache-2.0", // Raw value discovered
"spdxExpression": "Apache-2.0", // Normalized SPDX expression of the discovered value
"type": "declared", // "declared", "concluded", or "observed"
"urls": ["https://..."],
"locations": [] // Where license was found
}
],
"language": "c",
"cpes": [
{
"cpe": "cpe:2.3:a:openssl:openssl:1.1.1k:*:*:*:*:*:*:*",
"source": "nvd-dictionary"// Where the CPE was derived from (nvd-dictionary or syft-generated)
}
],
"purl": "pkg:apk/alpine/openssl@1.1.1k",
"metadata": {} // Ecosystem-specific fields (varies by type)
}
File
A file found on disk or referenced in package manager metadata.
{
"id": "def456",
"location": {
"path": "/usr/bin/example",
"layerID": "sha256:..."// For container images
},
"metadata": {
"mode": 493, // File permissions in octal
"type": "RegularFile",
"mimeType": "application/x-executable",
"size": 12345// Size in bytes
},
"digests": [
{
"algorithm": "sha256",
"value": "abc123..." }
],
"licenses": [
{
"value": "Apache-2.0", // Raw value discovered
"spdxExpression": "Apache-2.0", // Normalized SPDX expression of the discovered value
"type": "declared", // "declared", "concluded", or "observed"
"evidence": {
"confidence": 100,
"offset": 1234, // Byte offset in file
"extent": 567// Length of match
}
}
],
"executable": {
"format": "elf", // "elf", "pe", or "macho"
"hasExports": true,
"hasEntrypoint": true,
"importedLibraries": [
// Shared library dependencies
"libc.so.6",
"libssl.so.1.1" ],
"elfSecurityFeatures": {
// ELF binaries only
"symbolTableStripped": false,
"stackCanary": true, // Stack protection
"nx": true, // No-Execute bit
"relRO": "full", // Relocation Read-Only
"pie": true// Position Independent Executable
}
}
}
Relationship
Connects any two nodes (package, file, or source) with a typed relationship.
{
"parent": "package-id", // Package, file, or source ID
"child": "file-id",
"type": "contains"// contains, dependency-of, etc.
}
Source
Information about what was scanned (container image, directory, file, etc.).
The path field always contains the real path after resolving symlinks, while accessPath shows how Syft accessed the file (which may be through a symlink).
The evidence annotation indicates whether this location was used to discover the package (primary) or contains only auxiliary information (supporting).
Descriptor
Syft version and configuration used to generate this SBOM.
jq is a command-line tool for querying and manipulating JSON.
The following examples demonstrate practical queries for working with Syft JSON output.
Find packages by name pattern
Uses regex pattern matching to find security-critical packages
.artifacts[] | select(.name | test("^(openssl|ssl|crypto)")) |# Regex pattern match on package name {
name,
version,
type# Package type (apk, deb, rpm, etc.) }
Provides a summary count of packages per ecosystem
[.artifacts[]] | group_by(.type) |# Group packages by ecosystem typemap({
type: .[0].type,
count: length # Count packages in each group }) | sort_by(.count) | reverse # Highest count first
Configure which package catalogers Syft uses to discover software components including language-specific and file-based catalogers.
TL;DR
Syft automatically picks the right catalogers for you (recommended for most users)
Scanning a container image? Finds installed packages (like Python packages in site-packages)
Scanning a directory? Finds both installed packages and declared dependencies (like requirements.txt)
Want to customize? Use --select-catalogers to filter, add, or remove catalogers
Need complete control? Use --override-default-catalogers to replace all defaults
Catalogers are Syft’s detection modules that identify software packages in your projects.
Each cataloger specializes in finding specific types of packages—for example, python-package-cataloger finds Python dependencies declared in requirements.txt,
while python-installed-package-cataloger finds Python packages that have already been installed.
Syft includes dozens of catalogers covering languages like Python, Java, Go, JavaScript, Ruby, Rust, and more, as well as OS packages (APK, RPM, DEB) and binary formats.
Default Behavior
Syft uses different cataloger sets depending on what you’re scanning:
Scan Type
Default Catalogers
What They Find
Example
Container Image
Image-specific catalogers
Installed packages only
Python packages in site-packages
Directory
Directory-specific catalogers
Installed packages + declared dependencies
Python packages in site-packages AND requirements.txt
This behavior ensures accurate results across different contexts. When you scan an image, Syft assumes installation steps
have completed –this way you are getting results for software that is positively present.
When you scan a directory (like a source code repository), Syft looks for both what’s installed and what’s declared as
a dependency –this way you are getting results for not only what’s installed but also what you intend to install.
Why use different catalogers for different sources?
Most of the time, files that hint at the intent to install software do not have enough information in them to determine the exact version of the package that would be installed.
For example, a requirements.txt file might specify a package without a version, or with a version range.
By looking at installed packages in an image, after any build tooling has been invoked, Syft can provide more accurate version information.
syft <source-directory> --select-catalogers python
# Uses: python-installed-package-cataloger, python-package-cataloger# Finds: Packages in site-packages + requirements.txt, setup.py, Pipfile, etc.
Viewing Active Catalogers
The most reliable way to see which catalogers Syft used is to check the SBOM itself. Every SBOM captures both the catalogers that were requested and those that actually ran:
This shows what catalogers were attempted, not just what found packages. The requested field shows your cataloger selection strategy, while used lists every cataloger that ran.
You can also see cataloger activity in real-time using verbose logging, though this is less comprehensive and not as direct.
Exploring Available Catalogers
Use the syft cataloger list command to see all available catalogers, their tags, and test selection expressions.
List all catalogers
syft cataloger list
Output shows file and package catalogers with their tags:
You need catalogers from both image and directory sets
You want to use catalogers that aren’t in the default set
You need precise control regardless of scan type
Warning
Overriding defaults can lead to incomplete or inaccurate results if you don’t include all necessary catalogers. Use --select-catalogers for most cases.
Examples by Use Case
Filtering to Specific Languages
Scan for only Python packages using defaults for your scan type:
syft <target> --select-catalogers python
Scan for only Java and Go packages:
syft <target> --select-catalogers java,go
Adding Catalogers
Use defaults and also include the SBOM cataloger (which finds embedded SBOMs):
syft <target> --select-catalogers +sbom-cataloger
Scan with defaults plus both SBOM and binary catalogers:
Scan for Go packages, always include SBOM cataloger, but exclude binary analysis:
syft <container-image> --select-catalogers go,+sbom-cataloger,-binary
# Result: go-module-binary-cataloger, sbom-cataloger# (binary cataloger excluded even though it's in go tag)
Check which catalogers ran and whether they found packages:
# See which catalogers were usedsyft <target> -o json | jq '.descriptor.configuration.catalogers.used'# See which catalogers found packagessyft <target> -o json | jq '.artifacts[].foundBy'# See packages found by a specific catalogersyft <target> -o json | jq '.artifacts[] | select(.foundBy == "python-package-cataloger") | .name'
If your expected cataloger isn’t in the used list:
Verify the cataloger exists for your scan type: Use syft cataloger list --select-catalogers <tag> to preview
Check your selection expressions: You may have excluded it with - or not included it in your filter
Check file locations: Some catalogers look for specific paths (e.g., site-packages for Python)
If the cataloger ran but found nothing, check that:
Package files exist in the scanned source
Files are properly formatted
Files are in the expected locations for that cataloger
How do I know if I’m using image or directory defaults?
Name: The unique identifier for a single cataloger (e.g., python-package-cataloger)
Tag: A label that groups multiple catalogers (e.g., python includes both python-package-cataloger and python-installed-package-cataloger)
Use tags when you want to downselect from the default catalogers, and names when you need to target a specific cataloger.
Why use –select-catalogers vs –override-default-catalogers?
--select-catalogers: Respects Syft’s automatic image/directory behavior, safer for most use cases
--override-default-catalogers: Ignores scan type, gives complete control, requires more knowledge
When in doubt, use --select-catalogers.
Technical Reference
For reference, here’s the formal logic Syft uses for cataloger selection:
image_catalogers = all_catalogers AND catalogers_tagged("image")
directory_catalogers = all_catalogers AND catalogers_tagged("directory")
default_catalogers = image_catalogers OR directory_catalogers
sub_selected_catalogers = default_catalogers INTERSECT catalogers_tagged(TAG) [ UNION sub_selected_catalogers ... ]
base_catalogers = default_catalogers OR sub_selected_catalogers
final_set = (base_catalogers SUBTRACT removed_catalogers) UNION added_catalogers
This logic applies when using --select-catalogers. The --override-default-catalogers flag bypasses the default cataloger selection entirely and starts with the specified catalogers instead.
Filter files: Use File Selection to exclude irrelevant paths before cataloging
3.1.6 - File Selection
Control which files and directories Syft includes or excludes when generating SBOMs.
TL;DR
By default, Syft includes information about files owned by packages into the SBOM
Select which files to include: file.metadata.selection can be one of all, none, or owned-by-package
Exclude paths and globs: --exclude '**/node_modules/**'
By default, Syft catalogs file details and digests for files owned by discovered packages. You can change this behavior using the SYFT_FILE_METADATA_SELECTION environment variable or the file.metadata.selection configuration option.
Available options:
all: capture all files from the search space
owned-by-package: capture only files owned by packages (default)
none: disable file information capture
Excluding file paths
You can exclude specific files and paths from scanning using glob patterns with the --exclude parameter. Use multiple --exclude flags to specify multiple patterns.
# Exclude a specific directorysyft <source> --exclude /etc
# Exclude files by patternsyft <source> --exclude './out/**/*.json'# Combine multiple exclusionssyft <source> --exclude './out/**/*.json' --exclude /etc --exclude '**/*.log'
Tip
Always wrap glob patterns in single quotes to prevent your shell from expanding wildcards:
syft <source> --exclude '**/*.json'# Correctsyft <source> --exclude **/*.json # May not work as expected
Exclusion behavior by source type
How Syft interprets exclusion patterns depends on whether you’re scanning an image or a directory.
Image scanning
When scanning container images, Syft scans the entire filesystem. Use absolute paths for exclusions:
# Exclude system directoriessyft alpine:latest --exclude /etc --exclude /var
# Exclude files by pattern across entire filesystemsyft alpine:latest --exclude '/usr/**/*.txt'
Directory scanning
When scanning directories, Syft resolves exclusion patterns relative to the specified directory. All exclusion patterns must begin with ./, */, or **/.
# Scanning /usr/foosyft /usr/foo --exclude ./package.json # Excludes /usr/foo/package.jsonsyft /usr/foo --exclude '**/package.json'# Excludes all package.json files under /usr/foosyft /usr/foo --exclude './out/**'# Excludes everything under /usr/foo/out
Path prefix requirements for directory scans:
Pattern
Meaning
Example
./
Relative to scan directory root
./config.json
*/
One level of directories
*/temp
**/
Any depth of directories
**/node_modules
Note
When scanning directories, you cannot use absolute paths like /etc or /usr/**/*.txt. The pattern must begin with ./, */, or **/ to be resolved relative to your specified scan directory.
Missing quotes: Wrap patterns in single quotes to prevent shell expansion ('**/*.json' not **/*.json)
Wrong path prefix: Directory scans require ./, */, or **/ prefix; absolute paths like /etc won’t work
Pattern syntax: Use glob syntax, not regex (e.g., **/*.txt not .*\.txt)
What’s the difference between owned-by-package and all file metadata?
owned-by-package (default): Only catalogs files that belong to discovered packages (e.g., files in an RPM’s file manifest)
all: Catalogs every file in the scan space, which significantly increases SBOM size and scan time
Use all when you need complete file listings for compliance or audit purposes.
Can I exclude directories based on .gitignore?
Not directly, but you can convert .gitignore patterns to --exclude flags. Note that .gitignore syntax differs from glob patterns, so you may need to adjust patterns (e.g., node_modules/ becomes **/node_modules/**).
Do exclusions affect package detection?
Yes! If you exclude a file that a cataloger needs (like package.json or requirements.txt), Syft won’t detect packages from that file. Exclude carefully to avoid missing dependencies.
Next: Learn about Using Templates to create custom SBOM output formats tailored to your specific needs.
Additional resources:
Configure catalogers: See Package Catalogers to control which package types are detected
Configuration file: Use Configuration to set persistent exclusion patterns
Scan target types: Review Supported Scan Targets to understand scanning behavior for different scan target types
3.1.7 - Using Templates
Create custom SBOM output formats using Go templates with available data fields to build tailored reports for specific tooling or compliance requirements.
Syft lets you define custom output formats using Go templates. This is useful for generating custom reports, integrating with specific tools, or extracting only the data you need.
How to use templates
Set the output format to template and specify the template file path:
Templates receive the same data structure as the syft-json output format. The Syft JSON schema is the source of truth for all available fields and their structure.
To see what data is available:
# View the full JSON structuresyft <image> -o json
# Explore specific fieldssyft <image> -o json | jq '.artifacts[0]'
Key fields commonly used in templates:
.artifacts - Array of discovered packages
.files - Array of discovered files
.source - Information about what was scanned
.distro - Detected Linux distribution (if applicable)
If you have templates from before Syft v0.102.0 that no longer work, set format.template.legacy: true in your configuration. This uses internal Go structs instead of the JSON output schema.
Long-term support for this legacy option is not guaranteed.
The ability to convert existing SBOMs means you can create SBOMs in different formats quickly, without the need to regenerate the SBOM from scratch, which may take significantly more time.
We support formats with wide community usage AND good encode/decode support by Syft. The supported formats are:
Syft JSON (-o json)
SPDX JSON (-o spdx-json)
SPDX tag-value (-o spdx-tag-value)
CycloneDX JSON (-o cyclonedx-json)
CycloneDX XML (-o cyclonedx-xml)
Conversion example:
syft alpine:latest -o syft-json=sbom.syft.json # generate a syft SBOMsyft convert sbom.syft.json -o cyclonedx-json=sbom.cdx.json # convert it to CycloneDX
Best practices
Use Syft JSON as the source format
Generate and keep Syft JSON as your primary SBOM. Convert from it to other formats as needed:
# Generate Syft JSON (native format with complete data)syft <source> -o json=sbom.json
# Convert to other formatssyft convert sbom.json -o spdx-json=sbom.spdx.json
syft convert sbom.json -o cyclonedx-json=sbom.cdx.json
Converting between non-Syft formats loses data. Syft JSON contains all information Syft extracted, while other formats use different schemas that can’t represent the same fields.
Converting between formats may lose data. Packages (names, versions, licenses) transfer reliably, while tool metadata, source details, and format-specific fields may not. Use Syft JSON as the source format to minimize data loss.
Conversions from Syft JSON to SPDX or CycloneDX preserve all standard SBOM fields. Converted output matches directly-generated output (only timestamps and IDs differ).
Avoid chaining conversions (e.g., SPDX → CycloneDX). Each step may lose format-specific data.
Yes, but it’s not recommended. Converting between non-Syft formats loses data with each conversion. If you have the original Syft JSON or can re-scan the source, that’s a better approach.
Why is some data missing after conversion?
Different SBOM formats have different schemas with different capabilities. SPDX and CycloneDX can’t represent all Syft metadata. Converting from Syft JSON to standard formats works best; converting between standard formats loses more data.
Is conversion faster than re-scanning?
Yes, significantly. Conversion takes milliseconds while scanning can take seconds to minutes depending on source size. This makes conversion ideal for CI/CD pipelines that need multiple formats.
Can I convert back to Syft JSON from SPDX?
Yes, but you’ll lose Syft-specific metadata that doesn’t exist in SPDX (like cataloger information, layer details, and file metadata). The result won’t match the original Syft JSON.
Which format versions are supported?
See the Output Formats guide for supported versions of each format. Syft converts to the latest version by default, but you can specify older versions (e.g., -o spdx-json@2.2).
Available formats: Check Output Formats for all supported SBOM formats
Direct generation: Learn about generating formats directly in Getting Started
3.1.9 - Attestation
Generate cryptographically signed SBOM attestations using in-toto and Sigstore to create, verify, and attach attestations to container images for supply chain security.
Experimental Feature
This feature is experimental and may change in future releases.
TL;DR
Sign SBOMs: syft attest --output cyclonedx-json <image>(keyless via OIDC)
Or with keys: syft attest --key cosign.key --output spdx-json <image>
Requires cosign ≥ v1.12.0 and registry write access
Verify: cosign verify-attestation
Attestations attach to images in OCI registries
Overview
An attestation is cryptographic proof that you created a specific SBOM for a container image. When you publish an image, consumers need to trust that the SBOM accurately describes the image contents. Attestations solve this by letting you sign SBOMs and attach them to images, enabling consumers to verify authenticity.
Syft supports two approaches:
Keyless attestation: Uses your identity (GitHub, Google, Microsoft) as trust root via Sigstore. Best for CI/CD and teams.
Local key attestation: Uses cryptographic key pairs you manage. Best for air-gapped environments or specific security requirements.
Write access to the OCI registry where you’ll publish attestations
Registry authentication configured (e.g., docker login for Docker Hub)
For local key attestations, you’ll also need a key pair. Generate one with:
cosign generate-key-pair
This creates cosign.key (private key) and cosign.pub (public key). Keep the private key secure.
Keyless attestation
Keyless attestation uses Sigstore to tie your OIDC identity (GitHub, Google, or Microsoft account) to the attestation. This eliminates key management overhead.
Create a keyless attestation
syft attest --output cyclonedx-json <IMAGE>
Replace <IMAGE> with your image reference (e.g., docker.io/myorg/myimage:latest). You must have write access to this image.
What happens:
Syft opens your browser to authenticate via OIDC (GitHub, Google, or Microsoft)
After authentication, Syft generates the SBOM
Sigstore signs the SBOM using your identity
The attestation is uploaded to the OCI registry alongside your image
Verification for docker.io/myorg/myimage:latest --
The following checks were performed on each of these signatures:
- The cosign claims were validated
- The signatures were verified against the specified public key
- Any certificates were verified against the Fulcio roots.
Learn how to scan container images, filesystems, and SBOMs for known software vulnerabilities.
Vulnerability scanning is the automated process of proactively identifying security weaknesses and known exploits within software and systems.
This is crucial because it helps developers and organizations find and fix potential security holes before malicious actors can discover and exploit them, thus protecting data and maintaining system integrity.
Grype is an open-source vulnerability scanner specifically designed to analyze container images and filesystems.
It works by comparing the software components it finds against a database of known vulnerabilities, providing a report of potential risks so they can be addressed.
3.2.1 - Getting Started
Use Grype to scan your container images, directories, or archives for known vulnerabilities.
What is Vulnerability Scanning?
Vulnerability scanning is the process of identifying known security vulnerabilities in software packages and dependencies.
For developers, it helps catch security issues early in development, before they reach production.
For organizations, it’s essential for maintaining security posture and meeting compliance requirements.
Grype is a CLI tool for scanning container images, filesystems, and SBOMs for known vulnerabilities.
Installation
Grype is provided as a single compiled executable and requires no external dependencies to run.
Run the command for your platform to download the latest release.
curl -sSfL https://get.anchore.io/grype | sudo sh -s -- -b /usr/local/bin
brew install grype
nuget install Anchore.Grype
Check out installation guide for full list of official and community-maintained packaging options.
Scan a container image for vulnerabilities
Run grype against a small container image. Grype will download the latest vulnerability database
and output simple human-readable table of packages that are vulnerable:
Grype can scan container images directly, but it can also scan an existing SBOM document.
Note
This presumes you already created alpine_latest-spdx.json using Syft, or some other tool. If not, go to SBOM Generation Getting Started and create it now.
grype alpine_latest-spdx.json
Create a vulnerability report in JSON format
The JSON-formatted output from Grype can be processed or visualized by other tools.
Create the vulnerability report using the --output flag:
Only for downloading container images and the vulnerability database. After the initial database download, scanning works offline until you update the database.
What about private container registries?
Grype supports authentication for private registries. See Private Registries.
Can I use Grype in CI/CD pipelines?
Absolutely! Grype is designed for automation. Scan images or SBOMs during builds and fail pipelines based on severity thresholds.
What data does Grype send externally?
Nothing. Grype runs entirely locally and doesn’t send any data to external services.
Explore the different scan targets Grype supports including container images, directories, SBOMs, and individual packages
TL;DR
Grype automatically detects scan target type, simply pass it as an argument: grype <target>
Supports container images (Docker/Podman/Containerd/registries), directories, files, archives, and SBOMs
Scan individual packages via PURLs or CPE identifiers
Use --from <type> to explicitly specify scan target type
Grype can scan a variety of scan targets including container images, directories, files, archives, SBOMs, and individual packages.
In most cases, you can simply point Grype at what you want to analyze and it will automatically detect and scan it correctly.
Scan a container image from your local daemon or a remote registry:
grype alpine:latest
Scan a directory or file:
grype /path/to/project
Scan an SBOM:
grype sbom.json
To explicitly specify the scan target type, use the --from flag:
--from ARG
Description
docker
Use images from the Docker daemon
podman
Use images from the Podman daemon
containerd
Use images from the Containerd daemon
docker-archive
Use a tarball from disk for archives created from docker save
oci-archive
Use a tarball from disk for OCI archives
oci-dir
Read directly from a path on disk for OCI layout directories
singularity
Read directly from a Singularity Image Format (SIF) container file on disk
dir
Read directly from a path on disk (any directory)
file
Read directly from a path on disk (any single file)
registry
Pull image directly from a registry (bypass any container runtimes)
sbom
Read SBOM from file (supports Syft JSON, SPDX, CycloneDX formats)
purl
Scan individual packages via Package URL identifiers
Instead of using the --from flag explicitly, you can instead:
provide no hint and let Grype automatically detect the scan target type implicitly based on the input provided
provide the scan target type as a URI scheme in the target argument (e.g., docker:alpine:latest, oci-archive:/path/to/image.tar, dir:/path/to/dir)
For scan targets that are uniquely supported by Grype, see the sections below.
SBOM Scan Targets
You can scan pre-generated SBOMs instead of scanning the scan target directly. This approach offers several benefits:
Faster scans since package cataloging is already complete
Ability to cache and reuse SBOMs
Standardized vulnerability scanning across different tools
Scan an SBOM file
Grype scans SBOM files in multiple formats. You can provide an explicit sbom: prefix or just provide the file path:
Explicit SBOM prefix:
grype sbom:sbom.json
Implicit detection:
grype sbom.json
Grype automatically detects the SBOM format. Supported formats include:
Syft JSON
SPDX JSON, XML, and tag-value
CycloneDX JSON and XML
Use the explicit sbom: prefix when the file path might be ambiguous or when you want to be clear about the input type.
Scan an SBOM from stdin
You can pipe SBOM output directly from Syft or other SBOM generation tools:
Syft → Grype pipeline:
syft alpine:latest -o json | grype
Read SBOM from file via stdin:
Grype detects stdin input automatically when no command-line argument is provided and stdin is piped:
cat sbom.json | grype
Note
Grype will not attempt to read from redirected stdin in interactive terminal sessions when the use of a pipe is not detected.
Thus grype < sbom.json will not work in an interactive terminal session.
Package scan targets
You can scan specific packages without scanning an entire image or directory. This is useful for:
Testing whether a specific package has vulnerabilities
Lightweight vulnerability checks
Compliance scanning for specific dependencies
Grype supports two formats for individual package scanning: Package URLs (PURLs) and Common Platform Enumerations (CPEs).
When Grype receives input, it checks for PURL format first, then CPE format, before trying other scan target types.
Scan Package URLs (PURLs)
Package URLs (PURLs) provide a standardized way to identify software packages.
Without either the distro qualifier or the --distro flag hint, Grype may not find distribution-specific vulnerabilities.
Other qualifiers include:
upstream: The upstream package name or version. Vulnerability information tends to be tracked with the source or origin
package instead of the installed package itself (e.g. libcrypto
might be installed but the pacakge it was built from is openssl
which is where vulnerabilities are attributed to)
epoch: The epoch value for RPM packages. This is necessary when the package in question has changed the methodology for versioning
(e.g., switching from date-based versions to semantic versions) and the epoch is used to indicate that change.
You can scan multiple packages from a file. The file contains one PURL per line:
# contents of packages.txt follow, which must be a text file with one PURL per line
pkg:npm/lodash@4.17.20
pkg:pypi/requests@2.25.1
pkg:maven/org.apache.commons/commons-lang3@3.12.0
grype ./packages.txt
Grype scans all the packages in the file:
NAME INSTALLED FIXED IN TYPE VULNERABILITY SEVERITY
lodash 4.17.20 4.17.21 npm GHSA-35jh-r3h4-6jhm High
requests 2.25.1 2.31.0 python GHSA-j8r2-6x86-q33q Medium
commons-lang3 3.12.0 3.18.0 java-archive GHSA-j288-q9x7-2f5v Medium
...
Filter vulnerabilities: Use result filtering to focus on specific findings
Private registries: Set up authentication for private images
3.2.3 - Supported package ecosystems
Learn how Grype selects vulnerability data for different package types and what level of accuracy to expect
TL;DR
OS packages use distribution-specific security feeds (Alpine, Debian, Ubuntu, RHEL, etc.)
Language packages use GitHub Security Advisories (npm, PyPI, Maven, Go, etc.)
Other packages fall back to CPE matching against NVD (may have false positives)
Grype automatically selects the right data source based on package type
Grype automatically selects the right vulnerability data source based on the package type and distribution information in your SBOM. This guide explains how Grype chooses which vulnerability feed to use and what level of accuracy to expect.
How Grype chooses vulnerability data
Grype selects vulnerability feeds based on package type:
OS packages (apk, deb, rpm, portage, alpm) use vulnerability data sourced from distribution-specific security feeds.
Language packages (npm, PyPI, Maven, Go modules, etc.) use GitHub Security Advisories.
Other packages (binaries, Homebrew, Jenkins plugins, etc.) fall back to CPE matching against the NVD.
OS packages
When Grype scans an OS package, it uses vulnerability data sourced from distribution security feeds.
Distribution maintainers curate these feeds and provide authoritative information about vulnerabilities affecting specific distribution versions.
For example, when you scan Debian 10, Grype looks for vulnerabilities affecting Debian 10 packages:
$ grype debian:10
NAME INSTALLED FIXED IN TYPE VULNERABILITY SEVERITY
libgcrypt20 1.8.4-5+deb10u1 (won't fix) deb CVE-2021-33560 High
bash 5.0-4 deb CVE-2019-18276 Negligible
libidn2-0 2.0.5-1+deb10u1 (won't fix) deb CVE-2019-12290 High
OS distributions
Grype supports major Linux distributions with dedicated vulnerability feeds,
including Alpine, Debian, Ubuntu, RHEL, SUSE, and many others.
Some distributions have mature security tracking programs that report both fixed and unfixed vulnerabilities, providing comprehensive coverage.
Derivative distributions automatically use their parent distribution’s vulnerability feed.
Grype maps derivative distributions to their upstream source using the ID_LIKE field from /etc/os-release.
For example, Rocky Linux and AlmaLinux use the RHEL vulnerability feed, while Raspbian uses Debian’s feed.
When scanning Rocky Linux, Grype uses Red Hat security data:
The distro type shows rockylinux, but Grype searches the RHEL vulnerability feed automatically.
You don’t need to configure this mapping –it happens transparently based on the distribution’s ID_LIKE field.
Learn more
For a complete list of supported Linux distributions and their versions, see the OS support reference.
Language packages use vulnerability data from GitHub Security Advisories (GHSA).
GitHub maintains security advisories for major package ecosystems, sourced from package maintainers, security researchers, and automated scanning.
When you scan a JavaScript package, Grype searches GHSA for npm advisories:
$ grype node:18-alpine
NAME INSTALLED FIXED IN TYPE VULNERABILITY SEVERITY
cross-spawn 7.0.3 7.0.5 npm GHSA-3xgq-45jj-v275 High
Supported language ecosystems
Grype supports these language ecosystems through GHSA:
For language packages, Grype searches GHSA by package name and version, applying ecosystem-specific version comparison rules to determine if your package version falls within the vulnerable range.
In addition to language packages, Bitnami packages are searched against Bitnami’s vulnerability feed in a similar manner.
Other packages
Packages without dedicated feeds use CPE fallback matching
Packages using CPE matching
These package types rely on Common Platform Enumeration (CPE) matching against the National Vulnerability Database (NVD):
Binary executables
Homebrew packages
Jenkins plugins
Conda packages
WordPress plugins
CPE matching constructs a CPE string from the package name and version, then searches the NVD for matching vulnerability entries.
Understanding CPE match accuracy
CPE matching has important limitations:
May produce false positives - CPEs often do not distinguish between package ecosystems. For example, the PyPI package docker (a Python library for talking to the Docker daemon) can match vulnerabilities for Docker the container runtime because they share similar CPE identifiers.
May miss vulnerabilities - Not all vulnerabilities have CPE entries in the NVD.
Requires CPE metadata - Packages must have CPE information for matching to work.
You should verify CPE matches against the actual vulnerability details to confirm they apply to your specific package. Here’s a CPE match example:
Notice the version constraint shows (unknown) format rather than ecosystem-specific semantics, and the match type is cpe-match instead of exact-direct-match.
For more details on interpreting match types, confidence levels, and result reliability, see Understanding Grype results.
Filter results: Use result filtering to focus on specific vulnerabilities
Data sources: Explore vulnerability data sources for details on each data source and supported operating systems
3.2.4 - Understanding Grype results
Learn how to read and interpret Grype’s vulnerability scan output, including match types, confidence levels, and result reliability
TL;DR
Default table output shows package, vulnerability, severity, and fix info
Match types in JSON output indicate reliability: exact-direct-match and exact-indirect-match are high confidence, cpe-match requires verification
Use --by-cve to normalize vulnerability IDs to CVE format
Filter results with jq for analysis by match type, severity, or data source
This guide explains how to read and interpret Grype’s vulnerability scan output.
You’ll learn what different match types mean, how to assess result reliability, and how to filter results based on confidence levels.
Output formats
Grype supports several output formats for scan results:
Table (default) - Human-readable columnar output for terminal viewing
JSON - Complete structured data with all match details
SARIF - Standard format for tool integration and CI/CD pipelines
Template - Custom output using Go templates
This guide focuses on table and JSON formats, which you’ll use most often for understanding scan results.
Reading table output
The table format is Grype’s default output. When you run grype <image>, you see a table displaying one row per
unique vulnerability match, with deduplication of identical rows.
Table columns
The table displays eight standard columns, with an optional ninth column for annotations:
NAME - The package name
INSTALLED - The version of the package
FIXED-IN - The version that fixes the vulnerability (shows (won't fix) if the vendor won’t fix it, or empty if no fix is available). See Filter by fix availability to filter results based on fix states
TYPE - Package type (apk, deb, rpm, npm, python, java-archive, etc.)
VULNERABILITY - The vulnerability identifier (see below)
RISK - Calculated risk score combining CVSS, EPSS, and other severity metrics into a single numeric value (0.0 to 10.0)
Annotations (conditional) - Additional context like KEV (Known Exploited Vulnerability), suppressed status, or distribution version when scanning multi-distro images
The Annotations column appears conditionally to provide additional context:
KEV or (kev) - Indicates the vulnerability is in CISA’s Known Exploited Vulnerabilities catalog
suppressed or suppressed by VEX - Shown when using --show-suppressed flag (see View filtered results)
Distribution version (e.g., ubuntu:20.04) - Shown when scan results include matches from multiple different distributions
Understanding vulnerability IDs
The VULNERABILITY column displays different types of identifiers depending on the data source:
CVE IDs (e.g., CVE-2024-1234) - Common Vulnerabilities and Exposures identifiers used by most Linux distributions (Alpine, Debian, Ubuntu, RHEL, SUSE) and the NVD
GHSA IDs (e.g., GHSA-xxxx-xxxx-xxxx) - GitHub Security Advisory identifiers for language ecosystem packages
ALAS IDs (e.g., ALAS-2023-1234) - Amazon Linux Security Advisory identifiers
By default, Grype displays the vulnerability ID from the original data source. For example, an Alpine package might show CVE-2024-1234
while a GitHub Advisory for the same issue shows GHSA-abcd-1234-efgh. Use the --by-cve flag to normalize results to CVE identifiers:
grype <image> --by-cve
This flag replaces non-CVE vulnerability IDs with their related CVE ID when available, uses CVE metadata instead of the
original advisory metadata, and makes it easier to correlate vulnerabilities across different data sources.
Compare the two approaches:
# Default output - shows GitHub Advisory ID$ grype node:18
NAME INSTALLED FIXED-IN TYPE VULNERABILITY SEVERITY
lodash 4.17.20 4.17.21 npm GHSA-35jh-r3h4-6jhm High
# With --by-cve - converts to CVE$ grype node:18 --by-cve
NAME INSTALLED FIXED-IN TYPE VULNERABILITY SEVERITY
lodash 4.17.20 4.17.21 npm CVE-2021-23337 High
Sorting results
By default, Grype sorts vulnerability results by risk score, which combines multiple factors to help you prioritize remediation efforts.
Understanding how sorting works and when to use alternative methods helps you build effective security workflows.
Why risk-based sorting works best
The default risk score takes a holistic approach by combining:
Threat (likelihood of exploitation) - Based on EPSS (Exploit Prediction Scoring System) scores or presence in CISA’s Known Exploited Vulnerabilities (KEV) catalog
Impact (potential damage) - Based on CVSS scores and severity ratings from multiple sources
Context (exploitation evidence) - Additional weight for vulnerabilities with known ransomware campaigns
This multi-factor approach aligns with security best practices recommended by the EPSS project,
which emphasizes that “CVSS is a useful tool for capturing the fundamental properties of a vulnerability,
but it needs to be used in combination with data-driven threat information, like EPSS.”
Risk-based sorting helps you focus on vulnerabilities that are both likely to be exploited AND have significant business impact,
optimizing your remediation efficiency.
Why single-metric sorting can be misleading
While Grype offers several sorting options via the --sort-by flag, using single metrics can lead to inefficient prioritization:
Severity-only sorting (--sort-by severity) focuses solely on potential impact:
You may waste effort patching Critical severity vulnerabilities that are unlikely to ever be exploited in the wild
No consideration for whether attackers are actively targeting the vulnerability
Ignores real-world threat intelligence
EPSS-only sorting (--sort-by epss) focuses solely on exploitation likelihood:
You may prioritize vulnerabilities with high exploitation probability but low business impact
EPSS is not a risk score – it only addresses the threat component, not the complete risk picture
Missing context like asset criticality, network exposure, or available compensating controls
The EPSS documentation explicitly states that EPSS scores should be combined with severity information to make informed prioritization decisions,
which is exactly what Grype’s risk score does.
Understanding EPSS in Grype
EPSS (Exploit Prediction Scoring System) is a data-driven scoring model that estimates the probability a vulnerability will be exploited in the next 30 days.
Grype displays EPSS data in the table output showing both the raw score and percentile, such as 94.4% (99th), which means:
94.4% - The raw EPSS score indicating a 94.4% probability of exploitation within 30 days
99th - The percentile rank, meaning this score is higher than 99% of all EPSS scores
EPSS percentiles help normalize the heavily skewed distribution of EPSS scores, making it easier to set thresholds.
For example, a vulnerability in the 90th percentile is more concerning than one in the 50th percentile, even if the raw likelihood values appear to be similar.
Grype incorporates EPSS as the threat component of its risk calculation. When a vulnerability appears in the KEV catalog, Grype automatically treats it as maximum threat (overriding EPSS) since observed exploitation is more significant than predicted exploitation.
While risk-based sorting is recommended for most remediation workflows, alternative sorting methods serve specific use cases:
Sort by KEV status (--sort-by kev):
When you need to comply with regulatory requirements like CISA BOD 22-01
For incident response scenarios focusing on actively exploited vulnerabilities
Sort by severity (--sort-by severity):
When organizational SLAs or compliance frameworks specify severity-based remediation timeframes (e.g., “patch all Critical within 7 days”)
Sort by EPSS (--sort-by epss):
For threat landscape analysis and security research
Sort by package (--sort-by package):
When organizing remediation work by team ownership (different teams maintain different packages)
For coordinating updates across multiple instances of the same package
Sort by vulnerability ID (--sort-by vulnerability):
When tracking specific CVE campaigns across your environment
For correlating findings with external threat intelligence reports
For most security and remediation workflows, stick with the default risk-based sorting.
It provides the best balance of threat intelligence and impact assessment to help you prioritize effectively.
Grype’s native JSON output format provides a comprehensive representation of vulnerability scan results,
including detailed information about each vulnerability, how it was matched, and the affected packages.
This guide explains the structure of the JSON output and how to interpret its contents effectively.
Data shapes
The JSON output contains a top-level matches array. Each match has this structure:
cvss (array) - CVSS score information from various sources
fix (object) - Fix information including available versions and fix state (fixed, not-fixed, wont-fix, unknown). See Understanding fix states for details
advisories (array) - Related security advisories (where RHSAs appear)
risk (float64) - Calculated risk score combining CVSS, EPSS, and other severity metrics
Grype determines how it matched a package to a vulnerability based on the available data sources.
The match type indicates how the match was made:
exact-direct-match means the package name matched directly in a dedicated vulnerability feed.
Grype searched the feed using the package name from your scan and found a matching vulnerability entry.
exact-indirect-match means the source package name matched in a dedicated vulnerability feed.
This occurs when you scan a binary package (e.g., libcrypto1.1) but the feed tracks vulnerabilities under the source package (e.g., openssl).
Grype searches the feed using the source package name and maps the results to the binary package.
cpe-match means Grype used Common Platform Enumeration (CPE) matching as a fallback when no exact match was found in ecosystem-specific feeds.
CPE matching relies on CPE identifiers derived from package metadata and is less precise.
You can loosely think of the match type as a proxy for confidence level in the match, where exact-direct-match has the highest confidence,
followed by exact-indirect-match, and finally cpe-match.
A cpe-match means Grype used Common Platform Enumeration (CPE) matching as a fallback.
CPE matching occurs when:
No exact package match exists in ecosystem-specific feeds
Grype falls back to the NVD database
The match is based on CPE identifiers derived from package metadata
This match type has lower confidence because:
CPE matching is generic and not package-ecosystem aware
Package naming may not match CPE naming conventions exactly
Version ranges may be broader or less precise
Understanding version constraints
The found.versionConstraint field shows the version range (found on the vulnerability) which the
package version was found to be within (thus, the package is affected by the vulnerability).
The format indicates the constraint type and the comparison logic used:
< 1.2.3 (apk) - Alpine package version constraint using apk version comparison
< 1.2.3 (deb) - Debian package version constraint using dpkg version comparison
< 1.2.3 (rpm) - RPM package version constraint using rpm version comparison
< 1.2.3 (python) - Python package version constraint using PEP 440 comparison
< 1.2.3 (semantic) - Semantic versioning constraint using semver comparison
< 1.2.3 (unknown) - Unknown version format (lower reliability)
The constraint type tells you how Grype compared versions. Ecosystem-specific formats (apk, deb, rpm) use that
ecosystem’s version comparison rules, which handle epoch numbers, release tags, and other format-specific details correctly.
Generic formats like unknown may have less precise matching.
Tip
When you use filtering flags or ignore rules, filtered vulnerabilities appear in the ignoredMatches array instead of matches.
Each match in JSON output contains information about how Grype found the vulnerability and links to the original sources. This lets you examine what Grype looked at and verify the match yourself.
Reference URLs
The vulnerability object includes reference URLs from the vulnerability data:
For distro packages, this shows the distro, package name, and version. For CPE matches, this shows the CPE strings Grype constructed. This lets you see exactly what Grype queried.
What Grype found
The matchDetails[].found field shows what matched in the vulnerability data:
This shows the vulnerability ID and version constraint that matched, along with the match type. Comparing searchedBy and found shows how Grype connected your package to the vulnerability.
Control which vulnerabilities Grype reports using filtering flags, configuration rules, and VEX documents
TL;DR
Use --fail-on <severity> to set exit code thresholds for CI/CD pipelines
Filter by fix availability with --only-fixed or --only-notfixed
Create ignore rules in .grype.yaml to exclude specific vulnerabilities or packages
Use VEX documents with --vex to filter based on exploitability information
Learn how to control which vulnerabilities Grype reports using filtering flags and configuration options.
Set failure thresholds
Use the --fail-on flag to control Grype’s exit code based on vulnerability severity. This can be helpful for integrating Grype into CI/CD pipelines.
The --fail-on flag (alias: -f) sets a severity threshold. When scanning completes, Grype exits with code 2 if it found vulnerabilities at or above the specified severity:
grype alpine:3.10 --fail-on high
You’ll see vulnerabilities at or above the threshold:
NAME INSTALLED FIXED IN TYPE VULNERABILITY SEVERITY EPSS RISK
zlib 1.2.11-r1 apk CVE-2022-37434 Critical 92.7% (99th) 87.1
libcrypto1.1 1.1.1k-r0 apk CVE-2023-0286 High 89.1% (99th) 66.4
libssl1.1 1.1.1k-r0 apk CVE-2023-0286 High 89.1% (99th) 66.4
...
[0026] ERROR discovered vulnerabilities at or above the severity threshold
# Exit code: 2
Valid severity values, from lowest to highest:
negligible < low < medium < high < critical
When you set a threshold, Grype fails if it finds vulnerabilities at that severity or higher. For example, --fail-on high fails on both high and critical vulnerabilities.
Filter by fix availability
Grype provides flags to filter vulnerabilities based on whether fixes are available.
Show only vulnerabilities with fixes available
The --only-fixed flag filters scan results to show only vulnerabilities that have fixes available:
grype alpine:latest --only-fixed
This flag filters out vulnerabilities with these fix states:
not-fixed - No fix is available yet
wont-fix - Maintainers won’t fix this vulnerability
unknown - No fix state information is available
This is useful when you want to focus on actionable vulnerabilities that you can remediate by updating packages.
Note
Do not use --only-fixed and --only-notfixed together. These flags are mutually exclusive and filter out all vulnerabilities.
Show only vulnerabilities without fixes available
The --only-notfixed flag filters scan results to show only vulnerabilities that do not have fixes available:
grype alpine:3.10 --only-notfixed
These vulnerabilities don’t have fixes available yet:
NAME INSTALLED TYPE VULNERABILITY SEVERITY EPSS RISK
zlib 1.2.11-r1 apk CVE-2022-37434 Critical 92.7% (99th) 87.1
libcrypto1.1 1.1.1k-r0 apk CVE-2023-0286 High 89.1% (99th) 66.4
libssl1.1 1.1.1k-r0 apk CVE-2023-0286 High 89.1% (99th) 66.4
libcrypto1.1 1.1.1k-r0 apk CVE-2023-2650 Medium 92.0% (99th) 52.9
libssl1.1 1.1.1k-r0 apk CVE-2023-2650 Medium 92.0% (99th) 52.9
...
This flag filters out vulnerabilities with fix state fixed. Notice the FIXED-IN column is empty for these vulnerabilities.
This is useful when you want to identify vulnerabilities that require alternative mitigation strategies, such as:
Accepting the risk
Implementing compensating controls
Waiting for a fix to become available
Switching to a different package
Understanding fix states
Grype assigns one of four fix states to each vulnerability based on information from vulnerability data sources:
Fix State
Description
fixed
A fix is available for this vulnerability
not-fixed
No fix is available yet, but maintainers may release one
wont-fix
Package maintainers have decided not to fix this vulnerability
unknown
No fix state information is available
Vulnerabilities with no fix state information are treated as unknown. This ensures Grype handles missing data consistently.
Ignore specific fix states
The --ignore-states flag gives you fine-grained control over which fix states to filter out. You can ignore one or more fix states by specifying them as a comma-separated list:
# Ignore vulnerabilities with unknown fix statesgrype alpine:3.10 --ignore-states unknown
Only vulnerabilities with known fix states appear:
NAME INSTALLED FIXED IN TYPE VULNERABILITY SEVERITY EPSS RISK
apk-tools 2.10.6-r0 2.10.7-r0 apk CVE-2021-36159 Critical 1.0% (76th) 0.9
# Ignore both wont-fix and not-fixed vulnerabilitiesgrype alpine:3.10 --ignore-states wont-fix,not-fixed
This leaves only fixed vulnerabilities and those with unknown states:
NAME INSTALLED FIXED IN TYPE VULNERABILITY SEVERITY EPSS RISK
zlib 1.2.11-r1 apk CVE-2022-37434 Critical 92.7% (99th) 87.1libcrypto1.11.1.1k-r0 apk CVE-2023-0286 High 89.1% (99th) 66.4libssl1.11.1.1k-r0 apk CVE-2023-0286 High 89.1% (99th) 66.4apk-tools 2.10.6-r0 2.10.7-r0 apk CVE-2021-36159 Critical 1.0% (76th) 0.9...
Valid fix state values are: fixed, not-fixed, wont-fix, unknown.
If you specify an invalid fix state, Grype returns an error:
grype alpine:latest --ignore-states invalid-state
# Error: unknown fix state invalid-state was supplied for --ignore-states
Combining severity with fix filtering
You can combine --fail-on with fix state filtering to create sophisticated CI/CD policies:
# Fail only if fixable critical or high vulnerabilities existgrype alpine:3.10 --fail-on high --only-fixed
Grype now only fails on fixable critical/high vulnerabilities:
NAME INSTALLED FIXED IN TYPE VULNERABILITY SEVERITY EPSS RISK
apk-tools 2.10.6-r0 2.10.7-r0 apk CVE-2021-36159 Critical 1.0% (76th) 0.9[0026] ERROR discovered vulnerabilities at or above the severity threshold
# Exit code: 2
# Fail on medium or higher, but ignore wont-fix vulnerabilitiesgrype alpine:latest --fail-on medium --ignore-states wont-fix
The --fail-on check runs after vulnerability matching and filtering. Grype converts all filtering options (--only-fixed, --only-notfixed, --ignore-states, configuration ignore rules, and VEX documents) into ignore rules and applies them during matching. The severity threshold check then evaluates only the remaining vulnerabilities.
View filtered results
By default, Grype hides filtered vulnerabilities from output. You can view them in table output with --show-suppressed or in JSON output by inspecting the ignoredMatches field.
In table output
The --show-suppressed flag displays filtered vulnerabilities in table output with a (suppressed) label:
grype alpine:3.10 --only-fixed --show-suppressed
Filtered vulnerabilities now appear with a (suppressed) label:
NAME INSTALLED FIXED IN TYPE VULNERABILITY SEVERITY EPSS RISK
apk-tools 2.10.6-r0 2.10.7-r0 apk CVE-2021-36159 Critical 1.0% (76th) 0.9zlib 1.2.11-r1 apk CVE-2018-25032 High <0.1% (26th) <0.1 (suppressed)
libcrypto1.11.1.1k-r0 apk CVE-2021-3711 Critical 2.7% (85th) 2.4 (suppressed)
libssl1.11.1.1k-r0 apk CVE-2021-3711 Critical 2.7% (85th) 2.4 (suppressed)
libcrypto1.11.1.1k-r0 apk CVE-2021-3712 High 0.5% (66th) 0.4 (suppressed)
libssl1.11.1.1k-r0 apk CVE-2021-3712 High 0.5% (66th) 0.4 (suppressed)
...
Note
The --show-suppressed flag only applies to table output format. It has no effect on JSON, SARIF, or other output formats.
In JSON output
When you use JSON output (-o json), Grype places filtered vulnerabilities in the ignoredMatches array. Non-filtered vulnerabilities appear in the matches array.
For details on the complete JSON structure and all fields, see Reading JSON output.
When you combine multiple criteria in a rule, all criteria must match for the rule to apply.
Use VEX documents
Grype supports Vulnerability Exploitability eXchange (VEX) documents to provide information about which vulnerabilities affect your software.
VEX allows you to communicate vulnerability status in a machine-readable format that follows CISA minimum requirements.
Grype supports two VEX formats as input:
OpenVEX - Compact JSON format with minimal required fields
CSAF VEX - Comprehensive format with rich advisory metadata (OASIS standard)
VEX-filtered vulnerabilities behave like other filtered results:
Table output: Hidden by default, shown with --show-suppressed flag and marked as (suppressed by VEX)
JSON output: Moved to the ignoredMatches array with VEX rules listed in appliedIgnoreRules
This guide uses OpenVEX examples for simplicity, but both formats work identically with Grype.
The core concepts (status values, product identification, filtering behavior) apply to both formats.
Basic usage
Use the --vex flag to provide one or more VEX documents:
affected - Product is affected by the vulnerability
under_investigation - Impact is still being assessed
By default, Grype moves vulnerabilities with not_affected or fixed status to the ignored list.
Vulnerabilities with affected or under_investigation status are only added to results when you enable augmentation:
vex-add: ["affected", "under_investigation"]
Creating VEX documents with vexctl
The easiest way to create OpenVEX documents is with vexctl:
# Create a VEX statement marking a CVE as not affecting your imagevexctl create \
--product="pkg:oci/alpine@sha256:4b7ce07002c69e8f3d704a9c5d6fd3053be500b7f1c69fc0d80990c2ad8dd412"\
--subcomponents="pkg:apk/alpine/busybox@1.37.0-r19"\
--vuln="CVE-2024-58251"\
--status="not_affected"\
--justification="vulnerable_code_not_present"\
--file="vex.json"# Use the VEX document with Grypegrype alpine:3.22.2 --vex vex.json
Note
vexctl creates OpenVEX documents only.
For CSAF VEX, you’ll need to create documents manually or use CSAF-specific tooling. Both formats work the same way with Grype.
You can also create VEX documents manually. Here’s an OpenVEX example:
CSAF VEX documents have a more complex structure with product trees, branches, and vulnerability arrays. See the CSAF specification for complete structure details.
Justifications for not_affected
OpenVEX provides standardized justification values when marking vulnerabilities as not_affected:
component_not_present - The component is not included in the product
vulnerable_code_not_present - The vulnerable code is not present
vulnerable_code_not_in_execute_path - The vulnerable code cannot be executed
vulnerable_code_cannot_be_controlled_by_adversary - The vulnerability cannot be exploited
CSAF VEX uses a richer product status model with categories like known_not_affected that Grype maps to the standard VEX statuses. See the CSAF specification for details on CSAF-specific fields.
These justifications help security teams understand the rationale behind VEX statements.
Product identification
Grype matches VEX statements to scan results using several identification methods:
Grype uses a locally cached database of known vulnerabilities
Database auto-updates on each Grype launch when newer version is available
Manage manually with grype db check and grype db update
Database published by Anchore at no cost from multiple upstream feeds
Grype uses a locally cached database of known vulnerabilities when searching a container, directory, or SBOM for security vulnerabilities.
Anchore collates vulnerability data from common feeds, and publishes that data online, at no cost to users.
When Grype is launched, it checks for an existing vulnerability database, and looks for an updated one online.
If available, Grype will automatically download the new database.
Database age validation
Grype will automatically fail scans if the vulnerability database is more than 5 days old.
You can disable this behavior or adjust the age threshold in your configuration:
Set db.validate-age: false to disable age validation
Adjust db.max-allowed-built-age to change the threshold (e.g., 168h for 7 days)
To update the database manually, use the following command:
grype db update
If instead, you would like to simply check if a new DB is available without actually updating, use:
grype db check
This will return 0 if the database is up to date, and 1 if an update is available.
Or, you can delete the local database entirely:
grype db delete
Searching the database
The Grype vulnerability database contains detailed information about vulnerabilities and affected packages across all supported ecosystems.
While you can examine the raw SQLite database directly (use grype db status to find the local storage path),
the grype db search commands provide a much easier way to explore what’s in the database.
Search tips
For both affected package and vulnerability searches, keep these tips in mind:
Result limit: By default, searches return up to 5,000 results. Use --limit 0 for unlimited results.
JSON output: Add --output json for programmatic processing of results.
Search for affected packages
Use grype db search to find packages affected by vulnerabilities. This is useful when you want to understand
what packages are impacted by a specific CVE, or when you want to see all vulnerabilities affecting a particular package.
For example, to find all packages affected by Log4Shell across all ecosystems:
grype db search --vuln CVE-2021-44228
To find all vulnerable versions of the log4j package:
grype db search --pkg log4j
To search by PURL or CPE formats:
grype db search --pkg 'pkg:rpm/redhat/openssl'grype db search --pkg 'cpe:2.3:a:jetty:jetty_http_server:*:*:*:*:*:*:*:*'
Any version value provided will be ignored entirely.
You can also use these options in combination to filter results further (finding the common intersection);
in this example, finding packages named “openssl” in Alpine Linux 3.18 that have fixes available:
grype db search --pkg openssl --distro alpine-3.18 --fixed-state fixed
Search for vulnerabilities
Use grype db search vuln to look up vulnerability details directly, including descriptions, severity ratings, and data sources.
This is subtly different from searching for affected packages, as it focuses on the vulnerabilities themselves, so you can find information
about vulnerabilities that may not affect any packages (there are a few reasons why this could happen.)
To view full metadata for a specific CVE:
grype db search vuln CVE-2021-44228
To filter by data provider:
grype db search vuln CVE-2021-44228 --provider nvd
License scanning: Check dependency licenses with Grant
3.3 - License Scanning
Learn how to scan container images and filesystems for software licenses covering detection, compliance checking, and managing license obligations.
License scanning involves automatically identifying and analyzing the licenses associated with the various software components used in a project.
This is important because most software relies on third-party and open-source components, each with its own licensing terms that dictate how the software can be used, modified, and distributed, and failing to comply can lead to legal issues.
Grant is an open-source command-line tool designed to discover and report on the software licenses present in container images, SBOM documents, or filesystems. It helps users understand the licenses of their software dependencies and can check them against user-defined policies to ensure compliance.
3.3.1 - Getting Started
License Scanning Getting Started
Introduction
Grant searches SBOMs for licenses and the packages they belong to.
Install the latest Grant release
Grant is provided as a single compiled executable. Issue the command for your platform to download the latest release of Grant. The full list of official and community maintained packages can be found on the installation page.
Configure authentication for scanning container images from private registries using credentials, registry tokens, and credential helpers.
The Anchore OSS tools analyze container images from private registries using multiple authentication methods.
When a container runtime isn’t available, the tools use the go-containerregistry library to handle authentication directly with registries.
When using a container runtime explicitly (for instance, with the --from docker flag) the tools defer to the runtime’s authentication mechanisms.
However, if the registry source is used, the tools use the Docker configuration file and any configured credential helpers to authenticate with the registry.
Registry tokens and personal access tokens
Many registries support personal access tokens (PATs) or registry tokens for authentication. Use docker login with your token, then the tools can use the cached credentials:
# GitHub Container Registry - create token at https://github.com/settings/tokens (needs read:packages scope)docker login ghcr.io -u <username> -p <token>
syft ghcr.io/username/private-image:latest
# GitLab Container Registry - use deploy token or personal access tokendocker login registry.gitlab.com -u <username> -p <token>
syft registry.gitlab.com/group/project/image:latest
The tools read credentials from ~/.docker/config.json, the same file Docker uses when you run docker login. This file can contain either basic authentication credentials or credential helper configurations.
Here are examples of what the config looks like if you are crafting it manually:
docker run -v ./config.json:/auth/config.json -e "DOCKER_CONFIG=/auth" anchore/syft:latest <private_image>
Docker credential helpers
Docker credential helpers are specialized programs that securely store and retrieve registry credentials. They’re particularly useful for cloud provider registries that use dynamic, short-lived tokens.
Instead of storing passwords as plaintext in config.json, you configure helpers that generate credentials on-demand. This is facilitated by the google/go-containerregistry library.
Configuring credential helpers
Add credential helpers to your config.json:
{
"credHelpers": {
// using the docker-credential-gcr for Google Container Registry and Artifact Registry
"gcr.io": "gcr",
"us-docker.pkg.dev": "gcloud",
// using the amazon-ecr-credential-helper for AWS Elastic Container Registry
"123456789012.dkr.ecr.us-west-2.amazonaws.com": "ecr-login",
// using the docker-credential-acr for Azure Container Registry
"myregistry.azurecr.io": "acr" }
}
When the tools access these registries, they execute the corresponding helper program (for example, docker-credential-gcr, or more generically docker-credential-NAME where NAME is the config value) to obtain credentials.
Note
If both credHelpers and auths are configured for the same registry, credHelpers takes precedence.
For more information about Docker credential helpers for various cloud providers:
When running the tools in Kubernetes and you need access to private registries, mount Docker credentials as a secret.
Create secret
Create a Kubernetes secret containing your Docker credentials. The key config.json is important—it becomes the filename when mounted into the pod.
For more information about the credential file format, see the go-containerregistry config docs.
# Base64 encode your config.jsoncat ~/.docker/config.json | base64
# Apply the secretkubectl apply -f secret.yaml
Configure pod
Configure your pod to use the credential secret. The DOCKER_CONFIG environment variable tells the tools where to look for credentials.
Setting DOCKER_CONFIG=/config means the tools look for credentials at /config/config.json.
This matches the secret key config.json we created above—when Kubernetes mounts secrets, each key becomes a file with that name.
The volumeMounts section mounts the secret to /config, and the volumes section references the secret created in the previous step.
Summary of package analysis and vulnerability scanning capabilities across ecosystems
Capabilities describe the cross-cutting features available across Anchore’s tools:
Package analysis: What Syft can catalog from package manifests, lock files, and installed packages
Vulnerability scanning: What Grype can detect using vulnerability databases and matching rules
These capabilities are ecosystem-specific.
For example, Python’s capabilities differ from Go’s, and Ubuntu’s capabilities differ from Alpine’s.
Default capabilities do not require to be online or have special configuration (other than having a vulnerability DB downloaded).
Some capabilities may be conditionally supported, requiring additional configuration or online access to function.
Show me the data!
This page explains how to interpret the capabilities tables found on each ecosystem-specific capability pages.
Vulnerability data source qualities vary in the information they provide and how to interpret them correctly.
Disclosure and fix information
In terms of disclosures and fixes, each data source can be described along the following dimensions:
Independent Disclosure: Whether the advisory discloses the vulnerability regardless of fix availability. Sources with this capability report vulnerabilities even when no fix is available yet.
Disclosure Date: Whether the data source provides the date when a vulnerability was first publicly disclosed. This helps you understand the timeline of vulnerability exposure.
Fix Versions: Whether the data source specifies which package versions contain fixes for a vulnerability. This allows Grype to determine if an installed package version is vulnerable or fixed.
Fix Date: Whether the advisory includes a date when the fix was made available. This helps you understand the timeline of vulnerability remediation.
Track by source package
Some ecosystems have parent packages where the source code for the current package is maintained.
For example, the libcrypto for debian is part of the larger openssl package (where openssl is denoted as the origin package).
The same is true for redhat-based packages, except the parent package is denoted as the srcrpm package.
Ecosystems like this have vulnerabilities are often disclosed and fixed at the parent package level (origin and srcrpm).
More critically, the parent packages are often not installed on the system, making it impossible to directly detect vulnerabilities against them.
There tends to be package metadata on the downstream package that denotes the parent package name and version, which Syft can extract during package analysis.
Package analysis capabilities
Dependencies
We describe Syft’s ability to capture dependency information in the following dimentions:
Depth: How far into the true dependency graph we are able to discover package nodes.
direct: only captures dependencies explicitly declared by the project, but not necessarily dependencies of those dependencies
transitive: all possible depths of dependencies are captured
Edges: Whether we are able to capture relationships between packages, and if so, describe the topology of those relationships.
flat: we can capture the root package relative to all other dependencies, but are unaware of relationships between dependencies (a simple star topology, where all dependencies point to the root package)
complete: all possible relationships between packages are captured (the full dependency graph)
Kinds: The types of dependencies we are able to capture.
runtime: dependencies required for the package to function at runtime
dev: dependencies required for development
Licenses
Indicates whether Syft can detect and catalog license information from package metadata. When supported, Syft extracts license declarations from package manifests, metadata files, or installed package databases.
Package manager features
Syft can extract various package manager metadata beyond basic package information:
Files: Whether Syft can catalog the list of files that are part of a package installation. This provides visibility into all files installed by the package manager.
Digests: Whether Syft can capture file checksums (digests/hashes) for individual files within a package. This enables integrity verification of installed files. Note: this is not necessarily the actual hash of the file, but instead the claims made by the package manager about those files. We capture actual file hashes in the files section of the SBOM.
Integrity Hash: Whether Syft can capture a single package-level integrity hash used by package managers to verify the package archive itself (for example, the https://go.dev/ref/mod#go-sum-files for go packages).
Next steps
Explore capabilities for specific ecosystems using the navigation menu
Syft and Grype support several operating systems for package cataloging and vulnerability detection.
The table below shows which OS versions are supported and where Grype’s vulnerability data comes from.
The APK vulnerability database (a.k.a. “SecDB”) includes data from the Alpine Security Tracker, which provides fix information for known vulnerabilities that affect Alpine Linux packages.
This database only includes vulnerabilities that have fixes available and does not track unfixed vulnerabilities.
The maintainers of the SecDB intend for the primary source of truth for disclosures to be the National Vulnerability Database (NVD).
This is true of other APK vulnerability data sources as well (such as Chainguard, Wolfi, and MinimOS).
Binary package analysis and vulnerability scanning capabilities
File analysis
Within the .files[].executable sections of the Syft JSON there is an analysis of what features and claims were found within a binary file.
This includes:
Imported libraries (use of shared libraries)
Exported symbols
Security features (like NX, PIE, RELRO, etc)
Security features that can be detected include:
if debugging symbols have been stripped
presence of Stack Canaries to protect against stack smashing (which lead to buffer overflows)
NoExecute (NX) bit support to prevent execution of code on the stack or heap
Relocation Read-Only (RelRO) to protect the Global Offset Table (GOT) from being overwritten (can be “partial” or “full”)
Position Independent Executable (PIE) support such that offsets are used instead of absolute addresses
if it is a Dynamic Shared Object (DSO) (not a security feature, but important for analysis)
LLVM SafeStack partitioning is in use, which separates unsafe stack objects from safe stack objects to mitigate stack-based memory corruption vulnerabilities
LLVM Control Flow Integrity (CFI) is in use, which adds runtime checks to ensure that indirect function calls only target valid functions, helping to prevent control-flow hijacking attacks
Clang Fortified Builds is enabled, which adds additional runtime checks for certain standard library functions to detect buffer overflows and other memory errors
When it comes to shared library requirement claims and exported symbol claims, these are used by Syft to:
associate file-to-file relationships (in the case of executables/shared libraries being distributed without a package manager)
associate file-to-package relationships (when an executable imports a shared library that is managed by a package manager)
Syft can synthesize a dependency graph from the imported libraries and exported symbols found within a set of binaries,
even if all package manager information has been removed, allowing for a more complete SBOM to be generated.
In a mixed case, where there are some packages managed by package managers and some binaries without package manager metadata, Syft can still use the binary analysis to fill in the gaps.
Package-level relationships are preferred over file-level relationships when both are available, which simplifies the dependency graph.
Package analysis
ELF package notes
Syft is capable of looking at ELF formatted binaries, specifically the .note.package note, that are formatted using the convention established by the systemd project.
This spec requires a PE/COFF section that wraps a json payload describing the package metadata for the binary, however, syft does not require the PE/COFF wrapping and can extract the json payload directly from the ELF note.
Here’s an example of what the json payload looks like:
.NET package analysis and vulnerability scanning capabilities
Package analysis
Cataloger + Evidence
License
Dependencies
Package Manager Claims
Depth
Edges
Kinds
Files
Digests
Integrity Hash
dotnet-deps-binary-cataloger
*.deps.json, *.dll, *.exe
Transitive
Complete
Runtime
dotnet-deps-cataloger deprecated
*.deps.json
Transitive
Complete
Runtime
dotnet-packages-lock-cataloger
packages.lock.json
Transitive
Complete
Runtime, Dev, Build
dotnet-portable-executable-cataloger deprecated
*.dll, *.exe
Syft Configuration
Configuration Key
Description
dotnet.dep-packages-must-claim-dll
Allows for deps.json packages to be included only if there is a runtime/resource DLL claimed in the deps.json targets section. This does not require such claimed DLLs to exist on disk. The behavior of this
dotnet.dep-packages-must-have-dll
Allows for deps.json packages to be included only if there is a DLL on disk for that package.
dotnet.propagate-dll-claims-to-parents
Allows for deps.json packages to be included if any child (transitive) package claims a DLL. This applies to both the claims configuration and evidence-on-disk configurations.
dotnet.relax-dll-claims-when-bundling-detected
Will look for indications of IL bundle tooling via deps.json package names and, if found (and this config option is enabled), will relax the DepPackagesMustClaimDLL value to `false` only in those cases.
When scanning a .NET application evidence from deps.json (compiler output) as well as any built binaries are used together to identify packages.
This way we can enrich missing data from any one source and synthesize a more complete and accurate package graph.
Specifies the location of the local go module cache directory. When not set, syft will attempt to discover the GOPATH env or default to $HOME/go.
golang.local-vendor-dir
Specifies the location of the local vendor directory. When not set, syft will search for a vendor directory relative to the go.mod file.
golang.no-proxy
Is a list of glob patterns that match go module names that should not be fetched from the go proxy. When not set, syft will use the GOPRIVATE and GONOPROXY env vars.
golang.proxy
Is a list of go module proxies to use when fetching go module metadata and licenses. When not set, syft will use the GOPROXY env or default to https://proxy.golang.org,direct.
golang.search-local-mod-cache-licenses
Enables searching for go package licenses in the local GOPATH mod cache.
golang.search-local-vendor-licenses
Enables searching for go package licenses in the local vendor directory relative to the go.mod file.
golang.search-remote-licenses
Enables downloading go package licenses from the upstream go proxy (typically proxy.golang.org).
Version detection for binaries
When Syft scans a Go binary, the main module often has version (devel) because Go doesn’t embed version information by default.
Syft attempts to detect the actual version using three strategies (configurable via golang.main-module-version.*):
From ldflags (enabled by default): Looks for version strings passed during build like -ldflags="-X main.version=v1.2.3". Supports common patterns: *.version=, *.gitTag=, *.release=, etc.
From build settings (enabled by default): Uses VCS metadata (commit hash and timestamp) embedded by Go 1.18+ to generate a pseudo-version like v0.0.0-20230101120000-abcdef123456.
From contents (disabled by default): Scans binary contents for version string patterns. Can produce false positives.
Best practice: Use -ldflags when building to embed your version explicitly.
Example:
go build -ldflags="-X main.version=v1.2.3"
This ensures Syft (and Grype) can accurately identify your application version for vulnerability matching.
Standard library
Syft automatically creates a stdlib package for each Go binary, representing the Go standard library version used to compile it.
The version is extracted from the binary’s build metadata (e.g., go1.22.2).
This enables Grype to check for vulnerabilities reported against the go standard library.
Why this matters: Vulnerabilities in the Go compiler (like CVEs affecting the crypto library or net/http) can affect your application even if your code doesn’t directly use those packages.
allow comparison between main module pseudo-versions (e.g. v0.0.0-20240413-2b432cf643...)
Main module filtering
Grype skips vulnerability matching for packages that match all these conditions:
Package name equals the main module name (from the SBOM metadata)
Package version is unreliable:
When allow-main-module-pseudo-version-comparison is false (default): version starts with v0.0.0- or is (devel)
When allow-main-module-pseudo-version-comparison is true: version is (devel) only
This filtering exists because Go doesn’t have a standard way to embed the main module’s version into compiled binaries (see golang/go#50603). Pseudo-versions in compiled binaries are often unreliable for vulnerability matching.
You can disable this filtering with the allow-main-module-pseudo-version-comparison configuration option.
Troubleshooting
No vulnerabilities found for main module
Cause: The main module has a pseudo-version (v0.0.0-*) or (devel), which Grype filters by default.
Solution: Enable pseudo-version matching in your Grype configuration:
Specifies the location of the local maven repository. When not set, defaults to ~/.m2/repository.
java.maven-url
Specifies the base URL(s) to use for fetching POMs and metadata from maven central or other repositories. When not set, defaults to https://repo1.maven.org/maven2.
java.max-parent-recursive-depth
Limits how many parent POMs will be fetched recursively before stopping. This prevents infinite loops or excessively deep parent chains.
java.resolve-transitive-dependencies
Enables resolving transitive dependencies for java packages found within archives.
java.use-maven-local-repository
Enables searching the local maven repository (~/.m2/repository by default) for parent POMs and other metadata.
java.use-network
Enables network operations for java package metadata enrichment, such as fetching parent POMs and license information.
Archives
When scanning a Java archive (e.g. jar, war, ear, …), Syft will look for maven project evidence within the archive recursively.
This means that if a jar file contains other jar files, Syft will also look for pom.xml files within those nested jar files to identify packages (such as with shaded jars).
Additionally, if opted-in via configuration, Syft will scan non-java archive files (e.g., zip, tar, tar.gz, …) for Java package evidence as well.
Determines whether to record the list of files owned by each Nix package discovered in the store. Recording owned files provides more detailed information but increases processing time and memory usage.
Guidelines for developing & contributing to Anchore Open Source projects
Welcome! We appreciate all contributions to Anchore’s open source projects.
Whether you’re fixing a bug, adding a feature, or improving documentation, your help makes these tools better for everyone.
Getting Help
The Anchore open source community is here to help. Use Discourse for questions, discussions, and troubleshooting.
Use GitHub for reporting bugs, requesting features, and submitting code contributions. See Issues vs Discussions for guidance on which channel to use.
General discussion: Ideas, use cases, and community chat
Help requests: Troubleshooting your specific setup
Best practices: Sharing knowledge and experiences
Why separate channels?
GitHub issues track work items that require code changes.
Each issue represents a potential task for the development team.
Discourse provides a better format for conversations, questions, and community support without cluttering the issue tracker.
If you’re unsure which to use, start with Discourse. The community can help identify if an issue should be created.
Security Issues
If you discover a security vulnerability, please report it privately rather than creating a public issue.
See our Security Policy for details on how to report security issues responsibly. This gives us time to fix the problem and protect users before details become public.
5.2 - Syft
Developer guidelines when contributing to Syft
Getting started
In order to test and develop in the Syft repo you will need the following dependencies installed:
Golang
Docker
Python (>= 3.9)
make
Initial setup
Run once after cloning to install development tools:
make bootstrap
Make sure you’ve updated your docker settings so the default docker socket path is available.
Go to docker → settings → advanced and ensure “Allow the default Docker socket to be used” is checked.
Use the default docker context, run: docker context use default
Useful commands
Common commands for ongoing development:
make help - List all available commands
make lint - Check code formatting and linting
make lint-fix - Auto-fix formatting issues
make unit - Run unit tests
make integration - Run integration tests
make cli - Run CLI tests
make snapshot - Build release snapshot with all binaries and packages
Testing
Levels of testing
unit (make unit): The default level of test which is distributed throughout the repo are unit tests. Any _test.go file that
does not reside somewhere within the /test directory is a unit test. Other forms of testing should be organized in
the /test directory. These tests should focus on the correctness of functionality in depth. % test coverage metrics
only considers unit tests and no other forms of testing.
integration (make integration): located within cmd/syft/internal/test/integration, these tests focus on the behavior surfaced by the common library
entrypoints from the syft package and make light assertions about the results surfaced. Additionally, these tests
tend to make diversity assertions for enum-like objects, ensuring that as enum values are added to a definition
that integration tests will automatically fail if no test attempts to use that enum value. For more details see
the “Data diversity and freshness assertions” section below.
cli (make cli): located with in test/cli, these are tests that test the correctness of application behavior from a
snapshot build. This should be used in cases where a unit or integration test will not do or if you are looking
for in-depth testing of code in the cmd/ package (such as testing the proper behavior of application configuration,
CLI switches, and glue code before syft library calls).
acceptance (make install-test): located within test/compare and test/install, these are smoke-like tests that ensure that application
packaging and installation works as expected. For example, during release we provide RPM packages as a download
artifact. We also have an accompanying RPM acceptance test that installs the RPM from a snapshot build and ensures the
output of a syft invocation matches canned expected output. New acceptance tests should be added for each release artifact
and architecture supported (when possible).
Data diversity and freshness assertions
It is important that tests against the codebase are flexible enough to begin failing when they do not cover “enough”
of the objects under test. “Cover” in this case does not mean that some percentage of the code has been executed
during testing, but instead that there is enough diversity of data input reflected in testing relative to the
definitions available.
For instance, consider an enum-like value like so:
type Language stringconst (
Java Language = "java" JavaScript Language = "javascript" Python Language = "python" Ruby Language = "ruby" Go Language = "go")
Say we have a test that exercises all the languages defined today:
funcTestCatalogPackages(t *testing.T) {
testTable := []struct {
// ... the set of test cases that test all languages }
for _, test :=range cases {
t.Run(test.name, func (t *testing.T) {
// use inputFixturePath and assert that syft.CatalogPackages() returns the set of expected Package objects// ... })
}
}
Where each test case has a inputFixturePath that would result with packages from each language. This test is
brittle since it does not assert that all languages were exercised directly and future modifications (such as
adding a new language) won’t be covered by any test cases.
To address this, the enum-like object should have a definition of all objects that can be used in testing:
type Language string// const( Java Language = ..., ... )var AllLanguages = []Language{
Java,
JavaScript,
Python,
Ruby,
Go,
Rust,
}
Allowing testing to automatically fail when adding a new language:
funcTestCatalogPackages(t *testing.T) {
testTable := []struct {
// ... the set of test cases that (hopefully) covers all languages }
// new stuff... observedLanguages := strset.New()
for _, test :=range cases {
t.Run(test.name, func (t *testing.T) {
// use inputFixturePath and assert that syft.CatalogPackages() returns the set of expected Package objects// ...// new stuff...for _, actualPkg :=range actual {
observedLanguages.Add(string(actualPkg.Language))
}
})
}
// new stuff...for _, expectedLanguage :=range pkg.AllLanguages {
if !observedLanguages.Contains(expectedLanguage) {
t.Errorf("failed to test language=%q", expectedLanguage)
}
}
}
This is a better test since it will fail when someone adds a new language but fails to write a test case that should
exercise that new language. This method is ideal for integration-level testing, where testing correctness in depth
is not needed (that is what unit tests are for) but instead testing in breadth to ensure that units are well integrated.
A similar case can be made for data freshness; if the quality of the results will be diminished if the input data
is not kept up to date then a test should be written (when possible) to assert any input data is not stale.
An example of this is the static list of licenses that is stored in internal/spdxlicense for use by the SPDX
presenters. This list is updated and published periodically by an external group and syft can grab and update this
list by running go generate ./... from the root of the repo.
An integration test has been written to grabs the latest license list version externally and compares that version
with the version generated in the codebase. If they differ, the test fails, indicating to someone that there is an
action needed to update it.
Key Takeaway
Try and write tests that fail when data assumptions change and not just when code changes.
Snapshot tests
The format objects make a lot of use of “snapshot” testing, where you save the expected output bytes from a call into the
git repository and during testing make a comparison of the actual bytes from the subject under test with the golden
copy saved in the repo. The “golden” files are stored in the test-fixtures/snapshot directory relative to the go
package under test and should always be updated by invoking go test on the specific test file with a specific CLI
update flag provided.
Many of the Format tests make use of this approach, where the raw SBOM report is saved in the repo and the test
compares that SBOM with what is generated from the latest presenter code. The following command can be used to
update the golden files for the various snapshot tests:
make update-format-golden-files
These flags are defined at the top of the test files that have tests that use the snapshot files.
Snapshot testing is only as good as the manual verification of the golden snapshot file saved to the repo! Be careful
and diligent when updating these files.
Test fixtures
Syft uses a sophisticated test fixture caching system to speed up test execution. Test fixtures include pre-built test images,
language-specific package manifests, and other test data. Rather than rebuilding fixtures on every checkout, Syft can download
a pre-built cache from GitHub Container Registry.
Common fixture commands:
make fixtures - Intelligently download or rebuild fixtures as needed
make build-fixtures - Manually build all fixtures from scratch
make clean-cache - Remove all cached test fixtures
make check-docker-cache - Verify docker cache size is within limits
When to use each command:
First time setup: Run make fixtures after cloning the repository. This will download the latest fixture cache.
Tests failing unexpectedly: Try make clean-cache followed by make fixtures to ensure you have fresh fixtures.
Working offline: Set DOWNLOAD_TEST_FIXTURE_CACHE=false and run make build-fixtures to build fixtures locally without downloading.
Modifying test fixtures: After changing fixture source files, run make build-fixtures to rebuild affected fixtures.
The fixture system tracks input fingerprints and only rebuilds fixtures when their source files change. This makes the
development cycle faster while ensuring tests always run against the correct fixture data.
Code generation
Syft generates several types of code and data files that need to be kept in sync with external sources or internal structures:
What gets generated:
JSON Schema - Generated from Go structs to define the Syft JSON output format
SPDX License List - Up-to-date list of license identifiers from the SPDX project
CPE Dictionary Index - Index of Common Platform Enumeration identifiers for vulnerability matching
When to regenerate:
Run code generation after:
Modifying the pkg.Package struct or related types (requires JSON schema regeneration)
SPDX releases a new license list
CPE dictionary updates are available
Generation commands:
make generate - Run all generation tasks
make generate-json-schema - Generate JSON schema from Go types
make generate-license-list - Download and generate latest SPDX license list
make generate-cpe-dictionary-index - Generate CPE dictionary index
After running generation commands, review the changes carefully and commit them as part of your pull request. The CI pipeline
will verify that generated files are up to date.
The task system orchestrates all catalogers through CreateSBOMConfig,
which manages task execution, parallelism, and configuration.
generic.NewCataloger is an abstraction syft used to make writing common components easier (see the alpine cataloger for example usage).
It takes the following information as input:
A catalogerName to identify the cataloger uniquely among all other catalogers.
Pairs of file globs as well as parser functions to parse those files.
These parser functions return a slice of pkg.Package as well as a slice of artifact.Relationship to describe how the returned packages are related.
See this the alpine cataloger parser function as an example.
Identified packages share a common pkg.Package struct so be sure that when the new cataloger is constructing a new package it is using the Package struct.
If you want to return more information than what is available on the pkg.Package struct then you can do so in the pkg.Package.Metadata field, which accepts any type.
Metadata types tend to be unique for each pkg.Type but this is not required.
See the pkg package for examples of the different metadata types that are supported today.
When encoding to JSON, metadata type names are determined by reflection and mapped according to internal/packagemetadata/names.go.
Finally, here is an example of where the package construction is done within the alpine cataloger:
If you have questions about implementing a cataloger, feel free to file an issue or reach out to us on discourse!
Troubleshooting
Cannot build test fixtures with Artifactory repositories
Some companies have Artifactory setup internally as a solution for sourcing secure dependencies.
If you’re seeing an issue where the unit tests won’t run because of the below error then this section might be relevant for your use case.
[ERROR] [ERROR] Some problems were encountered while processing the POMs
If you’re dealing with an issue where the unit tests will not pull/build certain java fixtures check some of these settings:
a settings.xml file should be available to help you communicate with your internal artifactory deployment
this can be moved to syft/pkg/cataloger/java/test-fixtures/java-builds/example-jenkins-plugin/ to help build the unit test-fixtures
you’ll also want to modify the build-example-jenkins-plugin.sh to use settings.xml
For more information on this setup and troubleshooting see issue 1895
Next Steps
Understanding the Codebase
Architecture - Learn about package structure, core library flow, cataloger design patterns, and file searching
API Reference - Explore the public Go API, type definitions, and function signatures
Contributing Your Work
Pull Requests - Guidelines for submitting PRs and working with reviewers
In order to test and develop in the Grype repo you will need the following dependencies installed:
Golang
Docker
Python (>= 3.9)
make
SQLite3 (optional – for database inspection)
Initial setup
Run once after cloning to install development tools:
make bootstrap
Make sure you’ve updated your docker settings so the default docker socket path is available.
Go to docker → settings → advanced and ensure “Allow the default Docker socket to be used” is checked.
Use the default docker context, run: docker context use default
Useful commands
Common commands for ongoing development:
make help - List all available commands
make lint - Check code formatting and linting
make lint-fix - Auto-fix formatting issues
make format - Auto-format source code
make unit - Run unit tests
make integration - Run integration tests
make cli - Run CLI tests
make quality - Run vulnerability matching quality tests
make snapshot - Build release snapshot with all binaries and packages
Testing
Levels of testing
unit (make unit): The default level of test which is distributed throughout the repo are unit tests.
Any _test.go file that does not reside somewhere within the /test directory is a unit test.
Other forms of testing should be organized in the /test directory.
These tests should focus on the correctness of functionality in depth.
% test coverage metrics only considers unit tests and no other forms of testing.
integration (make integration): located within test/integration, these tests focus on the behavior surfaced by the Grype library entrypoints and make
assertions about vulnerability matching results.
The integration tests also update the vulnerability database and run with the race detector enabled to catch concurrency issues.
cli (make cli): located within test/cli, these are tests that test the correctness of application behavior from a snapshot build.
This should be used in cases where a unit or integration test will not do or if you are looking for in-depth testing of code in the cmd/ package (such as
testing the proper behavior of application configuration, CLI switches, and glue code before grype library calls).
quality (make quality): located within test/quality, these are tests that verify vulnerability matching quality by comparing Grype’s results against known-good results (quality gates).
These tests help ensure that changes to vulnerability matching logic don’t introduce regressions in match quality. The quality tests use a pinned database version to ensure consistent results.
See the quality gate architecture documentation for how the system works and the test/quality README for practical development workflows.
install (part of acceptance testing): located within test/install, these are smoke-like tests that ensure that application packaging and installation works as expected.
For example, during release we provide RPM packages as a download artifact.
We also have an accompanying RPM acceptance test that installs the RPM from a snapshot build and ensures the output of a grype invocation matches canned expected output.
Quality Gates
Quality gates validate that code changes don’t cause performance regressions in vulnerability matching. The system compares your PR’s matching results against a baseline using a pinned database to isolate code changes from database volatility.
What quality gates validate:
F1 score (combination of true positives, false positives, and false negatives)
False negative count (should not increase)
Indeterminate matches (should remain below 10%)
Common development workflows:
make capture - Download SBOMs and generate match results
make validate - Analyze output and evaluate pass/fail
yardstick label explore [UUID] - Interactive TUI for labeling matches
Grype uses Syft as a library for all-things related to obtaining and parsing the given scan target (pulling container images, parsing container images,
indexing directories, cataloging packages, etc). Releases of Grype should always use released versions of Syft (commits that are tagged and show up in the GitHub releases page).
However, continually integrating unreleased Syft changes into Grype incrementally is encouraged (e.g. go get github.com/anchore/syft@main) as long as by the time
a release is cut the Syft version is updated to a released version (e.g. go get github.com/anchore/syft@v<semantic-version>).
Inspecting the database
The currently supported database format is Sqlite3. Install sqlite3 in your system and ensure that the sqlite3 executable is available in your path.
Ask grype about the location of the database, which will be different depending on the operating system:
$ go run ./cmd/grype db status
Location: /Users/alfredo/Library/Caches/grype/db
Built: 2020-07-31 08:18:29 +0000 UTC
Current DB Version: 1Require DB Version: 1Status: Valid
The database is located within the XDG_CACHE_HOME path. To verify the database filename, list that path:
✓ Updated in-repo documentation if your changes affect user-facing behavior
✓ Written a clear PR title that describes the user-facing impact
✓ Followed existing code style and patterns in the project
Each of these items helps maintainers review your contribution more effectively and merge it faster.
PR Title
Your PR title is important—it becomes the changelog entry in release notes. Write titles that are meaningful to end users, not just developers.
Guidelines
Start with an action verb: “Add”, “Fix”, “Update”, “Remove”
Be specific: “Add support for Alpine 3.19” rather than “Update Alpine”
Keep it concise: Under 72 characters when possible
Focus on user impact: What changed for users, not implementation details
Examples
Good titles:
Add support for Python 3.12 package detection
Fix crash when parsing malformed RPM databases
Update documentation for custom template usage
Poor titles:
Updates (too vague—updates to what?)
Fixed bug (which bug?)
WIP: trying some things (not ready for review)
Refactor parseRPM function (implementation detail, not a user-facing change)
Note
We use chronicle to automatically generate changelogs from issue and PR titles, so a well-written title goes a long way.
PR Description
A clear description helps reviewers understand your changes quickly. Include these key sections:
What to include
Summary: Briefly describe what changed
Motivation: Explain why this change is needed or what problem it solves
Approach: If your solution isn’t obvious, explain your approach
Testing: Describe how you tested the changes
Related issues: Link to issues or discussions that provide context
Template
## Summary
Brief description of the change.
## Motivation
Why is this change needed? What problem does it solve?
## Changes
- Bullet point list of key changes
- Include any breaking changes or migration steps
## Type of change
<!-- Delete any that are not relevant -->
- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (please discuss with the team first; Syft is 1.0 software and we won't accept breaking changes without going to 2.0)
- [ ] Documentation (updates the documentation)
- [ ] Chore (improve the developer experience, fix a test flake, etc, without changing the visible behavior of Syft)
- [ ] Performance (make Syft run faster or use less memory, without changing visible behavior much)
## Checklist
- [ ] I have added unit tests that cover changed behavior
- [ ] I have tested my code in common scenarios and confirmed there are no regressions
- [ ] I have added comments to my code, particularly in hard-to-understand sections
Closes #123
Commit History
We use squash merging for all pull requests, which means:
Your entire PR becomes a single commit on the main branch
You don’t need to maintain a clean commit history in your PR
Merge commits in your feature branch are perfectly fine
You can commit as frequently as you like during development
The PR title (not individual commit messages) becomes the changelog entry
This approach keeps the main branch clean and linear while reducing friction for contributors. Focus on code quality rather than commit structure—reviewers care about the changes, not how you got there.
Size Matters
Small PRs get reviewed faster. Here’s how to make your PR easier to review:
Keep changes focused: Try to address one concern per PR
Avoid mixing unrelated changes: Don’t combine bug fixes with new features
Split large PRs when possible: If a PR is unavoidably large, provide extra context in the description
Consider breaking work into multiple PRs if you’re making both refactoring changes and feature additions. Reviewers can process smaller, focused changes more quickly.
What to Expect
Review Feedback
It’s normal and expected for reviewers to have questions and suggestions:
Questions about your approach: Be prepared to explain your decisions
Code style adjustments: You may be asked to match existing project patterns
Additional tests: Reviewers might request more test coverage
Scope changes: You might be asked to split or narrow the PR
How to respond to feedback
Address feedback promptly: Respond when you can, even if just to acknowledge
Ask for clarification: If something isn’t clear, ask questions
Explain your reasoning: It’s okay to discuss alternatives respectfully
Make changes in new commits: This makes incremental review easier
Mark conversations as resolved: When you’ve addressed a comment
Remember that review feedback is about the code, not about you. Reviewers want to help make the contribution successful.
After Approval
Once approved, a maintainer will merge your PR. Depending on the project, you might be asked to:
Rebase on the latest main branch if there are conflicts
Update the PR title or description for clarity
Make final adjustments based on last-minute feedback
Check the project-specific contributing guide for any additional requirements
Contributing to open source can feel intimidating at first, but the community is here to support you. Don’t hesitate to ask questions.
5.5 - Grype DB
Developer guidelines when contributing to Grype DB
Getting started
This codebase is primarily Go, however, there are also Python scripts critical to the daily DB publishing process as
well as acceptance testing. You will require the following:
Python 3.11+ installed on your system (Python 3.11-3.13 supported). Consider using pyenv if you do not have a
preference for managing python interpreter installations.
zstd binary utility if you are packaging v6+ DB schemas
(optional)xz binary utility if you have specifically overridden the package command options
uv installed for Python package and virtualenv management
To download Go tooling used for static analysis, dependent Go modules, and Python dependencies run:
make bootstrap
Useful commands
Common commands for ongoing development:
make help - List all available commands
make lint - Check code formatting and linting
make lint-fix - Auto-fix formatting issues
make unit - Run unit tests (Go and Python)
make cli - Run CLI tests
make db-acceptance schema=<version> - Run DB acceptance tests for a schema version
make snapshot - Build release snapshot with all binaries and packages
make download-all-provider-cache - Download pre-built vulnerability data cache
Development workflows
Getting vulnerability data
In order to build a grype DB you will need a local cache of vulnerability data:
make download-all-provider-cache
This will populate the ./data directory locally with everything needed to run grype-db build (without needing to run grype-db pull).
This data being pulled down is the same data used in the daily DB publishing workflow, so it should be relatively fresh.
Creating a new DB schema
Create a new v# schema package in the grype repo (within pkg/db)
Create a new v# schema package in the grype-db repo (use the bump-schema.py helper script) that uses the new changes from grype-db
Modify the manager/src/grype_db_manager/data/schema-info.json to pin the last-latest version to a specific version of grype and add the new schema version pinned to the “main” branch of grype (or a development branch)
Update all references in grype to use the new schema
Use the Staging DB Publisher workflow to test your DB changes with grype in a flow similar to the daily DB publisher workflow
Testing with staging databases
While developing a new schema version it may be useful to get a DB built for you by the Staging DB Publisher GitHub Actions workflow.
This code exercises the same code as the Daily DB Publisher, with the exception that only a single schema is built and is validated against a given development branch of grype.
When these DBs are published you can point grype at the proper listing file like so:
unit (make unit): Unit tests for both Go code in the main codebase and Python scripts in the manager/ directory.
These tests focus on correctness of individual functions and components. Coverage metrics track Go test coverage.
cli (make cli): CLI tests for both Go and Python components. These validate that command-line interfaces work correctly with various inputs and configurations.
db-acceptance (make db-acceptance schema=<version>): Acceptance tests that verify a specific DB schema version works correctly with Grype.
These tests build a database, run Grype scans, and validate that vulnerability matches are correct and complete.
Running tests
To run unit tests for Go code and Python scripts:
make unit
To verify that a specific DB schema version interops with Grype:
make db-acceptance schema=<version>
# Note: this may take a while... go make some coffee.
Next Steps
Understanding the Codebase
Architecture - Learn about the ETL pipeline, schema support, and publishing workflow
Vunnel Documentation - Understand the vulnerability data provider system that feeds Grype DB
Contributing Your Work
Pull Requests - Guidelines for submitting PRs and working with reviewers
posix shell (bash, zsh, etc… needed for the make dev “development shell”)
Once you have python and uv installed, get the project bootstrapped:
# clone grype and grype-db, which is needed for provider development
git clone git@github.com:anchore/grype.git
git clone git@github.com:anchore/grype-db.git
# note: if you already have these repos cloned, you can skip this step. However, if they
# reside in a different directory than where the vunnel repo is, then you will need to
# set the `GRYPE_PATH` and/or `GRYPE_DB_PATH` environment variables for the development
# shell to function. You can add these to a local .env file in the vunnel repo root.
# clone the vunnel repo
git clone git@github.com:anchore/vunnel.git
cd vunnel
# get basic project tooling
make bootstrap
# install project dependencies
uv sync --all-extras --dev
Pre-commit is used to help enforce static analysis checks with git hooks:
uv run pre-commit install --hook-type pre-push
Developing
Development shell
The easiest way to develop on a providers is to use the development shell, selecting the specific provider(s) you’d like to focus your development workflow on:
# Specify one or more providers you want to develop on.
# Any provider from the output of "vunnel list" is valid.
# Specify multiple as a space-delimited list:
# make dev providers="oracle wolfi nvd"
$ make dev provider="oracle"
Entering vunnel development shell...
• Configuring with providers: oracle ...
• Writing grype config: /Users/wagoodman/code/vunnel/.grype.yaml ...
• Writing grype-db config: /Users/wagoodman/code/vunnel/.grype-db.yaml ...
• Activating virtual env: /Users/wagoodman/code/vunnel/.venv ...
• Installing editable version of vunnel ...
• Building grype ...
• Building grype-db ...
Note: development builds grype and grype-db are now available in your path.
To update these builds run 'make build-grype' and 'make build-grype-db' respectively.
To run your provider and update the grype database run 'make update-db'.
Type 'exit' to exit the development shell.
You can now run the provider you specified in the make dev command, build an isolated grype DB, and import the DB into grype:
$ make update-db
• Updating vunnel providers ...[0000] INFO grype-db version: ede464c2def9c085325e18ed319b36424d71180d-adhoc-build
...[0000] INFO configured providers parallelism=1 providers=1[0000] DEBUG └── oracle
[0000] DEBUG all providers started, waiting for graceful completion...[0000] INFO running vulnerability provider provider=oracle
[0000] DEBUG oracle: 2023-03-0715:44:13 [INFO] running oracle provider
[0000] DEBUG oracle: 2023-03-0715:44:13 [INFO] downloading ELSA from https://linux.oracle.com/security/oval/com.oracle.elsa-all.xml.bz2
[0019] DEBUG oracle: 2023-03-0715:44:31 [INFO] wrote 6298 entries
[0019] DEBUG oracle: 2023-03-0715:44:31 [INFO] recording workspace state
• Building grype-db ...[0000] INFO grype-db version: ede464c2def9c085325e18ed319b36424d71180d-adhoc-build
[0000] INFO reading all provider state
[0000] INFO building DB build-directory=./build providers=[oracle] schema=5• Packaging grype-db ...[0000] INFO grype-db version: ede464c2def9c085325e18ed319b36424d71180d-adhoc-build
[0000] INFO packaging DB from="./build"for="https://toolbox-data.anchore.io/grype/databases"[0000] INFO created DB archive path=build/vulnerability-db_v5_2023-03-07T20:44:13Z_405ae93d52ac4cde6606.tar.gz
• Importing DB into grype ...Vulnerability database imported
You can now run grype that uses the newly created DB:
$ grype oraclelinux:8.4 ✔ Pulled image
✔ Loaded image
✔ Parsed image
✔ Cataloged packages [195 packages]
✔ Scanning image... [193 vulnerabilities]
├── 0 critical, 25 high, 146 medium, 22 low, 0 negligible
└── 193 fixed
NAME INSTALLED FIXED-IN TYPE VULNERABILITY SEVERITY
bind-export-libs 32:9.11.26-4.el8_4 32:9.11.26-6.el8 rpm ELSA-2021-4384 Medium
bind-export-libs 32:9.11.26-4.el8_4 32:9.11.36-3.el8 rpm ELSA-2022-2092 Medium
bind-export-libs 32:9.11.26-4.el8_4 32:9.11.36-3.el8_6.1 rpm ELSA-2022-6778 High
bind-export-libs 32:9.11.26-4.el8_4 32:9.11.36-5.el8 rpm ELSA-2022-7790 Medium
# note that we're using the database we just built...$ grype db status
Location: /Users/wagoodman/code/vunnel/.cache/grype/5# <--- this is the local DB we just built...# also note that we're using a development build of grype$ which grype
/Users/wagoodman/code/vunnel/bin/grype
The development builds of grype and grype-db provided are derived from ../grype and ../grype-db paths relative to the vunnel project.
If you want to use a different path, you can set the GRYPE_PATH and GRYPE_DB_PATH environment variables. This can be
persisted by adding a .env file to the root of the vunnel project:
# example .env file in the root of the vunnel repo
GRYPE_PATH=~/somewhere/else/grype
GRYPE_DB_PATH=~/also/somewhere/else/grype-db
Rebuilding development tools
To rebuild the grype and grype-db binaries from local source, run:
make build-grype
make build-grype-db
Common commands
This project uses Make for running common development tasks:
make # run static analysis and unit testing
make static-analysis # run static analysis
make unit # run unit tests
make format # format the codebase with black
make lint-fix # attempt to automatically fix linting errors
...
If you want to see all of the things you can do:
make help
If you want to use a locally-editable copy of vunnel while you develop without the custom development shell:
uv pip uninstall vunnel #... if you already have vunnel installed in this virtual env
uv pip install -e .
Snapshot tests
In order to ensure that the same feed state from providers would make the same
set of vulnerabilities, snapshot testing is used.
Snapshot tests are run as part of ordinary unit tests, and will run during
make unit.
To update snapshots, run the following pytest command. (Note that this example
is for the debian provider, and the test name and path will be different for
other providers):
“Vulnerability matching” is the process of taking a list of vulnerabilities and matching them against a list of packages.
A provider in this repo is responsible for the “vulnerability” side of this process. The “package” side is handled by
Syft. A prerequisite for adding a new provider is that Syft can catalog the package types that
the provider is feeding vulnerability data for, so Grype can perform the matching from these two sources.
To add a new provider, you will need to create a new provider class under /src/vunnel/providers/<name> that inherits from provider.Provider and implements:
name(): a unique and semantically-useful name for the provider (same as the name of the directory)
update(): downloads and processes the raw data, writing all results with self.results_writer()
All results must conform to a particular schema, today there are a few kinds:
os: a generic operating system vulnerability (e.g redhat, debian, ubuntu, alpine, wolfi, etc.)
nvd: tailored to describe vulnerabilities from the NVD
github-security-advisory: tailored to describe vulnerabilities from GitHub
Once the provider is implemented, you will need to wire it up into the application in a couple places:
add a new entry under the dispatch table in src/vunnel/providers/__init__.py mapping your provider name to the class
add the provider configuration to the application configuration under src/vunnel/cli/config.py (specifically the Providers dataclass)
For a more detailed example on the implementation details of a provider see the “example” provider.
Validating this provider has different implications depending on what is being added. For example, if the provider is
adding a new vulnerability source but is ultimately using an existing schema to express results then there may be very little to do!
If you are adding a new schema, then the downstream data pipeline will need to be altered to support reading data in the new schema.
Need help with your provider?
Feel free to reach out to a maintainer on an incomplete draft PR and we can help you get it over the finish line!
For an existing schema
1. Fork Vunnel and add the new provider.
Take a look at the example provider in the example directory. You are encouraged to copy example/awesome/* into
src/vunnel/providers/YOURPROVIDERNAME/ and modify it to fit the needs of your new provider, however, this is not required:
# from the root of the vunnel repo
cp -a example/awesome src/vunnel/providers/YOURPROVIDERNAME
See the “example” provider README as well as the code comments for steps and considerations to take when implementing a new provider.
Once implemented, you should be able to see the new provider in the vunnel list command and run it with vunnel run <name>.
The entries written should write out to a specific namespace in the DB downstream, as indicated in the record.
This namespace is needed when making Grype changes.
While developing the provider consider using the make dev provider="<your-provider-name>"developer shell to run the provider and manually test the results against grype.
At this point you can optionally open a Vunnel PR with your new provider and a Maintainer can help with the next steps. Or if you’d like to get PR changes merged faster you can continue with the next steps.
2. Fork Grype and map distro type to a specific namespace.
This step might not be needed depending on the provider.
Common reasons for needing Grype changes include:
Grype does not support the distro type and it needs to be added. See the grype/distro/types.go file to add the new distro.
Grype supports the distro already, but matching is disabled. See the grype/distro/distro.go file to enable the distro explicitly.
These images are used to test the provider on PRs and nightly builds to verify the specific provider is working.
Always use both the image tag and digest for all container image entries.
Pick an image that has a good representation of the package types that your new provider is adding vulnerability data for.
4. In Vunnel: swap the tools to your Grype branch in tests/quality/config.yaml.
If you wanted to see PR quality gate checks pass with your specific Grype changes (if you have any) then you can update the
yardstick.tools[*] entries for grype to use the a version that points to your fork (w.g. your-fork-username/grype@main).
If you don’t have any grype changes needed then you can skip this step.
5. In Vunnel: add new “vulnerability match labels” to annotate True and False positive findings with Grype.
In order to evaluate the quality of the new provider, we need to know what the expected results are. This is done by
annotating Grype results with “True Positive” labels (good results) and “False Positive” labels (bad results). We’ll use
Yardstick to do this:
$ cd tests/quality
# capture results with the development version of grype (from your fork)
$ make capture provider=<your-provider-name>
# list your results
$ uv run yardstick result list | grep grype
d415064e-2bf3-4a1d-bda6-9c3957f2f71a docker.io/anc... grype@v0.58.0 2023-03...
75d1fe75-0890-4d89-a497-b1050826d9f6 docker.io/anc... grype[custom-db]@bdcefd2 2023-03...
# use the "grype[custom-db]" result UUID and explore the results and add labels to each entry
$ uv run yardstick label explore 75d1fe75-0890-4d89-a497-b1050826d9f6
# You can use the yardstick TUI to label results:
# - use "T" to label a row as a True Positive
# - use "F" to label a row as a False Positive
# - Ctrl-Z to undo a label
# - Ctrl-S to save your labels
# - Ctrl-C to quit when you are done
Later we’ll open a PR in the vulnerability-match-labels repo to persist these labels.
For the meantime we can iterate locally with the labels we’ve added.
6. In Vunnel: run the quality gate.
cd tests/quality
# runs your specific provider to gather vulnerability data, builds a DB, and runs grype with the new DB
make capture provider=<your-provider-name>
# evaluate the quality gate
make validate
This uses the latest Grype DB release to build a DB and the specified Grype version with a DB containing only data from the new provider.
You are looking for a passing run before continuing further.
Vunnel uses the labels in the vulnerability-Match-Labels repo via a git submodule. We’ve already added labels locally
within this submodule in an earlier step. To persist these labels we need to push them to a fork and open a PR:
# fork the github.com/anchore/vulnerability-match-labels repo, but you do not need to clone it...
# from the Vunnel repo...
$ cd tests/quality/vulnerability-match-labels
$ git remote add fork git@github.com:your-fork-name/vulnerability-match-labels.git
$ git checkout -b 'add-labels-for-<your-provider-name>'
$ git status
# you should see changes from the labels/ directory for your provider that you added
$ git add .
$ git commit -m 'add labels for <your-provider-name>'
$ git push fork add-labels-for-<your-provider-name>
Note: you will not be able to open a Vunnel PR that passes PR checks until the labels are merged into the vulnerability-match-labels repo.
Once the PR is merged in the vulnerability-match-labels repo you can update the submodule in Vunnel to point to the latest commit in the vulnerability-match-labels repo.
cd tests/quality
git submodule update --remote vulnerability-match-labels
8. In Vunnel: open a PR with your new provider.
The PR will also run all of the same quality gate checks that you ran locally.
If you have Grype changes, you should also create a PR for that as well. The Vunnel PR will not pass PR checks until the Grype PR is merged and the test/quality/config.yaml file is updated to point back to the latest Grype version.
For a new schema
This is the same process as listed above with a few additional steps:
You will need to add the new schema to the Vunnel repo in the schemas directory.
Grype DB will need to be updated to support the new schema in the pkg/provider/unmarshal and pkg/process/v* directories.
The Vunnel tests/quality/config.yaml file will need to be updated to use development grype-db.version, pointing to your fork.
The final Vunnel PR will not be able to be merged until the Grype DB PR is merged and the tests/quality/config.yaml file is updated to point back to the latest Grype DB version.
Contributing improvements
Finding refactoring opportunities
Looking to help out with improving the code quality of Vunnel, but not sure where to start?
More general ways would be to use radon to search for complexity and maintainability issues:
$ radon cc src --total-average -nb
src/vunnel/provider.py
M 115:4 Provider._on_error - B
src/vunnel/providers/alpine/parser.py
M 73:4 Parser._download - C
M 178:4 Parser._normalize - C
M 141:4 Parser._load - B
C 44:0 Parser - B
src/vunnel/providers/amazon/parser.py
M 66:4 Parser._parse_rss - C
C 164:0 JsonifierMixin - C
M 165:4 JsonifierMixin.json - C
C 32:0 Parser - B
M 239:4 PackagesHTMLParser.handle_data - B
...
The output of radon indicates the type (M=method, C=class, F=function), the path/name, and a A-F grade. Anything that’s not an A is worth taking a look at.
Ideally we should try to get wily diff output into the CI pipeline and post on a sticky PR comment to show regressions (and potentially fail the CI run).
Adding type hints
This codebase has been ported from another repo that did not have any type hints. This is OK, though ideally over time this should
be corrected as new features are added and bug fixes made.
We use mypy today for static type checking, however, the ported code has been explicitly ignored (see pyproject.toml).
If you want to make enhancements in this area consider using automated tooling such as pytype to generate types via inference into .pyi files and later merge them into the codebase with merge-pyi.
Alternatively a tool like MonkeyType can be used generate static types from runtime data and incorporate into the code.
Next Steps
Understanding the Codebase
Vunnel Architecture - Learn about provider abstraction, workspace conventions, and vulnerability schemas
Example Provider - Detailed walkthrough of creating a new provider
Contributing Your Work
Pull Requests - Guidelines for submitting PRs and working with reviewers
In order to test and develop in the Grant repo you will need the following dependencies installed:
Golang
Docker
make
Initial setup
Run once after cloning to install development tools:
make bootstrap
Make sure you’ve updated your docker settings so the default docker socket path is available.
Go to docker → settings → advanced and ensure “Allow the default Docker socket to be used” is checked.
Use the default docker context, run: docker context use default
Useful commands
Common commands for ongoing development:
make help - List all available commands
make lint - Check code formatting and linting
make lint-fix - Auto-fix formatting issues
make unit - Run unit tests
make test - Run all tests
make snapshot - Build release snapshot with all binaries and packages (also available as make build)
make generate - Generate SPDX license index and license patterns
Testing
Levels of testing
unit (make unit): The default level of test which is distributed throughout the repo are unit tests.
Any _test.go file that does not reside somewhere within the /tests directory is a unit test.
These tests focus on the correctness of functionality in depth. % test coverage metrics only consider unit tests and no other forms of testing.
integration (make test): located in tests/integration_test.go, these tests focus on policy loading, license evaluation, and core library behavior.
They test the interaction between different components like policy parsing, license matching with glob patterns, and package evaluation logic.
cli (part of make test): located in tests/cli/, these are tests that test the correctness of application behavior from a snapshot build.
These tests execute the actual Grant binary and verify command output, exit codes, and behavior of commands like check, list, and version.
Testing conventions
Unit tests should focus on correctness of individual functions and components
Integration tests validate that core library components work together correctly (policy evaluation, license matching, etc.)
CLI tests ensure user-facing commands produce expected output and behavior
Current coverage threshold is 8% (see Taskfile.yaml)
Use table-driven tests where appropriate to test multiple scenarios
Linting
You can run the linter for the project by running:
make lint
This checks code formatting with gofmt and runs golangci-lint checks.
To automatically fix linting issues:
make lint-fix
Code generation
Grant generates code and data files that need to be kept in sync with external sources:
What gets generated:
SPDX License Index - Up-to-date list of license identifiers from the SPDX project for license identification and validation
License File Patterns - Generated patterns to identify license files in scanned directories
When to regenerate:
Run code generation after:
The SPDX license list has been updated
Adding new license file naming patterns
Contributing changes to license detection logic
Generation commands:
make generate - Run all generation tasks
make generate-spdx-licenses - Download and generate latest SPDX license list
make generate-license-patterns - Generate license file patterns (depends on SPDX license index)
After running generation commands, review the changes carefully and commit them as part of your pull request.
Package structure
Grant is organized into two main areas: the public library API and the CLI application. For detailed API documentation, see the Grant Go package reference.
grant/ - Public Library API
The top-level grant/ package is the public library that other projects can import and use. This is what you’d reference with import "github.com/anchore/grant/grant".
This package contains the core functionality:
License evaluation and matching
Policy loading and validation
Package analysis and filtering
Most contributions to core Grant functionality belong in this package.
cmd/grant/ - CLI Application
The CLI application is built on top of the grant/ library and contains application-specific code:
How to sign-off commits with the Developer’s Certificate of Origin
Sign off your work
All commits require a simple sign-off line to confirm you have the right to contribute your code.
This is a standard practice in open source called the Developer Certificate of Origin (DCO).
How to sign off
The easiest way is to use the -s or --signoff flag when committing:
git commit -s -m "your commit message"
This automatically adds a sign-off line to your commit message:
Signed-off-by: Your Name <your.email@example.com>
Tip: You can configure Git to always sign off commits automatically:
git config --global format.signoff true
Verify your sign-off
To check that your commit includes the sign-off, look at the log output:
git log -1
You should see the Signed-off-by: line at the end of your commit message:
commit 37ceh170e4hb283bb73d958f2036ee5k07e7fde7
Author: Your Name <your.email@example.com>
Date: Mon Aug 1 11:27:13 2020 -0400
your commit message
Signed-off-by: Your Name <your.email@example.com>
Why we require sign-off
In plain English: By adding a sign-off line, you’re confirming that:
You wrote the code yourself, OR
You have permission to submit it, AND
You’re okay with it being released under the project’s open source license
This protects both you and the project. It’s a simple legal formality that takes just a few seconds to add to each commit.
If you’ve already committed without a sign-off (easy to do!), you can add it retroactively.
For your most recent commit
git commit --amend --signoff
This updates your last commit to include the sign-off line.
For older commits
If you need to add sign-off to commits further back in your history:
git rebase --signoff HEAD~N
Replace N with the number of commits you need to sign. For example, HEAD~3 signs off the last 3 commits.
Note: If you’ve already pushed these commits, you’ll need to force-push after rebasing:
git push --force-with-lease
If you’re new to rebasing
Rebasing rewrites commit history, which can be tricky if you’re not familiar with it. If you run into issues:
Ask for help in the PR comments
Or, create a fresh branch from the latest main and cherry-pick your changes
The maintainers can also help you fix sign-off issues during the review process
What the DCO means (technical details)
The Developer Certificate of Origin (DCO) is a legal attestation that you have the right to submit your contribution under the project’s license.
Here’s the full text:
Developer's Certificate of Origin 1.1
By making a contribution to this project, I certify that:
(a) The contribution was created in whole or in part by me and I
have the right to submit it under the open source license
indicated in the file; or
(b) The contribution is based upon previous work that, to the best
of my knowledge, is covered under an appropriate open source
license and I have the right under that license to submit that
work with modifications, whether created in whole or in part
by me, under the same open source license (unless I am
permitted to submit under a different license), as indicated
in the file; or
(c) The contribution was provided directly to me by some other
person who certified (a), (b) or (c) and I have not modified
it.
(d) I understand and agree that this project and the contribution
are public and that a record of the contribution (including all
personal information I submit with it, including my sign-off) is
maintained indefinitely and may be redistributed consistent with
this project or the open source license(s) involved.
The DCO protects both contributors and the project by creating a clear record of contribution rights and licensing terms.
5.9 - SBOM Action
Developer guidelines when contributing to sbom-action
Getting started
In order to test and develop in the sbom-action repo you will need the following dependencies installed:
Node.js (>= 20.11.0)
npm
Docker
Initial setup
Run once after cloning to install dependencies and development tools:
npm install
This command installs all dependencies and sets up Husky git hooks that automatically format code and rebuild the distribution files before commits.
Useful commands
Common commands for ongoing development:
npm run build - Check TypeScript compilation (no output files)
npm run lint - Check code with ESLint
npm run format - Auto-format code with Prettier
npm run format-check - Check code formatting without changes
npm run package - Build distribution files with ncc (outputs to dist/)
npm test - Run Jest tests
npm run all - Complete validation suite (build + format + lint + package + test)
Testing
The sbom-action uses Jest for testing. To run the test suite:
npm test
The CI workflow handles any additional setup automatically (like Docker registries). For local development, you just need to install dependencies and run tests.
Test types
The test suite includes two main categories:
Unit tests (e.g., tests/GithubClient.test.ts, tests/SyftGithubAction.test.ts): Test individual components in isolation by mocking GitHub Actions context and external dependencies.
Integration tests (tests/integration/): Execute the full action workflow with real Syft invocations against test fixtures in tests/fixtures/ (npm-project, yarn-project). These tests use snapshot testing to validate SBOM output and GitHub dependency snapshot uploads.
Snapshot testing
Integration tests extensively use Jest’s snapshot testing to validate SBOM output. When you run integration tests, Jest compares the generated SBOMs against saved snapshots in tests/integration/__snapshots__/.
The tests normalize dynamic values (timestamps, hashes, IDs) before comparison to ensure consistent snapshots across runs.
Updating snapshots:
When you intentionally change SBOM output format or content, update the snapshots:
npm run test:update-snapshots
Important: Always manually review snapshot changes before committing. Snapshots capture expected behavior, so changes should be intentional and correct.
Development workflow
Pre-commit hooks
The sbom-action uses Husky to run automated checks before each commit:
The hook is defined in .husky/pre-commit and runs the precommit npm script.
Why commit dist/?
GitHub Actions can’t install dependencies or compile code at runtime. The action must include pre-built JavaScript files in the dist/ directory. The ncc compiler bundles all TypeScript source and dependencies into standalone JavaScript files.
Code organization
The sbom-action consists of three GitHub Actions, each with its own entry point:
Main action (action.yml):
Entry point: src/runSyftAction.ts
Compiled to: dist/runSyftAction/index.js
Generates SBOMs and uploads as workflow artifacts and release assets
Or test locally using act if you have it installed.
Action runtime
The sbom-action uses the Node.js 20 runtime (runs.using: node20 in action.yml). This runtime is provided by GitHub Actions and doesn’t require separate installation in workflows.
How to report security vulnerabilities in Anchore OSS projects
Security is a top priority for Anchore’s open source projects.
We appreciate the security research community’s efforts in responsibly disclosing vulnerabilities to help keep our users safe.
Supported Versions
Security updates are applied only to the most recent release of each project.
We strongly recommend staying up to date with the latest versions to ensure you have the most recent security patches and fixes.
If you’re using an older version and concerned about a security issue, please upgrade to the latest release.
For questions about specific versions, reach out on Discourse.
Reporting a Vulnerability
Found a security vulnerability? Please report security issues privately by emailing security@anchore.com rather than creating a public GitHub issue.
This gives us time to fix the problem and protect users before details become public.
What to Include in Your Report
To help us understand and address the issue quickly, please include as much detail as you can:
Description: A clear description of the vulnerability and its potential impact
Steps to reproduce: Detailed steps to recreate the issue
Affected versions: Which versions of the tool are vulnerable
Proof of concept: If available, a minimal example demonstrating the issue
Suggested mitigation: If you have ideas for how to fix or mitigate the issue
Urgency level: Your assessment of the severity (Critical, High, Medium, or Low)
Don’t worry if you can’t provide every detail –partial reports are still valuable and welcome.
We’ll work with you to understand the issue.
What to Expect
After you submit a report:
Acknowledgment: You’ll receive an initial response confirming we’ve received your report
Assessment: The security team will investigate and assess the severity and impact
Updates: We’ll keep you informed of our progress and any questions we have
Resolution: Once a fix is developed, if necessary, we’ll coordinate disclosure timing with you
Credit: With your permission, we’ll acknowledge your responsible disclosure in release notes
Disclosure Policy
Anchore follows a coordinated disclosure process:
Security issues are addressed privately until a fix is available
Fixes are released as quickly as possible based on severity
Security advisories are published after fixes are released
Credit is given to security researchers who report responsibly
Thank you for helping keep Anchore’s open source projects and their users secure.
5.11 - Code of Conduct
Community standards and guidelines for respectful collaboration
We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community.
Our Standards
Examples of behavior that contributes to a positive environment for our community include:
Demonstrating empathy and kindness toward other people
Being respectful of differing opinions, viewpoints, and experiences
Giving and gracefully accepting constructive feedback
Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience
Focusing on what is best not just for us as individuals, but for the overall community
Examples of unacceptable behavior include:
The use of sexualized language or imagery, and sexual attention or advances of any kind
Trolling, insulting or derogatory comments, and personal or political attacks
Public or private harassment
Publishing others’ private information, such as a physical or email address, without their explicit permission
Other conduct which could reasonably be considered inappropriate in a professional setting
Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of acceptable behavior and will take appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening, offensive, or harmful.
Community leaders have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, and will communicate reasons for moderation decisions when appropriate.
Scope
This Code of Conduct applies within all community spaces, and also applies when an individual is officially representing the community in public spaces. Examples of representing our community include using an official email address, posting via an official social media account, or acting as an appointed representative at an online or offline event.
Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement at opensource@anchore.com.
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the reporter of any incident.
Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining the consequences for any action they deem in violation of this Code of Conduct:
1. Warning
Community Impact: Use of inappropriate language or other behavior deemed unprofessional or unwelcome in the community.
Consequence: The original post will be edited or removed and a warning issued to the offender.
2. Temporary Ban
Community Impact: A serious violation of community standards, including sustained inappropriate behavior.
Consequence: A temporary ban from any sort of interaction or public communication with the community for a specified period of time.
No public or private interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
3. Permanent Ban
Community Impact: Demonstrating a pattern of violation of community standards, including sustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement of classes of individuals.
Consequence: A permanent ban from any sort of public interaction within the community.
Developer guidelines when contributing to scan-action
Getting started
In order to test and develop in the scan-action repo you will need the following dependencies installed:
Node.js (>= 20.11.0)
npm
Docker
Initial setup
Run once after cloning to install dependencies and development tools:
npm install
This command installs all dependencies and sets up Husky git hooks that automatically format code and rebuild the distribution files before commits.
Useful commands
Common commands for ongoing development:
npm run build - Bundle with ncc and normalize line endings
npm run lint - Check code with ESLint
npm run prettier - Auto-format code with Prettier
npm test - Complete test suite (lint + install Grype + build + run tests)
npm run run-tests - Run Jest tests only
npm run test:update-snapshots - Update test expectations (lint + install Grype + run tests with snapshot updates)
npm run audit - Run security audit on production dependencies
npm run update-deps - Update dependencies with npm-check-updates
Testing
Tests require Grype to be installed locally and a Docker registry for integration tests. Set up your test environment:
Install Grype locally:
npm run install-and-update-grype
Start local Docker registry:
docker run -d -p 5000:5000 --name registry registry:2
Tests automatically disable Grype database auto-update and validation to ensure consistent test results.
CI environment:
The GitHub Actions test workflow automatically:
Starts a Docker registry service on port 5000
Tests on Ubuntu, Windows, and macOS
Validates across multiple configurations (image/path/sbom sources, output formats)
Test types
The scan-action uses Jest for testing with several categories:
Unit tests (e.g., tests/action.test.js, tests/grype_command.test.js): Test individual functions in isolation by mocking GitHub Actions context and external dependencies.
Integration tests: Execute the full action workflow with real Grype invocations. These tests validate end-to-end functionality including downloading Grype, running scans, and generating output files.
SARIF validation tests (tests/sarif_output.test.js): Validate SARIF report structure and content using the @microsoft/jest-sarif library to ensure consistent output format and compliance with the SARIF specification.
Distribution tests (tests/dist.test.js): Verify that the committed dist/ directory is up-to-date with the source code.
Test fixtures:
The tests/fixtures/ directory contains sample projects and files for testing:
npm-project/ - Sample npm project for directory scanning
yarn-project/ - Sample yarn project for directory scanning
test_sbom.spdx.json - Sample SBOM file for SBOM scanning tests
SARIF output testing
The SARIF output tests validate report structure using the @microsoft/jest-sarif library. Tests normalize dynamic values (versions, fully qualified names) before validation to ensure consistent results across test runs.
The tests validate that:
Generated SARIF reports are valid according to the SARIF specification
Expected vulnerabilities are detected in test fixtures
Output structure remains consistent across runs
If you need to update test expectations, run:
npm run test:update-snapshots
Important: Always manually review test changes before committing. Tests capture expected behavior, so changes should be intentional and correct.
Development workflow
Pre-commit hooks
The scan-action uses Husky to run automated checks before each commit:
Code formatting - lint-staged runs Prettier on staged JavaScript files
Distribution rebuild - Runs npm run precommit to rebuild dist/ directory
The hook is defined in .husky/pre-commit and ensures that distribution files are always synchronized with source code.
Why commit dist/?
GitHub Actions can’t install dependencies or compile code at runtime. The action must include pre-built JavaScript files in the dist/ directory. The ncc compiler bundles all source code and dependencies into standalone JavaScript files.
Code organization
The scan-action has a straightforward single-file architecture:
Or test locally using act if you have it installed.
Action runtime
The scan-action uses the Node.js 20 runtime (runs.using: node20 in action.yml). This runtime is provided by GitHub Actions and doesn’t require separate installation in workflows.
This style guide is for the Anchore OSS documentation.
The style guide helps contributors to write documentation that readers can understand quickly and correctly.
The Anchore OSS docs aim for:
Consistency in style and terminology, so that readers can expect certain
structures and conventions. Readers don’t have to keep re-learning how to use
the documentation or questioning whether they’ve understood something
correctly.
Clear, concise writing so that readers can quickly find and understand the
information they need.
Capitalize only the first letter of each heading within the page. (That is, use sentence case.)
Capitalize (almost) every word in page titles. (That is, use title case.)
The little words like “and”, “in”, etc, don’t get a capital letter.
In page content, use capitals only for brand names, like Syft, Anchore, and so on.
See more about brand names below.
Don’t use capital letters to emphasize words.
Spell out abbreviations and acronyms on first use
Always spell out the full term for every abbreviation or acronym the first time you use it on the page.
Don’t assume people know what an abbreviation or acronym means, even if it seems like common knowledge.
Example: “To run Grype locally in a virtual machine (VM)”
Use contractions if you want to
For example, it’s fine to write “it’s” instead of “it is”.
Use full, correct brand names
When referring to a product or brand, use the full name.
Capitalize the name as the product owners do in the product documentation.
Do not use abbreviations even if they’re in common use, unless the product owner has sanctioned the abbreviation.
Use this
Instead of this
Anchore
anchore
Kubernetes
k8s
GitHub
github
Be consistent with punctuation
Use punctuation consistently within a page.
For example, if you use a period (full stop) after every item in list, then use a period on all other lists on the page.
Check the other pages if you’re unsure about a particular convention.
Examples:
Most pages in the Anchore OSS docs use a period at the end of every list item.
There is no period at the end of the page subtitle and the subtitle need not be a full sentence.
(The subtitle comes from the description in the front matter of each page.)
Use active voice rather than passive voice
Passive voice is often confusing, as it’s not clear who should perform the action.
Use active voice
Instead of passive voice
You can configure Grype to
Grype can be configured to
Add the directory to your path
The directory should be added to your path
Use simple present tense
Avoid future tense (“will”) and complex syntax such as conjunctive mood (“would”, “should”).
Use simple present tense
Instead of future tense or complex syntax
The following command provisions a virtual machine
The following command will provision a virtual machine
If you add this configuration element, the system is open to
the Internet
If you added this configuration element, the system would be open to
the Internet
Exception: Use future tense if it’s necessary to convey the correct meaning. This requirement is rare.
Address the audience directly
Using “we” in a sentence can be confusing, because the reader may not know whether they’re part of the “we” you’re describing.
For example, compare the following two statements:
“In this release we’ve added many new features.”
“In this tutorial we build a flying saucer.”
The words “the developer” or “the user” can be ambiguous.
For example, if the reader is building a product that also has users,
then the reader does not know whether you’re referring to the reader or the users of their product.
Address the reader directly
Instead of "we", "the user", or "the developer"
Include the directory in your path
The user must make sure that the directory is included in their path
In this tutorial you build a flying saucer
In this tutorial we build a flying saucer
Use short, simple sentences
Keep sentences short. Short sentences are easier to read than long ones.
Below are some tips for writing short sentences.
Use fewer words instead of many words that convey the same meaning
Use this
Instead of this
You can use
It is also possible to use
You can
You are able to
Split a single long sentence into two or more shorter ones
Use this
Instead of this
You do not need a running GKE cluster. The deployment process
creates a cluster for you
You do not need a running GKE cluster, because the deployment
process creates a cluster for you
Use a list instead of a long sentence showing various options
Use this
Instead of this
To scan a container for vulnerabilities:
Package the software in an OCI container.
Upload the container to an online registry.
Run Grype with the container name as a parameter.
To scan a container, you must package the software in an OCI container,
upload the container to an online registry, and run Grype with the container
name as a parameter.
Avoid too much text styling
Use bold text when referring to UI controls or other UI elements.
Use code style for:
filenames, directories, and paths
inline code and commands
object field names
Avoid using bold text or capital letters for emphasis.
If a page has too much textual highlighting it becomes confusing and even annoying.
Use angle brackets for placeholders
For example:
export SYFT_PARALLELISM=<number>
--email <your email address>
Style your images
The Anchore OSS docs recognize Bootstrap classes to style images and other content.
The following code snippet shows the typical styling that makes an image show up nicely on the page:
The Google Developer Documentation Style Guide contains detailed information about specific aspects of writing clear, readable, succinct documentation for a developer audience.
Next steps
Take a look at the documentation README for guidance on contributing to the Anchore OSS docs.
6 - Reference
Reference for Anchore OSS Tools
6.1 - Syft Command Line Reference
Note
This documentation was generated with Syft version 1.38.0.
Generate a packaged-based Software Bill Of Materials (SBOM) from container images and filesystems
Usage:
syft [SOURCE] [flags]
syft [command]
Examples:
syft scan alpine:latest a summary of discovered packages
syft scan alpine:latest -o json show all possible cataloging details
syft scan alpine:latest -o cyclonedx show a CycloneDX formatted SBOM
syft scan alpine:latest -o cyclonedx-json show a CycloneDX JSON formatted SBOM
syft scan alpine:latest -o spdx show a SPDX 2.3 Tag-Value formatted SBOM
syft scan alpine:latest -o spdx@2.2 show a SPDX 2.2 Tag-Value formatted SBOM
syft scan alpine:latest -o spdx-json show a SPDX 2.3 JSON formatted SBOM
syft scan alpine:latest -o spdx-json@2.2 show a SPDX 2.2 JSON formatted SBOM
syft scan alpine:latest -vv show verbose debug information
syft scan alpine:latest -o template -t my_format.tmpl show a SBOM formatted according to given template file
Supports the following image sources:
syft scan yourrepo/yourimage:tag defaults to using images from a Docker daemon. If Docker is not present, the image is pulled directly from the registry.
syft scan path/to/a/file/or/dir a Docker tar, OCI tar, OCI directory, SIF container, or generic filesystem directory
You can also explicitly specify the scheme to use:
syft scan docker:yourrepo/yourimage:tag explicitly use the Docker daemon
syft scan podman:yourrepo/yourimage:tag explicitly use the Podman daemon
syft scan registry:yourrepo/yourimage:tag pull image directly from a registry (no container runtime required)
syft scan docker-archive:path/to/yourimage.tar use a tarball from disk for archives created from "docker save" syft scan oci-archive:path/to/yourimage.tar use a tarball from disk for OCI archives (from Skopeo or otherwise)
syft scan oci-dir:path/to/yourimage read directly from a path on disk for OCI layout directories (from Skopeo or otherwise)
syft scan singularity:path/to/yourimage.sif read directly from a Singularity Image Format (SIF) container on disk
syft scan dir:path/to/yourproject read directly from a path on disk (any directory)
syft scan file:path/to/yourproject/file read directly from a path on disk (any single file)
Available Commands:
attest Generate an SBOM as an attestation for the given [SOURCE] container image
cataloger Show available catalogers and configuration
completion Generate the autocompletion script for the specified shell
config show the syft configuration
convert Convert between SBOM formats
help Help about any command
login Log in to a registry
scan Generate an SBOM
version show version information
Flags:
--base-path string base directory for scanning, no links will be followed above this directory, and all paths will be reported relative to this directory
-c, --config stringArray syft configuration file(s) to use
--enrich stringArray enable package data enrichment from local and online sources (options: all, golang, java, javascript, python)
--exclude stringArray exclude paths from being scanned using a glob expression
--file string file to write the default report output to (default is STDOUT) (DEPRECATED: use: --output FORMAT=PATH)
--from stringArray specify the source behavior to use (e.g. docker, registry, oci-dir, ...)
-h, --help help for syft
-o, --output stringArray report output format (<format>=<file> to output to a file), formats=[cyclonedx-json cyclonedx-xml github-json purls spdx-json spdx-tag-value syft-json syft-table syft-text template] (default [syft-table])
--override-default-catalogers stringArray set the base set of catalogers to use (defaults to 'image' or 'directory' depending on the scan source)
--parallelism int number of cataloger workers to run in parallel
--platform string an optional platform specifier for container image sources (e.g. 'linux/arm64', 'linux/arm64/v8', 'arm64', 'linux')
--profile stringArray configuration profiles to use
-q, --quiet suppress all logging output
-s, --scope string selection of layers to catalog, options=[squashed all-layers deep-squashed] (default"squashed")
--select-catalogers stringArray add, remove, and filter the catalogers to be used
--source-name string set the name of the target being analyzed
--source-supplier string the organization that supplied the component, which often may be the manufacturer, distributor, or repackager
--source-version string set the version of the target being analyzed
-t, --template string specify the path to a Go template file
-v, --verbose count increase verbosity (-v = info, -vv = debug)
--version version for syft
Use "syft [command] --help"for more information about a command.
syft attest
Generate a packaged-based Software Bill Of Materials (SBOM) from a container image as the predicate of an in-toto attestation that will be uploaded to the image registry.
Usage:
syft attest --output [FORMAT] <IMAGE> [flags]
Examples:
syft attest --output [FORMAT] alpine:latest defaults to using images from a Docker daemon. If Docker is not present, the image is pulled directly from the registry
You can also explicitly specify the scheme to use:
syft attest docker:yourrepo/yourimage:tag explicitly use the Docker daemon
syft attest podman:yourrepo/yourimage:tag explicitly use the Podman daemon
syft attest registry:yourrepo/yourimage:tag pull image directly from a registry (no container runtime required)
syft attest docker-archive:path/to/yourimage.tar use a tarball from disk for archives created from "docker save" syft attest oci-archive:path/to/yourimage.tar use a tarball from disk for OCI archives (from Skopeo or otherwise)
syft attest oci-dir:path/to/yourimage read directly from a path on disk for OCI layout directories (from Skopeo or otherwise)
syft attest singularity:path/to/yourimage.sif read directly from a Singularity Image Format (SIF) container on disk
Flags:
--base-path string base directory for scanning, no links will be followed above this directory, and all paths will be reported relative to this directory
--enrich stringArray enable package data enrichment from local and online sources (options: all, golang, java, javascript, python)
--exclude stringArray exclude paths from being scanned using a glob expression
--from stringArray specify the source behavior to use (e.g. docker, registry, oci-dir, ...)
-h, --help help for attest
-k, --key string the key to use for the attestation
-o, --output stringArray report output format (<format>=<file> to output to a file), formats=[cyclonedx-json cyclonedx-xml github-json purls spdx-json spdx-tag-value syft-json syft-table syft-text template] (default [syft-json])
--override-default-catalogers stringArray set the base set of catalogers to use (defaults to 'image' or 'directory' depending on the scan source)
--parallelism int number of cataloger workers to run in parallel
--platform string an optional platform specifier for container image sources (e.g. 'linux/arm64', 'linux/arm64/v8', 'arm64', 'linux')
-s, --scope string selection of layers to catalog, options=[squashed all-layers deep-squashed] (default"squashed")
--select-catalogers stringArray add, remove, and filter the catalogers to be used
--source-name string set the name of the target being analyzed
--source-supplier string the organization that supplied the component, which often may be the manufacturer, distributor, or repackager
--source-version string set the version of the target being analyzed
syft cataloger list
List available catalogers.
Usage:
syft cataloger list [OPTIONS] [flags]
Flags:
-h, --help help for list
-o, --output string format to output the cataloger list (available: table, json)
--override-default-catalogers stringArray override the default catalogers with an expression (default [all])
--select-catalogers stringArray select catalogers with an expression
-s, --show-hidden show catalogers that have been de-selected
syft config
Show the syft configuration.
Usage:
syft config [flags]
syft config [command]
Available Commands:
locations shows all locations and the order in which syft will look for a configuration file
Flags:
-h, --help help for config
--loadloadand validate the syft configuration
Usage:
syft convert [SOURCE-SBOM] -o [FORMAT] [flags]
Examples:
syft convert img.syft.json -o spdx-json convert a syft SBOM to spdx-json, output goes to stdout
syft convert img.syft.json -o cyclonedx-json=img.cdx.json convert a syft SBOM to CycloneDX, output is written to the file "img.cdx.json"
syft convert - -o spdx-json convert an SBOM from STDIN to spdx-json
Flags:
--file string file to write the default report output to (default is STDOUT) (DEPRECATED: use: --output FORMAT=PATH)
-h, --help help for convert
-o, --output stringArray report output format (<format>=<file> to output to a file), formats=[cyclonedx-json cyclonedx-xml github-json purls spdx-json spdx-tag-value syft-json syft-table syft-text template] (default [syft-table])
-t, --template string specify the path to a Go template file
syft login
Log in to a registry.
Usage:
syft login [OPTIONS] [SERVER] [flags]
Examples:
# Log in to reg.example.com
syft login reg.example.com -u AzureDiamond -p hunter2
Flags:
-h, --help help for login
-p, --password string Password
--password-stdin Take the password from stdin
-u, --username string Username
syft scan
Generate a packaged-based Software Bill Of Materials (SBOM) from container images and filesystems.
Usage:
syft scan [SOURCE] [flags]
Examples:
syft scan alpine:latest a summary of discovered packages
syft scan alpine:latest -o json show all possible cataloging details
syft scan alpine:latest -o cyclonedx show a CycloneDX formatted SBOM
syft scan alpine:latest -o cyclonedx-json show a CycloneDX JSON formatted SBOM
syft scan alpine:latest -o spdx show a SPDX 2.3 Tag-Value formatted SBOM
syft scan alpine:latest -o spdx@2.2 show a SPDX 2.2 Tag-Value formatted SBOM
syft scan alpine:latest -o spdx-json show a SPDX 2.3 JSON formatted SBOM
syft scan alpine:latest -o spdx-json@2.2 show a SPDX 2.2 JSON formatted SBOM
syft scan alpine:latest -vv show verbose debug information
syft scan alpine:latest -o template -t my_format.tmpl show a SBOM formatted according to given template file
Supports the following image sources:
syft scan yourrepo/yourimage:tag defaults to using images from a Docker daemon. If Docker is not present, the image is pulled directly from the registry.
syft scan path/to/a/file/or/dir a Docker tar, OCI tar, OCI directory, SIF container, or generic filesystem directory
You can also explicitly specify the scheme to use:
syft scan docker:yourrepo/yourimage:tag explicitly use the Docker daemon
syft scan podman:yourrepo/yourimage:tag explicitly use the Podman daemon
syft scan registry:yourrepo/yourimage:tag pull image directly from a registry (no container runtime required)
syft scan docker-archive:path/to/yourimage.tar use a tarball from disk for archives created from "docker save" syft scan oci-archive:path/to/yourimage.tar use a tarball from disk for OCI archives (from Skopeo or otherwise)
syft scan oci-dir:path/to/yourimage read directly from a path on disk for OCI layout directories (from Skopeo or otherwise)
syft scan singularity:path/to/yourimage.sif read directly from a Singularity Image Format (SIF) container on disk
syft scan dir:path/to/yourproject read directly from a path on disk (any directory)
syft scan file:path/to/yourproject/file read directly from a path on disk (any single file)
Flags:
--base-path string base directory for scanning, no links will be followed above this directory, and all paths will be reported relative to this directory
--enrich stringArray enable package data enrichment from local and online sources (options: all, golang, java, javascript, python)
--exclude stringArray exclude paths from being scanned using a glob expression
--file string file to write the default report output to (default is STDOUT) (DEPRECATED: use: --output FORMAT=PATH)
--from stringArray specify the source behavior to use (e.g. docker, registry, oci-dir, ...)
-h, --help help for scan
-o, --output stringArray report output format (<format>=<file> to output to a file), formats=[cyclonedx-json cyclonedx-xml github-json purls spdx-json spdx-tag-value syft-json syft-table syft-text template] (default [syft-table])
--override-default-catalogers stringArray set the base set of catalogers to use (defaults to 'image' or 'directory' depending on the scan source)
--parallelism int number of cataloger workers to run in parallel
--platform string an optional platform specifier for container image sources (e.g. 'linux/arm64', 'linux/arm64/v8', 'arm64', 'linux')
-s, --scope string selection of layers to catalog, options=[squashed all-layers deep-squashed] (default"squashed")
--select-catalogers stringArray add, remove, and filter the catalogers to be used
--source-name string set the name of the target being analyzed
--source-supplier string the organization that supplied the component, which often may be the manufacturer, distributor, or repackager
--source-version string set the version of the target being analyzed
-t, --template string specify the path to a Go template file
syft version
Show version information.
Usage:
syft version [flags]
Flags:
-h, --help help for version
-o, --output string the format to show the results (allowable: [text json]) (default "text")
6.2 - Syft Configuration Reference
Note
This documentation was generated with Syft version 1.38.0.
Syft searches for configuration files in the following locations, in order:
./.syft.yaml - current working directory
./.syft/config.yaml - app subdirectory in current working directory
The configuration file can use either .yaml or .yml extensions. The first configuration file found will be used.
For general information about how config and environment variables are handled, see the Configuration Reference section.
log:
# suppress all logging output (env: SYFT_LOG_QUIET)quiet: false# increase verbosity (-v = info, -vv = debug) (env: SYFT_LOG_VERBOSITY)verbosity: 0# explicitly set the logging level (available: [error warn info debug trace]) (env: SYFT_LOG_LEVEL)level: "warn"# file path to write logs to (env: SYFT_LOG_FILE)file: ""dev:
# capture resource profiling data (available: [cpu, mem]) (env: SYFT_DEV_PROFILE)profile: ""# the configuration file(s) used to load application configuration (env: SYFT_CONFIG)config: ""# the output format(s) of the SBOM report (options: syft-table, syft-text, syft-json, spdx-json, ...)# to specify multiple output files in differing formats, use a list:# output:# - "syft-json=<syft-json-output-file>"# - "spdx-json=<spdx-json-output-file>" (env: SYFT_OUTPUT)output:
- "syft-table"# file to write the default report output to (default is STDOUT) (env: SYFT_LEGACYFILE)legacyFile: ""format:
# default value for all formats that support the "pretty" option (default is unset) (env: SYFT_FORMAT_PRETTY)pretty:
template:
# path to the template file to use when rendering the output with the template output format.# Note that all template paths are based on the current syft-json schema (env: SYFT_FORMAT_TEMPLATE_PATH)path: ""# if true, uses the go structs for the syft-json format for templating.# if false, uses the syft-json output for templating (which follows the syft JSON schema exactly).## Note: long term support for this option is not guaranteed (it may change or break at any time) (env: SYFT_FORMAT_TEMPLATE_LEGACY)legacy: falsejson:
# transform any syft-json output to conform to an approximation of the v11.0.1 schema. This includes:# - using the package metadata type names from before v12 of the JSON schema (changed in https://github.com/anchore/syft/pull/1983)## Note: this will still include package types and fields that were added at or after json schema v12. This means# that output might not strictly be json schema v11 compliant, however, for consumers that require time to port# over to the final syft 1.0 json output this option can be used to ease the transition.## Note: long term support for this option is not guaranteed (it may change or break at any time) (env: SYFT_FORMAT_JSON_LEGACY)legacy: false# include space indentation and newlines# note: inherits default value from 'format.pretty' or 'false' if parent is unset (env: SYFT_FORMAT_JSON_PRETTY)pretty:
spdx-json:
# include space indentation and newlines# note: inherits default value from 'format.pretty' or 'false' if parent is unset (env: SYFT_FORMAT_SPDX_JSON_PRETTY)pretty:
cyclonedx-json:
# include space indentation and newlines# note: inherits default value from 'format.pretty' or 'false' if parent is unset (env: SYFT_FORMAT_CYCLONEDX_JSON_PRETTY)pretty:
cyclonedx-xml:
# include space indentation and newlines# note: inherits default value from 'format.pretty' or 'false' if parent is unset (env: SYFT_FORMAT_CYCLONEDX_XML_PRETTY)pretty:
# whether to check for an application update on start up or not (env: SYFT_CHECK_FOR_APP_UPDATE)check-for-app-update: true# enable one or more package catalogers (env: SYFT_CATALOGERS)catalogers: []
# set the base set of catalogers to use (defaults to 'image' or 'directory' depending on the scan source) (env: SYFT_DEFAULT_CATALOGERS)default-catalogers: []
# add, remove, and filter the catalogers to be used (env: SYFT_SELECT_CATALOGERS)select-catalogers: []
package:
# search within archives that do not contain a file index to search against (tar, tar.gz, tar.bz2, etc)# note: enabling this may result in a performance impact since all discovered compressed tars will be decompressed# note: for now this only applies to the java package cataloger (env: SYFT_PACKAGE_SEARCH_UNINDEXED_ARCHIVES)search-unindexed-archives: false# search within archives that do contain a file index to search against (zip)# note: for now this only applies to the java package cataloger (env: SYFT_PACKAGE_SEARCH_INDEXED_ARCHIVES)search-indexed-archives: true# allows users to exclude synthetic binary packages from the sbom# these packages are removed if an overlap with a non-synthetic package is found (env: SYFT_PACKAGE_EXCLUDE_BINARY_OVERLAP_BY_OWNERSHIP)exclude-binary-overlap-by-ownership: truelicense:
# include the content of licenses in the SBOM for a given syft scan; valid values are: [all unknown none] (env: SYFT_LICENSE_CONTENT)content: "none"# adjust the percent as a fraction of the total text, in normalized words, that# matches any valid license for the given inputs, expressed as a percentage across all of the licenses matched. (env: SYFT_LICENSE_COVERAGE)coverage: 75file:
metadata:
# select which files should be captured by the file-metadata cataloger and included in the SBOM.# Options include:# - "all": capture all files from the search space# - "owned-by-package": capture only files owned by packages# - "none", "": do not capture any files (env: SYFT_FILE_METADATA_SELECTION)selection: "owned-by-package"# the file digest algorithms to use when cataloging files (options: "md5", "sha1", "sha224", "sha256", "sha384", "sha512") (env: SYFT_FILE_METADATA_DIGESTS)digests:
- "sha1" - "sha256"content:
# skip searching a file entirely if it is above the given size (default = 1MB; unit = bytes) (env: SYFT_FILE_CONTENT_SKIP_FILES_ABOVE_SIZE)skip-files-above-size: 256000# file globs for the cataloger to match on (env: SYFT_FILE_CONTENT_GLOBS)globs: []
executable:
# file globs for the cataloger to match on (env: SYFT_FILE_EXECUTABLE_GLOBS)globs: []
# selection of layers to catalog, options=[squashed all-layers deep-squashed] (env: SYFT_SCOPE)scope: "squashed"# number of cataloger workers to run in parallel# by default, when set to 0: this will be based on runtime.NumCPU * 4, if set to less than 0 it will be unbounded (env: SYFT_PARALLELISM)parallelism: 0relationships:
# include package-to-file relationships that indicate which files are owned by which packages (env: SYFT_RELATIONSHIPS_PACKAGE_FILE_OWNERSHIP)package-file-ownership: true# include package-to-package relationships that indicate one package is owned by another due to files claimed to be owned by one package are also evidence of another package's existence (env: SYFT_RELATIONSHIPS_PACKAGE_FILE_OWNERSHIP_OVERLAP)package-file-ownership-overlap: truecompliance:
# action to take when a package is missing a name (env: SYFT_COMPLIANCE_MISSING_NAME)missing-name: "drop"# action to take when a package is missing a version (env: SYFT_COMPLIANCE_MISSING_VERSION)missing-version: "stub"# Enable data enrichment operations, which can utilize services such as Maven Central and NPM.# By default all enrichment is disabled, use: all to enable everything.# Available options are: all, golang, java, javascript, python (env: SYFT_ENRICH)enrich: []
dotnet:
# only keep dep.json packages which an executable on disk is found. The package is also included if a DLL is found for any child package, even if the package itself does not have a DLL. (env: SYFT_DOTNET_DEP_PACKAGES_MUST_HAVE_DLL)dep-packages-must-have-dll: false# only keep dep.json packages which have a runtime/resource DLL claimed in the deps.json targets section (but not necessarily found on disk). The package is also included if any child package claims a DLL, even if the package itself does not claim a DLL. (env: SYFT_DOTNET_DEP_PACKAGES_MUST_CLAIM_DLL)dep-packages-must-claim-dll: true# treat DLL claims or on-disk evidence for child packages as DLL claims or on-disk evidence for any parent package (env: SYFT_DOTNET_PROPAGATE_DLL_CLAIMS_TO_PARENTS)propagate-dll-claims-to-parents: true# show all packages from the deps.json if bundling tooling is present as a dependency (e.g. ILRepack) (env: SYFT_DOTNET_RELAX_DLL_CLAIMS_WHEN_BUNDLING_DETECTED)relax-dll-claims-when-bundling-detected: truegolang:
# search for go package licences in the GOPATH of the system running Syft, note that this is outside the# container filesystem and potentially outside the root of a local directory scan (env: SYFT_GOLANG_SEARCH_LOCAL_MOD_CACHE_LICENSES)search-local-mod-cache-licenses:
# specify an explicit go mod cache directory, if unset this defaults to $GOPATH/pkg/mod or $HOME/go/pkg/mod (env: SYFT_GOLANG_LOCAL_MOD_CACHE_DIR)local-mod-cache-dir: "~/go/pkg/mod"# search for go package licences in the vendor folder on the system running Syft, note that this is outside the# container filesystem and potentially outside the root of a local directory scan (env: SYFT_GOLANG_SEARCH_LOCAL_VENDOR_LICENSES)search-local-vendor-licenses:
# specify an explicit go vendor directory, if unset this defaults to ./vendor (env: SYFT_GOLANG_LOCAL_VENDOR_DIR)local-vendor-dir: ""# search for go package licences by retrieving the package from a network proxy (env: SYFT_GOLANG_SEARCH_REMOTE_LICENSES)search-remote-licenses:
# remote proxy to use when retrieving go packages from the network,# if unset this defaults to $GOPROXY followed by https://proxy.golang.org (env: SYFT_GOLANG_PROXY)proxy: "https://proxy.golang.org,direct"# specifies packages which should not be fetched by proxy# if unset this defaults to $GONOPROXY (env: SYFT_GOLANG_NO_PROXY)no-proxy: ""main-module-version:
# look for LD flags that appear to be setting a version (e.g. -X main.version=1.0.0) (env: SYFT_GOLANG_MAIN_MODULE_VERSION_FROM_LD_FLAGS)from-ld-flags: true# search for semver-like strings in the binary contents (env: SYFT_GOLANG_MAIN_MODULE_VERSION_FROM_CONTENTS)from-contents: false# use the build settings (e.g. vcs.version & vcs.time) to craft a v0 pseudo version# (e.g. v0.0.0-20220308212642-53e6d0aaf6fb) when a more accurate version cannot be found otherwise (env: SYFT_GOLANG_MAIN_MODULE_VERSION_FROM_BUILD_SETTINGS)from-build-settings: truejava:
# enables Syft to use the network to fetch version and license information for packages when# a parent or imported pom file is not found in the local maven repository.# the pom files are downloaded from the remote Maven repository at 'maven-url' (env: SYFT_JAVA_USE_NETWORK)use-network:
# use the local Maven repository to retrieve pom files. When Maven is installed and was previously used# for building the software that is being scanned, then most pom files will be available in this# repository on the local file system. this greatly speeds up scans. when all pom files are available# in the local repository, then 'use-network' is not needed.# TIP: If you want to download all required pom files to the local repository without running a full# build, run 'mvn help:effective-pom' before performing the scan with syft. (env: SYFT_JAVA_USE_MAVEN_LOCAL_REPOSITORY)use-maven-local-repository:
# override the default location of the local Maven repository.# the default is the subdirectory '.m2/repository' in your home directory (env: SYFT_JAVA_MAVEN_LOCAL_REPOSITORY_DIR)maven-local-repository-dir: "~/.m2/repository"# maven repository to use, defaults to Maven central (env: SYFT_JAVA_MAVEN_URL)maven-url: "https://repo1.maven.org/maven2"# depth to recursively resolve parent POMs, no limit if <= 0 (env: SYFT_JAVA_MAX_PARENT_RECURSIVE_DEPTH)max-parent-recursive-depth: 0# resolve transient dependencies such as those defined in a dependency's POM on Maven central (env: SYFT_JAVA_RESOLVE_TRANSITIVE_DEPENDENCIES)resolve-transitive-dependencies: falsejavascript:
# enables Syft to use the network to fill in more detailed license information (env: SYFT_JAVASCRIPT_SEARCH_REMOTE_LICENSES)search-remote-licenses:
# base NPM url to use (env: SYFT_JAVASCRIPT_NPM_BASE_URL)npm-base-url: ""# include development-scoped dependencies (env: SYFT_JAVASCRIPT_INCLUDE_DEV_DEPENDENCIES)include-dev-dependencies:
linux-kernel:
# whether to catalog linux kernel modules found within lib/modules/** directories (env: SYFT_LINUX_KERNEL_CATALOG_MODULES)catalog-modules: truenix:
# enumerate all files owned by packages found within Nix store paths (env: SYFT_NIX_CAPTURE_OWNED_FILES)capture-owned-files: falsepython:
# enables Syft to use the network to fill in more detailed license information (env: SYFT_PYTHON_SEARCH_REMOTE_LICENSES)search-remote-licenses:
# base Pypi url to use (env: SYFT_PYTHON_PYPI_BASE_URL)pypi-base-url: ""# when running across entries in requirements.txt that do not specify a specific version# (e.g. "sqlalchemy >= 1.0.0, <= 2.0.0, != 3.0.0, <= 3.0.0"), attempt to guess what the version could# be based on the version requirements specified (e.g. "1.0.0"). When enabled the lowest expressible version# when given an arbitrary constraint will be used (even if that version may not be available/published). (env: SYFT_PYTHON_GUESS_UNPINNED_REQUIREMENTS)guess-unpinned-requirements:
registry:
# skip TLS verification when communicating with the registry (env: SYFT_REGISTRY_INSECURE_SKIP_TLS_VERIFY)insecure-skip-tls-verify: false# use http instead of https when connecting to the registry (env: SYFT_REGISTRY_INSECURE_USE_HTTP)insecure-use-http: false# Authentication credentials for specific registries. Each entry describes authentication for a specific authority:# - authority: the registry authority URL the URL to the registry (e.g. "docker.io", "localhost:5000", etc.) (env: SYFT_REGISTRY_AUTH_AUTHORITY)# username: a username if using basic credentials (env: SYFT_REGISTRY_AUTH_USERNAME)# password: a corresponding password (env: SYFT_REGISTRY_AUTH_PASSWORD)# token: a token if using token-based authentication, mutually exclusive with username/password (env: SYFT_REGISTRY_AUTH_TOKEN)# tls-cert: filepath to the client certificate used for TLS authentication to the registry (env: SYFT_REGISTRY_AUTH_TLS_CERT)# tls-key: filepath to the client key used for TLS authentication to the registry (env: SYFT_REGISTRY_AUTH_TLS_KEY)auth: []
# filepath to a CA certificate (or directory containing *.crt, *.cert, *.pem) used to generate the client certificate (env: SYFT_REGISTRY_CA_CERT)ca-cert: ""# specify the source behavior to use (e.g. docker, registry, oci-dir, ...) (env: SYFT_FROM)from: []
# an optional platform specifier for container image sources (e.g. 'linux/arm64', 'linux/arm64/v8', 'arm64', 'linux') (env: SYFT_PLATFORM)platform: ""source:
# set the name of the target being analyzed (env: SYFT_SOURCE_NAME)name: ""# set the version of the target being analyzed (env: SYFT_SOURCE_VERSION)version: ""# the organization that supplied the component, which often may be the manufacturer, distributor, or repackager (env: SYFT_SOURCE_SUPPLIER)supplier: ""# (env: SYFT_SOURCE_SOURCE)source: ""# base directory for scanning, no links will be followed above this directory, and all paths will be reported relative to this directory (env: SYFT_SOURCE_BASE_PATH)base-path: ""file:
# the file digest algorithms to use on the scanned file (options: "md5", "sha1", "sha224", "sha256", "sha384", "sha512") (env: SYFT_SOURCE_FILE_DIGESTS)digests:
- "SHA-256"image:
# allows users to specify which image source should be used to generate the sbom# valid values are: registry, docker, podman (env: SYFT_SOURCE_IMAGE_DEFAULT_PULL_SOURCE)default-pull-source: ""# (env: SYFT_SOURCE_IMAGE_MAX_LAYER_SIZE)max-layer-size: ""# exclude paths from being scanned using a glob expression (env: SYFT_EXCLUDE)exclude: []
unknowns:
# remove unknown errors on files with discovered packages (env: SYFT_UNKNOWNS_REMOVE_WHEN_PACKAGES_DEFINED)remove-when-packages-defined: true# include executables without any identified packages (env: SYFT_UNKNOWNS_EXECUTABLES_WITHOUT_PACKAGES)executables-without-packages: true# include archives which were not expanded and searched (env: SYFT_UNKNOWNS_UNEXPANDED_ARCHIVES)unexpanded-archives: truecache:
# root directory to cache any downloaded content; empty string will use an in-memory cache (env: SYFT_CACHE_DIR)dir: "~/.cache/syft"# time to live for cached data; setting this to 0 will disable caching entirely (env: SYFT_CACHE_TTL)ttl: "7d"# show catalogers that have been de-selected (env: SYFT_SHOW_HIDDEN)show-hidden: falseattest:
# the key to use for the attestation (env: SYFT_ATTEST_KEY)key: ""# password to decrypt to given private key# additionally responds to COSIGN_PASSWORD env var (env: SYFT_ATTEST_PASSWORD)password: ""
6.3 - JSON Schema
6.3.1 - Syft v16 JSON Schema Reference
Complete reference for Syft JSON schema version 16.1.0
Document
Represents the syft cataloging findings as a JSON document
Contains the minimal information needed to describe how to find a file within any possible source object (e.g.
Field Name
Type
Description
path
str
RealPath is the canonical absolute form of the path accessed (all symbolic links have been followed and relative path components like '.' and '..' have been removed).
layerID
str
FileSystemID is an ID representing and entire filesystem. For container images, this is a layer digest. For directories or a root filesystem, this is blank.
Descriptor
Identifies the tool that generated this SBOM document, including its name, version, and configuration used during catalog generation.
Field Name
Type
Description
name
str
Name is the name of the tool that generated this SBOM (e.g., "syft").
version
str
Version is the version of the tool that generated this SBOM.
configuration
unknown
Configuration contains the tool configuration used during SBOM generation.
Digest
Represents a cryptographic hash of file contents.
Field Name
Type
Description
algorithm
str
Algorithm specifies the hash algorithm used (e.g., "sha256", "md5").
value
str
Value is the hexadecimal string representation of the hash.
ELFSecurityFeatures
Captures security hardening and protection mechanisms in ELF binaries.
Field Name
Type
Description
symbolTableStripped
bool
SymbolTableStripped indicates whether debugging symbols have been removed.
stackCanary
bool
StackCanary indicates whether stack smashing protection is enabled.
nx
bool
NoExecutable indicates whether NX (no-execute) protection is enabled for the stack.
relRO
str
RelocationReadOnly indicates the RELRO protection level.
pie
bool
PositionIndependentExecutable indicates whether the binary is compiled as PIE.
dso
bool
DynamicSharedObject indicates whether the binary is a shared library.
safeStack
bool
LlvmSafeStack represents a compiler-based security mechanism that separates the stack into a safe stack for storing return addresses and other critical data, and an unsafe stack for everything else, to mitigate stack-based memory corruption errors
see https://clang.llvm.org/docs/SafeStack.html
cfi
bool
ControlFlowIntegrity represents runtime checks to ensure a program's control flow adheres to the legal paths determined at compile time, thus protecting against various types of control-flow hijacking attacks
see https://clang.llvm.org/docs/ControlFlowIntegrity.html
fortify
bool
ClangFortifySource is a broad suite of extensions to libc aimed at catching misuses of common library functions
see https://android.googlesource.com/platform//bionic/+/d192dbecf0b2a371eb127c0871f77a9caf81c4d2/docs/clang_fortify_anatomy.md
Executable
Contains metadata about binary files and their security features.
Field Name
Type
Description
format
str
Format denotes either ELF, Mach-O, or PE
hasExports
bool
HasExports indicates whether the binary exports symbols.
hasEntrypoint
bool
HasEntrypoint indicates whether the binary has an entry point function.
importedLibraries
Array<str>
ImportedLibraries lists the shared libraries required by this executable.
Locations are file locations where this license was discovered.
contents
str
Contents is the full license text content.
LinuxKernelModuleParameter
Represents a configurable parameter for a kernel module with its type and description.
Field Name
Type
Description
type
str
Type is parameter data type (e.g. int, string, bool, array types)
description
str
Description is a human-readable parameter description explaining what the parameter controls
LinuxRelease
Contains Linux distribution identification and version information extracted from /etc/os-release or similar system files.
Field Name
Type
Description
prettyName
str
PrettyName is a human-readable operating system name with version.
name
str
Name is the operating system name without version information.
id
str
ID is the lower-case operating system identifier (e.g., "ubuntu", "rhel").
idLike
IDLikes
IDLike is a list of operating system IDs this distribution is similar to or derived from.
version
str
Version is the operating system version including codename if available.
versionID
str
VersionID is the operating system version number or identifier.
versionCodename
str
VersionCodename is the operating system release codename (e.g., "jammy", "bullseye").
buildID
str
BuildID is a build identifier for the operating system.
imageID
str
ImageID is an identifier for container or cloud images.
imageVersion
str
ImageVersion is the version for container or cloud images.
variant
str
Variant is the operating system variant name (e.g., "Server", "Workstation").
variantID
str
VariantID is the lower-case operating system variant identifier.
homeURL
str
HomeURL is the homepage URL for the operating system.
supportURL
str
SupportURL is the support or help URL for the operating system.
bugReportURL
str
BugReportURL is the bug reporting URL for the operating system.
privacyPolicyURL
str
PrivacyPolicyURL is the privacy policy URL for the operating system.
cpeName
str
CPEName is the Common Platform Enumeration name for the operating system.
supportEnd
str
SupportEnd is the end of support date or version identifier.
extendedSupport
bool
ExtendedSupport indicates whether extended security or support is available.
Location
Represents a path relative to a particular filesystem resolved to a specific file.Reference.
Field Name
Type
Description
path
str
RealPath is the canonical absolute form of the path accessed (all symbolic links have been followed and relative path components like '.' and '..' have been removed).
layerID
str
FileSystemID is an ID representing and entire filesystem. For container images, this is a layer digest. For directories or a root filesystem, this is blank.
accessPath
str
AccessPath is the path used to retrieve file contents (which may or may not have hardlinks / symlinks in the path)
annotations
obj
Package
Represents a pkg.Package object specialized for JSON marshaling and unmarshalling.
Represents all captured data from Bitnami packages described in Bitnami' SPDX files.
Field Name
Type
Description
name
str
Name is the package name as found in the Bitnami SPDX file
arch
str
Architecture is the target CPU architecture (amd64 or arm64 in Bitnami images)
distro
str
Distro is the distribution name this package is for (base OS like debian, ubuntu, etc.)
revision
str
Revision is the Bitnami-specific package revision number (incremented for Bitnami rebuilds of same upstream version)
version
str
Version is the package version as found in the Bitnami SPDX file
path
str
Path is the installation path in the filesystem where the package is located
files
Array<str>
Files are the file paths owned by this package (tracked via SPDX relationships)
CConanFileEntry
ConanfileEntry represents a single "Requires" entry from a conanfile.txt.
Field Name
Type
Description
ref
str
Ref is the package reference string in format name/version@user/channel
CConanInfoEntry
ConaninfoEntry represents a single "full_requires" entry from a conaninfo.txt.
Field Name
Type
Description
ref
str
Ref is the package reference string in format name/version@user/channel
package_id
str
PackageID is a unique package variant identifier
CConanLockEntry
ConanV1LockEntry represents a single "node" entry from a conan.lock V1 file.
Field Name
Type
Description
ref
str
Ref is the package reference string in format name/version@user/channel
package_id
str
PackageID is a unique package variant identifier computed from settings/options (static hash in Conan 1.x, can have collisions with complex dependency graphs)
prev
str
Prev is the previous lock entry reference for versioning
requires
Array<str>
Requires are the runtime package dependencies
build_requires
Array<str>
BuildRequires are the build-time dependencies (e.g. cmake, compilers)
py_requires
Array<str>
PythonRequires are the Python dependencies needed for Conan recipes
options
KeyValues
Options are package configuration options as key-value pairs (e.g. shared=True, fPIC=True)
path
str
Path is the filesystem path to the package in Conan cache
context
str
Context is the build context information
CConanLockV2Entry
ConanV2LockEntry represents a single "node" entry from a conan.lock V2 file.
Field Name
Type
Description
ref
str
Ref is the package reference string in format name/version@user/channel
packageID
str
PackageID is a unique package variant identifier (dynamic in Conan 2.0, more accurate than V1)
username
str
Username is the Conan user/organization name
channel
str
Channel is the Conan channel name indicating stability/purpose (e.g. stable, testing, experimental)
recipeRevision
str
RecipeRevision is a git-like revision hash (RREV) of the recipe
packageRevision
str
PackageRevision is a git-like revision hash of the built binary package
timestamp
str
TimeStamp is when this package was built/locked
CocoaPodfileLockEntry
Represents a single entry from the "Pods" section of a Podfile.lock file.
Field Name
Type
Description
checksum
str
Checksum is the SHA-1 hash of the podspec file for integrity verification (generated via `pod ipc spec ... | openssl sha1`), ensuring all team members use the same pod specification version
CondaMetadataEntry
CondaMetaPackage represents metadata for a Conda package extracted from the conda-meta/*.json files.
Field Name
Type
Description
arch
str
Arch is the target CPU architecture for the package (e.g., "arm64", "x86_64").
name
str
Name is the package name as found in the conda-meta JSON file.
version
str
Version is the package version as found in the conda-meta JSON file.
build
str
Build is the build string identifier (e.g., "h90dfc92_1014").
build_number
int
BuildNumber is the sequential build number for this version.
channel
str
Channel is the Conda channel URL where the package was retrieved from.
subdir
str
Subdir is the subdirectory within the channel (e.g., "osx-arm64", "linux-64").
noarch
str
Noarch indicates if the package is platform-independent (e.g., "python", "generic").
license
str
License is the package license identifier.
license_family
str
LicenseFamily is the general license category (e.g., "MIT", "Apache", "GPL").
md5
str
MD5 is the MD5 hash of the package archive.
sha256
str
SHA256 is the SHA-256 hash of the package archive.
size
int
Size is the package archive size in bytes.
timestamp
int
Timestamp is the Unix timestamp when the package was built.
fn
str
Filename is the original package archive filename (e.g., "zlib-1.2.11-h90dfc92_1014.tar.bz2").
url
str
URL is the full download URL for the package archive.
extracted_package_dir
str
ExtractedPackageDir is the local cache directory where the package was extracted.
depends
Array<str>
Depends is the list of runtime dependencies with version constraints.
files
Array<str>
Files is the list of files installed by this package.
Environment is SDK version constraints for Dart and Flutter
platforms
Array<str>
Platforms are the supported platforms (Android, iOS, web, etc.)
ignored_advisories
Array<str>
IgnoredAdvisories are the security advisories to explicitly ignore for this package
DartPubspecEnvironment
Represents SDK version constraints from the environment section of pubspec.yaml.
Field Name
Type
Description
sdk
str
SDK is the Dart SDK version constraint (e.g. ">=2.12.0 <3.0.0")
flutter
str
Flutter is the Flutter SDK version constraint if this is a Flutter package
DartPubspecLockEntry
Is a struct that represents a single entry found in the "packages" section in a Dart pubspec.lock file.
Field Name
Type
Description
name
str
Name is the package name as found in the pubspec.lock file
version
str
Version is the package version as found in the pubspec.lock file
hosted_url
str
HostedURL is the URL of the package repository for hosted packages (typically pub.dev, but can be custom repository identified by hosted-url). When PUB_HOSTED_URL environment variable changes, lockfile tracks the source.
vcs_url
str
VcsURL is the URL of the VCS repository for git/path dependencies (for packages fetched from version control systems like Git)
DotnetDepsEntry
Is a struct that represents a single entry found in the "libraries" section in a .NET [*.]deps.json file.
Field Name
Type
Description
name
str
Name is the package name as found in the deps.json file
version
str
Version is the package version as found in the deps.json file
path
str
Path is the relative path to the package within the deps structure (e.g. "app.metrics/3.0.0")
sha512
str
Sha512 is the SHA-512 hash of the NuGet package content WITHOUT the signed content for verification (won't match hash from NuGet API or manual calculation of .nupkg file)
hashPath
str
HashPath is the relative path to the .nupkg.sha512 hash file (e.g. "app.metrics.3.0.0.nupkg.sha512")
executables
obj
Executables are the map of .NET Portable Executable files within this package with their version resources
DotnetPackagesLockEntry
Is a struct that represents a single entry found in the "dependencies" section in a .NET packages.lock.json file.
Field Name
Type
Description
name
str
Name is the package name as found in the packages.lock.json file
version
str
Version is the package version as found in the packages.lock.json file
contentHash
str
ContentHash is the hash of the package content for verification
type
str
Type is the dependency type indicating how this dependency was added (Direct=explicit in project file, Transitive=pulled in by another package, Project=project reference)
DotnetPortableExecutableEntry
Is a struct that represents a single entry found within "VersionResources" section of a .NET Portable Executable binary file.
Field Name
Type
Description
assemblyVersion
str
AssemblyVersion is the .NET assembly version number (strong-named version)
legalCopyright
str
LegalCopyright is the copyright notice string
comments
str
Comments are additional comments or description embedded in PE resources
internalName
str
InternalName is the internal name of the file
companyName
str
CompanyName is the company that produced the file
productName
str
ProductName is the name of the product this file is part of
productVersion
str
ProductVersion is the version of the product (may differ from AssemblyVersion)
DpkgArchiveEntry
Represents package metadata extracted from a .deb archive file.
Field Name
Type
Description
package
str
Package is the package name as found in the status file
source
str
Source is the source package name this binary was built from (one source can produce multiple binary packages)
version
str
Version is the binary package version as found in the status file
sourceVersion
str
SourceVersion is the source package version (may differ from binary version when binNMU rebuilds occur)
architecture
str
Architecture is the target architecture per Debian spec (specific arch like amd64/arm64, wildcard like any, architecture-independent "all", or "source" for source packages)
maintainer
str
Maintainer is the package maintainer's name and email in RFC822 format (name must come first, then email in angle brackets)
installedSize
int
InstalledSize is the total size of installed files in kilobytes
provides
Array<str>
Provides are the virtual packages provided by this package (allows other packages to depend on capabilities. Can include versioned provides like "libdigest-md5-perl (= 2.55.01)")
depends
Array<str>
Depends are the packages required for this package to function (will not be installed unless these requirements are met, creates strict ordering constraint)
preDepends
Array<str>
PreDepends are the packages that must be installed and configured BEFORE even starting installation of this package (stronger than Depends, discouraged unless absolutely necessary as it adds strict constraints for apt)
Digest is the file content hash (typically MD5 for dpkg compatibility with legacy systems)
isConfigFile
bool
IsConfigFile is whether this file is marked as a configuration file (dpkg will preserve user modifications during upgrades)
DpkgDbEntry
Represents all captured data for a Debian package DB entry; available fields are described at http://manpages.ubuntu.com/manpages/xenial/man1/dpkg-query.1.html in the --showformat section.
Field Name
Type
Description
package
str
Package is the package name as found in the status file
source
str
Source is the source package name this binary was built from (one source can produce multiple binary packages)
version
str
Version is the binary package version as found in the status file
sourceVersion
str
SourceVersion is the source package version (may differ from binary version when binNMU rebuilds occur)
architecture
str
Architecture is the target architecture per Debian spec (specific arch like amd64/arm64, wildcard like any, architecture-independent "all", or "source" for source packages)
maintainer
str
Maintainer is the package maintainer's name and email in RFC822 format (name must come first, then email in angle brackets)
installedSize
int
InstalledSize is the total size of installed files in kilobytes
provides
Array<str>
Provides are the virtual packages provided by this package (allows other packages to depend on capabilities. Can include versioned provides like "libdigest-md5-perl (= 2.55.01)")
depends
Array<str>
Depends are the packages required for this package to function (will not be installed unless these requirements are met, creates strict ordering constraint)
preDepends
Array<str>
PreDepends are the packages that must be installed and configured BEFORE even starting installation of this package (stronger than Depends, discouraged unless absolutely necessary as it adds strict constraints for apt)
Digest is the file content hash (typically MD5 for dpkg compatibility with legacy systems)
isConfigFile
bool
IsConfigFile is whether this file is marked as a configuration file (dpkg will preserve user modifications during upgrades)
ElfBinaryPackageNoteJsonPayload
Represents metadata captured from the .note.package section of an ELF-formatted binary
Field Name
Type
Description
type
str
Type is the type of the package (e.g. "rpm", "deb", "apk", etc.)
architecture
str
Architecture of the binary package (e.g. "amd64", "arm", etc.)
osCPE
str
OSCPE is a CPE name for the OS, typically corresponding to CPE_NAME in os-release (e.g. cpe:/o:fedoraproject:fedora:33)
os
str
OS is the OS name, typically corresponding to ID in os-release (e.g. "fedora")
osVersion
str
osVersion is the version of the OS, typically corresponding to VERSION_ID in os-release (e.g. "33")
system
str
System is a context-specific name for the system that the binary package is intended to run on or a part of
vendor
str
Vendor is the individual or organization that produced the source code for the binary
sourceRepo
str
SourceRepo is the URL to the source repository for which the binary was built from
commit
str
Commit is the commit hash of the source repository for which the binary was built from
ElixirMixLockEntry
Is a struct that represents a single entry in a mix.lock file
Field Name
Type
Description
name
str
Name is the package name as found in the mix.lock file
version
str
Version is the package version as found in the mix.lock file
pkgHash
str
PkgHash is the outer checksum (SHA-256) of the entire Hex package tarball for integrity verification (preferred method, replaces deprecated inner checksum)
pkgHashExt
str
PkgHashExt is the extended package hash format (inner checksum is deprecated - SHA-256 of concatenated file contents excluding CHECKSUM file, now replaced by outer checksum)
ErlangRebarLockEntry
Represents a single package entry from the "deps" section within an Erlang rebar.lock file.
Field Name
Type
Description
name
str
Name is the package name as found in the rebar.lock file
version
str
Version is the package version as found in the rebar.lock file
pkgHash
str
PkgHash is the outer checksum (SHA-256) of the entire Hex package tarball for integrity verification (preferred method over deprecated inner checksum)
pkgHashExt
str
PkgHashExt is the extended package hash format (inner checksum deprecated - was SHA-256 of concatenated file contents)
GgufFileHeader
Represents metadata extracted from a GGUF (GPT-Generated Unified Format) model file.
Field Name
Type
Description
ggufVersion
int
GGUFVersion is the GGUF format version (e.g., 3)
fileSize
int
FileSize is the size of the GGUF file in bytes (best-effort if available from resolver)
architecture
str
Architecture is the model architecture (from general.architecture, e.g., "qwen3moe", "llama")
quantization
str
Quantization is the quantization type (e.g., "IQ4_NL", "Q4_K_M")
parameters
int
Parameters is the number of model parameters (if present in header)
tensorCount
int
TensorCount is the number of tensors in the model
header
obj
RemainingKeyValues contains the remaining key-value pairs from the GGUF header that are not already
represented as typed fields above. This preserves additional metadata fields for reference
(namespaced with general.*, llama.*, etc.) while avoiding duplication.
metadataHash
str
MetadataKeyValuesHash is a xx64 hash of all key-value pairs from the GGUF header metadata.
This hash is computed over the complete header metadata (including the fields extracted
into typed fields above) and provides a stable identifier for the model configuration
across different file locations or remotes. It allows matching identical models even
when stored in different repositories or with different filenames.
GithubActionsUseStatement
Represents a single 'uses' statement in a GitHub Actions workflow file referencing an action or reusable workflow.
Field Name
Type
Description
value
str
Value is the action reference (e.g. "actions/checkout@v3")
comment
str
Comment is the inline comment associated with this uses statement
GoModuleBuildinfoEntry
GolangBinaryBuildinfoEntry represents all captured data for a Golang binary
Field Name
Type
Description
goBuildSettings
KeyValues
BuildSettings contains the Go build settings and flags used to compile the binary (e.g., GOARCH, GOOS, CGO_ENABLED).
goCompiledVersion
str
GoCompiledVersion is the version of Go used to compile the binary.
architecture
str
Architecture is the target CPU architecture for the binary (extracted from GOARCH build setting).
h1Digest
str
H1Digest is the Go module hash in h1: format for the main module from go.sum.
mainModule
str
MainModule is the main module path for the binary (e.g., "github.com/anchore/syft").
goCryptoSettings
Array<str>
GoCryptoSettings contains FIPS and cryptographic configuration settings if present.
goExperiments
Array<str>
GoExperiments lists experimental Go features enabled during compilation (e.g., "arenas", "cgocheck2").
GoModuleEntry
GolangModuleEntry represents all captured data for a Golang source scan with go.mod/go.sum
Field Name
Type
Description
h1Digest
str
H1Digest is the Go module hash in h1: format from go.sum for verifying module contents.
GoSourceEntry
GolangSourceEntry represents all captured data for a Golang package found through source analysis
Field Name
Type
Description
h1Digest
str
H1Digest is the Go module hash in h1: format from go.sum for verifying module contents.
os
str
OperatingSystem is the target OS for build constraints (e.g., "linux", "darwin", "windows").
architecture
str
Architecture is the target CPU architecture for build constraints (e.g., "amd64", "arm64").
buildTags
str
BuildTags are the build tags used to conditionally compile code (e.g., "integration,debug").
cgoEnabled
bool
CgoEnabled indicates whether CGO was enabled for this package.
HaskellHackageStackEntry
HackageStackYamlEntry represents a single entry from the "extra-deps" section of a stack.yaml file.
Field Name
Type
Description
pkgHash
str
PkgHash is the package content hash for verification
HaskellHackageStackLockEntry
HackageStackYamlLockEntry represents a single entry from the "packages" section of a stack.yaml.lock file.
Field Name
Type
Description
pkgHash
str
PkgHash is the package content hash for verification
snapshotURL
str
SnapshotURL is the URL to the Stack snapshot this package came from
HomebrewFormula
Represents metadata about a Homebrew formula package extracted from formula JSON files.
Field Name
Type
Description
tap
str
Tap is Homebrew tap this formula belongs to (e.g. "homebrew/core")
homepage
str
Homepage is the upstream project homepage URL
description
str
Description is a human-readable formula description
JavaArchive
Encapsulates all Java ecosystem metadata for a package as well as an (optional) parent relationship.
Field Name
Type
Description
virtualPath
str
VirtualPath is path within the archive hierarchy, where nested entries are delimited with ':' (for nested JARs)
Parent is the parent POM reference for inheritance (child POMs inherit configuration from parent)
groupId
str
GroupID is Maven group identifier (reversed domain name like org.apache.maven)
artifactId
str
ArtifactID is Maven artifact identifier (project name)
version
str
Version is project version (together with groupId and artifactId forms Maven coordinates groupId:artifactId:version)
name
str
Name is a human-readable project name (displayed in Maven-generated documentation)
description
str
Description is detailed project description
url
str
URL is the project URL (typically project website or repository)
JavaPomProperties
Represents the fields of interest extracted from a Java archive's pom.properties file.
Field Name
Type
Description
path
str
Path is path to the pom.properties file within the archive
name
str
Name is the project name
groupId
str
GroupID is Maven group identifier uniquely identifying the project across all projects (follows reversed domain name convention like com.company.project)
artifactId
str
ArtifactID is Maven artifact identifier, the name of the jar/artifact (unique within the groupId scope)
version
str
Version is artifact version
scope
str
Scope is dependency scope determining when dependency is available (compile=default all phases, test=test compilation/execution only, runtime=runtime and test not compile, provided=expected from JDK or container)
extraFields
obj
Extra is additional custom properties not in standard Maven coordinates
JavaJvmInstallation
JavaVMInstallation represents a Java Virtual Machine installation discovered on the system with its release information and file list.
Release is JVM release information and version details
files
Array<str>
Files are the list of files that are part of this JVM installation
JavaVMRelease
Represents JVM version and build information extracted from the release file in a Java installation.
Field Name
Type
Description
implementor
str
Implementor is extracted with the `java.vendor` JVM property
implementorVersion
str
ImplementorVersion is extracted with the `java.vendor.version` JVM property
javaRuntimeVersion
str
JavaRuntimeVersion is extracted from the 'java.runtime.version' JVM property
javaVersion
str
JavaVersion matches that from `java -version` command output
javaVersionDate
str
JavaVersionDate is extracted from the 'java.version.date' JVM property
libc
str
Libc can either be 'glibc' or 'musl'
modules
Array<str>
Modules is a list of JVM modules that are packaged
osArch
str
OsArch is the target CPU architecture
osName
str
OsName is the name of the target runtime operating system environment
osVersion
str
OsVersion is the version of the target runtime operating system environment
source
str
Source refers to the origin repository of OpenJDK source
buildSource
str
BuildSource Git SHA of the build repository
buildSourceRepo
str
BuildSourceRepo refers to rhe repository URL for the build source
sourceRepo
str
SourceRepo refers to the OpenJDK repository URL
fullVersion
str
FullVersion is extracted from the 'java.runtime.version' JVM property
semanticVersion
str
SemanticVersion is derived from the OpenJDK version
buildInfo
str
BuildInfo contains additional build information
jvmVariant
str
JvmVariant specifies the JVM variant (e.g., Hotspot or OpenJ9)
jvmVersion
str
JvmVersion is extracted from the 'java.vm.version' JVM property
imageType
str
ImageType can be 'JDK' or 'JRE'
buildType
str
BuildType can be 'commercial' (used in some older oracle JDK distributions)
JavascriptNpmPackage
NpmPackage represents the contents of a javascript package.json file.
Field Name
Type
Description
name
str
Name is the package name as found in package.json
version
str
Version is the package version as found in package.json
author
str
Author is package author name
homepage
str
Homepage is project homepage URL
description
str
Description is a human-readable package description
url
str
URL is repository or project URL
private
bool
Private is whether this is a private package
JavascriptNpmPackageLockEntry
NpmPackageLockEntry represents a single entry within the "packages" section of a package-lock.json file.
Field Name
Type
Description
resolved
str
Resolved is URL where this package was downloaded from (registry source)
integrity
str
Integrity is Subresource Integrity hash for verification using standard SRI format (sha512-... or sha1-...). npm changed from SHA-1 to SHA-512 in newer versions. For registry sources this is the integrity from registry, for remote tarballs it's SHA-512 of the file. npm verifies tarball matches this hash before unpacking, throwing EINTEGRITY error if mismatch detected.
dependencies
obj
Dependencies is a map of dependencies and their version markers, i.e. "lodash": "^1.0.0"
JavascriptPnpmLockEntry
PnpmLockEntry represents a single entry in the "packages" section of a pnpm-lock.yaml file.
Resolution is the resolution information for the package
dependencies
obj
Dependencies is a map of dependencies and their versions
JavascriptYarnLockEntry
YarnLockEntry represents a single entry section of a yarn.lock file.
Field Name
Type
Description
resolved
str
Resolved is URL where this package was downloaded from
integrity
str
Integrity is Subresource Integrity hash for verification (SRI format)
dependencies
obj
Dependencies is a map of dependencies and their versions
LinuxKernelArchive
LinuxKernel represents all captured data for a Linux kernel
Field Name
Type
Description
name
str
Name is kernel name (typically "Linux")
architecture
str
Architecture is the target CPU architecture
version
str
Version is kernel version string
extendedVersion
str
ExtendedVersion is additional version information
buildTime
str
BuildTime is when the kernel was built
author
str
Author is who built the kernel
format
str
Format is kernel image format (e.g. bzImage, zImage)
rwRootFS
bool
RWRootFS is whether root filesystem is mounted read-write
swapDevice
int
SwapDevice is swap device number
rootDevice
int
RootDevice is root device number
videoMode
str
VideoMode is default video mode setting
LinuxKernelModule
Represents a loadable kernel module (.ko file) with its metadata, parameters, and dependencies.
Field Name
Type
Description
name
str
Name is module name
version
str
Version is module version string
sourceVersion
str
SourceVersion is the source code version identifier
path
str
Path is the filesystem path to the .ko kernel object file (absolute path)
description
str
Description is a human-readable module description
author
str
Author is module author name and email
license
str
License is module license (e.g. GPL, BSD) which must be compatible with kernel
kernelVersion
str
KernelVersion is kernel version this module was built for
versionMagic
str
VersionMagic is version magic string for compatibility checking (includes kernel version, SMP status, module loading capabilities like "3.17.4-302.fc21.x86_64 SMP mod_unload modversions"). Module will NOT load if vermagic doesn't match running kernel.
parameters
obj
Parameters are the module parameters that can be configured at load time (user-settable values like module options)
LuarocksPackage
Represents a Lua package managed by the LuaRocks package manager with metadata from .rockspec files.
Field Name
Type
Description
name
str
Name is the package name as found in the .rockspec file
version
str
Version is the package version as found in the .rockspec file
license
str
License is license identifier
homepage
str
Homepage is project homepage URL
description
str
Description is a human-readable package description
url
str
URL is the source download URL
dependencies
obj
Dependencies are the map of dependency names to version constraints
NixStoreEntry
Represents a package in the Nix store (/nix/store) with its derivation information and metadata.
Field Name
Type
Description
path
str
Path is full store path for this output (e.g. /nix/store/abc123...-package-1.0)
output
str
Output is the specific output name for multi-output packages (empty string for default "out" output, can be "bin", "dev", "doc", etc.)
outputHash
str
OutputHash is hash prefix of the store path basename (first part before the dash)
Derivation is information about the .drv file that describes how this package was built
files
Array<str>
Files are the list of files under the nix/store path for this package
NixDerivation
Represents a Nix .drv file that describes how to build a package including inputs, outputs, and build instructions.
Field Name
Type
Description
path
str
Path is path to the .drv file in Nix store
system
str
System is target system string indicating where derivation can be built (e.g. "x86_64-linux", "aarch64-darwin"). Must match current system for local builds.
Source is the source repository information for development (typically git repo, used when passing --prefer-source). Originates from source code repository.
Source is the source repository information for development (typically git repo, used when passing --prefer-source). Originates from source code repository.
Digest is file content hash (MD5 for regular files in CONTENTS format: "obj filename md5hash mtime")
PythonPackage
Represents all captured data for a python egg or wheel package (specifically as outlined in the PyPA core metadata specification https://packaging.python.org/en/latest/specifications/core-metadata/).
Field Name
Type
Description
name
str
Name is the package name from the Name field in PKG-INFO or METADATA.
version
str
Version is the package version from the Version field in PKG-INFO or METADATA.
author
str
Author is the package author name from the Author field.
authorEmail
str
AuthorEmail is the package author's email address from the Author-Email field.
platform
str
Platform indicates the target platform for the package (e.g., "any", "linux", "win32").
Digest contains the hash algorithm and value for file integrity verification.
userName
str
UserName is the owner username for the file.
groupName
str
GroupName is the group name for the file.
flags
str
Flags indicates the file type (e.g., "%config", "%doc", "%ghost").
RpmSignature
Represents a GPG signature for an RPM package used for authenticity verification.
Field Name
Type
Description
algo
str
PublicKeyAlgorithm is the public key algorithm used for signing (e.g., "RSA").
hash
str
HashAlgorithm is the hash algorithm used for the signature (e.g., "SHA256").
created
str
Created is the timestamp when the signature was created.
issuer
str
IssuerKeyID is the GPG key ID that created the signature.
RubyGemspec
Represents all metadata parsed from the *.gemspec file
Field Name
Type
Description
name
str
Name is gem name as specified in the gemspec
version
str
Version is gem version as specified in the gemspec
files
Array<str>
Files is logical list of files in the gem (NOT directly usable as filesystem paths. Example: bundler gem lists "lib/bundler/vendor/uri/lib/uri/ldap.rb" but actual path is "/usr/local/lib/ruby/3.2.0/bundler/vendor/uri/lib/uri/ldap.rb". Would need gem installation path, ruby version, and env vars like GEM_HOME to resolve actual paths.)
authors
Array<str>
Authors are the list of gem authors (stored as array regardless of using `author` or `authors` method in gemspec)
homepage
str
Homepage is project homepage URL
RustCargoAuditEntry
RustBinaryAuditEntry represents Rust crate metadata extracted from a compiled binary using cargo-auditable format.
Field Name
Type
Description
name
str
Name is crate name as specified in audit section of the build binary
version
str
Version is crate version as specified in audit section of the build binary
source
str
Source is the source registry or repository where this crate came from
RustCargoLockEntry
Represents a locked dependency from a Cargo.lock file with precise version and checksum information.
Field Name
Type
Description
name
str
Name is crate name as specified in Cargo.toml
version
str
Version is crate version as specified in Cargo.toml
source
str
Source is the source registry or repository URL in format "registry+https://github.com/rust-lang/crates.io-index" for registry packages
checksum
str
Checksum is content checksum for registry packages only (hexadecimal string). Cargo doesn't require or include checksums for git dependencies. Used to detect MITM attacks by verifying downloaded crate matches lockfile checksum.
dependencies
Array<str>
Dependencies are the list of dependencies with version constraints
SnapEntry
Represents metadata for a Snap package extracted from snap.yaml or snapcraft.yaml files.
Field Name
Type
Description
snapType
str
SnapType indicates the snap type (base, kernel, app, gadget, or snapd).
base
str
Base is the base snap name that this snap depends on (e.g., "core20", "core22").
snapName
str
SnapName is the snap package name.
snapVersion
str
SnapVersion is the snap package version.
architecture
str
Architecture is the target CPU architecture (e.g., "amd64", "arm64").
SwiftPackageManagerLockEntry
SwiftPackageManagerResolvedEntry represents a resolved dependency from a Package.resolved file with its locked version and source location.
Field Name
Type
Description
revision
str
Revision is git commit hash of the resolved package
SwiplpackPackage
SwiplPackEntry represents a SWI-Prolog package from the pack system with metadata about the package and its dependencies.
Field Name
Type
Description
name
str
Name is the package name as found in the .toml file
version
str
Version is the package version as found in the .toml file
author
str
Author is author name
authorEmail
str
AuthorEmail is author email address
packager
str
Packager is packager name (if different from author)
packagerEmail
str
PackagerEmail is packager email address
homepage
str
Homepage is project homepage URL
dependencies
Array<str>
Dependencies are the list of required dependencies
TerraformLockProviderEntry
Represents a single provider entry in a Terraform dependency lock file (.terraform.lock.hcl).
Field Name
Type
Description
url
str
URL is the provider source address (e.g., "registry.terraform.io/hashicorp/aws").
constraints
str
Constraints specifies the version constraints for the provider (e.g., "~> 4.0").
version
str
Version is the locked provider version selected during terraform init.
hashes
Array<str>
Hashes are cryptographic checksums for the provider plugin archives across different platforms.
WordpressPluginEntry
Represents all metadata parsed from the wordpress plugin file
Field Name
Type
Description
pluginInstallDirectory
str
PluginInstallDirectory is directory name where the plugin is installed
author
str
Author is plugin author name
authorUri
str
AuthorURI is author's website URL
6.4 - Grype Command Line Reference
Note
This documentation was generated with Grype version 0.104.0.
A vulnerability scanner for container images, filesystems, and SBOMs.
Supports the following image sources:
grype yourrepo/yourimage:tag defaults to using images from a Docker daemon
grype path/to/yourproject a Docker tar, OCI tar, OCI directory, SIF container, or generic filesystem directory
You can also explicitly specify the scheme to use:
grype podman:yourrepo/yourimage:tag explicitly use the Podman daemon
grype docker:yourrepo/yourimage:tag explicitly use the Docker daemon
grype docker-archive:path/to/yourimage.tar use a tarball from disk for archives created from "docker save" grype oci-archive:path/to/yourimage.tar use a tarball from disk for OCI archives (from Podman or otherwise)
grype oci-dir:path/to/yourimage read directly from a path on disk for OCI layout directories (from Skopeo or otherwise)
grype singularity:path/to/yourimage.sif read directly from a Singularity Image Format (SIF) container on disk
grype dir:path/to/yourproject read directly from a path on disk (any directory)
grype file:path/to/yourfile read directly from a file on disk
grype sbom:path/to/syft.json read Syft JSON from path on disk
grype registry:yourrepo/yourimage:tag pull image directly from a registry (no container runtime required)
grype purl:path/to/purl/file read a newline separated file of package URLs from a path on disk
grype PURL read a single package PURL directly (e.g. pkg:apk/openssl@3.2.1?distro=alpine-3.20.3)
grype CPE read a single CPE directly (e.g. cpe:2.3:a:openssl:openssl:3.0.14:*:*:*:*:*)
You can also pipe in Syft JSON directly:
syft yourimage:tag -o json | grype
Usage:
grype [IMAGE] [flags]
grype [command]
Available Commands:
completion Generate a shell completion forGrype (listing local docker images)
config show the grype configuration
db vulnerability database operations
explain Ask grype to explain a set of findings
help Help about any command
version show version information
Flags:
--add-cpes-if-none generate CPEs for packages with no CPE data
--by-cve orient results by CVE instead of the original vulnerability ID when possible
-c, --config stringArray grype configuration file(s) to use
--distro string distro to match against in the format: <distro>[-:@]<version>
--exclude stringArray exclude paths from being scanned using a glob expression
-f, --fail-on string set the return code to 1if a vulnerability is found with a severity >= the given severity, options=[negligible low medium high critical]
--file string file to write the default report output to (default is STDOUT)
--from stringArray specify the source behavior to use (e.g. docker, registry, podman, oci-dir, ...)
-h, --help help for grype
--ignore-states string ignore matches for vulnerabilities with specified comma separated fix states, options=[fixed not-fixed unknown wont-fix]
--name string set the name of the target being analyzed
--only-fixed ignore matches for vulnerabilities that are not fixed
--only-notfixed ignore matches for vulnerabilities that are fixed
-o, --output stringArray report output formatter, formats=[json table cyclonedx cyclonedx-json sarif template], deprecated formats=[embedded-cyclonedx-vex-json embedded-cyclonedx-vex-xml]
--platform string an optional platform specifier for container image sources (e.g. 'linux/arm64', 'linux/arm64/v8', 'arm64', 'linux')
--profile stringArray configuration profiles to use
-q, --quiet suppress all logging output
-s, --scope string selection of layers to analyze, options=[squashed all-layers deep-squashed] (default"squashed")
--show-suppressed show suppressed/ignored vulnerabilities in the output (only supported with table output format)
--sort-by string sort the match results with the given strategy, options=[package severity epss risk kev vulnerability] (default"risk")
-t, --template string specify the path to a Go template file (requires 'template' output to be selected)
-v, --verbose count increase verbosity (-v = info, -vv = debug)
--version version for grype
--vex stringArray a list of VEX documents to consider when producing scanning results
Use "grype [command] --help"for more information about a command.
grype config
Show the grype configuration.
Usage:
grype config [flags]
grype config [command]
Available Commands:
locations shows all locations and the order in which grype will look for a configuration file
Flags:
-h, --help help for config
--loadloadand validate the grype configuration
grype db check
Check to see if there is a database update available.
Usage:
grype db check [flags]
Flags:
-h, --help help for check
-o, --output string format to display results (available=[text, json]) (default "text")
grype db delete
Delete the vulnerability database.
Usage:
grype db delete [flags]
Flags:
-h, --help help for delete
grype db import
Import a vulnerability database archive from a local FILE or URL.
DB archives can be obtained from “https://grype.anchore.io/databases" (or running db list). If the URL has a checksum query parameter with a fully qualified digest (e.g. ‘sha256:abc728…’) then the archive/DB will be verified against this value.
Usage:
grype db import FILE | URL [flags]
Flags:
-h, --help help for import
grype db list
List all DBs available according to the listing URL.
Usage:
grype db list [flags]
Flags:
-h, --help help for list
-o, --output string format to display results (available=[text, raw, json]) (default "text")
grype db providers
List vulnerability providers that are in the database.
Usage:
grype db providers [flags]
Flags:
-h, --help help for providers
-o, --output string format to display results (available=[table, json]) (default "table")
grype db search
Search the DB for vulnerabilities or affected packages.
Usage:
grype db search [flags]
grype db search [command]
Examples:
Search for affected packages by vulnerability ID:
$ grype db search --vuln ELSA-2023-12205 Search for affected packages by package name:
$ grype db search --pkg log4j
Search for affected packages by package name, filtering down to a specific vulnerability:
$ grype db search --pkg log4j --vuln CVE-2021-44228 Search for affected packages by PURL (note: version is not considered):
$ grype db search --pkg 'pkg:rpm/redhat/openssl' # or: '--ecosystem rpm --pkg openssl
Search for affected packages by CPE (note: version/update is not considered):
$ grype db search --pkg 'cpe:2.3:a:jetty:jetty_http_server:*:*:*:*:*:*:*:*'
$ grype db search --pkg 'cpe:/a:jetty:jetty_http_server'
Available Commands:
vuln Search for vulnerabilities within the DB (supports DB schema v6+ only)
Flags:
--broad-cpe-matching allow for specific package CPE attributes to match with '*' values on the vulnerability
--distro stringArray refine to results with the given operating system (format: 'name', 'name[-:@]version', 'name[-:@]maj.min', 'name[-:@]codename')
--ecosystem string ecosystem of the package to search within
--fixed-state stringArray only show vulnerabilities with the given fix state (fixed, not-fixed, unknown, wont-fix)
-h, --help help for search
--limit int limit the number of results returned, use 0for no limit (default5000)
--modified-after string only show vulnerabilities originally published or modified since the given date (format: YYYY-MM-DD)
-o, --output string format to display results (available=[table, json]) (default"table")
--pkg stringArray package name/CPE/PURL to search for--provider stringArray only show vulnerabilities from the given provider
--published-after string only show vulnerabilities originally published after the given date (format: YYYY-MM-DD)
--vuln stringArray only show results for the given vulnerability ID
grype db status
Display database status and metadata.
Usage:
grype db status [flags]
Flags:
-h, --help help for status
-o, --output string format to display results (available=[text, json]) (default "text")
grype db update
Download and install the latest vulnerability database.
Usage:
grype db update [flags]
Flags:
-h, --help help for update
grype explain
Ask grype to explain a set of findings.
Usage:
grype explain --id [VULNERABILITY ID] [flags]
Flags:
-h, --help help for explain
--id stringArray CVE IDs to explain
grype version
Show version information.
Usage:
grype version [flags]
Flags:
-h, --help help for version
-o, --output string the format to show the results (allowable: [text json]) (default "text")
6.5 - Grype Configuration Reference
Note
This documentation was generated with Grype version 0.104.0.
Grype searches for configuration files in the following locations, in order:
./.grype.yaml - current working directory
./.grype/config.yaml - app subdirectory in current working directory
The configuration file can use either .yaml or .yml extensions. The first configuration file found will be used.
For general information about how config and environment variables are handled, see the Configuration Reference section.
log:
# suppress all logging output (env: GRYPE_LOG_QUIET)quiet: false# explicitly set the logging level (available: [error warn info debug trace]) (env: GRYPE_LOG_LEVEL)level: "warn"# file path to write logs to (env: GRYPE_LOG_FILE)file: ""dev:
# capture resource profiling data (available: [cpu, mem]) (env: GRYPE_DEV_PROFILE)profile: ""db:
# (env: GRYPE_DEV_DB_DEBUG)debug: false# the output format of the vulnerability report (options: table, template, json, cyclonedx)# when using template as the output type, you must also provide a value for 'output-template-file' (env: GRYPE_OUTPUT)output: []
# if using template output, you must provide a path to a Go template file# see https://github.com/anchore/grype#using-templates for more information on template output# the default path to the template file is the current working directory# output-template-file: .grype/html.tmpl## write output report to a file (default is to write to stdout) (env: GRYPE_FILE)file: ""# pretty-print output (env: GRYPE_PRETTY)pretty: false# distro to match against in the format: <distro>[-:@]<version> (env: GRYPE_DISTRO)distro: ""# generate CPEs for packages with no CPE data (env: GRYPE_ADD_CPES_IF_NONE)add-cpes-if-none: false# specify the path to a Go template file (requires 'template' output to be selected) (env: GRYPE_OUTPUT_TEMPLATE_FILE)output-template-file: ""# enable/disable checking for application updates on startup (env: GRYPE_CHECK_FOR_APP_UPDATE)check-for-app-update: true# ignore matches for vulnerabilities that are not fixed (env: GRYPE_ONLY_FIXED)only-fixed: false# ignore matches for vulnerabilities that are fixed (env: GRYPE_ONLY_NOTFIXED)only-notfixed: false# ignore matches for vulnerabilities with specified comma separated fix states, options=[fixed not-fixed unknown wont-fix] (env: GRYPE_IGNORE_WONTFIX)ignore-wontfix: ""# an optional platform specifier for container image sources (e.g. 'linux/arm64', 'linux/arm64/v8', 'arm64', 'linux') (env: GRYPE_PLATFORM)platform: ""search:
# selection of layers to analyze, options=[squashed all-layers deep-squashed] (env: GRYPE_SEARCH_SCOPE)scope: "squashed"# search within archives that do not contain a file index to search against (tar, tar.gz, tar.bz2, etc)# note: enabling this may result in a performance impact since all discovered compressed tars will be decompressed# note: for now this only applies to the java package cataloger (env: GRYPE_SEARCH_UNINDEXED_ARCHIVES)unindexed-archives: false# search within archives that do contain a file index to search against (zip)# note: for now this only applies to the java package cataloger (env: GRYPE_SEARCH_INDEXED_ARCHIVES)indexed-archives: true# A list of vulnerability ignore rules, one or more property may be specified and all matching vulnerabilities will be ignored.# This is the full set of supported rule fields:# - vulnerability: CVE-2008-4318# fix-state: unknown# package:# name: libcurl# version: 1.5.1# type: npm# location: "/usr/local/lib/node_modules/**"## VEX fields apply when Grype reads vex data:# - vex-status: not_affected# vex-justification: vulnerable_code_not_presentignore: []
# a list of globs to exclude from scanning, for example:# - '/etc/**'# - './out/**/*.json'# same as --exclude (env: GRYPE_EXCLUDE)exclude: []
external-sources:
# enable Grype searching network source for additional information (env: GRYPE_EXTERNAL_SOURCES_ENABLE)enable: falsemaven:
# search for Maven artifacts by SHA1 (env: GRYPE_EXTERNAL_SOURCES_MAVEN_SEARCH_MAVEN_UPSTREAM)search-maven-upstream: true# base URL of the Maven repository to search (env: GRYPE_EXTERNAL_SOURCES_MAVEN_BASE_URL)base-url: "https://search.maven.org/solrsearch/select"# (env: GRYPE_EXTERNAL_SOURCES_MAVEN_RATE_LIMIT)rate-limit: 300ms
match:
java:
# use CPE matching to find vulnerabilities (env: GRYPE_MATCH_JAVA_USING_CPES)using-cpes: falsejvm:
# (env: GRYPE_MATCH_JVM_USING_CPES)using-cpes: truedotnet:
# use CPE matching to find vulnerabilities (env: GRYPE_MATCH_DOTNET_USING_CPES)using-cpes: falsegolang:
# use CPE matching to find vulnerabilities (env: GRYPE_MATCH_GOLANG_USING_CPES)using-cpes: false# use CPE matching to find vulnerabilities for the Go standard library (env: GRYPE_MATCH_GOLANG_ALWAYS_USE_CPE_FOR_STDLIB)always-use-cpe-for-stdlib: true# allow comparison between main module pseudo-versions (e.g. v0.0.0-20240413-2b432cf643...) (env: GRYPE_MATCH_GOLANG_ALLOW_MAIN_MODULE_PSEUDO_VERSION_COMPARISON)allow-main-module-pseudo-version-comparison: falsejavascript:
# use CPE matching to find vulnerabilities (env: GRYPE_MATCH_JAVASCRIPT_USING_CPES)using-cpes: falsepython:
# use CPE matching to find vulnerabilities (env: GRYPE_MATCH_PYTHON_USING_CPES)using-cpes: falseruby:
# use CPE matching to find vulnerabilities (env: GRYPE_MATCH_RUBY_USING_CPES)using-cpes: falserust:
# use CPE matching to find vulnerabilities (env: GRYPE_MATCH_RUST_USING_CPES)using-cpes: falsestock:
# use CPE matching to find vulnerabilities (env: GRYPE_MATCH_STOCK_USING_CPES)using-cpes: true# upon scanning, if a severity is found at or above the given severity then the return code will be 1# default is unset which will skip this validation (options: negligible, low, medium, high, critical) (env: GRYPE_FAIL_ON_SEVERITY)fail-on-severity: ""registry:
# skip TLS verification when communicating with the registry (env: GRYPE_REGISTRY_INSECURE_SKIP_TLS_VERIFY)insecure-skip-tls-verify: false# use http instead of https when connecting to the registry (env: GRYPE_REGISTRY_INSECURE_USE_HTTP)insecure-use-http: false# Authentication credentials for specific registries. Each entry describes authentication for a specific authority:# - authority: the registry authority URL the URL to the registry (e.g. "docker.io", "localhost:5000", etc.) (env: SYFT_REGISTRY_AUTH_AUTHORITY)# username: a username if using basic credentials (env: SYFT_REGISTRY_AUTH_USERNAME)# password: a corresponding password (env: SYFT_REGISTRY_AUTH_PASSWORD)# token: a token if using token-based authentication, mutually exclusive with username/password (env: SYFT_REGISTRY_AUTH_TOKEN)# tls-cert: filepath to the client certificate used for TLS authentication to the registry (env: SYFT_REGISTRY_AUTH_TLS_CERT)# tls-key: filepath to the client key used for TLS authentication to the registry (env: SYFT_REGISTRY_AUTH_TLS_KEY)auth: []
# filepath to a CA certificate (or directory containing *.crt, *.cert, *.pem) used to generate the client certificate (env: GRYPE_REGISTRY_CA_CERT)ca-cert: ""# show suppressed/ignored vulnerabilities in the output (only supported with table output format) (env: GRYPE_SHOW_SUPPRESSED)show-suppressed: false# orient results by CVE instead of the original vulnerability ID when possible (env: GRYPE_BY_CVE)by-cve: false# sort the match results with the given strategy, options=[package severity epss risk kev vulnerability] (env: GRYPE_SORT_BY)sort-by: "risk"# same as --name; set the name of the target being analyzed (env: GRYPE_NAME)name: ""# allows users to specify which image source should be used to generate the sbom# valid values are: registry, docker, podman (env: GRYPE_DEFAULT_IMAGE_PULL_SOURCE)default-image-pull-source: ""# specify the source behavior to use (e.g. docker, registry, podman, oci-dir, ...) (env: GRYPE_FROM)from: []
# a list of VEX documents to consider when producing scanning results (env: GRYPE_VEX_DOCUMENTS)vex-documents: []
# VEX statuses to consider as ignored rules (env: GRYPE_VEX_ADD)vex-add: []
# match kernel-header packages with upstream kernel as kernel vulnerabilities (env: GRYPE_MATCH_UPSTREAM_KERNEL_HEADERS)match-upstream-kernel-headers: falsefix-channel:
redhat-eus:
# whether fixes from this channel should be considered, options are "never", "always", or "auto" (conditionally applied based on SBOM data) (env: GRYPE_FIX_CHANNEL_REDHAT_EUS_APPLY)apply: "auto"# (env: GRYPE_FIX_CHANNEL_REDHAT_EUS_VERSIONS)versions: ">= 8.0"# (env: GRYPE_TIMESTAMP)timestamp: truedb:
# location to write the vulnerability database cache (env: GRYPE_DB_CACHE_DIR)cache-dir: "~/.cache/grype/db"# URL of the vulnerability database (env: GRYPE_DB_UPDATE_URL)update-url: "https://grype.anchore.io/databases"# certificate to trust download the database and listing file (env: GRYPE_DB_CA_CERT)ca-cert: ""# check for database updates on execution (env: GRYPE_DB_AUTO_UPDATE)auto-update: true# validate the database matches the known hash each execution (env: GRYPE_DB_VALIDATE_BY_HASH_ON_START)validate-by-hash-on-start: true# ensure db build is no older than the max-allowed-built-age (env: GRYPE_DB_VALIDATE_AGE)validate-age: true# Max allowed age for vulnerability database,# age being the time since it was built# Default max age is 120h (or five days) (env: GRYPE_DB_MAX_ALLOWED_BUILT_AGE)max-allowed-built-age: 120h0m0s
# fail the scan if unable to check for database updates (env: GRYPE_DB_REQUIRE_UPDATE_CHECK)require-update-check: false# Timeout for downloading GRYPE_DB_UPDATE_URL to see if the database needs to be downloaded# This file is ~156KiB as of 2024-04-17 so the download should be quick; adjust as needed (env: GRYPE_DB_UPDATE_AVAILABLE_TIMEOUT)update-available-timeout: 30s
# Timeout for downloading actual vulnerability DB# The DB is ~156MB as of 2024-04-17 so slower connections may exceed the default timeout; adjust as needed (env: GRYPE_DB_UPDATE_DOWNLOAD_TIMEOUT)update-download-timeout: 5m0s
# Maximum frequency to check for vulnerability database updates (env: GRYPE_DB_MAX_UPDATE_CHECK_FREQUENCY)max-update-check-frequency: 2h0m0s
exp:
6.6 - Grant Command Line Reference
Note
This documentation was generated with Grant version 0.5.1.
Grant helps you view licenses for container images, SBOM documents, and filesystems. Apply filters and views that can help you build a picture of licenses in your SBOM.
Usage:
grant [command]
Available Commands:
check Check license compliance for one or more targets
completion Generate the autocompletion script for the specified shell
config Generate a comprehensive configuration file
help Help about any command
list List licenses found in one or more targets
version Show the version information for grant
Flags:
-c, --config string path to configuration file
-h, --help help for grant
--no-output suppress terminal output when writing to file
-o, --output string output format (table, json) (default "table")
-f, --output-file string write JSON output to file (sets output format to json)
-q, --quiet suppress all non-essential output
-v, --verbose enable verbose output
--version version for grant
Use "grant [command] --help" for more information about a command.
grant check
Check evaluates license compliance for container images, SBOMs, filesystems, and files.
Targets can be:
Container images: alpine:latest, ubuntu:22.04
SBOM files: path/to/sbom.json, path/to/sbom.json
Directories: dir:./project, ./my-app
Archive files: project.tar.gz, source.zip
License files: LICENSE, COPYING
Stdin: - (reads SBOM from stdin)
Exit codes:
0: All targets are compliant
1: One or more targets are non-compliant or an error occurred.
Usage:
grant check [TARGET...] [flags]
Flags:
--disable-file-search disable filesystem license file search
--dry-run run check without returning non-zero exit code on violations
-h, --help help for check
--summary show only summary information
--unlicensed show only packages without licenses
grant config
Generate a complete YAML configuration file with all available Grant options.
This command outputs a comprehensive configuration file that includes:
The generated configuration can be saved to a file and customized as needed.
Usage:
grant config [flags]
Flags:
-h, --help help for config
-o, --output string output file path (default: stdout)
grant list
List shows all licenses found in container images, SBOMs, filesystems, and files
without applying policy evaluation.
Targets can be:
Container images: alpine:latest, ubuntu:22.04
SBOM files: path/to/sbom.json, path/to/sbom.xml
Directories: dir:./project, ./my-app
Archive files: project.tar.gz, source.zip
License files: LICENSE, COPYING
Stdin: - (reads SBOM from stdin)
When no target is specified and stdin is available (piped input), grant will
automatically read from stdin. This allows usage like:
syft -o json dir:. | grant list Apache-2.0
License filtering:
If license names are provided as additional arguments, only packages with those
specific licenses will be shown. For example:
grant list dir:. “MIT” “Apache-2.0”
syft -o json dir:. | grant list “MIT” “Apache-2.0”
This command always returns exit code 0 unless there are processing errors.
Usage:
grant list [TARGET] [LICENSE...] [flags]
Flags:
--disable-file-search disable filesystem license file search
--group-by string group results by specified field (risk)
-h, --help help for list
--pkg string show detailed information for a specific package (requires license filter)
--unlicensed show only packages without licenses
grant version
Show the version information for grant.
Usage:
grant version [flags]
Flags:
-h, --help help for version
6.7 - Data sources
Complete list of data sources used by Grype for vulnerability scanning
The following are a list of data sources used to directly match packages to vulnerabilities in Grype:
Data-driven effort by FIRST to predict the likelihood that a software vulnerability will be exploited. Provides daily-updated probability scores (0-1) and percentile rankings for CVE prioritization.
CISA's authoritative catalog of vulnerabilities known to be actively exploited in the wild. Provides exploitation status, required remediation actions, due dates, and ransomware campaign associations.
These sources are cross-cutting in nature and are not tied to a specific distribution or ecosystem
(though, primarily enriching information about CVEs specifically).
6.8 - Grant Configuration Reference
Note
This documentation was generated with Grant version 0.5.1.
Grant searches for configuration files in the following locations, in order:
./.grant.yaml - current working directory
./.grant/config.yaml - app subdirectory in current working directory
The configuration file can use either .yaml or .yml extensions. The first configuration file found will be used.
For general information about how config and environment variables are handled, see the Configuration Reference section.
# Grant License Compliance Configuration# Complete configuration file with all available options# See: https://github.com/anchore/grantformat: table # Output format: "table" or "json" (default: "table")
quiet: false # Suppress all non-essential output (default: false)
verbose: false # Enable verbose output (default: false)
# List of allowed license patterns (supports glob matching)# Default behavior: DENY all licenses except those explicitly permittedallow:
- MIT
- Apache-2.0
- BSD-3-Clause
# List of package patterns to ignore from license checking# Supports glob patterns for flexible matchingignore-packages: []
# Add package patterns to ignore here# Examples:# - "github.com/mycompany/*"# - "internal/*"# Policy enforcement optionsrequire-license: true# When true, deny packages with no detected licensesrequire-known-license: false# When true, deny non-SPDX / unparsable licenses# ============================================================================# COMMAND-SPECIFIC OPTIONS# ============================================================================disable-file-search: false# Disable filesystem license file searchsummary: false# Show only summary information for check command# Show only packages without licenses (default: false)only-unlicensed: false# maps to grant check --unlicensed || grant list --unlicensed
6.9 - Configuration Rules
Configuration patterns and options used across all Anchore OSS tools
All Anchore open source tools (Syft, Grype, Grant) share the same configuration system. This guide explains how to configure these tools using command-line flags, environment variables, and configuration files.
Configuration precedence
When you configure a tool, settings are applied in a specific order. If the same setting is specified in multiple places, the tool uses the value from the highest-priority source:
Command-line arguments(highest priority)
Environment variables
Explicit config file (-c PATH or --config PATH)
Auto-discovered configuration file
Default values(lowest priority)
For example, if you set the log level using all three methods, the command-line flag overrides the environment variable, which overrides the config file value.
Tip
Running a tool with -vv log level prints the entire active configuration at startup, showing you exactly which values are being used.
Viewing your configuration
To see available configuration options and current settings:
syft --help — shows all command-line flags
syft config — prints a complete sample configuration file
syft config --load — displays your current active configuration
Replace syft with the tool you’re using (grype, grant, etc.).
Specifying a configuration file
You can explicitly specify a configuration file using the -c or --config flag,
which overrides the auto-discovery behavior.
Syft and Grype support multiple configuration files by specifying the flag multiple times:
syft alpine:latest -c base.yaml -c overrides.yaml
When multiple files are specified, individual settings from later files override earlier ones.
Using environment variables
Every configuration option can be set via environment variable. The variable name follows the path to the setting in the configuration file.
Example: To enable pretty-printed JSON output, the config file setting is:
format:
json:
pretty: true
The path from root to this value is format → json → pretty, so the environment variable is:
exportSYFT_FORMAT_JSON_PRETTY=true
The pattern is: <TOOL>_<PATH>_<TO>_<SETTING> where:
<TOOL> is the uppercase tool name (SYFT, GRYPE, GRANT)
Path segments are joined with underscores
All letters are uppercase
More examples:
# Set log level to debugexportSYFT_LOG_LEVEL=debug
# Configure output formatexportGRYPE_OUTPUT=json
# Set registry credentialsexportSYFT_REGISTRY_AUTH_USERNAME=myuser
Configuration file auto-discovery
When you don’t specify a configuration file with -c, the tool automatically searches for one.
Configuration files use YAML format. The tool searches these locations in order and uses the first file it finds:
Replace syft with your tool name (grype, grant, etc.).
Note
Only the first config file found is used — configuration files are not merged together.
7 - Architecture
How all the projects and datasets fit together
Anchore’s open source security tooling consists of several interconnected tools that work together to detect vulnerabilities and ensure license compliance in software packages. This page explains how these tools interact and how data flows through the system.
The Anchore OSS ecosystem includes five main tools that, at the 30,000 ft view, work together as follows:
chronicle for automatically generating release notes based on github issues and PR titles/labels.
quill for signing and notarizing release binaries for Mac.
This document explains how all of the golang-base Anchore OSS tools are organized, covering the
package structure, common core architectural concepts, and where key functionality is implemented.
Use this as a reference when trying to familiarize yourself with the overall structure of Syft, Grype, or other applications.
CLI
The cmd package uses the Clio framework (built on top of the spf13/cobra and spf13/viper) to manage flag/argument parsing, configuration, and command execution.
All flags, arguments, and config arguments are represented in the application as a struct.
Each command tends to get it’s own struct with all options the command needs to function.
Common options or sets of options can be defined independently and reused across commands, being composed within each command struct that needs the option.
Select options that represent flags are registered with the AddFlags method defined on the command struct (or on each option struct used within the command struct).
If any additional processing is needed to be done to elements in command structs or option structs before being used in the application then you can define a PostLoad method on the struct to mutate the elements you need.
In terms of what is executed when: all processing is done within the selected cobra command’s PreRun hook, wrapping any potential user-provided hook.
This means that all of this fits nicely into the existing cobra command lifecycle.
See the sign command in Quill for a small example of all of this together.
The reason for this approach is to smooth over the rough edges between cobra and viper, which have multiple ways to configure and use functionality, and provide a single way to specify any input into the application.
Being prescriptive about these approaches has allowed us to take many shared concerns that used to be a lot of boilerplate when creating an application and put it into one framework –Clio.
Execution flow
The following diagrams show the execution of a typical Anchore application at different levels of detail, using the scan command in Syft as a representative example:
sequenceDiagram
actor user as User
participant syft as Syft Application
participant cmd as Command Handler (Cobra)
participant lib as Library
user->>syft: syft scan alpine:latest
syft->>cmd: Execute
cmd->>cmd: Initialize & Load Configuration
cmd->>lib: Execute Scan Logic
lib->>cmd: SBOM
cmd-->>user: Display/Write SBOM
sequenceDiagram
actor user as User
box rgba(0,0,0,.1) Syft Application
participant main as main.go
participant cliApp as cli.Application()
participant clio as Clio Framework
end
box rgba(0,0,0,.1) Command Handler
participant cobra as Command PreRunE
participant opts as Command Options
participant runE as Command RunE
end
participant lib as Library
user->>main: syft scan alpine:latest
Note over main,clio: Syft Application (initialization)
main->>cliApp: Create app with ID
cliApp->>clio: clio.New(config)
clio-->>cliApp: app instance
Note over cliApp,cobra: Build Command Tree
cliApp->>cliApp: commands.Scan(app)
cliApp->>clio: app.SetupCommand(&cobra.Command, opts)
Note over clio: Bind config sources to options struct
clio-->>cliApp: configured scanCmd
cliApp->>cliApp: commands.Root(app, scanCmd)
cliApp->>clio: app.SetupRootCommand(&cobra.Command, opts)
clio-->>cliApp: rootCmd with scanCmd attached
main->>clio: app.Run()
clio->>cobra: rootCmd.Execute()
Note over cobra,runE: Command Handler (execution)
cobra->>cobra: Parse args → "scan alpine:latest"
cobra->>opts: Load config (files/env/flags)
cobra->>opts: opts.PostLoad() validation
cobra->>runE: RunE(cmd, args)
runE->>lib: Execute Scan Logic
lib-->>runE: SBOM
Note over runE: Result Output
runE-->>user: SBOM output
Package structure
Many of the Anchore OSS tools have the following setup (or very similar):
/cmd/NAME/ - CLI application layer.
This is the entry point for the command-line tool and wires up much of the functionality from the public API.
./cmd/NAME/
│ ├── cli/
│ │ ├── cli.go // where all commands are wired up
│ │ ├── commands/ // all command implementations
│ │ ├── options/ // all command flags and configuration options
│ │ └── ui/ // all handlers for events that are shown on the UI
│ └── main.go // entrypoint for the application
...
/NAME/ - Public library API.
This is how API users interact with the underlying capabilities without coupling to the application configuration, specific presentation on the terminal, or high-level workflows.
The internalization philosophy
Applications extensively use internal/ packages at multiple levels to minimize the public API surface area.
The codebase follows the guiding principle “internalize anything you can” - expose only what library consumers truly need.
Take for example the various internal packages within Syft
This multi-level approach allows Syft to expose a minimal, stable public API while keeping implementation details flexible and changeable.
Go’s module system prevents importing internal/ packages from outside their parent directory, which enforces clean separation of concerns.
Core facilities
The bus system
The bus system, under /internal/bus/ within the target application, is an event publishing mechanism that enables progress reporting and UI updates
without coupling the library to any specific user interface implementation.
The bus follows a strict one-way communication pattern: the library publishes events but never subscribes to them.
The intention is that functionality is NOT fulfilled by listening to events on the bus and taking action.
Only the application layer (CLI) subscribes to events for display.
This keeps the library completely decoupled from UI concerns.
You can think of the bus as a structured extension of the logger, allowing for publishing not just strings or maps of strings,
but enabling publishing objects that can yield additional telemetry on-demand, fueling richer interactions.
This enables library consumers to implement any UI they want (terminal UI, web UI, no UI) by subscribing to events and handling them appropriately.
The library has zero knowledge of how events are used, maintaining a clean separation between business logic and presentation.
The bus is implemented as a singleton with a global publisher that can be set by library consumers:
var publisher partybus.Publisher
funcSet(p partybus.Publisher) {
publisher = p
}
funcPublish(e partybus.Event) {
if publisher !=nil {
publisher.Publish(e)
}
}
The library calls bus.Publish() throughout cataloging operations. If no publisher is set, events are silently discarded.
This makes events truly optional.
Event streams
Picking the right “level” for events is key. Libraries tend to not assume that events can be read “quickly” off the bus.
At the same time, to remain lively and useful, we want to be able to have consumers of the bus to get information
at a rate they choose. A common pattern used is to publish a “start” event (for example, “cataloging started”) and
publish with that event a read-only, thread-safe object that can be polled by the caller to get progress or status-based
information out.
sequenceDiagram
participant CMD as cmd/<br/>(CLI Layer)
participant Bus as internal/bus/<br/>(Event Bus)
participant Lib as lib/<br/>(Library Layer)
participant Progress as Progress Object
CMD->>Bus: Subscribe()
CMD->>+Lib: PerformOperation()
Lib->>Progress: Create progress object
Lib->>Bus: Publish(StartEvent, progress)
Bus->>CMD: StartEvent
loop Poll until complete
CMD->>Progress: Size(), Current(), Stage(), Error()
Progress-->>CMD: status (Error: nil)
end
Lib-->>-CMD: Return result
CMD->>Progress: Error()
Progress-->>CMD: ErrCompleted
This prevents against the library accidentally being a “firehose” and overwhelming subscribers who are trying to convey
timely information. When subscribers cannot keep up with the amount of events emitted from the library then the very
information being displayed tends to get stale and useless anyway. At the same time, the there is a lot of value in
responding to events instead of polling for all information.
This pattern helps to balance the best of both worlds, getting an event driven system with a consumer-driven update
cadence.
The logging system
The logging system, under /internal/log/ within the target application, provides structured logging throughout Anchore’s applications with an injectable logger interface.
This allows library consumers to integrate the application’s logging into their own logging infrastructure.
There is an adapter for logrus to this interface implemented, and we’re happy to take additional contributions for other concrete logger adapters.
The logging system is implemented as a singleton with global functions (log.Info, log.Debug, etc.).
Library consumers inject their logger by calling the public API function syft.SetLogger(yourLoggerHere).
By default, Syft uses a discard logger (no-op) that silently ignores all log messages.
This ensures the library produces no output unless a logger is explicitly provided.
All loggers are automatically wrapped with a redaction layer when you call SetLogger().
The wrapping is applied internally by the logging system, which removes sensitive information (like authentication tokens) from log output.
This happens transparently within the application CLI, however, API users will need to explicitly register secrets to be redacted.
Releasing
Each application uses goreleaser to build and publish releases, as orchestrated by a release workflow.
The release workflow can be triggered with make release from a local checkout of the repository.
Chronicle is used to automatically generate release notes based on GitHub issues and PR titles/labels,
using the same information to determine the next version for the release.
With each repo, we tend to publish (but some details may vary slightly between repos):
a tag with the version (e.g., v0.50.0)
binaries for Linux, Mac, and Windows, uploaded as GitHub release assets (note, we sign and notarize Mac binaries with Quill)
Docker images, pushed to Docker Hub and ghcr.io registries
Update homebrew taps
We ensure the same tool versions are used locally and in CI by using Binny, orchestrated with make and task.
7.2 - Syft
Architecture and design of the Syft SBOM tool
Note
See the Golang CLI Patterns for common structures and frameworks used in Syft and across other Anchore open source projects.
At a high level, this is the package structure of Syft:
./cmd/syft/ // main entrypoint
│ └── ...
└── syft/ // the "core" syft library
├── format/ // contains code to encode or decode to and from SBOM formats
├── pkg/ // contains code to catalog packages from a source
├── sbom/ // contains the definition of an SBOM
└── source/ // contains code to create a source object for some input type (e.g. container image, directory, etc)
Syft’s core library is implemented in the syft package and subpackages.
The major packages work together in a pipeline:
The syft/source package produces a source.Source object that can be used to catalog a directory, container, and other source types.
The syft package knows how to take a source.Source object and catalog it to produce an sbom.SBOM object.
The syft/format package contains the ability to encode an sbom.SBOM object to and from different SBOM formats (such as SPDX and CycloneDX).
This design creates a clear flow: source → catalog → format:
sequenceDiagram
actor User
participant CLI
participant Resolve as Source Resolution
participant Catalog as SBOM Creation
participant Format as Format Output
User->>CLI: syft scan <target>
CLI->>CLI: Parse configuration
CLI->>Resolve: Resolve input (image/dir/file)
Note over Resolve: Tries: File→Directory→OCI→Docker→Podman→Containerd→Registry
Resolve-->>CLI: source.Source
CLI->>Catalog: Create SBOM from source
Note over Catalog: Task-based cataloging engine
Catalog-->>CLI: sbom.SBOM struct
CLI->>Format: Write to format(s)
Note over Format: Parallel: SPDX, CycloneDX, Syft JSON, etc.
Format-->>User: SBOM file(s)
Shows the task-based architecture and execution phases.
Tasks are selected by tags (image/directory/installed) and organized into serial phases, with parallel execution within each phase.
sequenceDiagram
participant CLI as scan.go
participant GetSource as Source Providers
participant CreateSBOM as syft.CreateSBOM
participant Config as CreateSBOMConfig
participant Executor as Task Executor
participant Builder as sbomsync.Builder
participant Resolver as file.Resolver
Note over CLI,GetSource: Source Resolution
CLI->>GetSource: GetSource(userInput, cfg)
GetSource->>GetSource: Try providers until success
GetSource-->>CLI: source.Source + file.Resolver
Note over CLI,Builder: SBOM Creation (task-based architecture)
CLI->>CreateSBOM: CreateSBOM(ctx, source, cfg)
CreateSBOM->>Config: makeTaskGroups(srcMetadata)
Note over Config: Task Selection & Organization
Config->>Config: Select catalogers by tags<br/>(image/directory/installed)
Config->>Config: Organize into execution phases
Config-->>CreateSBOM: [][]Task (grouped by phase)
CreateSBOM->>Builder: Initialize thread-safe builder
Note over CreateSBOM,Executor: Phase 1: Environment Detection
CreateSBOM->>Executor: Execute environment tasks
Executor->>Resolver: Read OS release files
Executor->>Builder: SetLinuxDistribution()
Note over CreateSBOM,Executor: Phase 2: Package + File Cataloging
CreateSBOM->>Executor: Execute package & file tasks
par Parallel Task Execution
Executor->>Resolver: Read package manifests
Executor->>Builder: AddPackages()
and
Executor->>Resolver: Read file metadata
Executor->>Builder: Add file artifacts
end
Note over CreateSBOM,Executor: Phase 3: Post-Processing
CreateSBOM->>Executor: Execute relationship tasks
Executor->>Builder: AddRelationships()
CreateSBOM->>Executor: Execute cleanup tasks
CreateSBOM-->>CLI: *sbom.SBOM
Note over CLI: Format Output
CLI->>CLI: Write multi-format output
The Package object
The pkg.Package object is a core data structure that represents a software package.
Key fields include:
FoundBy: the name of the cataloger that discovered this package (e.g. python-pip-cataloger).
Locations: the set of paths and layer IDs that were parsed to discover this package.
Language: the language of the package (e.g. python).
Type: a high-level categorization of the ecosystem the package resides in. For instance, even if the package is an egg, wheel, or requirements.txt reference, it is still logically a “python” package. Not all package types align with a language (e.g. rpm) but it is common.
Metadata: specialized data for specific location(s) parsed. This should contain as much raw information as seems useful, kept as flat as possible using the raw names and values from the underlying source material.
Additional package Metadata
Packages can have specialized metadata that is specific to the package type and source of information.
This metadata is stored in the Metadata field of the pkg.Package struct as an any type, allowing for flexibility in the data stored.
When pkg.Package is serialized, an additional MetadataType field is shown to help consumers understand the datashape of the Metadata field.
By convention the MetadataType value follows these rules:
Only use lowercase letters, numbers, and hyphens. Use hyphens to separate words.
Anchor the name in the ecosystem, language, or packaging tooling. For language ecosystems, prefix with the language/framework/runtime. For instance dart-pubspec-lock is better than pubspec-lock. For OS package managers this is not necessary (e.g. apk-db-entry is good, but alpine-apk-db-entry is redundant).
Be as specific as possible to what the data represents. For instance ruby-gem is NOT a good MetadataType value, but ruby-gemspec is, since Ruby gem information can come from a gemspec file or a Gemfile.lock, which are very different.
Describe WHAT the data is, NOT HOW it’s used. For instance r-description-installed-file is not good since it’s trying to convey how we use the DESCRIPTION file. Instead simply describe what the DESCRIPTION file is: r-description.
Use the lock suffix to distinguish between manifest files that loosely describe package version requirements vs files that strongly specify one and only one version of a package (“lock” files). These should only be used with respect to package managers that have the guide and lock distinction, but would not be appropriate otherwise (e.g. rpm does not have a guide vs lock, so lock should NOT be used to describe a db entry).
Use the archive suffix to indicate a package archive (e.g. rpm file, apk file) that describes the contents of the package. For example an RPM file would have a rpm-archive metadata type (not to be confused with an RPM DB record entry which would be rpm-db-entry).
Use the entry suffix to indicate information about a package found as a single entry within a file that has multiple package entries. If found within a DB or flat-file store for an OS package manager, use db-entry.
Should NOT contain the phrase package, though exceptions are allowed if the canonical name literally has the phrase package in it.
Should NOT have a file suffix unless the canonical name has the term “file”, such as a pipfile or gemfile.
Should NOT contain the exact filename+extensions. For instance pipfile.lock shouldn’t be in the name; instead describe what the file is: python-pipfile-lock.
Should NOT contain the phrase metadata, unless the canonical name has this term.
Should represent a single use case. For example, trying to describe Hackage metadata with a single HackageMetadata struct is not allowed since it represents 3 mutually exclusive use cases: stack.yaml, stack.lock, or cabal.project. Each should have its own struct and MetadataType.
The goal is to provide a consistent naming scheme that is easy to understand. If the rules don’t apply in your situation, use your best judgement.
When the underlying parsed data represents multiple files, there are two approaches:
Use the primary file to represent all the data. For instance, though the dpkg-cataloger looks at multiple files, it’s the status file that gets represented.
Nest each individual file’s data under the Metadata field. For instance, the java-archive-cataloger may find information from pom.xml, pom.properties, and MANIFEST.MF. The metadata is java-metadata with each possibility as a nested optional field.
Package Catalogers
Catalogers are the mechanism by which Syft identifies and constructs packages given a targeted list of files.
For example, a cataloger can ask Syft for all package-lock.json files in order to parse and raise up JavaScript packages (see file globs and file parser functions for examples).
There is a generic cataloger implementation that can be leveraged to
quickly create new catalogers by specifying file globs and parser functions (browse the source code for syft catalogers for example usage).
Design principles
From a high level, catalogers have the following properties:
They are independent of one another. The Java cataloger has no idea of the processes, assumptions,
or results of the Python cataloger, for example.
They do not know what source is being analyzed. Are we analyzing a local directory? An image?
If so, the squashed representation or all layers? The catalogers do not know the answers to these questions.
Only that there is an interface to query for file paths and contents from an underlying “source” being scanned.
Packages created by the cataloger should not be mutated after they are created. There is one exception made
for adding CPEs to a package after the cataloging phase, but that will most likely be moved back into the cataloger in the future.
Naming conventions
Cataloger names should be unique and named with these rules in mind:
Must end with -cataloger
Use lowercase letters, numbers, and hyphens only
Use hyphens to separate words
Catalogers for language ecosystems should start with the language name (e.g. python-)
Distinguish between when the cataloger is searching for evidence of installed packages vs declared packages. For example, there are two different gemspec-based catalogers: ruby-gemspec-cataloger and ruby-installed-gemspec-cataloger, where the latter requires that the gemspec is found within a specifications directory (meaning it was installed, not just at the root of a source repo).
File search and selection
All catalogers are provided an instance of the file.Resolver to interface with the image and search for files.
The implementations for these abstractions leverage stereoscope to perform searching.
Here is a rough outline how that works:
A stereoscope file.Index is searched based on the input given (a path, glob, or MIME type). The index is relatively
fast to search, but requires results to be filtered down to the files that exist in the specific layer(s) of interest.
This is done automatically by the filetree.Searcher abstraction. This abstraction will fallback to searching
directly against the raw filetree.FileTree if the index does not contain the file(s) of interest.
Note: the filetree.Searcher is used by the file.Resolver abstraction.
Once the set of files are returned from the filetree.Searcher the results are filtered down further to return
the most unique file results. For example, you may have requested files by a glob that returns multiple results.
These results are filtered down to deduplicate by real files, so if a result contains two references to the same file
(one accessed via symlink and one accessed via the real path), then the real path reference is returned and the symlink
reference is filtered out. If both were accessed by symlink then the first (by lexical order) is returned.
This is done automatically by the file.Resolver abstraction.
By the time results reach the pkg.Cataloger you are guaranteed to have a set of unique files that exist in the
layer(s) of interest (relative to what the resolver supports).
CLI and core API
The CLI (in the cmd/syft/ package) and the core library API (in the syft/ package) are separate layers with a clear boundary.
Application level concerns always reside with the CLI, while the core library focuses on SBOM generation logic.
That means that there is an application configuration (e.g. cmd/syft/cli) and a separate library configuration, and when the CLI uses
the library API, it must adapt its configuration to the library’s configuration types. In that adapter, the CLI layer
defers to API-level defaults as much as possible so there is a single source of truth for default behavior.
Architecture and design of the Grype vulnerability scanner
Note
See the Golang CLI Patterns for common structures and frameworks used in Grype and across other Anchore open source projects.
Code organization
At a high level, this is the package structure of Grype:
./cmd/grype/// main entrypoint│ └── ...└── grype/// the "core" grype library ├── db/// vulnerability database management, schemas, readers, and writers │ ├── v5/// V5 database schema │ └── v6/// v6 database schema ├── match/// core types for matches and result processing ├── matcher/// vulnerability matching strategies │ ├── stock/// default matcher (ecosystem + CPE) │ └── <ecosystem>/// ecosystem-specific matchers (java, dpkg, rpm, etc.) ├── pkg/// types for package representation (wraps Syft packages) ├── search/// search criteria and strategies ├── version/// version comparison across formats ├── vulnerability/// core types for vulnerabilities and provider interface └── presenter/// output formatters (JSON, table, etc.)
The grype package and subpackages implement Grype’s core library. The major packages work together in a pipeline:
The grype/pkg package wraps Syft packages and prepares them as match candidates, augmenting them with upstream package information and CPEs.
The grype/matcher package contains matching strategies that search for vulnerabilities matching specific package types.
The grype/db package manages the vulnerability database and provides query interfaces for matchers.
The grype/vulnerability package defines vulnerability data structures and the Provider interface for database queries.
The grype/search package implements search strategies (ecosystem, distro, CPE) and criteria composition.
The grype/presenter package formats match results into various output formats.
This design creates a clear flow: SBOM → package preparation → matching → results:
sequenceDiagram
actor User
participant CLI
participant DB as Database
participant Prep as Package Prep
participant Match as Matching Engine
participant Post as Post-Processing
participant Format as Presenter
User->>CLI: grype <target>
CLI->>CLI: Parse configuration
Note over CLI: Input Phase
alt SBOM provided
CLI->>CLI: Load SBOM from file
else Scan target
CLI->>CLI: Generate SBOM with Syft
end
Note over CLI,Prep: Preparation Phase
CLI->>DB: Load vulnerability database
DB-->>CLI: Database provider
CLI->>Prep: Prepare packages for matching
Note over Prep: Wrap Syft packages<br/>Add upstream packages<br/>Generate CPEs<br/>Filter overlaps
Prep-->>CLI: Match candidates
Note over CLI,Match: Matching Phase
CLI->>Match: FindMatches(match candidates, provider)
Note over Match: Group by package type<br/>Select matchers<br/>Execute in parallel
Match-->>CLI: Raw matches + ignore filters
Note over CLI,Post: Post-Processing Phase
CLI->>Post: Process matches
Note over Post: Apply ignore filters<br/>Apply user ignore rules<br/>Apply VEX statements<br/>Deduplicate results
Post-->>CLI: Final matches
Note over CLI,Format: Output Phase
CLI->>Format: Format results
Format-->>User: Vulnerability report
This diagram zooms into the Matching Phase from the high-level diagram, showing how the matching engine executes parallel matcher searches against the database. Components are grouped in boxes to show how they map to the high-level participants.
sequenceDiagram
participant CLI as grype/main
box rgba(200, 220, 240, 0.3) Matching Engine
participant Matcher as VulnerabilityMatcher
participant M as Matcher<br/>(Stock, Java, Dpkg, etc.)
end
participant Search as Search Strategies
box rgba(220, 240, 200, 0.3) Database
participant Provider as DB Provider
participant DB as SQLite
end
Note over CLI,DB: Matching Phase (expanded from high-level view)
CLI->>Matcher: FindMatches(match candidates, provider)
Matcher->>Matcher: Group candidates by package type
Note over Matcher,M: Each matcher runs in parallel with ecosystem-specific logic
loop For each package type (stock, java, dpkg, etc.)
Matcher->>M: Match(packages for this type)
M->>Search: Build search criteria<br/>(ecosystem, distro, or CPE-based)
Search->>Provider: SearchForVulnerabilities(criteria)
Provider->>DB: Query vulnerability_handles
DB-->>Provider: Matching handles
Provider->>Provider: Compare versions against constraints
Provider->>DB: Check unaffected_package_handles
DB-->>Provider: Unaffected records
Provider->>DB: Load blobs for confirmed matches
DB-->>Provider: Vulnerability details
Provider-->>Search: Confirmed matches
Search-->>M: Filtered matches
M-->>Matcher: Matches + ignore filters
end
Matcher->>Matcher: Collect matches from all matchers
Matcher-->>CLI: Raw matches + ignore filters
Note over CLI: Continues to Post-Processing Phase (see high-level view)
Relationship to Syft
Grype uses Syft’s SBOM generation capabilities rather than reimplementing package cataloging. The integration happens at two levels:
External SBOMs: You can provide an SBOM file generated by Syft (or any SPDX/CycloneDX SBOM), and Grype consumes it directly.
Inline scanning: When you provide a scan target (like a container image or directory), Grype invokes Syft internally to generate an SBOM, then immediately matches it against vulnerabilities.
The grype/pkg package wraps syft/pkg.Package objects and augments them with matching-specific data:
Upstream packages: For packages built from source (like Debian or RPM packages), Grype adds references to the source package so it can search both the binary package name and source package name.
CPE generation: Grype generates Common Platform Enumeration (CPE) identifiers for packages based on their metadata, enabling CPE-based matching as a fallback strategy.
Distro context: Grype preserves the Linux distribution information from Syft to enable distro-specific vulnerability matching.
This wrapping pattern maintains a clear architectural boundary. Syft focuses on finding packages, while Grype focuses on finding vulnerabilities in those packages.
Package representation
The grype/pkg package converts Syft packages into Grype match candidates. The pkg.FromCollection() function performs this conversion:
Wraps each Syft package in a grype.Package that preserves the original package data.
Adds upstream packages for packages that have source package relationships (e.g., a Debian binary package has a source package).
Generates CPEs based on package metadata (name, version, vendor, product).
Filters overlapping packages for comprehensive distros (like Debian or RPM-based distros) where you might have both installed packages and package files, preferring the installed packages.
The grype.Package type maintains a reference to the original syft.Package while augmenting it with:
Upstreams []UpstreamPackage: Source packages to search in addition to the binary package.
CPEs []syftPkg.CPE: Generated CPE identifiers for fallback matching.
This design preserves the complete SBOM information while preparing packages for the matching process. Matchers receive these enhanced packages and decide which attributes to use for searching.
Data flow
The data flow through Grype follows these steps:
SBOM ingestion: Load an SBOM from a file or generate one by scanning a target.
Package conversion: Convert Syft packages into grype.Package match candidates, adding upstream packages, CPEs, and filtering overlapping packages.
Matcher selection: Group packages by type (e.g., Java, dpkg, npm) and select appropriate matchers.
Parallel matching: Execute matchers in parallel, each querying the database with search criteria specific to their package types.
Result aggregation: Collect matches from all matchers and apply deduplication using ignore filters.
Output formatting: Format the final matches using the selected presenter (JSON, table, SARIF, etc.).
The database sits at the center of this flow. All matchers query the same database provider, but they use different search strategies based on their package types.
Vulnerability database
Grype uses a SQLite database to store vulnerability data. The database design prioritizes query performance and storage efficiency.
In order to interoperate any DB schema with the high-level Grype engine, each schema must implement a Provider interface.
This allows for DB specific schemas to be adapted to the core Grype types.
v6 Schema design
The overall design of the v6 database schema is heavily influenced by the OSV schema,
so if you are familiar with OSV, many of the entities / concepts will feel similar.
The database uses a blob + handle pattern:
Handles: Small, indexed records containing anything you might want to search by (package name, vulnerability id, provider name, etc.).
Grype stores these in tables optimized for fast lookups. These tables point to blobs for full details.
See the Grype DB SQL schemas for more details on handle table structures.
Blobs: Full JSON documents containing complete vulnerability details.
Grype stores these separately and loads them only when a match is made.
See the Grype DB blob schemas for more details on blob structures.
This separation allows Grype to quickly query millions of vulnerability records without loading full vulnerability details until necessary.
Key tables include:
vulnerability_handles: Searchable for vulnerability records by name (CVE/advisory ID), status (active, withdrawn, etc), published/modified/withdrawn dates, and provider ID.
References a blob containing full vulnerability details (description, references, aliases, severities).
affected_package_handles: Links vulnerabilities, packages, and (optionally) operating systems.
The referenced blob contains version constraints (for example, “vulnerable in 1.0.0 to 1.2.5”) and fix information.
Used when the package ecosystem is known (npm, python, gem, etc.).
unaffected_package_handles: Explicitly marks package versions that are NOT vulnerable.
Same structure as affected_package_handles but represents exemptions.
These are applied on top of any discovered affected records to remove matches (thus reduce false positives).
affected_cpe_handles: Links vulnerabilities and explicit CPEs, useful when a CPE cannot be resolved to a clear package ecosystem.
packages: Stores unique ecosystem + name combinations (for example, ecosystem=‘npm’, name=‘lodash’).
operating_systems: Stores OS release information with name, major/minor version, codename, and channel (for example, RHEL EUS versus mainline).
Provides context for distro-specific package matching.
cpes: Stores parsed CPE 2.3 components (part, vendor, product, edition, etc.).
Version constraints are stored in blobs, not in this table.
blobs: Complete vulnerability, package, and decorator details as compressed JSON.
There are 3 blob types:
known_exploited_vulnerability_handles: Links CVE identifiers to blob containing CISA KEV catalog data (date added, vendor, product, required action, ransomware campaign use).
epss_handles: Stores EPSS (Exploit Prediction Scoring System) data with CVE identifier, EPSS score (0-1 probability), and percentile ranking.
cwe_handles: Maps CVE identifiers to CWE (Common Weakness Enumeration) IDs with source and type information.
The schema also includes a package_cpes junction table creating many-to-many relationships between packages and CPEs.
When a CPE can be resolved to a package (via this table), vulnerabilities use affected_package_handles.
When a CPE cannot be resolved, vulnerabilities use affected_cpe_handles instead.
Grype versions the database schema (currently v6). When the schema changes, users download a new database file that Grype automatically detects and uses.
Data organization
Relationships between tables enable efficient querying:
The database provider queries the appropriate handle tables with these criteria.
The grype/version package filters handles by version constraints.
The provider loads the corresponding vulnerability blob for confirmed matches.
The complete vulnerability record returns to the matcher.
Version constraints in the database use multi-version constraint syntax, allowing a single record to express complex version ranges like “affected in 1.0.0 to 1.2.5 and 2.0.0 to 2.1.3”.
Matching engine
The matching engine orchestrates vulnerability matching across different package types. The core component is the VulnerabilityMatcher, which:
Groups packages by type: Java packages go to the Java matcher, dpkg packages to the dpkg matcher, etc.
Selects matchers: Each matcher declares which package types it handles.
Executes matching: Matchers run in parallel, querying the database with their specific search strategies.
Collects results: Matches from all matchers are aggregated.
Applies ignore filters: Matchers can mark certain matches to be ignored by other matchers, preventing duplicate reporting.
The ignore filter mechanism is important. For example, the dpkg matcher searches both the binary package name and the source package name. When it finds a match via the source package, it creates an ignore filter so the stock matcher doesn’t report the same vulnerability using a CPE match. This prevents duplicate matches for the same vulnerability.
Matchers
Each matcher implements the Matcher interface.
This allows Grype to support multiple matching strategies for different package ecosystems.
The process of making a match involves several steps:
Candidate creation: Matchers create match candidates when database records meet search criteria.
Version comparison: The grype/version package compares the package version against the vulnerability’s version constraints.
Unaffected check: If the database has an explicit “not affected” record for this version, the match is rejected.
Match creation: Confirmed matches become Match objects with confidence scores (the scores are currently unused).
Ignore filter check: Matches are checked against ignore filters from other matchers.
User ignore rules: Matches are checked against user-configured ignore rules.
Search strategies
Matchers determine what to search for based on package type and available metadata. Grype supports three main search strategies:
Ecosystem search: Queries vulnerabilities by package name and version within a specific package ecosystem (npm, pypi, gem, etc.). Search fields include ecosystem, package name, and version. The database returns handles where the package name matches and version constraints include the specified version.
Distro search: Queries vulnerabilities by Linux distribution, package name, and version for OS packages managed by apt, yum, or apk. Search fields include distro name and version (for example, debian:10), package name, and version. Also understands distro channels like RHEL EUS versus mainline.
CPE matching: Fallback strategy when ecosystem or distro matching isn’t applicable, using CPE identifiers in the format cpe:2.3:a:vendor:product:version:.... Search fields include CPE components (part, vendor, product). Broader and less precise than ecosystem matching, used primarily when ecosystem data isn’t available.
Search criteria system
The grype/search package provides a criteria system that matchers use to express search requirements.
Criteria can be combined with AND and OR operators:
The database provider translates these criteria into SQL queries against the handle tables.
This abstraction allows matchers to express complex search requirements without writing SQL directly.
Ideally, matchers orchestrate search criteria at a high level, letting each specific criteria type handle its own needs.
It’s the vulnerability provider that ultimately translates criteria into efficient database queries.
Version comparison
Grype supports multiple version formats because different ecosystems have different versioning schemes.
The grype/version package provides format-specific version comparers,
falling back to a “catch all” fuzzy comparer when the format cannot be determined.
Each format has its own constraint parser that understands ecosystem-specific constraint syntax.
The version comparison system detects the appropriate format based on the package type,
then uses the correct comparer to evaluate version constraints from the database.
The records from the Grype DB specify which version format to use on one side of the comparison, and the package type determines the format on the other side.
If no specific format is found, or the formats are incompatible (essentially do not match), the fuzzy comparer is used as a last resort.
Related architecture
Golang CLI Patterns - Common structures and frameworks used across Anchore OSS projects
Syft Architecture - SBOM generation architecture that Grype builds upon
7.4 - Grype DB
Architecture and design of the Grype vulnerability database build system
Overview
grype-db is essentially an application that extracts information from upstream vulnerability data providers, transforms it into smaller records targeted for Grype consumption, and loads the individual records into a new SQLite DB.
flowchart LR
subgraph pull["Pull"]
A[Pull vuln data<br/>from upstream]
end
subgraph build["Build"]
B[Transform entries]
C[Load entries<br/>into new DB]
end
subgraph package["Package"]
D[Package DB]
end
A --> B --> C --> D
style pull stroke-dasharray: 5 5, fill:none
style build stroke-dasharray: 5 5, fill:none
style package stroke-dasharray: 5 5, fill:none
Multi-Schema Support Architecture
What makes grype-db unique compared to a typical ETL job is the extra responsibility of needing to transform the most recent vulnerability data shape (defined in the vunnel repo) to all supported DB schema versions.
From the perspective of the Daily DB Publisher workflow, (abridged) execution looks something like this:
In order to support multiple DB schemas easily from a code-organization perspective, the following abstractions exist:
Provider - Responsible for providing raw vulnerability data files that are cached locally for later processing.
Processor - Responsible for unmarshalling any entries given by the Provider, passing them into Transformers, and returning any resulting entries. Note: the object definition is schema-agnostic but instances are schema-specific since Transformers are dependency-injected into this object.
Transformer (v5, v6) - Takes raw data entries of a specific vunnel-defined schema and transforms the data into schema-specific entries to later be written to the database. Note: the object definition is schema-specific, encapsulating grypeDB/v# specific objects within schema-agnostic Entry objects.
Entry - Encapsulates schema-specific database records produced by Processors/Transformers (from the provider data) and accepted by Writers.
Writer (v5, v6) - Takes Entry objects and writes them to a backing store (today a SQLite database). Note: the object definition is schema-specific and typically references grypeDB/v# schema-specific writers.
Data Flow
All the above abstractions are defined in the pkg/data Go package and are used together commonly in the following flow:
%%{ init: { 'flowchart': { 'curve': 'linear' } } }%%
flowchart LR
A["data.Provider"]
subgraph processor["data.Processor"]
direction LR
B["unmarshaller"]
C["v# data.Transformer"]
B --> C
end
D["data.Writer"]
E["grypeDB/v#/writer.Write"]
A -->|"cache file"| processor
processor -->|"[]data.Entry"| D --> E
style processor fill:none
Where there is:
A data.Provider for each upstream data source (e.g. canonical, redhat, github, NIST, etc.)
A data.Processor for every vunnel-defined data shape (github, os, msrc, nvd, etc… defined in the vunnel repo)
A data.Transformer for every processor and DB schema version pairing
A data.Writer for every DB schema version
Code Organization
From a Go package organization perspective, the above abstractions are organized as follows:
grype-db/
└── pkg
├── data # common data structures and objects that define the ETL flow
├── process
│ ├── processors # common data.Processors to call common unmarshallers and pass entries into data.Transformers
│ ├── v5 # schema v5 (legacy, active)
│ │ ├── processors.go # wires up all common data.Processors to v5-specific data.Transformers
│ │ ├── writer.go # v5-specific store writer
│ │ └── transformers # v5-specific transformers
│ └── v6 # schema v6 (current, active)
│ ├── processors.go # wires up all common data.Processors to v6-specific data.Transformers
│ ├── writer.go # v6-specific store writer
│ └── transformers # v6-specific transformers
└── provider # common code to pull, unmarshal, and cache upstream vuln data into local files
└── ...
Note: Historical schema versions (v1-v4) have been removed from the codebase.
DB Structure and Definitions
The definitions of what goes into the database and how to access it (both reads and writes) live in the public grype repo under the grype/db package. Responsibilities of grype (not grype-db) include (but are not limited to):
What tables are in the database
What columns are in each table
How each record should be serialized for writing into the database
How records should be read/written from/to the database
Providing rich objects for dealing with schema-specific data structures
The name of the SQLite DB file within an archive
The definition of a listing file and listing file entries
The purpose of grype-db is to use the definitions from grype/db and the upstream vulnerability data to create DB archives and make them publicly available for consumption via Grype.
DB Distribution Files
Grype DB currently supports two active schema versions, each with a different distribution mechanism:
Schema v5(legacy): Supports Grype v0.87.0+
Schema v6(current): Supports Grype main branch
Historical schemas (v1-v4) are no longer supported and their code has been removed from the codebase.
Schema v5: listing.json
The listing.json file is a legacy distribution mechanism used for schema v5 (and historically v1-v4):
Location: databases/listing.json
Structure: Contains URLs to DB archives organized by schema version, ordered by latest-date-first
Update Process: Generated and uploaded atomically with each DB build (no separate update step)
This dual-distribution approach allows Grype to maintain backward compatibility with v5 while providing a more efficient distribution mechanism for v6 and future versions.
Implementation Notes:
Distribution file definitions reside in the grype repo, while the grype-db repo is responsible for generating DBs and creating/updating these distribution files
As long as Grype has been configured to point to the correct distribution file URL, the DBs can be stored separately, replaced with a service returning the distribution file contents, or mirrored for systems behind an air gap
Daily Workflows
There are two workflows that drive getting a new Grype DB out to OSS users:
The daily DB publisher workflow, which builds and publishes a Grype DB from the data obtained in the daily data sync workflow.
Daily Data Sync Workflow
This workflow takes the upstream vulnerability data (from canonical, redhat, debian, NVD, etc), processes it, and writes the results to OCI repos.
%%{ init: { 'flowchart': { 'curve': 'linear' } } }%%
flowchart LR
A1["Pull alpine"] --> B1["Publish to ghcr.io/anchore/grype-db/data/alpine:<date>"]
A2["Pull amazon"] --> B2["Publish to ghcr.io/anchore/grype-db/data/amazon:<date>"]
A3["Pull debian"] --> B3["Publish to ghcr.io/anchore/grype-db/data/debian:<date>"]
A4["Pull github"] --> B4["Publish to ghcr.io/anchore/grype-db/data/github:<date>"]
A5["Pull nvd"] --> B5["Publish to ghcr.io/anchore/grype-db/data/nvd:<date>"]
A6["..."] --> B6["... repeat for all upstream providers ..."]
style A6 fill:none,stroke:none
style B6 fill:none,stroke:none
Once all providers have been updated, a single vulnerability cache OCI repo is updated with all of the latest vulnerability data at ghcr.io/anchore/grype-db/data:<date>. This repo is what is used downstream by the DB publisher workflow to create Grype DBs.
The in-repo .grype-db.yaml and .vunnel.yaml configurations are used to define the upstream data sources, how to obtain them, and where to put the results locally.
Daily DB Publishing Workflow
This workflow takes the latest vulnerability data cache, builds a Grype DB, and publishes it for general consumption:
The manager/ directory contains all code responsible for driving the Daily DB Publisher workflow, generating DBs for all supported schema versions (currently v5 and v6) and making them available to the public.
1. Pull
Download the latest vulnerability data from various upstream data sources into a local directory. The destination for the provider data is in the data/vunnel directory.
2. Generate
Build databases for all supported schema versions based on the latest vulnerability data and upload them to Cloudflare R2 (S3-compatible storage).
v5: Only the DB archive is uploaded; discoverability happens in the next step
v6: Both the DB archive AND latest.json are uploaded atomically, making the DB immediately discoverable
3. Update Listing (v5 Only)
This step only applies to schema v5.
Generate and upload a new listing.json file to Cloudflare R2 based on the existing listing file and newly discovered DB archives.
The listing file is tested against installations of Grype to ensure scans can successfully discover and download the DB. The scan must have a non-zero count of matches to pass validation.
Once the listing file has been uploaded to databases/listing.json, user-facing Grype v5 installations can discover and download the new DB.
Note: Schema v6 does not require this step because the latest.json file is generated and uploaded atomically with the DB archive in step 2, with a 5-minute cache TTL for fast updates.
Conceptually, one or more invocations of Vunnel will produce a single data directory which Grype DB uses to create a Grype database:
flowchart LR
subgraph vunnel_runs[ ]
vunnel_alpine[<b>vunnel run alpine</b>]
vunnel_rhel[<b>vunnel run rhel</b>]
vunnel_nvd[<b>vunnel run nvd</b>]
vunnel_other[(...)]
end
subgraph data[ ]
alpine_data[./data/alpine/]
rhel_data[./data/rhel/]
nvd_data[./data/nvd/]
other_data[...]
end
db_processor[Grype-DB]
subgraph db_out[ ]
sqlite_db[vulnerability.db<br/><small>sqlite</small>]
end
vunnel_alpine -->|write| alpine_data
vunnel_rhel -->|write| rhel_data
vunnel_nvd -->|write| nvd_data
alpine_data -->|read| db_processor
rhel_data -->|read| db_processor
nvd_data -->|read| db_processor
db_processor -->|write| sqlite_db
db_processor:::Application
vunnel_alpine:::Application
vunnel_rhel:::Application
vunnel_nvd:::Application
sqlite_db:::Database@{ shape: db }
alpine_data:::Database@{ shape: db }
rhel_data:::Database@{ shape: db }
nvd_data:::Database@{ shape: db }
style vunnel_other fill:none,stroke:none
style other_data fill:none,stroke:none
style vunnel_runs fill:none,stroke:none
style data fill:none,stroke:none
style db_out fill:none,stroke:none
classDef Application fill:#e1ffe1,stroke:#424242,stroke-width:1px
classDef Database stroke-width:1px, stroke-dasharray:none, stroke:#424242, fill:#fff9c4, color:#000000
Integration with Grype DB
The Vunnel CLI tool is optimized to run a single provider at a time, not orchestrating multiple providers at once. Grype DB is the tool that collates output from multiple providers and produces a single database, and is ultimately responsible for orchestrating multiple Vunnel calls to prepare the input data:
flowchart LR
subgraph data[ ]
data_in[(./data/)]
end
build[grype-db build]
subgraph db_out[ ]
db[(vulnerability.db<br/><small>sqlite</small>)]
end
data_in -->|read| build
build -->|write| db
build:::Application
data_in:::Database@{ shape: db }
db:::Database@{ shape: db }
style data fill:none,stroke:none
style db_out fill:none,stroke:none
classDef Application fill:#e1ffe1,stroke:#424242,stroke-width:1px
classDef Database stroke-width:1px, stroke-dasharray:none, stroke:#424242, fill:#fff9c4, color:#000000
grype-db package
flowchart LR
subgraph db_in[ ]
db[vulnerability.db<br/><small>sqlite</small>]
end
package[grype-db package]
subgraph archive_out[ ]
archive[[vulnerability-db-DATE.tar.gz]]
end
db -->|read| package
package -->|write| archive
package:::Application
db:::Database@{ shape: db }
archive:::Database@{ shape: document }
style db_in fill:none,stroke:none
style archive_out fill:none,stroke:none
classDef Application fill:#e1ffe1,stroke:#424242,stroke-width:1px
classDef Database stroke-width:1px, stroke-dasharray:none, stroke:#424242, fill:#fff9c4, color:#000000
For more information about how Grype DB uses Vunnel see the Grype DB Architecture page.
Provider Architecture
A “Provider” is the core abstraction for Vunnel and represents a single source of vulnerability data. Vunnel is a CLI wrapper around multiple vulnerability data providers.
Provider Requirements
All provider implementations should:
Live under src/vunnel/providers in their own directory (e.g. the NVD provider code is under src/vunnel/providers/nvd/...)
Be independent from other vulnerability providers data — that is, the debian provider CANNOT reach into the NVD data provider directory to look up information (such as severity)
Follow the workspace conventions for downloaded provider inputs, produced results, and tracking of metadata
Workspace Conventions
Each provider has a “workspace” directory within the “vunnel root” directory (defaults to ./data) named after the provider.
data/ # the "vunnel root" directory└── alpine/ # the provider workspace directory ├── input/ # any file that needs to be downloaded and referenced should be stored here ├── results/ # schema-compliant vulnerability results (1 record per file) ├── checksums # listing of result file checksums (xxh64 algorithm) └── metadata.json # metadata about the input and result files
The metadata.json and checksums are written out after all results are written to results/. An example metadata.json:
provider: the name of the provider that generated the results
urls: the URLs that were referenced to generate the results
listing: the path to the checksums listing file that lists all of the results, the checksum of that file, and the algorithm used to checksum the file (and the same algorithm used for all contained checksums)
timestamp: the point in time when the results were generated or last updated
schema: the data shape that the current file conforms to
Result Format
All results from a provider are handled by a common base class helper (provider.Provider.results_writer()) and is driven by the application configuration (e.g. JSON flat files or SQLite database). The data shape of the results are self-describing via an envelope with a schema reference.
The schema field is a URL to the schema that describes the data shape of the item field
The identifier field should have a unique identifier within the context of the provider results
The item field is the actual vulnerability data, and the shape of this field is defined by the schema
Note that the identifier is 3.3/cve-2015-8366 and not just cve-2015-8366 in order to uniquely identify cve-2015-8366 as applied to the alpine 3.3 distro version among other records in the results directory.
Currently only JSON payloads are supported.
Vulnerability Schemas
Possible vulnerability schemas supported within the vunnel repo are:
If at any point a breaking change needs to be made to a provider (and say the schema remains the same), then you can set the __version__ attribute on the provider class to a new integer value (incrementing from 1 onwards). This is a way to indicate that the cached input/results are not compatible with the output of the current version of the provider, in which case the next invocation of the provider will delete the previous input and results before running.
Provider Configuration
Each provider has a configuration object defined next to the provider class. This object is used in the vunnel application configuration and is passed as input to the provider class. Take the debian provider configuration for example:
from dataclasses import dataclass, field
from vunnel import provider, result
@dataclass
classConfig:
runtime: provider.RuntimeConfig = field(
default_factory=lambda: provider.RuntimeConfig(
result_store=result.StoreStrategy.SQLITE,
existing_results=provider.ResultStatePolicy.DELETE_BEFORE_WRITE,
),
)
request_timeout: int=125
Configuration Requirements
Every provider configuration must:
Be a dataclass
Have a runtime field that is a provider.RuntimeConfig field
The runtime field is used to configure common behaviors of the provider that are enforced within the vunnel.provider.Provider subclass.
Runtime Configuration Options
on_error: what to do when the provider fails
action: choose to fail, skip, or retry when the failure occurs
retry_count: the number of times to retry the provider before failing (only applicable when action is retry)
retry_delay: the number of seconds to wait between retries (only applicable when action is retry)
input: what to do about the input data directory on failure (such as keep or delete)
results: what to do about the results data directory on failure (such as keep or delete)
existing_results: what to do when the provider is run again and the results directory already exists
delete-before-write: delete the existing results just before writing the first processed (new) result
delete: delete existing results before running the provider
keep: keep the existing results
existing_input: what to do when the provider is run again and the input directory already exists
delete: delete the existing input before running the provider
keep: keep the existing input
result_store: where to store the results
sqlite: store results as key-value form in a SQLite database, where keys are the record identifiers values are the json vulnerability records
flat-file: store results in JSON files named after the record identifiers
Any provider-specific config options can be added to the configuration object as needed (such as request_timeout, which is a common field).
Related Architecture
For more details on how Grype DB uses Vunnel output, see the Grype DB Architecture page.
Almost every Thursday the OSS team holds a “Gardening” live stream on the Anchore YouTube channel. Each week, we announce what time the live stream is happening in the Announcements on Discourse.
We hold open meetings with the community, on alternate Thursdays. These are on Zoom, and are not recorded or streamed. There is an optional agenda which can be filled in. Everyone is welcome. A webcam is not required.
Anchore Events
Anchore has a separate Events page, for announcing industry & corporate events, and webinars.
8.2 - Adopters
Adopters of Anchore Open Source Tools
Our tools are used by organisations and developer teams of all sizes. Below is a small sample of users of our tools, in public GitHub repositories.
Docker
SAP
Grafana
OpenTelemetry
Wolfi
Kubescape
More organisations below are all adopters of our tools, in public GitHub repositories.
Definitions of terms used in software security, SBOM generation, and vulnerability scanning
A
Artifact
In Syft’s JSON output format, “artifacts” refers to the array of software packages discovered during scanning.
Each artifact represents a single package (library, application, OS package, etc.) with its metadata, version, licenses, locations, and identifiers like CPE and PURL.
This is distinct from general software artifacts like binaries or container images.
A cryptographically signed statement about a software artifact that provides verifiable claims about its properties, such as provenance, build process, or security scan results.
Attestations establish trust in the software supply chain by allowing you to verify that an SBOM truly represents a specific artifact or that vulnerability scan results are authentic.
Why it matters: Attestations enable you to verify the authenticity and integrity of SBOMs generated by Syft and vulnerability reports from Grype, ensuring they haven’t been tampered with.
C
Cataloger
A cataloger is a component within Syft that specializes in discovering and extracting package information from specific ecosystems or file formats.
Each cataloger knows how to find and parse packages for a particular type (e.g., apk-cataloger for Alpine packages, npm-cataloger for Node.js packages).
When Syft scans a target, it runs multiple catalogers to comprehensively discover all software components.
Why it matters: The foundBy field in Syft’s JSON output tells you which cataloger discovered each package, which can help debug why certain packages appear in your SBOM or troubleshoot scanning issues.
A lightweight, standalone, executable package that includes everything needed to run a piece of software, including the code, runtime, system tools, libraries, and settings.
Container images are built from layers and typically run using container runtimes like Docker or containerd. See also OCI.
Why it matters: Both Syft and Grype can scan container images directly without requiring them to be running. Syft generates SBOMs from container images, and Grype scans them for vulnerabilities.
Common Platform Enumeration (CPE) is a standardized method for describing and identifying software applications, operating systems, and hardware devices.
CPEs are used in vulnerability databases to match software components with known vulnerabilities.
Formats:
URI binding: cpe:/{part}:{vendor}:{product}:{version}:{update}:{edition}:{language}
Why it matters: Syft generates CPEs for discovered packages (from the NVD dictionary or synthetic generation), which Grype then uses to match packages against vulnerability data.
Understanding CPEs helps you troubleshoot why certain vulnerabilities are or aren’t being detected relative to vulnerabilities from NVD.
Common Vulnerabilities and Exposures (CVE) is a standardized identifier for publicly known security vulnerabilities.
Each CVE ID uniquely identifies a specific vulnerability and provides a common reference point for discussing and tracking security issues.
Format example: CVE-2024-12345
Why it matters: Grype reports vulnerabilities by their CVE IDs, making it easy to research specific issues, understand their impact, and find remediation guidance.
Each match in a Grype scan references one or more CVE IDs.
Common Vulnerability Scoring System (CVSS) is an open framework for communicating the characteristics and severity of software vulnerabilities.
CVSS (base) scores range from 0.0 to 10.0, with higher scores indicating more severe vulnerabilities.
Severity ranges:
None: 0.0
Low: 0.1-3.9
Medium: 4.0-6.9
High: 7.0-8.9
Critical: 9.0-10.0
There are more dimensions to CVSS, including Temporal and Environmental scores, but the Base score is the most commonly used as a way to quickly assess severity.
Why it matters: Grype uses CVSS scores to categorize vulnerability severity, helping you prioritize which issues to fix first.
You can filter Grype results by severity level to focus on the most critical vulnerabilities.
CycloneDX is an open-source standard for creating Software Bill of Materials (SBOMs), supporting JSON and XML representations.
Why it matters: Syft can generate SBOMs in CycloneDX format (-o cyclonedx-json or -o cyclonedx-xml), which is widely supported by security tools and compliance platforms.
Grype can also scan CycloneDX SBOMs for vulnerabilities.
A software component that another piece of software relies on to function. Dependencies can be direct (explicitly required by your code) or transitive (required by your dependencies).
Understanding and tracking dependencies is crucial for security and license compliance.
Why it matters: Syft catalogs both direct and transitive dependencies in your software, creating a complete inventory.
Grype then scans all dependencies for vulnerabilities, not just your direct dependencies—important because transitive dependencies often contain hidden security risks.
Distro
Short for “distribution”, referring to a specific Linux distribution like Alpine, Ubuntu, Debian, or Red Hat. The distro information includes the distribution name and version (e.g., “alpine 3.18”).
Why it matters: Grype uses distro information to match OS packages against the correct vulnerability database.
Syft automatically detects the distro from files like /etc/os-release and includes it in the SBOM, ensuring accurate vulnerability matching.
Docker is a platform for developing, shipping, and running applications in containers. While Docker is a specific implementation, the term is often used colloquially to refer to container technology in general.
See Container image and OCI.
Why it matters: Syft and Grype can pull and scan images directly from Docker registries or analyze images in your local Docker daemon without needing Docker to be installed.
In software, an ecosystem refers to a package management system and its associated community, tools, and conventions.
Examples include npm (JavaScript), PyPI (Python), Maven Central (Java), and RubyGems (Ruby).
Different ecosystems have different package formats, naming conventions, and vulnerability data sources.
Why it matters: Syft supports dozens of package ecosystems, and each uses a different cataloger.
The ecosystem determines how packages are identified (PURL type), which metadata is captured, and which vulnerability data sources Grype uses for matching.
Exploit Prediction Scoring System (EPSS) is a data-driven framework that estimates the probability that a software vulnerability will be exploited in the wild within the next 30 days.
EPSS provides two complementary metrics:
Score: A probability value from 0.0 to 1.0 (0% to 100%) indicating the likelihood of exploitation. For example, a score of 0.00034 means a 0.034% probability of exploitation.
Percentile: A ranking showing what percentage of all CVEs have a lower EPSS score. For example, a percentile of 0.09274 means this CVE scores higher than 9.274% of all tracked vulnerabilities.
Unlike CVSS which measures theoretical severity, EPSS predicts actual exploitation probability by analyzing factors like available exploits, social media activity, and observed attacks (among other signals).
Why it matters: EPSS helps you prioritize vulnerabilities more effectively than severity alone. A critical CVSS vulnerability with a low EPSS score might be less urgent than a medium severity issue with a high EPSS score.
Grype can display EPSS scores alongside CVSS to help you focus remediation efforts on vulnerabilities that are both severe and likely to be exploited.
In the context of scanning for vulnerabilities, a false positive is a vulnerability-package match reported by a scanner that doesn’t actually affect the software package in question.
False positives can occur due to incorrect CPE matching, version misidentification, or when a vulnerability applies to one variant of a package but not another.
Why it matters: When Grype reports a false positive, you can use VEX documents or Grype’s ignore rules to suppress it, preventing alert fatigue and focusing on real security issues.
If you believe a match is incorrect, you can report it on GitHub to help improve Grype for everyone.
False negative
In the context of scanning for vulnerabilities, a false negative occurs when a scanner fails to detect a vulnerability that actually affects a software package.
False negatives can happen when vulnerability data is incomplete, when a package uses non-standard naming or versioning, when CPE or PURL identifiers don’t match correctly, or when the vulnerability database hasn’t been updated yet.
Why it matters: False negatives are more dangerous than false positives because they create a false sense of security.
To minimize false negatives, keep Grype’s vulnerability database updated regularly and understand that no scanner catches 100% of vulnerabilities—defense in depth and multiple security controls are essential.
K
KEV
Known Exploited Vulnerability (KEV) is a designation for vulnerabilities that have been confirmed as actively exploited in real-world attacks.
CISA (Cybersecurity and Infrastructure Security Agency) maintains the authoritative KEV catalog, which lists CVEs with evidence of active exploitation and
provides binding operational directives for federal agencies.
The CISA KEV catalog includes:
CVE identifiers for exploited vulnerabilities
The product and vendor affected
A brief description of the vulnerability
Required remediation actions
Due dates for federal agencies to patch
Vulnerabilities are added to the KEV catalog based on reliable evidence of active exploitation, such as public reporting, threat intelligence, or incident response data.
Why it matters: KEV status is a strong signal for prioritization—these vulnerabilities are being actively exploited right now.
When Grype identifies a vulnerability that’s on the CISA KEV list, you should treat it as urgent regardless of CVSS score.
A medium-severity KEV vulnerability poses more immediate risk than a critical-severity vulnerability that’s never been exploited.
Some organizations make KEV remediation mandatory within tight timeframes (e.g., 15 days for critical KEVs).
Container images are built as a series of filesystem layers, where each layer represents changes from a Dockerfile instruction. Layers are stacked together to create the final filesystem.
Why it matters: By default, Syft scans only the “squashed” view of an image (what you’d see if the container were running).
Use --scope all-layers to scan all layers, which can reveal packages that were installed then deleted, potentially exposing vulnerabilities in build-time dependencies.
A legal instrument governing the use and distribution of software. Software licenses range from permissive (MIT, Apache) to copyleft (GPL) to proprietary.
Why it matters: Syft extracts license information from packages and includes it in SBOMs, helping you ensure compliance with open source licenses and identify packages with incompatible or restricted licenses.
A match is a vulnerability finding in Grype’s output, representing a single package-vulnerability pair. Each match indicates that a specific package version is affected by a particular CVE.
A matcher is a component within Grype that compares package information against vulnerability data using specific matching strategies.
Different matchers handle different package types or ecosystems (e.g., distro matcher for OS packages, language matcher for application dependencies).
Why it matters: Grype uses multiple matchers to ensure comprehensive vulnerability coverage. The matcher used for each finding is included in detailed output, helping you understand how the match was made.
N
NVD
National Vulnerability Database (NVD) is the U.S. government repository known software vulnerabilities.
It provides comprehensive vulnerability information including CVE IDs, CVSS scores, and affected software configurations. The NVD is maintained by NIST.
Why it matters: The NVD is one of the primary vulnerability data sources used by Grype. Syft also uses the NVD’s CPE dictionary to generate CPEs for packages, enabling accurate vulnerability matching.
Open Container Initiative (OCI) is an open governance structure for creating industry standards around container formats and runtimes.
The OCI Image Specification defines the standard format for container images, ensuring interoperability across different container tools and platforms.
Why it matters: Syft and Grype work with OCI-compliant images from any registry (Docker Hub, GitHub Container Registry, Amazon ECR, etc.), not just Docker images. They can read images in OCI layout format directly from disk.
A bundle of software that can be installed and managed by a package manager. Packages typically include the software itself, metadata (like version and dependencies), and installation instructions.
Packages are the fundamental units tracked in an SBOM.
Why it matters: Every entry in a Syft-generated SBOM represents a package. Grype matches packages against vulnerability data to find security issues.
Understanding what constitutes a “package” in different ecosystems helps you interpret SBOM contents.
Package manager
A tool that automates the process of installing, upgrading, configuring, and removing software packages.
Examples include npm, pip, apt, yum, and Maven. Package managers maintain repositories of available packages and handle dependency resolution.
Why it matters: Syft discovers packages by reading package manager metadata files (like package.json, requirements.txt, or /var/lib/dpkg/status).
Each package manager stores information differently, which is why Syft needs ecosystem-specific catalogers.
Provenance
Information about the origin and build process of a software artifact, including who built it, when, from what source code, and using what tools.
Build provenance helps verify that software was built as expected and hasn’t been tampered with.
Why it matters: SBOMs generated by Syft during builds can be combined with provenance information to create comprehensive supply chain attestations, enabling you to verify both what’s in your software and how it was built.
Package URL (PURL) is a standardized way to identify and locate software packages across different package managers and ecosystems.
PURLs provide a uniform identifier that works across different systems.
Why it matters: Syft generates PURLs for all discovered packages, and Grype uses PURLs as one of the primary identifiers for vulnerability matching.
PURLs provide a consistent way to refer to packages across different SBOM formats.
In Syft’s JSON output, relationships describe connections between artifacts (packages), files, and sources (what was scanned).
For example, a relationship might indicate that a file is “contained-by” a package, or that one package “depends-on” another.
Why it matters: Relationships provide the graph structure of your software, showing not just what packages exist but how they’re connected.
This is essential for understanding dependency chains and reachability analysis.
Software Bill of Materials (SBOM) is a comprehensive inventory of all components, libraries, and modules that make up a piece of software.
Like a list of ingredients on food packaging, an SBOM provides transparency into what’s included in your software, enabling security analysis, license compliance, and supply chain risk management.
Why it matters: Syft generates SBOMs that you can use with Grype for vulnerability scanning, share with customers for transparency, or use for license compliance.
SBOMs are becoming required by regulations and standards like Executive Order 14028.
A classification of how serious a vulnerability is, typically based on CVSS scores.
Common severity levels are Critical, High, Medium, Low, and Negligible (or None).
Why it matters: Grype reports vulnerability severity to help you prioritize remediation efforts. You can filter Grype output by severity (e.g., --fail-on high to fail CI builds for high or critical vulnerabilities).
The software supply chain encompasses all the components, processes, and steps involved in creating, building, and delivering software.
This includes source code, dependencies, build tools, CI/CD pipelines, and distribution mechanisms.
Securing the software supply chain helps prevent attacks that target the development and delivery process.
Why it matters: Syft and Grype are key tools in supply chain security. Syft provides visibility into what’s in your software (SBOM), and Grype identifies known vulnerabilities, helping you secure each link in the chain.
Source
In Syft’s JSON output, the “source” object describes what was scanned—whether it was a container image, directory, file archive, or other input. It includes details like image name, digest, and tags.
Why it matters: The source information helps you correlate SBOMs with specific artifacts, especially important when tracking multiple image versions or builds.
Software Package Data Exchange (SPDX) is an open standard for communicating software bill of materials information, including components, licenses, copyrights, and security references.
SPDX is an ISO/IEC standard (ISO/IEC 5962:2021) and supports multiple formats including JSON, YAML, XML, and tag-value.
Why it matters: Syft can generate SBOMs in SPDX format (-o spdx-json or -o spdx-tag-value), which is widely supported by compliance tools and required by many organizations and regulations.
Grype can also scan SPDX SBOMs for vulnerabilities.
The “squashed” view of a container image represents the final filesystem that would be visible if you ran the container.
It’s the result of applying all image layers in sequence, where later layers can override or delete files from earlier layers.
Why it matters: Syft scans the squashed view by default (what you actually run), but you can use --scope all-layers to also see packages that existed in intermediate layers but were deleted before the final image.
Vulnerability Exploitability eXchange (VEX) is a series of formats for communicating information about the exploitability status of vulnerabilities in software products.
VEX documents allow software vendors to provide context about whether identified vulnerabilities actually affect their product, helping users prioritize remediation efforts.
Why it matters: Grype can consume VEX documents to suppress false positives or provide additional context about vulnerabilities.
When Grype reports a vulnerability that doesn’t actually affect your application, you can create a VEX document explaining why it’s not exploitable.
A security weakness, flaw, or defect in software that can be exploited by an attacker to perform unauthorized actions, compromise systems, steal data, or cause harm.
Vulnerabilities can arise from coding errors, design flaws, misconfigurations, or outdated dependencies with known security issues.
Not all vulnerabilities affect all users of a package. Whether a vulnerability impacts you depends on:
The specific version you’re using
Which features or code paths you actually invoke
Your deployment configuration and environment
Whether compensating security controls are in place
Why it matters: Grype identifies vulnerabilities in the packages discovered by Syft, enabling you to find and fix security issues before they can be exploited.
Not all vulnerabilities are equally serious—use severity ratings (CVSS) and exploitation probability (EPSS) to prioritize fixes.
Understanding the context of a vulnerability helps you assess real risk rather than just responding to every CVE.
A repository of known security vulnerabilities, their affected software versions, severity scores, and remediation information.
Vulnerability databases aggregate data from multiple sources like NVD, security advisories, and vendor bulletins.
Why it matters: Grype downloads and maintains a local vulnerability database that’s updated daily.
The database quality directly impacts scan accuracy—Grype uses curated, high-quality data from multiple providers to minimize false positives and false negatives.
A tool that identifies known security vulnerabilities in software by comparing components against vulnerability databases.
Vulnerability scanners like Grype analyze software artifacts (container images, filesystems, or SBOMs) and report potential security issues that should be addressed.
Why it matters: Grype is a vulnerability scanner that works seamlessly with Syft-generated SBOMs.
You can scan images directly with Grype, or generate an SBOM with Syft first and scan it separately, enabling workflows where SBOMs are generated once and scanned multiple times as new vulnerabilities are discovered.