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

Malicious Buyer can theft funds

Summary

The "Escrow" smart contract contains a vulnerability that could allow funds to be stolen if the buyer and the arbiter are at the same address. This scenario could result in unintended consequences and potential loss of funds.

Vulnerability Details

constructor(
uint256 price,
IERC20 tokenContract,
address buyer,
address seller,
address arbiter,
uint256 arbiterFee
) {
if (address(tokenContract) == address(0)) revert Escrow__TokenZeroAddress();
if (buyer == address(0)) revert Escrow__BuyerZeroAddress();
if (seller == address(0)) revert Escrow__SellerZeroAddress();
if (arbiterFee >= price) revert Escrow__FeeExceedsPrice(price, arbiterFee);
if (tokenContract.balanceOf(address(this)) < price) revert Escrow__MustDeployWithTokenBalance();
i_price = price;
i_tokenContract = tokenContract;
i_buyer = buyer;
i_seller = seller;
i_arbiter = arbiter;
i_arbiterFee = arbiterFee;
}

here, Buyer can set buyer and i_arbiter as same address.

function initiateDispute() external onlyBuyerOrSeller inState(State.Created) {
if (i_arbiter == address(0)) revert Escrow__DisputeRequiresArbiter();
s_state = State.Disputed;
emit Disputed(msg.sender);
}
/// @inheritdoc IEscrow
function resolveDispute(uint256 buyerAward) external onlyArbiter nonReentrant inState(State.Disputed) {
uint256 tokenBalance = i_tokenContract.balanceOf(address(this));
uint256 totalFee = buyerAward + i_arbiterFee; // Reverts on overflow
if (totalFee > tokenBalance) {
revert Escrow__TotalFeeExceedsBalance(tokenBalance, totalFee);
}
s_state = State.Resolved;
emit Resolved(i_buyer, i_seller);
if (buyerAward > 0) {
i_tokenContract.safeTransfer(i_buyer, buyerAward);
}
if (i_arbiterFee > 0) {
i_tokenContract.safeTransfer(i_arbiter, i_arbiterFee);
}
tokenBalance = i_tokenContract.balanceOf(address(this));
if (tokenBalance > 0) {
i_tokenContract.safeTransfer(i_seller, tokenBalance);
}
}

malicious Buyer can initiate dispute using initiateDispute() and will call resolveDispute() with all the contract token balance as buyerAward and transfer funds back to his account address.

Impact

it allows the arbiter to withdraw the entire dispute amount, effectively stealing the funds intended for the buyer. Seller will be left with no token.

Tools Used

Manual Review

Recommendations

add check that if (buyer == arbiter) revert Escrow__BuyerEqualsArbiter();

Support

FAQs

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