osv.dev icon indicating copy to clipboard operation
osv.dev copied to clipboard

Rust Crate versions missing metadata

Open gitgitwhat opened this issue 4 months ago • 4 comments

Describe the bug Vulnerability reports for Rust crates are missing the metadata value (https://doc.rust-lang.org/cargo/reference/manifest.html#the-version-field) in the version field under 'affected/ranges' (and possibly other places).

To Reproduce Look at the report for RUSTSEC-2024-0013 (https://api.osv.dev/v1/vulns/RUSTSEC-2024-0013). It shows that it was fixed in version 0.16.2 however the correct way to identity this version is with the additional metadata of '+1.7.2'. Without that additional metadata, there is no way to resolve the correct crate.io repo of https://crates.io/crates/libgit2-sys/0.16.2+1.7.2 because just https://crates.io/crates/libgit2-sys/0.16.2 doesn't exist.

Expected behaviour The metadata must be included in order to resolve the package from other sources as well as perform proper vulnerability management. Because in this case the follow PURLs don't match

pkg:cargo/[email protected] != pkg:cargo/[email protected]%2B1.7.2

Additional context Your sister service (deps.dev) lists the versions properly (https://deps.dev/cargo/libgit2-sys/0.16.2%2B1.7.2) so there should be some consistency.

gitgitwhat avatar Oct 10 '25 12:10 gitgitwhat

Hi, The fixed version number 0.16.2 is coming directly from RustSec. I don't believe OSV.dev would drop the metadata suffix if it were present.

The metadata must be included in order to resolve the package from other sources as well as perform proper vulnerability management. Because in this case the follow PURLs don't match

pkg:cargo/[email protected] != pkg:cargo/[email protected]%2B1.7.2

I am unsure if we are generally able to guarantee a fixed version is always a 'real' version of the package. The affected[].ranges[] field mostly just encodes the range (>=0.0.0-0, <0.16.2) for vulnerability scanning. Since the metadata is ignored for SemVer comparison, it is reasonable for advisories to drop it in the fixed version.

If you require an exact, resolvable version of a package, then it would be best to consult crates.io for available packages and cross-reference it with the advisory's fixed version (for now, at least).

michaelkedar avatar Oct 13 '25 00:10 michaelkedar

Thanks @michaelkedar . I see in the RustSec that they mention the 1.7.2 release in the raw description of the vuln but leaves it out of the JSON field. I know it's ignored by semver but seems like bad practice that they don't include it if it's used other places.

Unfortunately your suggestion may be the only way to resolve the package (assuming that any package update updates both versions and not just the release version).

gitgitwhat avatar Oct 13 '25 19:10 gitgitwhat

cc @shnatsel

tarcieri avatar Oct 15 '25 14:10 tarcieri

In this particular case the issue stems from the upstream database recording the constraint as ">= 0.16.2", without the metadata prefix: https://rustsec.org/advisories/RUSTSEC-2024-0013.html

That said, in OSV you cannot assume that the specified version exists as-is in the package registry. OSV 1.0 didn't support last_affected, so the only way to express that was to synthesize a fixed version that does not exist in the registry but evaluates to the correct bounds under semver precedence rules. RustSec still exports 1.0 so we have to synthesize such versions on occasion. Also, there is no last_unaffected (exclusive lower bound, as opposed to introduced which is an inclusive lower bound) and RustSec allows specifying such versions, so they also need to be lowered that way.

It is conceivable that upstream RustSec could migrate to a newer OSV version to support last_affected and prohibit exclusive lower bounds on version ranges; these two measures together would eliminate the need to synthesize nonexistent versions. But then RustSec would also have to enforce that all versions in all the bounds exist in the package registry, and that would make preparing advisories for packages with upcoming fixes more difficult.

None of this is insurmountable, but it would require significant engineering effort, and RustSec maintainers are spread thin as it is. Given that the current system works fine for the intended use in vulnerability scanners, this would not be very high on the list of priorities. Furthermore, even if all of the above was implemented, it would still only improve the situation for RustSec and the same issues would persist for all other data sources. RustSec is not the only data source for Rust.

I believe the only robust solution would be cross-referencing the constraints from the OSV affected[].ranges[] field with the list of package versions in the registry. It would be nice if a library or an API would do that for you. In Rust you can use https://crates.io/crates/tame-index to fetch the list of existing versions for a given package and then match them against the affected[].ranges[] field.

TL;DR: this particular case is probably an easy fix, but guaranteeing this property in general would be very difficult.

Shnatsel avatar Oct 15 '25 15:10 Shnatsel