flawopen.com/Incidents/gitlab-commits-api-path-traversal-september-2026
●
GitLab · CVE-2026-85706 · September 2026 · CVSS 10.0 · 严重
安全研究 · FlawOpen
CVE-2026-85706:GitLab服务器文件泄露
GitLab上传解析器允许未认证请求选择服务器文件;无效转义可使片段出现在错误中。文件选择与内容泄露是不同阶段,需分别评估。[1], [3]
💡 通俗易懂的原理解析 (ELI5)
想象接待员本应处理收件盘里的文件,却接受访客手写的柜子位置。还没查验通行证,他就打开那个柜子;如果读不懂某一行,还会在报错时大声复述。擅自打开是一处失误,复述内容是另一处。[1]
核心概念与专有名词
Upload metadata- 请求提供的 file.path 或 metadata.path 不应替代可信上传中间件登记的缓冲区。[1]
Percent decoding- 表单解析会解码 % 后跟两个十六进制数字的序列;无效序列可能在报错中包含出错片段。[1]
CWE-22 / CVSS- CNA 将
CVE-2026-85706定为路径遍历,CVSS 10.0 严重;被跨越的边界是由请求方选择服务器文件。[3]
框架映射
- 本指南所述弱点的 CWE 参考: CWE-22
- CISA KEV — 收录日期 2026-09-11 — CVE-2026-85706
事件演进时间线
2026-09-10
GitLab 发布了 19.1.8、19.2.6 和 19.3.2 修复版本。[2]
2026-09-23
发布公告后来补充了 18.11.12 与 19.0.9 的回移修复。[2]
攻击执行流程分解
源代码对比:漏洞与安全实现
这是 Python 教学模型,并非 GitLab 源码或补丁。脆弱示例只使用内存缓冲区,并把任意 % 都视为错误;它不模拟真实的百分号校验或片段选择。强化版先认证,拒绝路径元数据,只接收可信上传系统登记的字节,限制大小并返回通用错误。仍须安装厂商更新:若较早的中间件已经读了文件,只在路由中认证就太晚了。[1]
存在漏洞的实现
from urllib.parse import unquote_to_bytes
def parse_upload(authenticated, metadata, buffers):
# 无害的内存中测试数据;不会访问文件系统。
body = buffers.get(metadata.get("path"), b"")
if b"%" in body:
return 400, body.decode("ascii", errors="replace")
if not authenticated:
return 401, "Unauthorized"
return 200, unquote_to_bytes(body)
加固后的安全修复
from urllib.parse import unquote_to_bytes
MAX_BYTES = 4096
HEX = frozenset(b"0123456789abcdefABCDEF")
def parse_upload(authenticated, metadata, registered_body):
# registered_body 来自可信的上传中间件,
# 而不是请求参数选择的路径。
if not authenticated:
return 401, "Unauthorized"
if metadata or type(registered_body) is not bytes:
return 400, "Invalid upload"
if len(registered_body) > MAX_BYTES:
return 413, "Upload too large"
for i, byte in enumerate(registered_body):
if byte == 37 and (i + 2 >= len(registered_body) or
registered_body[i+1] not in HEX or
registered_body[i+2] not in HEX):
return 400, "Invalid upload"
return 200, unquote_to_bytes(registered_body)
工程与系统安全加固清单
- ✓升级到受支持的修复版本。各分支最低版本为 18.11.12、19.0.9、19.1.8、19.2.6、19.3.2;受影响版本从 18.7 开始。按厂商公告核对实际版本。[2], [3]
- ✓用无害的内存标记测试匿名请求:认证前不得查找缓冲区,响应和普通日志中不得出现标记。解析前拒绝路径元数据。[1]
- ✓保存 Rails API 和 Workhorse 日志;通过
correlation_id关联记录,再比较api_error与written_bytes。检查解码后的 file.path 与 metadata.path,而不是因为同一日志行有正常上传路径就整行排除。 读取文件本身并不能证明内容已泄露:GitLab 指出,api_error 中反射出的片段并经 Workhorse 的 written_bytes 印证,才表明字节已发送给客户端;HTTP 状态码本身不能定论。[1] - ✓仅轮换已确认或有合理依据怀疑泄露的凭据。如果可能涉及
db_key_base或otp_key_base,请先咨询 GitLab 支持:GitLab 表示目前没有受支持的db_key_base轮换路径,并警告不受支持的密钥轮换可能导致数据丢失。缺少日志并不能证明没有泄露。[1]