Skip to main content

An XRP bridge was drained for roughly $200,000 this week. The mechanism matters more than the number. An attacker created unbacked XRP on another blockchain, presented it to the bridge, and the bridge exchanged it for real XRP out of its reserve. The software mistook fake deposits for real ones. The bridge has since been halted.

Nothing cryptographic broke. No key leaked, no signature forged, no consensus failure. The software did exactly what it was written to do: it received a claim that a deposit had occurred on the other side, believed it, and paid. Every component behaved correctly except the one nobody counts as a component, the assumption that an incoming assertion is true.

TL;DR

  • An XRP bridge paid out roughly $200,000 of real reserves against unbacked tokens minted on another chain, after its software accepted fake deposits as real.
  • Nothing was cryptographically broken. The bridge verified that somebody said a deposit happened, not that one had.
  • A Chainlink VRF proof covers one input to a game, the randomness, and says nothing about whether your stake, ticket, eligibility or balance arrived with any proof at all.
  • Crypto gaming reintroduces asserted inputs constantly: bridged stakes, backend deposit watchers crediting balances, tickets minted from a signature issued by the studio’s own API.
  • Satoshie stakes are escrowed in the same transaction that requests the randomness, on one chain with no bridge in the settlement path, so there is no separate assertion that you paid.

The sixteenth unasked half of fairness

This series works through the things a fairness proof does not cover: recourse after finality, payout timing, the entrant set, rule mutability, the durability of the record, the price of un-settling a settled result, the source that reports the outcome. Number sixteen is the one this bridge just demonstrated in public: the inputs you did not verify.

Split every input a system consumes into two categories and the whole thing becomes obvious.

A proof-carrying input arrives with evidence the receiving system checks itself, mechanically, before acting. Fail the check and the input is rejected with no human involved in that decision. A Chainlink VRF word is proof-carrying: the coordinator verifies the cryptographic proof on-chain before your game’s callback ever fires.

An asserted input arrives as somebody’s word. A relayer’s message, a signed attestation from a validator set, an API response from your own backend. The receiving system can verify that the assertion was properly formed and properly signed. What it cannot do is verify the underlying fact. It is checking that somebody said it, not that it happened.

Almost every large bridge failure in this industry is the same sentence: the system verified the message and not the world. That is not a slur on bridge engineers. Verifying the world properly means running a light client of the source chain inside the destination chain, which is expensive, slow and often impractical. Attestation is the compromise everyone reached, and its cost only shows up on the day somebody works out how to produce a convincing claim.

What this has to do with a coinflip

A VRF proof begins at the request and ends when the coordinator verifies it and the callback fires. Inside that window the guarantee is total. Outside it the proof says nothing, and a game has more inputs than randomness.

It has your stake, your ticket, the entrant count, and on most platforms a balance, which is less an input than a claim about a series of earlier inputs. Ask of each one: did the contract that decides my outcome verify this itself, or did it accept a report?

Four places where crypto gaming answers “a report”, usually without saying so. Bridged stakes: the game sits on a chain your money is not on, so the fairness claim covers the draw while the bridge upstream of it is nobody’s marketing responsibility. Backend deposit watchers: a service watches the chain and credits a balance in a database, making your balance an operator’s assertion about an on-chain fact, usually correct and never checkable without asking them. Signed tickets and points: entries minted on a signature from the studio’s own API, which verifies perfectly and proves only that the studio’s key signed something. Off-chain eligibility: whitelists, tiers and multipliers computed elsewhere and passed in as parameters, because nobody can enforce their way out of a wrong input.

This is structurally worse in gaming than in the bridge that just got hit. When a bridge accepts a fake deposit it prints an unbacked token or empties a visible reserve, and the discrepancy is a public balance anyone can watch. That is how this one surfaced. When a game accepts a fake input, a credited balance nobody paid for or a ticket nobody bought, it surfaces as an ordinary losing night for somebody else: no reserve to check, no supply to compare against, no artefact to reconstruct from. And a game processes thousands of resolutions a day, each a fresh opportunity for an unverified input to decide who gets paid.

The test

Does the thing that decides your outcome verify its inputs itself, or does it verify that someone told it something? A signature check is not a fact check. If the answer to “how does the contract know you paid” is “our backend told it”, the honesty of the draw is a proof sitting downstream of a step with no proof at all.

Satoshie’s version is not a philosophy, it is an exercise in having fewer inputs. One chain, so no bridge in the settlement path and no cross-chain message to spoof. No accounts and no balances, so nothing for a deposit watcher to credit. Your stake is escrowed in the same transaction that requests the randomness, so “did this player pay” is not an assertion the contract accepts, it is a state change the contract performed. Tickets require payment in the same transaction that mints them, and ticketsMinted is contract state you read before you enter rather than a number we render for you. Resolution happens inside the VRF callback in verified, immutable code: coinflip is one modulo on the VRF word, raffle is keccak256(VRF word + prior blockhash) % ticketsMinted. No privileged mint, no admin key.

The honest limits. If the stablecoin you stake with reached your wallet over a bridge, that happened upstream of us and no contract we deploy fixes it; the issuer can also freeze it, a trust assumption we inherit rather than remove. Our front end is an ordinary web application and the least trustworthy thing we ship. Base’s sequencer is operated by Coinbase and is not decentralised today, with data posted to Ethereum mainnet and L1 forced inclusion as the backstop. Immutability means our own bugs are permanent.

Three questions

  • When you place a bet, does the contract that decides the outcome receive your money, or does it receive a message saying your money arrived somewhere else?
  • If the platform’s backend signed something incorrect tomorrow, what in the system would reject it, and could you point at that check?
  • How many separate systems have to be honest between your funds leaving your wallet and the outcome being decided, and can you name them?

The bridge did not get hacked in any sense the word usually implies. It got told a lie in a format it was built to trust. Every fairness claim in crypto gaming has at least one input in that same position, and almost none of them mention it.

📷 Photo by Modestas Urbonas on Unsplash

Valentina Ní Críonna

Author Valentina Ní Críonna

More posts by Valentina Ní Críonna