Skip to main content

Replay attack protection

A replay attack on a payment system occurs when a valid payment credential (transaction hash or signed authorization) is submitted more than once to get double the service. Prudra prevents this with a UNIQUE constraint at the database level — not at the application level.

Why database-level, not application-level

Application-level uniqueness checks have a race condition window. Two concurrent requests carrying the same txHash can both pass the application-level check before either write commits to the database:
Both requests succeed. Double payment accepted. A UNIQUE constraint closes this window atomically. The database guarantees that exactly one INSERT for a given txHash succeeds, even under concurrent load:
The second INSERT raises a unique violation error, which Prudra catches and returns as a 409.

The 409 response

When a duplicate payment is detected:
The agent should not retry with the same credential. It must use a new transaction (or, for x402, a new ERC-3009 authorization with a new nonce).

What gets a UNIQUE constraint

For x402, the nonce is part of the signed ERC-3009 data. A new signing operation generates a new random nonce — so even if the same agent signs the same amount to the same recipient, the nonces differ. For MPP, the txHash of the Tempo transaction is globally unique by design — no two transactions can have the same hash.

Testing replay protection

In stub mode, Prudra uses the stub credential value itself as the txHash for uniqueness checking. This lets you test replay protection without real transactions.

No action required

Replay protection is handled automatically by Prudra middleware. You don’t need to implement any uniqueness checking in your handler code. If a 409 is returned to your handler (which shouldn’t happen — the middleware catches it before your handler runs), it means a concurrent request with the same credential slipped through, which is not possible with the UNIQUE constraint in place.