Free NFT Development Smart Contract Security Questions and Answers 1 — Questions and Answers
Question 1: An NFT contract has a public `mint()` function that anyone can call. Which of the following is the MOST critical security vulnerability this presents?
- Reentrancy attack during minting.
- Denial-of-service by exceeding the block gas limit.
- Unauthorized creation of NFTs, potentially exceeding the intended `MAX_SUPPLY`. (Correct answer)
- Inaccurate royalty payments due to manipulated token IDs.
Correct answer: Unauthorized creation of NFTs, potentially exceeding the intended `MAX_SUPPLY`.
An unprotected `mint()` function is a severe access control vulnerability. It allows any user or contract to create an unlimited number of NFTs, potentially devaluing the collection and violating the project's intended scarcity. Proper access control, such as using an `onlyOwner` modifier or a role-based system, is essential to restrict minting privileges.
Question 2: A developer is creating an NFT with rarity traits determined at mint time. They use `keccak256(abi.encodePacked(block.timestamp, msg.sender))` as the source of randomness. What is the primary security risk associated with this approach?
- It is computationally expensive, leading to high gas costs for minters.
- The `msg.sender` can be easily spoofed by malicious contracts.
- The result is predictable, allowing miners or attackers to influence or front-run the minting of rare NFTs. (Correct answer)
- It may cause transaction reverts if `block.timestamp` is the same for multiple transactions.
Correct answer: The result is predictable, allowing miners or attackers to influence or front-run the minting of rare NFTs.
On-chain variables like `block.timestamp`, `block.number`, and `blockhash` are not truly random and can be predicted or influenced by miners. An attacker could repeatedly call the mint function, reverting the transaction if the outcome isn't favorable, or a miner could reorder transactions to secure a rare NFT for themselves. Secure randomness requires off-chain solutions like a VRF (Verifiable Random Function) oracle.
Question 3: An NFT marketplace contract allows users to withdraw their earnings. The function first sends the user their ETH and then updates their internal balance to zero. Which vulnerability is this pattern most susceptible to?
- Integer Underflow
- Reentrancy (Correct answer)
- Signature Malleability
- Unchecked External Call
Correct answer: Reentrancy
This sequence of operations (external call before state change) is a classic example of a reentrancy vulnerability. A malicious contract, upon receiving the ETH in its fallback function, could call the withdraw function again before the original call has updated the balance. This would allow the attacker to drain funds repeatedly. The correct pattern is Checks-Effects-Interactions: first check conditions, then update the state (e.g., set balance to zero), and finally interact with the external contract (send ETH).
Question 4: A developer working on an NFT contract using Solidity `^0.7.0` implements a `batchMint(uint256 quantity)` function. The function calculates the total price as `quantity * MINT_PRICE`. If `quantity` is a very large number, which vulnerability could be exploited?
- Denial-of-Service (DoS)
- Reentrancy
- Access Control Violation
- Integer Overflow (Correct answer)
Correct answer: Integer Overflow
In Solidity versions prior to 0.8.0, arithmetic operations did not automatically revert on overflow. If a user provides a `quantity` large enough, the multiplication `quantity * MINT_PRICE` could wrap around to a very small number or zero, allowing the user to mint many NFTs for free or a fraction of the cost. Solidity 0.8.0+ introduced built-in overflow and underflow protection, which reverts the transaction in such cases.
Question 5: To prevent NFTs from being permanently locked, the `safeTransferFrom` function in ERC-721 performs a check on the recipient contract. What is the name of the function it calls on the recipient to ensure it can handle the token?
- `canReceiveNFT(tokenId)`
- `onERC721Received(operator, from, tokenId, data)` (Correct answer)
- `_checkOnTransfer(from, to, tokenId)`
- `supportsInterface(interfaceId)`
Correct answer: `onERC721Received(operator, from, tokenId, data)`
The ERC-721 standard specifies that when `safeTransferFrom` is called with a recipient that is a contract, it MUST call `onERC721Received` on that contract. The recipient contract is expected to return a specific magic value (`bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`) to signal that it can accept the transfer. If it doesn't, or if the call reverts, the transfer is reverted, preventing the NFT from being stuck.
Question 6: An NFT project implements a presale mint function that validates a user's eligibility by checking a digital signature provided by the project owner. To prevent an attacker from reusing a valid signature, which of the following is the most crucial element to include in the signed message?
- The contract's address.
- A nonce or a usage flag. (Correct answer)
- The `block.timestamp`.
- The minter's gas price.
Correct answer: A nonce or a usage flag.
Without a nonce (a number used once) or a mapping to track which signatures have been used, an attacker could intercept a valid signature and 'replay' it to mint an NFT for themselves or multiple NFTs if the logic allows. The contract must invalidate the signature after its first use. Including the contract address (or chain ID) is also vital to prevent cross-contract or cross-chain replay, but the nonce is what prevents reuse within the same contract.
An NFT contract has a public `mint()` function that anyone can call.
Which of the following is the MOST critical security vulnerability this presents?