From 6856b48700a96a62c1fb9cec982498516276b661 Mon Sep 17 00:00:00 2001 From: Yanhu007 Date: Sun, 12 Apr 2026 03:40:32 +0000 Subject: [PATCH] fix: enforce host boundary in withBase to prevent SSRF via prefix attack MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit withBase() uses startsWith() to check if the input URL already contains the base URL. However, startsWith() does not enforce host boundaries, allowing an attacker to bypass the base URL: // baseURL = 'http://api.internal' // input = 'http://api.internal.attacker.com/steal' // startsWith matches → input returned as-is → SSRF Add a boundary check after the startsWith match: the character following the base URL must be '/', '?', '#', or end-of-string. This prevents prefix attacks where the attacker appends a suffix to the hostname. Fixes #564 --- src/utils.url.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/utils.url.ts b/src/utils.url.ts index 5a725353..1d8d8f46 100644 --- a/src/utils.url.ts +++ b/src/utils.url.ts @@ -44,7 +44,13 @@ export function withBase(input = "", base = ""): string { const _base = withoutTrailingSlash(base); if (input.startsWith(_base)) { - return input; + // Ensure the match ends at a host/path boundary to prevent + // SSRF via prefix attacks (e.g. baseURL="http://api.internal" + // matching "http://api.internal.attacker.com/steal"). + const nextChar = input[_base.length]; + if (!nextChar || nextChar === "/" || nextChar === "?" || nextChar === "#") { + return input; + } } return joinURL(_base, input);