The Drift Log · Provenance, licensing and the paper trail
Why an SBOM Without Origin Hashes Is Meaningless
7 September 2026 · 4 min read · 851 words · established

An SBOM based solely on package names and declared licenses records your intent, not the actual bytes running in production.
Most Software Bills of Materials (SBOMs) generated in CI pipelines are lists of assertions, not evidence.
A standard scan inspects your manifest, finds left-pad@1.3.0, checks a remote database, and emits a CycloneDX or SPDX document stating that you depend on left-pad, version 1.3.0, licensed under MIT.
This output looks tidy during an audit. It satisfies standard check-the-box compliance questionnaires. But if an incident occurs, or if proprietary IP lawyers subpoena your source tree, that document proves almost nothing about the bytes running in your application.
An SBOM that records names, versions, and declared licenses without origin content hashes is a receipt without a transaction ID. It tells you what you intended to bring into your repository, not what actually arrived.
The Gap Between Names and Bytes
Software supply chain risks rarely announce themselves by changing package names. The failure modes that break license compliance and security postures happen below the manifest level:
- Mutable upstream tags. Git tags are movable pointers. Unless your package manager enforces immutable checksums against a public ledger, a tag like
v2.1.4can point to commita1b2c3on Monday and commitf9e8d7on Friday. - Local patches in vendored code. An engineer copies a utility file into
src/vendor/, patches three lines to fix a concurrency bug, and leaves the upstream header intact. The standard scanner either misses the file entirely or assumes it is pristine upstream code. - Registry substitution. Package namespaces get reclaimed, abandoned, or typosquatted. A manifest resolving a range like
^1.4.0can pull down entirely different source trees across two builds six months apart.
When you vendor third-party code directly, the metadata problem gets worse. As we covered in Vendoring Code Without a Paper Trail Is Unsecured Debt, the moment code enters your tree without cryptographic ties to its upstream source, its software provenance becomes institutional hearsay.
If your SBOM claims a component is Apache-2.0, but your local copy contains a patched routine derived from an AGPL-3.0 snippet copied from an issue thread, your SBOM is wrong. In a legal discovery process, declared metadata is irrelevant; the bytes on disk determine your liability.
Declared in SBOM:
Name: fast-parser
Version: 2.0.1
License: MIT
Source: https://github.com/example/fast-parser
Actual State on Disk:
Path: src/vendor/fast-parser/parser.c
SHA-256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
Upstream: 8f434346648f6b96df89dda901c5176b10a6d83961dd3c1ac88b59b2dc327aa4
Status: MODIFIED (32 lines inserted, attribution dropped)
What Real Provenance Requires
Verifiable software provenance requires tracking content hashes across every boundary: from the upstream source archive, to the extraction step, to the committed file tree, to the compiled binary.
A robust provenance record links three specific elements:
- The Origin Hash: The SHA-256 or BLAKE3 digest of the exact upstream archive or commit tree as retrieved from the authoritative host.
- The In-Tree Content Hash: The cryptographic digest of the files as they exist inside your repository.
- The Transformation Log: A recorded diff or patch sequence that accounts for every byte of variance between the Origin Hash and the In-Tree Content Hash.
If the origin hash matches the in-tree hash, the component is clean: upstream licensing and vulnerability data apply directly. If the hashes differ, the component is modified. At that point, any automated license compliance claim must be suspended until the diff itself is audited.
This approach is why secure release pipelines publish explicit root-of-trust checksums for their distributions rather than relying on registry package names. You verify the archive digest against a published ledger before you parse a single line of metadata.
The Genuine Hard Part
Tracking content hashes for every third-party boundary is not computationally difficult, but it introduces operational friction that many teams resist:
- File-level hashing generates volume. Deep dependency trees containing thousands of vendored files produce large hash manifests that must be versioned alongside the code.
- Whitespace and line-ending noise. Moving files between Windows and Unix environments can alter file hashes without changing logic. You need deterministic normalization rules (such as git's internal tree-hashing mechanism or strict LF enforcement) to prevent false drift alerts.
- Granular auditing is manual work. When a hash mismatch is detected, an automated tool cannot always tell whether a patch was a safe bug fix or a catastrophic license contamination. A human still has to read the diff.
Ignoring these realities does not make them go away. It simply defers the cost until an audit, an acquisition, or an upstream vulnerability disclosure forces you to do the forensic work under pressure.
What to Do on Monday
Do not overhaul your entire build system at once. Start by tightening the verification loop on code you already manage:
- Audit your vendored directories. Run a script across any
/vendoror/third_partyfolders to calculate SHA-256 digests for all third-party files. Compare them directly against the upstream release archives you believe you imported. - Flag modified dependencies. For any file where the local digest does not match upstream, isolate the diff. If the change introduced uncredited code or stripped license headers, fix the paper trail immediately.
- Reject unhashed lockfiles. Ensure your package manager is configured to verify cryptographic tarball checksums on every install (such as using
integrityfields inpackage-lock.jsonorCargo.lock), rather than resolving versions dynamically.
If your SBOM does not include the cryptographic hash of the content running in your application, you have an inventory of your intentions, not your software.
This post supports the longer argument in Vendoring Code Without a Paper Trail Is Unsecured Debt.
Keep reading
Next in the log
- Vendoring Code Without a Paper Trail Is Unsecured Debt
Inlining unverified code severs upstream security alerts and license tracking. Provenance must be captured at intake, not guessed by SBOMs.
- Link SBOM entries to exact source commits
Store Git blob hashes in your SBOM to link every file entry to its exact source bytes, enabling instant provenance verification.
- Tracing Load-Bearing Code When Dependencies Mask Logic
SBOM inventories show what sits in your build, but fail to reveal when critical tenant boundaries sit inside unmaintained transitive dependencies.
The Strategic Master Library · written and reviewed under the house's own epistemic rules: nothing claimed that we cannot show.