Skip to content

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 列出了模式 - 经纪人拒绝任何内容 即使获得许可也未声明
  • 路由完全存在于主机中;订户永远不会知道还有谁 订阅,发布者被排除在自己的扇出之外
  • 消息仅携带topicfrompayload和主机分配的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,除非主机环回。工具参数离开机器, 这就是为什么许可副本如此明确地说。
  • envheaders通过插件自己的设置进行解析 { "setting": "<key>" }。宿主环境永远不会被穿越,并且 清单中的字面秘密是审查气味,而不是受支持的模式 (D018)。
  • 连接预算:完成 initialize 需要 10 秒,每个 tools/call 需要 100 秒,8 tools/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. 实施情况

目前执行情况:

  1. PluginRuntime 中的默认拒绝权限检查 2.插件fs API的工作空间路径边界检查 3.面板窗口使用沙盒preload+隔离会话分区
  2. 插件仍然无法访问 Secrets/host DB
  3. Marketplace/package 安装需要在 UI 中明确接受权限 6.自动更新拒绝静默权限扩展
  4. 插件主程序在每个插件专用的 utilityProcess (ADR 0008) 中运行,并带有 最小环境;所有 pi.* 调用都跨越白名单 + 权限网关 在主机中,插件崩溃只会破坏该插件
  5. 贡献的主题 CSS 在到达主进程之前会在主进程中进行清理 渲染器(§3.1)
  6. 总线路由由主机拥有,并具有声明的主题和硬上限(§5.1)
  7. MCP 服务器仅从以下位置声明、权限控制和提供凭证: 插件设置(§8.1)

尚未强制执行:

  • 插件进程内的功能沙箱(Node 内置插件可访问) 那里,所以 fs.* 权限门插件 API,而不是进程)
  • CPU/内存限制
  • 签名验证(仅对包进行 sha256 检查)
  • 声明的清单权限在加载时自动授予

为本地优先开发而构建。