Open code423n4 opened 3 years ago
That's a good catch. The mitigation steps are right to avoid this being exploited by malicious users, but it would be better to fix the underlying issue.
The problem is that the Witch always applies a 1:1 exchange rate between underlying and fyToken, and that is not true after maturity. As long as this is not fixed, the protocol will lose money on after maturity liquidations.
More specifically, _debtInBase
should be a Cauldron public function, and return (debtInFYToken, debtInBase). The Ladle would save a bit in deployment gas, the Witch would use it to find out the underlying / fyToken exchange rate.
However, since grab
wouldn't be called on the Witch, the vault owner wouldn't be registered. With the liquidation being a Dutch auction, the vault owner would only get a portion of his collateral back after paying all the debt. The vault with the remaining collateral would be given to address(0).
There is a small protocol loss from miscalculated vault debt on vaults liquidated after maturity, but no user funds would be at risk.
I would propose a severity of 2, given there are monetary losses, however slight, to the protocol. The attack described can't happen, but it revealed a real issue.
Handle
shw
Vulnerability details
Impact
According to the protocol design, users have to pay borrowing interest when repaying the debt with underlying tokens after maturity. However, a user can give his vault to
Witch
and then buy all his collateral using underlying tokens to avoid paying the interest. Besides, this bug could make users less incentivized to repay the debt before maturity and hold the underlying tokens until liquidation.Proof of Concept
Ladle
), which is his debt multiplied by the rate accrual (line 373).Witch
by calling the functionbatch
ofLadle
with the operationGIVE
.buy
ofWitch
with the correspondingvaultId
to buy all his collateral using underlying tokens.In the last step, the
elapsed
time (line 61) is equal to the current timestamp since the vault is never grabbed byWitch
before, and thus the auction time of the vault,cauldron.auctions(vaultId)
, is 0 (the default mapping value). Therefore, the collateral is sold at a price ofbalances_.art/balances_.ink
(line 74). The user can buybalances_.ink
amount of collateral usingbalances_.art
but not paying for borrowing fees.Referenced code: Ladle.sol#L350 Ladle.sol#L368-L377 Ladle.sol#L267-L272 Cauldron.sol#L234-L252 Witch.sol#L61 Witch.sol#L74
Recommended Mitigation Steps
Do not allow users to
give
vaults toWitch
. To be more careful, requirevaultOwners[vaultId]
andcauldron.auctions(vaultId)
to be non-zero at the beginning of functionbuy
.