Rock Paper Scissors

First Flight #38
Beginner FriendlySolidity
100 EXP
View results
Submission Details
Severity: medium
Valid

No Mechanism to Extract ETH Sent Directly to Contract

Summary

The RockPaperScissors smart contract includes a receive() function that allows it to accept ETH directly, but it lacks any mechanism to extract these funds if they are accidentally sent to the contract outside of the intended game mechanisms. This creates a risk of permanently trapped ETH that cannot be recovered by either players or the contract administrator.

Vulnerability Details

The issue is present in the receive() function (lines 582-585):

/**
* @dev Fallback function to accept ETH
*/
receive() external payable {
// Allow contract to receive ETH
}

This function allows the contract to accept ETH transfers, but there is no corresponding functionality in the contract to withdraw or utilize these funds if they are sent outside of the normal game creation or joining process. While the contract includes a withdrawFees function for the admin to withdraw accumulated protocol fees, it specifically only allows withdrawal from the accumulatedFees balance, not from the contract's entire ETH balance.
The absence of a rescue mechanism means any ETH sent directly to the contract address (whether accidentally or intentionally) will be permanently locked within the contract with no way to recover it.

Impact

  • Permanent Fund Loss: Any ETH directly sent to the contract by mistake becomes permanently trapped.

  • No Recovery Mechanism: Neither players nor the admin can recover these trapped funds.

  • Accumulated Loss Over Time: Small amounts of accidentally sent ETH could accumulate over time into a significant amount.

Tools Used

  • Manual code review

Recommendations

  • Implement an admin function to withdraw any excess ETH that is not part of active games or accumulated fees:

Updates

Appeal created

m3dython Lead Judge about 1 month ago
Submission Judgement Published
Validated
Assigned finding tags:

Orphaned ETH due to Unrestricted receive() or Canceled Game

ETH sent directly to the contract via the receive function or after a canceled game becomes permanently locked

Support

FAQs

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