| name | cve-fix |
| description | Unbreak CI when the required govulncheck check goes red on every PR because of a new Go stdlib CVE — bump the go directive in go.mod to the fixed version (single-sourced into all workflows), verify locally, ship as a standalone auto-merged PR, then re-run the blocked PRs' checks. Also handles the dependency-CVE variant. Use when govulncheck fails in CI or locally, a Go security release / stdlib CVE lands, or PRs are suddenly all red on the govulncheck check. |
Fix a govulncheck CVE failure (stdlib or dependency)
govulncheck is a required check (.github/workflows/go.yml) on every PR.
A new CVE in the Go stdlib turns it red on ALL open PRs at once, regardless
of their diffs — that all-red wall is the signature of this situation, not a
sign that anyone's change broke something. The fix is one line; ship it first
and standalone, because it unblocks everything else.
STEP 1 — Diagnose: reproduce locally and read the report
command -v govulncheck || go install golang.org/x/vuln/cmd/govulncheck@latest
export PATH="$(go env GOPATH)/bin:$PATH"
govulncheck ./...
From the report note: the vuln id (GO-YYYY-NNNN), the affected package, and
the "Fixed in" version. Distinguish the two cases:
- Module
std / "Standard library" → the fix is the go.mod toolchain bump
(STEP 2). Example (2026-07-09): GO-2026-5856 in crypto/tls, fixed in
go1.26.5 → PR #116 bumped go 1.26.4 → 1.26.5.
- A dependency module →
go get <module>@<fixed-version> && go mod tidy
instead; if no fixed release exists yet, check whether our code actually
calls the vulnerable symbols (govulncheck already filters by reachability —
a finding means they ARE reached) and treat it as a real issue, not a bump.
If govulncheck is red for a non-CVE reason (network, tool install), that is an
environment problem — fix the environment, don't touch go.mod.
STEP 2 — The fix: bump the go directive in go.mod
The Go version is single-sourced in go.mod: every workflow
(go.yml build + govulncheck, docs.yml check, release.yml both jobs) uses
go-version-file: go.mod, so this one line updates the toolchain everywhere.
Do NOT touch the workflows.
# go.mod: go 1.X.Y → the "Fixed in" version from the report
Branch first (fix/go-1.X.Y-<vuln-id>), then edit. Keep the PR to exactly
this: the go.mod line (plus go.sum/tidy fallout for the dependency case) and a
### Internal bullet under ## [Unreleased] in docs/CHANGELOG.md
("toolchain to go1.X.Y for GO-YYYY-NNNN"). No drive-bys — this PR must merge
fast.
STEP 3 — Verify with the NEW toolchain
GOTOOLCHAIN=go1.X.Y go build ./... && GOTOOLCHAIN=go1.X.Y go vet ./...
GOTOOLCHAIN=go1.X.Y go test -race ./...
GOTOOLCHAIN=go1.X.Y govulncheck ./... # must come back clean
GOTOOLCHAIN downloads the patched toolchain if it isn't installed. Then the
full gate as usual (export PATH="$PWD/.venv/bin:$(go env GOPATH)/bin:$PATH"
and /usr/bin/make verify — plain make is a broken zsh stub on this
machine).
STEP 4 — PR, auto-merge, unblock the rest
- Commit:
fix: bump Go to 1.X.Y for GO-YYYY-NNNN (<package>) — body: what the
CVE is, reachability note, what was verified. No attribution trailers.
- No issue is required first — this is a CI break; the PR body carries the vuln
id. If a tracking issue or Dependabot alert exists, reference it (closing
keyword only if this PR fully resolves it).
gh pr create → gh pr merge <n> --squash --auto --delete-branch. If the
auto-mode guardrail denies the self-merge, ask the user to authorize — this
is the one PR where a quick "merge it" matters, say so.
- After it lands on
main: the other open PRs stay red until their checks
re-run against the new merge ref — gh run rerun <run-id> --failed (or ask
Dependabot PRs to @dependabot rebase). Confirm at least one goes green.
- If several PRs each carried the same bump, they de-dupe cleanly on merge —
identical one-line change, no conflict.
Guardrails
- The bump goes UP to the fixed version — never sideways or down, and never
pin
GOTOOLCHAIN in the repo to mask the failure.
- Never make govulncheck pass by removing it from
make verify/CI or by
filtering its output.
- One CVE fix per PR; nothing else rides along.