BriVault

First Flight #52
Beginner FriendlySolidity
100 EXP
View results
Submission Details
Impact: high
Likelihood: high
Invalid

Centralization Risk: Owner Can Arbitrarily Select Winner Without Verification

Root + Impact

The owner has complete, unchecked authority to declare any country as the winner through setWinner(), regardless of real-world event outcomes. There is no oracle integration, multi-signature requirement, or verification mechanism. This creates a critical trust assumption where the owner could collude with participants or act maliciously to steal funds.

Impact

Owner can steal all funds by:

  1. Creating multiple addresses and depositing/joining with a specific country

  2. Setting that country as winner regardless of actual results

  3. Withdrawing all funds through controlled addresses

This completely undermines the trustless nature expected in DeFi protocols.

Scenario

// Step 1: Owner creates sybil addresses
address ;
for(uint i = 0; i < 10; i++) {
sybils[i] = address(uint160(0xBEEF0000 + i));
}
// Step 2: Owner deposits through sybil addresses for country 47
for(uint i = 0; i < 10; i++) {
vault.deposit(largeAmount, sybils[i]);
vault.joinEvent(47); // Obscure country unlikely to win
}
// Step 3: Legitimate users deposit for likely winners
// ... users deposit billions for countries 0-10 ...
// Step 4: After event, country 5 actually wins
// Step 5: Owner calls setWinner(47) instead
vault.setWinner(47); // Sets their sybil country as winner
// Step 6: Owner withdraws everything through sybils
for(uint i = 0; i < 10; i++) {
vault.withdraw(); // Drains vault
}

Affected Code

function setWinner(uint256 countryIndex) public onlyOwner returns (string memory) {
if (block.timestamp <= eventEndDate) {
revert eventNotEnded();
}
require(countryIndex < teams.length, "Invalid country index");
if (_setWinner) {
revert WinnerAlreadySet();
}
winnerCountryId = countryIndex;
winner = teams[countryIndex]; // Owner chooses arbitrarily
_setWinner = true;
_getWinnerShares();
_setFinallizedVaultBalance();
emit WinnerSet(winner);
return winner;
}

Proposed Fix

Implement a decentralized winner determination mechanism:

// Option 1: Multi-sig or DAO governance
function setWinner(uint256 countryIndex) public {
require(msg.sender == governanceContract, "Only governance");
// ... rest of logic
}
// Option 2: Oracle integration
function setWinner() public {
require(block.timestamp > eventEndDate + DISPUTE_PERIOD);
uint256 winnerIndex = oracle.getEventWinner(eventId);
// ... rest of logic
}
// Option 3: Commit-reveal with multiple validators
mapping(address => bytes32) public validatorCommits;
mapping(address => uint256) public validatorReveals;
function commitWinner(bytes32 commitment) public onlyValidator {
validatorCommits[msg.sender] = commitment;
}
function revealWinner(uint256 countryIndex, uint256 nonce) public onlyValidator {
require(keccak256(abi.encode(countryIndex, nonce)) == validatorCommits[msg.sender]);
validatorReveals[msg.sender] = countryIndex;
// Determine winner based on majority
}
Updates

Appeal created

bube Lead Judge 19 days ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity
Assigned finding tags:

The winner is set by the owner

This is owner action and the owner is assumed to be trusted and to provide correct input arguments.

Support

FAQs

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

Give us feedback!