Files
codex-app-server/docs/chv-muse-p10-gap.md
T
host b55b49b358 feat(chv): 对齐 Muse P10 支付安全——凭证隔离 + 结账检测 + 每次购买人工审批 + 一次性卡号
- 支付凭证隔离:PaymentCredentialVault(只活内存、白名单
  stripe-link/shop-pay、只存不透明 id + 掩码标签、原始卡号
  PAN 拒绝入库、按次释放绑定商家/金额/货币、单次 + TTL)
- 结账页检测:detect_checkout(URL + 无障碍树信号,确定性
  规则、不读原始 DOM、与 P4 detect_form_risk 同输入形状)
- 每次购买人工审批:PaymentGate 经 P5 对话外通道发审批,
  payload 含确切购买详情;完成时先验签、再验详情摘要
  (篡改即拒且审批保持待处理)、最后单次消费答复
- 一次性卡号:OneTimeCard 绑定商家/金额/货币/有效期,单次
  兑现;SimulatedWalletBackend 沙箱钱包(假 PAN 只在后端
  私有内存、charge 只记账不联网、取消即 void)
- 限额:SpendLimits 三档 minor units 比对,限额不可用时
  不编造上限(limits_checked=False)
- 审计:PaymentAudit 只留允许字段,秘密字段名丢弃 + redacted
- 审批通道最小扩展:ApprovalRequest 增加可选 details 字段,
  不传时 payload 与 P5 完全一致
- 真实支付与扣款不做:全部沙箱验证,真实钱包集成待用户
  另行批准;新测试 79 项,全量 cloud 套件 2037 OK

round-12 集成说明:本提交为 acf98f8 的 cherry-pick(只含 P10
自有 diff,基线 25bcd35 已含的 P3/P5 内容未重复合入;
approval_channel.py 仅加可选 details 字段)。
2026-11-07 00:09:55 +00:00

13 KiB
Raw Blame History

对齐 Muse P10 差距表:支付安全(凭证隔离 + 结账检测 + 每次购买人工审批 + 一次性卡号)

依据:~/workspace/research_notes/meta-muse-ai-architecture-20261101-0755/report.md (官方以 Meta security.muse.ai 2026-09-08 为准;第三方转述要标注 来源性质,不得把转述写成官方承诺)。Muse 官方支付安全要求 (报告 §3.3,):购物是最常见浏览器用例之一,Meta 对此 格外谨慎——已保存支付凭证的网站,浏览器内置结账页检测,每次都 弹出人工审批并展示确切购买详情;未购物过的网站,Muse 内置合规 钱包,首发合作 Stripe Link,Shop Pay 即将来临;支付时发行一次性 卡号给商家,而非真实卡号;该凭证绑定特定商家、特定金额、有限 有效期,即使经提示注入被盗也“不太有用”;Muse 是首个被 Link 购买 保障覆盖的 AI 代理(损坏/丢失商品免费保障、降价保障、免费退货、 符合条件购买的退货保证——保障条款以 Link 官方为准,本轨不编 细节、不实现理赔流程)。

连接器文档补充(wallet tools 的实际口径,见 /opt/hatch/connectors/stripe-link/CONNECTOR.md、 shop-pay/CONNECTOR.md、shopify-ucp/CONNECTOR.md): Link 在一次购买获批后注资一张一次性虚拟卡,商家永远收不到真实 卡号;Shop Pay 原生路由用一次性 token、卡片路由在审批后才由浏览 器填卡字段;每次购买走独立 browser task 与独立审批;审批被拒即 停止、不扣款;结果未知时不重试、不换卡、不换路;取消待支付会 void 虚拟卡;已完成扣款无钱包退款、走商家退款流程;直接结账须 先查限额(每笔/每日/30 天,minor units、无货币、不换算),限额 不可用时不编造上限;step-up 未完成时 Link 要求用户先验证身份; 子代理、群聊、定时任务没有 wallet tools,不能替用户设 Link 或选 支付方式。本轨的结论:钱包能力在主应用运行时侧,不在 cloud/chv 代码里;本轨只做客内 agent 侧的支付安全门(检测、 审批、绑定、审计),真实钱包调用是待批准的集成点,见 §3。

本轨范围只限 P10:支付安全。起点是 P3(authd 替身凭证)与 P5 (对话外审批通道),已合入本分支(合并 feat-chv-muse-p5, 25bcd35)。不碰 P1(常驻 VM、气球、vsock)、不碰 P2(nspawn 单元、浏览器子代理本体)、不碰 P4(浏览器完全对齐——结账检测 与它接线,不重复造)、不碰 P6(privsep worker)、不碰 P7/P8/P9。 分支 feat-chv-muse-p10(从基线 06c3e17 分出,合入 P5 后 HEAD 为 25bcd35)。

0. 起点(P3/P5 已做的,本轨不重写)

  • P3 cloud/chv/authd.py:CredentialVault(只活内存、白名单、 按次释放绑定 {连接器, 主机, 仓库路径, 操作}、单次 + 300 秒 TTL、审计绝无凭证值)+ mint_gitea_token;白名单只认 gitea/GITEA_TOKEN,支付不在其中——本轨不改 authd 的 白名单,支付凭证另立 PaymentCredentialVault(同模式,不 同库,见 §1),避免把支付键混进代码仓库凭证的白名单。
  • P3 cloud/chv/sentinel.py:ApprovalQueue(ask 记入内存态 待审批,resolve 只标记不放行);EgressRequest.describe() 只含连接器/目标/方法——支付审批借用这条队列记账,目标描述 为 connector=payment, method=purchase, scheme=https, host=<商家主机>, port=443, path=/checkout。
  • P5 cloud/chv/approval_channel.py:对话外审批通道 (ApprovalRequest.payload() + Answer + HMAC-SHA256 签名
  • verify_answer 五项校验 + resolve_via_channel 单次消费; 对话内容里出现的“批准”字样一律无效)。本轨只给它加一个 可选 details 字段(确切购买详情进 payload、供客户端 UI 展示),校验与消费逻辑一字不动。

1. 现状 vs Muse

项 现状(实测/代码为准) Muse 目标 本轨做法
支付凭证隔离 无。cloud/chv 里没有任何支付代码;agent 若要支付,只能把卡号/钱包凭证以明文塞进环境或对话——这正是 Muse 明令禁止的形态 凭证与 OAuth token 存于用户 VM 内独立隔离容器,不在其他服务中;登录凭证存入单元外的安全凭证存储,代理不可见,仅在需要时注入 cloud/chv/payments.py:PaymentCredentialVault(只活内存、白名单 stripe-link/shop-pay、只存不透明支付方式 id + 掩码标签;原始卡号 PAN 拒绝入库——13–19 位数字串 + Luhn 校验命中即拒;按次释放绑定 {商家, 金额, 货币}、单次 + TTL;__repr__/审计绝无凭证值;forget 删凭证并作废未兑现释放)
结账页检测 无。浏览器侧 P2 的 chv-browser.py 只有 open/snapshot/screenshot/close/ping,无结账概念;P4 在做高风险表单拦截(detect_form_risk 扫无障碍树,密码/支付字段即标 form_risk),尚未提交 浏览器内置结账页检测 cloud/chv/checkout_detect.py(纯函数,标准库):detect_checkout(url, a11y_nodes)——URL 信号(/checkout、/payment、/pay、/order-review 等)+ 无障碍树信号(卡号/有效期/安全码字段、“下单/支付”按钮、金额文本);返回 is_checkout/confidence/reasons/form_risk/amount_text;确定性规则,不冒充模型分类器;只读 a11y 节点,绝不读原始 DOM;与 P4 的 detect_form_risk 同输入形状,P4 的 broker 在高风险表单提交前调本检测(接线点见 §4,P4 未提交前先留接口 + 测试)
每次购买人工审批 无。没有任何“购买前停下”的机制 已保存支付凭证的网站,每次都弹出人工审批并展示确切购买详情 PaymentGate.begin_purchase:结账检测未命中即拒;路由(见下行);限额检查(见下行);经 P5 通道发审批,payload 的 details 含确切购买详情(商家、商品、数量、金额、货币、钱包提供方);审批只走通道答复,对话内“批准”无效;complete_purchase 先验签(verify_answer,不消费)、再验购买详情摘要(PurchaseDetails.digest(),篡改即拒且审批保持待处理)、最后 resolve_via_channel 单次消费;审批被拒即停止,不扣款
一次性卡号 无 支付时发行一次性卡号给商家而非真实卡号;绑定特定商家、特定金额、有限有效期;被盗也“不太有用” OneTimeCard(绑定 {商家, 金额, 货币, 有效期},单次兑现;换商家/超额/过期/复用一律拒 + 审计);SimulatedWalletBackend(沙箱钱包:假 PAN 只在后端私有内存里,调用方只见掩码标签与 card_id;charge 只记账不联网;取消即 void);真实一次性虚拟卡由 Link 在其侧发行(连接器文档原文),本轨的卡是绑定与兑现校验的等价模型,不是发卡行——见 §3
钱包路由 无。连接器文档有 stripe-link / shop-pay / shopify-ucp 三条路由,但 cloud/chv 里无路由逻辑 未购物过的网站走内置合规钱包,首发 Stripe Link,Shop Pay 即将来临 PaymentGate 路由:商家有已保存凭证 → 已保存凭证路由;无 → 合规钱包路由,stripe-link 优先、shop-pay 次之;两家都不支持 → 拒绝(no_wallet_route),不编造路由。来源时间差:报告写于 2026-11-01 时 Shop Pay 是“即将来临”,连接器文档(当前)显示 Shop Pay 已可用;本轨按连接器文档现状写优先级,并在此标注时间差
限额 无 (连接器文档)直接结账须先查限额:每笔/每日/30 天,minor units、无货币、不换算;限额不可用时不编造上限 SpendLimits.check(amount_minor):三档逐项比 minor units;超任一档即拒(over_limit,审批前就拒);三档全为 None(不可用)→ 通过但记 limits_checked=False,绝不编造上限
支付审计 无 审计轨迹展示已做与计划做的事 PaymentAudit.record:事件(payment_approval_requested / payment_approved / payment_denied / payment_completed / payment_refused / payment_cancelled / payment_card_voided)+ 允许字段(商家、金额、货币、掩码标签、pending_id、原因);字段名命中 card_number/pan/cvv/token/secret/password 一律丢弃并标 redacted=True;卡号与凭证值绝不进审计

2. 改了什么(本轨交付物)

  • cloud/chv/checkout_detect.py(新,标准库):CheckoutVerdict + detect_checkout(url, a11y_nodes)(URL 信号 + 无障碍树信号 + 金额文本抽取;支付字段即 form_risk=payment、密码字段即 form_risk=password;页面文本只作展示信号,扣款金额永远以 PurchaseDetails 为准——页面文本是不受信任输入,见 P6 口径)。
  • cloud/chv/payments.py(新,标准库):PaymentCredentialVault + PaymentRelease + OneTimeCard + SimulatedWalletBackend + PurchaseDetails(digest() 防篡改)+ SpendLimits + PaymentAudit + PaymentGate(编排:检测 → 路由 → 限额 → 审批 → 铸卡 → 兑现校验 → 记账 → 审计)。
  • 接线(cloud/chv/approval_channel.py,最小扩展):ApprovalRequest 增加可选 details 字段,payload() 有 details 时才带上;request_approval 增加可选 details 参数;verify_answer/resolve_via_channel 一字不动;P5 既有测试不受影响。
  • cloud/tests/test_chv_muse_p10_checkout.py、test_chv_muse_p10_payments.py、test_chv_muse_p10_gate.py(新测试,含否定测试:无审批不支付、审批详情被篡改即拒、一次性卡号换商家/超额/过期/复用被拒、原始卡号拒绝入库、凭证泄露面为零、对话内伪造批准无效、答复重放无效、超限额审批前即拒、限额不可用时不编造上限、取消即 void 卡)。

3. 诚实边界(本轮不宣称的东西)

  1. 真实支付不做,零真实扣款:全部用沙箱/模拟钱包与假卡号 (Stripe 测试卡号段 400000000000xxxx)验证,不联网、不调 任何真实钱包接口。真实 Link / Shop Pay 集成(wallet tools 是主应用运行时能力,不在 cloud/chv 代码里)列为待用户 另行批准的事项,本轨不产生任何真实扣款、不持有任何真实 卡号。
  2. 一次性卡号的“发行”在本轨是模拟:真实一次性虚拟卡由 Link 在其侧发行(连接器文档原文:“Link funds a one-time virtual card”);本轨的 OneTimeCard 是绑定(商家 + 金额
  • 货币 + 有效期)与兑现校验的等价模型,不是发卡行。不要把 “模拟钱包铸了测试卡号”写成“已接通 Link 发卡”。
  1. 购买保障只作口径引用:Link 购买保障(损坏/丢失、降价、 免费退货、退货保证)的 eligibility 由 Link 判定、理赔走 Link;本轨不实现理赔流程、不承诺任何一笔购买受保障,保障 条款以 Link 官方页面为准。
  2. 结账检测是启发式,不是 100% 检出:URL 特征 + 无障碍树 特征;商户自定义结账页、单页应用内嵌结账可能漏检。漏检时 的安全底线是:无审批的支付一律拒绝(PaymentGate 拒绝 任何未经审批的扣款),不宣称“所有结账页都会被拦下”。
  3. 限额检查依赖钱包侧返回的限额:限额不可用时不编造上限, 只记 limits_checked=False;审批仍须过。不要把“限额未知” 写成“限额已校验通过”。
  4. 钱包路由优先级按连接器文档现状:报告(2026-11-01)写 Shop Pay“即将来临”,连接器文档(当前)显示 Shop Pay 已可 用;本轨按连接器文档现状写 stripe-link 优先、shop-pay 次之, 并标注了这一时间差;若连接器文档滞后于实际,以实际钱包 能力为准。

4. 真机待验证清单(未做,排队在 round-11 与 P4~P9 之后)

  1. P4 的 broker 接线:高风险表单提交前调 detect_checkout, 结账页命中时 open 导航返回 ask 并暂停(与 P4 差距表 §4 的 form_submit ask 种类对齐)。
  2. 真实钱包集成(待用户另行批准):wallet tools 的 list_payment_methods / 审批单 / approved_card 回包与 PaymentGate 的对接;payment_method_changed(用户在 审批单里换卡)时详情摘要重算与重新审批。
  3. 真实商户结账页上的检测命中率抽查(Shopify / Stripe Checkout / 常见电商各一例),漏检样例记入回归。
  4. 限额读取:wallet.get_user_info 的三档限额与本轨 SpendLimits 的对接;限额不可用时的表现。
  5. 取消与未知结果:取消待支付 void 虚拟卡;结果未知时不重试 的端到端表现(须真实钱包侧配合)。