The NFT minting process is a two-step operation:
A user calls requestMintWeatherNFT to initiate the mint, paying a fee and optionally depositing LINK for automation. This function stores the original minter's address (_userMintRequest.user).
After the Chainlink oracle responds, the user (or anyone) calls fulfillMintRequest to finalize the minting and receive the NFT.
The issue is that fulfillMintRequest mints the NFT to msg.sender (the caller of fulfillMintRequest) instead of the original user who initiated the request (_userMintRequest.user). This allows a front-runner, observing the oracle's response transaction, to call fulfillMintRequest before the legitimate minter, thereby stealing the NFT for which the original minter paid the minting fee and (if applicable) deposited LINK for automation.
Likelihood: High
The fulfillMintRequest function is external and permissionless once the oracle has fulfilled the initial request.
Transactions calling fulfillMintRequest can be observed in the mempool by front-running bots, which can then submit their own transaction with a higher gas price to get their call executed first.
Impact: High
NFT Theft: The original user who paid the mint fee and (if applicable) deposited LINK for automation services loses the NFT to the front-runner.
Loss of Funds for Original Minter: The original minter pays the mint price and potentially deposits LINK, but does not receive the NFT if front-run. These funds are not refunded.
Alice calls requestMintWeatherNFT paying s_currentMintPrice and _initLinkDeposit. s_funcReqIdToUserMintReq[reqId].user is set to Alice's address.
The Chainlink Oracle calls handleOracleFulfillment which in turn calls fulfillRequest, populating s_funcReqIdToMintFunctionReqResponse[reqId].
Bob (a front-runner) sees the oracle transaction in the mempool. Bob immediately calls fulfillMintRequest(reqId) with a higher gas price than Alice's potential call.
Bob's call to fulfillMintRequest executes first. The NFT is minted to Bob (_mint(msg.sender, tokenId) where msg.sender is Bob).
Alice attempts to call fulfillMintRequest but it may fail (e.g., if s_tokenCounter logic prevents reminting or if state is cleaned up, though currently it's not cleaned). Even if her call succeeds, Bob already owns the NFT associated with her initial request parameters. The primary issue is Bob gets the NFT.
Modify fulfillMintRequest to mint the NFT to the user stored in the UserMintRequest struct, who is the original initiator of the mint request. Also, update the WeatherNFTMinted event to reflect the correct user.
There is no check to ensure that the caller of the `fulfillMintRequest` function is actually the owner of the `requestId`. This allows a malicious user to receive a NFT that is payed from someone else.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.