Bid Beasts

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

Unrestricted `burn` lets anyone destroy any NFT (breaks auctions & assets)

Root + Impact

Description

  • Normal behavior: Only the token owner or an approved operator should be able to burn an ERC-721 token.

  • Issue: The public burn(uint256 tokenId) calls _burn(tokenId) without any authorization check. OpenZeppelin’s internal _burn assumes the caller already enforced permissions, so as written any external address can burn any token—including tokens held in escrow by the marketplace during a live listing.

function burn(uint256 _tokenId) public {
@> _burn(_tokenId); // no owner/approval check before burning
emit BidBeastsBurn(msg.sender, _tokenId);
}

Risk

Likelihood:

  • Happens whenever someone calls burn(tokenId) on an existing token.

  • Occurs in normal operation because no gatekeeping is present on the public burn.

Impact:

  • While listed (escrowed in marketplace): Attacker can burn the listed token, causing settlement functions to revert and potentially stranding bidder funds (auction DoS/griefing).

  • While not listed: Attacker can destroy users’ NFTs at will (permanent asset loss).

Proof of Concept

// Remix walkthrough with two accounts: Seller (S) and Attacker (A).
// Case A: Not listed yet
// 1) S mints tokenId 0 to S.
// 2) Switch to A (not owner, no approval).
// 3) A calls NFT.burn(0).
// Explanation: Since burn() lacks an ownership/approval check,
// OZ's _burn() executes and destroys tokenId 0.
// Result: token 0 is burned by an unauthorized caller.
// Case B: Listed in marketplace (worse)
// 1) S mints tokenId 1 to S.
// 2) S approves marketplace and calls listNFT(1, ...).
// => Marketplace now owns tokenId 1 (escrow).
// 3) Switch to A. A calls NFT.burn(1).
// Explanation: burn() still lacks an auth check;
// _burn() just destroys the token owned by the marketplace.
// Result: tokenId 1 no longer exists;
// settleAuction/takeHighestBid will revert (listing bricked; funds can be stranded).

Explanation:
In both cases, _burn checks token existence but does not verify that msg.sender is owner or approved. Because the public burn never enforces that check, anyone can call it and succeed.

Recommended Mitigation

- function burn(uint256 _tokenId) public {
- _burn(_tokenId);
- emit BidBeastsBurn(msg.sender, _tokenId);
- }
+ function burn(uint256 tokenId) public {
+ // Allow only token owner or approved operator to burn
+ require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: caller is not owner nor approved");
+ _burn(tokenId);
+ emit BidBeastsBurn(_msgSender(), tokenId);
+ }

Mitigation explanation:

Adding this require makes burn match standard ERC-721 authorization semantics, preventing arbitrary destruction.

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.