1 - SBOM Generation
An SBOM, or Software Bill of Materials, is a detailed list of all the components, libraries, and modules that make up a piece of software.
For a developer, having an SBOM is crucial for tracking dependencies, quickly identifying known vulnerabilities within those components, and ensuring license compliance.
For a consumer or organization using the software, an SBOM provides transparency into the software’s supply chain, allowing them to assess potential security risks and understand what’s “under the hood.”
Syft 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.
1.1 - Getting Started
Syft is a CLI tool for generating a Software Bill of Materials (SBOM) from container images and filesystems.
Installation
Syft is provided as a single compiled executable. Run the command for your platform to download the latest release. The full list of official and community maintained packages can be found on the installation page.
curl -sSfL <https://get.anchore.io/syft> | sudo sh -s -- -b /usr/local/bin
brew install syft
nuget install Anchore.Syft
See the installation guide for more options including package managers and manual installation.
Display the contents of a public container image
Run syft
against a small container image, which will be pulled from DockerHub. The output will be a simple human-readable table.
syft alpine:latest
The output will look similar to the following table.
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
...
Learn more
Syft supports more than just containers. Learn more about Supported SourcesCreate an industry-standard SBOM
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 -o table -o spdx-json=alpine.spdx.json -o cyclonedx-json=alpine.cdx.json
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 (note: 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:
"alpine-baselayout"
"alpine-baselayout-data"
"alpine-keys"
"alpine-release"
"apk-tools"
"busybox"
"busybox-binsh"
...
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
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.
Next steps
Now that you’ve generated your first SBOM, here’s what you can do next:
- Scan for vulnerabilities: Use Grype to find security issues in your SBOMs
- Check licenses: Learn about License Scanning to understand dependency licenses
- Customize output: Explore different Output Formats for various tools and workflows
- Scan different sources: Discover all Supported Sources Syft can analyze
- Query SBOM data: Master Working with Syft JSON for advanced data extraction
1.2 - Supported Sources
Syft can generate an SBOM from a variety of sources 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 source, 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) |
oci-dir |
Read directly from a path on disk for OCI layout directories (from Skopeo or otherwise) |
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) |
Source-Specific Behaviors
Container Image Sources
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 ofdocker.io/alpine:latest
), Syft assumesdocker.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 source type (i.e. no --from
flag), Syft attempts to resolve the image using the following sources 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 source.
See Configuration for more details.
Directory Sources
When you provide a directory path as the source, 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 informationsysfs
- Virtual filesystem for kernel and device informationdevfs
/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 Sources
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 Sources
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.
Create OCI sources without a registry
OCI archive from an image:
skopeo copy \
docker://alpine@sha256:eafc1edb577d2e9b458664a15f23ea1c370214193226069eb22921169fc7e43f \
oci-archive:alpine.tar
OCI layout directory from an image:
skopeo copy \
docker://alpine@sha256:eafc1edb577d2e9b458664a15f23ea1c370214193226069eb22921169fc7e43f \
oci:alpine
Container image archive from an image:
docker save -o alpine.tar alpine:latest
Container Runtime Configuration
Image Availability and Authentication
When using container runtime sources (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:
Source | 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 | |
CONTAINER_PASSPHRASE |
Passphrase for the SSH key | |
Containerd | CONTAINERD_ADDRESS |
Containerd socket address (overrides default /run/containerd/containerd.sock ) |
CONTAINERD_NAMESPACE |
Containerd namespace (defaults to default ) |
Podman Daemon Requirements
Unlike Docker Desktop, which typically auto-starts, Podman requires explicitly starting the service.
Syft attempts to connect to Podman using the following methods in order:
-
Unix Socket (primary)
- Checks
CONTAINER_HOST
environment variable first - Falls back to Podman config files
- Finally tries default socket locations ($XDG_RUNTIME_DIR/podman/podman.sock
and
/run/podman/podman.sock`)
- Checks
-
SSH (fallback)
- Configured via
CONTAINER_HOST
,CONTAINER_SSHKEY
, andCONTAINER_PASSPHRASE
environment variables - Used for remote Podman instances
- Configured via
Direct Registry Access
The registry
source 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.
1.3 - Output Formats
Syft supports multiple output formats to fit different workflows and requirements by using the -o
(or --output
) flag:
syft <image> -o <format>
Available formats
Syft-native formats
-o ARG |
Description |
---|---|
table |
A columnar summary (default) |
json |
Native output for Syft—use this to get as much information out of Syft as possible! (see the JSON schema) |
purls |
A line-separated list of Package URLs (PURLs) for all discovered packages |
github-json |
A JSON report conforming to GitHub’s dependency snapshot format |
template |
Lets you specify a custom output format via Go templates (see Templates for more detail) |
text |
A row-oriented, human-and-machine-friendly output |
CycloneDX
CycloneDX is an OWASP-maintained industry standard SBOM format.
-o ARG |
Description |
---|---|
cyclonedx-json |
A JSON report conforming to the CycloneDX specification |
cyclonedx-xml |
An XML report conforming to the CycloneDX specification |
SPDX
SPDX (Software Package Data Exchange) is an ISO/IEC 5962:2021 industry standard SBOM format.
-o ARG |
Description |
---|---|
spdx-json |
A JSON report conforming to the SPDX JSON Schema |
spdx-tag-value |
A tag-value formatted report conforming to the SPDX specification |
Format versions
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.4
syft <source> -o cyclonedx-json@1.4
# Use SPDX JSON version 2.2
syft <source> -o spdx-json@2.2
# Default to latest version if not specified
syft <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.
Format examples
NAME VERSION TYPE
busybox 1.37.0 binary
{
"artifacts": [
{
"id": "74d9294c42941b37",
"name": "busybox",
"version": "1.37.0",
"type": "binary",
"foundBy": "binary-classifier-cataloger",
"locations": [
{
"path": "/bin/[",
"layerID": "sha256:6aba5e0d32d91e3e923854dcb30588dc4112bfa1dae82b89535ad31d322a7b19",
"accessPath": "/bin/busybox",
"annotations": { "evidence": "primary" }
}
],
"licenses": [],
"language": "",
"cpes": [{ "cpe": "cpe:2.3:a:busybox:busybox:1.37.0:*:*:*:*:*:*:*", "source": "nvd-cpe-dictionary" }],
"purl": "pkg:generic/busybox@1.37.0",
"metadataType": "binary-signature",
"metadata": {
"matches": [
{
"classifier": "busybox-binary",
"location": {
"path": "/bin/[",
"layerID": "sha256:6aba5e0d32d91e3e923854dcb30588dc4112bfa1dae82b89535ad31d322a7b19",
"accessPath": "/bin/busybox",
"annotations": { "evidence": "primary" }
}
}
]
}
}
],
"artifactRelationships": [
{
"parent": "74d9294c42941b37",
"child": "de0bf36b25443562",
"type": "evident-by",
"metadata": { "kind": "primary" }
},
{
"parent": "cddc8af5547af9de5e6fb66b36d66ef7418561204e1255ae528d0b2c919d09a3",
"child": "74d9294c42941b37",
"type": "contains"
}
],
"files": [
{
"id": "de0bf36b25443562",
"location": {
"path": "/bin/[",
"layerID": "sha256:6aba5e0d32d91e3e923854dcb30588dc4112bfa1dae82b89535ad31d322a7b19"
},
"metadata": {
"mode": 755,
"type": "RegularFile",
"userID": 0,
"groupID": 0,
"mimeType": "application/x-sharedlib",
"size": 1119784
},
"digests": [
{ "algorithm": "sha1", "value": "99f9c7cb06f6f8f074b5c16245f295e33844855a" },
{ "algorithm": "sha256", "value": "8a4212147744cedcf7f679c81921942c81eb3b8d356bbb2b08b51336b2fe8add" }
],
"executable": {
"format": "elf",
"hasExports": true,
"hasEntrypoint": true,
"importedLibraries": ["libm.so.6", "libresolv.so.2", "libc.so.6"],
"elfSecurityFeatures": {
"symbolTableStripped": true,
"stackCanary": false,
"nx": true,
"relRO": "partial",
"pie": true,
"dso": true,
"safeStack": false
}
}
},
{
"id": "b240ee11665506ce",
"location": {
"path": "/bin/getconf",
"layerID": "sha256:6aba5e0d32d91e3e923854dcb30588dc4112bfa1dae82b89535ad31d322a7b19"
},
"executable": {
"format": "elf",
"hasExports": true,
"hasEntrypoint": true,
"importedLibraries": ["libc.so.6"],
"elfSecurityFeatures": {
"symbolTableStripped": true,
"stackCanary": false,
"nx": true,
"relRO": "full",
"pie": true,
"dso": true,
"safeStack": false
}
},
"unknowns": ["unknowns-labeler: no package identified in executable file"]
},
{
"id": "48a6e9fa63c5f6cc",
"location": {
"path": "/lib/ld-linux-aarch64.so.1",
"layerID": "sha256:6aba5e0d32d91e3e923854dcb30588dc4112bfa1dae82b89535ad31d322a7b19"
},
"executable": {
"format": "elf",
"hasExports": true,
"hasEntrypoint": true,
"importedLibraries": [],
"elfSecurityFeatures": {
"symbolTableStripped": true,
"stackCanary": true,
"nx": true,
"relRO": "full",
"pie": false,
"dso": true,
"safeStack": false
}
},
"unknowns": ["unknowns-labeler: no package identified in executable file"]
},
{
"id": "a2dc8cb35e1e0485",
"location": {
"path": "/lib/libc.so.6",
"layerID": "sha256:6aba5e0d32d91e3e923854dcb30588dc4112bfa1dae82b89535ad31d322a7b19"
},
"executable": {
"format": "elf",
"hasExports": true,
"hasEntrypoint": true,
"importedLibraries": ["ld-linux-aarch64.so.1"],
"elfSecurityFeatures": {
"symbolTableStripped": true,
"stackCanary": true,
"nx": true,
"relRO": "full",
"pie": false,
"dso": true,
"safeStack": false
}
},
"unknowns": ["unknowns-labeler: no package identified in executable file"]
},
{
"id": "8746a5a87ab9e597",
"location": {
"path": "/lib/libm.so.6",
"layerID": "sha256:6aba5e0d32d91e3e923854dcb30588dc4112bfa1dae82b89535ad31d322a7b19"
},
"executable": {
"format": "elf",
"hasExports": true,
"hasEntrypoint": false,
"importedLibraries": ["libc.so.6", "ld-linux-aarch64.so.1"],
"elfSecurityFeatures": {
"symbolTableStripped": true,
"stackCanary": true,
"nx": true,
"relRO": "full",
"pie": false,
"dso": true,
"safeStack": false
}
},
"unknowns": ["unknowns-labeler: no package identified in executable file"]
},
{
"id": "75835d9334e3cd14",
"location": {
"path": "/lib/libnss_compat.so.2",
"layerID": "sha256:6aba5e0d32d91e3e923854dcb30588dc4112bfa1dae82b89535ad31d322a7b19"
},
"executable": {
"format": "elf",
"hasExports": true,
"hasEntrypoint": false,
"importedLibraries": ["libc.so.6", "ld-linux-aarch64.so.1"],
"elfSecurityFeatures": {
"symbolTableStripped": true,
"stackCanary": true,
"nx": true,
"relRO": "full",
"pie": false,
"dso": true,
"safeStack": false
}
},
"unknowns": ["unknowns-labeler: no package identified in executable file"]
},
{
"id": "a75d014485c88e79",
"location": {
"path": "/lib/libnss_dns.so.2",
"layerID": "sha256:6aba5e0d32d91e3e923854dcb30588dc4112bfa1dae82b89535ad31d322a7b19"
},
"executable": {
"format": "elf",
"hasExports": true,
"hasEntrypoint": false,
"importedLibraries": ["libc.so.6"],
"elfSecurityFeatures": {
"symbolTableStripped": true,
"stackCanary": false,
"nx": true,
"relRO": "full",
"pie": false,
"dso": true,
"safeStack": false
}
},
"unknowns": ["unknowns-labeler: no package identified in executable file"]
},
{
"id": "b5abc725c65d58cf",
"location": {
"path": "/lib/libnss_files.so.2",
"layerID": "sha256:6aba5e0d32d91e3e923854dcb30588dc4112bfa1dae82b89535ad31d322a7b19"
},
"executable": {
"format": "elf",
"hasExports": true,
"hasEntrypoint": false,
"importedLibraries": ["libc.so.6"],
"elfSecurityFeatures": {
"symbolTableStripped": true,
"stackCanary": false,
"nx": true,
"relRO": "full",
"pie": false,
"dso": true,
"safeStack": false
}
},
"unknowns": ["unknowns-labeler: no package identified in executable file"]
},
{
"id": "8570ef9dff59aa56",
"location": {
"path": "/lib/libnss_hesiod.so.2",
"layerID": "sha256:6aba5e0d32d91e3e923854dcb30588dc4112bfa1dae82b89535ad31d322a7b19"
},
"executable": {
"format": "elf",
"hasExports": true,
"hasEntrypoint": false,
"importedLibraries": ["libresolv.so.2", "libc.so.6", "ld-linux-aarch64.so.1"],
"elfSecurityFeatures": {
"symbolTableStripped": true,
"stackCanary": true,
"nx": true,
"relRO": "full",
"pie": false,
"dso": true,
"safeStack": false
}
},
"unknowns": ["unknowns-labeler: no package identified in executable file"]
},
{
"id": "585855f0b92c8232",
"location": {
"path": "/lib/libpthread.so.0",
"layerID": "sha256:6aba5e0d32d91e3e923854dcb30588dc4112bfa1dae82b89535ad31d322a7b19"
},
"executable": {
"format": "elf",
"hasExports": true,
"hasEntrypoint": false,
"importedLibraries": ["libc.so.6"],
"elfSecurityFeatures": {
"symbolTableStripped": true,
"stackCanary": false,
"nx": true,
"relRO": "full",
"pie": false,
"dso": true,
"safeStack": false
}
},
"unknowns": ["unknowns-labeler: no package identified in executable file"]
},
{
"id": "ee8c205846a71e54",
"location": {
"path": "/lib/libresolv.so.2",
"layerID": "sha256:6aba5e0d32d91e3e923854dcb30588dc4112bfa1dae82b89535ad31d322a7b19"
},
"executable": {
"format": "elf",
"hasExports": true,
"hasEntrypoint": false,
"importedLibraries": ["libc.so.6", "ld-linux-aarch64.so.1"],
"elfSecurityFeatures": {
"symbolTableStripped": true,
"stackCanary": true,
"nx": true,
"relRO": "full",
"pie": false,
"dso": true,
"safeStack": false
}
},
"unknowns": ["unknowns-labeler: no package identified in executable file"]
}
],
"source": {
"id": "cddc8af5547af9de5e6fb66b36d66ef7418561204e1255ae528d0b2c919d09a3",
"name": "busybox",
"version": "sha256:cddc8af5547af9de5e6fb66b36d66ef7418561204e1255ae528d0b2c919d09a3",
"type": "image",
"metadata": {
"userInput": "busybox:latest",
"imageID": "sha256:e8291c1a323abf610ebeb32699b8df3e8046823b5dfbf795d888c9c6a73aeff8",
"manifestDigest": "sha256:cddc8af5547af9de5e6fb66b36d66ef7418561204e1255ae528d0b2c919d09a3",
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"tags": [],
"imageSize": 4170750,
"layers": [
{
"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
"digest": "sha256:6aba5e0d32d91e3e923854dcb30588dc4112bfa1dae82b89535ad31d322a7b19",
"size": 4170750
}
],
"manifest": "ewoJInNjaGVtYVZlcnNpb24iOiAyLAoJIm1lZGlhVHlwZSI6ICJhcHBsaWNhdGlvbi92bmQub2NpLmltYWdlLm1hbmlmZXN0LnYxK2pzb24iLAoJImNvbmZpZyI6IHsKCQkibWVkaWFUeXBlIjogImFwcGxpY2F0aW9uL3ZuZC5vY2kuaW1hZ2UuY29uZmlnLnYxK2pzb24iLAoJCSJkaWdlc3QiOiAic2hhMjU2OmU4MjkxYzFhMzIzYWJmNjEwZWJlYjMyNjk5YjhkZjNlODA0NjgyM2I1ZGZiZjc5NWQ4ODhjOWM2YTczYWVmZjgiLAoJCSJzaXplIjogNDc3Cgl9LAoJImxheWVycyI6IFsKCQl7CgkJCSJtZWRpYVR5cGUiOiAiYXBwbGljYXRpb24vdm5kLm9jaS5pbWFnZS5sYXllci52MS50YXIrZ3ppcCIsCgkJCSJkaWdlc3QiOiAic2hhMjU2OjQ5OWJjZjNjOGVhZDhlZjI1NzBmN2VlOGU0YWI1YTQ0ODk2NDdkNjdkZDFjMWI0MjVmZGJkNGE3NGY0YjQzODYiLAoJCQkic2l6ZSI6IDE5MDI3NjYKCQl9CgldLAoJImFubm90YXRpb25zIjogewoJCSJvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudXJsIjogImh0dHBzOi8vZ2l0aHViLmNvbS9kb2NrZXItbGlicmFyeS9idXN5Ym94IiwKCQkib3JnLm9wZW5jb250YWluZXJzLmltYWdlLnZlcnNpb24iOiAiMS4zNy4wLWdsaWJjIgoJfQp9Cg==",
"config": "ewoJImNvbmZpZyI6IHsKCQkiQ21kIjogWwoJCQkic2giCgkJXSwKCQkiRW52IjogWwoJCQkiUEFUSD0vdXNyL2xvY2FsL3NiaW46L3Vzci9sb2NhbC9iaW46L3Vzci9zYmluOi91c3IvYmluOi9zYmluOi9iaW4iCgkJXQoJfSwKCSJjcmVhdGVkIjogIjIwMjQtMDktMjZUMjE6MzE6NDJaIiwKCSJoaXN0b3J5IjogWwoJCXsKCQkJImNyZWF0ZWQiOiAiMjAyNC0wOS0yNlQyMTozMTo0MloiLAoJCQkiY3JlYXRlZF9ieSI6ICJCdXN5Qm94IDEuMzcuMCAoZ2xpYmMpLCBEZWJpYW4gMTMiCgkJfQoJXSwKCSJyb290ZnMiOiB7CgkJInR5cGUiOiAibGF5ZXJzIiwKCQkiZGlmZl9pZHMiOiBbCgkJCSJzaGEyNTY6NmFiYTVlMGQzMmQ5MWUzZTkyMzg1NGRjYjMwNTg4ZGM0MTEyYmZhMWRhZTgyYjg5NTM1YWQzMWQzMjJhN2IxOSIKCQldCgl9LAoJImFyY2hpdGVjdHVyZSI6ICJhcm02NCIsCgkib3MiOiAibGludXgiLAoJInZhcmlhbnQiOiAidjgiCn0K",
"repoDigests": [
"index.docker.io/library/busybox@sha256:d82f458899c9696cb26a7c02d5568f81c8c8223f8661bb2a7988b269c8b9051e"
],
"architecture": "arm64",
"os": "linux"
}
},
"distro": {
"prettyName": "BusyBox v1.37.0",
"name": "busybox",
"id": "busybox",
"idLike": ["busybox"],
"version": "1.37.0",
"versionID": "1.37.0"
},
"descriptor": {
"name": "syft",
"version": "1.33.0",
"configuration": {
"catalogers": {
"requested": { "default": ["image", "file"] },
"used": [
"alpm-db-cataloger",
"apk-db-cataloger",
"binary-classifier-cataloger",
"bitnami-cataloger",
"cargo-auditable-binary-cataloger",
"conan-info-cataloger",
"dotnet-deps-binary-cataloger",
"dotnet-packages-lock-cataloger",
"dpkg-db-cataloger",
"elf-binary-package-cataloger",
"file-content-cataloger",
"file-digest-cataloger",
"file-executable-cataloger",
"file-metadata-cataloger",
"go-module-binary-cataloger",
"graalvm-native-image-cataloger",
"homebrew-cataloger",
"java-archive-cataloger",
"java-jvm-cataloger",
"javascript-package-cataloger",
"linux-kernel-cataloger",
"lua-rock-cataloger",
"nix-cataloger",
"pe-binary-package-cataloger",
"php-composer-installed-cataloger",
"php-interpreter-cataloger",
"php-pear-serialized-cataloger",
"portage-cataloger",
"python-installed-package-cataloger",
"r-package-cataloger",
"rpm-db-cataloger",
"ruby-installed-gemspec-cataloger",
"wordpress-plugins-cataloger"
]
},
"data-generation": { "generate-cpes": true },
"files": {
"content": { "globs": null, "skip-files-above-size": 0 },
"hashers": ["sha-1", "sha-256"],
"selection": "owned-by-package"
},
"licenses": { "coverage": 75, "include-content": "none" },
"packages": {
"binary": [
"python-binary",
"python-binary-lib",
"pypy-binary-lib",
"go-binary",
"julia-binary",
"helm",
"redis-binary",
"nodejs-binary",
"go-binary-hint",
"busybox-binary",
"util-linux-binary",
"haproxy-binary",
"perl-binary",
"php-composer-binary",
"httpd-binary",
"memcached-binary",
"traefik-binary",
"arangodb-binary",
"postgresql-binary",
"mysql-binary",
"mysql-binary",
"mysql-binary",
"xtrabackup-binary",
"mariadb-binary",
"rust-standard-library-linux",
"rust-standard-library-macos",
"ruby-binary",
"erlang-binary",
"erlang-alpine-binary",
"erlang-library",
"swipl-binary",
"dart-binary",
"haskell-ghc-binary",
"haskell-cabal-binary",
"haskell-stack-binary",
"consul-binary",
"hashicorp-vault-binary",
"nginx-binary",
"bash-binary",
"openssl-binary",
"gcc-binary",
"fluent-bit-binary",
"wordpress-cli-binary",
"curl-binary",
"lighttpd-binary",
"proftpd-binary",
"zstd-binary",
"xz-binary",
"gzip-binary",
"sqlcipher-binary",
"jq-binary",
"chrome-binary",
"ffmpeg-binary",
"java-binary",
"java-jdb-binary"
],
"dotnet": {
"dep-packages-must-claim-dll": true,
"dep-packages-must-have-dll": false,
"propagate-dll-claims-to-parents": true,
"relax-dll-claims-when-bundling-detected": true
},
"golang": {
"local-mod-cache-dir": "/go/pkg/mod",
"local-vendor-dir": "",
"main-module-version": { "from-build-settings": true, "from-contents": false, "from-ld-flags": true },
"proxies": ["https://proxy.golang.org", "direct"],
"search-local-mod-cache-licenses": false,
"search-local-vendor-licenses": false,
"search-remote-licenses": false
},
"java-archive": {
"include-indexed-archives": true,
"include-unindexed-archives": false,
"maven-base-url": "https://repo1.maven.org/maven2",
"maven-localrepository-dir": "/.m2/repository",
"max-parent-recursive-depth": 0,
"resolve-transitive-dependencies": false,
"use-maven-localrepository": false,
"use-network": false
},
"javascript": {
"include-dev-dependencies": false,
"npm-base-url": "https://registry.npmjs.org",
"search-remote-licenses": false
},
"linux-kernel": { "catalog-modules": true },
"nix": { "capture-owned-files": false },
"python": { "guess-unpinned-requirements": false }
},
"relationships": {
"exclude-binary-packages-with-file-ownership-overlap": true,
"package-file-ownership": true,
"package-file-ownership-overlap": true
},
"search": { "scope": "squashed" }
}
},
"schema": {
"version": "16.0.39",
"url": "https://raw.githubusercontent.com/anchore/syft/main/schema/json/schema-16.0.39.json"
}
}
pkg:generic/busybox@1.37.0
{
"$schema": "http://cyclonedx.org/schema/bom-1.6.schema.json",
"bomFormat": "CycloneDX",
"specVersion": "1.6",
"serialNumber": "urn:uuid:ad79379e-ec73-4989-b6b7-31c113221b72",
"version": 1,
"metadata": {
"timestamp": "2025-10-09T14:08:19Z",
"tools": { "components": [{ "type": "application", "author": "anchore", "name": "syft", "version": "1.33.0" }] },
"component": {
"bom-ref": "84d86520b9546322",
"type": "container",
"name": "busybox",
"version": "sha256:cddc8af5547af9de5e6fb66b36d66ef7418561204e1255ae528d0b2c919d09a3"
}
},
"components": [
{
"bom-ref": "pkg:generic/busybox@1.37.0?package-id=74d9294c42941b37",
"type": "application",
"name": "busybox",
"version": "1.37.0",
"cpe": "cpe:2.3:a:busybox:busybox:1.37.0:*:*:*:*:*:*:*",
"purl": "pkg:generic/busybox@1.37.0",
"properties": [
{ "name": "syft:package:foundBy", "value": "binary-classifier-cataloger" },
{ "name": "syft:package:type", "value": "binary" },
{ "name": "syft:package:metadataType", "value": "binary-signature" },
{
"name": "syft:location:0:layerID",
"value": "sha256:6aba5e0d32d91e3e923854dcb30588dc4112bfa1dae82b89535ad31d322a7b19"
},
{ "name": "syft:location:0:path", "value": "/bin/[" }
]
},
{
"bom-ref": "os:busybox@1.37.0",
"type": "operating-system",
"name": "busybox",
"version": "1.37.0",
"description": "BusyBox v1.37.0",
"swid": { "tagId": "busybox", "name": "busybox", "version": "1.37.0" },
"properties": [
{ "name": "syft:distro:extendedSupport", "value": "false" },
{ "name": "syft:distro:id", "value": "busybox" },
{ "name": "syft:distro:idLike:0", "value": "busybox" },
{ "name": "syft:distro:prettyName", "value": "BusyBox v1.37.0" },
{ "name": "syft:distro:versionID", "value": "1.37.0" }
]
},
{
"bom-ref": "de0bf36b25443562",
"type": "file",
"name": "/bin/[",
"hashes": [
{ "alg": "SHA-1", "content": "99f9c7cb06f6f8f074b5c16245f295e33844855a" },
{ "alg": "SHA-256", "content": "8a4212147744cedcf7f679c81921942c81eb3b8d356bbb2b08b51336b2fe8add" }
]
}
]
}
<?xml version="1.0" encoding="UTF-8"?>
<bom xmlns="http://cyclonedx.org/schema/bom/1.6" serialNumber="urn:uuid:34686a58-0f6f-42ef-93ea-db6ce62f4dec" version="1"><metadata><timestamp>2025-10-09T14:08:20Z</timestamp><tools><components><component type="application"><author>anchore</author><name>syft</name><version>1.33.0</version></component></components></tools><component bom-ref="84d86520b9546322" type="container"><name>busybox</name><version>sha256:cddc8af5547af9de5e6fb66b36d66ef7418561204e1255ae528d0b2c919d09a3</version></component></metadata><components><component bom-ref="pkg:generic/busybox@1.37.0?package-id=74d9294c42941b37" type="application"><name>busybox</name><version>1.37.0</version><cpe>cpe:2.3:a:busybox:busybox:1.37.0:*:*:*:*:*:*:*</cpe><purl>pkg:generic/busybox@1.37.0</purl><properties><property name="syft:package:foundBy">binary-classifier-cataloger</property><property name="syft:package:type">binary</property><property name="syft:package:metadataType">binary-signature</property><property name="syft:location:0:layerID">sha256:6aba5e0d32d91e3e923854dcb30588dc4112bfa1dae82b89535ad31d322a7b19</property><property name="syft:location:0:path">/bin/[</property></properties></component><component bom-ref="os:busybox@1.37.0" type="operating-system"><name>busybox</name><version>1.37.0</version><description>BusyBox v1.37.0</description><swid tagId="busybox" name="busybox" version="1.37.0"></swid><properties><property name="syft:distro:extendedSupport">false</property><property name="syft:distro:id">busybox</property><property name="syft:distro:idLike:0">busybox</property><property name="syft:distro:prettyName">BusyBox v1.37.0</property><property name="syft:distro:versionID">1.37.0</property></properties></component><component bom-ref="de0bf36b25443562" type="file"><name>/bin/[</name><hashes><hash alg="SHA-1">99f9c7cb06f6f8f074b5c16245f295e33844855a</hash><hash alg="SHA-256">8a4212147744cedcf7f679c81921942c81eb3b8d356bbb2b08b51336b2fe8add</hash></hashes></component></components></bom>
{
"spdxVersion": "SPDX-2.3",
"dataLicense": "CC0-1.0",
"SPDXID": "SPDXRef-DOCUMENT",
"name": "busybox",
"documentNamespace": "https://anchore.com/syft/image/busybox-528e282e-94ed-49cc-9050-e1cd5bf3c766",
"creationInfo": {
"licenseListVersion": "3.27",
"creators": ["Organization: Anchore, Inc", "Tool: syft-1.33.0"],
"created": "2025-10-09T14:08:20Z"
},
"packages": [
{
"name": "busybox",
"SPDXID": "SPDXRef-Package-binary-busybox-74d9294c42941b37",
"versionInfo": "1.37.0",
"supplier": "NOASSERTION",
"downloadLocation": "NOASSERTION",
"filesAnalyzed": false,
"sourceInfo": "acquired package info from the following paths: /bin/[",
"licenseConcluded": "NOASSERTION",
"licenseDeclared": "NOASSERTION",
"copyrightText": "NOASSERTION",
"externalRefs": [
{
"referenceCategory": "SECURITY",
"referenceType": "cpe23Type",
"referenceLocator": "cpe:2.3:a:busybox:busybox:1.37.0:*:*:*:*:*:*:*"
},
{
"referenceCategory": "PACKAGE-MANAGER",
"referenceType": "purl",
"referenceLocator": "pkg:generic/busybox@1.37.0"
}
]
},
{
"name": "busybox",
"SPDXID": "SPDXRef-DocumentRoot-Image-busybox",
"versionInfo": "sha256:cddc8af5547af9de5e6fb66b36d66ef7418561204e1255ae528d0b2c919d09a3",
"supplier": "NOASSERTION",
"downloadLocation": "NOASSERTION",
"filesAnalyzed": false,
"checksums": [
{ "algorithm": "SHA256", "checksumValue": "cddc8af5547af9de5e6fb66b36d66ef7418561204e1255ae528d0b2c919d09a3" }
],
"licenseConcluded": "NOASSERTION",
"licenseDeclared": "NOASSERTION",
"copyrightText": "NOASSERTION",
"externalRefs": [
{
"referenceCategory": "PACKAGE-MANAGER",
"referenceType": "purl",
"referenceLocator": "pkg:oci/busybox@sha256%3Acddc8af5547af9de5e6fb66b36d66ef7418561204e1255ae528d0b2c919d09a3?arch=arm64&tag=latest"
}
],
"primaryPackagePurpose": "CONTAINER"
}
],
"files": [
{
"fileName": "bin/[",
"SPDXID": "SPDXRef-File-bin---de0bf36b25443562",
"fileTypes": ["APPLICATION", "BINARY"],
"checksums": [
{ "algorithm": "SHA1", "checksumValue": "99f9c7cb06f6f8f074b5c16245f295e33844855a" },
{ "algorithm": "SHA256", "checksumValue": "8a4212147744cedcf7f679c81921942c81eb3b8d356bbb2b08b51336b2fe8add" }
],
"licenseConcluded": "NOASSERTION",
"licenseInfoInFiles": ["NOASSERTION"],
"copyrightText": "NOASSERTION",
"comment": "layerID: sha256:6aba5e0d32d91e3e923854dcb30588dc4112bfa1dae82b89535ad31d322a7b19"
},
{
"fileName": "bin/getconf",
"SPDXID": "SPDXRef-File-bin-getconf-b240ee11665506ce",
"checksums": [{ "algorithm": "SHA1", "checksumValue": "0000000000000000000000000000000000000000" }],
"licenseConcluded": "NOASSERTION",
"licenseInfoInFiles": ["NOASSERTION"],
"copyrightText": "NOASSERTION",
"comment": "layerID: sha256:6aba5e0d32d91e3e923854dcb30588dc4112bfa1dae82b89535ad31d322a7b19"
},
{
"fileName": "lib/ld-linux-aarch64.so.1",
"SPDXID": "SPDXRef-File-lib-ld-linux-aarch64.so.1-48a6e9fa63c5f6cc",
"checksums": [{ "algorithm": "SHA1", "checksumValue": "0000000000000000000000000000000000000000" }],
"licenseConcluded": "NOASSERTION",
"licenseInfoInFiles": ["NOASSERTION"],
"copyrightText": "NOASSERTION",
"comment": "layerID: sha256:6aba5e0d32d91e3e923854dcb30588dc4112bfa1dae82b89535ad31d322a7b19"
},
{
"fileName": "lib/libc.so.6",
"SPDXID": "SPDXRef-File-lib-libc.so.6-a2dc8cb35e1e0485",
"checksums": [{ "algorithm": "SHA1", "checksumValue": "0000000000000000000000000000000000000000" }],
"licenseConcluded": "NOASSERTION",
"licenseInfoInFiles": ["NOASSERTION"],
"copyrightText": "NOASSERTION",
"comment": "layerID: sha256:6aba5e0d32d91e3e923854dcb30588dc4112bfa1dae82b89535ad31d322a7b19"
},
{
"fileName": "lib/libm.so.6",
"SPDXID": "SPDXRef-File-lib-libm.so.6-8746a5a87ab9e597",
"checksums": [{ "algorithm": "SHA1", "checksumValue": "0000000000000000000000000000000000000000" }],
"licenseConcluded": "NOASSERTION",
"licenseInfoInFiles": ["NOASSERTION"],
"copyrightText": "NOASSERTION",
"comment": "layerID: sha256:6aba5e0d32d91e3e923854dcb30588dc4112bfa1dae82b89535ad31d322a7b19"
},
{
"fileName": "lib/libnss_compat.so.2",
"SPDXID": "SPDXRef-File-lib-libnss-compat.so.2-75835d9334e3cd14",
"checksums": [{ "algorithm": "SHA1", "checksumValue": "0000000000000000000000000000000000000000" }],
"licenseConcluded": "NOASSERTION",
"licenseInfoInFiles": ["NOASSERTION"],
"copyrightText": "NOASSERTION",
"comment": "layerID: sha256:6aba5e0d32d91e3e923854dcb30588dc4112bfa1dae82b89535ad31d322a7b19"
},
{
"fileName": "lib/libnss_dns.so.2",
"SPDXID": "SPDXRef-File-lib-libnss-dns.so.2-a75d014485c88e79",
"checksums": [{ "algorithm": "SHA1", "checksumValue": "0000000000000000000000000000000000000000" }],
"licenseConcluded": "NOASSERTION",
"licenseInfoInFiles": ["NOASSERTION"],
"copyrightText": "NOASSERTION",
"comment": "layerID: sha256:6aba5e0d32d91e3e923854dcb30588dc4112bfa1dae82b89535ad31d322a7b19"
},
{
"fileName": "lib/libnss_files.so.2",
"SPDXID": "SPDXRef-File-lib-libnss-files.so.2-b5abc725c65d58cf",
"checksums": [{ "algorithm": "SHA1", "checksumValue": "0000000000000000000000000000000000000000" }],
"licenseConcluded": "NOASSERTION",
"licenseInfoInFiles": ["NOASSERTION"],
"copyrightText": "NOASSERTION",
"comment": "layerID: sha256:6aba5e0d32d91e3e923854dcb30588dc4112bfa1dae82b89535ad31d322a7b19"
},
{
"fileName": "lib/libnss_hesiod.so.2",
"SPDXID": "SPDXRef-File-lib-libnss-hesiod.so.2-8570ef9dff59aa56",
"checksums": [{ "algorithm": "SHA1", "checksumValue": "0000000000000000000000000000000000000000" }],
"licenseConcluded": "NOASSERTION",
"licenseInfoInFiles": ["NOASSERTION"],
"copyrightText": "NOASSERTION",
"comment": "layerID: sha256:6aba5e0d32d91e3e923854dcb30588dc4112bfa1dae82b89535ad31d322a7b19"
},
{
"fileName": "lib/libpthread.so.0",
"SPDXID": "SPDXRef-File-lib-libpthread.so.0-585855f0b92c8232",
"checksums": [{ "algorithm": "SHA1", "checksumValue": "0000000000000000000000000000000000000000" }],
"licenseConcluded": "NOASSERTION",
"licenseInfoInFiles": ["NOASSERTION"],
"copyrightText": "NOASSERTION",
"comment": "layerID: sha256:6aba5e0d32d91e3e923854dcb30588dc4112bfa1dae82b89535ad31d322a7b19"
},
{
"fileName": "lib/libresolv.so.2",
"SPDXID": "SPDXRef-File-lib-libresolv.so.2-ee8c205846a71e54",
"checksums": [{ "algorithm": "SHA1", "checksumValue": "0000000000000000000000000000000000000000" }],
"licenseConcluded": "NOASSERTION",
"licenseInfoInFiles": ["NOASSERTION"],
"copyrightText": "NOASSERTION",
"comment": "layerID: sha256:6aba5e0d32d91e3e923854dcb30588dc4112bfa1dae82b89535ad31d322a7b19"
}
],
"relationships": [
{
"spdxElementId": "SPDXRef-Package-binary-busybox-74d9294c42941b37",
"relatedSpdxElement": "SPDXRef-File-bin---de0bf36b25443562",
"relationshipType": "OTHER",
"comment": "evident-by: indicates the package's existence is evident by the given file"
},
{
"spdxElementId": "SPDXRef-DocumentRoot-Image-busybox",
"relatedSpdxElement": "SPDXRef-Package-binary-busybox-74d9294c42941b37",
"relationshipType": "CONTAINS"
},
{
"spdxElementId": "SPDXRef-DOCUMENT",
"relatedSpdxElement": "SPDXRef-DocumentRoot-Image-busybox",
"relationshipType": "DESCRIBES"
}
]
}
SPDXVersion: SPDX-2.3
DataLicense: CC0-1.0
SPDXID: SPDXRef-DOCUMENT
DocumentName: busybox
DocumentNamespace: https://anchore.com/syft/image/busybox-9e6cffe6-80e8-4cb9-ba5d-a1145b45d8d8
LicenseListVersion: 3.27
Creator: Organization: Anchore, Inc
Creator: Tool: syft-1.33.0
Created: 2025-10-09T14:08:21Z
##### Unpackaged files
FileName: bin/[
SPDXID: SPDXRef-File-bin---de0bf36b25443562
FileType: APPLICATION
FileType: BINARY
FileChecksum: SHA1: 99f9c7cb06f6f8f074b5c16245f295e33844855a
FileChecksum: SHA256: 8a4212147744cedcf7f679c81921942c81eb3b8d356bbb2b08b51336b2fe8add
LicenseConcluded: NOASSERTION
LicenseInfoInFile: NOASSERTION
FileCopyrightText: NOASSERTION
FileComment: layerID: sha256:6aba5e0d32d91e3e923854dcb30588dc4112bfa1dae82b89535ad31d322a7b19
FileName: bin/getconf
SPDXID: SPDXRef-File-bin-getconf-b240ee11665506ce
FileChecksum: SHA1: 0000000000000000000000000000000000000000
LicenseConcluded: NOASSERTION
LicenseInfoInFile: NOASSERTION
FileCopyrightText: NOASSERTION
FileComment: layerID: sha256:6aba5e0d32d91e3e923854dcb30588dc4112bfa1dae82b89535ad31d322a7b19
FileName: lib/ld-linux-aarch64.so.1
SPDXID: SPDXRef-File-lib-ld-linux-aarch64.so.1-48a6e9fa63c5f6cc
FileChecksum: SHA1: 0000000000000000000000000000000000000000
LicenseConcluded: NOASSERTION
LicenseInfoInFile: NOASSERTION
FileCopyrightText: NOASSERTION
FileComment: layerID: sha256:6aba5e0d32d91e3e923854dcb30588dc4112bfa1dae82b89535ad31d322a7b19
FileName: lib/libc.so.6
SPDXID: SPDXRef-File-lib-libc.so.6-a2dc8cb35e1e0485
FileChecksum: SHA1: 0000000000000000000000000000000000000000
LicenseConcluded: NOASSERTION
LicenseInfoInFile: NOASSERTION
FileCopyrightText: NOASSERTION
FileComment: layerID: sha256:6aba5e0d32d91e3e923854dcb30588dc4112bfa1dae82b89535ad31d322a7b19
FileName: lib/libm.so.6
SPDXID: SPDXRef-File-lib-libm.so.6-8746a5a87ab9e597
FileChecksum: SHA1: 0000000000000000000000000000000000000000
LicenseConcluded: NOASSERTION
LicenseInfoInFile: NOASSERTION
FileCopyrightText: NOASSERTION
FileComment: layerID: sha256:6aba5e0d32d91e3e923854dcb30588dc4112bfa1dae82b89535ad31d322a7b19
FileName: lib/libnss_compat.so.2
SPDXID: SPDXRef-File-lib-libnss-compat.so.2-75835d9334e3cd14
FileChecksum: SHA1: 0000000000000000000000000000000000000000
LicenseConcluded: NOASSERTION
LicenseInfoInFile: NOASSERTION
FileCopyrightText: NOASSERTION
FileComment: layerID: sha256:6aba5e0d32d91e3e923854dcb30588dc4112bfa1dae82b89535ad31d322a7b19
FileName: lib/libnss_dns.so.2
SPDXID: SPDXRef-File-lib-libnss-dns.so.2-a75d014485c88e79
FileChecksum: SHA1: 0000000000000000000000000000000000000000
LicenseConcluded: NOASSERTION
LicenseInfoInFile: NOASSERTION
FileCopyrightText: NOASSERTION
FileComment: layerID: sha256:6aba5e0d32d91e3e923854dcb30588dc4112bfa1dae82b89535ad31d322a7b19
FileName: lib/libnss_files.so.2
SPDXID: SPDXRef-File-lib-libnss-files.so.2-b5abc725c65d58cf
FileChecksum: SHA1: 0000000000000000000000000000000000000000
LicenseConcluded: NOASSERTION
LicenseInfoInFile: NOASSERTION
FileCopyrightText: NOASSERTION
FileComment: layerID: sha256:6aba5e0d32d91e3e923854dcb30588dc4112bfa1dae82b89535ad31d322a7b19
FileName: lib/libnss_hesiod.so.2
SPDXID: SPDXRef-File-lib-libnss-hesiod.so.2-8570ef9dff59aa56
FileChecksum: SHA1: 0000000000000000000000000000000000000000
LicenseConcluded: NOASSERTION
LicenseInfoInFile: NOASSERTION
FileCopyrightText: NOASSERTION
FileComment: layerID: sha256:6aba5e0d32d91e3e923854dcb30588dc4112bfa1dae82b89535ad31d322a7b19
FileName: lib/libpthread.so.0
SPDXID: SPDXRef-File-lib-libpthread.so.0-585855f0b92c8232
FileChecksum: SHA1: 0000000000000000000000000000000000000000
LicenseConcluded: NOASSERTION
LicenseInfoInFile: NOASSERTION
FileCopyrightText: NOASSERTION
FileComment: layerID: sha256:6aba5e0d32d91e3e923854dcb30588dc4112bfa1dae82b89535ad31d322a7b19
FileName: lib/libresolv.so.2
SPDXID: SPDXRef-File-lib-libresolv.so.2-ee8c205846a71e54
FileChecksum: SHA1: 0000000000000000000000000000000000000000
LicenseConcluded: NOASSERTION
LicenseInfoInFile: NOASSERTION
FileCopyrightText: NOASSERTION
FileComment: layerID: sha256:6aba5e0d32d91e3e923854dcb30588dc4112bfa1dae82b89535ad31d322a7b19
##### Package: busybox
PackageName: busybox
SPDXID: SPDXRef-DocumentRoot-Image-busybox
PackageVersion: sha256:cddc8af5547af9de5e6fb66b36d66ef7418561204e1255ae528d0b2c919d09a3
PackageSupplier: NOASSERTION
PackageDownloadLocation: NOASSERTION
PrimaryPackagePurpose: CONTAINER
FilesAnalyzed: false
PackageChecksum: SHA256: cddc8af5547af9de5e6fb66b36d66ef7418561204e1255ae528d0b2c919d09a3
PackageLicenseConcluded: NOASSERTION
PackageLicenseDeclared: NOASSERTION
PackageCopyrightText: NOASSERTION
ExternalRef: PACKAGE-MANAGER purl pkg:oci/busybox@sha256%3Acddc8af5547af9de5e6fb66b36d66ef7418561204e1255ae528d0b2c919d09a3?arch=arm64&tag=latest
##### Package: busybox
PackageName: busybox
SPDXID: SPDXRef-Package-binary-busybox-74d9294c42941b37
PackageVersion: 1.37.0
PackageSupplier: NOASSERTION
PackageDownloadLocation: NOASSERTION
FilesAnalyzed: false
PackageSourceInfo: acquired package info from the following paths: /bin/[
PackageLicenseConcluded: NOASSERTION
PackageLicenseDeclared: NOASSERTION
PackageCopyrightText: NOASSERTION
ExternalRef: SECURITY cpe23Type cpe:2.3:a:busybox:busybox:1.37.0:*:*:*:*:*:*:*
ExternalRef: PACKAGE-MANAGER purl pkg:generic/busybox@1.37.0
##### Relationships
Relationship: SPDXRef-Package-binary-busybox-74d9294c42941b37 OTHER SPDXRef-File-bin---de0bf36b25443562
RelationshipComment: evident-by: indicates the package's existence is evident by the given file
Relationship: SPDXRef-DocumentRoot-Image-busybox CONTAINS SPDXRef-Package-binary-busybox-74d9294c42941b37
Relationship: SPDXRef-DOCUMENT DESCRIBES SPDXRef-DocumentRoot-Image-busybox
{
"version": 0,
"job": {},
"detector": {
"name": "syft",
"url": "https://github.com/anchore/syft",
"version": "1.33.0"
},
"metadata": {
"syft:distro": "pkg:generic/busybox@1.37.0?like=busybox"
},
"manifests": {
"busybox:latest:/bin/busybox": {
"name": "busybox:latest:/bin/busybox",
"file": {
"source_location": "busybox:latest:/bin/busybox"
},
"metadata": {
"syft:filesystem": "sha256:6aba5e0d32d91e3e923854dcb30588dc4112bfa1dae82b89535ad31d322a7b19"
},
"resolved": {
"pkg:generic/busybox@1.37.0": {
"package_url": "pkg:generic/busybox@1.37.0",
"relationship": "direct",
"scope": "runtime"
}
}
}
},
"scanned": "2025-10-09T14:08:21Z"
}
Writing output to files
Direct Syft output to a file instead of stdout by appending =<file>
to the format option:
# Write JSON to a file
syft <source> -o json=sbom.json
# Write to stdout (default behavior)
syft <source> -o json
Multiple outputs
Generate multiple SBOM formats in a single run by specifying multiple -o
flags:
syft <source> \
-o json=sbom.json \
-o spdx-json=sbom.spdx.json
You can both display to terminal and write to file:
syft <source> \
-o table \ # report to stdout
-o json=sbom.json # write to file
Next steps
- Learn about customizing output with templates for specialized formats
- Explore supported sources to understand what Syft can analyze
- See configuration options for advanced format settings
1.4 - Working with Syft JSON
Syft’s native JSON format provides the most comprehensive view of discovered software components, capturing all package metadata, file details, relationships, and source information.
Since Syft can convert from its native JSON format to standard SBOM formats, capturing your SBOM in Syft JSON format lets you generate any SBOM format as needed for compliance requirements.
Data Shapes
A Syft JSON output contains these main sections:
{
"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.).
{
"id": "sha256:...",
"name": "alpine:3.9.2", // User input
"version": "sha256:...",
"type": "image", // image, directory, file
"metadata": {
"imageID": "sha256:...",
"manifestDigest": "sha256:...",
"mediaType": "application/vnd.docker...",
"tags": ["alpine:3.9.2"],
"repoDigests": []
}
}
Distribution
Linux distribution details from /etc/os-release
or similar sources.
{
"name": "alpine",
"version": "3.9.2",
"idLike": ["alpine"] // Related distributions
}
Location
Describes where a package or file was found.
{
"path": "/lib/apk/db/installed",
"layerID": "sha256:...",
"accessPath": "/var/lib/apk/installed",
"annotations": {
"evidence": "primary"
}
}
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.
{
"name": "syft",
"version": "1.0.0",
"configuration": {} // Syft configuration used
}
The Syft JSON schema is versioned and available in the Syft repository:
JQ Recipes
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.)
}
syft alpine:3.9.2 -o json | \
jq '.artifacts[] |
select(.name | test("^(openssl|ssl|crypto)")) |
{
name,
version,
type
}'
{
"name": "ssl_client",
"version": "1.29.3-r10",
"type": "apk"
}
Location of all JARs:
Shows Java packages with their primary installation paths
.artifacts[] |
select(.type == "java-archive") | # Filter for JAR packages
{
package: "\(.name)@\(.version)",
path: (.locations[] | select(.annotations.evidence == "primary") | .path) # Primary installation path
}
syft openjdk:11-jre-slim -o json | \
jq '.artifacts[] |
select(.type == "java-archive") |
{
package: "\(.name)@\(.version)",
path: (.locations[] | select(.annotations.evidence == "primary") | .path)
}'
{
"package": "jrt-fs@11.0.16",
"path": "/usr/local/openjdk-11/lib/jrt-fs.jar"
}
All executable files:
Lists all binary files with their format and entry point status
.files[] |
select(.executable != null) | # Filter for executable files
{
path: .location.path,
format: .executable.format, # ELF, Mach-O, PE, etc.
importedLibraries: .executable.importedLibraries # Shared library dependencies
}
syft alpine:3.9.2 -o json | \
jq '.files[] |
select(.executable != null) |
{
path: .location.path,
format: .executable.format,
importedLibraries: .executable.importedLibraries
}'
{
"path": "/bin/busybox",
"format": "elf",
"importedLibraries": [
"libc.musl-aarch64.so.1"
]
}
{
"path": "/lib/ld-musl-aarch64.so.1",
"format": "elf",
"importedLibraries": []
}
{
"path": "/lib/libcrypto.so.1.1",
"format": "elf",
"importedLibraries": [
"libc.musl-aarch64.so.1"
]
}
{
"path": "/lib/libssl.so.1.1",
"format": "elf",
"importedLibraries": [
"libcrypto.so.1.1",
"libc.musl-aarch64.so.1"
]
}
{
"path": "/lib/libz.so.1.2.11",
"format": "elf",
"importedLibraries": [
"libc.musl-aarch64.so.1"
]
}
{
"path": "/sbin/apk",
"format": "elf",
"importedLibraries": [
"libssl.so.1.1",
"libcrypto.so.1.1",
"libz.so.1",
"libc.musl-aarch64.so.1"
]
}
{
"path": "/sbin/mkmntdirs",
"format": "elf",
"importedLibraries": [
"libc.musl-aarch64.so.1"
]
}
{
"path": "/usr/bin/getconf",
"format": "elf",
"importedLibraries": [
"libc.musl-aarch64.so.1"
]
}
{
"path": "/usr/bin/getent",
"format": "elf",
"importedLibraries": [
"libc.musl-aarch64.so.1"
]
}
{
"path": "/usr/bin/iconv",
"format": "elf",
"importedLibraries": [
"libc.musl-aarch64.so.1"
]
}
{
"path": "/usr/bin/scanelf",
"format": "elf",
"importedLibraries": [
"libc.musl-aarch64.so.1"
]
}
{
"path": "/usr/bin/ssl_client",
"format": "elf",
"importedLibraries": [
"libtls-standalone.so.1",
"libc.musl-aarch64.so.1"
]
}
{
"path": "/usr/lib/engines-1.1/afalg.so",
"format": "elf",
"importedLibraries": [
"libcrypto.so.1.1",
"libc.musl-aarch64.so.1"
]
}
{
"path": "/usr/lib/engines-1.1/capi.so",
"format": "elf",
"importedLibraries": [
"libc.musl-aarch64.so.1"
]
}
{
"path": "/usr/lib/engines-1.1/padlock.so",
"format": "elf",
"importedLibraries": [
"libc.musl-aarch64.so.1"
]
}
{
"path": "/usr/lib/libtls-standalone.so.1.0.0",
"format": "elf",
"importedLibraries": [
"libssl.so.1.1",
"libcrypto.so.1.1",
"libc.musl-aarch64.so.1"
]
}
Binaries not owned by packages:
Uses set operations on relationships to identify untracked binaries that might indicate supply chain issues
. as $root |
[.files[] | select(.executable != null) | .id] as $binaries | # All binary IDs
[.artifactRelationships[] | select(.type == "contains") | .child] as $owned | # Package-owned files
($binaries - $owned) as $unowned | # Set subtraction to find unowned binaries
$root.files[] |
select(.id as $id | $unowned | index($id)) | # Filter to unowned binaries
{
path: .location.path,
sha256: .digests[] | select(.algorithm == "sha256") | .value # For integrity verification
}
syft httpd:2.4.65 -o json | \
jq '. as $root |
[.files[] | select(.executable != null) | .id] as $binaries |
[.artifactRelationships[] | select(.type == "contains") | .child] as $owned |
($binaries - $owned) as $unowned |
$root.files[] |
select(.id as $id | $unowned | index($id)) |
{
path: .location.path,
sha256: .digests[] | select(.algorithm == "sha256") | .value
}'
# .syft.yaml
file:
metadata:
selection: all
{
"path": "/usr/local/apache2/bin/ab",
"sha256": "1aa76de1f9eb534fe22d35a01ccbf7ede03e250f6f5d0a00553e687187565d3a"
}
{
"path": "/usr/local/apache2/bin/checkgid",
"sha256": "af3372d60eee3f8132d2bdd10fb8670db8a9965b2e056c267131586184ba11fb"
}
{
"path": "/usr/local/apache2/bin/fcgistarter",
"sha256": "eea2fa75671e7e647692cd0352405ef8a0b17167a05770b9552602a3c720bfdb"
}
{
"path": "/usr/local/apache2/bin/htcacheclean",
"sha256": "94e0fd5f0f5cf6231080177072846a4e99846f1f534224911e3bed17ce27ec38"
}
{
"path": "/usr/local/apache2/bin/htdbm",
"sha256": "e2a41d96c92cb16c98972a043ac380c06f19b5bddbafe0b2d2082ed174f8cfe3"
}
{
"path": "/usr/local/apache2/bin/htdigest",
"sha256": "0881598a4fd15455297c186fa301fdb1656ff26d0f77626d54a15421095e047f"
}
{
"path": "/usr/local/apache2/bin/htpasswd",
"sha256": "871ef0aa4ae0914747a471bf3917405548abf768dd6c94e3e0177c8e87334d9e"
}
{
"path": "/usr/local/apache2/bin/httpd",
"sha256": "4ee82f26958e62065b51ca56ab4c55b32988f27a8402ed518b05d48ed2342142"
}
{
"path": "/usr/local/apache2/bin/httxt2dbm",
"sha256": "1d5eb8e5d910760aa859c45e79b541362a84499f08fb79b8773bf9b8faf7bbdb"
}
{
"path": "/usr/local/apache2/bin/logresolve",
"sha256": "de8ed1fa5184170fca09980025f40c55d9fbf14b47c73b2575bc90ac1c9bf20e"
}
{
"path": "/usr/local/apache2/bin/rotatelogs",
"sha256": "f5ed895712cddcec7f542dee08a1ff74fd00ae3a9b0d92ede429e04ec2b9b8ae"
}
{
"path": "/usr/local/apache2/bin/suexec",
"sha256": "264efc529c09a60fed57fcde9e7a2c36f8bb414ae0e1afc9bb85595113ab4ec2"
}
{
"path": "/usr/local/apache2/modules/mod_access_compat.so",
"sha256": "0d6322b7d7d3d6c459751f8b271f733fa05a8b56eecd75f608100a5dbf464fc2"
}
{
"path": "/usr/local/apache2/modules/mod_actions.so",
"sha256": "6dc5dea7137ec0ae139c545b26efd860c6de7bcc19d2e31db213399c86bf2ead"
}
{
"path": "/usr/local/apache2/modules/mod_alias.so",
"sha256": "bb422c4486600ec349ac9b89acaa3793265d69498c30370e678a362900daea04"
}
{
"path": "/usr/local/apache2/modules/mod_allowmethods.so",
"sha256": "99a9db80c8f18fe3defb315731af3bceef321a98bd52f518f068ca2632596cee"
}
{
"path": "/usr/local/apache2/modules/mod_asis.so",
"sha256": "039014ad5ad3f357e811b570bd9977a772e74f191856981a503e57263b88cc44"
}
{
"path": "/usr/local/apache2/modules/mod_auth_basic.so",
"sha256": "1f9534187df98194fa60259c3d9feca05f1b2564d49b37b49da040232e7a327b"
}
{
"path": "/usr/local/apache2/modules/mod_auth_digest.so",
"sha256": "ad77d0457b773c9d13097adf47bebcd95297466fc9fb6886b7bff85e2acdd99d"
}
{
"path": "/usr/local/apache2/modules/mod_auth_form.so",
"sha256": "ceb56183d83c22ff08853982b0f35f122185cf69d3bcfd948eeb1df32dd12bbb"
}
{
"path": "/usr/local/apache2/modules/mod_authn_anon.so",
"sha256": "44308e1d5a65ab64232d27f24a827aa1afdb2fef580dd1a8454788431ebd639f"
}
{
"path": "/usr/local/apache2/modules/mod_authn_core.so",
"sha256": "9cbf85b1a20da26483ca4a57186161a2876ca296dd1174ed5a5af9f5301fe5e8"
}
{
"path": "/usr/local/apache2/modules/mod_authn_dbd.so",
"sha256": "08dc7b848a67131a091563046e3fc6914e86f248740bd2f23905f2f6df3ce541"
}
{
"path": "/usr/local/apache2/modules/mod_authn_dbm.so",
"sha256": "1e5900c8b41ca227b59ba54738154e04841cef2045d8040747e4b7887526a763"
}
{
"path": "/usr/local/apache2/modules/mod_authn_file.so",
"sha256": "74f83d5717276ae6a37f4a2d0c54f8d23e57ae1c3f73bb2b332c77860b7421ed"
}
{
"path": "/usr/local/apache2/modules/mod_authn_socache.so",
"sha256": "2f51212b62c5bbda54ddec0c1a07f523e96c2b56d987fefa43e0cc42dbf6f5d0"
}
{
"path": "/usr/local/apache2/modules/mod_authnz_fcgi.so",
"sha256": "4fa0fa7d3d4b742b3f73a781d2e8d4625d477c76aa0698aa0d499f87e6985554"
}
{
"path": "/usr/local/apache2/modules/mod_authnz_ldap.so",
"sha256": "dccffc453f46d201ecb1003b372a6ca417ac40a33036500a2215697b2e5ac0af"
}
{
"path": "/usr/local/apache2/modules/mod_authz_core.so",
"sha256": "e2b825ec9e2992b1cc157aef12c4ecd75960604658c3b7aa4a370088e89455b5"
}
{
"path": "/usr/local/apache2/modules/mod_authz_dbd.so",
"sha256": "61b427078b5d11b3fd8693cbfa22cb5871dc9784b08d3182b73ad3e99b8579d9"
}
{
"path": "/usr/local/apache2/modules/mod_authz_dbm.so",
"sha256": "1d99ed703743d9dd2185a0d7e9e351fa38066b3234ae997e87efa6dc1e4513eb"
}
{
"path": "/usr/local/apache2/modules/mod_authz_groupfile.so",
"sha256": "3e9adb775d41a8b01802ff610dda01f8e62a0d282ea0522d297a252207453c4d"
}
{
"path": "/usr/local/apache2/modules/mod_authz_host.so",
"sha256": "c0fcd53dc9596fd6bc280c55d14b61c72dc12470bf5c1bc86e369217af05cb2c"
}
{
"path": "/usr/local/apache2/modules/mod_authz_owner.so",
"sha256": "e8923ef5f11e03c37b4579e18d396758ee085bae4dadc0519374ca63da86c932"
}
{
"path": "/usr/local/apache2/modules/mod_authz_user.so",
"sha256": "3c5674a1e7af6b7d09e8c66f973a3138fed0dde4dfaee98fc132c89730cd9156"
}
{
"path": "/usr/local/apache2/modules/mod_autoindex.so",
"sha256": "2d992f31f40be2c0ec34a29981191c3bfb9e4448a2099f11a4876ba4d394dc2f"
}
{
"path": "/usr/local/apache2/modules/mod_brotli.so",
"sha256": "73bfe5aeff2040a7b56a0bf822bc4069ce3e9954186f81322060697f5cf0546f"
}
{
"path": "/usr/local/apache2/modules/mod_bucketeer.so",
"sha256": "9f146159e928405d2a007dba3690566a45e5793cde87871a30dbfd1dc9114db1"
}
{
"path": "/usr/local/apache2/modules/mod_buffer.so",
"sha256": "710bd1b238a7814963b2857eb92c891bafeff61d9e40f807d68ded700c8c37f2"
}
{
"path": "/usr/local/apache2/modules/mod_cache.so",
"sha256": "976222e2c7ddb317d8804383801b310be33c6b3542f6972edd12c38ddc527e38"
}
{
"path": "/usr/local/apache2/modules/mod_cache_disk.so",
"sha256": "c5359004a563b9b01bf0416cbe856bb50de642bf06649383ffcae26490dc69c8"
}
{
"path": "/usr/local/apache2/modules/mod_cache_socache.so",
"sha256": "94abdf3779a9f7d258b1720021e1e3f10c630e625f5aa13c683c3c811b8dac10"
}
{
"path": "/usr/local/apache2/modules/mod_case_filter.so",
"sha256": "79a0a336c1bacd06c0fc5ca14cfc97223c92f0f5b0c88ec95f7e163e8cdf917d"
}
{
"path": "/usr/local/apache2/modules/mod_case_filter_in.so",
"sha256": "aa5e1c9452e1be3789a8a867a98dab700e4a579c0ea1ff7180adf4e41b8495e3"
}
{
"path": "/usr/local/apache2/modules/mod_cern_meta.so",
"sha256": "1a6da74d768c01b1a96f5c0f0e74686d5b0f51c3d7f1149fa1124cdf10ba842a"
}
{
"path": "/usr/local/apache2/modules/mod_cgi.so",
"sha256": "f2716c663f4f7db8cd78f456e5bd098a62c1b8fde86253ed4617edfe9cdb93b2"
}
{
"path": "/usr/local/apache2/modules/mod_cgid.so",
"sha256": "d5a19aeeb7b9063bac25e4a172ea7578e83bb32da4fe21ecd858409115de166c"
}
{
"path": "/usr/local/apache2/modules/mod_charset_lite.so",
"sha256": "9c4a1b27532c5f47eea7cfc61f65a7cf2f132286e556175ec28e313024641c9d"
}
{
"path": "/usr/local/apache2/modules/mod_data.so",
"sha256": "4dcae9a704c7d9861497e57b15423b9ce3fc7dda6544096ecfff64e4223f3684"
}
{
"path": "/usr/local/apache2/modules/mod_dav.so",
"sha256": "1a33728b16ad05b12fbecf637168608cb10f258ef7a355bd37cef8ce2ed86fd7"
}
...
Binary file digests:
Useful for verifying binary integrity and detecting tampering
.files[] |
select(.executable != null) | # Filter for executable files
{
path: .location.path,
digests: [.digests[] | {algorithm, value}] # All available hash algorithms
}
syft alpine:3.9.2 -o json | \
jq '.files[] |
select(.executable != null) |
{
path: .location.path,
digests: [.digests[] | {algorithm, value}]
}'
{
"path": "/bin/busybox",
"digests": [
{
"algorithm": "sha1",
"value": "7423801dfb28659fcaaaa5e8d41051d470b19008"
},
{
"algorithm": "sha256",
"value": "2c1276c3c02ccec8a0e1737d3144cdf03db883f479c86fbd9c7ea4fd9b35eac5"
}
]
}
{
"path": "/lib/ld-musl-aarch64.so.1",
"digests": [
{
"algorithm": "sha1",
"value": "0b83c1eb91d633379e0c17349e7dae821fa36dbb"
},
{
"algorithm": "sha256",
"value": "0132814479f1acc1e264ef59f73fd91563235897e8dc1bd52765f974cde382ca"
}
]
}
{
"path": "/lib/libcrypto.so.1.1",
"digests": [
{
"algorithm": "sha1",
"value": "e9d1540e5bbd9e77b388ab0e6e2f52603eb032a4"
},
{
"algorithm": "sha256",
"value": "6c597c8ad195eeb7a9130ad832dfa4cbf140f42baf96304711b2dbd43ba8e617"
}
]
}
{
"path": "/lib/libssl.so.1.1",
"digests": [
{
"algorithm": "sha1",
"value": "a8d5036010b52a80402b900c626fe862ab06bd8b"
},
{
"algorithm": "sha256",
"value": "fb72f4615fb4574bd6eeabfdb86be47012618b9076d75aeb1510941c585cae64"
}
]
}
{
"path": "/lib/libz.so.1.2.11",
"digests": [
{
"algorithm": "sha1",
"value": "83378fc7a19ff908a7e92a9fd0ca39eee90d0a3c"
},
{
"algorithm": "sha256",
"value": "19e790eb36a09eba397b5af16852f3bea21a242026bbba3da7b16442b8ba305b"
}
]
}
{
"path": "/sbin/apk",
"digests": [
{
"algorithm": "sha1",
"value": "adac7738917adecff81d4a6f9f0c7971b173859a"
},
{
"algorithm": "sha256",
"value": "22d7d85bd24923f1f274ce765d16602191097829e22ac632748302817ce515d8"
}
]
}
{
"path": "/sbin/mkmntdirs",
"digests": [
{
"algorithm": "sha1",
"value": "fff9b110ad6c659a39681e7be3b2a036fbbcca7b"
},
{
"algorithm": "sha256",
"value": "a14a5a28525220224367616ef46d4713ef7bd00d22baa761e058e8bdd4c0af1b"
}
]
}
{
"path": "/usr/bin/getconf",
"digests": [
{
"algorithm": "sha1",
"value": "06ed40070e1c2ad6d4171095eff4a6bdf9c8489b"
},
{
"algorithm": "sha256",
"value": "82bcde66ead19bc3b9ff850f66c2dbf5eaff36d481f1ec154100f73f6265d2ef"
}
]
}
{
"path": "/usr/bin/getent",
"digests": [
{
"algorithm": "sha1",
"value": "c318a3a780fc27ed7dba57827a825191fa7ee8bd"
},
{
"algorithm": "sha256",
"value": "53ffb508150e91838d795831e8ecc71f2bc3a7db036c6d7f9512c3973418bb5e"
}
]
}
{
"path": "/usr/bin/iconv",
"digests": [
{
"algorithm": "sha1",
"value": "eb98f04742e41cfc3ed44109b0e059d13e5523ea"
},
{
"algorithm": "sha256",
"value": "1c99d1f4edcb8da6db1da60958051c413de45a4c15cd3b7f7285ed87f9a250ff"
}
]
}
{
"path": "/usr/bin/scanelf",
"digests": [
{
"algorithm": "sha1",
"value": "cb085d106f35862e44e17849026927bd05845bff"
},
{
"algorithm": "sha256",
"value": "908da485ad2edea35242f8989c7beb9536414782abc94357c72b7d840bb1fda2"
}
]
}
{
"path": "/usr/bin/ssl_client",
"digests": [
{
"algorithm": "sha1",
"value": "7e17cb64c3fce832e5fa52a3b2ed1e1ccd26acd0"
},
{
"algorithm": "sha256",
"value": "67ab7f3a1ba35630f439d1ca4f73c7d95f8b7aa0e6f6db6ea1743f136f074ab4"
}
]
}
{
"path": "/usr/lib/engines-1.1/afalg.so",
"digests": [
{
"algorithm": "sha1",
"value": "6bd2c385e3884109c581659a8b184592c86e7cee"
},
{
"algorithm": "sha256",
"value": "ea7c2f48bc741fd828d79a304dbf713e20e001c0187f3f534d959886af87f4af"
}
]
}
{
"path": "/usr/lib/engines-1.1/capi.so",
"digests": [
{
"algorithm": "sha1",
"value": "41bb990b6f8e2013487980fd430455cc3b59905f"
},
{
"algorithm": "sha256",
"value": "b461ed43f0f244007d872e84760a446023b69b178c970acf10ed2666198942c6"
}
]
}
{
"path": "/usr/lib/engines-1.1/padlock.so",
"digests": [
{
"algorithm": "sha1",
"value": "82d8308700f481884fd77c882e0e9406fb17b317"
},
{
"algorithm": "sha256",
"value": "0ccb04f040afb0216da1cea2c1db7a0b91d990ce061e232782aedbd498483649"
}
]
}
{
"path": "/usr/lib/libtls-standalone.so.1.0.0",
"digests": [
{
"algorithm": "sha1",
...
Binaries with security features:
Analyzes ELF security hardening features extracted during SBOM generation
.files[] |
select(.executable != null and .executable.format == "elf") | # ELF binaries only
{
path: .location.path,
pie: .executable.elfSecurityFeatures.pie, # Position Independent Executable
stackCanary: .executable.elfSecurityFeatures.stackCanary, # Stack protection
nx: .executable.elfSecurityFeatures.nx # No-Execute bit
}
syft alpine:3.9.2 -o json | \
jq '.files[] |
select(.executable != null and .executable.format == "elf") |
{
path: .location.path,
pie: .executable.elfSecurityFeatures.pie,
stackCanary: .executable.elfSecurityFeatures.stackCanary,
nx: .executable.elfSecurityFeatures.nx
}'
{
"path": "/bin/busybox",
"pie": true,
"stackCanary": true,
"nx": true
}
{
"path": "/lib/ld-musl-aarch64.so.1",
"pie": false,
"stackCanary": true,
"nx": true
}
{
"path": "/lib/libcrypto.so.1.1",
"pie": false,
"stackCanary": true,
"nx": true
}
{
"path": "/lib/libssl.so.1.1",
"pie": false,
"stackCanary": true,
"nx": true
}
{
"path": "/lib/libz.so.1.2.11",
"pie": false,
"stackCanary": true,
"nx": true
}
{
"path": "/sbin/apk",
"pie": true,
"stackCanary": true,
"nx": true
}
{
"path": "/sbin/mkmntdirs",
"pie": true,
"stackCanary": false,
"nx": true
}
{
"path": "/usr/bin/getconf",
"pie": true,
"stackCanary": false,
"nx": true
}
{
"path": "/usr/bin/getent",
"pie": true,
"stackCanary": true,
"nx": true
}
{
"path": "/usr/bin/iconv",
"pie": true,
"stackCanary": true,
"nx": true
}
{
"path": "/usr/bin/scanelf",
"pie": true,
"stackCanary": true,
"nx": true
}
{
"path": "/usr/bin/ssl_client",
"pie": true,
"stackCanary": true,
"nx": true
}
{
"path": "/usr/lib/engines-1.1/afalg.so",
"pie": false,
"stackCanary": true,
"nx": true
}
{
"path": "/usr/lib/engines-1.1/capi.so",
"pie": false,
"stackCanary": false,
"nx": true
}
{
"path": "/usr/lib/engines-1.1/padlock.so",
"pie": false,
"stackCanary": false,
"nx": true
}
{
"path": "/usr/lib/libtls-standalone.so.1.0.0",
"pie": false,
"stackCanary": true,
"nx": true
}
Binaries importing specific libraries:
Identifies which binaries depend on specific shared libraries for security audits
.files[] |
select(.executable != null and .executable.importedLibraries != null) |
select(.executable.importedLibraries[] | contains("libcrypto")) | # Find binaries using libcrypto
{
path: .location.path,
imports: .executable.importedLibraries # Shared library dependencies
}
syft alpine:3.9.2 -o json | \
jq '.files[] |
select(.executable != null and .executable.importedLibraries != null) |
select(.executable.importedLibraries[] | contains("libcrypto")) |
{
path: .location.path,
imports: .executable.importedLibraries
}'
{
"path": "/lib/libssl.so.1.1",
"imports": [
"libcrypto.so.1.1",
"libc.musl-aarch64.so.1"
]
}
{
"path": "/sbin/apk",
"imports": [
"libssl.so.1.1",
"libcrypto.so.1.1",
"libz.so.1",
"libc.musl-aarch64.so.1"
]
}
{
"path": "/usr/lib/engines-1.1/afalg.so",
"imports": [
"libcrypto.so.1.1",
"libc.musl-aarch64.so.1"
]
}
{
"path": "/usr/lib/libtls-standalone.so.1.0.0",
"imports": [
"libssl.so.1.1",
"libcrypto.so.1.1",
"libc.musl-aarch64.so.1"
]
}
Extract Package URLs (PURLs):
Extracts Package URLs for cross-tool SBOM correlation and vulnerability matching
.artifacts[] |
select(.purl != null and .purl != "") | # Filter packages with PURLs
{
name,
version,
purl # Package URL for cross-tool compatibility
}
syft alpine:3.9.2 -o json | \
jq '.artifacts[] |
select(.purl != null and .purl != "") |
{
name,
version,
purl
}'
{
"name": "alpine-baselayout",
"version": "3.1.0-r3",
"purl": "pkg:apk/alpine/alpine-baselayout@3.1.0-r3?arch=aarch64&distro=alpine-3.9.2"
}
{
"name": "alpine-keys",
"version": "2.1-r1",
"purl": "pkg:apk/alpine/alpine-keys@2.1-r1?arch=aarch64&distro=alpine-3.9.2"
}
{
"name": "apk-tools",
"version": "2.10.3-r1",
"purl": "pkg:apk/alpine/apk-tools@2.10.3-r1?arch=aarch64&distro=alpine-3.9.2"
}
{
"name": "busybox",
"version": "1.29.3-r10",
"purl": "pkg:apk/alpine/busybox@1.29.3-r10?arch=aarch64&distro=alpine-3.9.2"
}
{
"name": "ca-certificates-cacert",
"version": "20190108-r0",
"purl": "pkg:apk/alpine/ca-certificates-cacert@20190108-r0?arch=aarch64&distro=alpine-3.9.2&upstream=ca-certificates"
}
{
"name": "libc-utils",
"version": "0.7.1-r0",
"purl": "pkg:apk/alpine/libc-utils@0.7.1-r0?arch=aarch64&distro=alpine-3.9.2&upstream=libc-dev"
}
{
"name": "libcrypto1.1",
"version": "1.1.1a-r1",
"purl": "pkg:apk/alpine/libcrypto1.1@1.1.1a-r1?arch=aarch64&distro=alpine-3.9.2&upstream=openssl"
}
{
"name": "libssl1.1",
"version": "1.1.1a-r1",
"purl": "pkg:apk/alpine/libssl1.1@1.1.1a-r1?arch=aarch64&distro=alpine-3.9.2&upstream=openssl"
}
{
"name": "libtls-standalone",
"version": "2.7.4-r6",
"purl": "pkg:apk/alpine/libtls-standalone@2.7.4-r6?arch=aarch64&distro=alpine-3.9.2"
}
{
"name": "musl",
"version": "1.1.20-r3",
"purl": "pkg:apk/alpine/musl@1.1.20-r3?arch=aarch64&distro=alpine-3.9.2"
}
{
"name": "musl-utils",
"version": "1.1.20-r3",
"purl": "pkg:apk/alpine/musl-utils@1.1.20-r3?arch=aarch64&distro=alpine-3.9.2&upstream=musl"
}
{
"name": "scanelf",
"version": "1.2.3-r0",
"purl": "pkg:apk/alpine/scanelf@1.2.3-r0?arch=aarch64&distro=alpine-3.9.2&upstream=pax-utils"
}
{
"name": "ssl_client",
"version": "1.29.3-r10",
"purl": "pkg:apk/alpine/ssl_client@1.29.3-r10?arch=aarch64&distro=alpine-3.9.2&upstream=busybox"
}
{
"name": "zlib",
"version": "1.2.11-r1",
"purl": "pkg:apk/alpine/zlib@1.2.11-r1?arch=aarch64&distro=alpine-3.9.2"
}
Group packages by language:
Groups and counts packages by programming language
[.artifacts[] | select(.language != null and .language != "")] |
group_by(.language) | # Group by programming language
map({
language: .[0].language,
count: length # Count packages per language
}) |
sort_by(.count) |
reverse # Highest count first
syft node:18-alpine -o json | \
jq '[.artifacts[] | select(.language != null and .language != "")] |
group_by(.language) |
map({
language: .[0].language,
count: length
}) |
sort_by(.count) |
reverse'
[
{
"language": "javascript",
"count": 204
}
]
Count packages by type:
Provides a summary count of packages per ecosystem
[.artifacts[]] |
group_by(.type) | # Group packages by ecosystem type
map({
type: .[0].type,
count: length # Count packages in each group
}) |
sort_by(.count) |
reverse # Highest count first
syft node:18-alpine -o json | \
jq '[.artifacts[]] |
group_by(.type) |
map({
type: .[0].type,
count: length
}) |
sort_by(.count) |
reverse'
[
{
"type": "npm",
"count": 204
},
{
"type": "apk",
"count": 17
},
{
"type": "binary",
"count": 1
}
]
Package locations:
Maps packages to their filesystem locations
.artifacts[] |
{
name,
version,
type,
locations: [.locations[] | .path] # All filesystem locations
}
syft alpine:3.9.2 -o json | \
jq '.artifacts[] |
{
name,
version,
type,
locations: [.locations[] | .path]
}'
{
"name": "alpine-baselayout",
"version": "3.1.0-r3",
"type": "apk",
"locations": [
"/lib/apk/db/installed"
]
}
{
"name": "alpine-keys",
"version": "2.1-r1",
"type": "apk",
"locations": [
"/lib/apk/db/installed"
]
}
{
"name": "apk-tools",
"version": "2.10.3-r1",
"type": "apk",
"locations": [
"/lib/apk/db/installed"
]
}
{
"name": "busybox",
"version": "1.29.3-r10",
"type": "apk",
"locations": [
"/lib/apk/db/installed"
]
}
{
"name": "ca-certificates-cacert",
"version": "20190108-r0",
"type": "apk",
"locations": [
"/lib/apk/db/installed"
]
}
{
"name": "libc-utils",
"version": "0.7.1-r0",
"type": "apk",
"locations": [
"/lib/apk/db/installed"
]
}
{
"name": "libcrypto1.1",
"version": "1.1.1a-r1",
"type": "apk",
"locations": [
"/lib/apk/db/installed"
]
}
{
"name": "libssl1.1",
"version": "1.1.1a-r1",
"type": "apk",
"locations": [
"/lib/apk/db/installed"
]
}
{
"name": "libtls-standalone",
"version": "2.7.4-r6",
"type": "apk",
"locations": [
"/lib/apk/db/installed"
]
}
{
"name": "musl",
"version": "1.1.20-r3",
"type": "apk",
"locations": [
"/lib/apk/db/installed"
]
}
{
"name": "musl-utils",
"version": "1.1.20-r3",
"type": "apk",
"locations": [
"/lib/apk/db/installed"
]
}
{
"name": "scanelf",
"version": "1.2.3-r0",
"type": "apk",
"locations": [
"/lib/apk/db/installed"
]
}
{
"name": "ssl_client",
"version": "1.29.3-r10",
"type": "apk",
"locations": [
"/lib/apk/db/installed"
]
}
{
"name": "zlib",
"version": "1.2.11-r1",
"type": "apk",
"locations": [
"/lib/apk/db/installed"
]
}
Files by MIME type:
Filters files by MIME type, useful for finding specific file types
.files[] |
select(.metadata.mimeType == "application/x-sharedlib") | # Filter by MIME type
{
path: .location.path,
mimeType: .metadata.mimeType,
size: .metadata.size # File size in bytes
}
syft alpine:3.9.2 -o json | \
jq '.files[] |
select(.metadata.mimeType == "application/x-sharedlib") |
{
path: .location.path,
mimeType: .metadata.mimeType,
size: .metadata.size
}'
{
"path": "/bin/busybox",
"mimeType": "application/x-sharedlib",
"size": 841320
}
{
"path": "/lib/ld-musl-aarch64.so.1",
"mimeType": "application/x-sharedlib",
"size": 616960
}
{
"path": "/lib/libcrypto.so.1.1",
"mimeType": "application/x-sharedlib",
"size": 2321984
}
{
"path": "/lib/libssl.so.1.1",
"mimeType": "application/x-sharedlib",
"size": 515376
}
{
"path": "/lib/libz.so.1.2.11",
"mimeType": "application/x-sharedlib",
"size": 91888
}
{
"path": "/sbin/apk",
"mimeType": "application/x-sharedlib",
"size": 218928
}
{
"path": "/sbin/mkmntdirs",
"mimeType": "application/x-sharedlib",
"size": 5712
}
{
"path": "/usr/bin/getconf",
"mimeType": "application/x-sharedlib",
"size": 33544
}
{
"path": "/usr/bin/getent",
"mimeType": "application/x-sharedlib",
"size": 48704
}
{
"path": "/usr/bin/iconv",
"mimeType": "application/x-sharedlib",
"size": 21968
}
{
"path": "/usr/bin/scanelf",
"mimeType": "application/x-sharedlib",
"size": 79592
}
{
"path": "/usr/bin/ssl_client",
"mimeType": "application/x-sharedlib",
"size": 9808
}
{
"path": "/usr/lib/engines-1.1/afalg.so",
"mimeType": "application/x-sharedlib",
"size": 18568
}
{
"path": "/usr/lib/engines-1.1/capi.so",
"mimeType": "application/x-sharedlib",
"size": 5672
}
{
"path": "/usr/lib/engines-1.1/padlock.so",
"mimeType": "application/x-sharedlib",
"size": 5672
}
{
"path": "/usr/lib/libtls-standalone.so.1.0.0",
"mimeType": "application/x-sharedlib",
"size": 96032
}
Dependency relationships:
Traverses package dependency graph using relationships
. as $root |
.artifactRelationships[] |
select(.type == "dependency-of") | # Filter for dependency relationships
.parent as $parent |
.child as $child |
{
parent: ($root.artifacts[] | select(.id == $parent).name), # Parent package name
child: ($root.artifacts[] | select(.id == $child).name) # Dependency name
}
syft node:18-alpine -o json | \
jq '. as $root |
.artifactRelationships[] |
select(.type == "dependency-of") |
.parent as $parent |
.child as $child |
{
parent: ($root.artifacts[] | select(.id == $parent).name),
child: ($root.artifacts[] | select(.id == $child).name)
}'
{
"parent": "ca-certificates-bundle",
"child": "apk-tools"
}
{
"parent": "alpine-keys",
"child": "alpine-release"
}
{
"parent": "alpine-baselayout-data",
"child": "alpine-baselayout"
}
{
"parent": "musl",
"child": "ssl_client"
}
{
"parent": "musl",
"child": "libgcc"
}
{
"parent": "musl",
"child": "libstdc++"
}
{
"parent": "musl",
"child": "musl-utils"
}
{
"parent": "musl",
"child": "libssl3"
}
{
"parent": "musl",
"child": "busybox"
}
{
"parent": "musl",
"child": "apk-tools"
}
{
"parent": "musl",
"child": "scanelf"
}
{
"parent": "musl",
"child": "libcrypto3"
}
{
"parent": "musl",
"child": "zlib"
}
{
"parent": "libgcc",
"child": "libstdc++"
}
{
"parent": "libssl3",
"child": "ssl_client"
}
{
"parent": "libssl3",
"child": "apk-tools"
}
{
"parent": "busybox",
"child": "busybox-binsh"
}
{
"parent": "scanelf",
"child": "musl-utils"
}
{
"parent": "busybox-binsh",
"child": "alpine-baselayout"
}
{
"parent": "libcrypto3",
"child": "ssl_client"
}
{
"parent": "libcrypto3",
"child": "libssl3"
}
{
"parent": "libcrypto3",
"child": "apk-tools"
}
{
"parent": "zlib",
"child": "apk-tools"
}
Files without packages:
Finds orphaned files not associated with any package
. as $root |
[.files[].id] as $allFiles | # All file IDs
[.artifactRelationships[] | select(.type == "contains") | .child] as $ownedFiles | # Package-owned files
($allFiles - $ownedFiles) as $orphans | # Set subtraction for unowned files
$root.files[] |
select(.id as $id | $orphans | index($id)) | # Filter to orphaned files
.location.path
syft alpine:3.9.2 -o json | \
jq '. as $root |
[.files[].id] as $allFiles |
[.artifactRelationships[] | select(.type == "contains") | .child] as $ownedFiles |
($allFiles - $ownedFiles) as $orphans |
$root.files[] |
select(.id as $id | $orphans | index($id)) |
.location.path'
"/lib/apk/db/installed"
Largest files:
Identifies the top 10 largest files by size
[.files[] |
{
path: .location.path,
size: .metadata.size,
mimeType: .metadata.mimeType
}] |
sort_by(.size) |
reverse | # Largest first
.[0:10] # Top 10 files
syft alpine:3.9.2 -o json | \
jq '[.files[] |
{
path: .location.path,
size: .metadata.size,
mimeType: .metadata.mimeType
}] |
sort_by(.size) |
reverse |
.[0:10]'
[
{
"path": "/lib/libcrypto.so.1.1",
"size": 2321984,
"mimeType": "application/x-sharedlib"
},
{
"path": "/bin/busybox",
"size": 841320,
"mimeType": "application/x-sharedlib"
},
{
"path": "/lib/ld-musl-aarch64.so.1",
"size": 616960,
"mimeType": "application/x-sharedlib"
},
{
"path": "/lib/libssl.so.1.1",
"size": 515376,
"mimeType": "application/x-sharedlib"
},
{
"path": "/etc/ssl/cert.pem",
"size": 232598,
"mimeType": "text/plain"
},
{
"path": "/sbin/apk",
"size": 218928,
"mimeType": "application/x-sharedlib"
},
{
"path": "/usr/lib/libtls-standalone.so.1.0.0",
"size": 96032,
"mimeType": "application/x-sharedlib"
},
{
"path": "/lib/libz.so.1.2.11",
"size": 91888,
"mimeType": "application/x-sharedlib"
},
{
"path": "/usr/bin/scanelf",
"size": 79592,
"mimeType": "application/x-sharedlib"
},
{
"path": "/usr/bin/getent",
"size": 48704,
"mimeType": "application/x-sharedlib"
}
]
Extract CPEs:
Lists Common Platform Enumeration identifiers for vulnerability scanning
.artifacts[] |
select(.cpes != null and (.cpes | length) > 0) | # Filter packages with CPEs
{
name,
version,
cpes: [.cpes[].cpe] # Extract CPE strings
}
syft alpine:3.9.2 -o json | \
jq '.artifacts[] |
select(.cpes != null and (.cpes | length) > 0) |
{
name,
version,
cpes: [.cpes[].cpe]
}'
{
"name": "alpine-baselayout",
"version": "3.1.0-r3",
"cpes": [
"cpe:2.3:a:alpine-baselayout:alpine-baselayout:3.1.0-r3:*:*:*:*:*:*:*",
"cpe:2.3:a:alpine-baselayout:alpine_baselayout:3.1.0-r3:*:*:*:*:*:*:*",
"cpe:2.3:a:alpine_baselayout:alpine-baselayout:3.1.0-r3:*:*:*:*:*:*:*",
"cpe:2.3:a:alpine_baselayout:alpine_baselayout:3.1.0-r3:*:*:*:*:*:*:*",
"cpe:2.3:a:alpine:alpine-baselayout:3.1.0-r3:*:*:*:*:*:*:*",
"cpe:2.3:a:alpine:alpine_baselayout:3.1.0-r3:*:*:*:*:*:*:*"
]
}
{
"name": "alpine-keys",
"version": "2.1-r1",
"cpes": [
"cpe:2.3:a:alpine-keys:alpine-keys:2.1-r1:*:*:*:*:*:*:*",
"cpe:2.3:a:alpine-keys:alpine_keys:2.1-r1:*:*:*:*:*:*:*",
"cpe:2.3:a:alpine_keys:alpine-keys:2.1-r1:*:*:*:*:*:*:*",
"cpe:2.3:a:alpine_keys:alpine_keys:2.1-r1:*:*:*:*:*:*:*",
"cpe:2.3:a:alpine:alpine-keys:2.1-r1:*:*:*:*:*:*:*",
"cpe:2.3:a:alpine:alpine_keys:2.1-r1:*:*:*:*:*:*:*"
]
}
{
"name": "apk-tools",
"version": "2.10.3-r1",
"cpes": [
"cpe:2.3:a:apk-tools:apk-tools:2.10.3-r1:*:*:*:*:*:*:*",
"cpe:2.3:a:apk-tools:apk_tools:2.10.3-r1:*:*:*:*:*:*:*",
"cpe:2.3:a:apk_tools:apk-tools:2.10.3-r1:*:*:*:*:*:*:*",
"cpe:2.3:a:apk_tools:apk_tools:2.10.3-r1:*:*:*:*:*:*:*",
"cpe:2.3:a:apk:apk-tools:2.10.3-r1:*:*:*:*:*:*:*",
"cpe:2.3:a:apk:apk_tools:2.10.3-r1:*:*:*:*:*:*:*"
]
}
{
"name": "busybox",
"version": "1.29.3-r10",
"cpes": [
"cpe:2.3:a:busybox:busybox:1.29.3-r10:*:*:*:*:*:*:*"
]
}
{
"name": "ca-certificates-cacert",
"version": "20190108-r0",
"cpes": [
"cpe:2.3:a:ca-certificates-cacert:ca-certificates-cacert:20190108-r0:*:*:*:*:*:*:*",
"cpe:2.3:a:ca-certificates-cacert:ca_certificates_cacert:20190108-r0:*:*:*:*:*:*:*",
"cpe:2.3:a:ca_certificates_cacert:ca-certificates-cacert:20190108-r0:*:*:*:*:*:*:*",
"cpe:2.3:a:ca_certificates_cacert:ca_certificates_cacert:20190108-r0:*:*:*:*:*:*:*",
"cpe:2.3:a:ca-certificates:ca-certificates-cacert:20190108-r0:*:*:*:*:*:*:*",
"cpe:2.3:a:ca-certificates:ca_certificates_cacert:20190108-r0:*:*:*:*:*:*:*",
"cpe:2.3:a:ca_certificates:ca-certificates-cacert:20190108-r0:*:*:*:*:*:*:*",
"cpe:2.3:a:ca_certificates:ca_certificates_cacert:20190108-r0:*:*:*:*:*:*:*",
"cpe:2.3:a:mozilla:ca-certificates-cacert:20190108-r0:*:*:*:*:*:*:*",
"cpe:2.3:a:mozilla:ca_certificates_cacert:20190108-r0:*:*:*:*:*:*:*",
"cpe:2.3:a:ca:ca-certificates-cacert:20190108-r0:*:*:*:*:*:*:*",
"cpe:2.3:a:ca:ca_certificates_cacert:20190108-r0:*:*:*:*:*:*:*"
]
}
{
"name": "libc-utils",
"version": "0.7.1-r0",
"cpes": [
"cpe:2.3:a:libc-utils:libc-utils:0.7.1-r0:*:*:*:*:*:*:*",
"cpe:2.3:a:libc-utils:libc_utils:0.7.1-r0:*:*:*:*:*:*:*",
"cpe:2.3:a:libc_utils:libc-utils:0.7.1-r0:*:*:*:*:*:*:*",
"cpe:2.3:a:libc_utils:libc_utils:0.7.1-r0:*:*:*:*:*:*:*",
"cpe:2.3:a:libc:libc-utils:0.7.1-r0:*:*:*:*:*:*:*",
"cpe:2.3:a:libc:libc_utils:0.7.1-r0:*:*:*:*:*:*:*"
]
}
{
"name": "libcrypto1.1",
"version": "1.1.1a-r1",
"cpes": [
"cpe:2.3:a:libcrypto1.1:libcrypto1.1:1.1.1a-r1:*:*:*:*:*:*:*",
"cpe:2.3:a:libcrypto1.1:libcrypto:1.1.1a-r1:*:*:*:*:*:*:*",
"cpe:2.3:a:libcrypto:libcrypto1.1:1.1.1a-r1:*:*:*:*:*:*:*",
"cpe:2.3:a:libcrypto:libcrypto:1.1.1a-r1:*:*:*:*:*:*:*"
]
}
{
"name": "libssl1.1",
"version": "1.1.1a-r1",
"cpes": [
"cpe:2.3:a:libssl1.1:libssl1.1:1.1.1a-r1:*:*:*:*:*:*:*",
"cpe:2.3:a:libssl1.1:libssl:1.1.1a-r1:*:*:*:*:*:*:*",
"cpe:2.3:a:libssl:libssl1.1:1.1.1a-r1:*:*:*:*:*:*:*",
"cpe:2.3:a:libssl:libssl:1.1.1a-r1:*:*:*:*:*:*:*"
]
}
{
"name": "libtls-standalone",
"version": "2.7.4-r6",
"cpes": [
"cpe:2.3:a:libtls-standalone:libtls-standalone:2.7.4-r6:*:*:*:*:*:*:*",
"cpe:2.3:a:libtls-standalone:libtls_standalone:2.7.4-r6:*:*:*:*:*:*:*",
"cpe:2.3:a:libtls_standalone:libtls-standalone:2.7.4-r6:*:*:*:*:*:*:*",
"cpe:2.3:a:libtls_standalone:libtls_standalone:2.7.4-r6:*:*:*:*:*:*:*",
"cpe:2.3:a:libtls:libtls-standalone:2.7.4-r6:*:*:*:*:*:*:*",
"cpe:2.3:a:libtls:libtls_standalone:2.7.4-r6:*:*:*:*:*:*:*"
]
}
{
"name": "musl",
"version": "1.1.20-r3",
"cpes": [
"cpe:2.3:a:musl-libc:musl:1.1.20-r3:*:*:*:*:*:*:*",
"cpe:2.3:a:musl_libc:musl:1.1.20-r3:*:*:*:*:*:*:*",
"cpe:2.3:a:musl:musl:1.1.20-r3:*:*:*:*:*:*:*"
]
}
{
"name": "musl-utils",
"version": "1.1.20-r3",
"cpes": [
"cpe:2.3:a:musl-utils:musl-utils:1.1.20-r3:*:*:*:*:*:*:*",
"cpe:2.3:a:musl-utils:musl_utils:1.1.20-r3:*:*:*:*:*:*:*",
"cpe:2.3:a:musl_utils:musl-utils:1.1.20-r3:*:*:*:*:*:*:*",
"cpe:2.3:a:musl_utils:musl_utils:1.1.20-r3:*:*:*:*:*:*:*",
"cpe:2.3:a:musl:musl-utils:1.1.20-r3:*:*:*:*:*:*:*",
"cpe:2.3:a:musl:musl_utils:1.1.20-r3:*:*:*:*:*:*:*"
]
}
{
"name": "scanelf",
"version": "1.2.3-r0",
"cpes": [
"cpe:2.3:a:scanelf:scanelf:1.2.3-r0:*:*:*:*:*:*:*"
]
}
{
"name": "ssl_client",
"version": "1.29.3-r10",
"cpes": [
"cpe:2.3:a:ssl-client:ssl-client:1.29.3-r10:*:*:*:*:*:*:*",
"cpe:2.3:a:ssl-client:ssl_client:1.29.3-r10:*:*:*:*:*:*:*",
"cpe:2.3:a:ssl_client:ssl-client:1.29.3-r10:*:*:*:*:*:*:*",
"cpe:2.3:a:ssl_client:ssl_client:1.29.3-r10:*:*:*:*:*:*:*",
"cpe:2.3:a:ssl:ssl-client:1.29.3-r10:*:*:*:*:*:*:*",
"cpe:2.3:a:ssl:ssl_client:1.29.3-r10:*:*:*:*:*:*:*"
]
}
{
"name": "zlib",
"version": "1.2.11-r1",
"cpes": [
"cpe:2.3:a:zlib:zlib:1.2.11-r1:*:*:*:*:*:*:*"
]
}
Packages without licenses:
Identifies packages missing license information for compliance audits
.artifacts[] |
select(.licenses == null or (.licenses | length) == 0) | # Packages without license info
{
name,
version,
type,
locations: [.locations[].path] # Where package is installed
}
syft httpd:2.4.65 -o json | \
jq '.artifacts[] |
select(.licenses == null or (.licenses | length) == 0) |
{
name,
version,
type,
locations: [.locations[].path]
}'
{
"name": "httpd",
"version": "2.4.65",
"type": "binary",
"locations": ["/usr/local/apache2/bin/httpd"]
}
Packages with CPE identifiers:
Lists packages with CPE identifiers indicating potential CVE matches
.artifacts[] |
select(.cpes != null and (.cpes | length) > 0) | # Packages with CPE identifiers
{
name,
version,
type,
cpeCount: (.cpes | length) # Number of CPE matches
}
syft alpine:3.9.2 -o json | \
jq '.artifacts[] |
select(.cpes != null and (.cpes | length) > 0) |
{
name,
version,
type,
cpeCount: (.cpes | length)
}'
{
"name": "alpine-baselayout",
"version": "3.1.0-r3",
"type": "apk",
"cpeCount": 6
}
{
"name": "alpine-keys",
"version": "2.1-r1",
"type": "apk",
"cpeCount": 6
}
{
"name": "apk-tools",
"version": "2.10.3-r1",
"type": "apk",
"cpeCount": 6
}
{
"name": "busybox",
"version": "1.29.3-r10",
"type": "apk",
"cpeCount": 1
}
{
"name": "ca-certificates-cacert",
"version": "20190108-r0",
"type": "apk",
"cpeCount": 12
}
{
"name": "libc-utils",
"version": "0.7.1-r0",
"type": "apk",
"cpeCount": 6
}
{
"name": "libcrypto1.1",
"version": "1.1.1a-r1",
"type": "apk",
"cpeCount": 4
}
{
"name": "libssl1.1",
"version": "1.1.1a-r1",
"type": "apk",
"cpeCount": 4
}
{
"name": "libtls-standalone",
"version": "2.7.4-r6",
"type": "apk",
"cpeCount": 6
}
{
"name": "musl",
"version": "1.1.20-r3",
"type": "apk",
"cpeCount": 3
}
{
"name": "musl-utils",
"version": "1.1.20-r3",
"type": "apk",
"cpeCount": 6
}
{
"name": "scanelf",
"version": "1.2.3-r0",
"type": "apk",
"cpeCount": 1
}
{
"name": "ssl_client",
"version": "1.29.3-r10",
"type": "apk",
"cpeCount": 6
}
{
"name": "zlib",
"version": "1.2.11-r1",
"type": "apk",
"cpeCount": 1
}
Next steps
- Explore output formats to see all available SBOM formats
- Learn about format conversion to generate multiple formats efficiently
- Use templates to create custom output formats
1.5 - Package 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.
Example: Python Package Detection
Scanning an image:
$ syft <container-image> --select-catalogers python
# Uses: python-installed-package-cataloger
# Finds: Packages in site-packages directories
Scanning a directory:
$ 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:
syft busybox:latest -o json | jq '.descriptor.configuration.catalogers'
Output:
{
"requested": {
"default": [
"image",
"file"
]
},
"used": [
"alpm-db-cataloger",
"apk-db-cataloger",
"binary-classifier-cataloger",
"bitnami-cataloger",
"cargo-auditable-binary-cataloger",
"conan-info-cataloger",
"dotnet-deps-binary-cataloger",
"dotnet-packages-lock-cataloger",
"dpkg-db-cataloger",
"elf-binary-package-cataloger",
...
]
}
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:
┌───────────────────────────┬───────────────────────┐
│ FILE CATALOGER │ TAGS │
├───────────────────────────┼───────────────────────┤
│ file-content-cataloger │ content, file │
│ file-digest-cataloger │ digest, file │
│ file-executable-cataloger │ binary-metadata, file │
│ file-metadata-cataloger │ file, file-metadata │
└───────────────────────────┴───────────────────────┘
┌────────────────────────────────────┬────────────────────────────────────────────────────────┐
│ PACKAGE CATALOGER │ TAGS │
├────────────────────────────────────┼────────────────────────────────────────────────────────┤
│ python-installed-package-cataloger │ directory, image, installed, language, package, python │
│ python-package-cataloger │ declared, directory, language, package, python │
│ java-archive-cataloger │ directory, image, installed, java, language, maven │
│ go-module-binary-cataloger │ binary, directory, go, golang, image, installed │
│ ... │ │
└────────────────────────────────────┴────────────────────────────────────────────────────────┘
Test cataloger selection
Preview which catalogers a selection expression would use:
$ syft cataloger list --select-catalogers python
Default selections: 1
• 'all'
Selection expressions: 1
• 'python' (intersect)
┌────────────────────────────────────┬────────────────────────────────────────────────────────┐
│ PACKAGE CATALOGER │ TAGS │
├────────────────────────────────────┼────────────────────────────────────────────────────────┤
│ python-installed-package-cataloger │ directory, image, installed, language, package, python │
│ python-package-cataloger │ declared, directory, language, package, python │
└────────────────────────────────────┴────────────────────────────────────────────────────────┘
This shows exactly which catalogers your selection expression will use, helping you verify your configuration before running a scan.
Output formats
Get cataloger information in different formats:
# Table format (default)
$ syft cataloger list
# JSON format (useful for automation)
$ syft cataloger list -o json
Cataloger References
You can refer to catalogers in two ways:
- By name: The exact cataloger identifier (e.g.,
java-pom-cataloger
,go-module-binary-cataloger
) - By tag: A group label for related catalogers (e.g.,
java
,python
,image
,directory
)
Common tags include:
- Language tags:
python
,java
,go
,javascript
,ruby
,rust
, etc. - Scan type tags:
image
,directory
- Installation state tags:
installed
,declared
- Ecosystem tags:
maven
,npm
,cargo
,composer
, etc.
Customizing Cataloger Selection
Syft provides two flags for controlling catalogers:
--select-catalogers
: Modify Defaults
Use this flag to adjust the default cataloger set. This is the recommended approach for most use cases.
Syntax:
Operation | Syntax | Example | Description |
---|---|---|---|
Filter | <tag> |
--select-catalogers java |
Use only Java catalogers from the defaults |
Add | +<name> |
--select-catalogers +sbom-cataloger |
Add a specific cataloger to defaults |
Remove | -<name-or-tag> |
--select-catalogers -rpm |
Remove catalogers by name or tag |
Combine | <tag>,+<name>,-<tag> |
--select-catalogers java,+sbom-cataloger,-maven |
Multiple operations together |
Selection Logic:
- Start with default catalogers (image or directory based)
- If tags provided (without
+
or-
), filter to only those tagged catalogers - Remove any catalogers matching
-<name-or-tag>
- Add any catalogers specified with
+<name>
Note
Added catalogers (prefixed with+
) are always included, regardless of other filters or removals.
--override-default-catalogers
: Replace Defaults
Use this flag to completely replace Syft’s default cataloger selection. This bypasses the automatic image vs. directory behavior.
Syntax:
--override-default-catalogers <comma-separated-names-or-tags>
When to use:
- 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:
syft <target> --select-catalogers +sbom-cataloger,+binary-cataloger
Removing Catalogers
Use defaults but exclude all RPM-related catalogers:
syft <target> --select-catalogers -rpm
Scan with defaults but remove Java JAR cataloger specifically:
syft <target> --select-catalogers -java-archive-cataloger
Combining Operations
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)
Filter to Java, add POM cataloger, remove Gradle:
syft <directory> --select-catalogers java,+java-pom-cataloger,-gradle
Complete Override Examples
Use only binary analysis catalogers regardless of scan type:
$ syft <target> --override-default-catalogers binary
# Result: binary-cataloger, cargo-auditable-binary-cataloger,
# dotnet-portable-executable-cataloger, go-module-binary-cataloger
Use exactly two specific catalogers:
syft <target> --override-default-catalogers go-module-binary-cataloger,go-module-file-cataloger
Use all directory catalogers even when scanning an image:
syft <container-image> --override-default-catalogers directory
Troubleshooting
My language isn’t being detected
Check which catalogers ran and whether they found packages:
# See which catalogers were used
$ syft <target> -o json | jq '.descriptor.configuration.catalogers.used'
# See which catalogers found packages
$ syft <target> -o json | jq '.artifacts[].foundBy'
# See packages found by a specific cataloger
$ syft <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?
Check the SBOM’s cataloger configuration:
syft <target> -o json | jq '.descriptor.configuration.catalogers.requested'
This shows the selection strategy used:
"default": ["image", "file"]
indicates image defaults"default": ["directory", "file"]
indicates directory defaults
What’s the difference between a name and a tag?
- Name: The unique identifier for a single cataloger (e.g.,
python-package-cataloger
) - Tag: A label that groups multiple catalogers (e.g.,
python
includes bothpython-package-cataloger
andpython-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.
1.6 - File Selection
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 spaceowned-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 directory
syft <source> --exclude /etc
# Exclude files by pattern
syft <source> --exclude './out/**/*.json'
# Combine multiple exclusions
syft <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' # Correct
syft <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 directories
syft alpine:latest --exclude /etc --exclude /var
# Exclude files by pattern across entire filesystem
syft 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/foo
syft /usr/foo --exclude ./package.json # Excludes /usr/foo/package.json
syft /usr/foo --exclude '**/package.json' # Excludes all package.json files under /usr/foo
syft /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.
Common exclusion patterns
# Exclude all JSON files
syft <source> --exclude '**/*.json'
# Exclude build output directories
syft <source> --exclude '**/dist/**' --exclude '**/build/**'
# Exclude dependency directories
syft <source> --exclude '**/node_modules/**' --exclude '**/vendor/**'
# Exclude test files
syft <source> --exclude '**/*_test.go' --exclude '**/test/**'
1.7 - Using Templates
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:
syft <image> -o template -t ./path/to/custom.tmpl
You can also configure the template path in your configuration file:
#.syft.yaml
format:
template:
path: "/path/to/template.tmpl"
Available fields
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 structure
syft <image> -o json
# Explore specific fields
syft <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).descriptor
- Syft version and configuration
Common package (artifact) fields:
.name
,.version
,.type
- Basic package info.licenses
- License information (array).purl
- Package URL.cpes
- Common Platform Enumerations.locations
- Where the package was found
Template functions
Syft templates support:
- Go template built-ins - See the Go template documentation
- Sprig functions - Additional helpers from Sprig
- Syft-specific functions:
Function | Arguments | Description |
---|---|---|
getLastIndex |
collection |
Returns the last index of a slice (length - 1), useful for comma-separated lists |
hasField |
obj , field |
Checks if a field exists on an object, returns boolean |
Examples
The following examples show template source code and the rendered output when run against alpine:3.9.2
:
CSV output
"Package","Version","Type","Found by"
{{- range .artifacts}}
"{{.name}}","{{.version}}","{{.type}}","{{.foundBy}}"
{{- end}}
"Package","Version","Type","Found by"
"alpine-baselayout","3.1.0-r3","apk","apk-db-cataloger"
"alpine-keys","2.1-r1","apk","apk-db-cataloger"
"apk-tools","2.10.3-r1","apk","apk-db-cataloger"
"busybox","1.29.3-r10","apk","apk-db-cataloger"
"ca-certificates-cacert","20190108-r0","apk","apk-db-cataloger"
"libc-utils","0.7.1-r0","apk","apk-db-cataloger"
"libcrypto1.1","1.1.1a-r1","apk","apk-db-cataloger"
"libssl1.1","1.1.1a-r1","apk","apk-db-cataloger"
"libtls-standalone","2.7.4-r6","apk","apk-db-cataloger"
"musl","1.1.20-r3","apk","apk-db-cataloger"
"musl-utils","1.1.20-r3","apk","apk-db-cataloger"
"scanelf","1.2.3-r0","apk","apk-db-cataloger"
"ssl_client","1.29.3-r10","apk","apk-db-cataloger"
"zlib","1.2.11-r1","apk","apk-db-cataloger"
Filter by package type
{{range .artifacts}}
{{- if eq .type "apk"}}
{{.name}}@{{.version}}{{end}}
{{- end}}
alpine-baselayout@3.1.0-r3
alpine-keys@2.1-r1
apk-tools@2.10.3-r1
busybox@1.29.3-r10
ca-certificates-cacert@20190108-r0
libc-utils@0.7.1-r0
libcrypto1.1@1.1.1a-r1
libssl1.1@1.1.1a-r1
libtls-standalone@2.7.4-r6
musl@1.1.20-r3
musl-utils@1.1.20-r3
scanelf@1.2.3-r0
ssl_client@1.29.3-r10
zlib@1.2.11-r1
Markdown report
# SBOM Report: {{.source.metadata.userInput}}
Scanned: {{.source.name}}:{{.source.version}} ({{.source.type}})
{{- if .distro}}
Distribution: {{.distro.prettyName}}
{{- end}}
## Packages ({{len .artifacts}})
| Package | Version | Type |
|---------|---------|------|
{{- range .artifacts}}
| {{.name}} | {{.version}} | {{.type}} |
{{- end}}
# SBOM Report: alpine:3.9.2
Scanned: alpine:3.9.2 (image)
Distribution: Alpine Linux v3.9
## Packages (14)
| Package | Version | Type |
| ---------------------- | ----------- | ---- |
| alpine-baselayout | 3.1.0-r3 | apk |
| alpine-keys | 2.1-r1 | apk |
| apk-tools | 2.10.3-r1 | apk |
| busybox | 1.29.3-r10 | apk |
| ca-certificates-cacert | 20190108-r0 | apk |
| libc-utils | 0.7.1-r0 | apk |
| libcrypto1.1 | 1.1.1a-r1 | apk |
| libssl1.1 | 1.1.1a-r1 | apk |
| libtls-standalone | 2.7.4-r6 | apk |
| musl | 1.1.20-r3 | apk |
| musl-utils | 1.1.20-r3 | apk |
| scanelf | 1.2.3-r0 | apk |
| ssl_client | 1.29.3-r10 | apk |
| zlib | 1.2.11-r1 | apk |
License compliance
{{range .artifacts}}
{{- if .licenses}}
{{.name}}: {{range .licenses}}{{.value}} {{end}}{{end}}
{{- end}}
alpine-baselayout: GPL-2.0
alpine-keys: MIT
apk-tools: GPL2
busybox: GPL-2.0
ca-certificates-cacert: GPL-2.0-or-later MPL-2.0
libc-utils: BSD
libcrypto1.1: OpenSSL
libssl1.1: OpenSSL
libtls-standalone: ISC
musl: MIT
musl-utils: BSD GPL2+ MIT
scanelf: GPL-2.0
ssl_client: GPL-2.0
zlib: zlib
Custom JSON subset
{
"scanned": "{{.source.metadata.userInput}}",
"packages": [
{{- $last := sub (len .artifacts) 1}}
{{- range $i, $pkg := .artifacts}}
{"name": "{{$pkg.name}}", "version": "{{$pkg.version}}"}{{if ne $i $last}},{{end}}
{{- end}}
]
}
{
"scanned": "alpine:3.9.2",
"packages": [
{ "name": "alpine-baselayout", "version": "3.1.0-r3" },
{ "name": "alpine-keys", "version": "2.1-r1" },
{ "name": "apk-tools", "version": "2.10.3-r1" },
{ "name": "busybox", "version": "1.29.3-r10" },
{ "name": "ca-certificates-cacert", "version": "20190108-r0" },
{ "name": "libc-utils", "version": "0.7.1-r0" },
{ "name": "libcrypto1.1", "version": "1.1.1a-r1" },
{ "name": "libssl1.1", "version": "1.1.1a-r1" },
{ "name": "libtls-standalone", "version": "2.7.4-r6" },
{ "name": "musl", "version": "1.1.20-r3" },
{ "name": "musl-utils", "version": "1.1.20-r3" },
{ "name": "scanelf", "version": "1.2.3-r0" },
{ "name": "ssl_client", "version": "1.29.3-r10" },
{ "name": "zlib", "version": "1.2.11-r1" }
]
}
Executable file digests
{{range .files -}}
{{- if .executable}}
{{.location.path}}: {{range .digests}}{{if eq .algorithm "sha256"}}{{.value}}{{end}}{{end}}
{{end}}
{{- end}}
/bin/busybox: 2c1276c3c02ccec8a0e1737d3144cdf03db883f479c86fbd9c7ea4fd9b35eac5
/lib/ld-musl-aarch64.so.1: 0132814479f1acc1e264ef59f73fd91563235897e8dc1bd52765f974cde382ca
/lib/libcrypto.so.1.1: 6c597c8ad195eeb7a9130ad832dfa4cbf140f42baf96304711b2dbd43ba8e617
/lib/libssl.so.1.1: fb72f4615fb4574bd6eeabfdb86be47012618b9076d75aeb1510941c585cae64
/lib/libz.so.1.2.11: 19e790eb36a09eba397b5af16852f3bea21a242026bbba3da7b16442b8ba305b
/sbin/apk: 22d7d85bd24923f1f274ce765d16602191097829e22ac632748302817ce515d8
/sbin/mkmntdirs: a14a5a28525220224367616ef46d4713ef7bd00d22baa761e058e8bdd4c0af1b
/usr/bin/getconf: 82bcde66ead19bc3b9ff850f66c2dbf5eaff36d481f1ec154100f73f6265d2ef
/usr/bin/getent: 53ffb508150e91838d795831e8ecc71f2bc3a7db036c6d7f9512c3973418bb5e
/usr/bin/iconv: 1c99d1f4edcb8da6db1da60958051c413de45a4c15cd3b7f7285ed87f9a250ff
/usr/bin/scanelf: 908da485ad2edea35242f8989c7beb9536414782abc94357c72b7d840bb1fda2
/usr/bin/ssl_client: 67ab7f3a1ba35630f439d1ca4f73c7d95f8b7aa0e6f6db6ea1743f136f074ab4
/usr/lib/engines-1.1/afalg.so: ea7c2f48bc741fd828d79a304dbf713e20e001c0187f3f534d959886af87f4af
/usr/lib/engines-1.1/capi.so: b461ed43f0f244007d872e84760a446023b69b178c970acf10ed2666198942c6
/usr/lib/engines-1.1/padlock.so: 0ccb04f040afb0216da1cea2c1db7a0b91d990ce061e232782aedbd498483649
/usr/lib/libtls-standalone.so.1.0.0: 7f4c2ff4010e30a69f588ab4f213fdf9ce61a524a0eecd3f5af31dc760e8006c
Find binaries importing a library
{{range .files -}}
{{- if .executable}}
{{- $path := .location.path}}
{{- range .executable.importedLibraries}}
{{- if eq . "libcrypto.so.1.1"}}
{{$path}}
{{break}}
{{- end}}
{{- end}}
{{- end}}
{{- end}}
/lib/libssl.so.1.1
/sbin/apk
/usr/lib/engines-1.1/afalg.so
/usr/lib/libtls-standalone.so.1.0.0
Troubleshooting
“can’t evaluate field” errors: The field doesn’t exist or is misspelled. Check field names with syft <image> -o json | jq
.
Empty output: Verify your field paths are correct. Use syft <image> -o json
to see the actual data structure.
Template syntax errors: Refer to the Go template documentation for syntax help.
Note
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.
Additional resources
- Go template documentation - Template syntax reference
- Sprig function documentation - Helper functions
- Output formats - Other output format options
- Configuration options - Advanced settings
1.8 - Format Conversion
Experimental Feature
This feature is experimental and may change in future releases.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.
syft convert <ORIGINAL-SBOM-FILE> -o <NEW-SBOM-FORMAT>[=<NEW-SBOM-FILE>]
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 SBOM
syft 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 formats
syft 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.
Learn more
Learn more about working with Syft’s native format in the Working with Syft JSON guide.What gets preserved
Data Loss During Conversion
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.
Reliably preserved across conversions:
- Package names, versions, and PURLs
- License information
- CPEs and external references
- Package relationships
May be lost in conversions:
- Tool configuration and cataloger information
- Source metadata (image manifests, layers, container config)
- File location details and layer attribution
- Package-manager-specific metadata (git commits, checksums, provides/dependencies)
- Distribution details
When to convert vs regenerate
Convert from Syft JSON when:
- You need multiple formats for different tools
- The original source is unavailable
- Scanning takes significant time
Regenerate from source when:
- You need complete format-specific data
- Conversion output is missing critical information
1.9 - Attestation
Experimental Feature
This feature is experimental and may change in future releases.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.
Prerequisites
Before creating attestations, ensure you have:
- Syft installed
- Cosign ≥ v1.12.0 installed (installation guide)
- 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
Verify a keyless attestation
Anyone can verify the attestation using cosign:
COSIGN_EXPERIMENTAL=1 cosign verify-attestation <IMAGE>
Successful output shows:
- Attestation claims are validated
- Claims exist in the Sigstore transparency log
- Certificates verified against Fulcio (Sigstore’s certificate authority)
- Certificate subject (your identity email)
- Certificate issuer (identity provider URL)
Example:
Certificate subject: user@example.com
Certificate issuer URL: https://accounts.google.com
This proves the attestation was created by the specified identity.
Local key attestation
Local key attestation uses cryptographic key pairs you manage. You sign attestations with your private key, and consumers verify with your public key.
Create a key-based attestation
Generate the attestation and save it locally:
syft attest --output spdx-json --key cosign.key docker.io/myorg/myimage:latest > attestation.json
The output is a DSSE envelope containing an in-toto statement with your SBOM as the predicate.
Attach the attestation to your image
Use cosign to attach the attestation:
cosign attach attestation --attestation attestation.json docker.io/myorg/myimage:latest
You need write access to the image registry for this to succeed.
Verify a key-based attestation
Consumers verify using your public key:
cosign verify-attestation --key cosign.pub --type spdxjson docker.io/myorg/myimage:latest
Successful output shows:
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.
To extract and view the SBOM:
cosign verify-attestation --key cosign.pub --type spdxjson docker.io/myorg/myimage:latest | \
jq '.payload | @base64d | .payload | fromjson | .predicate'
Use with vulnerability scanning
Pipe the verified SBOM directly to Grype for vulnerability analysis:
cosign verify-attestation --key cosign.pub --type spdxjson docker.io/myorg/myimage:latest | \
jq '.payload | @base64d | .payload | fromjson | .predicate' | \
grype
This ensures you’re scanning a verified, trusted SBOM.
Troubleshooting
Authentication failures
- Ensure you’re logged into the registry:
docker login <registry>
- Verify you have write access to the image repository
Cosign version errors
- Update to cosign ≥ v1.12.0:
cosign version
Verification failures
- For keyless: ensure
COSIGN_EXPERIMENTAL=1
is set - For key-based: verify you’re using the correct public key
- Check the attestation type matches (
--type spdxjson
or--type cyclonedx-json
)
Permission denied uploading attestations
- Verify write access to the registry
- Check authentication credentials are current
- Ensure the image exists in the registry before attaching attestations
2 - Vulnerability Scanning
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.
2.1 - Getting Started
Introduction
Grype is an easy-to-integrate open source vulnerability scanning tool for container images and filesystems.
Install the latest Grype release
Grype is provided as a single compiled executable. Issue the command for your platform to download the latest release of Grype. The full list of official and community maintained packages can be found on the installation page.
curl -sSfL <https://get.anchore.io/grype> | sudo sh -s -- -b /usr/local/bin
brew install grype
nuget install Anchore.Grype
Once installed, ensure the grype
binary is in the PATH
for your system.
Scan a container for vulnerabilities
grype <image>
Scan a public container image for vulnerabilities
Run grype
with default options against a small container, which will be pulled from DockerHub. Grype will also download the latest vulnerability database. The output will be a simple human-readable table.
grype alpine:latest
✔ Loaded image alpine:latest
✔ Parsed image sha256:8d591b0b7dea080ea3be9e12ae563eebf9…
✔ Cataloged contents 058c92d86112aa6f641b01ed238a07a3885…
├── ✔ Packages [15 packages]
├── ✔ File metadata [82 locations]
├── ✔ File digests [82 files]
└── ✔ Executables [17 executables]
✔ Scanned for vulnerabilities [6 vulnerability matches]
├── by severity: 0 critical, 0 high, 0 medium, 6 low, 0 negligible
└── by status: 0 fixed, 6 not-fixed, 0 ignored
NAME INSTALLED FIXED-IN TYPE VULNERABILITY SEVERITY
busybox 1.37.0-r12 apk CVE-2024-58251 Low
busybox 1.37.0-r12 apk CVE-2025-46394 Low
busybox-binsh 1.37.0-r12 apk CVE-2024-58251 Low
busybox-binsh 1.37.0-r12 apk CVE-2025-46394 Low
ssl_client 1.37.0-r12 apk CVE-2024-58251 Low
ssl_client 1.37.0-r12 apk CVE-2025-46394 Low
Scan an existing SBOM for vulnerabilities
Grype can scan containers directly, but it can also scan an existing SBOM document.
Note
This presumes you already createdalpine_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
Grype should give similar output to the previous table.
Create a vulnerability report in JSON format
The JSON-formatted output from Grype may be processed or visualized by other tools.
Create the vulnerability report using the --output
, and via jq
to make it prettier.
grype alpine:latest --output json | jq . > vuln_report.json
Example:
✔ Pulled image
✔ Loaded image alpine:latest
✔ Parsed image sha256:8d591b0b7dea080ea3be9e12ae563eebf9869168ffced1cb25b2470a3d9fe15e
✔ Cataloged contents 058c92d86112aa6f641b01ed238a07a3885b8c0815de3e423e5c5f789c398b45
├── ✔ Packages [15 packages]
├── ✔ File digests [82 files]
├── ✔ Executables [17 executables]
└── ✔ File metadata [82 locations]
✔ Scanned for vulnerabilities [6 vulnerability matches]
├── by severity: 0 critical, 0 high, 0 medium, 6 low, 0 negligible
└── by status: 0 fixed, 6 not-fixed, 0 ignored
Create an HTML Vulnerability Report
Next steps
- Try searching for vulnerabilities in an older container!
- Learn about SBOM Generation and License Scanning your SBOMs.
2.2 - Vulnerability Database
Introduction
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.
Learn more
Find out more about the vulnerability data sources at Vulnerability Data Sources.Updating the local database
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.
Users can manage the locally cached database with the grype db
command:
Check and update the database
Manually checking for updates shouldn’t be necessary, due to Grype automatically doing this on launch. However, it is possible to force Grype to look for an updated vulnerability database.
grype db check
A message will indicate if no updates are available since the last download.
Installed DB version v6.0.2 was built on 2025-05-08T04:08:40Z
No update available
If the database is outdated, a message such as this will be displayed.
Installed DB version v6.0.2 was built on 2025-05-07T04:08:13Z
Updated DB version v6.0.2 was built on 2025-05-08T04:08:40Z
You can run 'grype db update' to update to the latest db
[0000] ERROR db upgrade available
grype db update
A short animation will show progress of downloading, uncompressing and hydrating (creating indexes on) the database. Then a message reporting the successful update will be displayed.
grype db update
✔ Vulnerability DB [updated]
Vulnerability database updated to latest version!
Next steps
- Learn how the vulnerability DB is created and published.
- Learn about SBOM Generation and License Scanning your SBOMs.
2.3 - Data sources
Grype matches vulnerabilities by comparing package information from your software against vulnerability databases. Grype sources these databases from multiple upstream providers, each covering different operating systems and programming language ecosystems. This page documents each data source, what it covers, and how Grype interprets the data.
Quick reference
Language ecosystems
Ecosystem | Data Source | Vunnel provider |
---|---|---|
Composer (PHP) | GitHub Security Advisories | github |
Dart | GitHub Security Advisories | github |
Go | GitHub Security Advisories | github |
Java (Maven) | GitHub Security Advisories | github |
npm (JavaScript) | GitHub Security Advisories | github |
NuGet (.NET) | GitHub Security Advisories | github |
Python (PyPI) | GitHub Security Advisories | github |
Ruby (RubyGems) | GitHub Security Advisories | github |
Rust (crates.io) | GitHub Security Advisories | github |
Swift | GitHub Security Advisories | github |
GitHub Actions | GitHub Security Advisories | github |
Various | Bitnami Vulnerability Database | bitnami |
Operating systems
Operating System | Supported Versions | Data Source | Vunnel provider |
---|---|---|---|
Ubuntu | 12.04, 14.04, 16.04, 18.04, 20.04, 22.04, 24.04, 24.10, 25.04, 25.10 |
Ubuntu CVE Tracker | ubuntu |
Debian | 7 (wheezy), 8 (jessie), 9 (stretch), 10 (buster), 11 (bullseye), 12 (bookworm), 13 (trixie), 14 (forky), 15 (duke), unstable (sid) |
Debian Security Tracker | debian |
Alpine Linux | 3.2+, edge | Alpine SecDB | alpine |
Red Hat Enterprise Linux | 5, 6, 7, 8, 9 | Red Hat Security Data API | rhel |
Amazon Linux | 2, 2022, 2023 | Amazon Linux Security Center | amazon |
Oracle Linux | 5, 6, 7, 8, 9 | Oracle Linux Security | oracle |
SUSE Linux Enterprise Server | 11, 12, 15 | SUSE Security OVAL | sles |
Wolfi | Current | Wolfi Security | wolfi |
Chainguard | Current | Chainguard Security | chainguard |
AlmaLinux | 8, 9 | AlmaLinux OSV Database | alma |
Rocky Linux | 8, 9 | Rocky Linux Apollo API | rocky |
CBL-Mariner | 1.0, 2.0, 3.0 | Microsoft CBL-Mariner OVAL | mariner |
Cross-cutting sources
The National Vulnerability Database (NVD) provides Common Vulnerabilities and Exposures (CVE) data that supplements ecosystem-specific sources. Grype uses the NVD CVE API 2.0 (Vunnel provider: nvd
) to access vulnerability information across all ecosystems using Common Platform Enumeration (CPE) matching.
Language ecosystem providers
GitHub Security Advisories
Data source: GitHub Security Advisories
Vunnel provider: github
What it covers:
GitHub Security Advisories provides vulnerability data for multiple language ecosystems:
- Composer (PHP) →
composer
- Dart →
dart
- Go →
go
- Java (Maven) →
java
- npm (JavaScript) →
npm
- NuGet (.NET) →
nuget
- Python (PyPI) →
python
- Ruby (RubyGems) →
gem
- Rust (crates.io) →
rust
- Swift →
swift
- GitHub Actions →
github-action
How it works:
Grype retrieves vulnerability data from GitHub’s GraphQL Application Programming Interface (API). Each advisory includes a GitHub Security Advisories ID (GHSA-xxx) and may include associated CVE identifiers. The data includes both general vulnerabilities and malware classifications.
The provider downloads advisories in batches of 100 per GraphQL request and handles GitHub’s rate limiting by pausing when fewer than 10 API requests remain. For incremental updates, the provider uses an updatedSince
timestamp parameter to fetch only advisories modified since the last update.
Assumptions and interpretation:
-
Severity mapping: GitHub provides four severity levels that map directly to Grype’s normalized scale:
- LOW → Low
- MODERATE → Medium
- HIGH → High
- CRITICAL → Critical
-
Version matching: GitHub provides version ranges in ecosystem-specific formats. For example, npm packages use semantic versioning (semver) syntax, while Python packages use PEP 440 version specifiers. Grype interprets these ranges according to each ecosystem’s version comparison rules.
-
CVSS scores: When available, Grype extracts and validates CVSS vector strings from the advisory data to provide detailed vulnerability scoring information.
-
Authentication: GitHub requires a personal access token for API access. Without proper authentication, data retrieval fails.
Bitnami Vulnerability Database
Data source: Bitnami Vulnerability Database
Vunnel provider: bitnami
What it covers:
The Bitnami Vulnerability Database contains vulnerability information for applications packaged by Bitnami. The data covers various language ecosystems and is stored in Open Source Vulnerability (OSV) format version 1.5.0.
How it works:
Grype clones the Bitnami VulnDB Git repository from the main branch and processes the OSV-formatted vulnerability records.
Assumptions and interpretation:
-
Data format: All vulnerability records follow the OSV schema, which provides a standardized structure for vulnerability information across different ecosystems.
-
Scope: The database focuses on vulnerabilities affecting Bitnami-packaged applications, which may include both upstream vulnerabilities and Bitnami-specific issues.
Operating system providers
Ubuntu Security Tracker
Data source: Ubuntu CVE Tracker
Vunnel provider: ubuntu
Supported versions:
- 12.04 (precise)
- 14.04 (trusty)
- 16.04 (xenial)
- 18.04 (bionic)
- 20.04 (focal)
- 22.04 (jammy)
- 24.04 (noble)
- 24.10 (oracular)
- 25.04 (plucky)
- 25.10 (questing)
Additional development and end-of-life releases are also supported.
How it works:
Grype clones the Ubuntu CVE Tracker Git repository and parses the tracking files that document vulnerability status for each Ubuntu release. The tracker includes patch states that indicate whether a package is vulnerable, fixed, or not affected.
For end-of-life Ubuntu releases, Grype examines the repository’s revision history to determine the final patch states before support ended.
Assumptions and interpretation:
-
Severity mapping: Ubuntu uses a six-level severity scale that maps to Grype’s normalized levels:
- Untriaged → Unknown
- Negligible → Negligible
- Low → Low
- Medium → Medium
- High → High
- Critical → Critical
-
Patch states: Ubuntu tracks vulnerabilities with several patch states:
DNE
(Does Not Exist) → Package not affected because it doesn’t exist in this releaseneeds-triage
→ Vulnerability confirmed but not yet assessedneeded
→ Vulnerable, no fix available yetreleased
→ Vulnerable, fix available at specified versionpending
→ Fix prepared but not yet releasedactive
→ Vulnerability being actively worked onignored
→ Vulnerability acknowledged but deliberately not fixed (not considered vulnerable for matching purposes)
-
Version format: Ubuntu uses dpkg version comparison rules for determining whether a package version is affected.
-
End-of-life handling: For releases that have reached end-of-life, Grype merges patch states from the repository’s revision history to capture the final vulnerability status.
-
Fix availability: When a patch state indicates
released
, Grype extracts the fix version from the tracking data. A fix version of “None” means the package is vulnerable with no fix available.
Debian Security Tracker
Data source: Debian Security Tracker
Vunnel provider: debian
Supported versions:
- 7 (wheezy)
- 8 (jessie)
- 9 (stretch)
- 10 (buster)
- 11 (bullseye)
- 12 (bookworm)
- 13 (trixie)
- 14 (forky)
- 15 (duke)
- unstable (sid)
How it works:
Grype retrieves vulnerability data from two Debian sources: a JSON feed from the Debian Security Tracker and Debian Security Advisory (DSA) lists. The provider combines information from both sources to build a complete picture of vulnerabilities affecting Debian packages.
Assumptions and interpretation:
-
Severity mapping: Debian uses an urgency-based severity system with some special notations:
unimportant
→ Negligiblelow
,low**
→ Lowmedium
,medium**
→ Mediumhigh
,high**
→ High- When Debian doesn’t provide severity information, Grype falls back to NVD severity data if available
-
Version format: Debian uses dpkg version comparison rules, the same as Ubuntu.
-
Special version handling: A fix version of “0” indicates the package is not vulnerable in that particular Debian release.
-
Advisory metadata: When a DSA (Debian Security Advisory) exists for a vulnerability, Grype includes the DSA identifier and provides a link to the advisory.
-
Legacy data support: The provider can also process data from Debian’s previous feed service format to maintain historical vulnerability records.
Alpine SecDB
Data source: Alpine SecDB
Vunnel provider: alpine
Supported versions:
Alpine Linux 3.2 and newer, plus the edge (development) branch.
How it works:
Grype downloads YAML files from Alpine’s Security Database (SecDB) for each supported Alpine release. Each release has separate databases for the main and community package repositories. The provider parses the “secfixes” sections that map package versions to the CVE identifiers they fix.
Assumptions and interpretation:
-
Severity: Alpine’s SecDB does not include severity ratings in the source data. All Alpine vulnerabilities show as “Unknown” severity unless supplemented by data from other sources like NVD.
-
Version format: Alpine uses apk package version comparison rules.
-
Database types: Alpine maintains two package databases:
main
→ Core Alpine packagescommunity
→ Community-maintained packages
Note: Alpine 3.2 does not have a community database (community repository support was added in 3.3).
-
Fix mapping: The secfixes section lists package versions and the CVE IDs they address. When a package version includes a fix for a CVE, Grype considers that version and all later versions non-vulnerable.
Red Hat Enterprise Linux
Data source: Red Hat Security Data API
Vunnel provider: rhel
Supported versions:
Red Hat Enterprise Linux 5, 6, 7, 8, 9 (RHEL 3 and 4 are skipped by default)
How it works:
Grype retrieves vulnerability data from Red Hat’s Common Vulnerabilities and Exposures (CVE) summary Application Programming Interface (API) and supplements it with detailed information from either Common Security Advisory Framework (CSAF) or Open Vulnerability and Assessment Language (OVAL) sources. You can configure which advisory format to use.
The provider performs a minimal initial download of CVE summaries, then fetches full CVE details only for relevant vulnerabilities. To avoid excessive API calls, the provider performs full synchronization at a configurable interval (default: 2 days) and uses incremental updates between full syncs.
Assumptions and interpretation:
-
RHSA source options: Red Hat Security Advisories (RHSA) are available in two formats:
- CSAF (Common Security Advisory Framework) → Structured JSON format
- OVAL (Open Vulnerability and Assessment Language) → XML format for automated assessment
-
Version format: Red Hat uses RPM version comparison rules.
-
Extended Update Support (EUS): The provider handles EUS versions, which receive extended security updates beyond the normal RHEL lifecycle.
-
Parallel processing: By default, Grype processes Red Hat data using 4 parallel workers to improve performance during large synchronizations.
Amazon Linux
Data source: Amazon Linux Security Center
Vunnel provider: amazon
Supported versions:
- Amazon Linux 2
- Amazon Linux 2022
- Amazon Linux 2023
How it works:
Grype retrieves Amazon Linux Security Advisories (ALAS) from RSS feeds maintained for each Amazon Linux version. The provider parses the RSS feed to get advisory summaries, then scrapes the HTML pages for detailed package and vulnerability information.
Due to occasional HTTP 403 errors when accessing advisory pages, the provider tolerates up to 25 such errors by default before failing.
Assumptions and interpretation:
-
Severity mapping: Amazon Linux uses four severity levels:
low
→ Lowmedium
→ Mediumimportant
→ Highcritical
→ Critical
-
Version format: Amazon Linux uses RPM version comparison rules.
-
RSS feeds: Each Amazon Linux version has its own RSS feed URL:
- AL2:
https://alas.aws.amazon.com/AL2/alas.rss
- AL2022:
https://alas.aws.amazon.com/AL2022/alas.rss
- AL2023:
https://alas.aws.amazon.com/AL2023/alas.rss
- AL2:
Oracle Linux
Data source: Oracle Linux Security
Vunnel provider: oracle
Supported versions:
Oracle Linux 5, 6, 7, 8, 9
How it works:
Grype downloads a compressed OVAL XML file that contains all Enterprise Linux Security Advisories (ELSA) for Oracle Linux. The provider parses this XML file to extract vulnerability and package information.
Assumptions and interpretation:
-
Severity mapping: Oracle Linux uses a five-level severity scale:
n/a
→ Negligiblelow
→ Lowmoderate
→ Mediumimportant
→ Highcritical
→ Critical
-
Version format: Oracle Linux uses RPM version comparison rules.
-
Ksplice filtering: The provider filters out packages related to Ksplice (Oracle’s kernel live-patching technology) because these packages are not fully supported for vulnerability matching.
-
OVAL format: The data comes from a single compressed XML file:
https://linux.oracle.com/security/oval/com.oracle.elsa-all.xml.bz2
SUSE Linux Enterprise Server
Data source: SUSE Security OVAL
Vunnel provider: sles
Supported versions:
SUSE Linux Enterprise Server 11, 12, 15 (configurable, defaults to these three versions)
How it works:
Grype downloads OVAL XML files from SUSE’s FTP server, with one file per major SLES version. Each file contains vulnerability definitions and affected package information.
Assumptions and interpretation:
-
Severity mapping: SUSE uses multiple terms that map to Grype’s normalized levels:
low
→ Lowmoderate
→ Mediummedium
→ Mediumhigh
→ Highimportant
→ Highcritical
→ Critical
-
Version format: SUSE uses RPM version comparison rules.
-
URL template: OVAL files follow this pattern:
https://ftp.suse.com/pub/projects/security/oval/suse.linux.enterprise.server.{version}.xml.bz2
Wolfi
Data source: Wolfi Security
Vunnel provider: wolfi
What it covers:
Wolfi is a Linux distribution (undistro) designed for containers. The security feed covers packages in the Wolfi OS.
How it works:
Grype downloads a JSON file from Wolfi’s package repository that contains security information for all Wolfi packages.
Assumptions and interpretation:
- Version format: Wolfi uses apk package version comparison rules (similar to Alpine).
Chainguard
Data source: Chainguard Security
Vunnel provider: chainguard
What it covers:
Chainguard Images are minimal container images based on Wolfi. The security feed covers packages used in Chainguard Images.
How it works:
Grype downloads a JSON file from Chainguard’s package repository that contains security information for packages in Chainguard Images.
Assumptions and interpretation:
- Version format: Chainguard uses apk package version comparison rules (same as Wolfi and Alpine).
AlmaLinux
Data source: AlmaLinux OSV Database
Vunnel provider: alma
Supported versions:
AlmaLinux 8, 9
How it works:
Grype clones the AlmaLinux OSV Database Git repository and processes vulnerability records stored in Open Source Vulnerability (OSV) format.
Assumptions and interpretation:
-
Data format: All vulnerability records follow the OSV schema.
-
Version format: AlmaLinux uses RPM version comparison rules.
Rocky Linux
Data source: Rocky Linux Apollo API
Vunnel provider: rocky
Supported versions:
Rocky Linux 8, 9
What it covers:
Rocky Linux is a community enterprise operating system designed to be downstream compatible with Red Hat Enterprise Linux.
How it works:
Grype fetches vulnerability data for Rocky Linux from the Rocky Linux Apollo API, which provides records in Open Source Vulnerability (OSV) format.
Assumptions and interpretation:
-
Data format: All vulnerability records follow the OSV schema.
-
Ecosystem normalization: The provider normalizes ecosystem identifiers from the OSV format. For example, “Rocky Linux:8” becomes “rocky:8” for consistency with Grype’s internal ecosystem naming.
-
Version format: Rocky Linux uses RPM version comparison rules.
CBL-Mariner
Data source: Microsoft CBL-Mariner OVAL
Vunnel provider: mariner
Supported versions:
CBL-Mariner 1.0, 2.0, 3.0
What it covers:
CBL-Mariner (Common Base Linux) is Microsoft’s internal Linux distribution, also available as an open source project.
How it works:
Grype downloads OVAL XML files for CBL-Mariner and parses them using the xsdata library. The provider processes rpminfo_test
, rpminfo_object
, and rpminfo_state
elements to extract vulnerability and package information.
Assumptions and interpretation:
-
Version format: CBL-Mariner uses RPM version comparison rules.
-
OVAL processing: The provider handles standard OVAL XML structures to identify which package versions are affected by vulnerabilities.
Cross-cutting providers
National Vulnerability Database (NVD)
Data source: NVD CVE API 2.0
Vunnel provider: nvd
What it covers:
The National Vulnerability Database provides comprehensive Common Vulnerabilities and Exposures (CVE) data across all ecosystems. Unlike ecosystem-specific providers, NVD uses Common Platform Enumeration (CPE) matching to identify vulnerable software.
How it works:
Grype retrieves CVE data from the NVD API 2.0, which provides up to 2000 results per request. For initial synchronization, the provider downloads all CVEs. For subsequent updates, it uses the last modified timestamp to fetch only CVEs that changed since the previous update.
The provider caches input data in a SQLite database to improve performance across runs. It supports retry logic (10 retries by default) to handle transient API failures.
Assumptions and interpretation:
-
CPE matching: NVD identifies vulnerable software using CPE (Common Platform Enumeration) identifiers. A CPE describes a software product with vendor, product name, version, and other attributes. Grype matches packages against CPE patterns to determine vulnerability status.
-
Incremental updates: The provider uses
lastModStartDate
andlastModEndDate
parameters to fetch only CVEs modified within a specific time range, reducing API calls and bandwidth. -
API rate limits: NVD enforces rate limits on API requests. You can provide an API key to enable higher rate limits. Without an API key, you’re limited to the public rate limit.
-
Fix date enrichment: NVD data often lacks information about when fixes became available. Grype supplements NVD data with fix dates from external databases when available, improving the accuracy of vulnerability timelines.
-
CPE configuration overrides: The provider supports custom CPE configurations that can override or supplement the default CPE matching data from NVD.
-
Publication date ranges: When querying by publication date, the API enforces a maximum 120-day range per request. The provider automatically splits larger date ranges into multiple requests.
Relationship to other providers:
NVD serves as a cross-cutting data source that complements ecosystem-specific providers. When an ecosystem-specific provider lacks severity information (such as Alpine), Grype can fall back to NVD severity ratings. NVD is also essential for CVE-only lookups where you need to check for a specific CVE across all ecosystems.
Because NVD uses CPE matching rather than package manager metadata, it can identify vulnerabilities in software that doesn’t come from a package manager. However, ecosystem-specific sources typically provide more accurate and granular information for their respective ecosystems by using native package version information.
Common patterns across providers
Severity normalization
All vulnerability providers map their severity ratings to a common scale that Grype uses for reporting:
- Unknown → Severity information not available
- Negligible → Minimal or no practical impact
- Low → Limited impact, typically requiring complex exploit conditions
- Medium → Moderate impact, may require specific conditions
- High → Serious impact, relatively easy to exploit
- Critical → Severe impact, easily exploitable, or widespread effect
Different providers use different severity scales in their source data. For example, Amazon Linux uses “important” while Oracle Linux uses “important” with the same meaning (both map to High). Grype normalizes these provider-specific terms to ensure consistent severity reporting across all data sources.
When a provider doesn’t include severity information in their data, Grype may fall back to NVD severity ratings if available.
Version matching
Version matching rules depend on the package format:
DEB-based systems (Ubuntu, Debian):
These systems use dpkg version comparison rules, which handle Debian-specific version components like epochs and revisions. For example, 1:2.0-1
has an epoch of 1
, making it newer than 2.0-1
despite appearing lower numerically.
RPM-based systems (RHEL, Amazon, Oracle, SLES, Mariner, Alma, Rocky):
These systems use RPM version comparison rules, which compare version strings segment by segment. RPM versions can include release numbers and distribution tags. For example, 1.2.3-4.el8
includes version 1.2.3
, release 4
, and distribution tag el8
.
APK-based systems (Alpine, Wolfi, Chainguard):
These systems use Alpine package version rules, which follow a simpler numeric comparison scheme with support for suffix modifiers like -r1
for package revisions.
Language packages (GitHub):
Language ecosystems use their own version comparison rules:
- npm uses semantic versioning (semver) with ranges like
>=1.2.3 <2.0.0
- Python uses PEP 440 version specifiers with ranges like
>=1.2,<2.0
- Ruby uses RubyGems version comparison
- Maven uses Maven version ordering rules
Each ecosystem has its own syntax for expressing version ranges, and Grype interprets these ranges according to the ecosystem’s version comparison semantics.
Fix date enrichment
Many providers supplement vulnerability records with “fix available” dates, which indicate when a vulnerability fix first became available. This information establishes accurate vulnerability timelines.
Grype uses external databases (called “fixdaters”) to determine fix availability dates. These databases track when security advisories were published or when fixed package versions were released. The fix date information includes:
- Date: When the fix became available
- Kind: The type of evidence (such as “advisory” for security advisory publication dates or “snapshot” for package repository snapshots)
Fix dates improve matching accuracy by allowing Grype to determine whether a vulnerability existed in a package at a specific point in time.
Data freshness
Different providers use different strategies for keeping vulnerability data current:
Incremental updates:
Some providers support incremental updates that fetch only changed data since the last run:
- GitHub Security Advisories: Uses an
updatedSince
timestamp parameter to fetch only advisories modified after a specific date - NVD: Uses
lastModStartDate
andlastModEndDate
parameters to fetch only CVEs modified within a date range - Red Hat: Downloads minimal CVE summaries, then selectively fetches full CVE details for relevant vulnerabilities; performs full synchronization every 2 days by default
Full refresh:
Other providers re-download and re-process all data each run, though they may use caching to improve performance:
- Git-based providers (Ubuntu, Bitnami, Alma): Clone the entire Git repository each run
- Feed-based providers (Debian, Alpine, Oracle, SLES): Download complete feeds, which may be cached locally
- RSS-based providers (Amazon): Parse RSS feeds and fetch advisory pages
The update strategy affects how quickly new vulnerability data appears in Grype. Providers with incremental updates can fetch recent changes more efficiently, while full refresh providers ensure complete data consistency at the cost of higher bandwidth usage.
Related information
3 - License Scanning
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.1 - 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.
Note
Grant is not currently available for Windows
curl -sSfL <a href="https://get.anchore.io/grant">https://get.anchore.io/grant</a> | sudo sh -s – -b /usr/local/bin
brew install grant
- Scan a container for all the licenses used
grant alpine:latest
Grant will produce a list of licenses.
* alpine:latest
* license matches for rule: default-deny-all; matched with pattern *
* Apache-2.0
* BSD-2-Clause
* GPL-2.0-only
* GPL-2.0-or-later
* MIT
* MPL-2.0
* Zlib
- Scan a container for OSI compliant licenses
Now we scan a different container, that contains some software that is distributed under non-OSI-compliant licenses.
Note
The image used here is quite large (over 3GB) so may take a while to download and analyzegrant check pytorch/pytorch:latest --osi-approved
Read more in our License Auditing User Guide.
Next steps
- Try running Syft against other containers, or an application directory on your workstation.
- Find out more about Supported Sources and Output Formats.
- Learn about Vulnerability Scanning and License Scanning your SBOMs.
4 - Private Registries
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 token
docker 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:
Basic authentication example:
{
"auths": {
"registry.example.com": {
"username": "AzureDiamond",
"password": "hunter2"
}
}
}
Token authentication example:
// token auth, where credentials are base64-encoded
{
"auths": {
"ghcr.io": {
"auth": "dXNlcm5hb...m5h=="
}
}
}
Security Warning
Storing plaintext passwords inconfig.json
is insecure. Use credential helpers where possible.
By default, the tools look for credentials in ~/.docker/config.json
. You can override this location using the DOCKER_CONFIG
environment variable:
export DOCKER_CONFIG=/path/to/custom/config
syft registry.example.com/private/image:latest
You can also use this in a container:
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 bothcredHelpers
and auths
are configured for the same registry, credHelpers
takes precedence.
For more information about Docker credential helpers for various cloud providers:
- ECR authentication documentation.
- Artifact Registry authentication documentation.
- ACR authentication documentation.
Within Kubernetes
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.
# secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: registry-config
namespace: syft
data:
config.json: <base64-encoded-config.json>
Create the secret:
# Base64 encode your config.json
cat ~/.docker/config.json | base64
# Apply the secret
kubectl 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.
# pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: syft-k8s-usage
spec:
containers:
- image: anchore/syft:latest
name: syft-private-registry-demo
env:
- name: DOCKER_CONFIG
value: /config
volumeMounts:
- mountPath: /config
name: registry-config
readOnly: true
args:
- <private-image>
volumes:
- name: registry-config
secret:
secretName: registry-config
Apply and check logs:
kubectl apply -f pod.yaml
kubectl logs syft-private-registry-demo