Notarium文档
文档版本: latest

安全与可见性

让 agent 直接访问存储引擎,等于凑齐了「致命三要素」:私有数据 × 不可信的笔记内容 × 对外通道。任何一个维度单独存在都无害,但三者合流,笔记里的一次注入就能把你的数据带出门外。Notarium MCP 网关从构造层面斩断每一个维度——靠的是设计,而不是配置。这不是一层图方便的封装,而是一道信任边界。

从构造上斩断三要素

  • 没有对外通道。 每个工具都带有 openWorldHint:false——没有工具能触达网络。空间之间既不能搬运也不能复制,内部数据外泄同样被堵死。数据无处可带。
  • 不可信内容被拆除。 服务端的指令是静态的,从不与笔记内容混合:笔记里的任何东西都不会被塞进工具描述,也不会被塞进服务端的 instructions。这样一来,笔记正文里的注入永远变不成对 agent 的命令。
  • 破坏性操作始终可逆。 delete_note 把笔记送进回收站;恢复它、以及彻底清除,都由来做,而非 agent。这就是「agent 不做任何不可逆之事」这条底线。

每次调用都校验权限

权限会校验两次。首先,tools/list 会按令牌的权限上限过滤——read 令牌根本看不到写入类工具。然后,每次 tools/call 还会额外校验对具体空间的访问权(can(principal, action, {space}))。权限公式为 effective = scopes(token) ∩ grants(principal):令牌的作用域(其动作上限)与在各空间中的实时成员资格取交集。撤销一项授权会立刻收窄令牌。

管理类动作(签发令牌、管理成员)位于 write 之上——一个泄露的 write 级令牌既签发不了新令牌,也授不出访问权。

拒绝 = 404,而非 403

访问被拒时返回的是 404(「查无此物」),而非 403(「不允许」)。这样就无法通过响应码来枚举,在你获授的权限之外还存在哪些笔记或空间。别人的空间从根本上就无法触达,与一个不存在的空间毫无区别。

flowchart TD
  call[tools/call] --> listed{工具在令牌<br/>权限上限内?}
  listed -->|否| gone[工具不出现在 tools/list]
  listed -->|是| acl{can principal,<br/>action, space?}
  acl -->|否| notfound[404 · 反枚举]
  acl -->|是| exec[执行 · 溯源写入日志]

拆除不可信内容

发给 agent 的一切——title、snippet、content、frontmatter——在发送前都会被清洗:伪控制标签(<system><instructions> 及类似标签)的尖括号会被拆除。有人在里面写下「系统指令」的笔记,抵达 agent 时是一段普通文本,而非一条命令。

编辑历史可见

每次编辑都会把是谁改的——某个具体的人或 agent——记入编辑历史get_noterecall 能返回是谁编辑了笔记:是人还是 agent,具体是哪一个。经由 agent 的注入,始终可见、可追溯。

这在实践中意味着什么

即便一个 agent 被提示词彻底攻陷,它仍被自己的令牌所限:它触达不了网络,够不到别的空间,做不出不可逆的删除,也给不了自己权限。它能造成的最坏后果,不过是在自身权限范围内做一次可逆的编辑,且在日志中留有完整溯源。

边界:不做 E2EE

Notarium 刻意不做端到端加密。一个聪明的服务端——搜索、语义、历史、agent——需要访问明文。这里的隐私建立在自托管与拥有自己的文件之上,而非建立在 E2EE 之上。网关的威胁模型防的是被攻陷的 agent,而不是被攻陷的主机——反正你的文件本来就已经托付给它了。

下一步

  • 接入 agent —— 令牌、权限,以及 OAuth 门面。
  • 检索审计 —— 对 agent 检索了什么的可观测性。
  • 意图工具 —— 工具集为何恰恰是这些。