ERC721 Smart Contract Security

ERC721 is the standard for non-fungible tokens (NFTs). Its security model differs significantly from ERC20 — each token is unique, ownership tracking is more complex, and the safeTransferFrom mechanism introduces reentrancy vectors that surprise many developers.

Vulnerability 1: Reentrancy via safeTransferFrom

When safeTransferFrom sends an NFT to a contract address, it calls onERC721Received on the recipient. This is an external call that can re-enter your contract before state updates complete — a classic reentrancy scenario.

// VULNERABLE — state update happens after the external call
function sell(uint256 tokenId) public {
    nft.safeTransferFrom(address(this), msg.sender, tokenId);
    balances[msg.sender] -= price; // too late — re-entered here
}

Always update state before transferring NFTs. Use OpenZeppelin's ReentrancyGuard on any function that calls safeTransferFrom. See reentrancy.

Vulnerability 2: Royalty bypass

ERC2981 on-chain royalties are enforced by NFT marketplaces voluntarily — they are not enforced by the ERC721 contract itself. A custom marketplace or a direct transfer between wallets will not pay royalties. Protocols that assume royalties are always collected will have incorrect accounting.

Vulnerability 3: Unprotected mint functions

A common bug in NFT contracts is leaving the mint function callable by anyone, or with an overly broad access control. Always restrict minting to authorized addresses and implement maximum supply caps to prevent infinite minting. See access control.

Vulnerability 4: tokenId overflow and enumeration

Using uint256 for tokenIds is standard, but iteration over all tokens owned by an address is expensive on-chain. Use the ERC721Enumerable extension carefully — the storage overhead grows linearly with NFT count and can make ownership tracking prohibitively expensive in loops.

Vulnerability 5: Centralized metadata (rug risk)

Most NFT metadata is hosted off-chain (IPFS or centralized servers). Contracts with a mutable setBaseURI function allow the deployer to change the metadata — or delete it — after sale. Buyers may end up with NFTs pointing to empty or changed images. Prefer IPFS with immutable CIDs and remove URI mutability after reveal.

Secure NFT contract checklist

  • Use OpenZeppelin's ERC721 or ERC721A as the base contract
  • Add ReentrancyGuard to any function that calls safeTransferFrom
  • Restrict mint with onlyOwner or a signature-based allow list
  • Set a MAX_SUPPLY constant enforced in the mint function
  • Use a commit-reveal scheme for fair mint randomness instead of block.timestamp
  • Lock baseURI after reveal

Audit your NFT contract

SmartContract.us audits ERC721 contracts for reentrancy, access control, and metadata security issues. Analyze an NFT contract →