Weather Witness

First Flight #40
Beginner FriendlyFoundrySolidityNFT
100 EXP
View results
Submission Details
Impact: medium
Likelihood: medium
Invalid

[M-2] Lack of Validation in `WeatherNft::performUpkeep`

Root + Impact

Lack of Input Validation in WeatherNft::performUpkeep.

Impact: Low to Medium severity—incorrect state updates could disrupt automation logic.

Description

The WeatherNft.sol::performUpkeep function is called by Chainlink Keepers to update an NFT’s weather data. It decodes performData to get a _tokenId but doesn’t validate if the NFT exists or if the upkeepId is valid, leading to incorrect state updates (e.g., lastFulfilledAt) for non-existent NFTs, which could interfere with valid automation.

function performUpkeep(bytes calldata performData) external override {
uint256 _tokenId = abi.decode(performData, (uint256));
uint256 upkeepId = s_weatherNftInfo[_tokenId].upkeepId;
//@> Start of root cause
s_weatherNftInfo[_tokenId].lastFulfilledAt = block.timestamp;
//@> End of root cause
string memory pincode = s_weatherNftInfo[_tokenId].pincode;
string memory isoCode = s_weatherNftInfo[_tokenId].isoCode;
bytes32 _reqId = _sendFunctionsWeatherFetchRequest(pincode, isoCode);
s_funcReqIdToTokenIdUpdate[_reqId] = _tokenId;
emit NftWeatherUpdateRequestSend(_tokenId, _reqId, upkeepId);
}

Risk

Likelihood:

  • Chainlink Keepers call performUpkeep with an invalid _tokenId (e.g., for an un-minted NFT).

  • An attacker spams performUpkeep with invalid data to manipulate state.

Impact:

  • Incorrect lastFulfilledAt updates for non-existent NFTs waste gas and could delay updates for valid NFTs.

  • Off-chain systems may misinterpret state, affecting user experience.

Proof of Concept

// Scenario: Call performUpkeep with invalid tokenId
function testInvalidTokenId() external {
bytes memory performData = abi.encode(uint256(9999)); // Non-existent tokenId
WeatherNft(weatherNftAddress).performUpkeep(performData);
// Result: s_weatherNftInfo[9999].lastFulfilledAt is updated, wasting gas
}
  1. Scenario: Call performUpkeep with invalid tokenId

  2. Result: s_weatherNftInfo[9999].lastFulfilledAt is updated, wasting gas

Recommended Mitigation

Add validation to the performUpKeep function to ensure the NFT exists:

function performUpkeep(bytes calldata performData) external override {
uint256 _tokenId = abi.decode(performData, (uint256));
+ require(_ownerOf(_tokenId) != address(0), "NFT does not exist");
uint256 upkeepId = s_weatherNftInfo[_tokenId].upkeepId;
s_weatherNftInfo[_tokenId].lastFulfilledAt = block.timestamp;
// ... rest of the function
}
Updates

Appeal created

bube Lead Judge 4 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.