sbomdrift
What became vulnerable since last time?
Vulnerability scanners answer what is vulnerable now. They are stateless, so they cannot answer the question that actually reaches an on-call engineer: what changed? A build that was clean last Tuesday and is not clean today has a story, and no one-shot scan can tell it.
sbomdrift stores the component inventories described by your SBOMs, re-evaluates
them against OSV.dev, and reports the diff between two
evaluations:
DRIFT python:3.11-slim 2026-03-01 → 2026-07-24
+ newly vulnerable 3
CRITICAL CVE-2026-1234 pkg:deb/debian/libssl3@3.0.11-1
HIGH CVE-2026-2233 pkg:pypi/requests@2.31.0
MEDIUM GHSA-xxxx-yyyy pkg:pypi/urllib3@2.0.7
- newly fixed 1
HIGH CVE-2025-9999 pkg:deb/debian/zlib1g@1:1.2.13
It is one pip install, one SQLite file and no server.
Install
pip install sbomdrift # or: uv tool install sbomdrift
Use
# 1. Remember what an artefact contained
sbomdrift ingest sbom.cdx.json --artefact python:3.11-slim
# 2. Ask the oracle — twice, at two points in time
sbomdrift eval --as-of 2026-03-01 --label march
sbomdrift eval --label today
# 3. What changed?
sbomdrift diff --from march --to today
In CI, --fail-on HIGH makes the command exit non-zero when drift introduces a new
finding at or above that severity — so a pipeline breaks on new risk rather than on
the accumulated backlog it already knew about.
Two kinds of drift
| Kind | What it answers | How |
|---|---|---|
| Version drift | what changed when the artefact moved | two snapshots (different digests), one evaluation date |
| Time drift | what became vulnerable while the artefact stood still | one snapshot, two evaluation dates (--as-of) |
--as-of reconstructs history from OSV's own published timestamps, so temporal
drift is demonstrable immediately instead of after a month of waiting — and it makes
drift deterministically testable, which is why the test suite can assert an exact
diff.
Caveat, stated plainly: OSV records are amended over time. --as-of filters on
publication date, so it reconstructs when an advisory became known, not the exact
data an evaluation would have returned on that day.
Where the history lives
The store is a single SQLite file. CI runners are ephemeral, so sbomdrift can pull
that file from S3 at the start of a run and push it back at the end:
sbomdrift pull s3://my-bucket/drift/history.db
... ingest / eval / diff ...
sbomdrift push s3://my-bucket/drift/history.db
Requires the s3 extra (pip install "sbomdrift[s3]") and credentials from the
standard AWS chain — in GitHub Actions, short-lived OIDC credentials.
How it compares
| Tool | Answers | Needs |
|---|---|---|
| Grype, Trivy | is this vulnerable now | nothing — but no memory, no diff |
| sbomgr, bomctl | which SBOM contains X | nothing — but not "what changed" |
| OWASP Dependency-Track | drift, and much more | a server, a database, a frontend |
| AWS Inspector | drift, for images in ECR | an AWS account; per-scan pricing |
| sbomdrift | what changed | one CLI and one file |
Licence
Apache-2.0.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file sbomdrift-0.1.0.tar.gz.
File metadata
- Download URL: sbomdrift-0.1.0.tar.gz
- Upload date:
- Size: 123.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a76115189e9ead807507ddee5b387fee875af24af332737d85b5b69e495aaddd
|
|
| MD5 |
0b01b9fc20a354060c8dc912b4f97afd
|
|
| BLAKE2b-256 |
2eaa3a2632ede4b50656bb87de2777f8ff6156dd6e721d6abe5b7a9c472f5a52
|
Provenance
The following attestation bundles were made for sbomdrift-0.1.0.tar.gz:
Publisher:
publish.yml on EngineerSamet/sbomdrift
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
sbomdrift-0.1.0.tar.gz -
Subject digest:
a76115189e9ead807507ddee5b387fee875af24af332737d85b5b69e495aaddd - Sigstore transparency entry: 2234710940
- Sigstore integration time:
-
Permalink:
EngineerSamet/sbomdrift@cbee6e9d93d29344836bda63ff0638240cc52b3d -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/EngineerSamet
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@cbee6e9d93d29344836bda63ff0638240cc52b3d -
Trigger Event:
release
-
Statement type:
File details
Details for the file sbomdrift-0.1.0-py3-none-any.whl.
File metadata
- Download URL: sbomdrift-0.1.0-py3-none-any.whl
- Upload date:
- Size: 32.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
80acef3577e8b692dba4dc4ba10baa33148df4d763652b184a0e140a1bbecf90
|
|
| MD5 |
7f4f36dac4eaf4c7c686d81332fcec41
|
|
| BLAKE2b-256 |
bae441df62ab92643c546f3c6b37ede98ee1bc7f07fb0cced1c8605bb31e2ae4
|
Provenance
The following attestation bundles were made for sbomdrift-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on EngineerSamet/sbomdrift
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
sbomdrift-0.1.0-py3-none-any.whl -
Subject digest:
80acef3577e8b692dba4dc4ba10baa33148df4d763652b184a0e140a1bbecf90 - Sigstore transparency entry: 2234711343
- Sigstore integration time:
-
Permalink:
EngineerSamet/sbomdrift@cbee6e9d93d29344836bda63ff0638240cc52b3d -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/EngineerSamet
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@cbee6e9d93d29344836bda63ff0638240cc52b3d -
Trigger Event:
release
-
Statement type: