🔒 加固 MAIN 世界脚本 GM RPC 权限边界 - #1747
Draft
cyfung1031 wants to merge 71 commits into
Draft
cyfung1031 wants to merge 71 commits into
cyfung1031 wants to merge 71 commits into
Conversation
cyfung1031
marked this pull request as draft
September 16, 2026 23:03
Bind USER_SCRIPT bootstrap data to the service-worker-issued document token, preserve sender provenance, and enforce per-execution GM capabilities across page RPC and native message paths. Harden captured collection operations and exact-match early startup handling.
3 tasks
说明原生方法捕获、USER_SCRIPT 来源校验、页面 RPC 句柄生命周期、脚本包装完整性和回调收尾约束,降低后续维护时误改安全契约的风险。
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Checklist / 检查清单
背景
MAIN world 脚本与隔离环境共用 GM RPC 通道时,页面可以伪造脚本 UUID、run flag、API 名称或参数,service worker 也缺少与具体页面文档绑定的能力证明。部分内部 Map、绑定函数和监听器状态还会把可变的页面对象作为接收方或跨脚本全局状态保存。
本次改动
GM.setValue等待能收到正确确认,并修正 inject/content 两个 pageLoad 调用的绑定轮换竞态。Reflect.applywrapper,并把页面可变接收方相关的对话、任务监听器、通知和值确认状态改为实例或上下文关联存储;XHR 在所有终止路径完成 resolve、loadend 和清理。USER_SCRIPTcontent bootstrap、GM RPC、值更新和事件回调迁移到原生 extension 消息;bootstrap 使用 service worker 按文档签发的一次性 token 绑定脚本句柄,DOMCustomEventMessage仅保留同步节点引用及 bootstrap 触发。USER_SCRIPT执行器的 GM RPC 前缀,使原生 content 脚本的异步值 API 直接到达 service worker,而 isolated page 脚本继续使用 scripting broker。实现考虑
请求中的句柄是范围标识,不是秘密;service worker 仍以真实消息发送方的 tab/frame/document 身份、脚本存在状态和既有 permission verification 作为授权依据。BFCache 恢复不会重新执行 content script,因此旧 document binding 会保留到标签页关闭或全局/脚本撤销;解析时仍严格拒绝其他 document 使用该句柄。
USER_SCRIPT与 isolated scripting bundle 分别请求ct与it脚本列表,避免并发启动时一方撤销另一方刚签发的 binding。USER_SCRIPT handshake 不接受页面提供的句柄列表;service worker 只接受与当前 sender 文档匹配的一次性 bootstrap token,并从已保存的脚本清单派生句柄集合。已知限制
MAIN inject 路径仍保留现有 page-observable DOM
CustomEvent传输和页面可观察的 GM 返回值、句柄及能力结果;完整的 MAIN 原生消息迁移、USER_SCRIPT早期预加载 companion 和更细的跨 realm facade 不在本次范围内。绑定表的旧 document 项会在 BFCache 语义要求下保留,service worker 重启、脚本撤销或标签页关闭时清理。Firefox 未在本次手动浏览器会话中验证。建议审查重点
USER_SCRIPT原生端口与 DOM 节点辅助通道是否保持边界,以及值更新和事件回调是否只到达匹配 document。GM.setValue、connect和页面值广播时序。pageShow路径是否继续复用原 document 绑定,新 document 的 sender 校验是否隔离旧句柄。验证
pnpm exec vitest run ...— 15 个安全路径 suite、352 tests passed(commit9f98995e)。pnpm run typecheck— passed(commit9f98995e)。pnpm run lint— Prettier, TypeScript, i18n, issue-template checks and ESLint passed(commit9f98995e)。pnpm run build— production build passed; existing Rspack asset-size and Monaco dynamic-require warnings remain(commit9f98995e)。pnpm test(commitd65bcf3e) — 373 files / 4,790 tests passed, with the existingtests/verification-tools.test.mjsconsole-collector case timing out in the sandbox and two unhandledlisten EPERM 127.0.0.1errors; no changed security-path test failed.25714ff6— lint, both Vitest shards, all four E2E shards, and the aggregate test job passed. test run 35238597251 on9f98995e— lint, both Vitest shards, all four E2E shards, and the aggregate test job passed.pnpm exec playwright test e2e/gm-api.spec.ts -g 'Content inject tests|early-start content world' --workers=1 --retries=0— 2 passed after rebuilding the extension; both suites completed their asynchronous GM value cases and emitted validsctest/v1summaries.prior=seenafter reload, and the DOM helper marker; after rebuilding/restarting, no new service-workerDocument is not definedcrash appeared. The browser XHR smoke did not produce a callback and is not claimed as browser-verified.