Missing input validation on _pincode and _isoCode allows empty strings to be processed, resulting in invalid oracle requests and potential LINK wastage.
Description
-
The requestMintWeatherNFT
and _sendFunctionsWeatherFetchRequest
functions accept user-supplied location identifiers (_pincode and _isoCode) to fetch current weather data via Chainlink Functions.
-
However, both functions fail to validate these inputs. As a result, a user can pass empty strings (""), triggering oracle calls with malformed or meaningless data. This wastes LINK funds, may return garbage results, or cause unpredictable behavior in the off-chain function logic.
function requestMintWeatherNFT(
string memory _pincode,
string memory _isoCode,
bool _registerKeeper,
uint256 _heartbeat,
uint256 _initLinkDeposit
) external payable returns (bytes32 _reqId) {
@>
...
_reqId = _sendFunctionsWeatherFetchRequest(_pincode, _isoCode);
}
function _sendFunctionsWeatherFetchRequest(
string memory _pincode,
string memory _isoCode
) internal returns (bytes32 _reqId) {
@> string[] memory _args = new string[](2);
@> _args[0] = _pincode;
@> _args[1] = _isoCode;
...
}
Risk
Likelihood:
-
This will occur whenever a user passes empty strings to requestMintWeatherNFT, whether by accident (bad frontend) or intention (malicious griefing).
-
The oracle request will still be sent and consume LINK + gas, regardless of the input validity.
Impact:
-
Unvalidated inputs can trigger broken or failed Chainlink Function executions, potentially wasting LINK or causing unwanted side effects.
-
Multiple invalid calls can drain LINK balances or spam the Chainlink DON, leading to cost or rate-limit issues.
Proof of Concept
In this test:
-
requestMintWeatherNFT() accepts invalid inputs
-
Triggers an off-chain request to OpenWeather with invalid parameters
-
Wastes resources without error
event WeatherNFTMintRequestSent(address user, string pincode, string isoCode, bytes32 requestId);
function testMintAllowsEmptyPincodeAndIsoCode() public {
string memory emptyPincode = "";
string memory emptyIsoCode = "";
vm.expectEmit(true, true, true, true);
emit WeatherNFTMintRequestSent(
address(this),
emptyPincode,
emptyIsoCode,
bytes32(0)
);
weatherNft.requestMintWeatherNFT{value: 0.01 ether}(
emptyPincode,
emptyIsoCode,
false,
0,
0
);
}
Output:
╰─ forge test --mt testMintAllowsEmptyPincodeAndIsoCode -vv ─╯
[⠊] Compiling...
No files changed, compilation skipped
Ran 1 test for test/WeatherNftForkTest.t.sol:WeatherNftForkTest
[FAIL: log != expected log] testMintAllowsEmptyPincodeAndIsoCode() (gas: 44615)
Suite result: FAILED. 0 passed; 1 failed; 0 skipped; finished in 11.63ms (1.62ms CPU time)
Ran 1 test suite in 184.16ms (11.63ms CPU time): 0 tests passed, 1 failed, 0 skipped (1 total tests)
Failing tests:
Encountered 1 failing test in test/WeatherNftForkTest.t.sol:WeatherNftForkTest
[FAIL: log != expected log] testMintAllowsEmptyPincodeAndIsoCode() (gas: 44615)
Encountered a total of 1 failing tests, 0 tests succeeded
Recommended Mitigation
- function requestMintWeatherNFT(
- string memory _pincode,
- string memory _isoCode,
+ function requestMintWeatherNFT(
+ string memory _pincode,
+ string memory _isoCode,
+ ) external payable returns (bytes32 _reqId) {
+ require(bytes(_pincode).length > 0, "Invalid pincode");
+ require(bytes(_isoCode).length > 0, "Invalid ISO code");
- function _sendFunctionsWeatherFetchRequest(string memory _pincode, string memory _isoCode) internal returns (bytes32 _reqId) {
+ function _sendFunctionsWeatherFetchRequest(string memory _pincode, string memory _isoCode) internal returns (bytes32 _reqId) {
+ require(bytes(_pincode).length > 0, "Invalid pincode");
+ require(bytes(_isoCode).length > 0, "Invalid ISO code");