feat(mcp): MCP Gateway 注入宿主可信调用身份 - #917
Conversation
|
感谢这个 PR,把 Data MCP 的身份从「模型可见参数」收敛到 Botmux 可信 turn 通道、用飞书盖章的 open_id/union_id 做信任根、并做 fail-closed,这个方向是对的,代码组织和测试覆盖也很用心(本地 不过在自动化复核里发现 3 个建议在合入前先解决的问题(附实际验证): 1)可信身份文件在同一 OS 用户下可被模型进程改写(最关键) 2)ksher 专属 MCP 被无条件注入进公共 Codex 适配器 3) 另外几个非阻断的小项: 以上是自动化评审的初步意见,可能有理解偏差,最终以维护者审阅为准。辛苦啦 🙏 |
|
已按自动化复核意见补充修复,并同步合并最新
本次针对 review 中提到的阻断项做了以下处理: 1. 移除同 UID 可改写的 trusted-turn 文件链路认可 review 中关于 已处理:
2. 移除公共 Codex adapter 中的私有 MCP 默认注入认可 review 中关于公共 npm 包不应无条件注入租户私有 MCP 的意见。 已处理:
3. 收紧 metadata query 默认发布边界认可 review 中关于 SQL guard 不能只靠正则补洞的意见。当前先把该 host 命令改成默认关闭,避免公共发布时暴露高风险查询入口。 已处理:
4. 额外清理
验证已在本地执行并通过:
另外已复查以下关键字在
当前页面还显示 |
|
感谢快速跟进,也认可这版按 review 意见做的收敛( 不过基于当前形态,想和你同步一个架构层面的建议:与其把这套能力以「收敛后默认关闭」的形式并入主线,不如按 Botmux 既有的插件 + MCP Gateway机制重做——这样能力更内聚、复用性更好,也不需要往公共代码路径塞任何租户专属内容。具体: 1)业务能力做成一个 Botmux 插件(而非进主线)
如果这套具备通用性,还可以按官方 2)唯一值得进主线的通用原语:Gateway 的「按 turn 注入宿主可信身份」 这样拆分后:通用侧只多一个「per-turn 身份注入」能力,租户专属的 Data MCP + 查询/导出/审批流程作为独立插件维护,主线保持干净。 以上是自动化评审的初步意见,可能有理解偏差,最终以维护者审阅为准。这版本身安全面已经干净、且默认关闭,是否直接合入、还是按上面思路重做,请维护者定夺。辛苦! |
|
本次已按 review 建议把主线收敛为 Gateway 通用可信身份注入,Data MCP 业务能力已拆到私有插件骨架,不进入 botmux 公共主仓。 |
|
已按插件化方向继续调整:
验证:
|
|
感谢采纳上一轮的架构建议,这版 已正确解决的(赞)
建议合入前再修一处(附实跑验证) 🔴 Gateway 注入身份时没有清理「客户端自带的身份」。之前那版(已删)的 stdio 代理会在注入前无条件删掉客户端传来的身份字段(
建议修法:在注入前无条件删除 🟡 metadata query 的 SQL 校验仍有几处可绕过(非阻断,因为该命令默认关闭,但任何环境启用前应一并收紧):
建议:FROM 段出现任何 验证: |
|
已采纳并修复这条 strip 反馈。Gateway 现在会在注入前无条件剥离模型侧传入的 botmux 保留身份字段:_meta 中所有 botmux* 键会先被清理,再写入宿主侧可信的 botmuxTrustedCaller;无宿主身份时也不会把模型伪造的 botmuxTrustedCaller 下传给插件。HTTP transport 同样会先清理 x-botmux-trusted-*、x-botmux-turn-id、x-botmux-dispatch-attempt,再按宿主身份重建。已补回归用例覆盖无宿主身份伪造、有宿主身份 sibling 键伪造,以及 HTTP header 伪造清理。实跑验证:git diff --check、pnpm build、pnpm test -- plugin-mcp-gateway plugin-mcp-sandbox worker-durable-expiry-order raw-input-followup-atomicity 均通过,其中 62 passed、3 skipped。metadata query 相关反馈当前已不适用,因为该命令和 SQL guard 已从 botmux 主线 PR 中移除。 |
说明 Gateway 注入的可信身份出现在 _meta.botmuxTrustedCaller 与 x-botmux-trusted-* 头, 插件只应读取 botmux 命名空间键(注入前无条件剥离客户端自带同名键,模型无法伪造), 缺身份时须 fail-closed,身份仅存于宿主进程内存不落文件。中英文档同步。 Co-Authored-By: Claude <noreply@anthropic.com>
440c213 to
ea6d820
Compare
#917 给 fixture echo 回显加了 :meta={} 段,同步改了 gateway 测试却漏改 sandbox 测试,其整段连续子串断言被切断导致 Linux CI 红(该文件仅在 Linux+bwrap 跑,macOS 本地 skip)。本 PR 将断言拆成两段 toContain 对齐 gateway 写法,不改运行时,也不放宽 token 不进沙箱的隔离断言。 验证:master CI 红点字节级坐实为该两条 sandbox 用例(17176 passed/2 failed);PR head CI 上 sandbox 用例真跑非 skip 全过(17178 passed/0 failed,零回归);全仓排查确认无第二处同类漏改;反向变异确认 token 泄漏/session 串错/args 篡改/服务器冒充下新断言仍失败,安全语义完整。
改动内容
tools/call时注入到_meta.botmuxTrustedCaller;streamable-http 传输额外注入x-botmux-trusted-*请求头。_meta里自带的、以botmux开头的任意键,以及入站的x-botmux-trusted-*头——无论本轮是否存在宿主身份——因此模型无法通过工具参数伪造身份。trustedCaller(按飞书盖章的发送方 open_id/union_id 构造),喂给上述 Gateway provider。docs-site/docs/{en,zh}/plugins.md的 MCP Gateway 小节补充该身份注入契约(插件只应读取botmux命名空间键、缺身份须 fail-closed)。为什么改
插件化的 Agent 工具(如按真实用户做权限/审计的数据查询类 MCP)需要绑定当前真实用户身份,但身份不能暴露给模型、也不能依赖模型传参(可被诱导伪造)。此改动把身份注入收敛到宿主侧 MCP Gateway:凭据与身份只存在于 worker 进程内存,模型只拿到不含身份的工具调用能力,Gateway 在转发时注入宿主盖章的身份并剥离客户端伪造值。这是一个通用原语,任何需要可信调用者身份的插件 MCP 都可复用,不绑定具体业务。
影响范围
core/plugins/mcp/(gateway、host)、worker.ts、daemon.ts、worker-pool 透传。属多 CLI × 多后端共用路径。tools/call转发时附加/清理botmux命名空间的_meta键与x-botmux-trusted-*头。验证
pnpm build通过。test/plugin-mcp-gateway.test.ts(含「有/无宿主身份下注入与剥离客户端伪造身份」用例)、write-input、codex-app-threads、daemon-codex-app-workflow-wiring、initial-user-turn-opening、group-join-shared-routing 等。_meta塞botmuxTrustedCaller/botmux前缀 sibling 键 / 大小写变体 → 下游插件均收不到伪造值;合法非botmux键保留;有宿主身份时注入宿主值并覆盖模型伪造值。merge-tree对master无冲突,git diff --check干净。备注
yousay123:barry/data-mcp-identity-origin-merge;Allow edits by maintainers保持勾选。