如何理解 AI 浏览器智能体的安全边界?爪爪 PawWork 的 QuickJS 沙箱、tab 租约与无服务器设计剖析
【免费下载链接】BrowserKittenPaw Work - selection-first web agent for Chrome: select on the live page, describe the outcome, take away an editable office file. BYOK, sandboxed, no server.项目地址: https://gitcode.com/gh_mirrors/pa/BrowserKitten
爪爪 · PawWork(PawWork_ZhuaZhua)是一款 Chrome MV3 浏览器智能体扩展:你在已登录的网页上选中内容、描述想要的结果,它就能自动操作页面并把成果带走成可编辑的办公文件。它自带模型(BYOK,自带 API Key)、代码在沙箱内运行、完全没有服务器——会话、密钥、交付物全部留在本地。正因为一个"能替你点网页"的 AI Agent 天然危险,本文将带你快速看懂它是怎么画好安全边界的。
一图看懂:安全靠"进程分层",不靠自觉
PawWork 不是单页应用。Chrome 把它的代码拆进 5 类进程,每一层"能做什么、不该做什么"在 AGENTS.md 里有明确契约:
| 层 | 职责 | 硬性禁区 |
|---|---|---|
| 侧栏 Side panel | 渲染对话、收集输入 | 不跑模型、不持有存储 |
| Service Worker(src/background.js) | 权限面:标签、下载、sys系统调用 | 不跑模型循环 |
| Offscreen(src/offscreen/runtime.js) | 会话仓库 + Agent 工具循环 | 不直接碰 DOM /chrome.tabs |
| Content script | 页面选区与action执行 | 无会话语义 |
| Sandbox(src/sandbox/runtime.js) | 执行模型生成的访客 JS | 没有任何chrome.* |
关键思想:危险能力被集中到最少的进程里,其余进程想越权也拿不到句柄。
QuickJS 沙箱:模型写的代码为什么出不来
Agent 的run工具会执行模型生成的 JavaScript——这是最危险的动作。PawWork 的答案是 src/agent/vnext/adapters/codeRuntime.js 里的 QuickJS-WASM 隔离:
- 独立 WASM 堆:访客代码运行在自己的 QuickJS 运行时里,天然没有宿主的
window、document; - 封禁探测,失败即关闭:运行时主动把
chrome、fetch、localStorage、indexedDB等 15 个名字定义成"一访问就抛错"的陷阱属性。恶意探测代码不会悄悄拿到宿主数据,而是以非零退出码失败; - 资源限额:内存上限、512KB 栈上限、超时 deadline + 中断处理器,死循环会被强制打断;
- 沙箱页二次隔离:在扩展环境中,代码实际跑在 manifest.json 声明的
sandbox.pages页面里(sandbox allow-scripts+ 独立 CSP)。这个页面注释写得直白——"No chrome.* — FS and sys are postMessage RPCs",连文件读写都要发消息请宿主代劳。
访客可用的sys浏览器接口(tab 管理、fetch、截图等)只是"系统调用门面",真正的实现全部在服务 Worker 端(src/agent/vnext/host/browserSysHost.js),并带并发上限(最多 128 个在途调用)与操作级超时。
网络守卫:AI 指哪儿,fetch 不能打哪儿
扩展持有<all_urls>权限,如果没有这道闸,模型可以把 fetch 打到你的内网。src/agent/vnext/primitives/netGuard.js 在宿主侧执行网络策略(注释原话:"Runtime Policy lives in the host, not the prompt"):
- 拦截
localhost、.local/.lan/.internal等内网名; - 拦截 RFC1918 私有段、
169.254链路本地(含云元数据端点169.254.169.254)、CGNAT、IPv6 ULA/链路本地,甚至::ffff:a.b.c.d这种 IPv4-mapped 马甲; - 只放行公网
http(s),其余一律NET_DENIED。
tab 租约:多个会话抢同一个标签页怎么办
两个会话同时操作同一个网页,页面状态就会互相踩踏。src/agent/vnext/host/tabLease.js 用一张Map<tabId, { sessionId, executionId }>做跨会话互斥锁:
- 会话 A 占用 tab 12 后,会话 B 的页面动作直接得到
TAB_LEASED错误; - 同一会话同一执行内重入是允许的(
reentrant); - 执行结束、中止或关闭标签时自动释放。
它的诚实之处同样写在注释里:"Not a journal: process death drops the map"——Service Worker 被 Chrome 杀掉后锁会丢,因此它只做互斥,不承诺跨崩溃的精确一次语义。
无服务器设计:数据与密钥都不出门
"BYOK, sandboxed, no server" 是 PawWork 的三件套,对应到实现上:
- 自带 Key:模型密钥填在侧栏,存于
chrome.storage.local,请求直连你配置的 OpenAI 兼容端点(src/agent/provider.js); - 会话本地持久化:会话仓库用 IndexedDB + OPFS 存在本机(src/agent/vnext/sessionWorkspace/durableStore.js),不经过任何第三方中转;
- 边界诚实:AGENTS.md「未实现的边界」一节明确列出"没有跨崩溃 exactly-once""截图不是原子快照""出不了浏览器"等硬边界——知道能力到哪里为止,本身就是安全设计的一部分。
小结
PawWork 的安全模型可以浓缩成四句话:危险代码关进 QuickJS 沙箱、浏览器特权收敛到 Worker 系统调用、网络请求经宿主守卫、并发冲突用 tab 租约互斥,再加上全程无服务器。对于想自建浏览器 Agent 的开发者,这套"进程分层 + 宿主策略 + 诚实边界"的清单,是一份可以直接抄的参考答案。
【免费下载链接】BrowserKittenPaw Work - selection-first web agent for Chrome: select on the live page, describe the outcome, take away an editable office file. BYOK, sandboxed, no server.项目地址: https://gitcode.com/gh_mirrors/pa/BrowserKitten
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考