Safeguard
Security Guides•

How do OSV version ranges work, and where can scans go wrong?

OSV records use SEMVER, ECOSYSTEM and GIT ranges. Learn what introduced, fixed and last_affected mean and which choices create false negatives.

Safeguard Security Team
3 min read

An OSV advisory states which versions are affected with a range of one of three types: SEMVER, ECOSYSTEM or GIT. Events such as introduced and fixed mark the edges. Most scan errors in this area come from how a tool compares versions, or from records that use last_affected instead of fixed.

The three range types

The OSV schema defines the type field as required, and it controls how the values are read.

TypeValues areComparison rule
SEMVERSemVer 2.0.0 strings, no leading vSemantic versioning order
ECOSYSTEMPlain stringsThe package ecosystem's own ordering
GITFull commit hashesNeeds the repository's commit graph

For ECOSYSTEM ranges the schema notes that questions about inclusion may not be answerable without the ecosystem's own logic, which is why a versions list is recommended. GIT ranges still require an explicit versions list because they cannot be evaluated without a copy of the repository.

The events

  • introduced starts the vulnerable range. The value 0 sorts before every other version.
  • fixed is the first version containing the fix, and the schema says it is overwhelmingly preferred.
  • last_affected is the highest affected version at the time of publication when no fix exists.
  • limit sets an upper bound. For linear version ranges the schema says it should not be used.

A version is affected if it lies within any one range or appears in the versions list.

Where false negatives come from

The schema itself flags one risk. With last_affected, versions above the stated value are treated as unaffected, which "opens up the possibility for false negatives." If a vulnerability turns out to affect a later release, a record that named a last affected version can understate it until someone updates the record.

For GIT ranges, the schema says fixed events must include cherry picked fixes on every branch, or false positives result, while using limit instead can cause false negatives.

A third source is the scanner. If a tool applies SemVer ordering to a package that follows another scheme, it can place a version on the wrong side of a boundary. See why Python and SemVer versions sort differently.

How to check a record you care about

  1. Open the advisory in its source database and view the raw OSV JSON.
  2. Note the range type and the event that ends the range.
  3. If it uses last_affected, look at the upstream project for later releases and read their notes.
  4. Test your scanner on one version just inside and one just outside each boundary.

Safeguard's dependency scanning matches component versions against advisory data, and you can try a manifest at https://gold.safeguard.sh/scan.

Quick check

What is the difference between fixed and last_affected?

Fixed names the first version with the fix. Last_affected names the highest known affected version when no fix exists, and versions above it are treated as unaffected.

Why do GIT ranges need a repository?

Commit hashes cannot be ordered without the commit graph, so a tool needs the repository to decide whether a version falls in the range.

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.