aj2108/CVE-2026-9811
GitHub: aj2108/CVE-2026-9811
该项目披露了 Mautic 7 Project Selector 组件中因 AJAX 返回数据未经 HTML 编码而导致的存储型 XSS 漏洞(CVE-2026-9811),并提供了完整的攻击链分析与修复方案。
Stars: 0 | Forks: 0
# CVE-2026-9811
CVE-2026-9811 是一个存储型跨站脚本攻击(Stored XSS)漏洞,影响 Mautic 7(7.0.0 至 7.1.1 版本)。该漏洞存在于 Project Selector 组件中,通过 AJAX 请求返回的项目名称在未经适当输出编码或净化的情况下被插入到页面中。拥有创建项目权限的已认证用户可以在项目名称中存储恶意的 JavaScript payload。当其他管理员随后打开包含该项目选择器的实体编辑器时,恶意脚本就会在其浏览器中执行。
受影响软件
属性 值
产品 Mautic
受影响版本 7.0.0 – 7.1.1
修复版本 7.1.2
组件 Project Selector
漏洞类型 存储型跨站脚本攻击 (XSS)
漏洞类型
类别:存储型跨站脚本攻击(Stored XSS)
CWE-79:网页生成时对输入的不当中和处理(“跨站脚本攻击”)
根本原因
应用程序存储由已认证用户提供的项目名称,随后通过 AJAX 端点检索这些名称。在渲染项目选择器时,应用程序直接将这些值作为 HTML option 元素插入到 DOM 中,而没有对内容进行转义或净化。
概念说明:
用户创建项目
│
▼
项目名称存储在数据库中
│
▼
AJAX 返回项目名称
│
▼
未经净化直接插入到 DOM 中
│
▼
浏览器执行内嵌的 JavaScript
由于应用程序信任存储的数据,因此每当其他特权用户加载易受攻击的页面时,恶意的 JavaScript 就会执行。
攻击流程
攻击者
│
▼
创建一个以恶意 JavaScript payload 为名称的项目
│
▼
Payload 存储在数据库中
│
▼
管理员打开实体编辑器
│
▼
AJAX 请求检索项目名称
│
▼
应用程序未经编码直接将项目名称插入到 DOM 中
│
▼
浏览器执行恶意脚本
│
▼
攻击者在管理员的会话中获取操作权限
攻击场景
拥有创建项目权限的攻击者创建了一个名称中包含恶意 JavaScript payload 的项目。
随后,管理员编辑另一个包含 Project Selector 的实体。该选择器通过 AJAX 加载项目名称并直接将其插入到页面中。由于项目名称未被净化,浏览器将以管理员的权限执行内嵌的脚本。
# 示例
第 1 步:正常的项目创建
假设 Mautic 有这样一个表单:
POST /projects/create HTTP/1.1
Content-Type: application/x-www-form-urlencoded
projectName=Marketing Campaign
description=Email Campaign
该项目被保存为:
Marketing Campaign
第 2 步:攻击者创建项目
攻击者没有输入正常的名称,而是输入了包含无害 JavaScript 事件的 HTML:
POST /projects/create HTTP/1.1
Content-Type: application/x-www-form-urlencoded
projectName=
description=Test
数据库现在准确无误地存储了该字符串。
第 3 步:AJAX 返回存储的值
随后,管理员打开一个加载项目的页面。
AJAX 响应:
{
"id": 7,
"projectName": "
"
}
第 4 步:存在漏洞的 JavaScript
假设应用程序执行了以下操作:
const project = response.projectName;
document.getElementById("projects").innerHTML +=
``;
浏览器看到的内容:
由于应用程序将该字符串作为 HTML 而不是文本插入,浏览器将其解析为实际的 `
` 元素。图像加载失败(`src="x"`),导致 `onerror` 处理程序执行。
影响
成功利用此漏洞可能会使攻击者:
在其他用户的浏览器中执行任意 JavaScript。
劫持管理员的会话。
代表管理员执行操作。
访问敏感的仪表板信息。
使用受害者的权限修改应用程序数据。
该漏洞主要影响机密性和完整性。
严重程度
指标 分数
CVSS v3.1 (CNA) 5.4 (Medium)
NVD 尚未发布针对此 CVE 的 CVSS 评估。
概念性漏洞代码
注意:供应商尚未发布确切的漏洞源代码。以下示例仅用于说明漏洞模式。
// 从 AJAX 返回的数据
const project = response.projectName;
// 不安全:直接插入到 DOM 中
document.getElementById("projectSelector").innerHTML +=
``;
为什么存在漏洞
项目名称源自用户输入,但在插入页面时未进行 HTML 编码。如果存储的值包含 HTML 或 JavaScript,浏览器会将其解释为可执行内容,而不是纯文本。
修正后的代码(概念性)
const option = document.createElement("option");
// 安全:作为文本而非 HTML 赋值
option.textContent = response.projectName;
document.getElementById("projectSelector").appendChild(option);
或者,如果无法避免 HTML 输出,请确保在插入前进行适当的输出编码。
此修复方案为何有效
使用 `textContent`(或等效的安全 API)可确保任何特殊字符都被视为纯文本,而不是可执行的 HTML 或 JavaScript。即使数据库中存储了恶意的项目名称,它也将按字面意思显示,而不会被执行。
标签:Mautic, Web安全, 多模态安全, 数据可视化, 漏洞分析, 蓝队分析, 跨站脚本攻击, 路径探测