Git 堆溢出漏洞深度剖析:CVE-2026-105437 三路合并 xdiff 整型溢出根因与应急响应

深度剖析 Git 堆溢出漏洞(CVE-2026-105437):三路合并 xdiff 中 32 位整型溢出导致攻击者可控制堆内存。本文从架构师视角拆解漏洞根因、攻击链路与影响面,提供 size_t 修复方案、conflict-marker-size 临时缓解配置及服务端合并检查加固策略,助你快速完成应急响应与生产环境闭环。

导语:Git 堆溢出漏洞(CVE-2026-105437)是近期开源生态中影响面极广的高危安全问题——攻击者只需推送一个受控仓库并触发合并,即可在服务端造成堆内存越界写入。本文从一线架构师视角,完整拆解该漏洞的根因链路、影响面评估与工业级应急响应方案。

🎯 核心技术Git xdiff 三路合并引擎
⚡ 架构难度资深架构级 (Level 3-4)
🚀 核心收益阻断 RCE 风险 / 服务端合并检查加固
📐 Git 堆溢出漏洞攻击链路与修复执行流水线全景
企业级架构规范

flowchart TD
    subgraph 攻击面 ["攻击者可控输入层 (Attacker Controlled Tier)"]
        A["恶意仓库 .gitattributes"] --> B["conflict-marker-size = 超大正整数"]
        B --> C["小体积文件 + 大量冲突块"]
    end
    subgraph 触发层 ["服务端合并检查触发层 (Trigger Tier)"]
        C --> D["git-merge-tree / git-merge / git-rebase"]
        D --> E["xdiff 三路合并引擎"]
    end
    subgraph 漏洞层 ["整型溢出与越界写入层 (Vulnerability Tier)"]
        E --> F["合并输出总大小累加 (32 位有符号整型)"]
        F --> G["总大小超过 4 GiB 触发整型回绕"]
        G --> H["按回绕后小值分配缓冲区"]
        H --> I["攻击者可控数据越界写入堆内存"]
    end
    subgraph 修复层 ["修复与缓解层 (Mitigation Tier)"]
        I --> J["升级 Git:size_t 计算 + 每次加法溢出检查"]
        I --> K["临时缓解:info/attributes 设置 conflict-marker-size=7"]
        I --> L["关闭不可信仓库服务端合并检查"]
    end
  
图 1:Git 堆溢出漏洞从恶意仓库输入到 xdiff 整型回绕越界写入的完整攻击链路与修复路径

一、漏洞速览:Git 堆溢出漏洞的核心指标

CVE-2026-105437 是一个影响 Git 三路合并代码(xdiff)的高危堆缓冲区溢出漏洞。其 CVSS 评分为 7.5,属于 High 级别。与常见的远程代码执行漏洞不同,该漏洞的触发面非常“安静”——攻击者不需要诱导用户执行任何特殊命令,只需推送一个精心构造的仓库分支并请求合并,即可在服务端触发。

评估维度 详情 架构影响
漏洞编号 CVE-2026-105437 / GHSA-m7r7-8v36-j77r 已公开披露
严重等级 High,CVSS 7.5 需优先处置
漏洞类型 堆缓冲区溢出(32 位整型回绕) 可导致堆破坏
触发入口 git-merge / git-rebase / git-cherry-pick / git-merge-tree 服务端合并检查高危
攻击前提 可推送分支并请求合并(如 PR/MR) 低门槛
修复方式 升级至已修补版本(size_t + 溢出检查) 官方补丁已发布
🚨 严重隐患告警

任何提供 Git 托管服务的平台(GitLab、Gitea、Gerrit 等)如果启用了服务端合并可行性检查(mergeability check),且允许外部用户推送分支并创建合并请求,则默认处于可被攻击状态。攻击者推送的数据量很小,因为超大输出仅在合并过程中动态产生,常规仓库体积审查无法拦截。

二、根因拆解:Git 堆溢出漏洞的 32 位整型回绕链路

要理解这个 Git 堆溢出漏洞,必须深入 xdiff 三路合并引擎的内存分配逻辑。Git 在执行文本三路合并时,会先遍历所有冲突块,累加计算合并输出所需的总缓冲区大小,然后一次性分配该大小的堆内存,最后将合并结果写入其中。

2.1 关键缺陷:总大小使用 32 位有符号整型

问题出在“总大小”这个累加变量上。它被声明为 32 位有符号整型(int),最大只能表示约 2 GiB(2^31-1)。而 conflict-marker-size 属性允许任意正整数,并且每个冲突块会写入多次冲突标记。攻击者通过提交一个包含超大 conflict-marker-size 的 .gitattributes 文件,再构造大量独立冲突块,就能让累加值突破 4 GiB 边界,触发有符号整型回绕为一个很小的值。

conflict-marker-size = 2147483647.gitattributes

2.2 越界写入:小缓冲区承载攻击者可控数据

整型回绕后,Git 按照错误的小尺寸分配堆缓冲区,但后续写入的合并输出仍然是完整的、由攻击者部分控制的数据。这就形成了经典的堆缓冲区溢出:写入量远超分配量,且溢出内容在很大程度上受攻击者控制。最低限度会导致 Git 进程崩溃(DoS),更严重的情况下可造成堆内存破坏,为后续利用链提供基础。

⚠️ 生产避坑风险

不要误以为“只影响客户端”就掉以轻心。Git 托管平台在服务端使用 git-merge-tree 做合并可行性预检时,会直接读取仓库树中的属性(通过 attr.tree 或 --attr-source),这意味着攻击者无需任何交互即可触发服务端溢出。

三、影响面评估:谁需要立即行动

该 Git 堆溢出漏洞的影响面可以从“客户端”和“服务端”两个维度来评估。客户端场景下,攻击者需要诱导受害者对恶意仓库执行合并、变基或拣选操作;服务端场景下,攻击门槛更低,危害也更大。

  • Git 托管平台(最高优先级):使用 git-merge-tree 做服务端合并检查的 GitLab、Gitea、Gerrit、Bitbucket 等平台,任何能创建合并请求的用户均可触发。
  • CI/CD 流水线:自动化流水线中执行 git merge、git rebase 的构建节点,若拉取不可信分支,同样暴露在风险中。
  • 开发者本地环境:克隆并合并不可信仓库时可能触发,主要风险为本地崩溃或堆破坏。
  • 代码审查工具:内部自研的合并预检、冲突检测服务,若直接调用 Git 合并命令,需同步排查。
💡 架构核心决策

对于无法立即升级 Git 的服务端,优先采用“仓库级属性覆盖”作为临时缓解,同时评估关闭不可信仓库的服务端合并检查。两者组合可将攻击面收敛到接近零,为升级窗口争取时间。

四、修复与应急响应:Git 堆溢出漏洞的闭环处置

官方修复方案的核心思路非常清晰:将合并输出总大小的计算类型从 32 位有符号整型改为 size_t,并在每一次加法运算后检查是否发生溢出。一旦检测到溢出,Git 直接报错退出,而不是继续分配和写入。这是处理整型溢出类漏洞的标准工程范式。

4.1 首选方案:升级至已修补版本

最彻底的处置方式是升级 Git 至包含该补丁的版本。升级后,所有三路合并路径(merge、rebase、cherry-pick、merge-tree)均受到保护。建议在升级后对服务端合并检查链路做一次回归验证。

点击展开:Git 升级与版本验证命令
# 查看当前 Git 版本
git --version

# Debian/Ubuntu 系升级
sudo apt-get update && sudo apt-get install --only-upgrade git

# RHEL/CentOS 系升级
sudo yum update git

# 验证升级后版本
git --version

# 回归验证:对含大量冲突的仓库执行合并预检
git merge-tree --write-tree HEAD origin/target-branch

4.2 临时缓解:仓库级属性覆盖

对于暂时无法升级 Git 的服务端,可以通过在每个仓库的 info/attributes 文件中写入 conflict-marker-size=7 来覆盖仓库树内 .gitattributes 的任何设置。由于 info/attributes 的优先级高于树内属性文件,攻击者提交的恶意配置将失效。

* conflict-marker-size=7info/attributes
点击展开:批量写入 info/attributes 缓解配置脚本
#!/usr/bin/env bash
# 对所有裸仓库批量写入 conflict-marker-size=7 缓解配置
REPO_ROOT="/var/lib/git/repositories"

find "$REPO_ROOT" -maxdepth 2 -name "*.git" -type d | while read -r repo; do
  attr_file="$repo/info/attributes"
  mkdir -p "$repo/info"
  if ! grep -q "conflict-marker-size=7" "$attr_file" 2>/dev/null; then
    echo "* conflict-marker-size=7" >> "$attr_file"
    echo "[OK] 已写入缓解配置: $attr_file"
  else
    echo "[SKIP] 配置已存在: $attr_file"
  fi
done

4.3 兜底策略:关闭不可信仓库的服务端合并检查

如果既无法升级也无法批量写入属性文件,最后的兜底手段是关闭服务端对不可信仓库的合并可行性检查。这会影响合并请求的预检体验,但能彻底阻断服务端触发路径。待升级完成后应尽快恢复该功能。

五、架构师视角的长期加固建议

Git 堆溢出漏洞再次提醒我们:处理外部可控输入时,任何尺寸计算都必须使用无符号且足够宽的类型,并在每次累加后做溢出检查。这不仅是 Git 的问题,也是所有解析器、合并引擎、序列化框架的通用安全准则。

  • 输入尺寸边界校验:对所有来自仓库属性、配置文件的数值型参数设置合理上限,避免“任意正整数”直接参与内存分配计算。
  • 服务端合并检查隔离:将合并可行性检查放入受限沙箱或独立低权限进程,限制堆破坏后的影响半径。
  • 依赖安全监控:将 Git 等基础工具纳入 SBOM 与漏洞情报订阅范围,确保类似 CVE 能在第一时间触达运维团队。
  • 不可信仓库分级:对来自外部贡献者的仓库启用更严格的资源限制与属性白名单策略。
💡 架构核心决策

安全修复不是“升级完就结束”。建议在升级后补充一条针对合并路径的模糊测试用例,持续覆盖超大 conflict-marker-size 与大量冲突块的组合场景,防止同类问题回归。

原文出处与权威溯源声明:
本文核心技术背景源自 GitHub Advisory Database 官方安全公告:
GHSA-m7r7-8v36-j77r / CVE-2026-105437 (GitHub Advisory Database)

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注