Generating a Server (OS + Application) SBOM
A delivered server is not a single source tree. It is an operating system, the application installed on top of it, and libraries statically linked into the binaries during the build. Scanning only one of these misses the others, which is a common reason a server SBOM is rejected.
Treat the server as two layers — the OS and the application — generate each separately, then merge them. Both are produced with BomLens; only the input changes. Statically linked libraries, which neither layer’s scan catches, are handled separately as a blind spot.
The two layers of a server
| Layer | What it covers | Symptom if omitted |
|---|---|---|
| OS | The OS and its installed packages (e.g. CentOS plus everything in the rpm database) | OS vulnerabilities missing |
| Application | The delivered application and its package-manager dependencies, direct and transitive | Application dependencies missing |
Beyond the two layers, statically linked libraries (for example an openssl or liblfds built into the binary) are a blind spot: a package manager does not declare them and the OS package database does not list them, so neither layer’s scan finds them. They must be detected and recorded separately, and missing them is the most common rejection cause.
Generating each layer
The commands below use BomLens’s scan-sbom.sh script. For installing BomLens and its basics (downloading the script, the options, the web UI, and so on), see BomLens first. To use cdxgen/Syft directly, see Using Open Source Tools.
OS layer
Scan the server’s rootfs (the extracted root filesystem) or a container image of it. The package database (rpm/dpkg/apk) is read so every installed package gets a real purl (pkg:rpm/...).
# Target a rootfs directory
scan-sbom.sh --project myserver-os --version 7 --target /path/to/server-rootfs --all --generate-only
# Or, if the server is packaged as a container image
scan-sbom.sh --project myserver-os --version 7 --target myserver:7 --all --generate-only
The target must contain the package database. A folder holding only unpacked install files, with no rpm database, yields empty purls and is rejected.
Application layer
Scan the application source after the build. With a package manager (Maven, npm, pip, Go modules, Conan, and others), transitive dependencies resolve automatically.
cd /path/to/app-source
scan-sbom.sh --project myserver-app --version 2.0.0 --all --generate-only
A pure CMake/Make application with no manifest produces a sparse component list; add --deep-license to record the first-party source licenses.
Static-link libraries (a blind spot)
Source scanners do not see libraries statically linked into a binary, and the OS package database does not list them either — the blind spot the two layers leave. There is no fully automatic path, so combine two approaches. Analyze the delivered binary for what tooling can find, and for what it still misses, record the source and version by hand from the build script (for example openssl 1.1.1za).
scan-sbom.sh --project myserver-bin --version 2.0.0 --target /path/to/delivered-binary --all --generate-only
A precise inventory of statically linked components comes from binary composition analysis (BDBA), which SK Telecom runs as a complementary check.
Merge into one BOM for submission
SK Telecom’s submission system registers one SBOM per product. Merge the per-layer SBOMs with --merge into a single BOM and stamp the top-level component with the delivered product name and version. --merge dedupes by purl, so a library appearing in more than one layer is counted once.
scan-sbom.sh --project myserver --version 1.0.0 \
--merge myserver-os_7_bom.json myserver-app_2.0.0_bom.json myserver-bin_2.0.0_bom.json \
--generate-only
If the whole server is delivered as a single container image, you can scan that image with --target to capture the OS and application layers together.
The official submission is the merged single BOM, but the per-layer SBOMs show at a glance which layer is missing or vulnerable, so they are useful for your own review and for responding to rejections. Keep them. The merged BOM unions each layer’s dependency graph (so it keeps transitive-dependency information) and records each component’s source layer, so you can still filter by layer.
Verify before submitting
Check that components carry real purls in both the per-layer SBOMs and the merged one. The total component count and the PURL-bearing count should be close.
jq '.components | length' myserver_1.0.0_bom.json
jq '[.components[] | select(.purl)] | length' myserver_1.0.0_bom.json
A large gap means many components lack a purl, usually from a raw-directory scan. For the full check, follow the Validation Checklist.
Learn more
The detailed procedure and examples for server delivery live in the canonical BomLens documentation.
Related Documents
- BomLens: SK Telecom’s SBOM generation tool
- Using Open Source Tools: using cdxgen/Syft directly
- Submission Requirements: required data fields
- Validation Checklist: items to verify before submission
Feedback
Was this page helpful?
Glad to hear it! Please tell us how we can improve.
Sorry to hear that. Please tell us how we can improve.