This means that getEscrowAddress(borrower, account, asset) returns a different address. The immediate implication of this is that a user or contract interfacing with getEscrowAddress() will be unable to find the correct WildcatSanctionsEscrow.
Furthermore, the borrower and account will then have swapped places also in the deployed WildcatSanctionsEscrow. This means that canReleaseEscrow() now returns !WildcatSanctionsSentinel(sentinel).isSanctioned(account, borrower); which most likely is true since it was the account that was sanctioned, not the borrower. Then the borrower can releaseEscrow() which will now IERC20(asset).transfer(borrower, amount);. That is, the borrower can immediately transfer the lender's escrowed funds to himself.
createEscrow() will now also set sanctionOverrides[account][escrowContract] = true;, which seems less of an issue.
Lines of code
https://github.com/code-423n4/2023-10-wildcat/blob/c5df665f0bc2ca5df6f06938d66494b11e7bdada/src/market/WildcatMarketBase.sol#L173-L174 https://github.com/code-423n4/2023-10-wildcat/blob/c5df665f0bc2ca5df6f06938d66494b11e7bdada/src/market/WildcatMarketWithdrawals.sol#L167-L168
Vulnerability details
Impact
getEscrowAddress()
returns the wrong WildcatSanctionsEscrow. Borrower can steal lender's escrowed funds.Proof of concept
createEscrow()
andgetEscrowAddress()
both take the parametersborrower
,account
,asset
, in that order, as defined in WildcatSanctionsSentinel.sol. However, wherecreateEscrow()
is used, inWildcatMarketBase._blockAccount()
and inWildcatMarketWithdrawals.executeWithdrawal()
, the intendedborrower
andaccount
have swapped places.This means that
getEscrowAddress(borrower, account, asset)
returns a different address. The immediate implication of this is that a user or contract interfacing withgetEscrowAddress()
will be unable to find the correct WildcatSanctionsEscrow.Furthermore, the
borrower
andaccount
will then have swapped places also in the deployed WildcatSanctionsEscrow. This means thatcanReleaseEscrow()
now returns!WildcatSanctionsSentinel(sentinel).isSanctioned(account, borrower);
which most likely istrue
since it was theaccount
that was sanctioned, not theborrower
. Then the borrower canreleaseEscrow()
which will nowIERC20(asset).transfer(borrower, amount);
. That is, the borrower can immediately transfer the lender's escrowed funds to himself.createEscrow()
will now also setsanctionOverrides[account][escrowContract] = true;
, which seems less of an issue.Recommended mitigation steps
Correct the order of the parameters in
WildcatMarketBase._blockAccount()
and inWildcatMarketWithdrawals.executeWithdrawal()
.Assessed type
Context