From a67bf0c3415568ec76e86c72541aa2797e0858a0 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Wed, 25 Feb 2026 12:51:36 +0000 Subject: [PATCH] security: fix unvalidated URL scheme in webhook target This commit adds URL validation to the `sendWebhook` function to ensure that only `http://` and `https://` schemes are allowed for webhook targets. This prevents potential misuse of other protocols allowed by the browser environment, such as `javascript:` or `file:`. Changes: - Implemented protocol validation in `utils/utils.js`. - Added localized error messages in `_locales/en/messages.json`. - Improved error handling to provide specific feedback for invalid schemes vs malformed URLs. Co-authored-by: cmuench <211294+cmuench@users.noreply.github.com> --- _locales/en/messages.json | 15 +++++++++++++-- utils/utils.js | 18 ++++++++++++++++++ 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 3d28615..f00c96c 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -272,8 +272,19 @@ "optionsTestError": { "message": "Error sending test webhook: ", "description": "Error message for the test webhook." - } - , + }, + "optionsErrorInvalidUrlScheme": { + "message": "Invalid URL scheme. Only http:// and https:// are allowed.", + "description": "Error message when a webhook URL has an invalid scheme." + }, + "optionsErrorInvalidUrl": { + "message": "Invalid URL.", + "description": "Error message when a webhook URL is invalid." + }, + "optionsErrorUrlRequired": { + "message": "URL is required.", + "description": "Error message when a webhook URL is missing." + }, "optionsAppearanceHeader": { "message": "Appearance", "description": "Header for the appearance section." diff --git a/utils/utils.js b/utils/utils.js index 98dd95d..f8436e7 100644 --- a/utils/utils.js +++ b/utils/utils.js @@ -192,6 +192,24 @@ async function sendWebhook(webhook, isTest = false) { const url = webhook.url; + if (!url) { + throw new Error(browserAPI.i18n.getMessage("optionsErrorUrlRequired") || "URL is required."); + } + + try { + const urlObj = new URL(url); + if (urlObj.protocol !== "http:" && urlObj.protocol !== "https:") { + const schemeError = new Error(browserAPI.i18n.getMessage("optionsErrorInvalidUrlScheme") || "Invalid URL scheme. Only http:// and https:// are allowed."); + schemeError.name = "SchemeError"; + throw schemeError; + } + } catch (e) { + if (e.name === "SchemeError") { + throw e; + } + throw new Error(browserAPI.i18n.getMessage("optionsErrorInvalidUrl") || "Invalid URL."); + } + if (method === "POST") { fetchOpts.body = JSON.stringify(payload); } else if (method === "GET") {