Use the Docker image directly

July 29, 2026 · View on GitHub

For everyday use we recommend the scan-sbom.sh script, which handles language detection, image selection, and volume mounts for you. This document explains how to call the image directly with docker run in environments where the script cannot live (CI runners, Kubernetes jobs, and so on).

Images and tags

ImagePurpose
ghcr.io/sktelecom/bomlensScanning and post-processing (canonical name)
ghcr.io/sktelecom/sbom-generator, ghcr.io/sktelecom/sbom-scannerAliases of the same image (former names, same digest)
ghcr.io/sktelecom/bomlens-firmwareFirmware analysis (includes GPL tools, opt-in) (legacy alias: sbom-scanner-firmware)

latest and version tags are available, and both linux/amd64 and linux/arm64 are supported. Images are signed with cosign before publishing.

docker pull ghcr.io/sktelecom/bomlens:latest

What is in the image

It is a lightweight image (based on python 3.12 slim) without language toolchains. For source scans, transitive dependency resolution is handled by the script, which pulls per-language cdxgen images separately. See Architecture for the structure.

ToolVersionRole
syftv1.46.0Scans images, binaries, and directories
Trivyv0.72.0Vulnerability report
cosignv2.4.1SBOM signing
jqSBOM normalization and notice generation
ScanCode Toolkit32.5.0Precise license detection (included only in opt-in builds)

Tool versions are pinned with ARG in docker/Dockerfile.

Running directly

Select the analysis mode with the MODE environment variable. All examples below leave their outputs in the current directory and do not upload anything (UPLOAD_ENABLED=false).

Analyze a Docker image

docker run --rm \
  -v "$(pwd)":/host-output \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -e MODE=IMAGE \
  -e TARGET_IMAGE="nginx:alpine" \
  -e UPLOAD_ENABLED=false \
  -e HOST_OUTPUT_DIR=/host-output \
  -e PROJECT_NAME="Nginx" \
  -e PROJECT_VERSION="alpine" \
  ghcr.io/sktelecom/bomlens:latest

Analyze a binary file

docker run --rm \
  -v "$(pwd)":/target \
  -v "$(pwd)":/host-output \
  -e MODE=BINARY \
  -e TARGET_FILE=/target/firmware.bin \
  -e UPLOAD_ENABLED=false \
  -e HOST_OUTPUT_DIR=/host-output \
  -e PROJECT_NAME="Firmware" \
  -e PROJECT_VERSION="1.0" \
  ghcr.io/sktelecom/bomlens:latest

Analyze a source directory

docker run --rm \
  -v "$(pwd)":/src \
  -v "$(pwd)":/host-output \
  -e MODE=SOURCE \
  -e UPLOAD_ENABLED=false \
  -e HOST_OUTPUT_DIR=/host-output \
  -e PROJECT_NAME="MyApp" \
  -e PROJECT_VERSION="1.0.0" \
  ghcr.io/sktelecom/bomlens:latest

In direct runs, SOURCE mode has syft read the package manifests inside the container, so it may only capture direct dependencies. If you need transitive dependencies, use scan-sbom.sh, which routes to the per-language cdxgen images.

Notice and reports in one run

In direct runs, the notice and security reports are off by default. Turn on the following variables to get the same outputs as the CLI's --all.

docker run --rm \
  -v "$(pwd)":/host-output \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -e MODE=IMAGE \
  -e TARGET_IMAGE="nginx:alpine" \
  -e GENERATE_NOTICE=true \
  -e GENERATE_SECURITY=true \
  -e GENERATE_REPORT=true \
  -e UPLOAD_ENABLED=false \
  -e HOST_OUTPUT_DIR=/host-output \
  -e PROJECT_NAME="Nginx" \
  -e PROJECT_VERSION="alpine" \
  ghcr.io/sktelecom/bomlens:latest

Environment variables

VariableRequiredDefaultDescription
MODEYesPOSTPROCESSAnalysis mode: SOURCE, IMAGE, BINARY, ROOTFS, FIRMWARE, ANALYZE
PROJECT_NAMEYesProject name
PROJECT_VERSIONYesProject version
TARGET_IMAGEPer modeImage name for IMAGE mode (requires the docker.sock mount)
TARGET_FILEPer modeFile path for BINARY/FIRMWARE mode (path inside the container)
TARGET_DIRPer modeDirectory path for ROOTFS mode
UPLOAD_ENABLEDtrueIf false, save locally without uploading (same as CLI --generate-only)
HOST_OUTPUT_DIRMounted path to copy the outputs to
GENERATE_NOTICEfalseGenerate the open-source notice (CLI --notice)
GENERATE_SECURITYfalseGenerate the Trivy security report (CLI --security)
GENERATE_REPORTfalseGenerate the open-source risk analysis report (off in direct runs, unlike the CLI default)
ENRICH_MAVEN_CPEtrueAttach an NVD-matchable cpe:2.3 to maven components (derived from the groupId) so a CPE-aware engine can reach their NVD-only CVEs; unmapped groups get no CPE (skipped for AI SBOMs)
SECURITY_NVD_VERIFYfalseWith --deep-cve: verify each grype nvd:cpe finding against the live NVD version range and drop out-of-range false positives (needs NVD_API_KEY + network; adds minutes). Off by default — findings are kept and flagged version-unverified
NVD_API_KEYFor SECURITY_NVD_VERIFYNVD API key used by the deep-cve version filter; passed to the container by name only (never inlined)
ENRICH_EOLtrueFlag components past their upstream end-of-life from a bundled offline snapshot (skipped for AI SBOMs)
ENRICH_MALICIOUStrueFlag components that are known-malicious packages (typosquats, hijacked accounts) from a bundled offline OSV snapshot. A separate signal from vulnerabilities: the response is removal and credential rotation, not an upgrade
ENRICH_OS_CONTEXTtrueSynthesize an operating-system component from distro package PURLs (rpm, deb, and apk). Trivy selects the distro vulnerability feed from that component, so without it the OS packages in a supplier SBOM or rootfs scan would get no OS CVE matches at all. No-op when the SBOM has no recognizable distro packages — including a distro Trivy carries no feed for, such as OpenWRT (skipped for AI SBOMs)
STALENESS_ENRICHfalseAdd deps.dev version currency (how many releases behind latest); needs network access
ENRICH_HF_SECURITYtrueAIBOM mode: read HuggingFace's per-file security scan results (ClamAV + picklescan) into the ML-BOM; metadata only, no file download
API_KEY, API_URLFor uploadsUpload credential and server URL. DT uses X-Api-Key; TRUSCA uses a Bearer token
UPLOAD_TARGETdependency-trackUpload destination: dependency-track (DT-compatible) or trusca (native ingest, not DT-compatible)
TRUSCA_PROJECT_IDWhen truscaTarget TRUSCA project id (UUID). Must already exist (no auto-create)
TRUSCA_REFmainIngest ref label
TRUSCA_RELEASEPROJECT_VERSIONIngest release label
BOMLENS_MAVEN_FULL_GRAPHMaven source scans: set 1 to keep the full resolved graph instead of filtering to compile/runtime scope
BOMLENS_NODE_FULL_GRAPHNode.js source scans: set 1 to keep the full dev-plus-production graph instead of the production-only set
BOMLENS_KEEP_BUILD_OUTPUTSource scans: set 1 to leave the resolved tree in place. By default the scan restores the files its resolvers rewrote (go.mod, go.sum, Cargo.lock, Gemfile.lock, Package.resolved) and removes the build directories they created, so the scanned project is handed back as it was
CYCLONEDX_SPEC_VERSIONS1.3 1.4 1.5 1.6Accepted CycloneDX spec versions for the conformance check (space-separated); overrides the default range
AI_CYCLONEDX_SPEC_VERSIONS1.3 1.4 1.5 1.6 1.7Accepted CycloneDX versions for AI SBOMs (ML-BOM), which additionally allow 1.7
SPDX_SPEC_VERSIONSSPDX-2.2 SPDX-2.3Accepted SPDX spec versions for the conformance check

TRUSCA's (formerly TrustedOSS Portal) native ingest endpoint (POST /v1/projects/{id}/sbom-ingest, Bearer auth) is not Dependency-Track compatible. To push to a regular Dependency-Track server, keep UPLOAD_TARGET=dependency-track (the default).

For the full mapping between CLI flags and environment variables, see the flag mapping in Architecture.

Building and publishing the image

The procedure for building the image yourself or publishing it for multiple platforms is in the contributor-facing docker/README.


Related: Getting started | CLI reference | Architecture