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
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| Flag | Description |
|---|---|
-e, --ecosystem | Ecosystem, case-sensitive per OSV spec (PyPI, npm, Maven) |
-r, --ref-type | Reference type, auto-uppercased (ADVISORY, FIX, WEB) |
-a, --alias | Alias prefix, upper-cased before matching (CVE, GHSA, CVE-2024) |
-o, --output | text (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:
osv filter -e PyPI test_data/GHSA-vxv8-r8q2-63xw.jsonID: 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):
osv filter -e PyPI -o json test_data/GHSA-vxv8-r8q2-63xw.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
// 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, notpypi) - Reference types are auto-uppercased in the CLI
- Alias prefixes are upper-cased before matching, so
-a cveworks like-a CVE HasEcosystemreturns a bool;FilterByEcosystemreturns the filtered slice
Cross-references
- [[osv-parse]] — parse first
- [[osv-query]] — extract fields after filtering
- See Ecosystems for the full constant list