Achilles heels of Lightning services
One of the main components of the Standard Sats project is the Hedge service. It must be deployed along with Lightning Network client Eclair and its plugins and allows the creation of synthetic assets on-the-fly while the LN transaction settles. We have released this service to the public and it relies on Kollider Exchange. We selected this exchange as a proof-of-concept for the whole technology and concluded that synthetic assets may reliably work with the types of contracts provided by this exchange. Besides that, LN-native exchange creates conditions for creating risk-minimized systems thanks to instant settlement and hedging capital may be dynamically adapting to users’ demands.
While preparing open-sourcing of the Hedge service and increasing our liquidity on exchange deposits we also tried to look into how safely the Kollider exchange operates and we discovered a few unpleasant surprises.
Standard Sats maintains a custom fork of Simple Bitcoin Wallet by Anton Kumaigorodsky, Ukrainian developer and a fighter. StS SBW tries to preserve all functionality of the original wallet except that instead of Hosted Channel it opens Fiat Channel by default. User may open normal channels with any public node in the network and use onchain wallet with bitcoins as well. An ability to generate HODL-invoice is one of its features. This invoice, when received, allows to put LN transaction on hold up until 15 minutes.
The first attack was so simple everybody could conduct it. And the attacker might not use a dedicated LN node at all. The exchage has been doing automatic returns on deposits after specific timeouts, and these timeouts were less than 15 minutes allowed by SBW interface. This fatal flaw was immidiately reported to Kollider developers and they stopped automatic withdrawals. With 5.7 BTC of total node liquidity the exchange agreed to pay 20M in bounty for discovering this bug (while it regularly rewards millions to competitors). We knew how this attack might be automated. By occasion we even tested specific eclair plugin few days before discovering this vulnerability. “We should hack them” said my peer after some hours of bargaining for bounty size. We couldn’t enjoy it because half of this bounty we decided to put into insurance deposit. We knew the exchange was insecure.
Fee Siphoning Attack
After exploiting Kollider with just Android Wallet, I decided to check if I could conduct what already became a classic LN attack. To do such attack a malicious actor needs to provide certain simple topology to collect fees paid by custodial service. Therefore this time I needed a dedicated LN node. An attacker controls intermediate routing node and increases significantly fees on final hop. On the first step attacker deposits funds and on the second step he or she just withdraws money. Cycle may be repeated indefinitely until the channel between Custodial Service and Routing node becomes totally exhausted and after that the attacker needs only wait a bit or manually rebalance channel, effectively draining liquidity from other channels of the Custodial service node. So far at that time Kollider allowed to withdraw funds into channels with fees from 10 000 ppm to 50 000 ppm. Simply speaking maximum successfull fee we could get from the payment was 30%.
We agreed with my peer on splitting bounty and work together. After few hours I got everything ready, confirmed attack vector and we were ready to do really evil things. However, as in the first time we decided to cooperate with exchange because we had long term plans regarding using its services, so we have reported about yet another vulnerability and suprisingly found ourserves in even cheaper talks about bounty. Since I felf myself pretty exhausted I decided not to bargain anymore and just dropped description of the attack to Kollider developers.
After a while, “Withdrawal rejection” from Kollider User Interface made me angry because I errornously thought it started banning payments with routing hints. The Exchange still subsidized users’ withdrawals and I decided to exploit this. So I took their market-maker bot, made some changes and allowed it to interact with LN node for making deposits and withdrawals. I realized that “Withdrawal rejection” works only above some fee threshold and not because the invoice has route hints for private channels. After proportional fee adjustment the bot started working relatively smoothly while depositing and withdrawing funds. I allowed it to do some trading so activity wouldn’t look completely artificial.
After couple of days I’ve noticed that web-socket events arriving with a bit late information about daily withdrawal limits. It looked like an invitation to try to make few large withdrawals fast instead of slowly milking Kollider node with subsidy. The attempt failed because the assumption was wrong moreover the account was frozen and no funds could be withdrawn. Few hours after and few trades past, the account was unlocked again but I decided to stop “attacking” their node because they discovered that they actually control situation with their subsidies. They have capped maximum fee and they track fees on per-account level.
The Kollider Exchange proved that they are learning and this is important for Standard Sats because people may want running Eclair and using our Hedge service specifically designed for this exchange. If you like this post, this is LNURL for tipping me with sats.