ruvnet/ruflo · error · Error
SSRF guard: only HTTPS URLs are permitted, got ${parsed.prot
Error message
SSRF guard: only HTTPS URLs are permitted, got ${parsed.protocol} What it means
Identical HTTPS-only check to error 5, in ruflo/src/ruvocal/mcp-bridge/index.js:746. Once a URL parses, assertSafeUrl requires parsed.protocol === 'https:' and rejects every other scheme. Enforces TLS on all outbound calls from the chat-UI MCP bridge.
Source
Thrown at ruflo/src/ruvocal/mcp-bridge/index.js:746
return { error: err.message };
}
}
// =============================================================================
// SSRF GUARD — Reject requests to private/loopback ranges (CWE-918)
// =============================================================================
const PRIVATE_IP_RE = /^(?:10\.|172\.(?:1[6-9]|2\d|3[01])\.|192\.168\.|127\.|0\.|::1|fc|fd)/i;
function assertSafeUrl(rawUrl) {
let parsed;
try {
parsed = new URL(rawUrl);
} catch {
throw new Error(`SSRF guard: invalid URL — ${rawUrl}`);
}
if (parsed.protocol !== "https:") {
throw new Error(`SSRF guard: only HTTPS URLs are permitted, got ${parsed.protocol}`);
}
const host = parsed.hostname;
if (PRIVATE_IP_RE.test(host) || host === "localhost" || host.endsWith(".local")) {
throw new Error(`SSRF guard: private/loopback host rejected — ${host}`);
}
}
// =============================================================================
// HELPER — Call a backend Cloud Function / API
// =============================================================================
async function callCloudFunction(url, payload, timeoutMs = 25000) {
// Validate the URL before making any network request.
assertSafeUrl(url);
const controller = new AbortController();
const timer = setTimeout(() => controller.abort(), timeoutMs);
try {
const resp = await fetch(url, {View on GitHub (pinned to 6b01dc5a68)
Solutions
- Switch the configured endpoint to https://.
- Put TLS-terminating reverse proxy in front of the HTTP-only service.
- Grep ruvocal .env files and config for 'http://' base URLs and convert them.
- Do not weaken the guard — exempt only reviewed local profiles.
Example fix
// before OPENAI_BASE_URL=http://router.internal/v1 // after OPENAI_BASE_URL=https://router.internal/v1
Defensive patterns
Strategy: validation
Validate before calling
function isHttps(raw: string): boolean { try { return new URL(raw).protocol === 'https:'; } catch { return false; } }
if (!isHttps(url)) throw new Error('ruvocal endpoint must be https'); Type guard
function isHttpsUrl(raw: string): boolean { try { return new URL(raw).protocol === 'https:'; } catch { return false; } } Try / catch
try { await callCloudFunction(url, payload); } catch (e) { if (e instanceof Error && /only HTTPS URLs are permitted/.test(e.message)) throw new Error('Switch ruvocal endpoint to https', { cause: e }); throw e; } Prevention
- Audit ruvocal .env for http:// base URLs.
- Use https:// for OPENAI_BASE_URL and MCP endpoints.
- Apply TLS-terminating proxy for HTTP-only internal services.
When it happens
Trigger: A ruvocal callCloudFunction/assertSafeUrl caller passes a URL with a non-https scheme: 'http://...', 'ws://...', 'ftp://...'.
Common situations: A dev/staging OPENAI_BASE_URL or MCP endpoint left as http://; an internal inference service exposed only over plain HTTP; a websocket URL used where HTTPS is required; config copied from docs that used http.
Related errors
- SSRF guard: only HTTPS URLs are permitted, got ${parsed.prot
- SSRF guard: invalid URL — ${rawUrl}
- SSRF guard: private/loopback host rejected — ${host}
- SSRF guard: invalid URL — ${rawUrl}
- SSRF guard: private/loopback host rejected — ${host}
AI-assisted analysis of ruvnet/ruflo@6b01dc5a68 (2026-08-12).
Data as JSON: /api/errors/45bc221a2df830e5.
Report an issue: GitHub.