POST /microsub/webmention fetched the attacker-supplied source URL with
redirect:follow and no IP guard, and never checked that target was on this
site — an unauthenticated SSRF reaching RFC1918/loopback/link-local.
- new lib/utils/ssrf-guard.js: assertPublicUrl resolves DNS and rejects
private/loopback/link-local/IPv6-ULA/IPv4-mapped on the resolved IP
(rebinding-resistant, unlike the prior string-prefix isPrivateUrl); safeFetch
re-guards every redirect hop.
- verifier.js: source fetch routed through safeFetch.
- receiver.js: reject target not on publication.me host (spec-required; closes
open-relay angle). No auth gate added — webmention stays an open protocol.
- test/ssrf-guard.test.js: 7 cases, internal blocked + public accepted.