From 73a88c82b1b2cada26cc4b2bc095b54554242239 Mon Sep 17 00:00:00 2001 From: Mir Arif Hasan Date: Thu, 11 Jun 2026 16:08:36 +0600 Subject: [PATCH] fix(backend): reject path/query/fragment in SMTP URL validation (GHSA-v7q6-r45w-2c6r) (#6413) * fix(backend): reject path/query/fragment in SMTP URL validation * refactor: fix ai feedbacks * fix(backend): harden SMTP URL validation against parser differentials --- packages/hoppscotch-backend/src/utils.ts | 25 ++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/packages/hoppscotch-backend/src/utils.ts b/packages/hoppscotch-backend/src/utils.ts index 62d3f77ef..f2c0901ee 100644 --- a/packages/hoppscotch-backend/src/utils.ts +++ b/packages/hoppscotch-backend/src/utils.ts @@ -205,10 +205,27 @@ export const validateSMTPUrl = (url: string) => { if (!url || url.length === 0) return false; - const regex = - /^(smtp|smtps):\/\/(?:([^:]+):([^@]+)@)?((?!\.)[^:]+)(?::(\d+))?$/; - if (regex.test(url)) return true; - return false; + if (/[\s\x00-\x1f\x7f]/.test(url)) return false; + if (/[?#\\]/.test(url)) return false; + if (url.endsWith(':')) return false; + + let parsed: URL; + try { + parsed = new URL(url); + } catch { + return false; + } + + // Only the SMTP schemes are permitted. + if (parsed.protocol !== 'smtp:' && parsed.protocol !== 'smtps:') return false; + if (parsed.pathname !== '' && parsed.pathname !== '/') return false; + if (parsed.search !== '' || parsed.hash !== '') return false; + + // A hostname is required and must not start with a dot. + if (!parsed.hostname || parsed.hostname.startsWith('.')) return false; + + // Port, when present, must be numeric (the URL parser already guarantees this). + return true; }; /**