Sparkn

CodeFox Inc.
DeFiFoundryProxy
15,000 USDC
View results
Submission Details
Severity: high

Malicious user can front-run `deployProxyAndDistributeBySignature` function to steal 95% of funds.

Summary

A malicious user can front-run deployProxyAndDistrubuteBySignature function in order to steal 95% of the funds.

Vulnerability Details

There are many ways in the protocol to deploy the proxy and distribute the funds. One of the ways is by calling the function deployProxyAndDistrubuteBySignature.

function deployProxyAndDistributeBySignature(
address organizer,
bytes32 contestId,
address implementation,
bytes calldata signature,
bytes calldata data
) public returns (address) {
bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(contestId, data)));
if (ECDSA.recover(digest, signature) != organizer) revert ProxyFactory__InvalidSignature();
bytes32 salt = _calculateSalt(organizer, contestId, implementation);
if (saltToCloseTime[salt] == 0) revert ProxyFactory__ContestIsNotRegistered();
if (saltToCloseTime[salt] > block.timestamp) revert ProxyFactory__ContestIsNotClosed();
address proxy = _deployProxy(organizer, contestId, implementation);
_distribute(proxy, data);
return proxy;
}

The problem here, is that this function is subject to a front-run. No where in the logic does is check if msg.sender is the organizer. Instead the organizer must provide his signature. The problem with this is that the ethereum mempool is a Dark Forest anyone can see the organizer's tx in the the mempool and copy all of the data including the signature and front run the organizers tx. Now, the malicious attacker can inject whatever data he wants to and since tokens are sent to the proxy contract before hand, the attacker can set himself as the only winner of the contest and take all of the funds - the fees.

Proof Of Concept

  1. Organizer has sent funds to the proxy address, this is the intended flow of the protocol according to the read me and natspec.

  2. Organizer decides to deploy proxy and distribute awards via the function deployProxyAndDistributeBySignature.

  3. The organizer calls the function and all the details, including the signature, are sent to the mempool for anyone to see.

  4. A malicious user can then copy all of the tx input data and front-run the organizers tx.

  5. the data parameter is never validated in the function so the attacker can inject his own data into his front-runned tx.

  6. Since the data is used for distribution of awards, the attacker can set himself as the only winner, and allocating 95% of the funds to himself.

  7. why only 95% and not the full 100%? This is because in the implementation contract there is a check that does not allow the percentages to add up to more than 95%

if (totalPercentage != (10000 - COMMISSION_FEE)) {
revert Distributor__MismatchedPercentages();
}
  1. the proxy will then distribute 95% of all of the tokens to the attackers wallet and 5% of the tokens to the stadium address as the fee.

  2. By copying all of the inputs of the organizer, except for the data, the malicious user has now successfully stolen almost all of the funds.

Impact

Nearly all of the funds can be stolen by a malicious actor

Tools Used

Manual Review

Recommendations

Honestly the best way to fully remove the issue is to remove the function deployProxyAndDistributeBySignature because of the risk of front running. Regardless, there exist other functions that do the same thing but are not susceptible to front running. Such as the function deployProxyAndDistribute.

Support

FAQs

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

Give us feedback!