Safeguard
Industry Analysis•

How do you cite an OSV snapshot when it has no version number?

OSV exports have no release number. Cite the ecosystem file, its Last-Modified header, your fetch date and a hash, and note the top modified_id.csv line.

Safeguard Security Team
6 min read

OSV exports have no release number, so cite the exact file URL, the Last-Modified time the server reports, your fetch date, and a SHA-256 hash of the download. Optionally add the top line of modified_id.csv. Together these let a reader tell which version of a continuously changing database you used.

Why OSV needs a different approach

KEV has a catalogVersion and EPSS has a model version and score date. OSV does not publish a version for the whole database. OSV documents that its sources are continuously exported to a bucket, with per-ecosystem archives at a path such as the ecosystem name followed by all.zip, and a modified_id.csv listing recently changed records, newest first. The database changes all day, so "I used OSV" says almost nothing.

Five things to record

  1. The file URL. The per-ecosystem archive, not just "OSV". Different ecosystems are different files.
  2. The Last-Modified header. A HEAD request returns it without downloading anything.
  3. Your fetch date and time, in UTC.
  4. A SHA-256 hash of the file you analyzed.
  5. Optionally, the first line of modified_id.csv at fetch time, which names the newest change.
curl -sSI https://osv-vulnerabilities.storage.googleapis.com/PyPI/all.zip | grep -i last-modified
curl -sSL -o PyPI.zip https://osv-vulnerabilities.storage.googleapis.com/PyPI/all.zip
shasum -a 256 PyPI.zip

What the headers showed on 19 October 2026

Each ecosystem export has its own timestamp. When the author checked five of them, the Last-Modified values were:

EcosystemLast-Modified (GMT)
PyPIMon, 19 Oct 2026 02:33:11
crates.ioSat, 17 Oct 2026 15:32:45
GoSun, 18 Oct 2026 11:02:47
RubyGemsSat, 17 Oct 2026 03:03:05
PackagistSat, 17 Oct 2026 17:02:51

So a "five ecosystem comparison" was really five snapshots spanning about two days. A good methodology says that in one sentence. The top line of the top level modified_id.csv at the time was dated 2026-10-19T04:00:18Z, for a Debian record.

A citation line

Source: OSV per-ecosystem exports (PyPI, crates.io, Go, RubyGems, Packagist), Last-Modified between 2026-10-17 and 2026-10-19 GMT, fetched 19 October 2026, SHA-256 hashes in the appendix.

Records change after you download

Per the OSV schema, each record has a modified timestamp in UTC, and if two entries share an ID, the one with the later modified time is authoritative. Withdrawn records stay in the exports with a withdrawn timestamp. That means a record you counted as current can be withdrawn tomorrow. Your snapshot is a photograph, and the citation line is its caption. To watch for changes instead, see polling OSV for new advisories.

A worked example, from request to citation

Start with the question "how many PyPI advisories are in OSV?" and walk the chain.

  1. Send a HEAD request to the PyPI archive and note the Last-Modified time. On 19 October 2026 it was Monday 19 October 02:33:11 GMT.
  2. Download the file and record your fetch time in UTC.
  3. Hash the file.
  4. Open it and count the JSON files. The author counted 26,383, which includes withdrawn records.
  5. Count the withdrawn ones separately. There were 617.
  6. Write the sentence: "The PyPI export, Last-Modified 2026-10-19 02:33 GMT, held 26,383 records, 617 of them withdrawn."

Each part answers a different reader question. Which file? When was it built? Which records count? A sentence that skips the third will be read as 26,383 current advisories, which overstates the number.

Why the timestamps differ by ecosystem

OSV documents that sources are aggregated and continuously exported, with a separate archive per ecosystem. Each archive is rebuilt on its own schedule, so the Last-Modified time varies, as the table showed. If you compare ecosystems, the older archive may miss records the newer one already includes. State the spread, and if it matters for your argument, fetch all of them within the same hour.

SituationWhat to do
One ecosystemCite that archive and its header
Several ecosystemsCite each, and state the time spread
All of OSVCite the top level archive and its header, and note the size
Tracking changes over timeKeep a dated copy of each fetch

Using modified_id.csv as a second anchor

The file lists changed records in reverse chronological order, one line per record, with a timestamp and the path. Its top line tells you the newest change at the time you looked. The line you saw is a useful anchor: "the newest change in the index was 2026-10-19T04:00:18Z". It does not prove your archive contains that change, since archives are built on separate schedules, so use it as context and not as proof.

What to say when you cannot verify

If you downloaded a file and forgot the header, say so. Write "fetched 19 October 2026, Last-Modified not recorded" rather than guessing. A visible gap is better than an invented value. For a related approach to storing what you download, see freeze a dataset.

Citation checklist

Before you publish, tick each item.

  1. The URL of each archive is in the methodology.
  2. The Last-Modified time is recorded for each one.
  3. Your fetch time is in UTC.
  4. The hash of each file is stored.
  5. Withdrawn records are counted separately.
  6. A sentence says whether the counts include withdrawn records.

If any item is missing, add it now. It is much harder to recover later, because the archive will have been rebuilt.

Try it yourself

Click through it at your own pace, or open it full screen. Look for what changes between one scan and the next.

Quick check

Is the fetch date enough?

No. The Last-Modified header tells you how old the export itself was, and the hash proves which file you analyzed.

Do I need to cite every ecosystem separately?

Yes, if you use several. Each archive is its own file with its own timestamp.

Can I re-download the file later and get the same data?

Not reliably. The archive is rebuilt as records change. Keep your own dated copy and its hash.

Sources

Last reviewed: 19 October 2026.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.