Resources
People often ask me "How did you learn how to hack?" The answer: by reading. This page is a collection of the blog posts and other articles that I have accumulated over the years of my journey. Enjoy!
Relay Protocol has a Bitcoin bridge. Here's how a transfer works going to the bridge:
- A user is given a unique deposit address via NEAR MPC, to which the user sends the BTC.
- After the deposit is confirmed,
sweep() is called with the UTXO, and the fee.
- Relay builds a transaction that sends the deposit (minus the fee) into a single account.
- NEAR MPC signs the transaction and broadcasts it to Bitcoin.
Since NEAR MPC can't see the UTXO, there's some off-chain code that reviews the UTXO and then signs for it. There are a few checks in this code. It checks that the fee doesn't exceed the maximum rate; otherwise, you'd be able to drain the entire deposit. What it DOESN'T check is that the value submitted on the sweep matches the UTXO! The UTXO is a one-time-use deposit address, so you can't overcredit the user, though. So, what's the issue?
On Bitcoin P2PKH mode, the SIGHASH_ALL preimage does NOT include the amount of the input being spent. Since the fee is calculated sum(inputs) - sum(outputs) this becomes a permisionless DoS. On the call to sweep, send a very small amount compared to the UTXO. Now, most is burned as the fee instead of being used as the actual value.
This appears to steal funds from the user; it doesn't affect the protocol's solvency. Great bug in the nuances of Bitcoin parsing.