40,000 USDC
View results
Submission Details
Severity: medium
Valid

If seller gets blacklisted, attacker can exploit this to block any attempts to recover funds from escrow.

Summary

If the seller is blacklisted during the escrow process, fund recovery from the contract relies solely on the arbiter's intervention. Nonetheless, an attacker can obstruct the arbiter from executing resolveDispute(), resulting in funds being locked in the escrow contract indefinitely.

Vulnerability Details

There are only two possible ways to transfer funds out of the Escrow contract, either by calling confirmReceipt() or resolveDispute(). On the situation of the seller becoming blacklisted (if the token supports this, e.g USDC, USDT, etc) it is impossible to call confirmReceipt() as every call will revert due to the blacklist of the seller's address. Therefore the only way for recovering the funds in the Escrow contract is through the resolveDispute() function. Unfortunately, under these circumstances resolveDispute() is susceptible to being blocked by an attacker, as will be described below.

Consider an example Escrow contract with 10000 USDC, in the above case (seller address gets blacklisted) the funds could be recovered only if the arbiter calls resolveDispute() with buyerAward = price - arbiterfee, this way during the execution of resolveDispute(), after the funds are transfered first to the buyer and the arbiter and the remaining balance on the contract will be zero, therefore skipping the transfer to the seller and thus sucessfully getting the funds out of the Escrow contract.

However, if a contract is in this situation, a malicious actor can exploit this to block the recover of funds by frontrunning the arbiters' resolveDispute() with a minimum deposit of the selected token to the contract. As a consequence, after the transfers to the buyer and the arbiter the balance will not be zero, thus when trying to transfer the remaining funds to the buyer, it will revert due to the blacklist. See the example scenario below. There is a deployed escrow with 10000 USDC (USDC balance = 1e10) balance and with arbiterfee set to 500 USDC. for whatever reason the seller gets blacklisted, making impossible to call confirmReceipt().

  1. Arbiter has to interfere as it is the only way to recover the funds from the escrow. Therefore he calculate buyerAward to price - arbiterFee = 10000000000 - 500000000 = 9500000000 and calls resolveDispute(9500000000).

  2. The attacker is monitoring the mempool, see the arbiter transaction and tries to frontrun it by transfering 1 unit of USDC to the escrow addresss.

If the attacker succeed in frontrunning the arbiter, the Escrow balance is now higher than the arbiter calculations, therefore when the arbiter's resolveDispute() call is being executed it will revert, as shown in the resolveDispute() below.

// Escrow USDC balance = 10000000001
if (buyerAward > 0) {
i_tokenContract.safeTransfer(i_buyer, buyerAward);
}
// Escrow USDC balance = 500000001
if (i_arbiterFee > 0) {
i_tokenContract.safeTransfer(i_arbiter, i_arbiterFee);
}
// Escrow USDC balance = 1
tokenBalance = i_tokenContract.balanceOf(address(this));
if (tokenBalance > 0) {
i_tokenContract.safeTransfer(i_seller, tokenBalance);
// the above transfer will revert because of the seller address blacklist
}

Impact

In scenarios where the seller is blacklisted during the escrow process, an attacker can block the arbiter's attempts to recover funds back. He can repeat the attack every time the arbiter tries to call resolveDispute(), locking the funds in the escrow contract for an indeterminate amount of time.

Tools Used

Manual Review

Recommendations

Consider changing resolveDispute() so that the arbiter specifies both the sellerAward and also the buyerAward. This way the arbiter can guarantee that no matter which party (seller or buyer) gets blacklisted, the funds can be recovered, because he controls exactly how much tokens will be transferred and therefore not susceptible to the attack described above.

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.