Eggstravaganza

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

Lack of Ownership Verification in depositEgg() Enables Deposit Spoofing

Summary

The EggVault.sol contract allows forged egg deposit claims due to a lack of ownership verification before recording deposits. A malicious actor can deposit an egg they don’t own, as long as the NFT has been transferred into the vault (even via a third party), and falsely claim credit for it.

Vulnerability Details

  • Function: depositEgg(uint256 tokenId, address depositor)

  • Problem: The function does not validate that depositor was the rightful owner of the egg before it was transferred into the vault.

  • Result: Anyone can spoof the deposit history by calling depositEgg() with a tokenId already in the vault — even if someone else sent it there.

PoC

Add this to EggHuntGameTest.t.sol

function testForgedEggDeposit() public {
vm.warp(1000);
game.startGame(600);
game.setEggFindThreshold(100);
vm.warp(1100);
vm.prank(alice);
game.searchForEgg(); // Alice mints egg with tokenId = 1
uint256 tokenId = 1;
vm.prank(alice);
nft.approve(address(vault), tokenId);
vm.prank(alice);
nft.transferFrom(alice, address(vault), tokenId);
vm.prank(bob);
vault.depositEgg(tokenId, bob); // Bob falsely claims deposit
vm.prank(bob);
vault.withdrawEgg(tokenId); // Bob withdraws Alice’s egg
assertEq(nft.ownerOf(tokenId), bob, "Bob should fraudulently own the egg");
}

Impact

  • Loss of Ownership Integrity: Depositors are no longer guaranteed to be the rightful owner.

  • Theft Vector: Attackers can trick the vault into recording false depositors and steal NFTs.

  • Critical in Competitive Scenarios: If egg count or vault participation impacts rewards or rankings, this could be abused for unfair advantage.

Tools Used

Foundry

Recommendations

Update depositEgg() to validate that depositor was the previous owner of the NFT before it was transferred to the vault.

function depositEgg(uint256 tokenId, address depositor) public {
require(eggNFT.ownerOf(tokenId) == address(this), "NFT not transferred to vault");
require(!storedEggs[tokenId], "Egg already deposited");
require(
eggNFT.getApproved(tokenId) == address(this) ||
eggNFT.isApprovedForAll(depositor, address(this)),
"Depositor not authorized"
);
// Optional: Add proof-of-ownership mechanism via events or signature
storedEggs[tokenId] = true;
eggDepositors[tokenId] = depositor;
emit EggDeposited(depositor, tokenId);
}
Updates

Lead Judging Commences

m3dython Lead Judge 3 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.