79% 对 51%:独立数字银行的应用安全落后。 阅读报告

深度解析

深度解析

MongoDB 副本集 use-after-free 未认证崩溃(CVE-2026-118383)

未认证请求可让 4.4.32、5.0.35、6.0.30、7.0.48、8.0.37、8.3.16 和 9.0.7 之前的 MongoDB 副本集落后主节点崩溃。

TL;DR

  • MongoDB 复制追赶阶段的一个 use-after-free 允许未认证客户端植入 waiter,使成员在成为主节点时崩溃。MongoDB 于 2026 年 11 月 10 日发布 CVE-2026-118383。
  • 受影响分支上的所有副本集成员都暴露,包括分片和配置服务器成员。独立的 mongod 不执行追赶,不受影响。
  • MongoDB 将其评为 CVSS v4.0 9.5 Critical。Datadog 复现了崩溃;MongoDB 表示在特定条件下可能实现代码执行。未报告攻击,截至 2026 年 11 月 13 日不在 CISA KEV 中。
  • 将每个成员升级到其分支的修复版本:4.4.32、5.0.35、6.0.30、7.0.48、8.0.37、8.3.16 或 9.0.7。Atlas 和容器参见“如何修复?”。

我受影响吗?

以下条件全部成立时,你会受到影响:

  • 服务器是 MongoDB 副本集成员,包括分片集群中的分片或配置服务器副本集成员。
  • 版本位于表中的某个受影响范围。
  • 攻击者能够访问该成员的 MongoDB 端口,并发送携带 readConcern.afterOpTime 的 ping 命令。在受影响版本上,服务器在检查凭据之前就接受这些请求,因此启用身份验证无法阻止准备步骤。

独立的 mongod 不受影响。它没有主节点追赶状态,也无法参与崩溃所需的选举。

崩溃还需要该成员落后于其他成员,然后赢得选举。攻击者无法促成这两件事,因此植入的 waiter 是一个在真实维护事件或故障转移时触发的陷阱。

分支 受影响版本 修复版本
9.0 9.0.0 至 9.0.6 9.0.7
8.3 8.3.0 至 8.3.15 8.3.16
8.0 8.0.0 至 8.0.36 8.0.37
7.0 7.0.0 至 7.0.47 7.0.48
6.0 6.0.0 至 6.0.29 6.0.30
5.0 5.0.0 至 5.0.34 5.0.35
4.4 4.4.0 至 4.4.31 4.4.32

MongoDB 的公告没有列出 8.2 分支,该分支已于 2026 年 7 月 31 日终止支持,不再获得修复。公开概念验证报告称,在使用仅测试用设置的实验中,8.2.12 仍会出现该缺陷。请将 8.2 视为不受支持,并迁移到已修复的分支。

检查每个成员的版本,而不仅是主节点:

# On each host, including members in containers and members that were offline
mongosh --quiet --eval 'db.version()'

# In a replica set, list every member and its state
mongosh --quiet --eval 'rs.status().members.map(m => m.name + " " + m.stateStr)'

# Docker
docker exec <container> mongosh --quiet --eval 'db.version()'

# Kubernetes, for each member pod
kubectl exec <pod> -- mongosh --quiet --eval 'db.version()'

rs.status() 在独立服务器上返回错误,这可以确认该主机不是副本集成员。对于 Atlas,请打开集群的维护设置;MongoDB 表示集群会在维护期间自动升级。

如何修复?

将每个副本集成员升级到其分支的修复版本。部分升级会让其余成员继续暴露,之后的选举可能将主节点角色转移到其中一个成员。

  1. 备份部署,并在供应商下载页面确认每个分支的修复版本。
  2. 一次升级一个成员,等它重新加入后再继续。在副本集上,先让主节点降级,或升级一个从节点,以便操作期间集合仍有主节点。
  3. 每次升级后在该成员上运行 db.version(),确认显示修复版本。也要检查维护窗口期间离线的成员。
  4. 对于 Docker,拉取修复后的镜像并重新创建容器。只替换镜像而不重新创建容器会让旧进程继续运行。公开概念验证使用 mongodb/mongodb-community-server:8.0.37-ubi9 进行修复版对照测试。
  5. 对于 Atlas,应用待处理的维护。如果项目推迟维护,MongoDB 建议尽快应用升级。

没有服务器设置可以关闭存在漏洞的追赶路径。限制对成员的网络访问,例如仅允许应用主机和其他成员,可以减少能够植入 waiter 的客户端。这不会移除已经植入的 waiter,也不能修复竞态。仅在所有成员升级完成前保留该限制。

修复版本改变了两点。追赶回调现在只结束仍然存活且当前正在使用的追赶状态,并且只有内部用户可以发送 readConcern.afterOpTime。两者都需要:前者阻止双重清理,后者阻止客户端植入 waiter。

根本原因是什么?

主节点追赶完成回调持有追赶状态的原生指针,而该状态可能在回调运行时释放自身。因此被中止的追赶会在已释放内存上再次调用 abort_inlock()。

ReplicationCoordinatorImpl 在新当选的主节点应用其错过的操作期间保留一个 CatchupState。该状态在 _lastAppliedOpTimeWaiterList 中注册 waiter,这是一个以 OpTime 为键的 multimap。当已应用的 OpTime 达到目标时,waiter 完成,回调调用 abort_inlock() 退出追赶模式。abort_inlock() 会重置 _catchupState,从而销毁状态对象。

存在漏洞的回调忽略了完成状态,也没有检查其状态是否仍是当前状态。在 MongoDB 8.0.34 的 src/mongo/db/repl/replication_coordinator_impl.cpp 第 5267 行,回调如下:

auto targetOpTimeCB = [this](Status status) {
    // Double check the target time since stepdown may signal us too.
    const auto myLastApplied = _repl->_getMyLastAppliedOpTime_inlock();
    if (_targetOpTime <= myLastApplied) {
        ...
        abort_inlock(PrimaryCatchUpConclusionReason::kSucceeded);
    }
};

状态由 std::unique_ptr 持有,因此对象没有共享生命周期。头文件第 1972 行声明了 std::unique_ptr<CatchupState> _catchupState;。

公开概念验证补充了缺失的步骤。两个带有对抗性 OpTime 项的 readConcern.afterOpTime waiter 会在 multimap 中形成排序循环,因此真正的追赶 waiter 永远不会被 setValueIf_inlock() 触及。下一次心跳判断成员已经追平并中止追赶。该中止重置尚未完成的 waiter,从而同步执行回调。回调再次调用 abort_inlock(),外层栈帧继续读取内层调用已释放的状态。

如何被利用?

  1. 攻击者向可达成员发送两个未认证的 ping 命令,并携带 readConcern.afterOpTime。所选的 OpTime 项使 waiter 在 multimap 中排序错误,因此真正的追赶 waiter 无法完成。
  2. waiter 会保留下来。它们不会过期,会一直存在到成员重启、回滚或从主节点降级。
  3. 该成员之后落后于另一个成员并赢得选举。攻击者无法导致滞后或选举,因此这一步依赖真实的维护事件或故障。
  4. 追赶结束时,清理会运行两次。新的主节点读取并写入已经释放的内存,并在接受写入前崩溃。
  5. Datadog 在 8.0.34 上复现了崩溃,CatchupState::abort_inlock() 处发生段错误。实验使用管理员访问权限暂停成员并强制故障转移;只有两个 ping 请求来自未认证客户端。

MongoDB 的公告称,在特定条件下该漏洞还可能允许在服务器进程中执行任意代码。Datadog 未在实验中实现代码执行,也没有声称崩溃在每个部署中都可靠。

攻击如何展开?

未认证客户端植入两个 afterOpTime waiter,之后的故障转移使该成员在落后的情况下成为主节点,追赶清理在已释放内存上运行两次。

flowchart LR A["两个未认证 ping
携带 readConcern.afterOpTime"] --> B["waiter 存入
lastAppliedOpTime multimap"] B --> C["OpTime 排序使真正的
追赶 waiter 未完成"] C --> D["成员落后,
然后赢得选举"] D --> E["追赶结束,
abort_inlock() 重置 waiter"] E --> F["回调在已释放状态上
再次调用 abort_inlock()"] F --> G["新主节点在接受写入前
崩溃"]

攻击者能做什么?

未认证攻击者可以在副本集成员成为主节点的那一刻使其崩溃,从而将主节点从集合中移除,并中断写入,直到另一个成员接管。

影响取决于崩溃成员的角色:

  • 普通副本集的主节点崩溃会引发选举和短暂的写入中断。如果有可用成员,它可以接管。
  • 分片副本集的主节点崩溃可能会阻塞经过该分片的操作,直到选出新的主节点。
  • 配置服务器的主节点崩溃可能会阻塞集群的元数据更改,直到配置服务器集合选出新的主节点。

条件也是影响的一部分:

  • 攻击者需要能够访问该成员的 MongoDB 端口。
  • 请求不需要账户,也不需要用户交互。
  • 该成员之后必须在落后于另一个成员时赢得选举。攻击者无法强制这一点,因此崩溃是延迟陷阱,而不是立即攻击。
  • 独立的 mongod 不受影响。

MongoDB 表示在特定条件下该漏洞可能允许任意代码执行。没有来源证明代码执行,Datadog 的复现以崩溃结束。请将代码执行视为供应商评估,而不是已证明的能力。

为什么修复有效?

修复为追赶状态提供了共享生命周期,并让回调检查 waiter 的状态以及其状态是否仍是当前状态。回调不能再第二次运行 abort_inlock()。

MongoDB 8.0.34 与 8.0.37 之间的差异改变了所有权和回调:

-    _catchupState = std::make_unique<CatchupState>(this);
+    _catchupState = std::make_shared<CatchupState>(this);
...
-    auto targetOpTimeCB = [this](Status status) {
+    auto targetOpTimeCB = [weakSelf = weak_from_this()](Status status) {
+        if (!status.isOK()) {
+            return;
+        }
+        auto self = weakSelf.lock();
+        if (!self || self->_repl->_catchupState != self) {
+            return;
+        }
         const auto myLastApplied = _repl->_getMyLastAppliedOpTime_inlock();
         if (_targetOpTime <= myLastApplied) {
             ...
-            abort_inlock(PrimaryCatchUpConclusionReason::kSucceeded);
+            self->abort_inlock(PrimaryCatchUpConclusionReason::kSucceeded);
         }
     };

头文件让 CatchupState 继承 std::enable_shared_from_this<CatchupState>,并用 std::shared_ptr 持有它。回调保留 weak_ptr,因此只能结束仍然存活且仍安装在 _catchupState 中的状态。非 OK 状态意味着另一条路径已经结束了追赶,回调直接返回,不触碰状态。

第二个修复提交 6111165c32 要求客户端提供的 readConcern.afterOpTime 具有内部用户权限。这消除了普通客户端植入 waiter 的前提。两个提交构成 8.0.37 修复;供应商为每个受影响分支列出了相应的修复版本。

如何检查是否已遭入侵?

没有报告利用,也没有发布入侵指标。这些检查在服务器日志中寻找崩溃特征和 waiter 请求。

  • 查找日志 ID 51803 的 Slow query 条目,对应未认证的 ping,携带 readConcern.afterOpTime 并以 MaxTimeMSExpired 结束。
  • 查找同一转换中成员进入主节点追赶(日志 ID 21359)后退出两次(日志 ID 21363)。
  • 在这些退出之后查找指明 CatchupState::abort_inlock() 的致命信号或回溯。
  • 检查同一成员更早的日志。两个请求可能在故障转移之前到达,之后成为主节点的成员会保留它们。

正常选举或单次追赶退出不符合该模式。请求字段是否出现在日志中取决于日志设置,attr.remote 字段可能显示回环地址而不是客户端真实地址。失败的尝试可能不留下痕迹。

时间线

  • 2026-10-30:MongoDB 编写 8.0.37 热修复的两个修复,一个针对追赶状态,一个针对 readConcern.afterOpTime。
  • 2026-11-10:MongoDB 于 20:23 UTC 发布 CVE-2026-118383,并发布修复版本。两个修复提交于 23:07 和 23:09 UTC 合入。
  • 2026-11-11:Datadog Security Labs 发布分析和复现,公开概念验证创建。
  • 2026-11-12:The Hacker News 报道该漏洞以及 MongoDB 表示未发现利用的声明。
  • 2026-11-13:CISA 的 KEV 目录未列出该 CVE。

从修复到公开概念验证用时 12 天
图 1:修复于 2026 年 10 月 30 日编写,CVE 和修复版本于 11 月 10 日发布,公开分析和概念验证于 11 月 11 日发布。来源:MongoDB、Datadog Security Labs 和公开概念验证,2026 年 11 月 13 日检查

常见问题

CVE-2026-118383 是否已在真实环境中被利用?

没有。MongoDB 表示在内部发现该漏洞,且不知道有任何利用尝试。截至 2026 年 11 月 13 日,该 CVE 不在 CISA KEV 目录中。

身份验证能阻止攻击吗?

在受影响版本上不能。两个 ping 命令在服务器检查凭据之前就被接受,因此 Datadog 能够用未认证客户端植入 waiter。8.0.37 修复会拒绝非内部用户客户端提供的 readConcern.afterOpTime。

独立的 mongod 会以这种方式崩溃吗?

不会。独立服务器没有副本集,也没有主节点追赶状态,因此导致 use-after-free 的双重清理无法运行。公告排除了独立实例。

攻击者能强制故障转移吗?

不能。攻击者可以植入 waiter,但成员必须自行落后并赢得选举。在 Datadog 的实验中,研究人员使用管理员访问权限暂停成员并触发选举;只有两个请求是未认证的。

Atlas 集群会怎样?

MongoDB 表示 Atlas 集群会在集群维护期间自动升级到修复版本。如果项目推迟维护,MongoDB 建议尽快应用升级。

我使用 8.2 分支,它已修复吗?

公告没有列出 8.2,该分支已于 2026 年 7 月 31 日终止支持。公开概念验证报告称,在使用仅测试用设置时 8.2.12 仍会出现该缺陷。请将部署迁移到受支持分支的修复版本。

用 Ostorlab 发现暴露的 MongoDB 成员

Ostorlab 攻击面发现会清点组织中面向互联网的主机和服务。用它列出你暴露的 MongoDB 端口,以便知道先升级或限制哪些成员。这是暴露主机的清单,不是对该 CVE 的检测。

参考文献

  • CVE-2026-118383 记录,MongoDB CNA,2026-11-10 发布,CVSS v4.0 9.5 和 CVSS v3.1 9.0:https://www.cve.org/CVERecord?id=CVE-2026-118383(2026 年 11 月 13 日检查)
  • MongoDB,“Important MongoDB security update available (Action Required) - November 10, 2026”,供应商声明和 Atlas 维护指南:https://www.mongodb.com/community/forums/t/important-mongodb-security-update-available-action-required-november-10-2026/344843(2026 年 11 月 13 日检查)
  • Datadog Security Labs,“CVE-2026-118383: Use-after-free vulnerability in MongoDB”,2026 年 11 月 11 日,复现、崩溃日志和利用条件:https://securitylabs.datadoghq.com/articles/cve-2026-118383-mongodb-server-use-after-free/(2026 年 11 月 13 日检查)
  • 公开概念验证和分析、两个请求的触发方式、waiter 排序循环和修复提交:https://github.com/googlesky/CVE-2026-118383(2026 年 11 月 13 日检查)
  • 修复提交 23dfc542199ab3b88d6a9420b6cd3f125a897620,“SERVER-138175 [v8.0.37-hotfix] Conclude primary catch-up only from a live, current catch-up state”,2026-11-10 合入:https://github.com/mongodb/mongo/commit/23dfc542199ab3b88d6a9420b6cd3f125a897620(2026 年 11 月 13 日检查)
  • 修复提交 6111165c32bfc74f197e2dfeb9480d0b52154d68,“SERVER-138119 [v8.0.37-hotfix] Allow only internal users to use readConcern.afterOpTime”,2026-11-10 合入:https://github.com/mongodb/mongo/commit/6111165c32bfc74f197e2dfeb9480d0b52154d68(2026 年 11 月 13 日检查)
  • MongoDB 8.0.34 源码,src/mongo/db/repl/replication_coordinator_impl.cpp 第 5267 行的易受攻击回调和头文件第 1972 行的 unique_ptr:https://github.com/mongodb/mongo/blob/r8.0.34/src/mongo/db/repl/replication_coordinator_impl.cpp(2026 年 11 月 13 日检查)
  • MongoDB 8.0.37 源码,修复后的回调和共享所有权:https://github.com/mongodb/mongo/blob/r8.0.37/src/mongo/db/repl/replication_coordinator_impl.cpp(2026 年 11 月 13 日检查)
  • MongoDB 下载页面,修复后的 Community Server 构建:https://www.mongodb.com/try/download/community(2026 年 11 月 13 日检查)
  • MongoDB 生命周期日程,8.2 于 2026 年 7 月 31 日终止支持:https://www.mongodb.com/legal/support-policy/lifecycles(2026 年 11 月 13 日检查)
  • Docker Hub,官方 mongo 镜像及拉取次数:https://hub.docker.com/_/mongo(2026 年 11 月 13 日检查)
  • CISA 已知被利用漏洞目录 JSON 订阅源,2026 年 11 月 13 日检查 CVE-2026-118383(未列出):https://www.cisa.gov/sites/default/files/feeds/known_exploited_vulnerabilities.json(2026 年 11 月 13 日检查)
  • The Hacker News,“Critical Pre-Auth MongoDB Flaw (CVE-2026-118383) Can Crash Lagging Servers on Failover”,2026 年 11 月 12 日,Datadog 复现和供应商声明:https://thehackernews.com/2026/11/critical-pre-auth-mongodb-flaw-cve-2026.html(2026 年 11 月 13 日检查)