From 01e376f10b4f87bfae5617020de3bc3f62418b7d Mon Sep 17 00:00:00 2001 From: Luis Montes Date: Fri, 6 Feb 2026 23:58:13 -0700 Subject: [PATCH] fix: validate dynamicHost URL to prevent injection (CVE-HSYNC-2026-004) --- connection.js | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/connection.js b/connection.js index ffef33a..d28ea40 100644 --- a/connection.js +++ b/connection.js @@ -47,12 +47,23 @@ export async function createHsync(config) { let dynamicTimeout; if (dynamicHost && !hsyncSecret) { - const result = await fetch.post(`${dynamicHost}/${hsyncBase}/dyn`, {}); - if (dynamicHost.toLowerCase().startsWith('https')) { - hsyncServer = `wss://${result.url}`; - } else { - hsyncServer = `ws://${result.url}`; + // Validate dynamicHost to prevent URL injection/SSRF (CVE-HSYNC-2026-004) + let validatedHost; + let isSecure; + try { + const parsed = new URL(dynamicHost); + // Only allow http/https protocols + if (!['http:', 'https:'].includes(parsed.protocol)) { + throw new Error(`Invalid protocol: ${parsed.protocol}`); + } + isSecure = parsed.protocol === 'https:'; + // Reconstruct URL with only origin to strip path/query/fragment + validatedHost = parsed.origin; + } catch (urlErr) { + throw new Error(`Invalid dynamicHost URL: ${urlErr.message}`); } + const result = await fetch.post(`${validatedHost}/${hsyncBase}/dyn`, {}); + hsyncServer = isSecure ? `wss://${result.url}` : `ws://${result.url}`; hsyncSecret = result.secret; dynamicTimeout = result.timeout; }