goprivaudit
Audits a Go module's GOPRIVATE/GONOSUMDB configuration against its go.mod dependencies and its private-module auth setup — git insteadOf rewrites, git credential helpers, URL-scoped extra HTTP headers, and netrc credentials — catching two silent misconfigurations around private Go modules:
- Sumdb leaks. If you've set up a git insteadOf rewrite, a git
credential helper, a URL-scoped http.<url.extraHeader, or netrc credentials to authenticate go get to a private host, but forgot to add that module's path to GOPRIVATE/GONOSUMDB, the go command still queries the public checksum database (sum.golang.org) for it on every build. The source fetch is private; the module's existence, path, and version are not — they leak to Google's sumdb regardless.
- Overly broad patterns. A bare GOPRIVATE= (or GONOSUMDB=)
"fixes" the leak above but also disables checksum verification for every public dependency in the module, silently removing supply-chain protection you almost certainly still want.
It makes no network calls. Everything it checks — go.mod, git config, the netrc file, go env output — is local.
Both checks are skipped (reported clean) when GOSUMDB=off: that setting disables the checksum database entirely, for every module, so neither finding can apply — there's no sumdb query happening for anything to leak from or over-trust.
GOPROXY=off (or any GOPROXY chain shape) is deliberately not treated as a reason to skip either check, even though it might look like the same "cannot leak" case as GOSUMDB=off/vendor mode above. Verified live: with GOPROXY=off, GOSUMDB left at its default, and a required module's exact pinned version already sitting in the local module cache (an entirely ordinary state — e.g. a shared $GOMODCACHE warmed by an earlier, online CI stage) but not yet recorded in go.sum, a real GOFLAGS=-mod=mod go build still sent a genuine /lookup/<module@<version request straight to GOSUMDB's configured URL — bypassing GOPROXY entirely, since go's sumdb client falls back to a direct connection the moment every proxy in the chain reports "off"/"direct". GOPROXY=off only prevents the leak when the module isn't in the local cache at all yet, and this tool has no way to know the cache state — so treating it as a blanket "cannot leak" guarantee (an earlier release did) is unsafe precisely for the mainstream reason anyone sets GOPROXY=off in the first place: a network-locked-down build stage relying on an earlier online stage having already populated the cache.
Both checks are also skipped when the module resolves its dependencies from a committed vendor/ directory instead of the network — either because vendor/modules.txt exists next to go.mod and the module's go directive is 1.14 or higher (the go command's own auto-vendor default; see go help modules), or because -mod=vendor is set explicitly via GOFLAGS. Verified live: a vendor-mode build succeeds even with GOPROXY unreachable and GOSUMDB left at its default, so there's no sumdb query happening in that mode either. An explicit -mod=mod/-mod=readonly in GOFLAGS overrides the vendor auto-default back to the normal network-resolving path, and goprivaudit follows that override too. The auto-default does NOT apply inside an active Go workspace — verified live, a per-module vendor/ directory that would auto-vendor on its own is silently ignored the moment GOWORK points at a real workspace file, and go build reaches the network exactly as if no vendor/ existed. Workspace vendoring is a separate, opt-in mechanism (go work vendor, one vendor/ at the workspace root, always paired with an explicit -mod=vendor), which goprivaudit still honors as an explicit override either way.
If you hit "could not read Username" or "terminal prompts disabled"
That's the real go get error that sends most people looking for a GOPRIVATE/git insteadOf fix in the first place — the go tool tries the plain HTTPS path to a private module and there's no credential prompt available to satisfy it. Verified against a real private-looking module path with no auth configured:
go: github.com/experimental-gains-private-test/nonexistent-repo-for-repro@v0.1.0: invalid version: git ls-remote -q origin in /root/go/pkg/mod/cache/vcs/5c411848ac859bfd85ccfed9106f5f8e8633b853e482c574fe6c70398ee55132: exit status 128:
fatal: could not read Username for 'https://github.com': terminal prompts disabled
Confirm the import path was entered correctly.
If this is a private repository, see https://golang.org/doc/faq#git_https for additional information.The usual fix is a git insteadOf rewrite to fetch over SSH instead — which is exactly the setup goprivaudit audits. Getting the fetch working is only half the job: once insteadOf is in place, go can read the source, but it still checks the module's path and version against the public checksum database unless GOPRIVATE/GONOSUMDB also covers that path. goprivaudit catches the case where someone fixes the fetch error above and stops there.
Install
go install github.com/experimental-gains/goprivaudit@latestOr via Homebrew:
brew install experimental-gains/tap/goprivaudit