interBTC is a wrapper around Bitcoin on the Polkadot ecosystem. Each interBTC is backed 1 to 1 for Bitcoin.
Over-collateralization is when a loan of more money is used to obtain something of lesser value. In the context of cryptocurrencies, this is commonly used for Collateralized Debt Position (CDP) protocols for minting stable coins from valuable assets. For instance, the MakerDAO does this for the DAI token.
In the context of InterBTC, a mapping of a high value token (BTC) to the native tokens of INTR and KINT can be made. Usually, the price properties of these tokens are made by price oracles. How do we trust these anonymous entities though?
When using Bitcoins assets from the Bitcoin blockchain to the Moonlight blockchain, there has to be a way to verify that the things claimed from BTC are correct. This is done via a Simplified Payment Verification (SPV) system. The validation is done by storing minimum information about the header of each block then checking the merkle proof and it.
An off-chain relayer ensures that the vaults don't move BTC unless specific calls are made. If a vault moves BTC without authorization, then the collateral of the vault is slashed. A vault can be reported for fraud by calling the function report_vault_double_payment(), which takes two txs and verify that they reference the same user request.
When comparing if two tx's are the different, the check is flawed. The class BytesParser will ignore trailing bytes of a raw transaction. This results in different transactions being parsed into the same transaction. From looking at the fix, it appears that a duplication check for the two IDs needs to be done. Hence, an attacker can report ANY vault and steal 5% of the funds while the rest get dumped.
Within Moonlight, there are several different versions of an address. All of the balances are maintained by uxtos; every utxtos has a public key which can only be unlocked with the corresponding ScriptSig or private key.
One of the interesting types is Pay to Script Hash (P2SH). Any public key can be encoded in a vault address with just its hash and the actual public key. The rest of the ScriptSig can be edited to match our mutable public key.
This creates a signature malleability problem with trying to ensure duplicates aren't being used. This isn't a problem until we enter the SPV system.
This lack of consistency on the public key has interesting implications. Within the SPV system, the function report_vault_theft gets the ScriptPubKey address from the ScriptSig. However, as mentioned before, we can arbitrarily forge these to return other vaults. So, we can always bypass the misbehavior checks and, even worse, we can get a benign vault slashed to steal money! P2WSH had a similar parsing problem as well.
What's the solution to this? Since these are fundamental design flaws, they decided to remove the theft reporting functions entirely. Overall, this was an awesome post diving into the complicated parts of a blockchain ecosystem.