Replaces the regex blocklist in assertNotPrivateUrl with ipaddr.js range
classification and normalizes the host before checking it. Consolidates two
community proposals (#930 ipaddr.js parsing, #912 trailing-dot normalization)
into one validator so the SSRF-critical path lives in-house with full tests.
- Classify literal IPs by range (loopback / linkLocal / unspecified) via
ipaddr.js instead of a hand-maintained regex list, which also catches
alternate IPv4 encodings and avoids over-blocking mapped public IPs (the old
`::ffff:` regex blocked every mapped address, including public ones). IPv4-
mapped IPv6 is reduced to its embedded IPv4 before classification.
- Strip a trailing root dot from the host so `localhost.` / `127.0.0.1.` can't
bypass the checks (they resolve to the same target as the dotless form, #911).
- Strip IPv6 brackets and lowercase for the localhost comparison.
- RFC1918, bare LAN hostnames (e.g. `nomad3`), and external FQDNs remain
allowed — LAN appliances need them, and DNS rebinding is a fetch-time concern
outside this guard's scope.
Adds a consolidated unit spec covering loopback/link-local/unspecified literals,
alternate encodings, IPv4-mapped v6, mixed-case + trailing-dot localhost, and
the allowed LAN/FQDN/mapped-public cases.
Resolves#922. Supersedes #930 and #912 (thanks @Gujiassh and @luyua9).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>