编程 Go 1.27.4 / 1.26.11 修 12 个 CVE:先重建 net/http 服务,再处理 --sysroot 构建失败

2026-11-12 20:02:30

Go 1.27.4 / 1.26.11 修 12 个 CVE:先重建 net/http 服务,再处理 --sysroot 构建失败

2026-11-10,Go 1.27.4 与 Go 1.26.11 同时发布,带 12 个安全修复。公告见 oss-security 转发的 golang-announce,版本说明在 go.dev/doc/devel/release,下载页 go.dev/dl,漏洞条目为 GO-2026-6859。12 个 CVE 于 11 月 5 日以 PRIVATE-track 预公告。

这 12 个修复分两类:11 个在 cgo 构建链,涉及 go 命令、编译器、链接器处理 #cgo 指令、.syso 与链接输入时的漏洞,一个使用 cgo 的依赖可以借此在构建机上执行代码;第 12 个在 net/http。

这意味着两个不同的动作:已部署的 HTTP/1 服务要重新构建并重部署;所有会编译非自己代码的机器要换新工具链。

12 个 CVE

CVE位置修复
CVE-2026-97054net/httpHTTP/1 服务器用 MaxBytesReader / MaxBytesHandler 命中上限、handler 同时设置响应头时可能 panic
CVE-2026-97033#cgo 编译器与链接器 flag不允许 --sysroot 与 -target;-isysroot 与 -Wl,-syslibroot 不得指向普通文件;-x 限于 cgo 编译的语言
CVE-2026-97034cgo 链接器搜索目录-L、-isysroot、-Wl,-syslibroot 指向的目录若含 GCC spec 文件则被拒
CVE-2026-97035#cgo flags不允许 Clang -gen-* 与 GCC -gnat*(过去的 -g* 通配匹配到了它们)
CVE-2026-97036macOS 上的 #cgo LDFLAGS-l to_library(Apple 链接器会拼成 -lto_library 用来加载插件)被拒,连同 -lazy_library、-lazy_framework、-load_hidden、-library、-library-path
CVE-2026-97037拆分的 -Wl, flag第二个 token 也必须带 -Wl, 前缀
CVE-2026-97038.syso 文件与链接输入必须是合法二进制或归档
CVE-2026-97039#cgo pkg-config不允许 --with-path=、--personality=、部分 --define-variable= 取值与本地 .pc 路径
CVE-2026-97040伪装成 Go 对象的 .syso链接器拒绝不认识的宿主对象格式
CVE-2026-97041//go:cgo_* 指令逗号被拒
CVE-2026-97042cgo_import_dynamic 的 Windows DLL 名含路径分隔符、..、:,或以 - / @ 开头的库名被拒
CVE-2026-97043//go:cgo_ldflag转义引号不再能把被禁 flag 蒙过去

net/http:崩溃在已部署的二进制里

CVE-2026-97054 影响 net/http。据 golang/go#82563,HTTP/1 服务器在 MaxBytesReader 超限时会“未经同步”地设置 Connection: close,若一个 goroutine 读请求体、另一个设置响应头,就会 runtime panic 打死进程。该 issue 只描述 HTTP/1 服务器上这一模式。

受影响版本:before go1.26.11、from go1.27.0-0 before go1.27.4。报告者是 Jakub Ciolek。

这条和 cgo 那批不同:漏洞在已经编译好的二进制里,换工具链不会修好已部署的进程。必须用 1.27.4 或 1.26.11 重新构建,再重部署。撰写 importstatic.com 文章 的作者没有复现这个崩溃,只按 issue 记录了触发条件。

cgo:正常构建也会被打断

11 个 cgo 修复会拒绝更多 flag,因此也会打断一些本来没有恶意的构建。最典型的是交叉编译:--sysroot= 与 -target 写在 #cgo CFLAGS 里,现在报 invalid flag。

会撞上的情况包括:

  • #cgo CFLAGS 或 LDFLAGS 里的 --sysroot=、-target;
  • -isysroot、-Wl,-syslibroot 指向普通文件而不是目录;
  • -L、-isysroot、-Wl,-syslibroot 指向的目录里含 GCC spec 文件;
  • Clang 的 -gen-*、GCC 的 -gnat*;
  • macOS 上的 -l to_library、-lazy_library、-lazy_framework、-load_hidden、-library、-library-path;
  • -Wl, 拆开写时,第二个 token 没带 -Wl, 前缀;
  • .syso 或链接输入不是合法二进制或归档,或伪装成 Go 对象;
  • #cgo pkg-config 里的 --with-path=、--personality=、部分 --define-variable= 和本地 .pc 路径;
  • //go:cgo_* 指令里带逗号;
  • cgo_import_dynamic 的 Windows DLL 名含路径分隔符、..、:,或以 - / @ 开头;
  • //go:cgo_ldflag 里用转义引号绕开限制。

两种绕过方式,代价不同

第一种是把 flag 从源码移到环境变量。cgo 文档写得很明确:“Flags obtained from environment variables are not subject to the security limitations.” 例如:

CGO_CFLAGS='--sysroot=/path/to/sysroot --target=aarch64-linux-gnu' go build ./...

importstatic.com 的作者在 darwin/arm64、Apple clang 21.0.0 上,用 Go 1.27.3 / 1.27.4 / 1.26.10 / 1.26.11 测过这个组合,四个版本都能编过。注意这是该文章的测试结论,不是本机实测。

第二种是放宽白名单:

CGO_CFLAGS_ALLOW='--sysroot=.*|--target=.*'
CGO_LDFLAGS_ALLOW='--sysroot=.*'

1.27.4 源码里 --sysroot 与 -target 是从合法 flag 列表里删掉,而不是加进禁止列表,所以这两个变量仍能接受它们。模式要匹配整个参数,所以末尾必须有 .*。代价是这两个变量作用于构建中所有 cgo 包,等于对所有依赖重开了 CVE-2026-97033 的洞。除非自己维护的包必须把 flag 写在源码里,否则优先用 CGO_CFLAGS。

钉住构建工具链

go.mod 的 go 行不会拉入点版本。go 命令在自带工具链“至少和 go 或 toolchain 行一样新”时就会用它,所以写着 go 1.27.0 的模块,仍可能用 CI 镜像上装的任何 Go 构建。要么更新已安装的 Go,要么在模块里钉补丁版本:

go get go@1.27.4
# go: added toolchain go1.27.4

这会在 go 行下加一行 toolchain go1.27.4。任何装了更旧 Go、且 GOTOOLCHAIN=auto(默认)的机器,下次构建会切到 1.27.4,必要时下载。优先处理的是 CI 里构建 PR、尝试依赖升级、开 cgo 的 job。

govulncheck 对点版本可能看不到

importstatic.com 的作者用 go1.27.3 构建了一个用 http.MaxBytesReader 包 body 的小服务器,2026-11-11 00:12 UTC 左右跑 govulncheck v1.9.0,对“the go1.27.3 standard library”报 No vulnerabilities found。标准库的点版本在这里不可靠,确认二进制实际由哪个工具链构建要用:

go version ./server-bin

来源

8 个 cgo 洞由 Go 安全团队内部审计发现;其余 3 个 cgo 问题与 net/http 崩溃由外部报告者提供。Microsoft 的 v1.27.4-1 与 v1.26.11-1 构建同日可用,见 Microsoft Go 博客公告。

复制全文 生成海报 Go 安全 CVE cgo 构建

推荐文章

程序员茄子在线接单