Normal Behavior: A user pays to request an NFT mint. Upon oracle fulfillment, the user calls a function to receive their NFT.
Specific Issue: The fulfillMintRequest function mints the NFT to msg.sender (the caller of fulfillMintRequest) instead of the original user who paid for the mint. An attacker can monitor for oracle responses and call fulfillMintRequest before the legitimate user, stealing the NFT.
Likelihood: High
The necessary requestId is publicly emitted.
Attackers can easily monitor and front-run the legitimate user's transaction.
Impact: Critical
The original paying user loses their funds and does not receive the NFT.
Attackers acquire NFTs for free (gas cost only).
Victim calls requestMintWeatherNFT(), pays, and requestId is emitted.
Oracle calls fulfillRequest(requestId, ...) with data.
Attacker, seeing the requestId and oracle response, calls fulfillMintRequest(requestId) before the victim.
Attacker receives the NFT. Victim receives nothing.
To run this PoC:
Save the code above as test/WeatherNft_PoC_Theft.test.js (or similar) in your Hardhat project.
Make sure your WeatherNft.sol and WeatherNftStore.sol are in the contracts directory.
Run from your terminal: npx hardhat test ./test/WeatherNft_PoC_Theft.test.js
You should see the test pass, demonstrating that the attacker successfully acquired tokenId 1, even though the victim paid for it. The console logs will also highlight who received the NFT.
The fulfillMintRequest function has been updated to ensure the NFT is minted to the original user who initiated and paid for the mint request (_userMintRequest.user), rather than the caller of fulfillMintRequest (msg.sender). This change correctly assigns NFT ownership and prevents an attacker from front-running the legitimate minter to steal the NFT. The corresponding event emission for WeatherNFTMinted has also been updated to reflect the correct recipient.
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.