What does `go mod verify` actually check, and what does a passing result not prove?
answer
- it never opens a network connection
- the module cache is the subject
- recomputes hashes recorded at download time
- silent about trust and vulnerabilities
basics
~20 sgo mod verify recomputes hashes of the dependencies in your local module cache and compares them with the hashes recorded at download time. It proves nobody edited the cache since; it does not re-download, contact the checksum database, or find vulnerabilities.
solid answer
~50 s`go mod verify` is a local integrity check over the module cache, not a network check. For every module the main module depends on it recomputes the hash of the cached zip and of the extracted source tree, compares them with the hashes recorded in the cache at download time, and prints `all modules verified` if everything matches; otherwise it names the module, says the zip or dir has been modified, and exits non-zero. What it proves is narrow: the dependency source on this machine is byte-identical to what arrived. It does not re-fetch the module, does not consult `sum.golang.org`, does not tell you the code is safe, and does not scan for known vulnerabilities. It earns its keep where a module cache is long-lived or shared — a self-hosted runner, a pre-warmed build image, a mirror host in an isolated network — because that cache is an ordinary writable directory that a stray tool or a compromised job can rewrite.
code
text · 6 lines$ go mod verify
all modules verified
$ go mod verify
example.internal/lib v1.4.2: dir has been modified
example.internal/lib v1.4.2: zip has been modifiedgo deeper
Be ready to say in one sentence that go mod verify is an offline check of the local module cache against hashes recorded at download time, and that it prints all modules verified when nothing changed.
Explain the mechanics: which two artefacts are hashed (the cached zip and the extracted source tree), where those recorded hashes come from, and why an ordinary build already checks hashes without this command.
Show the operational judgment — name the situations where a cache lives long enough to be worth verifying, such as self-hosted runners and pre-warmed images, and describe the right response to a failure rather than a retry.
Own the question of where in the build platform this check belongs and what it is worth: whether every job pays for it, whether caches should instead be ephemeral, and what residual risk you are accepting either way.
## What the command does `go mod verify` looks at the modules the current main module depends on, finds their downloaded copies in the local module cache (the directory `go env GOMODCACHE` reports, `$GOPATH/pkg/mod` by default), recomputes cryptographic hashes over them, and compares those against the hashes that were recorded in the cache when the modules were first downloaded. If everything matches it prints `all modules verified` and exits 0. If something does not match it names the offending module, says that its zip or its extracted directory has been modified, and exits non-zero. ## What "modified" means here A module version normally lives in the cache twice: as the original `.zip` archive the proxy or origin served, and as a read-only extracted source tree that the compiler actually reads. Next to them the cache keeps the hash that was computed at download time — the same hash that was checked against `go.sum` then, and (unless the module path was exempted) against the checksum database. `go mod verify` re-derives both hashes and compares them with those recorded values. So the property it establishes is *local* integrity: nothing on this machine has altered a dependency's source since it arrived. ## The four things it does not do 1. **No network.** It does not re-download the module, does not ask a proxy, and does not consult `sum.golang.org`. Delete the cache and it has nothing left to check. 2. **No trust judgement.** It says the bytes are still the same bytes. It says nothing about whether those bytes deserved trust in the first place. If the very first download was already hostile, `go mod verify` will cheerfully confirm the hostile copy is intact. 3. **No vulnerability scanning.** A dependency with a published advisory verifies perfectly. 4. **It is not the check that protects an ordinary build.** Every normal `go build` or `go test` already verifies a module's hash against `go.sum` at download time. `go mod verify` is the *after the fact* check on what is already on disk. ## Why it exists Because module caches outlive builds. A self-hosted CI runner keeps `GOMODCACHE` between jobs; a build image ships with a pre-warmed cache; a mirror host in a network with no direct egress may populate its cache once and reuse it for months. That cache is a plain directory. Its files are written read-only, but nothing cryptographic stops a process running as the same user — a rogue `go:generate` step, a test that writes outside its temp dir, a compromised job on a shared runner — from rewriting a dependency's source between the download that verified it and the build that compiles it. `go mod verify` is the cheap periodic check for exactly that window, and it is why running it on a shared runner is worth the seconds it costs. ## Reading a failure The two failure shapes carry different information. If the *extracted directory* differs while the zip still matches, something rewrote the source tree in place — an editor, a script, a code generator pointed at the wrong path. If the *zip itself* differs, the cache entry was replaced wholesale. Neither is proof of an attack, but both mean the build you just ran did not compile the source you believe it compiled. The right response is to delete the affected cache entry (or the whole cache) and re-download so the hashes are checked again on the way in — never to record the new hash as the expected one. ## How it sits next to the other integrity mechanisms Three different guarantees are easy to conflate: - **`go.sum`** records the hashes your project expects, and is checked on every download. It is the file a reviewer reads in a diff. - **The checksum database** is the outside opinion consulted the *first* time a hash is about to be written into `go.sum`, so that your first sight of a module is not automatically trusted. - **`go mod verify`** is the local check that what is on disk now still matches what was recorded then. A candidate who can separate those three has the model right. A candidate who says `go mod verify` "checks the dependencies against upstream" has merged all three into one, and will reach for the wrong tool during an incident.
- Given ordinary builds already check hashes at download time, when is running go mod verify in CI actually worth it?When the module cache is long-lived or shared rather than fresh per job: a self-hosted runner that keeps `GOMODCACHE` between builds, a cache restored from an artifact store, a pre-warmed build image, or a mirror host in an isolated network that populated its cache months ago. In all of those the window between "downloaded and hash-checked" and "compiled" is long and writable, which is precisely what `go mod verify` closes.
- go mod verify passes, but you still suspect a dependency was swapped. What would you do next?Verify only proves the cache matches what was recorded there, so if the poisoning happened before or during the original download it is invisible. Wipe the cache with `go clean -modcache`, re-download on a machine where the checksum database is reachable, and see whether the hashes the go command writes still agree with the `go.sum` in the repository. A disagreement at that point is the real signal.
- What does it mean when go mod verify reports that a module's dir has been modified but its zip has not?The archive that was downloaded is intact, but the extracted source tree that the compiler reads was edited in place after extraction — typically by a tool or script writing into `GOMODCACHE` rather than by anything malicious. The build you just ran did not compile the published source, so delete that cache entry and re-extract instead of ignoring it.
saying these in an interview costs you the question
- Says go mod verify contacts sum.golang.org or the proxy
- Thinks it scans dependencies for known vulnerabilities
- Claims a clean run proves a dependency is safe to import
- Believes it re-downloads modules and diffs them against upstream
- Fixes a failure by re-recording the new hash instead of re-downloading