To freeze a vulnerability dataset, download the raw file once, compute its SHA-256 hash, and record the URL, fetch time and hash in a small manifest stored beside it. Run every analysis against that saved copy, never against a live URL. Then your numbers stay reproducible even after the source changes.
Why freeze at all
KEV, EPSS and OSV all change, and the "current" URL for EPSS is replaced each day. If you rerun a script next week against the live URL, you get different numbers and no way to explain the gap. A saved copy plus a hash gives you a fixed input and a way to prove it has not changed.
Steps
- Create a folder named for the date, such as snapshot-2026-10-19.
- Download each file with curl and keep the original name.
- Hash each file.
- Write the manifest.
- Make the folder read only, or commit it to version control.
- Point your scripts at the folder, not the URL.
mkdir snapshot-2026-10-19 && cd snapshot-2026-10-19
curl -sSL -o kev.json https://www.cisa.gov/sites/default/files/feeds/known_exploited_vulnerabilities.json
curl -sSL -o epss.csv.gz https://epss.empiricalsecurity.com/epss_scores-current.csv.gz
shasum -a 256 kev.json epss.csv.gz | tee SHA256SUMS
date -u +%Y-%m-%dT%H:%M:%SZ > FETCHED_AT.txt
On a Linux system use sha256sum instead of shasum. A reader can later run the same hash command on your published file and compare.
What the manifest holds
| Field | Why |
|---|---|
| File name | Matches the hash list |
| Source URL | Where it came from |
| Fetched at (UTC) | When you downloaded it |
| SHA-256 | Proof of contents |
| Source version | KEV catalogVersion, EPSS header line, OSV Last-Modified |
On 19 October 2026 the author's KEV file hashed to b6e27975f6635ecfc546fbd4fd6e444ba63a07ab2abc8876229d77fe083d357d. That value is only meaningful alongside the file it describes; it tells you nothing about any other download.
What a hash does and does not prove
A matching hash proves that two files are byte identical. It does not prove the data is correct, complete or authoritative. It also will not match if you re-save a file through a tool that changes formatting, so hash the original download, not a pretty printed copy.
A hash does not make an analysis valid. It only makes it repeatable. For a full approach to publishing the rest of the package, see a methodology section template.
Large files
The OSV all.zip archives are large for a quick analysis. Per-ecosystem archives are smaller; in the author's fetch, the five used here ranged from about 3.6 MB to 36 MB. Freeze only the ecosystems you use and list them in the manifest.
A worked example of a manifest
Here is a small manifest for the files fetched on 19 October 2026. The KEV hash is the real value from the author's download; the EPSS and OSV values are described rather than invented, so fill in your own.
| File | Source | Version evidence | SHA-256 |
|---|---|---|---|
| kev.json | CISA KEV JSON feed | catalogVersion 2026.10.16 | b6e27975f6635ecfc546fbd4fd6e444ba63a07ab2abc8876229d77fe083d357d |
| epss.csv.gz | EPSS current file | Header: model v2026.06.15, score date 2026-10-18T12:03:10Z | your computed value |
| PyPI.zip | OSV PyPI archive | Last-Modified 2026-10-19 02:33:11 GMT | your computed value |
Save this as a plain text or CSV file in the same folder. Commit the folder or write protect it, so nothing can change under your scripts.
Verifying a snapshot later
Weeks later, run the same command and compare:
shasum -a 256 kev.json
If the value matches the manifest, the file is byte identical to the one you analyzed. If it does not, something changed it: a re-save, a different download or an edit. Do not run analyses on a file that fails the check.
Folder layout that scales
- snapshot-YYYY-MM-DD for each fetch, so old ones are never overwritten.
- A SHA256SUMS file in each folder.
- A short README with the questions the snapshot supports.
- A scripts folder outside the snapshot, so scripts can run against any snapshot.
- An output folder named for the snapshot, so results are traceable.
Keeping scripts separate from data also follows a safe habit: treat downloaded files as untrusted input. Do not run code that lives inside a downloaded archive, and read data with a loader that only parses it.
Publishing the package
If you publish your analysis, include the script, the manifest and the output tables. If the license allows you to share the raw files, include them; if not, include the URLs and hashes so a reader can fetch and verify. Check the terms first; see the attribution checklist. Then test your own package: on a clean machine, fetch the files, check the hashes and run the script. If the numbers match your post, publish.
Common mistakes
- Hashing a file after opening and re-saving it in a spreadsheet.
- Overwriting last week's folder with this week's download.
- Recording the hash only in your head or a chat message.
- Pointing a script at the live URL "just for a quick check", then publishing the result.
- Forgetting the comment line in the EPSS file, so the first row is parsed as data.
Each of these has caused numbers in a draft to stop matching numbers in a table. A frozen folder and a manifest prevent all of them.
Try it yourself
Click through it at your own pace, or open it full screen. Open the inventory and notice how each component carries a version, which is the same discipline a snapshot manifest applies to a dataset.
Quick check
Is it fine to store the raw files in a public repository?
Check the license first. KEV is distributed with a CC0 license file. OSV sources set their own licenses. This is not legal advice.
Should I hash the decompressed EPSS file?
Hash the original download and note the decompression step. If you also hash the decompressed file, label which is which.
What if the live file has changed and my hash no longer matches it?
That is expected. The hash is for your saved copy. The live file is a newer version of the same source.
Sources
- CISA KEV JSON feed and license file, https://www.cisa.gov/sites/default/files/feeds/known_exploited_vulnerabilities.json and https://www.cisa.gov/sites/default/files/licenses/kev/license.txt (fetched 19 October 2026).
- EPSS daily scores file, https://epss.empiricalsecurity.com/epss_scores-current.csv.gz (fetched 19 October 2026).
- OSV data documentation, https://google.github.io/osv.dev/data/ (fetched 19 October 2026).
Last reviewed: 19 October 2026.