Eggstravaganza

First Flight #37
Beginner FriendlySolidity
100 EXP
View results
Submission Details
Severity: medium
Invalid

Reentrancy Vulnerability in withdrawEgg Function of NFT Vault Contract

Summary

The withdrawEgg function in the vault smart contract is vulnerable to a medium severity reentrancy attack. Although state variables are updated before the external call, the function still performs an unprotected call to an external NFT contract (eggNFT.transferFrom), which could lead to unexpected behavior if that contract is malicious or improperly implemented.

Vulnerability Details
Function: withdrawEgg(uint256 tokenId)

  • Vulnerability: Reentrancy

  • External Call: eggNFT.transferFrom(address(this), msg.sender, tokenId)

The function calls an external contract (eggNFT) to transfer the NFT, but it does not use any reentrancy protection such as a nonReentrant modifier.

While the internal state is modified before the call this alone does not guarantee safety in complex contract systems, especially when eggNFT could be a user-controlled contract (e.g., a proxy or malicious wrapper).

If eggNFT.transferFrom is overridden in a malicious contract to call withdrawEgg again before the first call completes, it could potentially bypass internal logic or interfere with vault behavior in future extensions of the contract

Impact
Severity: Medium

  • Assets at Risk: NFTs held in the vault

  • Attack Scenario:
    An attacker creates a malicious eggNFT contract that calls back into the vault's withdrawEgg during the transferFrom execution. If the vault function is expanded or its logic changes in future versions, this reentrancy may be exploited to:

    • Withdraw multiple eggs

    • Bypass state checks

    • Interfere with bookkeeping

    • Cause denial of service or logical inconsistencies

Even if not currently exploitable, the lack of protection weakens the overall security posture of the contract.

Tools Used

  • Solidity knowledge

  • Common DeFi attack patterns

  • OpenZeppelin documentation

  • Manual Code Review

Recommendations
Adding the nonReentrant modifier to the withdrawEgg() function using OpenZeppelin's ReentrancyGuard. This helps protect the contract from reentrancy attacks, where a malicious contract could try to call the function again before it finishes

import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
contract EggVault is Ownable, ReentrancyGuard {
function withdrawEgg(uint256 tokenId) public nonReentrant {
require(storedEggs[tokenId], "Egg not in vault");
require(eggDepositors[tokenId] == msg.sender, "Not the original depositor");
storedEggs[tokenId] = false;
delete eggDepositors[tokenId];
eggNFT.transferFrom(address(this), msg.sender, tokenId);
emit EggWithdrawn(msg.sender, tokenId);
}
}
Updates

Lead Judging Commences

m3dython Lead Judge 4 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

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