/** * Search-box.ai * Author: Simon-Pierre Boucher * Contact: contact@spboucher.ai * File: packages/firecrawl/src/url-guard.ts * Description: SSRF guard — rejects private/localhost/metadata URLs before any fetch. */ const BLOCKED_HOSTNAMES = new Set([ "localhost", "127.0.0.1", "0.0.0.0", "::1", "169.254.169.254", // cloud metadata "metadata.google.internal" ]); const PRIVATE_IP_PATTERNS = [ /^10\./, /^127\./, /^169\.254\./, /^172\.(1[6-9]|2\d|3[01])\./, /^192\.168\./, /^0\./, /^fc/i, /^fd/i, /^fe80/i ]; /** Throws if the URL is not a safe public http(s) URL. Returns the normalized URL. */ export function assertSafeUrl(raw: string): string { let url: URL; try { url = new URL(raw); } catch { throw new Error(`invalid URL: ${raw}`); } if (url.protocol !== "http:" && url.protocol !== "https:") { throw new Error(`unsupported protocol: ${url.protocol}`); } const host = url.hostname.toLowerCase(); if (BLOCKED_HOSTNAMES.has(host)) throw new Error(`blocked host: ${host}`); if (host.endsWith(".local") || host.endsWith(".internal")) { throw new Error(`blocked internal host: ${host}`); } if (PRIVATE_IP_PATTERNS.some((re) => re.test(host))) { throw new Error(`blocked private address: ${host}`); } return url.toString(); }