In Google's osv-scanner, a single OSV advisory carrying an ecosystem name the pinned schema didn't recognize would panic the matcher and abort the entire offline scan, not just skip that advisory. Because osv.dev adds ecosystems over time, an older binary hits this in normal use. PR #2882 fixes it by skipping unknown ecosystems instead of crashing; the matcher has since moved to osv-scalibr, where the same fix is PR #2429.
osv-scanner is Google's open-source vulnerability scanner. It matches the dependencies in your project against advisories from the OSV database, and in offline mode it runs entirely against a local copy of that database, the mode you reach for in air-gapped environments and reproducible CI builds.
We found that a single OSV advisory carrying an ecosystem name the scanner didn't recognize would panic the matcher and abort the entire scan. Not skip one advisory, not warn: crash the whole run.
One advisory whose ecosystem string isn't in your build's pinned schema, and the scan of every package stops with a panic.
MustParse panic on an unknown ecosystem?Deep in the matcher, vulns.IsAffected and vulns.AffectsEcosystem resolved an advisory's ecosystem with osvecosystem.MustParse. As the name says, MustParse panics on any string the vendored osv-schema registry doesn't recognize:
// matcher, before the fix eco := osvecosystem.MustParse(advisory.Ecosystem) // panics on an unknown ecosystem // ...one unrecognized advisory here aborts the whole scan
Here's why that is reachable in normal operation, not a contrived input: the OSV database on osv.dev adds new ecosystems over time, while any given osv-scanner binary is built against a pinned snapshot of the schema. The day the database ships an advisory for an ecosystem newer than your installed scanner knows about, that advisory's ecosystem string is “unknown” to MustParse, and the panic takes the entire offline scan down with it.
The failure mode is the worst kind for a scanner. It doesn't quietly miss one advisory; it aborts the whole run. A CI gate that depends on osv-scanner to fail the build on a known-vulnerable dependency simply stops producing a verdict the moment an unrelated new ecosystem lands upstream, and offline, reproducible builds are precisely where you can't just pull a fresh schema to make the crash go away. A robustness bug in the tool becomes a gap in the thing the tool exists to guarantee.
PR #2882 (maintainer-approved), addressing issue #2867, replaces the panic-prone call with a parseAffectedEcosystem helper built on the non-panicking osvecosystem.Parse. When an ecosystem isn't recognized, the affected entry is skipped with a debug-level log instead of crashing, mirroring the error handling the scanner already used for version parsing.
Update, September 2026. Before #2882 merged, osv-scanner moved its local matcher into osv-scalibr, and the maintainer asked for the PR to follow. The same fix, with the regression test, is now osv-scalibr PR #2429. The panic site (osvecosystem.MustParse in IsAffected) was carried over unchanged in the move, so the bug is still live in osv-scalibr until that PR lands.
// after the fix eco, err := osvecosystem.Parse(advisory.Ecosystem) if err != nil { // skip this affected entry, keep scanning log.Debug(...); continue }
The practical effect: older builds now gracefully skip the entries they can't interpret instead of aborting all offline scans when osv.dev moves faster than the pinned schema.
A scanner is a state machine over its inputs, and its inputs include the advisory data it's asked to interpret. Feed it something just outside its modeled domain (an ecosystem that isn't in the pinned enumeration), and the correct behavior is to degrade, not halt. RedMirror looks for exactly that: a reachable input that drives a program into a state it has no graceful path out of. Here it's an advisory field with an unrecognized value reaching a MustParse that treats “unknown” as “impossible.” We surface the input that gets there so it can be handled before it takes a scan down in production.
In Google's osv-scanner, a single OSV advisory carrying an ecosystem name the scanner didn't recognize would panic the matcher and abort the entire offline scan. It did not skip the one advisory or warn, it crashed the whole run.
The OSV database on osv.dev adds new ecosystems over time, while any given osv-scanner binary is built against a pinned snapshot of the schema. The day the database ships an advisory for an ecosystem newer than your installed scanner knows about, that string is unknown to MustParse, and the panic takes the entire offline scan down.
The failure mode is the worst kind for a scanner: it aborts the whole run instead of quietly missing one advisory. A CI gate that relies on osv-scanner to fail the build on a known-vulnerable dependency stops producing a verdict the moment an unrelated new ecosystem lands upstream, and offline reproducible builds are exactly where you cannot just pull a fresh schema to make the crash go away.
Yes. PR #2882 (maintainer-approved, addressing issue #2867) replaces the panic-prone MustParse call with a parseAffectedEcosystem helper built on the non-panicking osvecosystem.Parse. The matcher has since moved to osv-scalibr, so the fix was re-submitted there as osv-scalibr PR #2429. An unrecognized ecosystem is now skipped with a debug-level log instead of crashing the scan, mirroring the error handling the scanner already used for version parsing.
Update, September 2026. Before #2882 merged, osv-scanner moved its local matcher into osv-scalibr, and the maintainer asked for the PR to follow. The same fix, with the regression test, is now osv-scalibr PR #2429. The panic site (osvecosystem.MustParse in IsAffected) was carried over unchanged in the move, so the bug is still live in osv-scalibr until that PR lands.
Go. osv-scanner is Google's open-source vulnerability scanner, and the panic lived in its matcher, where vulns.IsAffected and vulns.AffectsEcosystem resolved an advisory's ecosystem with osvecosystem.MustParse.
RedMirror treats a scanner as a state machine over its inputs and looks for a reachable input that drives the program into a state it has no graceful path out of. Here it surfaced an advisory field with an unrecognized ecosystem value reaching a MustParse that treats unknown as impossible, so it can be handled before it takes a scan down in production.
Parsers, matchers, and anything that consumes external data have states like this: an input the code assumed could never appear. RedMirror finds the reachable one and reports it as a concrete path, so a robustness gap doesn't become a security gap.
Get RedMirror Read the docs