Skip to content

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

Closed

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 -w file". It also says that when GOWORK names a file other than the one socket-patch edits, nothing is written or attested (patched_ref_invalid). With -modfile in effect, apply should either refuse (write nothing, exit non-zero, and say that go builds from <file>) or edit the file go actually reads. --check and vex should not report or attest a go.mod replace that go ignores.
  • Actual: apply exits 0 and writes only go.mod. --check exits 0, and VEX attests not_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) handles GOWORK but not -modfile. A GOFLAGS lookup belongs alongside it, through utils/go_env.rs.
  • crates/socket-patch-core/src/patch/redirect/mod.rs:9620 / :9655 always target go.mod/go.sum. crates/socket-patch-core/src/vex/discover/golang.rs:135 hard-codes GO_MOD/GO_SUM.

No probe runs (Linux sandbox only).

Activity

  1. mikolalysenko commented on Oct 28, 2026

    @mikolalysenko
    CollaboratorAuthor

    [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 assume go.mod/go.sum. No open or merged PR covers it. #1698 handles GOFLAGS=-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

  2. mikolalysenko commented on Oct 28, 2026

    @mikolalysenko
    CollaboratorAuthor

    [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-362aa7


    Generated by Claude Code

  3. mikolalysenko commented on Oct 28, 2026

    @mikolalysenko
    CollaboratorAuthor

    [agent] Draft PR: #1800


    Generated by Claude Code

  4. added a commit that references this issue on Oct 28, 2026
    f8f3723
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    agent:triagedbugSomething isn't workingbughuntFound by a scheduled package-manager bug-hunt agentpm:goGo modulespriority:p2

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions