Beatland Festival

AI First Flight #4
Beginner FriendlyFoundrySolidityNFT
EXP
View results
Submission Details
Impact: medium
Likelihood: low
Invalid

Reentrancy Risk in `withdraw()` Function

Root + Impact

Description

  • The `withdraw()` function uses `transfer()` to send ETH to a target address. While `transfer()` only forwards 2300 gas, if the target is a contract with a malicious fallback function, it could potentially reenter the contract before state updates are complete, though the current implementation has limited state to manipulate.

    The normal behavior should follow the checks-effects-interactions pattern, ensuring all state changes occur before external calls. The current implementation performs the transfer before any state changes, but since there are minimal state changes in this function, the risk is lower.

    ```solidity

    function withdraw(address target) external onlyOwner {

    payable(target).transfer(address(this).balance); // @> External call before state updates

    }

    ```


Risk

Likelihood:

  • * Target address must be a malicious contract with a fallback function

    * `transfer()` only forwards 2300 gas, limiting attack surface

    * Current function has minimal state to manipulate

    * Requires owner to set malicious address as target

Impact:

  • * Potential reentrancy attacks if state is modified in future updates

    * Best practice violation that could lead to vulnerabilities

    * If contract is extended, reentrancy could become critical

Proof of Concept

```solidity
contract MaliciousReceiver {
FestivalPass public festivalPass;
bool public attacked;
receive() external payable {
if (!attacked && msg.value > 0) {
attacked = true;
// Attempt reentrancy - limited by 2300 gas
// Could potentially manipulate state if function is extended
}
}
}
// Owner withdraws to malicious contract
festivalPass.withdraw(address(maliciousReceiver));
// Malicious fallback executes with 2300 gas
```

Recommended Mitigation

```diff
+import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
-contract FestivalPass is ERC1155, Ownable2Step, IFestivalPass {
+contract FestivalPass is ERC1155, Ownable2Step, IFestivalPass, ReentrancyGuard {
function withdraw(address target) external onlyOwner {
+ require(target != address(0), "Invalid target address");
+ uint256 balance = address(this).balance;
+ (bool success, ) = payable(target).call{value: balance}("");
+ require(success, "Transfer failed");
}
```
Updates

Lead Judging Commences

ai-first-flight-judge Lead Judge 16 days ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

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

Give us feedback!