{"record":{"id":"fdfda431f2904f87","repo":"ruvnet/ruflo","slug":"ssrf-guard-only-https-urls-are-permitted-got-p","errorCode":null,"errorMessage":"SSRF guard: only HTTPS URLs are permitted, got ${parsed.protocol}","messagePattern":"SSRF guard: only HTTPS URLs are permitted, got (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"ruflo/src/mcp-bridge/index.js","lineNumber":657,"sourceCode":"\n  return { guidance: `Unknown topic '${topic}'. Use 'overview', 'groups', or a specific group name.`, topic };\n}\n\n// =============================================================================\n// SSRF GUARD — Reject requests to private/loopback ranges (CWE-918)\n// =============================================================================\n\nconst PRIVATE_IP_RE = /^(?:10\\.|172\\.(?:1[6-9]|2\\d|3[01])\\.|192\\.168\\.|127\\.|0\\.|::1|fc|fd)/i;\n\nfunction assertSafeUrl(rawUrl) {\n  let parsed;\n  try {\n    parsed = new URL(rawUrl);\n  } catch {\n    throw new Error(`SSRF guard: invalid URL — ${rawUrl}`);\n  }\n  if (parsed.protocol !== \"https:\") {\n    throw new Error(`SSRF guard: only HTTPS URLs are permitted, got ${parsed.protocol}`);\n  }\n  const host = parsed.hostname;\n  if (PRIVATE_IP_RE.test(host) || host === \"localhost\" || host.endsWith(\".local\")) {\n    throw new Error(`SSRF guard: private/loopback host rejected — ${host}`);\n  }\n}\n\n// =============================================================================\n// HELPER — Call a backend Cloud Function / API\n// =============================================================================\n\nasync function callCloudFunction(url, payload, timeoutMs = 25000) {\n  // Validate the URL before making any network request.\n  assertSafeUrl(url);\n  const controller = new AbortController();\n  const timer = setTimeout(() => controller.abort(), timeoutMs);\n  try {\n    const resp = await fetch(url, {","sourceCodeStart":639,"sourceCodeEnd":675,"githubUrl":"https://github.com/ruvnet/ruflo/blob/6b01dc5a687b26b3e218f796de45ec51f8fa9e8c/ruflo/src/mcp-bridge/index.js#L639-L675","documentation":"Second check in assertSafeUrl(): after a URL parses successfully, the guard requires parsed.protocol === 'https:'. Any other scheme (http:, ftp:, ws:, file:, etc.) is rejected. This is an SSRF/transport-security control ensuring all outbound calls from the MCP bridge use TLS.","triggerScenarios":"Passing a URL whose scheme is not https: — 'http://api.example.com', 'ws://service', 'ftp://host/file'. A bare hostname that the URL constructor coerces is caught here too if it resolves to a non-https scheme.","commonSituations":"Local/dev base URLs left as http://localhost:...; an internal service that only exposes plain HTTP; a config copied from a staging doc that used http; a websocket URL passed where an HTTPS endpoint is expected.","solutions":["Change the base URL to its https:// form.","Terminate TLS at a reverse proxy in front of the local/internal service and point the config at the https endpoint.","Add an allowlisted local-override only in non-production with an explicit, reviewed exception — never disable the guard globally.","Audit env vars and config files for any http:// base URLs."],"exampleFix":"// before\nconst url = 'http://internal-svc.example.com/func';\n\n// after\nconst url = 'https://internal-svc.example.com/func';","handlingStrategy":"validation","validationCode":"function isHttps(raw: string): boolean { try { return new URL(raw).protocol === 'https:'; } catch { return false; } }\nif (!isHttps(url)) throw new Error('backend URL must use https');","typeGuard":"function isHttpsUrl(raw: string): boolean { try { return new URL(raw).protocol === 'https:'; } catch { return false; } }","tryCatchPattern":"try { await callCloudFunction(url, payload); } catch (e) { if (e instanceof Error && /only HTTPS URLs are permitted/.test(e.message)) throw new Error('Backend URL must be https:// — check config', { cause: e }); throw e; }","preventionTips":["Use https:// for all configured base URLs.","Terminate TLS in front of HTTP-only internal services.","Grep configs for http:// base URLs in CI."],"tags":["security","ssrf","protocol","tls","mcp-bridge"],"backgroundTag":null,"analyzedSha":"6b01dc5a687b26b3e218f796de45ec51f8fa9e8c","analyzedAt":"2026-08-12T13:20:50.148Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}