Bid Beasts

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

Burn Function Missing Access Control — Arbitrary NFT Destruction

Root + Impact

Description

  • Normal behavior: An ERC-721 implementation should only allow a token to be burned by its owner or an approved operator; external callers must not be able to destroy tokens they do not control.

  • Issue: The contract exposes a public burn(uint256) that directly calls _burn(tokenId) without checking ownership or approval. As a result, any address can call burn for any tokenId and irrevocably destroy that token.

@> // PUBLIC burn WITHOUT access checks: any caller can burn arbitrary tokenId
function burn(uint256 _tokenId) public {
_burn(_tokenId);
emit BidBeastsBurn(msg.sender, _tokenId);
}

Risk

Likelihood:

  • High — Calling the vulnerable burn requires only a single transaction from any externally owned account; no preconditions, approvals, or privileged access are necessary.

  • High — Exploitation cost is minimal (only gas), so attackers or bots can trivially enumerate tokens and burn them.

Impact:

  • Permanent asset loss — NFTs can be irreversibly destroyed, causing direct financial loss to owners.

  • Critical reputational damage — loss of collector trust and marketplace credibility; potential cascading economic effects on the collection.

Proof of Concept

A minimal PoC (Solidity-style / test pseudocode) demonstrating exploitation:

function test_AnyoneCanBurnOthersNFT() public {
// --- Arrange: mint token to seller
vm.prank(OWNER);
uint256 tokenId = nft.mint(SELLER);
// Sanity: token exists and owner is SELLER
assertEq(nft.ownerOf(tokenId), SELLER, "precondition: seller owns token");
// --- Act: unauthorised user burns the token
vm.prank(ATTACKER);
nft.burn(tokenId); // on vulnerable contract this will succeed
// --- Assert: token no longer exists (ownerOf reverts with OZ message)
vm.expectRevert();
nft.ownerOf(tokenId);
}

Recommended Mitigation

Inherit OpenZeppelin’s ERC721Burnable to enforce access control (owner or approved operator).
If custom events are required, wrap the parent burn with super.burn while preserving the original logic:

+ import {ERC721Burnable} from "@openzeppelin/contracts/token/ERC721/extensions/ERC721Burnable.sol";
- contract BidBeasts is ERC721, Ownable(msg.sender) {
+ contract BidBeasts is ERC721, ERC721Burnable, Ownable(msg.sender) {
...
- function burn(uint256 _tokenId) public {
- _burn(_tokenId);
- emit BidBeastsBurn(msg.sender, _tokenId);
- }
+ function burn(uint256 tokenId) public override {
+ address owner = ownerOf(tokenId);
+ super.burn(tokenId);
+ emit BidBeastsBurn(owner, tokenId);
+ }
}
Updates

Lead Judging Commences

cryptoghost Lead Judge about 1 month 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.