| name | supply-chain-secure-install |
| description | Use when adding, updating, or auditing Go module dependencies. Provides supply chain attack countermeasures including go.sum verification, GOPROXY hardening, govulncheck auditing, and CI/CD pipeline security. Adapted from Shai-Hulud npm attack lessons. |
| allowed-tools | Read, Write, Edit, Bash, Grep, Glob |
| user-invocable | true |
Supply Chain Secure Install (Go Modules)
This skill provides comprehensive defense-in-depth guidelines for safe dependency management with Go modules, adapted from lessons learned from the Shai-Hulud npm supply chain attacks (2025). While Go's module system is inherently more secure than npm's, supply chain attacks targeting Go have occurred and the same principles apply.
When to Apply
Apply these guidelines when:
- Adding new dependencies (
go get)
- Updating existing dependencies (
go get -u)
- Setting up CI/CD pipelines
- Auditing current project dependency security posture
- Reviewing pull requests that modify
go.mod or go.sum
Go vs npm: Built-in Security Advantages
Go modules have significant structural advantages over npm that mitigate Shai-Hulud-style attacks:
| Feature | npm (Shai-Hulud vector) | Go Modules |
|---|
| Lifecycle scripts | preinstall/postinstall execute arbitrary code | No equivalent - no code runs on go get |
| Dependency resolution | Mutable versions, can overwrite | Immutable - module versions are append-only |
| Integrity verification | Optional (package-lock.json) | Mandatory - go.sum checksums verified against sumdb |
| Global checksum DB | None | sum.golang.org - tamper-evident checksum database |
| Module proxy | npm registry (single point) | GOPROXY - cacheable, verifiable proxy layer |
However, Go is NOT immune. Attack vectors include:
go generate directives executing arbitrary commands
- Build-time code (cgo, compiler plugins)
- Malicious code in imported packages that executes at runtime
- Typosquatting on module paths
- Compromised module proxy or VCS accounts
go.sum Integrity Verification
How It Works
Every module version fetched is checksummed and recorded in go.sum. Before using any module, Go verifies:
- The module content matches the hash in
go.sum
- The hash matches the global checksum database (sum.golang.org)
Mandatory Practices
git add go.mod go.sum
go mod verify
go mod download
go mod verify
GONOSUMCHECK / GONOSUMDB
GONOSUMCHECK=* go get example.com/pkg
GONOSUMCHECK=private.company.com/* go get private.company.com/internal/pkg
GONOSUMDB=private.company.com/*
GOPROXY Hardening
Default Configuration
GOPROXY=https://proxy.golang.org,direct
GOPROXY=https://your-private-proxy.example.com,https://proxy.golang.org,direct
Private Proxy Benefits
| Benefit | Description |
|---|
| Caching | Modules cached even if upstream is deleted |
| Auditing | Log all module fetches |
| Allowlisting | Restrict which modules can be fetched |
| Scanning | Integrate vulnerability scanning |
Options: Athens, Artifactory, Nexus
GOFLAGS for Default Security
export GOFLAGS="-mod=readonly"
go generate Security
go generate is Go's equivalent of npm lifecycle scripts -- it can execute arbitrary commands.
Threat: Malicious go:generate Directives
Defense
- NEVER run
go generate on untrusted code
- Review
go:generate directives in new dependencies:
grep -r "//go:generate" vendor/ 2>/dev/null
grep -r "//go:generate" $(go env GOMODCACHE) 2>/dev/null
- In CI: separate generate from build
steps:
- name: Build (no generate)
run: go build ./...
Dependency Audit
govulncheck (Mandatory)
go install golang.org/x/vuln/cmd/govulncheck@latest
govulncheck ./...
- name: Vulnerability check
run: govulncheck ./...
Pre-Install Dependency Review
Before go get <module>:
go doc <module>
govulncheck -test ./...
go mod graph | grep <module>
Red Flags During Review
| Red Flag | Risk |
|---|
| Module not on pkg.go.dev | Unverified, possibly malicious |
| Very few importers | Potential typosquatting |
| Recent repository transfer | Possible account takeover |
Contains go:generate directives | Arbitrary code execution |
| Uses cgo extensively | Native code can bypass Go safety |
Imports os/exec or net/http | May exfiltrate data or execute commands |
| replace directives in go.mod | May redirect to malicious modules |
CI/CD Pipeline Security
Secure Go Build in CI
jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: read
timeout-minutes: 15
steps:
- uses: actions/checkout@<SHA>
with:
persist-credentials: false
- uses: actions/setup-go@<SHA>
with:
go-version-file: go.mod
- name: Verify modules
run: go mod verify
- name: Vulnerability check
run: |
go install golang.org/x/vuln/cmd/govulncheck@latest
govulncheck ./...
- name: Build
env:
GOFLAGS: "-mod=readonly"
run: go build ./...
- name: Test
run: go test ./...
Environment Variable Protection
steps:
- name: Download modules
env:
GOPRIVATE: private.company.com/*
run: go mod download
- name: Build (no secrets needed)
run: go build ./...
Periodic Audit Checklist
govulncheck ./...
go mod verify
go mod tidy
git diff go.mod go.sum
go list -m all
go list -m -u all
Emergency Response: Suspected Compromise
- Do NOT run
go generate on the affected project
- Check go.sum for unexpected hash changes
- Run
go mod verify to check integrity
- Run
govulncheck to check for known vulnerabilities
- Pin to a known-good version in go.mod with exact version
- Rotate credentials if malicious code may have executed
- Report to the Go security team and module maintainers
Post-Compromise Detection
grep -r "//go:generate" $(go env GOMODCACHE) 2>/dev/null | head -50
grep -r "os/exec\|net/http\|io/ioutil" $(go env GOMODCACHE) 2>/dev/null | \
grep -v "_test.go" | head -50
go mod verify
grep "replace" go.mod
References