Dependency Scanning with govulncheck & SBOM
Go modules plus govulncheck give you a first-class supply-chain signal in CI, while SBOM export answers auditors and security teams asking what ships in each binary.
Search across all documentation pages
Go modules plus govulncheck give you a first-class supply-chain signal in CI, while SBOM export answers auditors and security teams asking what ships in each binary.
Treat vulnerability scanning as a gate, not a one-time checkbox.
Your service imports dozens of transitive modules.
The Go vulnerability database records CVEs affecting standard library and third-party packages.
govulncheck analyzes which imported symbols are actually reachable from your code and reports relevant findings.
SBOMs (Software Bill of Materials) list components and versions for compliance, license review, and faster incident triage when a new CVE lands.
Pair scanning with go mod tidy, pinned CI Go versions, and a patch SLA.
Quick-reference recipe card - copy-paste ready.
go install golang.org/x/vuln/cmd/govulncheck@latest
govulncheck ./...When to reach for this:
#!/usr/bin/env bash
set -euo pipefail
# CI job excerpt for example.com/myapi
export GOTOOLCHAIN=local
go version
go mod download
go mod verify
echo "== govulncheck =="
govulncheck -json ./... > govulncheck.json
# Fail on any finding in CI (tune with allowlist file if needed)
if jq -e '.finding | length > 0' govulncheck.json >/dev/null 2>&1; then
echo "vulnerabilities found"
jq '.finding' govulncheck.json
exit 1
fi
echo "== SBOM (CycloneDX) =="
go install github.com/CycloneDX/cyclonedx-gomod/cmd/cyclonedx-gomod@latest
cyclonedx-gomod mod -json -output sbom.json// main.go - minimal module for scanning demos
package main
import (
"encoding/json"
"net/http"
)
func main() {
http.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(map[string]string{"status": "ok"})
})
http.ListenAndServe(":8080", nil)
}What this demonstrates:
go mod verify confirms go.sum entries match downloaded modules.govulncheck -json output suitable for CI parsing and dashboards.go mod resolves require directives into a module graph recorded in go.sum.GOPROXY) serve zip hashes; tampering breaks verification.govulncheck performs static analysis to see if vulnerable functions are called from your packages, reducing noise versus naive CVE scanners.cyclonedx-gomod, syft) emit JSON listing modules, versions, and hashes for attachment to container images or release pages.go.mod commit baked into the image tag.| Stage | Command | Purpose |
|---|---|---|
| Verify | go mod verify | Detect sum tampering |
| Tidy check | go mod tidy diff fail | Prevent drift |
| Vuln scan | govulncheck ./... | CVE signal |
| SBOM | cyclonedx-gomod mod | Compliance artifact |
| Build | go build -trimpath | Reproducible binary |
| Severity | Action |
|---|---|
| Reachable stdlib CVE | Bump Go patch release in CI image |
| Reachable module CVE | Upgrade module; run tests |
| Unreachable finding | Document false positive; re-check on upgrades |
| No fix yet | Track exception with expiry; mitigate if possible |
# Pin toolchain in go.mod for reproducible CI
# go.mod line: go 1.26
# Private modules
export GOPRIVATE=github.com/myorg/*
export GONOSUMDB=github.com/myorg/*./... at package level.go.sum.replace bypasses normal provenance; review like first-party code.govulncheck may report no reachable vulns on an old version until symbols change; still bump per release policy.
| Alternative | Use When | Don't Use When |
|---|---|---|
| GitHub Dependabot / Renovate | Automated bump PRs | You lack CI tests to validate bumps |
| Container scanners (Trivy, Grype) | Image OS packages plus binary layers | Substitute for Go-specific reachability analysis |
| Snyk / commercial SCA | Enterprise policy dashboards | Budget or air-gapped builds block SaaS |
go list -m all manual review | Tiny modules | Large graphs need automation |
On every pull request and release build at minimum.
Nightly scheduled runs catch new CVEs published after your last merge.
No.
It reports findings; you bump versions with go get -u or targeted go get module@patch.
Reachable means your code imports and calls a vulnerable symbol.
Unreachable findings may still warrant upgrades but are lower priority.
Yes for complete transparency.
CycloneDX gomod includes module dependencies; document Go toolchain version separately in release metadata.
govulncheck analyzes your code graph; private module code is included.
Vulnerability data comes from the public Go VulnDB for public modules and stdlib.
Document risk acceptance with owner, reason, and expiry date.
Re-scan weekly; remove allowlist when fix is released.
Run govulncheck against the same packages; vendored code is what compiles.
Keep vendor/ synced with go mod vendor in CI.
Match go directive in go.mod and patch level your security policy requires.
Use GOTOOLCHAIN or container image pins for consistency.
When a new CVE drops, search SBOMs for affected component versions across services without re-scanning live clusters blindly.
SBOM lists components; license classification may need separate tools.
Still valuable for legal review of transitive deps.
Yes.
It enables reproducible builds and go mod verify for all collaborators and CI.
SBOM plus vuln scanning addresses known vulnerable components (CWE-1104).
Pair with signed commits, protected branches, and minimal dependency policy.
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 at build).
Reviewed by Chris St. John·Last updated Jul 19, 2026