koala73/worldmonitor · error · Error
Webhook URL must use HTTPS
Error message
Webhook URL must use HTTPS
What it means
Returned by blockedNotificationWebhookUrlReason when the parsed URL's protocol is anything other than `https:`. Webhook payloads can carry alert content, so the registration gate refuses cleartext http:// (and any other scheme) to prevent interception and to keep the SSRF surface consistent.
Source
Thrown at api/_notification-webhook-ssrf.ts:223
async function defaultResolveHostname(hostname: string): Promise<string[]> {
const records = await Promise.all([
resolveDnsJson(hostname, 'A'),
resolveDnsJson(hostname, 'AAAA'),
]);
return records.flat();
}
/**
* Fail fast at registration when the webhook hostname currently resolves to a
* private or reserved address. Delivery repeats this check (and pins its
* connection) because DNS can change after registration.
*/
export async function assertNotificationWebhookRegistrationUrlSafe(
rawUrl: string,
resolveHostname: ResolveHostname = defaultResolveHostname,
): Promise<void> {
const staticError = blockedNotificationWebhookUrlReason(rawUrl);
if (staticError) throw new Error(staticError);
const hostname = new URL(rawUrl).hostname.toLowerCase();
if (isIpLiteral(hostname)) return;
let resolvedAddresses: string[];
try {
resolvedAddresses = await resolveHostname(hostname);
} catch (error) {
const message = error instanceof Error ? error.message : String(error);
throw new Error(`Webhook URL DNS resolution failed: ${message}`);
}
if (!resolvedAddresses.length) throw new Error('Webhook URL DNS resolution returned no addresses');
if (resolvedAddresses.some(isBlockedNotificationResolvedAddress)) {
throw new Error('Webhook URL must not point to a private/local address');
}
}
View on GitHub (pinned to ffec79ac33)
Solutions
- Register an https:// URL — terminate TLS at the webhook target (Let's Encrypt, Caddy, or a platform-managed cert).
- For local testing, expose the local server over TLS via a tunnel (e.g. ngrok/cloudflared with https) before registering.
- Update the registration UI to force https and reject http submissions before they reach the API.
Example fix
// before
registerWebhook('http://localhost:9000/hook')
// after
registerWebhook('https://my-tunnel.example.dev/hook') Defensive patterns
Strategy: validation
Validate before calling
function isHttpsUrl(rawUrl: string): boolean {
try { return new URL(rawUrl).protocol === 'https:'; } catch { return false; }
}
if (!isHttpsUrl(input)) return res.status(400).json({ error: 'Webhook URL must use HTTPS.' }); Type guard
function isHttpsWebhookUrl(value: unknown): value is string {
if (typeof value !== 'string') return false;
try { return new URL(value).protocol === 'https:'; } catch { return false; }
} Try / catch
try {
await assertNotificationWebhookRegistrationUrlSafe(rawUrl);
} catch (err) {
if (err.message === 'Webhook URL must use HTTPS') {
return res.status(400).json({ error: 'Webhook URL must use HTTPS. Use an https:// URL.' });
}
throw err;
} Prevention
- Terminate TLS at the webhook target before registering it.
- In the registration UI, reject any submitted value whose parsed protocol is not https.
- For local dev, use an https tunnel (ngrok/cloudflared) rather than http://localhost.
When it happens
Trigger: A webhook registration URL whose scheme is `http:`, `ftp:`, `file:`, or any non-https protocol passes URL parsing but fails this check at api/_notification-webhook-ssrf.ts:169.
Common situations: Local dev webhook pointing at http://localhost; an internal/staging integration that has not been issued a TLS cert; a typo leaving the scheme off so the form defaults to http.
Related errors
- Webhook URL is not a valid URL
- Webhook URL must not point to a metadata endpoint
- Webhook URL must not point to a private/local address
- Webhook URL DNS resolution returned no addresses
- Webhook URL DNS resolution failed: ${message}
AI-assisted analysis of koala73/worldmonitor@ffec79ac33 (2026-08-12).
Data as JSON: /api/errors/45550d68e61728ee.
Report an issue: GitHub.