Submitted by 0xStalin, also found by elprofesor, Infect3d, serial-coder, xeros, radev_sw, jasonxiale, ast3ros, QiuhaoLi, Fulum, TrungOre (1, 2), SandNallani (1, 2), SovaSlava, kodyvim, 0xbepresent, Eigenvectors, 3docSec, marqymarq10, ayden, HChang26, cu5t0mpeo (1, 2), 0xCiphky (1, 2), rvierdiiev (1, 2), nobody2018, YusSecurity, gizzy, nisedo, bdmcbri, ZdravkoHr, 0xComfyCat, and max10afternoon
Lenders can escape the sanctioning of their account in any market.
Before diving into the details of how the lenders can escape the sanctioning of their account, first, lets analyze how a lender can be excised from a Market:
In either of the two options, the execution flow calls the Sentinel::isSanctioned() function to verify if the account(lender) is sanctioned by the borrower of the market
WildcatSanctionsSentinel.sol
Now, based on the previous explanation, we know that the lenders account needs to be sanctioned in the Chainalysis Oracle before the Sentinel::isSanctioned() function is called.
This opens up the doors for lenders who realize that their account has been sanctioned in the Chainalysis Oracle to move their MarketTokens to different accounts before the lenders account is fully blocked in the Market. You may be wondering whats the point of transferring tokens to accounts that have not been granted any role in the Market, Ill explain more about this shortly.
The lender transfers their MarketTokens to different accounts using the WildcatMarketToken::transfer() function. As a result, the lenders account that is sanctioned in the Chainalysis Oracle has no MarketTokens anymore; all those tokens have been moved to other accounts.
Now, at this point, anybody could call the nukeFromOrbit() function to fully sanction the lenders account in a specific Market. Ether way, the Lender has already moved their tokens to other accounts.
At this point, the lenders MarketTokens were distributed among different accounts of their own. Such accounts have never interacted with the Market, so their current role is the Null Role.
Everything might look fine because the accounts where the tokens were sent have no permissions to interact with the Market, but there is a bug that allows lenders to gain the WithdrawOnly Role on any account they want, without having the consent of the borrower.
This problem is located in the WildcatMarketController::updateLenderAuthorization() function. The reason of this problem will be explained in the below code walkthrough:
In short, the Lender will be able to set the WithdrawOnly Role to any account they wish. The reason is that any account that is not registered in the _authorizedLenders variable of the Controller will forward the value of _isAuthorized as false. In the WildMarketConfig::updateAccountAuthorization() function, because the value of _isAuthorized is false, it will end up granting the WithdrawOnly Role. This effectively allows any Lender to grant the WithdrawOnly Role to any account they want to.
WildcatMarketController.sol
EnumerableSet.sol
WildcatMarketConfig.sol
At this point, the Lender has been able to move their MarketTokens to different accounts and to grant the WithdrawOnly Role to all of the accounts they wish to.
Now, they can decide to exit the Market by queuing and executing some withdrawal requests from the different accounts where the MarketTokens were moved. Any of those accounts have now the WithdrawOnly Role and have a balance of MarketTokens, so the Lender will be able to exit the market from any of those accounts.
The mitigation for this problem is very straight-forward, by limiting the access to which entities can call the WildcatMarketController::updateLenderAuthorization() function; either only allow the Borrower to call it, or create a type of whitelist of valid actors who are capable of updating the lenders authorization on the Markets. In this way, the Lenders wont be capable of granting the WithdrawOnly Role to any account they want to; thus, they wont be able even to attempt to escape the sanctions.
WildcatMarketController.sol
Context
0xTheC0der (judge) increased severity to High
laurenceday (Wildcat) commented:
laurenceday (Wildcat) confirmed
