Trick or Treat

First Flight #27
Beginner FriendlyFoundry
100 EXP
View results
Submission Details
Severity: medium
Invalid

Violation of the Checks-Effects-Interactions pattern

Summary

The SpookySwap contract is an ERC721 NFT contract that allows users to mint NFTs representing "treats" through couple of functions, including mintTreat. This function is called internally when users purchase treats via the trickOrTreat function or other mechanisms. It handles the minting of the NFT to the recipient and updates the contract's state accordingly.

Vulnerability Details

The mintTreat function violates the Checks-Effects-Interactions (CEI) pattern by making an external call to _mint before updating critical state variables. Specifically, it calls _mint(recipient, tokenId), which can trigger external code execution if the recipient is a contract, before incrementing nextTokenId. This violation can potentially be exploited through reentrancy attacks, allowing a malicious recipient to manipulate the contract's state, mint multiple NFTs, or cause other unintended behaviors.

The mintTreat function is defined as follows:

function mintTreat(address recipient, Treat memory treat) internal {
uint256 tokenId = nextTokenId;
_mint(recipient, tokenId);
_setTokenURI(tokenId, treat.metadataURI);
nextTokenId += 1;
emit Swapped(recipient, treat.name, tokenId);

}

Impact

The violation of the CEI pattern in the mintTreat function can lead to significant security risks:

  • Unauthorized Minting: An attacker can mint multiple NFTs without authorization, leading to inflation of the NFT supply and potential devaluation.

  • Financial Losses: Unauthorized minting can result in direct financial losses to the contract owner or users.

  • Contract Disruption: Reentrancy can disrupt the normal operation of the contract, potentially causing corrupting the contract's state.

Tools Used

Manual review

Recommendations

To mitigate this vulnerability, the contract should adhere to the Checks-Effects-Interactions pattern by updating the state before making any external calls:

function mintTreat(address recipient, Treat memory treat) internal {
nextTokenId += 1;
uint256 tokenId = nextTokenId;
// Update state before external interaction
_mint(recipient, tokenId);
_setTokenURI(tokenId, treat.metadataURI);
emit Swapped(recipient, treat.name, tokenId);
}
Updates

Appeal created

bube Lead Judge 9 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

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