Skip to main content
Glama
nexus-mcp-infra

x402-receipt-verifier

x402 Receipt Verifier

NEXUS의 자체 x402 결제 로그를 NEXUS의 자체 전달(delivery) 로그와 대조하고, 특정 결제가 실제로 성공한 서비스 호출과 상관관계가 있음을 증명하는 서명된 영수증을 발급한다. NEXUS 후보 #13 -- 수동 빌드. FORGE 생성 아님.

  • POST /verify-payment-receipt {"asset_name": "...", "payer_address": "0x...", "claimed_amount_usd": 0.01, "claimed_at": "2026-08-22T21:31:34Z"} -- $0.02가 x402로 청구됨 (Base Sepolia 테스트넷).

  • POST /payer-spend-health {"asset_name": "...", "payer_address": "0x..."} -- $0.02가 x402로 청구됨.

  • 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 요청) 는 두 개의 분리된 상관이 없는 테이블이다. — 어느 INSERT도 특정 지급과 그 지급이 제공한 특정 요청을 연결하는 공유 ID를 저장하지 않는다. 이 자산은 NEXUS가 다른 곳에서는 하지 않는 상관을 수행한다: claimed (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-only RLS 정책(CLAUDE.md SS5 참조)과 일치한다. 마이그레이션: add_x402_payment_receipt_verification_rpcs (Supabase 프로젝트 ieduhdgfjdeffvzxvihf).

범위, 의도적: 로 만, NEXUS 자체가 이미 배포한 x402 자산(우리 자신의 revenue_events/traffic_events에 실제 들어 있는 것)만 다룬다. 제3자 결제 주장과 제3자 로그를 대조하는 것이 원래의, 더 넓은 아이디어였으며(기회 목록 항목 #3, "recibo/prueba de ejecucion verificable para pagos entre agentes") 거기서 다른 두 당사자 사이 중재자 역할을 하는 것이 법률/분쟁 책임 리스크를 지닌다는 점이 명시적으로 표시되어 있다. 우리 이미 공개된 자산 카탈로그로 범위를 좁히면 그 문제 전체가 피할 수 있다. 우리가 판정할 제3자의 주장이 없고, 오직 우리 자신의 이미 정산된 데이터만 있기 때문이다.

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가 올바르게(버그가 아니라) PAYMENT_NOT_FOUND를 반환한다. 현재글 작성 시점에 revenue_events에서 실제로 본 값: document-conversion-api, live-entity-verification, agent-verification-api, url-metadata-api, Similarity Search API, ws.

서명된 영수증

signature는 receipt의 표준 JSON 인코딩에 대해 NEXUS_RECEIPT_SIGNING_KEY를 키로 한 HMAC-SHA256(hex)이다. 이것은 오프라인에서 검증 가능한 서명이 아니다 (그러려면 비대칭 암호화 + 공개된 공개 키가 필요하며, 의도적으로 제외다, "알려진 제한 사항" 참조): 보유자는 이 자산 자체의 무료 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" 순서를 혹 메인넷 자산이 재사용하기 전에, 결제 전 Supabase 연결 가능성 확인을 추가하거나, 핸들러 결과가 성공한 후에만 결제를 확정되도록 바꿔야 한다.

  • Anon-key RPC 우회. 이 두 Postgres RPC 함수는 anon에게 권한이 부여되어 있다(PostgREST가 이를 노출하기 위해 필요). 누출된 SUPABASE_ANON_KEY를 사용하면 /rest/v1/rpc/nexus_verify_payment_receipt에서 이 함수를 직접 호출해 이 자산의 x402 청구를 우회할 수 있다. 수용됨: RPC는 NEXUS 자체의 이미 공개된 자산 카탈로그에 대한 상관 주장만 반환하며, 우회 자체로 민감한 정보가 노출되진 않고 결제벽만 무력화된다. 이 코드베이스의 다른 모든 Supabase anon-key 사용과 동일한 위험 분류다.

  • 호출자별 속도 제한 없음. 7일 일괄 측정창에는 충분하다.

품질 게이트 (2026-08-22 배포, 지출 한도 중단으로 2026-08-23에 게이트 완료)

후보 #3/#4/#6과 동일한 2-에이전트 프로세스 (보안 렌즈; 기능+품질+구매자-경험 렌즈)를 이번에는 배포 후 실행했다 — 월별 지출 한도가 밤사이 세션을 중단시킬 때 리뷰가 아직 진행 중이었고, 다음 세션에서 재개하여 완료했다. 실제 발견한 항목, 적용된:

  • 보안 (1건, 낮음): POST /verify-receipt-signature에는 x402 게이트도, 크기/깊이 제한도 없었으므로 호출자가 제공한 임의의 receipt 사전을 무료로 해시했다. 심각한 취약점이라기보다 값/가능성상의 방해 수준이다. 수정: 어떤 해시 전에 >4096바이트 또는 >10단계(깊이)의 본본을 400/413으로 거부한다(main.py의 _validate_receipt_shape, _MAX_RECEIPT_BYTES/_MAX_RECEIPT_DEPTH).

  • 기능/구매자-경험 (1건, medium): 결제가 RPC 실행보다 먼저 확정되므로, 결제 후 Supabase 인프라 실패가 발생하면 구매자는 아무런 응답도 없고 구제도 없이 결제만 된 상태가 된다 — 공개되지 않던 일이다. 수정: 위의 "알려진 한계 사항"에서 문서화함 (코드 변경 없음; 테스트넷에서만 수용 가능, 이 패턴을 메인넷에 재사용하기 전에 반드시 재검토해야 함).

  • 그 밖의 다른 모든 점검 (후보 #3의 SSRF 계열, 후보 #6의 zip-bomb/쓰레드-누출 계열, anon-key RPC의 지나친 반환, HMAC 일관성, 후보 #4의 자기-결제 payTo 트릭, IP로 잘라버림, 주입 표면)은 모두 결함이 없는 것으로 확인됐다. 관련 코드 경로를 다시 읽고 확인했지 단순히 주장한 것으로 그치지 않았다.

  • 두 가지 매우 사소한 표면 문제는 의도적으로 그대로 맡겼습니다: 사용되지 않는 MCP 도구 매개변수 ctx: Context = None (agent-verification-api/main.py에 이미 존재하는 동일한 미사용-매개변수 관례와 에서, 여기서 고칠 가치가 있는 편차 아님), 그리고 MCP 경로에서만 window_seconds/lookback_days를 조용히 클램핑하는 것 (REST는 Pydantic으로 범위 밖을 이미 거부한다; MCP 경로는 대체된 값을 영수증에 다시 반환하므로, 잘못된 것은 아니며 명시적 오류만 아닐 뿐 — 이 게이트가 필요하다는 증거는 아직 없다).

측정 (후보 #13, 7일 창)

최초 실제 배포: 2026-08-23 시작 7일 창 (2026-08-23 -> 결정 시점 2026-08-30). 진위 traffic_events/revenue_events/mcp_call_events (asset_name = 'x402-receipt-verifier')이며, Cloud Run 로그가 아니다. 7일: 실 트래픽(아브라징 크롤러 제외)이 0이면 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