fix(webhook): guard deliveries against loopback and link-local SSRF #27

Merged
nalum merged 1 commit from fix/webhook-ssrf-guards into main 2026-08-13 11:39:45 +00:00
Owner

Webhook deliveries used http.DefaultClient: redirects followed, no IP validation, DNS-rebinding-prone. Now:

  • Dedicated client validates the resolved IP in the dialer Control hook (after DNS, before connect — rebinding-safe): loopback, link-local (including 169.254.169.254 metadata), unspecified, and multicast are refused, each with a named reason.
  • Private ranges stay allowed — LAN targets (ntfy on the household network) are the product's point. Recorded in an ADR-0024 update note.
  • Redirects are refused outright with a named error (delivery semantics never need them).
  • validateTargetURL applies the same IP-class check at create/update time (best-effort resolve, 2s timeout) so admins get an immediate InvalidArgument naming the class instead of silent delivery failures.
  • Test seam AllowLoopbackWebhooks (off in production) keeps the integration harness's 127.0.0.1 receivers working; make test-integration passes.

Fixes #14

🤖 Generated with Claude Code

Webhook deliveries used `http.DefaultClient`: redirects followed, no IP validation, DNS-rebinding-prone. Now: - Dedicated client validates the **resolved** IP in the dialer `Control` hook (after DNS, before connect — rebinding-safe): loopback, link-local (including 169.254.169.254 metadata), unspecified, and multicast are refused, each with a named reason. - **Private ranges stay allowed** — LAN targets (ntfy on the household network) are the product's point. Recorded in an ADR-0024 update note. - Redirects are refused outright with a named error (delivery semantics never need them). - `validateTargetURL` applies the same IP-class check at create/update time (best-effort resolve, 2s timeout) so admins get an immediate `InvalidArgument` naming the class instead of silent delivery failures. - Test seam `AllowLoopbackWebhooks` (off in production) keeps the integration harness's 127.0.0.1 receivers working; `make test-integration` passes. Fixes #14 🤖 Generated with [Claude Code](https://claude.com/claude-code)
fix(webhook): guard deliveries against loopback and link-local SSRF
All checks were successful
check / go (push) Successful in 1m50s
check / web (push) Successful in 1m26s
19727211ab
Admin-configured webhook URLs could previously reach anything the
server can dial — loopback services, the cloud-metadata range, or a
redirect chain ending anywhere. Deliveries now use a dedicated client
that validates the IP in the dialer's Control hook, after DNS and
immediately before connect, so a DNS-rebinding name is judged on every
attempt rather than once at create. Blocked classes: loopback,
link-local (incl. 169.254.169.254 metadata), unspecified, multicast.
Private LAN ranges stay allowed on purpose — household targets like
ntfy on the family LAN are the product's point (ADR-0024).

Redirects are refused outright with a named error instead of
http.ErrUseLastResponse: delivery semantics never need them (the admin
configures the final URL), the explicit error tells the admin what to
fix, and not following closes the redirect-to-blocked-address hole.

Create/update apply the same IP-class check as a best-effort fast-fail
so a bad target is named immediately; the dial-time check remains the
real guard. The httptest-mounted harnesses opt out via a Config knob
(their receivers live on 127.0.0.1), mirroring EnableReminder.

Fixes #14
nalum force-pushed fix/webhook-ssrf-guards from 19727211ab
All checks were successful
check / go (push) Successful in 1m50s
check / web (push) Successful in 1m26s
to 4f429d671c
Some checks failed
tag / tag (push) Has been cancelled
check / web (push) Successful in 1m29s
check / go (push) Successful in 1m49s
android / build (pull_request) Successful in 6m17s
2026-08-13 11:33:35 +00:00
Compare
nalum scheduled this pull request to auto merge when all checks succeed 2026-08-13 11:34:04 +00:00
nalum merged commit 4f429d671c into main 2026-08-13 11:39:45 +00:00
nalum deleted branch fix/webhook-ssrf-guards 2026-08-13 11:39:45 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
eagraiclainne/app!27
No description provided.