Sparkn

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

Organizer Can steal Funds / Receive funds mistakenly.

Summary

Fraud Organizer Can Pass his own address or some other address to steal funds.

Vulnerability Details

NOTE:
Some checks can be done off-chain for that but still wants to share my thoughts on Downside

The Organizer in the Protocol is responsible for sending funds to winners (also can be done by owner if not done by him). But he can manipulate the protocol in Two ways:

  1. pass his own address and can call the deployProxyAndDistribute function to transfer the funds to the winners. And in that way he would be able to steal the funds.

  2. An Organizer can pass some different fraud address to take the funds.

Here is a Test That Verifies that: [Test]

Only Doing Verification using KYC or some other way on frontend is not a solution for this as if he is able to withdraw all the tokens then retrieving the tokens would take a lot of time because of many issues(ex. legal process). And this may incur some extra cost as well.

Yes we need to make a lot of changes(some are mentioned in the Recommendations section) when organizer use some other address for stealing funds. This needs to be implemented properly. For this we can go with KYC like way. But for first case, we can add a condition like (winner address != organizer address). This can give us little bit guarantee that organizer cannot commit fraud or what could happen is he might send his own address mistakenly among the addresses of the winners. This check can help to prevent that.

Impact

Funds can be drained from the contract.

Tools Used

Manual Review

Recommendations

For the first case, It would be better if we can add a check during the transfer of funds in _distribute function to check if the winner is equal to Organizer or not(Yes we have to add the address of the organizer in the contract as well).

function _distribute(address token, address[] memory winners, uint256[] memory percentages, bytes memory data) internal {
//inside for loop that transfers token
require(winner != organizer, "Organizer cannot be a winner");
// Rest of the distribution logic
}

And In second case, The way could be little gas expensive if we want to protect the tokens from some different fraud address. Below are some ways to do that:

  1. store an array of the winners in the ProxyFactory contract or Proxy contract and check against the list of winner's with the winners in the contract. And exmaple code:

contract ProxyFactory {
struct Contest {
bytes32 contestId;
address[] winners;
}
mapping(bytes32 => Contest) public contests;
modifier onlyContestOrganizer(bytes32 contestId) {
require(msg.sender == contests[contestId].organizer, "Only contest organizer can call this");
_;
}
function createContest(bytes32 contestId) external {
contests[contestId] = Contest(contestId, new address[](0));
}
function addWinner(bytes32 contestId, address winner) external onlyContestOrganizer(contestId) {
contests[contestId].winners.push(winner);
}
function isWinner(bytes32 contestId, address addr) public view returns (bool) {
Contest memory contest = contests[contestId];
for (uint256 i = 0; i < contest.winners.length; i++) {
if (contest.winners[i] == addr) {
return true;
}
}
return false;
}
// Rest of the contract code
}
  1. Or we can use Merkle Trees(Can be created easily with Openzeppelin contracts) to store the same info in more gas efficient manner. An example code:

import "@openzeppelin/contracts/cryptography/MerkleProof.sol";
contract ProxyFactory {
bytes32 public merkleRoot;
function setMerkleRoot(bytes32 root) external onlyOrganizer {
merkleRoot = root;
}
function verifyWinner(address winner, bytes32[] memory proof) public view returns (bool) {
bytes32 leaf = keccak256(abi.encodePacked(winner));
return MerkleProof.verify(proof, merkleRoot, leaf);
}
// Rest of the contract code
}

NOTE:
Make appropriate checks for who can use these functions

Support

FAQs

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

Give us feedback!