Introduction

Go's module system verifies downloaded modules against hashes stored in go.sum. When the downloaded module's hash does not match the expected hash in go.sum, Go refuses to use it. This protects against supply chain attacks but can also break legitimate builds when modules are republished (which should not happen but does in practice), when the proxy serves different content, or when go.sum is out of sync.

Symptoms

  • go: github.com/example/lib@v1.2.3: checksum mismatch
  • verifying github.com/example/lib@v1.2.3: checksum mismatch
  • security: checksum mismatch for github.com/example/lib
  • Build works on one machine but fails on another
  • CI fails after developer updates go.mod but not go.sum

``` go: github.com/example/lib@v1.2.3: verifying module: checksum mismatch downloaded: h1:abc123def456... go.sum: h1:xyz789ghi012...

SECURITY ERROR This download does NOT match the one recorded in go.sum. The download may have been tampered with. ```

Common Causes

  • go.sum not committed to version control
  • Module author republished a version (violates Go module immutability)
  • GOPROXY returning different content than direct download
  • Switching between GOPROXY and direct fetching
  • Private modules not in the sum database
  • go.mod updated but go.sum not regenerated

Step-by-Step Fix

  1. 1.Regenerate go.sum from scratch:
  2. 2.```bash
  3. 3.# Remove existing sum file
  4. 4.rm go.sum

# Re-download and regenerate go mod download go mod verify

# Or in one step go mod tidy ```

  1. 1.Configure GONOSUMCHECK for private modules:
  2. 2.```bash
  3. 3.# Skip checksum verification for private repos
  4. 4.go env -w GONOSUMCHECK="github.com/myorg/*,gitlab.com/company/*"

# Or combined with GOPRIVATE go env -w GOPRIVATE="github.com/myorg/*" # This automatically sets GONOSUMCHECK and GONOSUMDB ```

  1. 1.Use consistent GOPROXY across all environments:
  2. 2.```bash
  3. 3.# Set proxy explicitly
  4. 4.go env -w GOPROXY="https://proxy.golang.org,direct"

# Or use corporate proxy go env -w GOPROXY="https://artifactory.company.com/api/go/go-proxy,https://proxy.golang.org,direct" ```

  1. 1.Verify module integrity:
  2. 2.```bash
  3. 3.# Verify all modules against go.sum
  4. 4.go mod verify

# Shows: all modules verified # Or: github.com/example/lib@v1.2.3: tampered check

# Check specific module go list -m -json github.com/example/lib@v1.2.3 ```

  1. 1.Handle module republishing (rare):
  2. 2.```bash
  3. 3.# If a module was legitimately republished by the author
  4. 4.# Update to a new version instead
  5. 5.go get github.com/example/lib@v1.2.4

# Or if you must use the republished version rm go.sum go mod tidy # Commit the new go.sum ```

Prevention

  • Always commit go.sum to version control
  • Run go mod tidy before committing dependency changes
  • Use go mod verify in CI pipeline as a security check
  • Pin dependency versions to specific commits if needed:
  • ```bash
  • go get github.com/example/lib@abc123def
  • `
  • Use GOPROXY consistently across development and CI
  • For private modules, always set GOPRIVATE to skip sum checks
  • Monitor go mod verify output in CI for supply chain integrity