MCPcopy Create free account
hub / github.com/PerpetualSoftware/pad / ValidateWebhookURL

Function ValidateWebhookURL

internal/webhooks/validate.go:13–57  ·  view source on GitHub ↗

ValidateWebhookURL checks that a webhook URL is safe to call. It rejects non-HTTP(S) schemes, URLs with credentials, private/reserved IPs (loopback, link-local, RFC1918, cloud metadata), and hostnames that resolve to private IPs.

(rawURL string)

Source from the content-addressed store, hash-verified

11// IPs (loopback, link-local, RFC1918, cloud metadata), and hostnames that
12// resolve to private IPs.
13func ValidateWebhookURL(rawURL string) error {
14 u, err := url.Parse(rawURL)
15 if err != nil {
16 return fmt.Errorf("invalid URL: %w", err)
17 }
18
19 // Scheme must be http or https
20 switch u.Scheme {
21 case "http", "https":
22 // ok
23 default:
24 return fmt.Errorf("unsupported scheme %q: only http and https are allowed", u.Scheme)
25 }
26
27 // Reject URLs with embedded credentials
28 if u.User != nil {
29 return fmt.Errorf("URLs with embedded credentials are not allowed")
30 }
31
32 host := u.Hostname()
33 if host == "" {
34 return fmt.Errorf("URL must have a hostname")
35 }
36
37 // Check if host is a literal IP
38 if ip := net.ParseIP(host); ip != nil {
39 if isPrivateIP(ip) {
40 return fmt.Errorf("webhook URLs must not target private or reserved IP addresses")
41 }
42 return nil
43 }
44
45 // Host is a name — resolve it and check all resulting IPs
46 ips, err := net.LookupIP(host)
47 if err != nil {
48 return fmt.Errorf("failed to resolve hostname %q: %w", host, err)
49 }
50 for _, ip := range ips {
51 if isPrivateIP(ip) {
52 return fmt.Errorf("hostname %q resolves to private/reserved IP %s", host, ip)
53 }
54 }
55
56 return nil
57}
58
59// isPrivateIP returns true if the IP is in a private, reserved, or
60// otherwise non-routable range. It covers loopback (127.0.0.0/8, ::1),

Callers 4

handleCreateWebhookMethod · 0.92
checkRedirectMethod · 0.85
attemptDeliverMethod · 0.85
TestValidateWebhookURLFunction · 0.85

Calls 1

isPrivateIPFunction · 0.70

Tested by 1

TestValidateWebhookURLFunction · 0.68