系统:运行中
← 返回所有攻击
INFRASTRUCTURE CRITICAL NEW

RAGFlow CVE-2026-45312:一个会执行系统命令的提示词模板

RAGFlow 提示词生成器中的 Jinja2 模板注入,把用户可控字段变成服务器端 RCE。CVSS 9.9,于 2026 年 5 月 9 日披露。

2026-06-20 // 6 min affects: ragflow

这是什么?

CVE-2026-45312 是 RAGFlow 中的一个远程代码执行漏洞。RAGFlow 是部署最广泛的开源 RAG(检索增强生成)引擎之一。该漏洞由 Verichains 的 Yuu(VNUHCM-UIT) 报告,并在 2026 年 5 月 9 日发布的厂商公告 GHSA-wpg4-h5g2-jxm6 中披露;CVE 记录于 2026 年 5 月 29 日进入 NVD。它影响 RAGFlow 0.24.0 及更早的版本,CVSS 评分为 9.9AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H),归类为 CWE-1336,即服务器端模板注入。

这个漏洞是这类产品反复犯下的同一个错误的教科书案例:提示词模板被当作代码渲染。一个看起来像配置的字段被直接送入模板引擎,而该引擎是图灵完备的。

工作原理

RAGFlow 用 Jinja2 构建部分提示词。rag/prompts/generator.py 中的提示词生成器在创建环境时关闭了沙箱:

# rag/prompts/generator.py — 未沙箱化的环境
PROMPT_JINJA_ENV = jinja2.Environment(autoescape=False, trim_blocks=True, lstrip_blocks=True)

随后一个辅助函数会把用户提供的文本通过该环境进行渲染:

def citation_prompt(user_defined_prompts: dict = {}) -> str:
    template = PROMPT_JINJA_ENV.from_string(
        user_defined_prompts.get("citation_guidelines", CITATION_PROMPT_TEMPLATE))
    return template.render()

citation_guidelines 的值并不是开发者常量,而是从 LLM 组件 sys_prompt 中的 <CITATION_GUIDELINES> XML 标签里取出的——这是用户通过 RAGFlow 的 Canvas 工作流 DSL 完全可控的参数。由于 RAGFlow 默认开启自助注册,并允许任何已登录用户保存任意 Canvas,因此一个普通的低权限账户就足够了

只有当引用功能开启(cite=True,默认值)存在检索片段时,渲染才会触发。研究者的攻击链用一个 DuckDuckGo 搜索节点来提供这些片段,因此不需要任何嵌入模型,也不需要供应商 API 密钥。结果是:放入提示词字段的字符串在服务器端被求值,一个遍历 Python 对象图的 Jinja2 表达式触及 os 并在 RAGFlow 进程中执行 shell 命令。公开公告中的概念验证把 id 的输出写入磁盘以确认代码执行——在其实验室运行中,身份为 root

载荷本身就是经典的 Jinja2 SSTI 沙箱逃逸惯用法(遍历 __globals__ / __builtins__ 以导入 os),因此我们在此不复现可用的代码行——要吸取的是这个模式,而不是那串字符。一份同源公告 GHSA-vvwj-fvwh-4whx 报告了 RAGFlow 智能体文本处理组件中同一类 SSTI,这表明问题是系统性的,而非个例。

为什么重要

RAG 服务器是高价值目标。它通常存有供应商 API 密钥、数据库凭据以及组织已摄入的文档——正是攻击者想要的东西。把一个自助式提示词字段变成主机 RCE,会让整个信任边界崩塌:一个低权限用户(或任何能注册的人)就能在服务器上下文中获得代码执行,并由此触及其机密和网络位置。

更深层的要点远超 RAGFlow。提示词模板就是代码,用户输入绝不能成为模板本身。 许多 LLM 产品把 system_promptcitation_guidelines 或人设字段当作无害文本,再交给 Jinja2、f-string 或 format() 去填充变量。一旦不可信内容能够定义模板而非仅仅定义其中的值,你就有了 SSTI——这正是 Web 框架十年前学到的同一个漏洞,如今又从 AI 工具层重新进入。

防御

绝不要把不可信输入当作模板渲染。 把用户可控的提示词字段严格视为数据:以渲染变量的方式传入(template.render(guidelines=user_text)),绝不作为模板源。如果必须接受模板片段,那么该输入就是特权输入,必须相应地加以管控。

如果确实要做模板化,就要沙箱化。 使用 Jinja2 的 SandboxedEnvironment(或 ImmutableSandboxedEnvironment),它会阻止访问 dunder 属性和不安全的可调用对象。未经沙箱化的 Environment().from_string(user_input) 是一个 RCE 原语,而不是便利功能。

隔离工作进程。 以非特权用户身份在容器中运行 RAG/智能体进程,默认禁用出站网络,使用只读文件系统并丢弃 capabilities,使得一次成功注入也无法触及元数据端点、凭据或更广的网络。

收紧注册与 DSL 的攻击面。 在可从互联网访问的实例上禁用开放的自助注册,要求真正的权限才能定义或修改工作流 DSL,并对允许的组件采用白名单,而不是加载任意图。

打补丁并盘点资产。 RAGFlow ≤ 0.24.0 受影响;请关注项目的安全公告并升级到最新的修复版本。然后找出你暴露在外的实例——一个 RAG 引擎不应在默认开启注册的情况下暴露在公网上。

状态

项目详情
CVECVE-2026-45312(GHSA-wpg4-h5g2-jxm6)
受影响RAGFlow ≤ 0.24.0
严重性9.9 CVSS v3.1;CWE-1336(SSTI)
是否需要认证是——任意低权限用户(默认开启自助注册)
攻击向量经 Canvas DSL 在 citation_prompt() 中的 Jinja2 SSTI → RCE
报告者Yuu(anzuukino),VNUHCM-UIT / Verichains
公告发布2026 年 5 月 9 日(CVE 于 5 月 29 日进入 NVD)
相关GHSA-vvwj-fvwh-4whx(智能体文本处理组件中的 SSTI)

Sources