n8n-io/n8n · error · Error

Webhook URL must use HTTPS. Got

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.

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.

Appendix: 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)