Platform: Code4rena
Start Date: 16/10/2023
Pot Size: $60,500 USDC
Total HM: 16
Participants: 131
Period: 10 days
Judge: 0xTheC0der
Total Solo HM: 3
Id: 296
League: ETH
Rank: 49/131
Findings: 2
Award: $104.36
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: 0xStalin
Also found by: 0xCiphky, 0xComfyCat, 0xbepresent, 3docSec, Eigenvectors, Fulum, HChang26, Infect3d, QiuhaoLi, SandNallani, SovaSlava, TrungOre, YusSecurity, ZdravkoHr, ast3ros, ayden, bdmcbri, cu5t0mpeo, elprofesor, gizzy, jasonxiale, kodyvim, marqymarq10, max10afternoon, nisedo, nobody2018, radev_sw, rvierdiiev, serial-coder, xeros
13.1205 USDC - $13.12
https://github.com/code-423n4/2023-10-wildcat/blob/c5df665f0bc2ca5df6f06938d66494b11e7bdada/src/market/WildcatMarketConfig.sol#L74-L81 https://github.com/code-423n4/2023-10-wildcat/blob/c5df665f0bc2ca5df6f06938d66494b11e7bdada/src/market/WildcatMarketBase.sol#L163 https://github.com/code-423n4/2023-10-wildcat/blob/c5df665f0bc2ca5df6f06938d66494b11e7bdada/src/market/WildcatMarketToken.sol#L64-L82 https://github.com/code-423n4/2023-10-wildcat/blob/c5df665f0bc2ca5df6f06938d66494b11e7bdada/src/market/WildcatMarketBase.sol#L152-L153
In order to prevent a sanctioned lender (for example by OFAC) to poison an entire market, a function has been developed to block and transfer the sanctionned user's funds to an escrow contract. This escrow contract can be released if borrower decides so (by setting up an override), or if sanctioned lender is removed from the sanction lists.
To do that, the borrower (or any actor) can call nukeFromOrbit
, which will change authentication role of user to AuthRole.Blocked
which basically disallow him any action on the market, and as said before, by calling _blockAccount
seize and transfer the funds to an escrow contract, waiting for more clarity on the situation.
But there is a way for the sanctionned lender to avoid this situation.
The requirement are:
nukeFromOrbit
[WildcatMarketToken::transfer](https://github.com/code-423n4/2023-10-wildcat/blob/c5df665f0bc2ca5df6f06938d66494b11e7bdada/src/market/WildcatMarketToken.sol#L36-L39)
_transfer
, through _getAccount
ensure lender isn't blocked, this check pass as he is not blocked yet, only sanctionnedOnce the balance has been queued, while borrower could decide not to process the request (to prevent user to get the funds), this would have this impact:
All of this is possible because nothing in WildcatMarketToken
prevent a sanctioned lender to operate a transfer, even if he is in the sanction list.
There is indeed a _getAccount
call which checks if an address has AuthRole.Blocked
and revert if true, but by front-running the blocking action, he can transfer the funds before this role is assigned.
Because this situation will impact the withdrawing function availability until solved, and can incur losses (through deliquency) to the borrower until finding a proper solution, also impacting the reputation of the protocol, I categorized this vulnerabilty as high.
Code review
It doesn't seem that transfer of scaledBalance will be used very often, devs could add a check to sanction list on the "from" address to prevent a sanctionned user to move its funds at all, and thus escape the escrow. This change could be applied:
diff --git a/src/market/WildcatMarketToken.sol b/src/market/WildcatMarketToken.sol index f6a7f94..27c32c8 100644 --- a/src/market/WildcatMarketToken.sol +++ b/src/market/WildcatMarketToken.sol @@ -62,6 +62,7 @@ contract WildcatMarketToken is WildcatMarketBase { } function _transfer(address from, address to, uint256 amount) internal virtual { + require(!IWildcatSanctionsSentinel(sentinel).isSanctioned(borrower, from),"from is sanctionned"); MarketState memory state = _getUpdatedState(); uint104 scaledAmount = state.scaleAmount(amount).toUint104();
Invalid Validation
#0 - c4-pre-sort
2023-10-27T03:14:57Z
minhquanym marked the issue as duplicate of #54
#1 - c4-judge
2023-11-07T14:37:21Z
MarioPoneder marked the issue as satisfactory
🌟 Selected for report: osmanozdemir1
Also found by: 0xCiphky, 0xStalin, HChang26, Infect3d, Jiamin, Juntao, QiuhaoLi, circlelooper, crunch, rvierdiiev
91.2409 USDC - $91.24
When a user is sanctioned, if he has a scaledBalance
(not in the withdrawal queue), calling the nukeFromOrbit
function will send sanctioned funds to an escrow contract, and these funds will keep earning APR.
This is because when a deposit is executed, the deposited amount is converted to a scaledBalance
, by dividing amount by the scaleFactor
(which can be seen as an exchange rate between the underlying token and the market shares). And only when withdrawn, the scaleBalance
is multiplied back by the scaleFactor, which will have grown in regard to the APR and other fees owed by the borrower.
But the protocol itself will also earn fees on the sanctionned balance, as the ProtocolFee
is calculated from state.scaledTotalSupply
(L47):
File: src\libraries\FeeMath.sol 40: function applyProtocolFee( 41: MarketState memory state, 42: uint256 baseInterestRay, 43: uint256 protocolFeeBips 44: ) internal pure returns (uint256 protocolFee) { 45: // Protocol fee is charged in addition to the interest paid to lenders. //note baseInterestRay: interest rate accrued to lenders 46: uint256 protocolFeeRay = protocolFeeBips.bipMul(baseInterestRay); 47: protocolFee = uint256(state.scaledTotalSupply).rayMul( 48: uint256(state.scaleFactor).rayMul(protocolFeeRay) 49: ); 50: state.accruedProtocolFees = (state.accruedProtocolFees + protocolFee).toUint128(); 51: }
And this variable isn't decreased when escrowing the sanctionned funds. This means both borrower and protocol will still interact with the sanctionned address and funds, even if it has been blocked by the market.
Code review
When blocking an account, automatically queue, apply and execute sanctionned lender balance so that it is normalized back, removed from the total supply and thus stop earning fees and paying APR on it. This will ensure that no sanctioned funds leaks after being blocked.
Another way to do this would be to save the scaleFactor
in a specific variable (like scaleFactorAtSanction
) and use this scale factor rather than the current one to convert the market shares to the underlying asset on withdraw.
Other
#0 - c4-pre-sort
2023-10-27T14:47:37Z
minhquanym marked the issue as duplicate of #123
#1 - c4-judge
2023-11-07T18:14:15Z
MarioPoneder marked the issue as satisfactory