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-97054 | net/http | HTTP/1 服务器用 MaxBytesReader / MaxBytesHandler 命中上限、handler 同时设置响应头时可能 panic |
| CVE-2026-97033 | #cgo 编译器与链接器 flag | 不允许 --sysroot 与 -target;-isysroot 与 -Wl,-syslibroot 不得指向普通文件;-x 限于 cgo 编译的语言 |
| CVE-2026-97034 | cgo 链接器搜索目录 | -L、-isysroot、-Wl,-syslibroot 指向的目录若含 GCC spec 文件则被拒 |
| CVE-2026-97035 | #cgo flags | 不允许 Clang -gen-* 与 GCC -gnat*(过去的 -g* 通配匹配到了它们) |
| CVE-2026-97036 | macOS 上的 #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-97042 | cgo_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 博客公告。