Skip to content

fix: harden x402 settlement verification against replay & RPC mismatch - #184

Merged
Darkvader-ship-it merged 7 commits into
PHASE-STELLAR:mainfrom
Timmmytunner:security/issue-30-spike-harden-x402-settlement-verification
Aug 31, 2026
Merged

fix: harden x402 settlement verification against replay & RPC mismatch#184
Darkvader-ship-it merged 7 commits into
PHASE-STELLAR:mainfrom
Timmmytunner:security/issue-30-spike-harden-x402-settlement-verification

Conversation

@Timmmytunner

Copy link
Copy Markdown
Contributor

Overview

This PR hardens the x402 settlement flow by introducing a persistent transaction-hash spent-registry and removing the demo-mode bypass that previously allowed a single Soroban settlement receipt to be replayed for multiple AI artifact mints.

All settlement verification paths in /api/forge-agent and /api/x402/verify now share a single, audited path that:

  • rejects duplicate settlementReceiptTxHash values with HTTP 409,
  • verifies the Soroban transaction's event log for the exact contract ID, settle function name, and minimum stroop payment,
  • validates RPC response header consistency, and
  • enforces on-chain verification in production with no unverified demo shortcut.

Related Issue

Closes the bounty spike issue: Harden x402 Settlement Verification Against Replay Attacks & RPC Header Mismatches

Changes

🔐 Persistent Settlement Spent-Registry

  • [ADD] lib/settlement-store.ts
    • File-backed spent-registry at .data/used-settlements.json.
    • Atomic file locking (lock + rename) to guarantee single-use settlement.
    • markUsed(txHash) / isUsed(txHash) API for all verification paths.

🔍 On-Chain Verification Hardening

  • [MODIFY] lib/phase-protocol.ts

    • verifyPhaseSettleTxOnChain now checks Soroban event logs for exact contract ID, settle event/function name, and minimum stroop payment amount.
    • Rejects transactions with missing/tampered event logs or insufficient payment.
    • RPC response header mismatches are treated as verification failures.
  • [MODIFY] lib/stellar.ts

    • Adds defensive validation for Soroban RPC headers and event-log decoding.
    • Ensures the network/ledger context returned by RPC matches the expected chain.
  • [MODIFY] app/api/forge-agent/route.ts

    • Removes the demo-mode bypass at lines 977–981.
    • Checks spent-registry before minting an AI artifact.
    • Duplicate settlement hash returns HTTP 409 Conflict immediately.
  • [MODIFY] app/api/x402/verify/route.ts

    • Audits all settlement paths and applies the same spent-registry + on-chain event verification.
    • Prevents replay of a verified x402 settlement across multiple requests.

🧪 Replay & Tamper Test Suite

  • [ADD] tests/replay-settlement.test.ts
    • Reusing a previously submitted transaction hash returns 409 on the second attempt.
    • Wrong contract ID, wrong function name, missing event log, and underpayment are rejected.
    • Demo mode can no longer bypass verification.
    • Concurrent duplicate submissions resolve to exactly one approval.

Verification Results

npm test -- tests/replay-settlement.test.ts
✅ 14/14 passed

Live acceptance check:
✅ Duplicate tx hash returns HTTP 409
✅ Soroban event log verified (contract ID + settle + min stroop)
✅ RPC header mismatch rejected
✅ Demo bypass removed in production path
✅ 0 unverified settlement approvals
Acceptance Criteria Status
Reusing a previously submitted transaction hash returns HTTP 409 Conflict immediately. ✅ Spent-registry lookup rejects duplicate hashes before mint/approval.
Zero unverified settlement approvals in production environment. ✅ Demo-mode bypass removed; all production paths require full Soroban verification.
Comprehensive security test suite attempting replay payloads. ✅ Replay, tamper, underpayment, and RPC-header mismatch cases covered.

Closes #30

@drips-wave

drips-wave Bot commented Aug 31, 2026

Copy link
Copy Markdown

@Timmmytunner Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@Darkvader-ship-it
Darkvader-ship-it merged commit 1af6497 into PHASE-STELLAR:main Aug 31, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Spike] Harden x402 Settlement Verification Against Replay Attacks & RPC Header Mismatches

2 participants