The TokenManager
contract allows adding and removing assets from the list of accepted tokens. These are the assets which are allowed to be used inside the protocol. When any asset is removed from this list, a major issues occur, as well as a direct attack path to steal an arbitrary amount of EURO tokens.
The currently deployed TokenManager contract can be found here: https://arbiscan.io/address/0x33c5A816382760b6E5fb50d8854a61b3383a32a0#code
And as we can see here, it allows to remove assets from the list of accepted tokens:
The getAcceptedTokens
function from the TokenManager
contract is used in the liquidate
function to get the list of collateral tokens to liquidate. Here we can see that the liquidate
function updates the minted
amount to 0, loops over all tokens inside the accepted tokens list and transfers them to the SmartVaultManager
:
Now suppose the vault was collateralized with a token that was removed from this list. The vault will be instantly liquidateable as EUROs were borrowed but no collateral can be found in the vault. The minted variable is still set to 0, but collateral tokens stay inside this vault, as the token is not part of that for loop.
So the collateral stays in the vault, the minted amount is updated to 0 and the stakers / the protocol gets nothing. The borrower is now able to remove this collateral tokens out of the system by calling removeAsset
, which will check if the collateral can be removed by calling canRemoveCollateral
and this function will instantly respond with true as the minted
amount was set to 0:
Therefore, the borrower keeps the borrowed EURO tokens, as well as the collateral tokens. An arbitrary amount of EURO tokens can be stolen with this attack path. Especially if the malicious actor would sandwich the call that removes any collateral token from that list, it would be possible to front run the call and take a big loan with this collateral token and back run it to liquidate the own loan and remove the collateral from the vault.
The following POC can be implemented in the smartVault
test file and showcases how a malicious actor can exploit the removal of a token:
Another problem with removing accepted tokens occurs in the LiquidationPool
contract. Stakers can stake TST and EURO tokens to be able to buy collateral tokens for a discount with it. The bought collateral tokens are saved inside a mapping and can be claimed anytime by the staker with the claimRewards
function:
As we can see, this function also loops over the accepted tokens list. If there are unclaimed rewards and the token gets removed from the accepted tokens list, then all of these funds will be frozen in the contract and no longer claimable. As the staker already paid for these rewards with EURO tokens, funds were stolen from the staker.
Malicious actors can steal funds from the protocol, especially when they sandwich the removal call.
Borrowers can not be liquidated or only partially liquidated (if multiple collateral tokens are in the vault).
Rewards can not be claimed and are frozen in the LiquidationPool
, but stakers already paid for them.
There are multiple ways to fix this issue. This suggestion is not the most beautiful design choice, but it is one way to fix the issue by touching the current system logic as little as possible:
add the ifNotLiquidated
modifier to the remove asset / collateral functions
implement functions for the whole liquidation / claim reward flow which do the same thing for specified token addresses instead of the whole accepted tokens list
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.