Skip to content

OSV-Scanner

Overview

OSV-Scanner is a free, open-source vulnerability scanner from Google that queries the OSV.dev database — a distributed, open vulnerability database covering over 20 package ecosystems (npm, PyPI, Go, Maven, crates.io, NuGet, RubyGems, etc.) and aggregating data from GitHub Security Advisories, NVD, GHSA, CVE.org, and ecosystem-specific feeds. It scans lockfiles, SBOM files, container images, git repository histories, and directories. The guided remediation feature (osv-scanner fix) proposes the minimal version bumps to resolve vulnerabilities.

Installation

Go install (latest)

go install github.com/google/osv-scanner/cmd/osv-scanner@latest
osv-scanner --version

GitHub Releases (binary)

# Linux x86_64
curl -LO https://github.com/google/osv-scanner/releases/latest/download/osv-scanner_linux_amd64
chmod +x osv-scanner_linux_amd64
sudo mv osv-scanner_linux_amd64 /usr/local/bin/osv-scanner

Homebrew (macOS / Linux)

brew install osv-scanner

Docker

docker run --rm -v "$(pwd):/src" ghcr.io/google/osv-scanner --lockfile /src/package-lock.json

Verify installation

osv-scanner --version
osv-scanner --help

Configuration

osv-scanner.toml (project-level)

[[IgnoredVulns]]
id = "GO-2023-1840"
reason = "Not reachable in our usage pattern"

[[IgnoredVulns]]
id = "GHSA-1234-abcd-5678"
ignoreUntil = 2024-06-01  # Auto-expire ignore
reason = "Upstream fix pending, tracked in JIRA-123"

[IgnorePackages]
# Ignore all vulns for this package
[[IgnorePackages.packages]]
name = "vendored-library"
ecosystem = "npm"
reason = "Internal fork, managed separately"

[Licenses]
# License compliance checking
allowlist = ["MIT", "Apache-2.0", "BSD-2-Clause", "BSD-3-Clause", "ISC"]
deny = ["GPL-2.0", "GPL-3.0", "AGPL-3.0"]

Config file discovery

osv-scanner looks for osv-scanner.toml in:

  1. Directory explicitly passed via --config
  2. Each scanned directory (walking up to repo root)
  3. ~/.config/osv-scanner/config.toml

Core Commands

CommandDescription
osv-scanner scan --lockfile package-lock.jsonScan an npm lockfile
osv-scanner scan --lockfile requirements.txtScan Python requirements
osv-scanner scan --lockfile go.sumScan Go module lockfile
osv-scanner scan --lockfile Cargo.lockScan Rust Cargo lockfile
osv-scanner scan --lockfile yarn.lockScan Yarn lockfile
osv-scanner scan --lockfile poetry.lockScan Poetry lockfile
osv-scanner scan --lockfile pnpm-lock.yamlScan pnpm lockfile
osv-scanner scan --dir .Scan directory for lockfiles automatically
osv-scanner scan --recursive .Recursively scan all lockfiles
osv-scanner scan --sbom sbom.jsonScan a CycloneDX or SPDX SBOM
osv-scanner scan --docker myapp:latestScan a Docker image
osv-scanner scan --git-commit abc123fScan at a specific commit
osv-scanner fixGuided remediation (suggest version bumps)
osv-scanner scan -f json .JSON output
osv-scanner scan -f sarif .SARIF output
osv-scanner scan --fail-on-vuln .Exit non-zero if vulns found
osv-scanner scan --config custom.toml .Use custom config
osv-scanner scan --experimental-call-analysis .Enable call graph analysis
osv-scanner scan --offline .Offline mode (use local DB)
osv-scanner scan --licenses-summary .License compliance report

Advanced Usage

Supported lockfile formats

FileEcosystem
package-lock.jsonnpm
yarn.locknpm (Yarn)
pnpm-lock.yamlnpm (pnpm)
requirements.txtPyPI
Pipfile.lockPyPI
poetry.lockPyPI
go.sumGo
Cargo.lockRust (crates.io)
Gemfile.lockRubyGems
composer.lockPackagist (PHP)
pubspec.lockpub.dev (Dart/Flutter)
packages.lock.jsonNuGet
pom.xmlMaven
build.gradleGradle
conan.lockConan (C/C++)
mix.lockHex (Elixir)

Guided remediation (osv-scanner fix)

# Interactive mode: suggests minimal version bumps
osv-scanner fix --lockfile package-lock.json

# Non-interactive: apply fixes automatically
osv-scanner fix --lockfile package-lock.json --non-interactive

# Preview only (no changes)
osv-scanner fix --lockfile package-lock.json --dry-run

# Fix for specific ecosystem
osv-scanner fix --lockfile go.sum

# Fix with Maven/Gradle (requires Java build tool)
osv-scanner fix --lockfile pom.xml

Call graph analysis (experimental)

# Reduces false positives by checking if vulnerable code is reachable
# Supported: Go, Rust (Cargo)

# Go call graph analysis
osv-scanner scan --experimental-call-analysis --lockfile go.sum

# Combined with directory scan
osv-scanner scan --experimental-call-analysis --dir ./mygoapp/

# The output marks each vuln as:
# CALLED / UNCALLED / UNKNOWN

Git repository scanning

# Scan entire git history for lockfiles at past commits
osv-scanner scan --recursive --git .

# Scan at a specific commit hash
osv-scanner scan --git-commit 9f8e7d6c .

# Scan between commits (find when a vuln was introduced)
osv-scanner scan --git-commit HEAD~50 --lockfile go.sum

Container image scanning

# Scan a Docker image (pulls if not cached)
osv-scanner scan --docker alpine:3.19
osv-scanner scan --docker nginx:latest
osv-scanner scan --docker myapp:production

# Save image and scan tarball
docker save myapp:latest | osv-scanner scan --docker -

SBOM scanning

# CycloneDX JSON
osv-scanner scan --sbom bom.json

# SPDX JSON
osv-scanner scan --sbom sbom.spdx.json

# SPDX TV format
osv-scanner scan --sbom sbom.spdx

# Generate SBOM with Syft then scan
syft myapp:latest -o cyclonedx-json > sbom.json
osv-scanner scan --sbom sbom.json

Output formats

# Default table output
osv-scanner scan --lockfile go.sum

# JSON (detailed, machine-readable)
osv-scanner scan -f json --lockfile go.sum | jq '.results[].packages[].vulnerabilities[]'

# SARIF (GitHub Code Scanning / Azure DevOps)
osv-scanner scan -f sarif --lockfile go.sum > osv-results.sarif

# Markdown (for PR comments)
osv-scanner scan -f markdown --lockfile go.sum

# Vertical (compact human-readable)
osv-scanner scan -f vertical --lockfile go.sum

Offline mode

# Download vulnerability database for offline use
osv-scanner download-vulns --dir ./vuln-db/

# Scan in offline mode with local DB
osv-scanner scan --offline --local-db-path ./vuln-db/ --lockfile go.sum

# Useful for air-gapped CI environments

License compliance

# Report all licenses found
osv-scanner scan --licenses-summary --lockfile package-lock.json

# Block on disallowed licenses (uses config allowlist)
osv-scanner scan --experimental-licenses --lockfile package-lock.json

# With config specifying allowed licenses
# See osv-scanner.toml [Licenses] section above

Common Workflows

GitHub Actions integration

name: OSV-Scanner
on:
  push:
    branches: [main]
  pull_request:
  schedule:
    - cron: '0 6 * * *'  # Daily at 6 AM

jobs:
  scan:
    runs-on: ubuntu-latest
    permissions:
      security-events: write  # Required for SARIF upload
      contents: read
    steps:
      - uses: actions/checkout@v4

      - name: Run OSV-Scanner
        uses: google/osv-scanner-action@v1
        with:
          scan-args: |-
            --recursive
            --format=sarif
            --output=results.sarif
            ./
        continue-on-error: true

      - name: Upload SARIF to GitHub
        uses: github/codeql-action/upload-sarif@v3
        with:
          sarif_file: results.sarif

PR diff scanning (only new vulns)

- name: OSV-Scanner PR diff
  uses: google/osv-scanner-action/osv-scanner-pr-action@v1
  with:
    scan-args: --recursive ./

Pre-commit hook

# .pre-commit-config.yaml
repos:
  - repo: https://github.com/google/osv-scanner
    rev: v1.7.0
    hooks:
      - id: osv-scanner
        args: ['--recursive', '.']

Multi-lockfile project scan

#!/bin/bash
# scan-all.sh
set -e

echo "Scanning Python dependencies..."
osv-scanner scan --lockfile poetry.lock

echo "Scanning Node dependencies..."
osv-scanner scan --lockfile package-lock.json

echo "Scanning Go dependencies..."
osv-scanner scan --lockfile go.sum

echo "All scans passed."

Comparing OSV-Scanner vs Grype vs Snyk

FeatureOSV-ScannerGrypeSnyk
CostFreeFreeFreemium
DatabaseOSV.dev (open)Anchore + NVDSnyk DB (proprietary)
Call graphYes (Go, Rust)NoYes (partial)
Guided fixYesNoYes
Container scanningYesYes (primary)Yes
SBOM inputYesYesYes
License checksYesNoYes
Offline supportYesYesNo
CI actionsOfficialVia AnchoreOfficial

Tips and Best Practices

Use --recursive for monorepos. A single osv-scanner scan --recursive . will discover and scan all lockfiles in the repository tree. Combine with --fail-on-vuln for CI gating.

Enable call graph analysis for Go and Rust. --experimental-call-analysis dramatically reduces false positives by only flagging vulnerabilities in code paths that are actually reachable. It is slower but highly recommended for Go services.

Use osv-scanner fix before opening a security PR. The guided remediation tells you the exact minimal version change to resolve each vulnerability, saving hours of manual dependency tree analysis.

Scan on every PR with diff mode. Use osv-scanner-pr-action to only alert on vulnerabilities introduced by the current PR, not existing baseline findings. This keeps PR checks relevant.

Set ignoreUntil on exceptions. When you accept a risk temporarily, always set an expiry date. This forces revisiting the decision and prevents forget-and-ignore accumulation.

Prefer lockfile scanning over manifest scanning. Scanning poetry.lock vs pyproject.toml gives exact versions rather than version ranges, resulting in far more accurate and actionable results.

Integrate with OSV.dev for deeper research. When a CVE appears, visit https://osv.dev/vulnerability/GO-2023-XXXX for full details, affected version ranges, and upstream patches.

Use SARIF in GitHub for code review context. SARIF output uploaded to GitHub Advanced Security shows vulnerabilities annotated on the relevant line of the lockfile in pull request diffs.