Weather Witness

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

Improper Handling of Geocoding API Response Errors in `GetWeather.js` May Lead to Subsequent Weather Request Failures

Root + Impact

Description

In the GetWeather.js script, the Geocoding API is first called to convert a pincode and country code into latitude and longitude. The script checks geoCodingResponse.error, and if true, throws an error "Request failed, try checking the params provided". However, it does not check if geoCodingResponse.data actually exists or contains the expected lat and lon fields before using them in the subsequent Weather API request.
If the Geocoding API request itself does not have a network error (geoCodingResponse.error is false), but returns an unexpected data format (e.g., due to an invalid pincode or country code combination, the API might return an empty data object or an error message body without lat/lon), then accessing geoCodingResponse.data.lat and geoCodingResponse.data.lon could result in undefined.
When these undefined values are used as parameters for the Weather API request, the Weather API request will almost certainly fail, either returning an error or weather for a nonsensical default location (like near the equator and prime meridian). The script subsequently checks weatherResponse.error, but this may not catch logical errors stemming from invalid latitude/longitude.

// Root cause in the codebase with @> marks to highlight the relevant section
// File: functionsSource/GetWeather.js
// ref: https://openweathermap.org/api/geocoding-api
const geoCodingRequest = Functions.makeHttpRequest({
url: "http://api.openweathermap.org/geo/1.0/zip",
method: "GET",
params: { zip: `${args[0]},${args[1]}`, appid: secrets.apiKey }
})
const geoCodingResponse = await geoCodingRequest;
if (geoCodingResponse.error) throw Error("Request failed, try checking the params provided") // Checks for network error
// @> Missing check for whether geoCodingResponse.data is valid and contains lat/lon.
// @> For example, if args[0] or args[1] are invalid, the API might return a response like { "cod": "404", "message": "city not found" },
// @> in which case geoCodingResponse.data.lat would be undefined.
// ref: https://openweathermap.org/current
const weatherRequest = Functions.makeHttpRequest({
url: "https://api.openweathermap.org/data/2.5/weather",
method: "GET",
// @> If geoCodingResponse.data.lat or .lon are undefined, this will cause the Weather API request to fail or return erroneous data.
params: { lat: geoCodingResponse.data.lat, lon: geoCodingResponse.data.lon, appid: secrets.apiKey }
})
const weatherResponse = await weatherRequest
if (weatherResponse.error) throw Error("Request failed, try checking the params provided") // May catch Weather API network errors, but not necessarily logical errors from invalid lat/lon.
// ... (subsequent weather ID processing) ...

Risk

Likelihood: Medium

  • Users might provide invalid pincode or country code combinations (e.g., typos, non-existent pincodes).

  • In such cases, the Geocoding API response body might not contain lat and lon.

Impact: Low

  • Chainlink Function Failure or Inaccurate Data Return: If the Weather API request fails due to invalid lat/lon, the Chainlink Function might fail (if weatherResponse.error becomes true), or if the Weather API silently handles invalid lat/lon by returning some default data, the NFT might be updated with weather for an irrelevant location.

  • Wasted Oracle Calls and Gas: A failed Function execution still consumes LINK from the oracle subscription and gas for the transaction.

  • Poor User Experience: User-provided input leads to unexplained errors or inaccurate weather updates.

Proof of Concept

  1. A user initiates a request in WeatherNft.sol (either requestMintWeatherNFT or performUpkeep) where args[0] (pincode) is "00000" and args[1] (ISO country code) is "XX" (an invalid country code).

  2. GetWeather.js executes the Geocoding API request.

  3. The OpenWeather Geocoding API, for an invalid zip and country code, might return an HTTP 200 OK response, but with an error message in the body, e.g., {"cod":"404", "message":"city not found"}. In this scenario, geoCodingResponse.error is false.

  4. The script attempts to access geoCodingResponse.data.lat and geoCodingResponse.data.lon. Since geoCodingResponse.data is {"cod":"404", "message":"city not found"}, these accesses will yield undefined.

  5. The script proceeds to construct the Weather API request with lat and lon URL parameters both being undefined.

  6. The Weather API (api.openweathermap.org/data/2.5/weather) receives a request with invalid lat/lon parameters.

    • Scenario A: The Weather API returns an error (e.g., HTTP 400 Bad Request). weatherResponse.error would then be true, and the script would throw "Request failed, try checking the params provided".

    • Scenario B: The Weather API might attempt to "guess" or use default values (e.g., lat=0, lon=0) and return weather for that location. The script would not detect this problem, and the NFT would be updated with weather for the wrong location.

  7. The end result is either a failed Function call or an NFT updated with incorrect data.

Recommended Mitigation

Add stricter checks after the Geocoding API call to ensure geoCodingResponse.data exists and contains the required lat and lon fields before accessing them. If the check fails, a more specific error should be thrown.

// File: functionsSource/GetWeather.js
// ... (geoCodingRequest setup) ...
const geoCodingResponse = await geoCodingRequest;
if (geoCodingResponse.error) {
throw Error("Geocoding API request failed. Network error or an issue with the Functions request setup.");
}
// @> Add validation for geoCodingResponse.data and its content
+if (!geoCodingResponse.data || typeof geoCodingResponse.data.lat === 'undefined' || typeof geoCodingResponse.data.lon === 'undefined') {
+ // Attempt to log more info from the API response for debugging, if possible
+ // console.log("Geocoding API did not return valid latitude/longitude. Response data:", geoCodingResponse.data);
+ throw Error("Geocoding API did not return valid latitude/longitude. Check pincode and country code validity. Response: " + JSON.stringify(geoCodingResponse.data));
+}
// ref: https://openweathermap.org/current
const weatherRequest = Functions.makeHttpRequest({
url: "https://api.openweathermap.org/data/2.5/weather",
method: "GET",
params: { lat: geoCodingResponse.data.lat, lon: geoCodingResponse.data.lon, appid: secrets.apiKey }
})
const weatherResponse = await weatherRequest
if (weatherResponse.error) {
// console.log("Weather API request failed. Response data:", weatherResponse.data);
throw Error("Weather API request failed. Network error or an issue with the Functions request setup, possibly due to invalid lat/lon from geocoding.");
}
// @> Add validation for weatherResponse.data and its content to ensure it has expected weather info
+if (!weatherResponse.data || !weatherResponse.data.weather || !weatherResponse.data.weather[0] || typeof weatherResponse.data.weather[0].id === 'undefined') {
+ // console.log("Weather API did not return expected weather data structure. Response data:", weatherResponse.data);
+ throw Error("Weather API did not return expected weather data structure. Response: " + JSON.stringify(weatherResponse.data));
+}
const weather_id = weatherResponse.data.weather[0].id;
// ... (rest of the script) ...

By adding these extra checks, the script can catch issues arising from invalid input or unexpected API responses earlier and provide more informative errors, rather than potentially proceeding with invalid data or returning inaccurate results. A check on the weatherResponse.data structure has also been added to ensure the subsequent extraction of weather_id is safe.

Updates

Appeal created

bube Lead Judge 3 days ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity
Assigned finding tags:

[Invalid] Lack of input validation in `requestMintWeatherNFT`

This is informational. It is user's responsibility to provide correct input arguments. If the user provides incorrect arguments, it will lead to incorrect results, lost funds or failed transaction.

Support

FAQs

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