govulncheck for Dependency Vulnerabilities
govulncheck scans Go modules against the Go vulnerability database and reports whether known security issues affect packages and symbols your code actually uses.
Summary
Dependency alerts from generic bots can flood teams with CVEs on modules you never call into vulnerable APIs.
govulncheck narrows signal by analyzing module versions, import paths, and static reachability where possible.
Run it locally before release and in CI on every push so upgrades and transitive bumps are caught early.
Recipe
Quick-reference recipe card - copy-paste ready.
go install golang.org/x/vuln/cmd/govulncheck@latest
# Scan all packages in the module
govulncheck ./...
# JSON for automation
govulncheck -json ./... > vuln-report.json
# Show only vulnerable symbols called from your code
govulncheck -show verbose ./...When to reach for this:
- Before tagging a release or promoting a container image.
- After
go get -u ./...or Dependabot PRs touchinggo.sum. - In CI as a non-optional check after
go test. - When security asks "are we affected by CVE-YYYY-NNNN?"
Working Example
// example.com/demo/cmd/api/main.go
package main
import (
"log"
"net/http"
"golang.org/x/text/language"
)
func main() {
tag, _ := language.Parse("en")
http.HandleFunc("/lang", func(w http.ResponseWriter, r *http.Request) {
_, _ = w.Write([]byte(tag.String()))
})
log.Fatal(http.ListenAndServe(":8080", nil))
}govulncheck ./...Example output shape (IDs and versions vary over time):
Vulnerability #1: GO-2024-0001
Module: golang.org/x/text
Found in: golang.org/x/text@v0.3.0
Fixed in: golang.org/x/text@v0.14.0
Symbol: language.Parse
Trace: cmd/api/main.go:12:22 -> language.Parse
Upgrade path:
go get golang.org/x/text@v0.14.0
go mod tidy
govulncheck ./...What this demonstrates:
- govulncheck names the module, vulnerable version, fixed version, and symbol.
- A trace ties the symbol to your source line.
- Bumping the module and re-running confirms remediation.
Deep Dive
How It Works
- Downloads vulnerability entries curated for Go modules (OSV-compatible records).
- Loads your module graph from
go.mod/go.sum. - Type-checks and analyzes packages to determine reachability of vulnerable symbols.
- Reports findings with severity metadata when available from the database.
CLI Modes
| Flag / mode | Purpose |
|---|---|
./... | Standard scan of all packages under module |
-json | Machine-readable output for CI dashboards |
-mode=binary | Scan a compiled binary (supply-chain audits) |
-show=traces | Emphasize call paths into vulnerable code |
CI Integration
# excerpt - GitHub Actions style
- run: go install golang.org/x/vuln/cmd/govulncheck@latest
- run: govulncheck ./...Pin the govulncheck version in CI docs when reproducibility matters.
Fail the job on any finding until triaged; use -json upload for security ticketing.
Triage Workflow
- Confirm reachability - Read the trace; library-only presence may still warrant upgrade.
- Check fixed version - Prefer minor/patch bumps compatible with your
godirective. - Run tests after
go geton the patched version. - Document exceptions rarely - if a finding is a false positive, file upstream and record ADR; do not silence without review.
Go Notes
# Private modules need the same GOPRIVATE settings as go build
export GOPRIVATE=example.com/*
govulncheck ./...govulncheck respects module proxy and checksum settings from your environment.
Gotchas
- Ignoring all CVEs because "not exploitable" - Reachability lowers noise but upgrades are still cheap insurance. Fix: Bump to fixed versions unless blocked, then record risk acceptance.
- Only running on default branch - Vulnerable deps land on feature branches first. Fix: Run govulncheck on every PR in CI.
- Stale
go.sum- Incomplete sums break module loading. Fix:go mod tidybefore scan. - Vendor directory drift - Vendored copies may lag
go.mod. Fix: Regenerate vendor after upgrades or scan with-mod=readonlyconsistent with CI. - Binary scan without sources -
-mode=binaryhelps ops teams but traces are thinner. Fix: Keep source-linked scans in developer CI; use binary mode for release artifacts. - Assuming green govulncheck means secure code - It only covers known module CVEs, not your SQL strings or auth bugs. Fix: Pair with gosec, code review, and penetration testing.
Alternatives
| Alternative | Use When | Don't Use When |
|---|---|---|
| GitHub Dependabot | Broad ecosystem alerts across repos | You need Go-specific reachability traces |
npm audit style generic scanners | Polyglot monorepos | Primary signal for Go modules (prefer govulncheck) |
| Manual CVE mailing lists | Zero tooling allowed | Normal Go service development |
gopls vulncheck integration | Quick editor glance | Authoritative CI gate (use CLI in pipeline) |
FAQs
Does govulncheck phone home with my source code?
It fetches vulnerability data and analyzes locally checked packages.
It does not upload your source to a third party as part of the default CLI workflow.
What if no fixed version exists yet?
Document the risk, mitigate with configuration (disable feature), or fork/replace the dependency.
Re-scan when the database updates.
Should govulncheck fail CI on indirect dependencies?
Yes, if the vulnerable symbol is reachable.
Upgrade the direct dep that pulls the transitive module, or bump the transitive explicitly.
How often does the vulnerability database update?
Continuously as maintainers and the Go security team publish entries.
CI on each push picks up new entries automatically.
Can I scan old Go versions?
govulncheck requires a recent Go toolchain to build its analysis.
Your module may still target older go directives; upgrade the toolchain used in CI.
Does vendoring affect results?
govulncheck analyzes the module graph you present.
Keep vendor in sync with go.mod or scan without stale vendor copies.
What is the difference versus gosec?
govulncheck matches known CVEs in dependencies.
gosec flags dangerous patterns in your hand-written code.
Can I suppress a finding?
There is no durable per-CVE ignore flag meant for long-term silence.
Prefer upgrading; engage security review for exceptions.
Does it work with private modules?
Yes, with GOPRIVATE and credentials configured like go build.
Should I pin govulncheck in CI?
Pinning documents the scanner version for audits.
@latest is fine for small teams if CI logs print the installed version each run.
Related
- Go Tooling Setup Basics - install govulncheck
- gosec & nilaway for Security and Nil Safety - static rules in your code
- staticcheck & golangci-lint in CI - other CI quality gates
- gopls & Analysis Tooling Best Practices - security tooling hygiene
Stack versions: This page was written for Go 1.26.x (Green Tea GC default, go fix modernizers - verify patch at build), chi (latest - verify at build), gin (latest - verify at build), echo (latest - verify at build), google.golang.org/grpc (latest - verify at build), sigs.k8s.io/controller-runtime (latest - verify at build), kubebuilder (latest - verify at build), tinygo (latest - verify board targets at build), wazero (latest - verify at build), and golangci-lint (latest - verify linter set at build).