osv-scanner
Google's dependency scanner — lockfiles + SBOMs, minimal false positives.
Quick Start
# Scan directory (auto-detect lockfiles)
osv-scanner scan source -r .
# Scan specific lockfile
osv-scanner scan source --lockfile package-lock.json
# Scan container image
osv-scanner scan image nginx:latest
# JSON output
osv-scanner scan source -r . --format json
Core Flags
| Flag |
Purpose |
-l, --lockfile <file> |
Scan specific lockfile |
-r, --recursive |
Recursively find lockfiles in directory |
--format <fmt> |
Output: json / vertical / html / sarif |
-o, --output-file <file> |
Save output to file |
--serve |
Serve HTML report at localhost:8000 |
--experimental-call-analysis |
Reachability analysis (skip unused vuln code) |
--all-packages |
Include packages without CVEs in JSON output |
--no-resolve |
Disable transitive dependency resolution |
--offline-vulnerabilities |
Use cached local DB (no network) |
--download-offline-databases <dir> |
Cache DB locally |
--licenses |
Check license compliance |
--config <file> |
Config file (overrides directory-level configs) |
--verbosity <level> |
info / warning / error |
Supported Lockfiles (19+ formats)
| Language |
Files |
| Go |
go.mod, go.sum |
| JavaScript |
package-lock.json, yarn.lock, pnpm-lock.yaml, bun.lock |
| Python |
requirements.txt, poetry.lock, Pipfile.lock, pdm.lock, pylock.toml, uv.lock |
| Java |
pom.xml, gradle.lockfile, gradle/verification-metadata.xml |
| Rust |
Cargo.lock |
| Ruby |
Gemfile.lock, gems.locked |
| PHP |
composer.lock |
| .NET |
packages.config, packages.lock.json |
| Dart |
pubspec.lock |
| Elixir |
mix.lock |
| Haskell |
cabal.project.freeze, stack.yaml.lock |
Common Workflows
# Full project scan (recursive)
osv-scanner scan source -r /path/to/project
# Multiple specific lockfiles
osv-scanner scan source \
-l package-lock.json \
-l requirements.txt \
-l go.sum
# Container image scan
osv-scanner scan image myapp:latest --format json
# Reachability analysis (reduces false positives)
osv-scanner scan source -r . --experimental-call-analysis
# HTML interactive report
osv-scanner scan source -r . --format html --serve
# Offline scan (use cached DB)
osv-scanner scan source -r . --offline-vulnerabilities
# CI gate: fail on any finding
osv-scanner scan source -r . --format sarif -o results.sarif
echo $? # non-zero = vulnerabilities found
# License compliance check
osv-scanner scan source -r . --licenses --format json
Output Parsing
osv-scanner scan source -r . --format json -o scan.json
# Extract findings
cat scan.json | jq '.results[].packages[].vulnerabilities[] | {id: .id, package: .packages[0].package.name, severity: .database_specific.severity}'
# Count by ecosystem
cat scan.json | jq '[.results[].packages[] | select(.vulnerabilities | length > 0) | .package.ecosystem] | group_by(.) | map({eco: .[0], count: length})'
# List affected packages
cat scan.json | jq -r '.results[].packages[] | select(.vulnerabilities | length > 0) | "\(.package.name) \(.package.version) (\(.package.ecosystem))"'
GitHub Actions
name: OSV Scanner
on:
pull_request:
schedule:
- cron: "0 0 * * 0" # Weekly full scan
jobs:
# PR scan: only new vulnerabilities introduced in PR
scan-pr:
uses: google/osv-scanner-action/.github/workflows/osv-scanner-reusable-pr.yml@v2
with:
scan-args: |-
--lockfile=./package-lock.json
--lockfile=./requirements.txt
fail-on-vuln: true
upload-sarif: true
# Scheduled full scan
scan-full:
if: github.event_name == 'schedule'
uses: google/osv-scanner-action/.github/workflows/osv-scanner-reusable.yml@v2
with:
scan-args: |-
-r .
fail-on-vuln: true
Resources
| File |
When to load |
references/config-ignore.md |
osv-scanner.toml config, ignore rules, package overrides, comparison with grype/trivy |
1---2name: osv-scanner3description: Auth/lab ref: Google's dependency vulnerability scanner using the OSV.dev database (30+ ecosystem sources).4license: Apache-2.05---67# osv-scanner89Google's dependency scanner — lockfiles + SBOMs, minimal false positives.1011## Quick Start1213```bash14# Scan directory (auto-detect lockfiles)15osv-scanner scan source -r .1617# Scan specific lockfile18osv-scanner scan source --lockfile package-lock.json1920# Scan container image21osv-scanner scan image nginx:latest2223# JSON output24osv-scanner scan source -r . --format json25```2627## Core Flags2829| Flag | Purpose |30|------|---------|31| `-l, --lockfile <file>` | Scan specific lockfile |32| `-r, --recursive` | Recursively find lockfiles in directory |33| `--format <fmt>` | Output: `json` / `vertical` / `html` / `sarif` |34| `-o, --output-file <file>` | Save output to file |35| `--serve` | Serve HTML report at localhost:8000 |36| `--experimental-call-analysis` | Reachability analysis (skip unused vuln code) |37| `--all-packages` | Include packages without CVEs in JSON output |38| `--no-resolve` | Disable transitive dependency resolution |39| `--offline-vulnerabilities` | Use cached local DB (no network) |40| `--download-offline-databases <dir>` | Cache DB locally |41| `--licenses` | Check license compliance |42| `--config <file>` | Config file (overrides directory-level configs) |43| `--verbosity <level>` | `info` / `warning` / `error` |4445## Supported Lockfiles (19+ formats)4647| Language | Files |48|----------|-------|49| Go | `go.mod`, `go.sum` |50| JavaScript | `package-lock.json`, `yarn.lock`, `pnpm-lock.yaml`, `bun.lock` |51| Python | `requirements.txt`, `poetry.lock`, `Pipfile.lock`, `pdm.lock`, `pylock.toml`, `uv.lock` |52| Java | `pom.xml`, `gradle.lockfile`, `gradle/verification-metadata.xml` |53| Rust | `Cargo.lock` |54| Ruby | `Gemfile.lock`, `gems.locked` |55| PHP | `composer.lock` |56| .NET | `packages.config`, `packages.lock.json` |57| Dart | `pubspec.lock` |58| Elixir | `mix.lock` |59| Haskell | `cabal.project.freeze`, `stack.yaml.lock` |6061## Common Workflows6263```bash64# Full project scan (recursive)65osv-scanner scan source -r /path/to/project6667# Multiple specific lockfiles68osv-scanner scan source \69 -l package-lock.json \70 -l requirements.txt \71 -l go.sum7273# Container image scan74osv-scanner scan image myapp:latest --format json7576# Reachability analysis (reduces false positives)77osv-scanner scan source -r . --experimental-call-analysis7879# HTML interactive report80osv-scanner scan source -r . --format html --serve8182# Offline scan (use cached DB)83osv-scanner scan source -r . --offline-vulnerabilities8485# CI gate: fail on any finding86osv-scanner scan source -r . --format sarif -o results.sarif87echo $? # non-zero = vulnerabilities found8889# License compliance check90osv-scanner scan source -r . --licenses --format json91```9293## Output Parsing9495```bash96osv-scanner scan source -r . --format json -o scan.json9798# Extract findings99cat scan.json | jq '.results[].packages[].vulnerabilities[] | {id: .id, package: .packages[0].package.name, severity: .database_specific.severity}'100101# Count by ecosystem102cat scan.json | jq '[.results[].packages[] | select(.vulnerabilities | length > 0) | .package.ecosystem] | group_by(.) | map({eco: .[0], count: length})'103104# List affected packages105cat scan.json | jq -r '.results[].packages[] | select(.vulnerabilities | length > 0) | "\(.package.name) \(.package.version) (\(.package.ecosystem))"'106```107108## GitHub Actions109110```yaml111name: OSV Scanner112on:113 pull_request:114 schedule:115 - cron: "0 0 * * 0" # Weekly full scan116117jobs:118 # PR scan: only new vulnerabilities introduced in PR119 scan-pr:120 uses: google/osv-scanner-action/.github/workflows/osv-scanner-reusable-pr.yml@v2121 with:122 scan-args: |-123 --lockfile=./package-lock.json124 --lockfile=./requirements.txt125 fail-on-vuln: true126 upload-sarif: true127128 # Scheduled full scan129 scan-full:130 if: github.event_name == 'schedule'131 uses: google/osv-scanner-action/.github/workflows/osv-scanner-reusable.yml@v2132 with:133 scan-args: |-134 -r .135 fail-on-vuln: true136```137138## Resources139140| File | When to load |141|------|--------------|142| `references/config-ignore.md` | osv-scanner.toml config, ignore rules, package overrides, comparison with grype/trivy |