Skip to content

osv-filter

Filter OSV data by ecosystem, reference type, or alias pattern.

Trigger: mentions of filtering by package ecosystem (npm, PyPI, Maven), reference type (ADVISORY, FIX), or alias pattern (CVE, GHSA). Skill source: .claude/skills/osv-filter/SKILL.md

CLI

bash
osv filter -e PyPI vulnerability.json        # By ecosystem
osv filter -r FIX vulnerability.json         # By reference type
osv filter -a CVE vulnerability.json         # By alias pattern
osv filter -e PyPI -r FIX vulnerability.json # Combine
osv filter -o json -e PyPI vulnerability.json
FlagDescription
-e, --ecosystemEcosystem, case-sensitive per OSV spec (PyPI, npm, Maven)
-r, --ref-typeReference type, auto-uppercased (ADVISORY, FIX, WEB)
-a, --aliasAlias prefix, upper-cased before matching (CVE, GHSA, CVE-2024)
-o, --outputtext (default) or json

At least one filter flag is required.

The default text output reports the filter, a yes/no Has ecosystem check, and matching counts. With no -o json, each dimension prints its own block:

bash
osv filter -e PyPI test_data/GHSA-vxv8-r8q2-63xw.json
text
ID: GHSA-vxv8-r8q2-63xw

Ecosystem filter: PyPI
  Has ecosystem: true
  Matching packages (9):
    - PyPI/tensorflow
    ...

-o json returns the filtered affected entries — note each event object carries only its one non-empty field (omitempty at work):

bash
osv filter -e PyPI -o json test_data/GHSA-vxv8-r8q2-63xw.json
json
{
  "affected": [
    {
      "package": { "ecosystem": "PyPI", "name": "tensorflow" },
      "ranges": [{ "type": "ECOSYSTEM", "events": [ { "introduced": "0" }, { "fixed": "2.7.2" } ] }]
    }
  ]
}

The three filter dimensions

The three flags are not combined into one predicate. Each operates on a different slice of the record and emits its own block-e PyPI -r FIX does not mean "FIX references inside PyPI packages"; it means "filter affected by PyPI and, separately, filter references by FIX", producing two independent results.

A flag you don't pass simply contributes no block — there is no "match all" default. That is also why Has ecosystem: true/false appears only under the ecosystem block: it's a property of the affected slice, asked only when -e is given.

SDK equivalent

go
// Ecosystem
pypi := v.Affected.FilterByEcosystem(osv.EcosystemPyPI)
hasNpm := v.Affected.HasEcosystem(osv.EcosystemNpm)

// References
fixes := v.References.FilterByType(osv.ReferenceTypeFix)

// Aliases
cves := v.Aliases.Filter(func(a string) bool {
    return strings.HasPrefix(strings.ToUpper(a), "CVE-")
})

Decision tree

Execution order of combined filters

Each flag independently acts on a different slice of the original data; combining them takes the intersection.

Matching semantics per flag

The three flags do not match the same way — this is the most common source of "why did my filter return nothing?".

-e is the strict one

Ecosystem is compared verbatim against the OSV spec's exact casing, so -e pypi silently returns nothing. Reference types are forgiving (auto-uppercased) and aliases are prefix-based. When a filter comes back empty, check -e casing first against the Ecosystems list.

Notes

  • Ecosystem names are case-sensitive (PyPI, not pypi)
  • Reference types are auto-uppercased in the CLI
  • Alias prefixes are upper-cased before matching, so -a cve works like -a CVE
  • HasEcosystem returns a bool; FilterByEcosystem returns the filtered slice

Cross-references

  • [[osv-parse]] — parse first
  • [[osv-query]] — extract fields after filtering
  • See Ecosystems for the full constant list

Last updated:

Released under the MIT License.