Sparkn

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

FrontRunning during distrubution of tokens

Summary

There is an issue of frontrunning in the protocol. In the contract ProxyFactory, there are public functions that can deploy the proxy and distribute the tokens in the protocol, when this function is triggered by a transaction via owner or organizer, it can be frontrun by the attacker before the transaction is mined in the block.

Vulnerability Details

Ethereum nodes pool transactions and form them into blocks. The transactions are only considered valid once a miner has solved a consensus mechanism. The miner who solves the block also chooses which transactions from the pool will be included in the block, this is typically ordered by the gasPrice of a transaction. Here lies a potential attack vector. An attacker can watch the transaction pool for transactions that may contain solutions to problems. The attacker can then get the data from this transaction and create a transaction of their own with a higher gasPrice and get their transaction included in a block before the original. E.g This can happen with functions like

function deployProxyAndDistribute(bytes32 contestId, address implementation, bytes calldata data)
public
returns (address)
{
bytes32 salt = _calculateSalt(msg.sender, contestId, implementation);
if (saltToCloseTime[salt] == 0) revert ProxyFactory__ContestIsNotRegistered();
// can set close time to current time and end it immediately if organizer wish
if (saltToCloseTime[salt] > block.timestamp) revert ProxyFactory__ContestIsNotClosed();
address proxy = _deployProxy(msg.sender, contestId, implementation);
_distribute(proxy, data);
return proxy;
}
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;
}

Impact

This can potentially distribute the funds to the wrong addresses stipulated by the attacker.

Tools Used

Manual Analysis

Recommendations

Create logic in the contract that places an upper bound on the gasPrice. This prevents attackers from increasing the gasPrice and getting preferential transaction ordering beyond the upper-bound. Secondly, Implement a commit-reveal scheme, whenever possible. Such a scheme dictates users send transactions with hidden information (typically a hash). After the transaction has been included in a block, the user sends a transaction revealing the data that was sent (the reveal phase). This method prevents both miners and attackers from frontrunning transactions as they cannot determine the contents of the transaction.

Support

FAQs

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