Skip to main content
Glama
nexus-mcp-infra

x402-receipt-verifier

x402 Receipt Verifier

审计 NEXUS 自身的 x402 支付日志与其自身的交付日志是否一致,并签发带签名的收据,以证明某笔特定支付与一次真实、成功的服务调用相关。NEXUS 候选 #13 -- 手动构建,非 FORGE 生成。

  • POST /verify-payment-receipt {"asset_name": "...", "payer_address": "0x...", "claimed_amount_usd": 0.01, "claimed_at": "2026-08-22T21:31:34Z"} -- 经 x402 收取 $0.02(Base Sepolia 测试网)。

  • POST /payer-spend-health {"asset_name": "...", "payer_address": "0x..."} -- 经 x402 收取 $0.02。

  • POST /verify-receipt-signature {"receipt": {...}, "signature": "..."} -- 免费,确认此前签发的收据真实且未被修改。

  • 位于 /mcp 的 MCP 工具 verify_payment_receipt / payer_spend_health -- 目前免费,见“已知限制”。

  • GET /health、GET /.well-known/agent-card.json、GET /openapi.json(带上 x-payment-info)。

它实际做什么(以及为什么不只是日志转储)

revenue_events(已结算的 x402 支付)与 traffic_events(已响应的 HTTP 请求)是两张相互独立、互不关联的表——两次插入都没有存储某个共享 ID,将一笔特定支付与它为这次支付所对应的具体请求关联起来。本资产负责关联 NEXUS 本身在其他地方都不会做的这件事:给定一个声明的 (asset_name, payer_address, claimed_amount_usd, claimed_at),它会在 window_seconds 内找到真实匹配的 revenue_events 行(如果有),然后检查同一资产是否有成功(2xx)的 traffic_events 行落在该真实支付时间之后不久。结论(VERIFIED_DELIVERY / PAYMENT_NO_DELIVERY / PAYMENT_NOT_FOUND)加上带签名的收据就是产品本身——而不是对任意一张表的原始访问。两张表都通过两个 Postgres SECURITY DEFINER RPC 函数(nexus_verify_payment_receipt、nexus_payer_spend_health)读取;这两个函数只返回计算后的结论对象,绝不返回行转储——这也与本代码库中两张表上既有的仅 INSERT 的 RLS 策略保持一致(见 CLAUDE.md SS5)。迁移:add_x402_payment_receipt_verification_rpcs(Supabase 项目 ieduhdgfjdeffvzxvihf)。

范围(刻意如此): 只覆盖 NEXUS 自己已部署的 x402 资产(也就是我们自己的 revenue_events / traffic_events 中实际存在的资产)。审计第三方针对第三方日志的支付,本来是这个原本更宏大的想法(机会清单第 3 项,"recibo/prueba de ejecucion verificable para pagos entre agentes"),并且在那里的确被特别指出:在另外两方之间充当仲裁者,会带来法律/争议责任风险。把范围缩小到自己已经公开的资产目录,就完全绕开了这个问题——我们不需要裁决任何第三方的声称,只有我们自己已经结算的数据。

Related MCP server: io.github.jsjfin/ailabra-agent-profit-ledger

已知的 asset_name 拼写(在构建本资产时发现,来自真实数据)

revenue_events.asset_name 在现有目录中不是统一的 kebab-case —— 例如,相似性搜索资产的真实存储值是 Similarity Search API(展示大小写),而不是 similarity-search-api。调用方必须传入与存储完全一致的字符串,否则 RPC 会正确地返回 FAYMENT_NOT_FOUND(这不是 bug)。截至 2026 年 8 月,在 revenue_events 中看到的真实值:document-conversion-api、live-entity-verification、agent-verification-api、url-metadata-api、Similarity Search API、ws。

签名收据

signature 是对 receipt 的规范 JSON 编码计算出的 HMAC-SHA256(十六进制),密钥为 NEXUS_RECEIPT_SIGNING_KEY。这不是一个可离线验证的签名(那需要非对称加密 + 公网发布的公钥——刻意省略了,见“已知限制”):持有者通过调用本资产自带的免费 POST /verify-receipt-signature 来证明收据真实;该接口会在服务端重新校验 HMAC。轮换 NEXUS_RECEIPT_SIGNING_KEY 会使在旧密钥下签发的每一张收据全部失效。

部署目标 Cloud Run

与候选 #4/#3/#6 相同的流水线 —— 参见 skills/infra-deploy-ops。

# 1. First deploy -- PUBLIC_DOMAIN not known yet, every real request 421s until step 2.
./scripts/deploy_cloud_run.sh x402-receipt-verifier manual_assets/x402-receipt-verifier

# 2. Grab the printed *.run.app URL, then (only if it differs from env-vars.deploy.yaml's guess):
gcloud run services update x402-receipt-verifier --region us-central1 --project nexus-505016 \
    --update-env-vars PUBLIC_DOMAIN=<the-real-domain>

已知限制(刻意不修复 —— CLAUDE.md SS3,无证据就不加门禁)

  • MCP 工具调用不收费。 与本代码库中每个其他手动资产(url-metadata-api、agent-verification-api、document-conversion-api)采用相同的进程内调用模式。

  • 接收的签名需要在线校验,而不是离线非对称验证——见上文。

  • 关联是时间窗口启发式,而非硬链接。 revenue_events 和 traffic_events 在插入时都没有保存共享的关联 ID,因此 VERIFIED_DELIVERY 表示“在这笔支付之后的时间窗口内,有一次对该资产的请求”,而不是“这个精确的请求由这笔精确的交易买单”。在低流量资产上,这基本等同于精确;而在一个假设的高流量、调用者并发较多的资产上,则可能产生歧义——这时 candidate_successful_calls(直接显示在 receipt 上,见 main.py 中的 PaymentReceipt)会显示大于 1。截至 2026-08-23,这是覆盖范围内 6 个资产中,没有任何一个并发流量密集到足以触发这一点。

  • 支付执行先于 Supabase RPC。 支付成功后发生的基础设施故障是一个真实的“白付钱”缺口——在写到这一行之前尚未披露(发现于 2026-08-23 的质量门禁,采用功能/买家体验视角)。如果 nexus_verify_payment_receipt / nexus_payer_spend_health 本身失败(Supabase 不可用、RPC 超时、上游响应结构错误——参见 _nexus_supabase_rpc 的 502/503/504 路径),买家已经通过 PaymentMiddlewareASGI 完成支付,却只会得到错误,而不是答案,且没有任何退款途径。目前接受的原因只有这一个:这是 Base Sepolia 测试网——没有真实资金面临风险。在把这个“先支付、后 RPC”的顺序复用到任何 mainnet asset 之前,要么加入支付前的 Supabase 可达性检查,要么改为仅在 handler 成功返回结果后再结算支付。

  • anon 密钥 RPC 绕过。 两个 Postgres RPC 函数被赋权给 anon(PostgREST 必须这样才能暴露它们)——因此,一个被泄露的 SUPABASE_ANON_KEY 会让调用者绕过本资产的 x402 付费。可直接在 /rest/v1/rpc/nexus_verify_payment_receipt 调用这两个函数,从而绕过本资产的 x402 收费。可以接受:这些 RPC 只返回 NEXUS 自身已公开资产目录的相关性结论;绕过行为本身不会暴露任何敏感信息,只是把付费墙绕过了。与本代码库中其他 Supabase anon 密钥使用属于同一类风险。

  • 没有按调用者维度限流。 对 7 天的一次性测量窗口来说足够。

Quality gate(2026-08-22 部署,经历一次支出限额中断后,门禁于 2026-08-23 完成)

与候选 #3/#4/#6 相同的双 agent 过程(安全视角;功能+质量+买家体验视角),只是本次是部署后再运行。当时审查还在进行中,账户的每月支出配额在中断中截止,下一次会话继续并完成。真实发现均已落实:

  • 安全(1 项发现,低): POST /verify-receipt-signature 既没有 x402 付费墙,也没有大小/深度限制,因此它可以任意地对调用者提交的 receipt dict 进行免费哈希——这是一个廉价的成本/可用性滋扰,而非严重漏洞。修复:在任何哈希之前,拒绝 >4096 字节或 >10 层深度的请求体,并返回 400/413(_validate_receipt_shape 与 main.py 中的 _MAX_RECEIPT_BYTES / _MAX_RECEIPT_DEPTH)。

  • 功能/买家体验(1 项发现,中): 支付先于 RPC 运行,因此支付后的 Supabase 基础设施故障会让买家已经被扣款,却没有答案和任何通道——此前隐瞒。修复:已在上述“已知限制”中书面说明(未改代码;在测试网上接受,必须重新评估主网上的这类模式,之后才可复用主网)。

其余所有检查项(来自候选 #3 的 SSRF 类、候选 #6 的 zip-bomb / 线程泄漏类、anon-key RPC 返回过多数据、HMAC 正确性、候选 #4 的自支付 payTo 类、IP 截断、注入受力面)均通过——是通过重新阅读相关代码路径验证,而非只是声称通过。

有两个非常轻微的外观类问题被有意保留原样:MCP 工具存在一个 ctx: Context = None 未用参数(与 agent-verification-api/main.y 中已经存在的未用参数完全一致,不值得在此修复);以及 MCP 路径上会静默把 window_seconds / lookback_days 截断(REST 已通过 Pydantic 拒绝越界,MCP 路径会在收据中回显替代后的值,所以只是可发现、没有显式报错——目前还没有证据表明这需要设门禁)。

测量(候选 #13,7 天窗口)

从首次真实部署(2026-08-23 → 决策点 2026-08-30)起 7 天。数据源:traffic_events / revenue_events / mcp_call_events(asset_name = 'x402-receipt-verifier'),而非 Cloud Run 日志。第 7 天:如果真实流量为零(过滤爬虫后),则暂停/删除 Cloud Run 服务(gcloud run services delete x402-receipt-verifier --region us-central1 --project nexus-505016)。

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    B
    maintenance
    Enables autonomous agents to inspect and audit unfamiliar x402 endpoints before spending USDC, using bounded read-only probes to surface payment challenges, pricing, network, receiver, and operational signals without signing or spending funds.
    -
  • A
    license
    Not graded
    quality
    C
    maintenance
    Enables AI clients to discover, trust-check, and pay for Algorand x402 services in USDC, with policy-guarded spending, relay fallback, and an audit ledger.
    2 npm
    MIT