Replaying a Signed Withdrawal: Nonce Reuse and Double-Spend

Cryptocurrency & Blockchain Security Level 3/4 ~5 min August 23, 2026

The challenge

This custodial wallet API signs each withdrawal with a one-time nonce so a request cannot be used twice. Except it never records which nonces it has already spent. Send your fresh withdrawal first to see it succeed, then resend a nonce from an earlier signed withdrawal and watch the same money leave twice. Read the flag the double-spend leaks.

What you'll learn

  • Recognize a replay attack where a previously valid signed request is resent to repeat its effect
  • Understand the purpose of a one-time nonce and how it fails when not tracked server-side
  • Run a two-step exploit: send a fresh request, then replay an earlier one
  • Read API responses to confirm a double-spend was accepted
  • Explain why nonces must be durably marked consumed and duplicates rejected atomically

Skills tested

HTTP request inspection and multi-step tampering with a proxy-style editorIdentifying replay and nonce-reuse vulnerabilitiesReading and interpreting JSON API responsesReasoning about idempotency and state in financial APIs

Prerequisites

  • Basic understanding of HTTP requests and JSON bodies
  • Familiarity with the idea of a nonce as a one-time value
  • Awareness that a withdrawal moves funds and should happen at most once per authorization

How it works

A nonce (number used once) is meant to make a signed request single-use: each withdrawal is authorized with a unique nonce so that capturing and resending the request cannot move the money again. The protection only works if the server remembers which nonces it has already settled and refuses any repeat. This API generates and checks the signature on the nonce but never persists a spent-nonce record, so the same nonce can be presented as many times as the attacker likes.

That gap turns into a replay attack. An earlier withdrawal - nonce 41 - was already signed and completed. Because nothing marks 41 as consumed, resending it is accepted again and the wallet broadcasts the identical transfer a second time, a double-spend. No signature was forged and no value was edited; the original, legitimately signed request was simply replayed. This is one of the most common flaws in payment, wallet, and authorization flows, and it is why idempotency is a security property, not just a reliability one.

The exploit is inherently two-step, which is what places it above a single-field flip: you first send your own fresh nonce to establish that the endpoint works and to see what a real settlement looks like, then you replay a prior nonce and observe the duplicate being accepted. Understanding why 42 succeeds once but 41 succeeds again is the whole lesson.

Common mistakes

  • Incrementing the nonce to a future value like 43 and giving up on the 409 - higher nonces are not yet signed by the wallet, so they are correctly rejected.
  • Assuming the signature on the request makes it safe to resend, when a signature proves authenticity, not single-use.
  • Sending only the fresh nonce and concluding the API is fine, missing that the flaw appears only when an already-settled nonce is replayed.
  • Treating this as a tampering bug rather than the real flaw: the request is unchanged and legitimately signed; the server simply forgot it had already honored that nonce.

How to defend against it

Make each nonce truly one-time by durably recording consumption and rejecting any reuse before funds move. A nonce that is not tracked is decoration, not defense.

  • Persist every settled nonce per account and reject duplicates; or enforce a strictly increasing per-account sequence and refuse anything not greater than the last settled value.
  • Make the spend check and the settlement atomic (a single transaction or a unique constraint on account plus nonce) so concurrent replays cannot both win the race.
  • Bind the signed authorization to all material fields (amount, asset, destination, nonce, chain id) and a short expiry, so a captured request cannot be reused later or against a different transfer.
  • Log and alert on any request presenting an already-consumed nonce, since that is an unambiguous replay attempt.

Full solution

Pro and Max members unlock the complete step-by-step walkthrough.

Go Pro

Community stats

111 completions
79% success rate
M2F14M3 First blood

Related Daily Hacks

25,000+ Hackers 100+ Labs & Courses Free
Start Hacking Free