Bid Beasts

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

Anyone can burn: burn(uint256) is public with no owner/approval check → unauthorized permanent NFT destruction

Root + Impact

Description

  • Normal behavior: Burning an ERC-721 token should be restricted to the token owner or an approved operator (e.g., OpenZeppelin ERC721Burnable uses _isApprovedOrOwner).

  • Issue: BidBeasts.burn(uint256) is public and calls _burn(tokenId) without checking ownership or approval. OpenZeppelin’s internal _burn does not authenticate the caller. As a result, any address can permanently destroy any existing token, including those currently escrowed by the marketplace, breaking auctions/settlements.

contract BidBeasts is ERC721, Ownable(msg.sender) {
...
function burn(uint256 _tokenId) public {
// @> VULN: No authorization. Anyone can call this for any tokenId.
_burn(_tokenId); // @> OZ _burn() does not validate msg.sender
emit BidBeastsBurn(msg.sender, _tokenId);
}
}

Risk

Likelihood:

  • Occurs whenever a valid tokenId exists and any EOA/contract calls burn(tokenId); no approvals or ownership required.

  • Also occurs while listed/escrowed in the marketplace, since the token contract does not restrict burning during escrow.

Impact:

  • Permanent asset loss: Tokens are irreversibly destroyed by unauthorized third parties.

Marketplace disruption: Auctions and unlisting/settlement flows later revert on transferFrom due to the token’s nonexistence, causing state/UX inconsistencies and potential fund-flow issues.Impact 2

Proof of Concept

// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;
import {BidBeasts} from "../src/BidBeasts_NFT_ERC721.sol";
contract BurnPoC {
function attack(address nftAddr, uint256 tokenId) external {
// Attacker (neither owner nor approved) burns the victim's token
BidBeasts(nftAddr).burn(tokenId); // succeeds → token permanently destroyed
}
}

(Extended scenario: even when the marketplace holds the NFT in escrow, calling burn(tokenId) succeeds, and later unlistNFT / _executeSale revert when attempting transferFrom.)


Recommended Mitigation

Additional hardening (optional but recommended):

  • Consider inheriting ERC721Burnable (OpenZeppelin) which already implements this gate.

  • If business logic does not require user-initiated burns, restrict to a specific role (e.g., onlyOwner/AccessControl).

  • Since the marketplace escrows tokens, evaluate forbidding external burns while listed (policy or role-based control) to prevent escrow-time griefing.

- function burn(uint256 _tokenId) public {
- _burn(_tokenId);
- emit BidBeastsBurn(msg.sender, _tokenId);
- }
+ function burn(uint256 _tokenId) public {
+ // Enforce standard ERC-721 authorization
+ require(_isApprovedOrOwner(_msgSender(), _tokenId), "Not owner nor approved");
+ _burn(_tokenId);
+ emit BidBeastsBurn(_msgSender(), _tokenId);
+ }
Updates

Lead Judging Commences

cryptoghost Lead Judge 25 days 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.