kigi allowed loopback unconditionally and missed several non-public
ranges, and the SSRF check ran only on the initial URL.
Policy (ssrf.rs):
- loopback is blocked unless `[toolset.web_fetch] allow_local` (or
KIGI_WEB_FETCH_ALLOW_LOCAL) is on, AND the URL names it explicitly,
so a public name resolving to loopback stays blocked (DNS rebinding)
- add 0.0.0.0/8, 100.64/10, 192.0.0.0/24, TEST-NET-1/2/3, 198.18/15,
240/4, IPv6 site-local and documentation prefixes
- inherit the IPv4 verdict through mapped, compatible, NAT64 and 6to4
wrappers; network-specific NAT64 prefixes remain uncovered (see doc)
Plumbing (client.rs), where the exploitable half lived:
- re-check every redirect hop, not just the first
- compare hosts exactly; a `www` sibling has its own A records, so it
is a cross-host redirect rather than an auto-followed hop
- run the check before the fetch service, so a blocked URL is never
posted to an endpoint that egresses elsewhere
- exempt explicit local hosts from the https upgrade and from the
single-label filter, and re-upgrade each followed hop
Wiring: allow_local reaches WebFetchParams from both construction
paths; documented in the config guide and the README env table.