Repository navigation
Go apply, apply --check and vex ignore GOFLAGS=-modfile, so they report a patch as applied while go builds from another go.mod and links the unpatched module #1799
Description
[agent] Found by the scheduled Go modules bug-hunt routine (ledger #317).
Summary
When GOFLAGS contains -modfile=<file>, set either in the environment or with go env -w, every go command reads <file> and its matching .sum file instead of go.mod/go.sum. socket-patch never reads GOFLAGS. Agent-mode apply still writes its replace into go.mod and exits 0. apply --check then reports the patch in sync, and vex attests not_affected. Meanwhile go build/go run links the unpatched module.
Impact
A project or CI job that sets -modfile through GOFLAGS ships the vulnerable code, and socket-patch's own --check and VEX claim it is fixed. That is the "VEX attestation for a patch that isn't actually applied" failure mode. The CLI contract already treats the analogous case of a GOWORK that names a non-default file as fail-closed: nothing is written or attested, and refs are reported patched_ref_invalid. -modfile gets no such handling.
Repro (Linux; hermetic file GOPROXY; hand-staged manifest + blob in the tests/e2e_golang_build.rs shape)
# proxy has example.com/upstream v1.0.0 (lib.go: Greeting() returns "PRISTINE")
export GOMODCACHE=$PWD/modcache GOPROXY=file://$PWD/proxy GOSUMDB=off GOTOOLCHAIN=local
mkdir c && cd c
printf 'module example.com/c\n\ngo 1.21\n\nrequire example.com/upstream v1.0.0\n' > go.mod
printf 'package main\nimport ("fmt"; "example.com/upstream")\nfunc main(){fmt.Println("OUT:", upstream.Greeting())}\n' > main.go
GOFLAGS=-mod=mod go mod tidy
cp go.mod go.alt.mod; cp go.sum go.alt.sum
export GOFLAGS=-modfile=go.alt.mod # or: go env -w GOFLAGS=-modfile=go.alt.mod
go run . # OUT: PRISTINE
# stage .socket/manifest.json + blob for pkg:golang/example.com/upstream@v1.0.0 (lib.go -> "PATCHED")
socket-patch apply --offline --ecosystems golang # exit 0, "1 of 1 targeted patch applied"
go run . # OUT: PRISTINE <-- still unpatched
GOFLAGS= go run . # OUT: PATCHED (only the default go.mod got the replace)
socket-patch apply --check --offline --ecosystems golang # exit 0, "in sync"
socket-patch vex --product pkg:golang/example.com/c@v0 # status "not_affected"Expected vs actual
- Expected: CLI_CONTRACT.md says Go settings resolve "as go resolves it: the environment, then the
go env -wfile". It also says that whenGOWORKnames a file other than the one socket-patch edits, nothing is written or attested (patched_ref_invalid). With-modfilein effect,applyshould either refuse (write nothing, exit non-zero, and say that go builds from<file>) or edit the file go actually reads.--checkandvexshould not report or attest ago.modreplace that go ignores. - Actual: apply exits 0 and writes only
go.mod.--checkexits 0, and VEX attestsnot_affected. The build links PRISTINE.
OS × version
| OS | go | GOFLAGS env |
go env -w GOFLAGS |
|---|---|---|---|
| Linux | 1.21.13 | reproduces | not run |
| Linux | 1.24.7 | reproduces (2×) | reproduces |
| Linux | 1.26.8 | reproduces | not run |
| macOS / Windows | any | not run (the logic is OS-independent) | not run |
Tested on main a9d2312. I didn't bisect: GOFLAGS is not read anywhere outside a unit test in crates/socket-patch-core/src/utils/go_env.rs, so it is probably long-standing. Hosted and vendored modes write the same go.mod/go.sum and probably behave the same way, but I didn't run them.
Suspect code
crates/socket-patch-core/src/vendor/go_workspace.rs:55(resolve) handlesGOWORKbut not-modfile. AGOFLAGSlookup belongs alongside it, throughutils/go_env.rs.crates/socket-patch-core/src/patch/redirect/mod.rs:9620/:9655always targetgo.mod/go.sum.crates/socket-patch-core/src/vex/discover/golang.rs:135hard-codesGO_MOD/GO_SUM.
No probe runs (Linux sandbox only).
Activity
go: run 17 ledger (#1799)
mikolalysenko commentedon Oct 28, 2026
[agent] Triaged as priority:p2 (Go modules). Confirmed on main
eb75d20: nothing outside tests reads-modfile(grep -rn modfile crates/finds no hits), so every Go writer and the VEX discoverer assumego.mod/go.sum. No open or merged PR covers it. #1698 handlesGOFLAGS=-mod=for native vendor checks but not-modfile. It doesn't share a cause with #549 (go.sum restore on rollback).Generated by Claude Code
mikolalysenko commentedon Oct 28, 2026
[agent] Claiming this issue (shared root cause: Go writers and VEX never read
GOFLAGS, so they don't see-modfile). Branch: agent/fix-go-goflags-modfile. Claim-ID: 2026-10-28T22:20:51Z-362aa7Generated by Claude Code
mikolalysenko commentedon Oct 28, 2026
[agent] Draft PR: #1800
Generated by Claude Code
Refuse Go patches that GOFLAGS=-modfile bypasses