Repository navigation
fix(golang): require Go 1.26.10 so crypto/x509 blocks the eMudhra intermediates - #1302
Conversation
…ermediates Go 1.26.10 and 1.27.3 are the first releases whose crypto/x509 rejects chains through the eight compromised eMudhra intermediate CAs (CVE-2026-111943, golang/go#82345). A program built with an older toolchain would accept a chain through them, which would let the key holder impersonate ZeroKMS or the auth endpoints to the Go SDK. - languages/golang/go.mod: `go 1.26.0` -> `go 1.26.10`. The `go` line is the one directive a dependency's go.mod imposes on its consumers: `go get` raises the consumer's own `go` line to it, and GOTOOLCHAIN=auto then fetches a fixed toolchain. A `toolchain` directive is honoured only in the main module, so it would protect this repo's builds and nobody importing the SDK. - mise.toml: pin go to "1.26.10" rather than the floating "1.26", so CI (tests-golang.yml and release-golang.yml both resolve Go from this pin) and local builds cannot pick an older patch from a cache. - The encrypt and stashgen READMEs, encrypt/doc.go and AGENTS.md state the new minimum, and note that 1.27.0 to 1.27.2 are also vulnerable, which a minimum version cannot express. Closes #1300 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014Givi9JCPVy1s8ZL8oPo6D
|
cipherstash-agent
left a comment
There was a problem hiding this comment.
Review attestation: automated review by Claude Code (/code-review medium, then company-skills:cross-check-review-findings) at head 7b4ceef.
Result: no findings. No critical or blocking issues.
Checked against the head commit:
go.modraisesgoto 1.26.10, the right directive for a library. Atoolchainline would not reach importers.mise.tomlpinsgo = "1.26.10". Thesed -n 's/^go = "\(.*\)"/\1/p'step intests-golang.ymlstill matches it, andrelease-golang.ymltakes Go from the same pin.- No other docs or workflows name the old minimum. The remaining
go 1.26lines are thestashgen/testdatafixture modules andrefusal_test.go, which are not shipped. - No
skills/file mentions a Go version, and the Go module releases outside Changesets, so no changeset is needed. The changeset-bot warning can be ignored. - No existing human review feedback to cross-check. The only comments are bot notices.
Not verified: I could not independently confirm that 1.26.10 / 1.27.3 are the first releases with the eMudhra block (CVE-2026-111943 / golang/go#82345). That rests on the PR description.
Review source: Claude Code (automated). The scripted feedback fetch hit a GraphQL 403 here, so existing comments and reviews were read through the REST-backed GitHub tools instead.
Generated by Claude Code
Mutation testing (cargo-mutants,
|
freshtonic
left a comment
There was a problem hiding this comment.
This looks good. It would be great if there were tests but I can't see how it would be possible: we'd need the compromised keys to attempt a TLS connection in order to see it rejected.
| This needs Go 1.26.10 or later (or 1.27.3 or later on 1.27): | ||
| those are the first releases whose `crypto/x509` blocks the compromised eMudhra intermediate CAs | ||
| ([CVE-2026-111943](https://github.com/golang/go/issues/82345)). | ||
| The module's `go` line requires 1.26.10, so under the default `GOTOOLCHAIN=auto` an older local Go downloads and switches to 1.26.10. | ||
| A minimum cannot exclude 1.27.0 to 1.27.2, which are also vulnerable: do not build with those. |
cipherstash-bot
left a comment
There was a problem hiding this comment.
Recommendation: 🟢 merge as it is
Nothing must change before merging. The go 1.26.10 line is the correct directive for a library, and the version pins and docs agree. Two follow-ups can wait: add a test that guards the version floor, and consider a run-time check for Go 1.27.0 to 1.27.2, which go.mod cannot exclude.
How this review was made
| Agent | Model | Review type | Result |
|---|---|---|---|
| claude | claude-opus-5-5 | test-gap | 1 found, 1 posted |
| claude | claude-opus-5-5 | golang | 1 found, 1 posted |
| codex | gpt-5.6-terra | test-gap | 0 found, 0 posted |
| codex | gpt-5.6-terra | golang | 0 found, 0 posted |
Synthesis: claude-sonnet-5-5 merged the findings, removed duplicates and dropped findings it could not confirm in the code. 0 posted finding(s) were raised by two or more models.
Plain language: claude-sonnet-5-5 read every comment as a new reader would. No comment had a problem that stopped the reader acting, so none was rewritten.
Stack: not part of a stack.
Context loaded: the description, 1 linked issue(s) and 6 discussion entries.
| # 1.26.10 is the first 1.26 release whose crypto/x509 blocks the compromised | ||
| # eMudhra intermediates (CVE-2026-111943, #1300), and a floating "1.26" could | ||
| # resolve an older patch from a cache. Keep it at or above go.mod's `go` line. | ||
| go = "1.26.10" |
There was a problem hiding this comment.
Fix in a follow-up: no test checks the Go 1.26.10 security floor in go.mod and mise.toml.
Impact: The fix for CVE-2026-111943 is two version strings. A later change can lower the go line in languages/golang/go.mod, or set this pin back to a floating "1.26". CI still passes in both cases. A Go SDK binary built after that change can accept certificate chains through the compromised eMudhra intermediates again.
Evidence: No file in scripts/__tests__/ reads the go line of go.mod or the go = "…" pin in mise.toml. go-module-path.test.mjs and go-release-version.test.mjs read only the module line. The comment above this line says "Keep it at or above go.mod's go line", but no test checks that rule.
Fix: Add scripts/__tests__/go-toolchain-floor.test.mjs. It must check three things: the go.mod go line is 1.26.10 or higher; the mise.toml pin is a full X.Y.Z version; the mise.toml pin is at or above the go.mod line.
Found by 1 model: claude
| module github.com/cipherstash/stack/languages/golang | ||
|
|
||
| go 1.26.0 | ||
| go 1.26.10 |
There was a problem hiding this comment.
Fix in a follow-up: a binary built with Go 1.27.0, 1.27.1 or 1.27.2 still trusts the compromised eMudhra intermediates, and the SDK does not detect it.
Impact: The go 1.26.10 line forces a toolchain switch only when the local Go is older than 1.26.10. Go 1.27.0 to 1.27.2 are newer, so go get and go build keep them. A consumer on an unpatched Go 1.27 builds a vulnerable binary. That binary uses http.DefaultTransport by default (encrypt/client.go:75, auth/transport.go:81). A holder of the compromised keys can then impersonate ZeroKMS or the auth endpoint. Only the READMEs warn about this range.
Evidence: In go/version order, go1.27.0 is greater than go1.26.10, so a minimum in go.mod cannot exclude it. The PR description lists this gap as known.
Fix: Check runtime.Version() before the first request, for example in encrypt.NewClient and the auth store constructor. Use go/version: return an error when the version is at least go1.27 and below go1.27.3. Treat an invalid (devel) version as allowed.
Found by 1 model: claude
Requested by Toby · project thread
Closes #1300
Summary
Go 1.26.10 and 1.27.3 are the first releases whose
crypto/x509rejects chains through the eight compromised eMudhra intermediate CAs (CVE-2026-111943, golang/go#82345). A Go SDK binary built with an older toolchain would still accept such a chain, so whoever holds those keys could impersonate ZeroKMS or the auth endpoints to it.languages/golang/go.mod:go 1.26.0→go 1.26.10mise.toml:go = "1.26"→go = "1.26.10", with a comment saying why it is pinned to the patchencrypt/README.md,cmd/stashgen/README.md,encrypt/doc.go: the stated minimum goes from "Go 1.26 or later" to 1.26.10 (or 1.27.3 on 1.27)AGENTS.md: the toolchain note now says Go 1.26.10Why
go 1.26.10and not atoolchain go1.26.10directiveThe SDK is a library that other modules import, so the directive has to reach consumers:
gois the only directive a dependency's go.mod passes on to the modules that import it. When a consumer runsgo geton this module, their owngoline goes up to 1.26.10. Under the defaultGOTOOLCHAIN=auto, an older local Go then downloads 1.26.10 and switches to it. UnderGOTOOLCHAIN=local, it refuses to build. Both are the outcomes we want.toolchaindirective only applies in the main module. It would protect builds inside this repo and nobody who imports the SDK. It also wouldn't raise the language minimum, so a 1.26.0 toolchain withGOTOOLCHAIN=localwould still build the module.Raising
godoes make 1.26.10 a hard requirement, but that is the point of this fix.go mod tidy -diffis clean, so notoolchainline gets added.One gap a minimum can't close: 1.27.0 to 1.27.2 are higher than 1.26.10 but still vulnerable. The READMEs and
doc.gosay so.CI and release
tests-golang.yml(setup-go, from thego = "…"line it reads with sed) andrelease-golang.yml(mise-action) both take Go from the rootmise.tomlpin, so they now build with 1.26.10. The sed still matches the new value. No guard test underscripts/__tests__orscripts/go-release-version.mjspins the Go toolchain version.Changeset
None. The Go module is released by hand with
release-golang.yml, not through Changesets. No file underskills/mentions a Go version, so thestashtarball doesn't change.Verification
Run locally with
GOTOOLCHAIN=go1.26.10(the toolchain downloaded fine):deterministic-kms,eql,eql,deterministic-kms, and authscripts/go-binding-test.sh languages/golang(thego:testbody): gofmt,go vet,go test ./...on amd64, andGOARCH=386 go test ./.... All pass.go generate ./...: no diffgo mod tidy -diff: cleanpnpm run test:scripts: 79 files, 1415 passed, 1 skipped (already skipped before this change)Not run:
golangci-lint(not installed here), and the live Go tests that need credentials.Generated by Claude Code
Summary by CodeRabbit
Documentation
GOTOOLCHAIN=autois enabled.Chores