40,000 USDC
View results
Submission Details
Severity: medium

The seller can DoS all buyer's escrow without any consequence

Summary

The seller can keep calling initiateDispute in any accepted escrow just to DoS the buyer without any punishment. Since only the arbiter is trusted, and the buyer is handling all the risk, the arbiter should be the one that allows the seller to call initiateDispute because the seller doesn't lose anything.

Vulnerability Details

If there is any dispute between the buyer and the seller during the process of the project, either party can initiate a dispute by calling initiateDispute() and asking an impartial 3rd party, the arbiter, to solve the case. However, the buyer has to think twice before calling dispute because he has to pay the arbiter fee. The seller has no consequence because his funds is not locked up in the contract and he doesn't need to pay the arbiter fee. Thus, the seller can call the dispute at any time just to DoS the process.

function initiateDispute() external onlyBuyerOrSeller inState(State.Created) {
if (i_arbiter == address(0)) revert Escrow__DisputeRequiresArbiter();
s_state = State.Disputed;
emit Disputed(msg.sender);
}

I believe the protocol should be fair to both the buyer and seller. There should only be two main reasons for disputing:

  1. The seller doesn't do his work

In this case, the buyer has every right to dispute the issue and make sure that he gets his money back (minus arbiter fees) without having to pay the seller

  1. The buyer doesn't want to pay up

In this case, the seller has every right to dispute and ask for payment. Since the arbiter is handling the distributions of funds, the arbiter can pay the seller using the buyer's deposit

Any other reason would not be fair to either parties, for example:

  1. The seller is has poor work ethic / is malicious

If the seller is malicious, he should not be able to dispute the issue and not let the buyer lose out on arbiter fees. However, the current iteration of the protocol means that the seller can call dispute and go MIA, and the buyer has to fork out the arbiter fees, which is unfair for the buyer.

This is an issue because the buyer and seller is not assumed to be trustable, otherwise no escrow protocol will ever need to exist. Only the arbiter is assumed to be trustable. Thus, to make this escrow process the most fair for both buyers and sellers, the seller should be granted conditional rights to call `initiateDispute() by the arbiter.

Impact

The seller can call a dispute with nothing much to lose. The person that loses out is the buyer because he has to pay for the arbiter fee.

Tools Used

Manual Review

Recommendations

Recommend splitting the initiateDispute() function into two: one for the buyer and one for the seller. The buyer can call it anytime he likes because he is the one at risk with the funds. The seller only can call initiateDispute() if the arbiter allows (and if there is an arbiter in the first place). Since the arbiter is always trusted, the buyer can trust the arbiter to solve his dispute if he calls initiateDispute(), and the seller can trust the arbiter to grant him disputing rights if the buyer becomes malicious because the arbiter is fair and just.

Support

FAQs

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