Christmas Dinner

First Flight #31
Beginner FriendlyFoundrySolidity
100 EXP
View results
Submission Details
Severity: low
Valid

Vulnerability in `ChristmasDinner:changeParticipationStatus:` Allows Unauthorized Participation

Summary

  • While the contract is designed to allow only paid individuals to become participants, the ChristmasDinner:changeParticipationStatus function is flawed. It enables anyone who calls the function to become a participant, bypassing the payment requirement.

Impact

  • The vulnerability in changeParticipationStatus undermines the contract's core purpose by allowing unpaid users to become participants, leading to inaccurate budgeting and potential financial losses for the host. It disrupts event planning, diminishes trust in the system, and opens the contract to potential abuse, such as spamming the participant list. This could result in an unusable or unreliable platform for organizing events.

Proof Of Concept

The below code is the POC

function test_POC_changeParticipationStatus()public{
address EXPLOITER=makeAddr("EXPLOITER");
vm.startPrank(EXPLOITER);
bool check_before_call=cd.getParticipationStatus(EXPLOITER);
cd.changeParticipationStatus();
bool check_after_call=cd.getParticipationStatus(EXPLOITER);
console.log("Before call participation status",check_before_call);
console.log("After call participation status",check_after_call);
}
  • Add the above code in ChristmasDinnerTest.t.sol:ChristmasDinnerTest

  • shell forge test --match-test test_POC_receive -vv

  • You will get output as following

    • Before call participation status : false

    • After call participation status : true

Tools Used

Foundry

Recommendations

  • You can mitigate this by checking whether the msg.sender is having a enough threshold to become the participant.

+ function getParticipantBalances(address _user)public view returns(uint256 totalBalances){
+ uint256 player_WETH_balance=balances[_user][address(i_WETH)];
+ uint256 player_USDC_balance=balances[_user][address(i_USDC)];
+ uint256 player_WBTC_balance=balances[_user][address(i_WBTC)];
+ uint256 player_ETH_balance=etherBalance[_user];
+ totalBalances=player_WETH_balance+player_USDC_balance+player_WBTC_balance+player_ETH_balance;
+ }
function changeParticipationStatus() external {
+ uint256 participantBalances=getParticipantBalances(msg.sender);
+ if(participantBalances>0){
+ if(participant[msg.sender]) {
+ participant[msg.sender] = false;
+ // @audit some one can directly become the participant by calling this function
+ } else if(!participant[msg.sender] && block.timestamp <= deadline) {
+ participant[msg.sender] = true;
+ } else {
+ revert BeyondDeadline();
+ }
+ emit ChangedParticipation(msg.sender, participant[msg.sender]);
+ }
+ else{
+ revert("You can't change participant status without having funds");
+ }
+ }

Add the ChristmasDinner:getParticipantBalances function at the external getters section and make the above necessary chnages in changeParticipationStatus:changeParticipationStatus function.

The changeParticipationStatus function has been updated to enforce payment validation, ensuring only users who have contributed the required funds can become participants. This fix resolves the vulnerability that previously allowed unauthorized users to gain participant status.

The following is a proof of concept (PoC) demonstrating that the proposed changes will function as intended.

function test_FIX_changeParticipationStatus()public{
address EXPLOITER=makeAddr("EXPLOITER");
startHoax(EXPLOITER,1.5 ether);
uint256 balance_before_depsoit=EXPLOITER.balance;
(bool check1,)=address(cd).call{value: 1 ether}("");
require(check1,"Native ETH depsoit failed");
uint256 balance_after_depsoit=EXPLOITER.balance;
console.log("Balance Before deposit :",balance_before_depsoit);
console.log("Balance After deposit :", balance_after_depsoit);
bool participation_status_before_change_pariticipation=cd.getParticipationStatus(EXPLOITER);
cd.changeParticipationStatus();
bool participation_status_after_change_pariticipation=cd.getParticipationStatus(EXPLOITER);
console.log("Participation status before call :",participation_status_before_change_pariticipation);
console.log("Participation status after call :",participation_status_after_change_pariticipation);
}
Updates

Lead Judging Commences

0xtimefliez Lead Judge 10 months ago
Submission Judgement Published
Validated
Assigned finding tags:

usage of change participation logic circumvents deposit

Support

FAQs

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