Weather Witness

First Flight #40
Beginner FriendlyFoundrySolidityNFT
100 EXP
View results
Submission Details
Severity: low
Valid

Insecure HTTP for geocoding API call

Root + Impact

Description

The GetWeather.js is responsible for fetching weather data based on a postal code and country ISO code provided by the user. The script first makes a geocoding request to the OpenWeatherMap API to convert the postal code into latitude and longitude coordinates. This initial geocoding API call is made using an insecure HTTP connection.

Using HTTP for this API call exposes the request and response to Man in the Middle attacks. An attacker on the network path between the Chainlink node and the OpenWeatherMap API server can intercept or modify the data in transit. While the subsequent call to fetch the actual weather data uses HTTPS, it relies on the latitude and longitude obtained from the insecure HTTP geocoding call. When these coordinates are manipulated the entire weather fetching process is compromised.

// ref: https://openweathermap.org/api/geocoding-api
const geoCodingRequest = Functions.makeHttpRequest({
url: "http://api.openweathermap.org/geo/1.0/zip", // URL uses HTTP
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")
// Subsequent request uses HTTPS, but relies on potentially tainted data from geoCodingResponse
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 }
})

Risk

Likelihood:

  • A Chainlink node executes the GetWeather.js script, triggering an API call to the OpenWeatherMap geocoding service via an unsecured HTTP channel.

  • An adversary successfully intercepts and manipulates the network traffic of this HTTP request or its response between the Chainlink node and the API server

Impact:

  • An attacker can modify the latitude and longitude in the geocoding API response. This will cause the script to request weather data for an incorrect location in the API call.

  • The smart contract will receive weather data for the attacker chosen location not the user specified one. This results in the Weather NFT being minted with inaccurate weather attributes or an existing NFT's weather status being updated incorrectly.

Proof of Concept

const http = require('http');
const PORT = 8080;
const server = http.createServer((req, res) => {
// Log incoming request path to verify it's being called
console.log(`Intercepted request for: ${req.url}`);
// Always return coordinates for (0, 0)
const spoofedResponse = [
{
name: "Null Island",
lat: 0,
lon: 0,
country: "ZZ",
},
];
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify(spoofedResponse));
});
server.listen(PORT, () => {
console.log(` Malicious Geocode Server listening on http://localhost:${PORT}`);
});

Recommended Mitigation

--- a/Functions/scripts/GetWeather.js
+++ b/Functions/scripts/GetWeather.js
@@ -8,7 +8,7 @@ const main = async (args, secrets) => {
"use strict";
- url: "http://api.openweathermap.org/geo/1.0/zip",
+ url: "https://api.openweathermap.org/geo/1.0/zip",
params: { zip: `${args[0]},${args[1]}`, appid: secrets[0] },
});
Updates

Appeal created

bube Lead Judge 4 months ago
Submission Judgement Published
Validated
Assigned finding tags:

Use of `http` instead of `https` for getting geo location

Support

FAQs

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