
Offline single-binary web app that ingests CycloneDX, SPDX and syft SBOMs, runs an ensemble of CVE scanners, enriches findings with EPSS, CISA-KEV and nuclei, and exports SARIF, CSAF and PDF.
A single-binary, offline web application to investigate SBOM (Software Bill of Materials) files. Upload an SBOM or import a folder of them, analyse each with an ensemble of independent tools, review the normalised findings in one local UI, and export the result in eight formats. No installation, no network access, no telemetry.
NOASSERTION from a
field that is simply absent.The home page (/) lists every stored SBOM and stays usable as the corpus
grows:
log4j or
openssl finds every SBOM that ships that component. The query is
length-capped and parsed leniently.Each tool is optional at runtime and detected on PATH (override the binary
with SBA_TOOL_<NAME>_BIN). Findings never depend on any single tool.
| Tool | Role |
|---|---|
| syft | SBOM normaliser / CycloneDX 1.6 converter |
| grype | CVE matcher |
| trivy | Vulnerability scanner |
| osv-scanner | OSV database lookups |
| bomber | Independent ensemble matcher |
| bomdrift | Supply-chain drift / typosquat (SARIF) |
| inspektr | SBOM vulnerability scanner (JSON) |
| shieldbom | Offline embedded/IoT CVE scanner (SARIF) |
| provenant | Licence / copyright / provenance (ScanCode) |
The first eight tools contribute CVE-shaped vulnerability findings;
provenant is different — it reports licence, copyright, holder and author
provenance, which the auditor stores and displays as its own finding shape (a
"Licence & provenance" section per run, included in the Markdown export) rather
than discarding it.
The scanners cannot read every format directly: bomber consumes only
CycloneDX ≤ 1.6, and none of the scanners read SPDX 3.0 JSON-LD. In both cases
the auditor normalises the input to CycloneDX via syft convert first, and
skips with a documented reason when syft is unavailable rather than let a tool
report zero packages. grype's vulnerability database is refreshed once per run
(out of band) so a routine staleness is a fresh scan, not a failed one.
After analysis, each CVE-shaped finding is enriched with three real signals pulled from a vulnlookup service (default https://vulnlookup.ndaal.eu):
Each finding shows its KEV, Nuclei, EPSS and Source values, where Source links back to the vulnlookup record, and findings are ordered most-urgent-first: known-exploited (KEV) entries lead, then those with the higher EPSS percentile; findings with no enrichment keep the order the analyzer produced them in. The enrichment travels into every export format — SARIF 2.1 / 2.2, Markdown, ODT, DOCX, PDF and CSAF 2.1 / 2.2, where CSAF carries EPSS as a native metric and records CISA-KEV and nuclei as notes — and the export form now ticks every format by default.
Configure it under Settings → Vulnerability enrichment: an on/off toggle (enabled by default) and up to three vulnlookup sources, each with a base URL, a TCP port and a QUIC port (a blank port is treated as 443). Sources 1 and 2 default to the public https://vulnlookup.ndaal.eu on port 443; source 3 defaults to a loopback https://127.0.0.1 on this host's own 8680 (TCP) / 8681 (QUIC) ports, so a co-located vulnlookup is a working fallback out of the box. The sources are tried in order — the first is primary, the others are fallbacks.
#![forbid(unsafe_code)]; the lint
policy denies panicking shortcuts, unchecked arithmetic and unchecked
indexing in production code.--encryption-key-file).--tls-key refuses a PKCS#1 RSA key (no-RSA
policy) and, on Unix, a group- or world-readable key file.GET /export/download serves only
names with a recognised export or checksum-sidecar extension, so a
misconfigured export directory cannot hand out a system file.cargo audit is clean.Install the published release from crates.io — cargo install builds it
from source, cargo binstall fetches the prebuilt binary from the GitLab
release:
cargo install sbom-auditor # build from source
cargo binstall sbom-auditor # prebuilt GitLab-release binary
Or build this checkout directly (a recent stable Rust toolchain is required):
cargo build --release
./target/release/sbom-auditor
Then open https://127.0.0.1:8680 (the browser will warn once about the self-signed certificate). The top navigation runs Home, Upload, Import, Export, Components, Tools, Settings, followed by the dark/light theme switch, language menu and info menu on the right. The interface ships in 49 languages — English, Deutsch and Français plus every European official language, Norwegian Nynorsk, the three Sámi languages official in Norway (Northern, Lule and Southern Sámi), and three Asian additions — Chinese (中文), Hindi (हिन्दी) and Urdu (اردو, right-to-left) — selectable from the language menu (and remembered per browser). The Supported GUI languages section below has the full breakdown.
--port <PORT> Listen port (default 8680, env SBA_PORT)
--bind <ADDR> Bind address (default 127.0.0.1, env SBA_BIND)
--data-dir <DIR> Data directory (SQLite store + stored SBOMs)
--db <PATH> Database path (default <data-dir>/auditor.db)
--encryption-key-file <F> Enable storage encryption with this 32-byte key
--tls-cert <F> --tls-key <F> Operator certificate instead of self-signed
--allow-non-loopback Permit binding a non-loopback address
--check-update Check gitlab.com for a newer release, then exit
--self-update Download + verify + install the latest release
--help Full option list
Ports: 8680 serves the API and web UI over TLS 1.3 (HTTP/1.1 + HTTP/2); 8681 is reserved for a future QUIC / HTTP-3 listener (not yet implemented).
The web UI ships in 49 languages. English, Deutsch and Français are the maintained, human-authored set and are pinned to the front of the language switcher; every other language follows in alphabetical order by its English name.
Three Asian languages joined this cycle: Chinese / 中文 (Mandarin,
Simplified), Hindi / हिन्दी and Urdu / اردو. Urdu is right-to-left — the
application renders <html dir="rtl"> while it is selected.
Every language beyond the pinned three is machine-translated and pending native review; any string missing from a translation falls back automatically to English. The in-page switcher lists each language by its own native-name endonym and is the authoritative list — consult it rather than an enumeration here.
This applies to the web UI only. The generated reports (SARIF, CSAF and the PDF export) and the HTTP API remain English-only.
cargo nextest run # unit + integration suite
cargo test --doc # doctests
Additional harnesses: loom-harness/ (concurrency permutation models),
test/bruno/ (API collection), test/playwright/ (browser E2E),
test/example-corpus/ (API + GUI upload→analyze→export over the bundled
example/ SBOM corpus) and loadtest/ (Goose load scenarios).
tests/scripts/test_examples_upload_via_api.sh (with a sister .bats)
uploads every example/ SBOM against a running instance and asserts each
yields a SARIF, a CSAF and a PDF via the streamed POST /export/download
ZIP; TLS is verified for non-loopback hosts and skipped for localhost's
self-signed certificate, and --base-url targets any instance (for
example https://sbom.ndaal.eu/). The
test/magnitude/ suite (Magnitude, *.mag.ts) adds AI-driven visual checks
of the navbar order and the export defaults plus Start download; it
complements the deterministic tests, needs an LLM to run and is not part of
the blocking CI gate. The example/
directory carries 651 public test SBOMs (Git LFS); see
example/PROVENANCE.md. See
documentation/structure.md for the module map
and the request flow.
Code is licensed Apache-2.0. Bundled UI assets carry their own licences
(Bootstrap MIT, htmx 0BSD, Roboto OFL-1.1); see the per-file .license
sidecars under src/static/.