From 3fbba4c2f4782282261f2f7187bbbce1f5e72519 Mon Sep 17 00:00:00 2001 From: Kristjan ESPERANTO <35647502+KristjanESPERANTO@users.noreply.github.com> Date: Sun, 23 Aug 2026 14:25:38 +0200 Subject: [PATCH] fix(weather): restrict provider loading to the providers directory --- defaultmodules/weather/node_helper.js | 11 +++++++++-- .../modules/default/weather/node_helper_spec.js | 15 +++++++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/defaultmodules/weather/node_helper.js b/defaultmodules/weather/node_helper.js index 153ab1c17c..a83a7caf3d 100644 --- a/defaultmodules/weather/node_helper.js +++ b/defaultmodules/weather/node_helper.js @@ -2,6 +2,8 @@ const path = require("node:path"); const NodeHelper = require("node_helper"); const Log = require("logger"); +const providersDir = path.join(__dirname, "providers"); + module.exports = NodeHelper.create({ providers: {}, lastData: {}, @@ -26,7 +28,7 @@ module.exports = NodeHelper.create({ * @param {object} config The configuration object */ async initWeatherProvider (config) { - const identifier = config.weatherProvider.toLowerCase(); + const identifier = typeof config.weatherProvider === "string" ? config.weatherProvider.toLowerCase() : ""; const instanceId = config.instanceId; Log.log(`Attempting to initialize provider ${identifier} for instance ${instanceId}`); @@ -46,8 +48,13 @@ module.exports = NodeHelper.create({ } try { + // Reject anything that would resolve outside providersDir (path traversal) + const providerPath = path.join(providersDir, `${identifier}.js`); + if (path.dirname(providerPath) !== providersDir) { + throw new Error(`Unsupported weather provider: ${config.weatherProvider}`); + } + // Dynamically load the provider module - const providerPath = path.join(__dirname, "providers", `${identifier}.js`); Log.log(`Loading provider from: ${providerPath}`); const ProviderClass = require(providerPath); diff --git a/tests/unit/modules/default/weather/node_helper_spec.js b/tests/unit/modules/default/weather/node_helper_spec.js index 2f18e9654a..81a49b7305 100644 --- a/tests/unit/modules/default/weather/node_helper_spec.js +++ b/tests/unit/modules/default/weather/node_helper_spec.js @@ -95,6 +95,21 @@ describe("weather node_helper reconnect handling", () => { expect(helper.sendSocketNotification).toHaveBeenCalledTimes(1); }); + it("rejects unsupported weather providers before loading a module", async () => { + const helper = await loadWeatherNodeHelper(); + + await helper.initWeatherProvider({ + weatherProvider: "../../calendar/node_helper", + instanceId: "weather-current", + type: "current" + }); + + expect(helper.sendSocketNotification).toHaveBeenCalledWith("WEATHER_ERROR", { + instanceId: "weather-current", + error: "Unsupported weather provider: ../../calendar/node_helper" + }); + }); + it("cleans up provider and cached data when stopping an instance", async () => { const helper = await loadWeatherNodeHelper(); const instanceId = "weather-current";