Yes, whenever someone other than the current job could have written or changed the cache. Verify after restore and before build: Go has a verify command, pip has hash checking mode, and npm's strict install follows the lockfile. A cache is a convenience, not a source of truth.
The question behind the question
A cache stores bytes from an earlier time. Between then and now, those bytes may have changed because of a bug, a poisoned write, a disk problem or a compromised job. The build cannot tell by looking. Re-verifying compares the cached bytes with a record you trust, such as a hash from a lockfile or checksum database.
What each ecosystem offers
Go. The Go modules reference says go mod verify checks that dependencies in the module cache have not been modified since they were downloaded. It hashes each downloaded module archive and its extracted directory and compares them with a hash recorded when the module was first downloaded. If every module is unmodified it prints a success message. Otherwise it reports which modules changed and exits with a non-zero status. The reference also notes that module aware commands verify that hashes in the main module's go.sum match the downloaded content.
pip. The pip secure installs documentation describes hash checking mode, which uses hashes embedded in a requirements file to protect against remote tampering and network issues. It is all or nothing: if any requirement has a hash, hashes are required for all of them, and requirements must be pinned. The documentation suggests pairing it with a ban on source distributions so that no build step runs unchecked code. A package taken from a local wheel cache must still match.
npm. The npm ci documentation says the command needs an existing lockfile, exits with an error if the lockfile and package.json do not match, and removes an existing node_modules before installing. It does not rewrite the lockfile. That means a restored node_modules tree is thrown away and rebuilt from the cache and lockfile, which is why caching the download cache is safer than caching an installed tree.
Where to place the check
| Ecosystem | Check | When |
|---|---|---|
| Go | Run the verify command | After restoring the module cache, before build |
| pip | Install with the require hashes option | Every install, including from a wheel cache |
| npm | Use the strict install command | Every install, from the lockfile |
Fail the job on any mismatch. A warning no one reads is worse than a broken build.
When a check fails
- Do not retry blindly. A mismatch may mean the cache changed, not that the network flaked.
- Delete that cache and rebuild from the mirror, then compare. The procedure is in purge CI caches after a compromise.
- Look at who wrote the cache. If a pull request job could write it, tighten the rule. See can fork pull requests poison your GitHub Actions cache.
- Search for the same package version across your other repositories and images. See find a compromised package version across repos, images and caches.
What verification does not prove
A hash match proves the bytes are the same as before. It does not prove the package was safe in the first place. If a malicious version was cached and hashed, it verifies perfectly. Pair verification with scanning and with release delay policies such as those in minimum release age policies.
Where Safeguard fits
Hash checks protect integrity. Safeguard's dependency scanning, zero-day discovery and reachability analysis address whether the packages themselves are a problem, and policies and gates can block a build on the result.
Quick check
If the hash matches, is the package safe?
No. It only means the bytes are unchanged. A package that was already malicious would match its own hash.
Is verifying every build too slow?
Hash checks are usually cheap compared with the download itself. Measure on your own project before assuming otherwise.
Sources
Last reviewed: 19 October 2026.