Summary
The requestMintWeatherNFT
function in the WeatherNft contract lacks proper input validation for critical parameters including pincode, isoCode, heartbeat interval, and initial LINK deposit, potentially allowing invalid data to be stored or excessive LINK deposits.
Vulnerability Details
The function accepts several parameters without validation:
function requestMintWeatherNFT(
string memory _pincode,
string memory _isoCode,
bool _registerKeeper,
uint256 _heartbeat,
uint256 _initLinkDeposit
) external payable returns (bytes32 _reqId) {
}
This could lead to:
Invalid location data being stored (empty or malformed pincode/isoCode)
Extremely short heartbeat intervals causing excessive Chainlink Function calls
Excessive LINK deposits that could be locked in the contract
Proof of Concept
pragma solidity 0.8.29;
import "forge-std/Test.sol";
import "../src/WeatherNft.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
contract InputValidationTest is Test {
WeatherNft public weatherNft;
address public user;
IERC20 public linkToken;
function setUp() public {
weatherNft = WeatherNft(address(0x123));
linkToken = IERC20(address(0x456));
user = address(0x789);
vm.deal(user, 10 ether);
}
function testEmptyPincode() public {
vm.startPrank(user);
uint256 mintPrice = weatherNft.s_currentMintPrice();
linkToken.approve(address(weatherNft), 1 ether);
weatherNft.requestMintWeatherNFT{value: mintPrice}(
"",
"US",
true,
3600,
0.1 ether
);
vm.stopPrank();
}
function testZeroHeartbeat() public {
vm.startPrank(user);
uint256 mintPrice = weatherNft.s_currentMintPrice();
linkToken.approve(address(weatherNft), 1 ether);
weatherNft.requestMintWeatherNFT{value: mintPrice}(
"12345",
"US",
true,
0,
0.1 ether
);
vm.stopPrank();
}
function testExcessiveLinkDeposit() public {
vm.startPrank(user);
uint256 mintPrice = weatherNft.s_currentMintPrice();
linkToken.approve(address(weatherNft), 1000 ether);
weatherNft.requestMintWeatherNFT{value: mintPrice}(
"12345",
"US",
true,
3600,
1000 ether
);
vm.stopPrank();
}
function testInvalidIsoCode() public {
vm.startPrank(user);
uint256 mintPrice = weatherNft.s_currentMintPrice();
linkToken.approve(address(weatherNft), 1 ether);
weatherNft.requestMintWeatherNFT{value: mintPrice}(
"12345",
"INVALID_TOO_LONG",
true,
3600,
0.1 ether
);
vm.stopPrank();
}
}
This PoC demonstrates how the lack of input validation allows users to create NFTs with invalid or problematic parameters, which could lead to various issues in the system.
Impact
The lack of input validation could result in:
NFTs with invalid or unusable location data
Excessive consumption of LINK tokens due to too-frequent updates
Economic losses for users who deposit more LINK than necessary
Potential DoS conditions if many NFTs are created with very short heartbeat intervals
Recommendations
Implement proper input validation for all parameters:
function requestMintWeatherNFT(
string memory _pincode,
string memory _isoCode,
bool _registerKeeper,
uint256 _heartbeat,
uint256 _initLinkDeposit
) external payable returns (bytes32 _reqId) {
require(bytes(_pincode).length > 0, "WeatherNft__InvalidPincode");
require(bytes(_isoCode).length > 0, "WeatherNft__InvalidIsoCode");
require(_heartbeat >= MIN_HEARTBEAT, "WeatherNft__HeartbeatTooShort");
require(_initLinkDeposit <= MAX_LINK_DEPOSIT, "WeatherNft__ExcessiveLinkDeposit");
}
Define appropriate constants for minimum heartbeat and maximum LINK deposit based on the system's requirements.