Eggstravaganza

First Flight #37
Beginner FriendlySolidity
100 EXP
View results
Submission Details
Severity: high
Valid

Unauthorized NFT Withdrawal

Summary

Any user can assign themselves as the depositor of an NFT they do not own, allowing them to later withdraw it and effectively steal the asset.

Vulnerability Details

The depositEgg function lets any caller provide an arbitrary depositor address, without verifying that the caller owns the NFT or has deposited it properly

function depositEgg(uint256 tokenId, address depositor) public {
require(eggNFT.ownerOf(tokenId) == address(this), "NFT not transferred to vault");
require(!storedEggs[tokenId], "Egg already deposited");
storedEggs[tokenId] = true;
eggDepositors[tokenId] = depositor;
emit EggDeposited(depositor, tokenId);
}
  • The attacker can front-run a legitimate transfer and call depositEgg(tokenId, attackerAddress) to claim ownership of the NFT.

Impact

An attacker could claim and withdraw any NFT that gets transferred to the contract, even if they never owned it.

Tools Used

Manual review

Recommendations

Require the caller to own and transfer the NFT within the function

function depositEgg(uint256 tokenId) public {
require(eggNFT.ownerOf(tokenId) == msg.sender, "Caller must be the owner");
require(eggNFT.getApproved(tokenId) == address(this) || eggNFT.isApprovedForAll(msg.sender, address(this)), "Contract not approved");
require(!storedEggs[tokenId], "Egg already deposited");
eggNFT.transferFrom(msg.sender, address(this), tokenId);
storedEggs[tokenId] = true;
eggDepositors[tokenId] = msg.sender;
emit EggDeposited(msg.sender, tokenId);
}
Updates

Lead Judging Commences

m3dython Lead Judge 4 months ago
Submission Judgement Published
Validated
Assigned finding tags:

Frontrunning Vulnerability DepositEgg

Front-running depositEgg allows deposit ownership hijacking.

Support

FAQs

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