Skip to content

Webhook delivery client bypasses SSRF protection and disables TLS verification #314

Description

@ThiagoBauken

Summary

The per-user webhook delivery client (created in startClient) does not use the SSRF-protected transport that guards globalHTTPClient, and it disables TLS certificate verification. Filing as a hardening discussion before a PR, since the right fix is likely opt-in to avoid breaking existing setups.

Details

main.go builds globalHTTPClient with a custom dialer (newSafeHTTPClient / isPrivateOrLoopback) that refuses to connect to private/loopback IPs — good SSRF protection. But the per-user webhook client (used by callHookWithHmac / callHookFileWithHmac) is plain:

// wmiau.go (~452)
httpClient := resty.New()
httpClient.SetRedirectPolicy(resty.FlexibleRedirectPolicy(15))
...
httpClient.SetTLSClientConfig(&tls.Config{InsecureSkipVerify: true})   // ~458
  1. SSRF: no IP guard, and it follows up to 15 redirects with no re-validation. On a multi-tenant instance, a user who controls their own webhook URL can point/redirect it to http://169.254.169.254/... (cloud metadata) or other internal services. The global client's guard does not apply here.
  2. TLS InsecureSkipVerify: true: cert verification is disabled for all webhook calls. As HMAC signing is the only webhook integrity mechanism, a MitM can intercept the signed payload + signature.

Threat model

Mainly relevant when operators don't fully trust the users who can configure webhooks (multi-tenant / resold instances); lower risk for single-operator deployments.

Why opt-in

Many deployments legitimately webhook to internal/Docker addresses (n8n, Chatwoot, etc.). A blanket private-IP block would break them, so the fix should be configurable, e.g.:

  • apply the newSafeHTTPClient transport (+ a redirect re-validation hook) to the per-user client, gated by WUZAPI_WEBHOOK_SSRF_PROTECT=true;
  • default TLS verification on, with an opt-in per-user tls_skip_verify for self-signed endpoints.

Locations

  • wmiau.go:452-458
  • main.go (newSafeHTTPClient / isPrivateOrLoopback)

Happy to open a PR along these lines — wanted to agree on defaults/flag names first.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions