Vulnerability scan results can change even when the code does not. Advisory data, comparison rules, or exclusions may change between scans, making earlier results difficult to explain.
I built dumpscan to make vulnerability scans reproducible.
Each scan records four inputs by digest:
- Dependency lockfile
- OSV vulnerability snapshot
- Version comparison rules
- Applied exclusions
Using the same inputs produces the same findings byte for byte. When results differ, dumpscan identifies which input changed.
Create a reproducible scan
Instead of relying on the latest advisory data, dumpscan requires a content-addressed OSV snapshot:
dumpscan scan package-lock.json \
--snapshot ./snapshot \
--out scan.bundle.json
The resulting bundle contains the input digests, findings, and findings root needed to verify the result later.
This is useful during audits, incident reviews, and investigations where teams need to understand what the scanner knew at a specific time.
Sign and verify results
A signature proves that a file was signed, but not that its findings can be reproduced.
dumpscan records the input digests and findings root in an in-toto statement. It also supports keyless signing with Sigstore:
dumpscan scan package-lock.json \
--snapshot ./snapshot \
--out scan.bundle.json \
--sign
Verify the bundle without running another scan:
dumpscan verify scan.bundle.json
Verification checks the signature, payload binding, findings root, findings count, input manifest, and lockfile digest. It can also verify the certificate issuer and workflow identity.
Replay a scan
Replay derives the findings again from the recorded inputs:
dumpscan replay scan.bundle.json \
--lockfile package-lock.json \
--snapshot ./snapshot
The replay must produce the same findings root. If it does not, dumpscan reports the expected and observed digests.
Explain changed results
When two scans differ, dumpscan diff determines whether the change came from the project or the scanning inputs:
dumpscan diff scan-day-1.bundle.json scan-day-2.bundle.json \
--snapshot-a ./snapshot-day-1 \
--snapshot-b ./snapshot-day-2
It compares the lockfile, vulnerability feed, version rules, and exclusions. When snapshots are available, it can also identify changed advisory fields.
This helps distinguish a dependency update from an advisory being rescored, withdrawn, or assigned a new fixed version.
Keep uncertainty visible
Excluded, withdrawn, and unevaluated findings remain in the findings set with their status and reason.
Unsupported version ranges are not treated as unaffected, and exclusions are recorded as scan inputs. This keeps the result complete and makes policy decisions visible during review.
Get started
dumpscan requires Node 22.22.2 or later:
npm install --global dumpscan
You can also run it without a global installation:
npx dumpscan --help
Create a snapshot from local OSV records:
dumpscan snapshot \
--from fixtures/osv/synthetic/records \
--out ./snapshot
Generate SARIF 2.1.0 output for GitHub code scanning:
dumpscan scan package-lock.json \
--snapshot ./snapshot \
--out scan.bundle.json \
--sarif scan.sarif
The SARIF file is derived output. The bundle remains the reproducible source of truth.
Scope
The first release focuses on lockfile scanning. It does not provide reachability analysis, exploitability analysis, risk scoring, container scanning, or SBOM generation.
These limits are intentional. dumpscan prioritizes reproducible, verifiable results over broad vulnerability-management coverage.
dumpscan is available under the Apache 2.0 license:
Top comments (0)