n8n-io/n8n · error · Error

Webhook URL must use HTTPS. Got: ${url.protocol}

Error message

Webhook URL must use HTTPS. Got: ${url.protocol}

What it means

`validateWebhookUrl` parses the `--webhook-url` value with `new URL(...)` and rejects any scheme other than `https:`. The check is the first line of SSRF/transport defense for the webhook result-sender: plaintext `http://` URLs would expose the (signed) payload and HMAC headers to the network. The thrown message echoes the offending protocol so the cause is obvious.

Source

Thrown at packages/@n8n/ai-workflow-builder.ee/evaluations/cli/webhook.ts:115

		return true;
	}

	return false;
}

/**
 * Validate webhook URL for security (hostname-based checks only).
 * - Must be HTTPS
 * - Must not target localhost or private/internal IP addresses (SSRF prevention)
 *
 * Note: This performs synchronous hostname string validation.
 * For full SSRF protection, use validateWebhookUrlWithDns() which also resolves DNS.
 */
export function validateWebhookUrl(webhookUrl: string): void {
	const url = new URL(webhookUrl);

	if (url.protocol !== 'https:') {
		throw new Error(`Webhook URL must use HTTPS. Got: ${url.protocol}`);
	}

	const hostname = url.hostname.toLowerCase();

	if (
		hostname === 'localhost' ||
		hostname === '127.0.0.1' ||
		hostname === '::1' ||
		hostname === '[::1]'
	) {
		throw new Error('Webhook URL cannot target localhost');
	}

	if (isPrivateIp(hostname)) {
		throw new Error('Webhook URL cannot target private/internal IP addresses');
	}

	const blockedHostnames = ['internal', 'intranet', 'corp', 'private', 'local'];

View on GitHub (pinned to 5ac6606e81)

Solutions

  1. Change the URL scheme to `https://`.
  2. If the receiver is local-only, put it behind a TLS-terminating proxy or a self-signed cert and use an `https://` URL (and accept that localhost is still blocked separately).
  3. For development, use a tunnel (ngrok/cloudflared) that exposes your local receiver over HTTPS.

Example fix

// before
validateWebhookUrl('http://hooks.example.com/eval');
// after
validateWebhookUrl('https://hooks.example.com/eval');
Defensive patterns

Strategy: validation

Validate before calling

function assertHttpsWebhook(url: string): void {
  let parsed: URL;
  try { parsed = new URL(url); } catch { throw new Error(`invalid webhook URL: ${url}`); }
  if (parsed.protocol !== 'https:') {
    throw new Error(`webhook URL must be https, got ${parsed.protocol}`);
  }
}
assertHttpsWebhook(webhookUrl);

Prevention

When it happens

Trigger: Passing `--webhook-url http://example.com/hook` (or any non-https URL) to the eval CLI, or programmatically calling `validateWebhookUrl('http://...')`. The URL parses successfully (so `new URL` does not throw) but `url.protocol` is not `'https:'`.

Common situations: Pointing at a local/test receiver over plain HTTP, a typo (`http:/` vs `https:/`), or a config file that stores the URL without a scheme upgrade after migrating to TLS.

Related errors


AI-assisted analysis of n8n-io/n8n@5ac6606e81 (2026-08-12). Data as JSON: /api/errors/2b3932b17b96e1ff. Report an issue: GitHub.