04. 插件安全
翻译说明: 本页是与 英文源规格 一一对应的机器辅助翻译。代码、协议字段和标识符保持原文;如翻译与英文源事实有歧义,以英文版本为准。
1. 威胁模型
插件可能来自:
- 用户自行开发
- 同事分享
- 未来市场中的第三方
主要风险: 1.恶意文件read/write 2、恶意命令执行 3.窃取API密钥/会话内容 4. 劫持代理工具 5. 通过用户界面进行网络钓鱼
2. 默认拒绝原则
- 未声明的权限=不可用
- 禁用插件 = 代码未加载
- 未经确认的高风险行动=未执行
- 主机 API 不在允许名单上 = 不存在
3. 隔离策略
必须
1.插件UI与宿主UI DOM隔离 2. 插件不能直接请求主机模块 3.秘密商店不对插件开放 4.插件私有数据目录与主机核心库分离
目标
1.插件main在单独的进程中运行 2. 碰撞隔离 3.资源限制(后来:CPU/memory/timeout)
3. 1 贡献主题CSS
主题贡献 (ui.theme) 是插件创作内容的一种情况 在主机渲染器内部运行,因此它会在主进程中穿过消毒剂 在发送到 UI 之前:
- 拒绝:
@import、任何不是data:的url()目标 URI、url(解析器无法解析javascript:、expression(和标记序列 (<style、</style、<!--);空纸也会被拒绝 - 每个文件上限为 256KB,每个插件 8 个主题
- CSS 在加载时从磁盘读取并通过 IPC 整体交付;的 渲染器将其注入到附加在后面的单个专用
<style>元素中 应用程序自己的样式表,因此它可以覆盖令牌但从不注入标记 - 选择主题是一个设置值(
plugin:<pluginId>:<themeId>);如果 如果插件被禁用或卸载,设置将回退到system
CSS 无法脚本化,但它可能会产生误导:主题仍然是第三方代码塑造 用户看到的内容,这就是为什么它是声明的、可撤销的权限。
4. 权限授予用户体验
在 install/load 时间,显示:
- 权限列表
- 风险描述
- 开发者信息
- 源路径
用户操作:
- 接受并启用
- 取消
首次使用高风险的 API 可能会再次确认。
5. 数据隔离
插件可以访问:
- 他们自己的设置
- 他们自己的数据路径
插件无法访问:
- 其他插件的数据
- 主机秘密
- 主机的完整会话数据库(除非将来存在受控的 API)
5. 1 插件间消息总线
总线是两个插件之间的唯一通道,并且故意狭窄:
- 双方在清单中声明其流量 -
bus.publish列出了具体的流量 主题,bus.subscribe列出了模式 - 经纪人拒绝任何内容 即使获得许可也未声明 - 路由完全存在于主机中;订户永远不会知道还有谁 订阅,发布者被排除在自己的扇出之外
- 消息仅携带
topic、from、payload和主机分配的at - 上限:每个有效负载 64KB,每个插件 16 个订阅,每个滚动 100 个发布 10秒窗口;超上限调用失败并显示
LIMIT_EXCEEDED/RATE_LIMITED与主题一起审核 - 有效负载是数据,而不是能力:接收消息并不授予任何功能 订户还没有
将主题视为应用程序内的公共主题:任何可以声明匹配的插件 模式并按住 bus.subscribe 就会看到它。不要在公交车上泄露秘密。
6. 路径安全
对于 fs.*:
- 仅工作区相对路径
- 归一化+根边界
- 拒绝绝对路径和转义
7. Agent 安全性
- 插件工具名称采用命名空间,以避免使用冻结强制前缀
plugin_<pluginIdSafe>_<toolName>(D015) 发生冲突 - 工具执行超时
- 用户可以一键禁用工具
- 提示注入 API 默认情况下是高风险的,需要显式许可
7. 1 到达代理的技能和 MCP 工具
两个表面都可以让插件改变代理知道或可以做的事情,所以两者都是 在到达模型之前有界:
技能 (agent.prompt.inject) — 系统提示符仅携带目录 (id、名称、一行描述,上限为 240 个字符);按需读取正文 通过内置的 Skill 工具。一个插件最多可以教授 32 个技能,每个技能 文档最多 128KB。未经许可,技能将被简单地跳过: 清单仍然有效,没有任何提示。
MCP 工具 (mcp.server.local / mcp.server.remote) — 已发现的工具是 与手写插件工具注册在相同的 plugin_* 命名空间下 因此继承工具超时、审计跟踪和每个插件禁用 转变。它们始终在 risk: "medium" 处注册:它们的架构和 描述来自第三方服务器,因此主机无法信任 自我声明的风险水平。每个服务器最多 64 个工具,每个插件最多 8 个服务器。
Plan 是代理工具的附加主机策略边界:
- Plan 中没有可见或可执行的插件工具;
- 拒绝先于明显风险、declared/granted 权限、会话 grants,以及
auto权限模式; - 直接伪造的
tools.execute调用返回PLUGIN_DISABLED_IN_PLAN并且是 已审核;它不会转发到插件运行时; - 插件命令和面板仍可用作显式用户 UI 操作, 但它们不能成为模型可调用的 Plan 工具或默默地改变 Plan 状态。
8. 网络和外部链接
- 默认情况下不授予
net.fetch openExternal应确认- 禁止插件静默下载和执行二进制文件(MVP 中根本没有这样做)
8. 1 MCP 服务器出口和凭证
MCP 服务器是 net.fetch 旁边的第二个出口路径,因此它是声明性的 并且是可审查的而不是编程的——插件无法打开连接 清单未命名:
transport: "stdio"生成本地可执行文件 (mcp.server.local)。的command必须是裸路径名称或插件相对路径;绝对路径 在验证时被拒绝。孩子得到的环境是最小的——只有 声明的env条目加上主机运行进程所需的内容。transport: "http"到达远程端点 (mcp.server.remote)。url必须为https,除非主机环回。工具参数离开机器, 这就是为什么许可副本如此明确地说。env和headers值仅通过插件自己的设置进行解析{ "setting": "<key>" }。宿主环境永远不会被穿越,并且 清单中的字面秘密是审查气味,而不是受支持的模式 (D018)。- 连接预算:完成
initialize需要 10 秒,每个tools/call需要 100 秒,8tools/list页,每条 stdio 线 4MB。服务器连接缓慢且撕裂 当插件卸载或禁用时关闭。
9. 审计和应急响应
用户应该能够:
- 查看插件权限
- 查看插件错误日志
- 一键禁用
- 一键卸载
主机应该能够:
- 出现异常时自动禁用插件
- 保证主应用程序可以启动
10. 安全验收
1.没有fs.write.workspace权限,写入文件失败 2、没有fs.delete.workspace权限删除文件失败,并且永远不会递归删除 3.禁用插件后,其工具不再可见 4. 插件无法读取 API 键 5.插件面板无法调用任意主机IPC 6.插件未捕获的异常不会导致应用程序退出 7. 带有 @import 或远程 url() 的主题 CSS 文件被拒绝,并禁用 提供的插件将应用程序返回到 system 主题 8. 发布到未声明的主题失败,发布者永远不会收到它的消息 自己的留言 9. 使用绝对 command 或普通 http 远程声明的 MCP 服务器 url 清单验证失败 10. 低风险或授予的插件工具在 Plan 中仍然无法关闭
11. 实施情况
目前执行情况:
PluginRuntime中的默认拒绝权限检查 2.插件fs API的工作空间路径边界检查 3.面板窗口使用沙盒preload+隔离会话分区- 插件仍然无法访问 Secrets/host DB
- Marketplace/package 安装需要在 UI 中明确接受权限 6.自动更新拒绝静默权限扩展
- 插件主程序在每个插件专用的
utilityProcess(ADR 0008) 中运行,并带有 最小环境;所有pi.*调用都跨越白名单 + 权限网关 在主机中,插件崩溃只会破坏该插件 - 贡献的主题 CSS 在到达主进程之前会在主进程中进行清理 渲染器(§3.1)
- 总线路由由主机拥有,并具有声明的主题和硬上限(§5.1)
- MCP 服务器仅从以下位置声明、权限控制和提供凭证: 插件设置(§8.1)
尚未强制执行:
- 插件进程内的功能沙箱(Node 内置插件可访问) 那里,所以
fs.*权限门插件 API,而不是进程) - CPU/内存限制
- 签名验证(仅对包进行 sha256 检查)
- 声明的清单权限在加载时自动授予