本文永久链接 – https://tonybai.com/2026/11/02/cve-2026-98432-linux-kernel-vulnerability-go-mptcp

大家好,我是Tony Bai。

【导读】

AI 安全研究正在进入一个新的阶段。

10 月 27 日,Anthropic 发布了一篇安全研究报告,披露 Claude 在研究人员的引导下,发现并利用了多个真实世界软件中的严重漏洞。其中,一个 Linux 内核网络栈漏洞尤其值得关注:Claude 不仅找到了漏洞,还构造出了一个无需身份认证、无需用户交互,就能在远程 Linux 服务器上以 root 权限执行命令的攻击链。

这个漏洞的编号是 CVE-2026-98432,CVSS 评分高达 9.8。

而这次事件还意外牵出了 Go。

从 Go 1.24 开始,Go 标准库在 Linux 上默认启用了 Multipath TCP(MPTCP)监听能力。这使得大量 Go 网络服务可能满足 Claude 所展示的攻击条件。

Go Security Team 随后专门发布了安全公告。

一个发生在 Linux 内核中的漏洞,为什么会影响 Go 应用?Go 开发者又应该如何应对?

【文章要点】

  • Claude 不只是发现漏洞,还完成了从漏洞分析到远程代码执行利用链的构建。
  • CVE-2026-98432 是 Linux IPv4 TCP 握手过程中的 Use-After-Free 漏洞。
  • Go 1.24 起默认启用 Linux MPTCP Listener,使 Go 服务更容易满足已公开 PoC 的攻击条件。
  • 关闭 MPTCP 可以缓解已展示的攻击路径,但不能修复 Linux 内核中的底层漏洞。
  • 升级到包含补丁的 Linux 内核,才是根本解决方案。
  • Go 的默认行为是否应该改变,以及标准库应该如何权衡新功能与安全性,是这次事件留下的进一步讨论。

Claude 发现了什么?一个可以远程获取 root 权限的 Linux 漏洞

先来看 Anthropic 的研究成果。

在 10 月 27 日发布的《Discovering and exploiting vulnerabilities in critical, real-world software with Claude》中,Anthropic 展示了 Claude 在 Chrome、Safari、Android、Windows 和 Linux 等关键软件中的漏洞研究成果。

其中,Linux 部分尤其引人注目。

Claude 发现了 Linux 内核网络栈中的一个 Use-After-Free(UAF)漏洞。Anthropic 将其报告给 Linux 内核维护者,最终获得了 CVE-2026-98432 编号。

这个漏洞位于 Linux IPv4 TCP 连接处理过程中。

更令人惊讶的是,Claude 不只是发现了漏洞,还完成了完整的利用链构建。

Anthropic 展示的攻击可以分成两个阶段:

第一阶段:绕过 KASLR,泄露内核地址。

KASLR(Kernel Address Space Layout Randomization)是 Linux 内核的一项安全机制,通过随机化内核代码和数据在内存中的位置,增加攻击者预测内存地址的难度。

Claude 利用漏洞中的竞争条件(Race Condition),让内核读取攻击者控制的长度字段,进而从内核内存中多读取一些数据,并通过网络响应返回给攻击者。

只要返回的数据中包含一个内核指针,攻击者就有机会推算出内核地址空间布局,从而绕过 KASLR。

第二阶段:劫持内核控制流。

获得内核地址信息后,Claude 再次利用同一个 UAF 漏洞,覆盖内核中的回调函数指针。

攻击者提前通过正常的协议功能,将载荷放入内核内存。随后,当内核调用被覆盖的回调函数时,攻击者就可以借助已有的内核函数完成一系列调用,最终执行攻击者指定的 Shell 命令。

整个过程不需要登录凭证,也不需要用户点击任何东西。

Anthropic 披露,在其 PoC 中,泄露内核指针耗时约 48 分钟,最终获得命令执行能力又耗时约 5 分钟。

这意味着,攻击者只需要能够向目标服务器发送网络数据包,就有机会获得 root 权限。

需要说明的是,Anthropic 并没有公开完整的攻击代码,其展示的是实验室环境中的 PoC。

这次研究真正值得关注的,不仅是漏洞本身,更是 AI 已经能够将复杂的漏洞分析、内存布局推断和多阶段利用串联起来,完成过去通常需要专业安全研究团队才能做到的工作。

CVE-2026-98432:问题出在 TCP 握手中的 Use-After-Free

那么,这个漏洞究竟是怎么产生的?

要理解它,需要先了解 Linux 内核处理 TCP 连接时的一段机制。

当客户端向 Linux 服务器发起 TCP 连接时,内核首先处理 SYN 请求,并创建一个轻量级的 Request Socket,用于跟踪尚未完成的 TCP 握手。

如果客户端的 IPv4 数据包携带了 IP Options,Linux 内核会保存相关选项信息,以便在后续握手响应中使用。

问题就出在这里。

在某些竞争条件下,Linux 内核会将 Request Socket 中保存的 IPv4 选项数据转移给新创建的连接,却没有正确处理并发读取与内存释放之间的时序关系。

在连接销毁过程中,这块内存可能被提前释放,但另一个 CPU 核心仍然可能在读取它。

于是,Use-After-Free 就发生了。

简单来说:

一块内存已经被释放,却仍然被另一个执行路径当作有效内存使用。

这正是典型的内存生命周期管理错误。

可以用下面的示意图理解:

这里需要特别强调一点:

这个漏洞并不是 MPTCP 专属漏洞。

Go 核心团队成员在 GitHub issue #82717 中明确指出,漏洞根因是 Linux IPv4 TCP 连接处理中的 UAF,竞争条件发生在处理包含 IPv4 Header Options 的 TCP SYN 数据包时。

MPTCP 只是 Anthropic 已经展示的那条远程 RCE 利用链所需要的条件之一。

也就是说,即使系统没有 MPTCP Listener,也不能因此断言它完全不受这个底层漏洞影响。

Linux 内核是如何修复的?

这个漏洞的修复非常有意思。

Linux 网络子系统维护者 Eric Dumazet 提交的补丁,标题为:

ipv4: free inet_opt and ireq_opt after an RCU grace period

核心修改是将原来的:

kfree(ptr);

替换为:

kfree_rcu(ptr, rcu);

两者的区别在于:

  • kfree():直接释放内存。
  • kfree_rcu():等待 RCU Grace Period(宽限期)结束,确保此前仍在访问该内存的读者完成操作后,再释放内存。

这正是并发环境下解决此类内存生命周期问题的一种经典方法。

值得注意的是,这个修复并没有引入复杂的新机制,而是让相关内存释放行为与其他已经使用 RCU 保护的代码路径保持一致。

为什么 Go 程序也会受到影响?

现在来到这次事件与 Go 最直接的交集。

答案是:Multipath TCP。

MPTCP 是 TCP 的扩展协议,定义于 RFC 8684。传统 TCP 连接通常依赖一条网络路径,而 MPTCP 允许一条逻辑连接使用多条网络路径。

例如,一台移动设备可能同时连接 Wi-Fi 和蜂窝网络。

传统 TCP 在网络切换时,连接可能中断或需要重新建立;MPTCP 则可以利用多个子连接,在不同网络路径之间切换,甚至实现带宽聚合。

这对于移动设备、网络冗余和多链路场景具有实际价值。

Go 从 1.24 开始,在 Linux 平台上默认启用了 MPTCP Listener。

这意味着,当 Go 程序使用标准库创建 TCP 监听器时,在满足系统条件的情况下,它可能创建 MPTCP 监听 Socket,而不再只是普通 TCP Socket。

例如,下面这段代码:

package main

import (
    "log"
    "net/http"
)

func main() {
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        w.Write([]byte("Hello, Go!"))
    })

    log.Fatal(http.ListenAndServe(":8080", nil))
}

开发者没有显式调用任何 MPTCP API。

但是,在使用 Go 1.24 及之后版本、且 go.mod 版本声明也满足要求的 Linux 程序中,这个普通 HTTP 服务可能默认创建 MPTCP Listener。

这就是问题所在。

Anthropic 展示的 Linux RCE 利用链需要目标服务器存在 MPTCP Listener。

而 Go 的默认行为,恰好让大量 Go 服务具备了这个条件。

需要注意,这并不意味着所有 Go 程序都必然受到同等影响。实际情况还取决于 Linux 内核版本、系统是否启用 MPTCP、Go 模块的 Go 版本声明,以及服务是否存在相应的网络监听。

另外,Go Security Team 也特别强调:底层 UAF 并不依赖 MPTCP。没有 MPTCP Listener,只能说明目前展示的那条 PoC 攻击路径不再满足条件,不能证明系统安全。

Go Security Team 的回应:如何临时缓解?

2026 年 10 月 30 日,Go Security Team 在 golang-announce 邮件列表中发布了专门的安全公告:《Protecting against CVE-2026-98432》。

公告给出的首要建议非常明确:

升级到已经修复该漏洞的 Linux 内核版本。

不过,如果暂时无法升级内核,Go 也提供了关闭 MPTCP 默认行为的办法。

方案一:通过 GODEBUG 关闭 MPTCP

对于已经部署的 Go 服务,可以通过环境变量:

GODEBUG=multipathtcp=0

关闭 MPTCP 默认行为。

例如:

GODEBUG=multipathtcp=0 ./my-go-server

这种方式不需要重新编译程序,适合已有服务的临时缓解。

方案二:在 go.mod 中设置

也可以在项目主模块的 go.mod 中加入:

module example.com/myapp

go 1.24

godebug multipathtcp=0

这样就能把“关闭 MPTCP”固化在构建配置里。

此外,也可以在 main 包声明之前添加:

//go:debug multipathtcp=0
package main

这两种方式都能为程序指定相应的默认配置。

方案三:通过 Linux 系统配置关闭 MPTCP

如果不希望依赖每个 Go 应用单独配置,也可以在 Linux 系统层面关闭 MPTCP:

sudo sysctl -w net.mptcp.enabled=0

需要注意,这属于系统级配置,会影响该网络命名空间中的其他应用。对于容器环境,还需要关注各自 Network Namespace 的配置。

同时,已经创建的 MPTCP Listener 不会因为修改配置而自动变成普通 TCP Listener,需要重启相关服务。

重要提醒:关闭 MPTCP 不等于修复漏洞

这里必须强调 Go Security Team 的一个关键提醒:

关闭 MPTCP,只能阻止 Anthropic 当前展示的那条特定利用路径,不能修复 Linux 内核中的 UAF。

由于漏洞本身并不专属于 MPTCP,未来仍然可能出现不依赖 MPTCP 的其他攻击路径。

因此,GODEBUG 应该被看作临时缓解手段,而不是最终修复方案。

Go 是否应该默认启用 MPTCP?社区出现了不同声音

这次事件还引出了 Go 社区一个值得讨论的问题:Go 是否应该继续默认启用 MPTCP Listener?

GitHub 上的 issue #82717,标题为:proposal: net: Disable MPTCP by default。

该提案于 2026 年 10 月 29 日创建,讨论的正是是否应该改变 Go 的默认行为。

社区出现了不同观点。

一种观点:应该关闭默认行为。

支持者认为,MPTCP 并不是所有服务都需要的功能。既然它会增加网络协议栈的攻击面,而且其他主流网络库也没有普遍默认开启,那么将其改为显式启用可能更加稳妥。

这次事件也让一些开发者重新审视 Go 当初启用 MPTCP 的决策。

另一种观点:不应该因为第三方内核漏洞改变 Go 的默认行为。

反对者认为,CVE 的根因在 Linux 内核,而不是 Go。

既然 Linux 上游已经修复,正确的责任边界应该是由操作系统维护者发布补丁,由系统管理员及时更新内核,而不是让 Go 标准库为每一个第三方组件的漏洞改变默认行为。

更重要的是,MPTCP 确实具有实际价值。

它可以支持无缝网络切换、网络路径选择和带宽聚合。即使客户端没有使用 MPTCP,普通 TCP 连接仍然可以正常工作。

Go 社区此前启用 MPTCP 的一个重要思路,就是让 Go 程序能够自动使用更好的网络能力,而不需要开发者修改应用代码。

这与 Go 标准库默认支持 HTTP/2、TLS 1.3 等新能力的理念有相似之处。

截至本文撰写时,issue #82717 仍处于开放讨论状态,尚不能将其视为 Go 已经决定关闭 MPTCP 默认行为。

我认为,这场讨论真正值得关注的,并不是简单地争论 MPTCP 应不应该默认开启,而是一个更深层的问题:

当标准库主动替开发者开启一项新的系统能力时,它是否也应该承担这项能力所带来的额外安全风险?

这是 Go 一直强调合理默认值,就必须面对的权衡。

Go 开发者现在应该做什么?

对于正在 Linux 上运行 Go 服务的开发者,我建议立即做一次检查。

首先,确认当前运行的 Linux 内核版本:

uname -r

截至 2026 年 10 月 31 日,上游已经发布修复的主要内核版本包括:

内核分支 修复版本
7.3 7.3
7.2 7.2.10
6.18 6.18.56
6.12 6.12.113
6.6 6.6.159
6.1 6.1.190
5.15 5.15.223
5.10 5.10.272

注意:发行版通常会将安全补丁回移到自己的内核版本中,因此不能只根据 uname -r 与上游版本号进行简单比较。应该检查发行版的安全公告和软件包状态,并确保系统已经重启进入修复后的内核。

其次,检查系统是否存在 MPTCP Listener:

ss -Mlnp

还可以检查内核是否允许启用 MPTCP:

sysctl net.mptcp.enabled

其中,ss -Mlnp 可以列出当前的 MPTCP 监听 Socket 及其所属进程。

如果发现 Go 服务正在监听 MPTCP,可以优先处理这些服务。

对于暂时无法升级内核的环境,可以考虑通过 GODEBUG=multipathtcp=0 关闭 Go 的 MPTCP 默认行为,并结合系统防火墙策略降低风险。

最后,还有一个容易被忽视的地方:

不要只检查容器镜像,还要检查宿主机内核。

Docker 容器和 Kubernetes Pod 通常共享宿主机内核。即使重新构建了一个完全没有变化的 Go 应用镜像,也不会修复宿主机上的 Linux 内核漏洞。

因此,Kubernetes 节点、云服务器宿主机以及容器运行时所在的 Linux 主机,都应该纳入这次安全检查。

小结:AI 让漏洞发现更快,系统安全却不能只靠 AI

CVE-2026-98432 是一次很有代表性的安全事件。

Claude 不仅发现了 Linux 内核中一个隐蔽的并发内存管理错误,还将其转化为一条完整的远程 root 利用链。

更值得 Go 开发者思考的是,这次漏洞并不在 Go 语言本身,却因为 Go 标准库的一个默认行为,让 Go 服务成为了需要重点关注的对象。

这也提醒我们:

现代应用的安全边界早已延伸至自己的业务代码之外。

标准库、运行时、操作系统内核、网络协议栈、容器环境,都是应用实际运行时安全模型的一部分。

过去,我们习惯于关注自己的 Go 代码有没有 SQL 注入、越界访问或者数据竞争。

但在今天,还需要问一个问题:

我们的程序默认开启了哪些系统能力?这些能力又把我们划入了怎样的安全边界?

当 AI 已经能够自动发现并利用复杂的系统级漏洞时,及时更新底层依赖、理解运行时默认行为、持续审视系统攻击面,可能比以往任何时候都更加重要。

参考资料:


还在为“复制粘贴喂AI”而烦恼?我的新专栏 《AI原生开发工作流实战》 将带你:

  • 告别低效,重塑开发范式
  • 驾驭AI Agent(Claude Code),实现工作流自动化
  • 从“AI使用者”进化为规范驱动开发的“工作流指挥家”

扫描下方二维码,开启你的AI原生开发之旅。


你的Go技能,是否也卡在了“熟练”到“精通”的瓶颈期?

  • 想写出更地道、更健壮的Go代码,却总在细节上踩坑?
  • 渴望提升软件设计能力,驾驭复杂Go项目却缺乏章法?
  • 想打造生产级的Go服务,却在工程化实践中屡屡受挫?

继《Go语言第一课》后,我的《Go语言进阶课》终于在极客时间与大家见面了!

我的全新极客时间专栏 《Tony Bai·Go语言进阶课》就是为这样的你量身打造!30+讲硬核内容,带你夯实语法认知,提升设计思维,锻造工程实践能力,更有实战项目串讲。

目标只有一个:助你完成从“Go熟练工”到“Go专家”的蜕变! 现在就加入,让你的Go技能再上一个新台阶!


商务合作方式:撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。如有需求,请扫描下方公众号二维码,与我私信联系。