<!--
SPDX-License-Identifier: Apache-2.0
SPDX-FileCopyrightText: 2026 ndaal Gesellschaft für Sicherheit in der Informationstechnik mbH & Co KG, Cologne
SPDX-FileCopyrightText: Author: Pierre Gronau <Pierre.Gronau@ndaal.eu>
-->
# ndaal SBOM Auditor
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.
> Translations: [Deutsch](LIESMICH.md) · [Français](LISEZMOI.md)
## What it does
1. **Ingest** — upload an SBOM in the browser, or import every SBOM in a
configurable folder. CycloneDX (JSON/XML), SPDX (JSON/tag-value and 3.0
JSON-LD) and syft-json are detected; files are content-hashed and
deduplicated.
2. **Analyse** — run the enabled tools against the SBOM, each as an isolated
subprocess under a deadline and a concurrency limit. A missing tool is a
clean, visibly distinct *skip* — never reported as a clean result.
3. **Findings** — each tool's output is normalised to a common shape, with the
CVE alias resolved from the tool's GHSA/OSV identifier, and shown per tool
with severity badges.
4. **Score** — grade the SBOM against all seventeen CISA 2026 minimum
elements, distinguishing a supplier's explicit `NOASSERTION` from a
field that is simply absent.
5. **Search** — find which of your SBOMs declare a given component, across
the whole corpus, by name or package URL.
6. **Export** — write the analysis as SARIF 2.1.0, SARIF 2.2, Markdown, ODT,
DOCX, PDF and CSAF 2.1 / 2.2 advisories, each accompanied by five
cryptographic hash sidecars.
## Analyzer ensemble
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](https://github.com/anchore/syft) | SBOM normaliser / CycloneDX 1.6 converter |
| [grype](https://github.com/anchore/grype) | CVE matcher |
| [trivy](https://github.com/aquasecurity/trivy) | Vulnerability scanner |
| [osv-scanner](https://github.com/google/osv-scanner) | OSV database lookups |
| [bomber](https://github.com/devops-kung-fu/bomber) | Independent ensemble matcher |
| [bomdrift](https://crates.io/crates/bomdrift) | Supply-chain drift / typosquat (SARIF) |
| [inspektr](https://crates.io/crates/inspektr) | SBOM vulnerability scanner (JSON) |
| [shieldbom](https://crates.io/crates/shieldbom-core) | Offline embedded/IoT CVE scanner (SARIF) |
| [provenant](https://crates.io/crates/provenant-cli) | 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.
## Security posture
- **Transport:** HTTPS only, TLS 1.3 (rustls + aws-lc-rs) with post-quantum
key exchange (X25519MLKEM768) offered first. Self-signed dev certificate,
regenerated at start-up; operator PEM files supported.
- **Memory safety:** written in Rust with `#![forbid(unsafe_code)]`; the lint
policy denies panicking shortcuts, unchecked arithmetic and unchecked
indexing in production code.
- **Filesystem confinement:** all data / import / export I/O is confined by a
cap-std capability handle (path-traversal, symlink and TOCTOU classes
closed). Stored file names are server-derived, never client-supplied.
- **Storage encryption (optional):** XChaCha20-Poly1305 seals stored SBOM
bytes and raw tool output while they sit on disk (`--encryption-key-file`).
- **Web hardening:** defence-in-depth response headers on every response, a
hash-pinned Content-Security-Policy, same-origin checks on every POST, and a
request-body size limit.
- **No telemetry, no backdoors.** Everything runs locally. Meets the TeleTrusT
"IT Security made in Germany / Europe" criteria.
## Build and run
Requires a recent stable Rust toolchain.
```bash
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).
### Common options
```text
--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).
## Testing
```bash
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). The `example/`
directory carries 651 public test SBOMs (Git LFS); see
[example/PROVENANCE.md](example/PROVENANCE.md). See
[documentation/structure.md](documentation/structure.md) for the module map
and the request flow.
## Documentation
- [REFERENCE.md](REFERENCE.md) — CLI, environment, routes, settings and
export-format reference
- [documentation/structure.md](documentation/structure.md) — architecture map
- [documentation/User_Guide.md](documentation/User_Guide.md) — end-user
walkthrough
- [documentation/Administrator_Guide.md](documentation/Administrator_Guide.md)
— deployment and operations
- [documentation/arc42/en/](documentation/arc42/en/01-introduction-and-goals.md)
— arc42 architecture views
- [documentation/compliance/CSI_2026_cisa_sbom_minimum_elements_508c.md](documentation/compliance/CSI_2026_cisa_sbom_minimum_elements_508c.md)
— conformance assessment against the CISA 2026 SBOM Minimum Elements
- [CHANGELOG.md](CHANGELOG.md) — release history
## Licence
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/`.