Skip to content

🔒 全面加固跨世界 GM RPC、用户脚本与 Agent 边界 - #1747

Open
cyfung1031 wants to merge 104 commits into
scriptscat:mainfrom
cyfung1031:codex/main-world-security-refactor
Open

cyfung1031 wants to merge 104 commits into
scriptscat:mainfrom
cyfung1031:codex/main-world-security-refactor

Conversation

@cyfung1031

@cyfung1031 cyfung1031 commented Sep 16, 2026

Copy link
Copy Markdown
Collaborator

Checklist / 检查清单

  • Fixes mentioned issues / 修复已提及的问题
  • Code reviewed by human / 代码通过人工检查
  • Changes tested / 已完成测试

背景

本 PR 系统性加固跨世界 GM API、MAIN world、USER_SCRIPT、Service Worker、Offscreen、Sandbox 与 Agent/CAT API 的边界。原实现中,部分请求依赖页面可观察的 DOM 通道、可变对象或跨上下文全局状态,存在请求伪造与重放、旧文档错配、accessor/proxy 执行、值和附件越权、异步请求悬挂,以及监听器和连接泄漏等风险。

当前 PR 目标分支为 main(live ref 249e2fc31896d6a00ce9425e0a31bcccdc475b2e);PR API 的 base OID 与当前 diff merge-base 均为 0eeeb5d12a1c87b94aa9b31a94e035422f497ad1,head 为 5b07c7e00321e54ae77c2230971e57b230ffe883,涉及 95 个文件。

变更总览

范围 关键改动 解决的问题
页面 GM RPC 身份 为脚本、环境、tab、frame、document 签发执行句柄;绑定 canonical UUID、run flag、grant 能力;Service Worker 每次请求重新校验发送方和绑定状态 防止页面伪造身份、跨文档复用旧句柄或扩大 API 权限
MAIN world 通道 特权 GM 请求迁移到原生扩展通道;增加 bootstrap gate、一次性 token、文档绑定和 native 失败后的兼容回退;成功时不再把完整脚本 DTO 主动放到页面桥 降低页面观察和伪造特权流量的机会,同时保留旧浏览器兼容路径
USER_SCRIPT 生命周期 原生通道承载 bootstrap、GM RPC、值更新和事件回调;支持断线重连、值更新排队、连接撤销、旧会话清理、frame 定向和来源校验 防止回调错投、重连状态丢失和旧文档连接残留
早期启动与导航 恢复 early-start manifest 执行;将 wrapper、metadata、页面 URL 和 document 绑定;隐藏 preload 值;处理 pageLoad 与 binding rotation 竞态;支持 BFCache 页面恢复 防止启动期泄露值数据和新旧文档状态混用
DTO 与消息边界 对 PageMessage、ExtensionMessage、WindowMessage、CustomEvent、Server action 和 USER_SCRIPT DTO 做严格字段、来源、版本、身份和数据描述符校验;先检查再 structured clone 拒绝 accessor、Proxy、thenable、函数、Symbol、不可 clone 值和 hostile envelope
重放与集合安全 按 binding/document 记录 page RPC requestId 并拒绝重放,不设固定数量上限;捕获原生 Reflect/Map/Set/数组方法;校验 Map/Set/数组和普通对象条目;隔离 capability map 的 own-property 查找 防止重放、避免长会话因达到固定窗口上限而永久拒绝合法请求,并阻止原型链污染、内建方法篡改和集合遍历 getter
GM facade 与 API 注册 将 GM broker、transport、CAT conversation 状态和受保护字段收进 facade/private state;保留 API registry 枚举与 merge 兼容;明确 none grant、别名和依赖图边界 防止 MAIN world 取得完整 GM_Base、内部传输对象或可变全局状态
GM 值与资源 加固 GM value clone、GM_setValues、删除 falsy 值、prototype key、null-prototype result/config record;移除 CAT fetch 的 live Document;修正资源和附件读取边界 防止 getter 执行、__proto__ 污染、跨脚本附件读取和跨 realm live object 泄露
GM XHR 与回调 统一 setup、connect、abort、error、load、loadend 和 teardown 的 settle-once 流程;清理连接和请求表;降低回调 dispatch 扫描成本 防止 Promise/回调悬挂、重复回调、abort 后残留监听器和连接泄漏
Agent/CAT 权限 conversation、task、DOM monitor、OPFS、skill、model 等服务统一覆盖请求中的伪造 scriptUuid;task 使用 owner/generation/revision CAS;模型结果隐藏 apiKey;附件读取检查脚本可达性 防止脚本跨身份读取或修改 Agent 数据,以及并发更新覆盖
DOM/CDP 生命周期 为 DOM 操作补充 URL、tab、owner 和受限页面校验;监控结果按 owner 隔离;同一 tab 的 monitor start/stop 使用串行队列,避免并发 attach 后遗留监听器 防止浏览器内部页面操作、跨脚本监控读取和并发连接泄漏
性能与维护 复用缓存的 PageMessage sender;直接调用捕获的原生 structuredClone,避免创建绑定包装器;减少重复 collection factory、反射和回调扫描;补充安全边界注释并同步架构文档 在保持固定能力边界的同时减少重复工作,避免后续维护误破坏安全契约
回归测试 覆盖 hostile getter/proxy、不可 clone 值、绑定轮换、重放、URL/document 匹配、USER_SCRIPT 重连、GM XHR 终止、Agent owner/CAS、OPFS、DOM monitor 并发等路径 将跨上下文安全和异步生命周期约束固定为可重复证据

生产代码用法统计

用法 main (249e2fc31896d6a00ce9425e0a31bcccdc475b2e) PR (5b07c7e00321e54ae77c2230971e57b230ffe883) 变化
.bind 属性引用 / 直接调用 131 / 126 128 / 120 -3 / -6
.call 属性引用 / 直接调用 9 / 9 7 / 5 -2 / -4
.apply 属性引用 / 直接调用 14 / 6 17 / 2 +3 / -4
Map new Map 154 155 +1
Set new Set 247 243 -4
Map for...of 29 43 +14
Set for...of 19 19 0
Map .forEach 6 6 0
Set .forEach 5 6 +1

统计扫描 main 的 654 个和 PR 的 658 个 tracked TypeScript/JavaScript 源文件;排除测试、E2E、fixture/mock、benchmark、生成文件和依赖/构建目录。.bind.call.apply 先列属性引用数,再列直接调用数;.apply 包含 Reflect.apply。Map/Set 相关行按类型识别 Map/ReadonlyMap/MapIterator 与 Set 对应类型。

实现考虑

设计约束 说明
句柄不是秘密 page execution handle 只用于范围标识;最终授权仍由真实 sender 的 tab/frame/document、脚本存在状态、grant 和既有 permission verification 决定
兼容性边界 特权 MAIN GM 流量走原生通道;DOM CustomEvent 仍保留给 bootstrap、兼容回退和节点辅助场景,页面仍可观察返回值、句柄和能力结果
BFCache 与导航 BFCache 恢复复用当前 document 的有效绑定;新 document 必须重新匹配 sender;脚本撤销、导航轮换和 tab 关闭会清理失效绑定
Agent 并发 task 和 conversation 持久化使用 generation/revision 约束;DOM monitor 的 start/stop 在单 tab 内串行,确保 attach、listener 和 detach 成对
运行时开销 主要采用 setup-time 绑定、捕获原生方法、Map/Set 和固定能力集合,避免在每次请求中建立多层 adapter

已知限制

  • MAIN 页面桥仍保留兼容回退和页面可观察结果;本 PR 没有宣称完全移除所有 DOM 可观察信息。
  • page RPC 的 requestId Set 按 binding/document 生命周期保留;移除固定上限后,长会话会继续累积唯一 requestId,这是避免合法请求被固定阈值永久拒绝的资源权衡。
  • Firefox 未完成本轮手动浏览器验证。
  • 早前本地 Chromium throwaway MAIN bootstrap smoke 未观察到预期 GM sentinel(passed:-1, failed:-1);该次运行早于最终 guard,当前 head 未重跑。当前 head 的 hosted E2E shards 均通过,这不能替代该本地路径的复测。
  • 当前 head 5b07c7e00321e54ae77c2230971e57b230ffe883GitHub Actions run 35427222270 中,Lint、两个测试 shard、聚合测试和四个 E2E shard 均通过;FOSSA License Compliance 尚无结果。
  • 本地 production build 仍有仓库已有的 bundle-size 和 Monaco dynamic-require 警告。

建议审查重点

审查面 重点
身份与授权 伪造 UUID、handle、run flag、envTag、grant、frame/document 和 stale binding 是否都在 broker 或 Service Worker 边界拒绝
跨世界传输 native 通道、bootstrap token、USER_SCRIPT reconnect 与 DOM fallback 是否不会互相扩大能力
数据安全 accessor、Proxy、thenable、函数、Symbol、__proto__、不可 clone 值和 live Document 是否不会进入特权服务
生命周期 XHR、USER_SCRIPT connection、pageLoad gate、DOM monitor 的 abort、reconnect、teardown 和重复调用是否都能收尾
Agent/CAT conversation、task、attachment、OPFS、DOM monitor 是否始终使用调用脚本的 canonical identity
兼容性 Chrome/Firefox、BFCache、导航、早期启动和 native channel 不可用时的回退行为

验证

检查 结果
Live diff 绑定 live main 249e2fc31896d6a00ce9425e0a31bcccdc475b2e / merge-base 0eeeb5d12a1c87b94aa9b31a94e035422f497ad1 → head 5b07c7e00321e54ae77c2230971e57b230ffe883;95 个文件
消息解析器测试 pnpm exec vitest run packages/message --reporter=dot;6 files, 76 tests passed
消息解析器 ESLint pnpm exec eslint packages/message/window_message.ts packages/message/page_message.ts;passed
消息解析器格式检查 pnpm exec prettier --check packages/message/window_message.ts packages/message/page_message.ts;passed
跨边界重点回归 pnpm exec vitest run packages/message src/app/service/content/utils.test.ts src/app/service/content/page_rpc.test.ts src/pkg/utils/script_compat.test.ts --reporter=dot;9 files, 189 tests passed
当前改动静态检查 pnpm exec eslint src/app/service/content/global.tspnpm exec prettier --check src/app/service/content/global.tspnpm typecheckpnpm build;passed,build 有 4 个既有 bundle-size/Monaco warnings
structuredClone 微基准 Node v25.9,250,000 次 clone/run、交替 9 轮;bound median 511.4 ms,direct median 519.1 ms,未证明稳定吞吐收益;本改动只主张移除 setup-time bind/wrapper
重点 DOM/CDP 测试 pnpm exec vitest run src/app/service/agent/service_worker/dom_cdp.test.ts src/app/service/agent/service_worker/dom.test.ts --reporter=dot;42 tests passed
类型检查 pnpm run typecheck;passed
重点 ESLint pnpm exec eslint src/app/service/agent/service_worker/dom_cdp.ts src/app/service/agent/service_worker/dom_cdp.test.ts;passed
重点格式检查 pnpm exec prettier --check src/app/service/agent/service_worker/dom_cdp.ts src/app/service/agent/service_worker/dom_cdp.test.ts;passed
Production build pnpm build;passed,保留已有 bundle-size/Monaco warnings
Commit hook typecheck 和 Prettier passed
远端提交 fork 分支已发布,git ls-remote 与 head SHA 5b07c7e00321e54ae77c2230971e57b230ffe883 一致

@cyfung1031
cyfung1031 marked this pull request as draft September 16, 2026 23:03
@cyfung1031 cyfung1031 changed the title 🔒 加固 MAIN 世界脚本 GM RPC 权限边界 🔒 全面加固跨世界 GM RPC、用户脚本与 Agent 边界 Sep 18, 2026
Replace replay-cap loops with constant-time full-state invariant checks and enforce a 40-second E2E budget across Playwright configuration, helper waits, and CI. Make retry helpers side-effect bounded and preserve failure logs while closing pages on all paths.
Keep CI and helper timeout behavior outside this PR. Retain the constant-time replay invariant tests while restoring the existing E2E configuration and retry semantics.
@cyfung1031
cyfung1031 marked this pull request as ready for review September 19, 2026 06:53
@cyfung1031
cyfung1031 marked this pull request as draft September 19, 2026 07:09
@cyfung1031

cyfung1031 commented Sep 19, 2026

Copy link
Copy Markdown
Collaborator Author

Performance Degradation Found. Change to Draft first.
It seems like the server issue...

@cyfung1031
cyfung1031 marked this pull request as ready for review September 19, 2026 07:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant