aboutsummaryrefslogtreecommitdiffstats
path: root/lib/safe-fetch.ts
Commit message (Collapse)AuthorAgeFilesLines
* safe-fetch: decode IPv6 hosts before checking for private addressesAdam Soltys2026-09-251-10/+46
| | | | | | | | | URL parsing serializes IPv6 hosts in hex, so an IPv4-mapped address never matched the dotted-quad pattern and passed as public. Expand the address and judge every form that embeds an IPv4 address by that address, and block the remaining non-public IPv6 ranges. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
* lnurl: pin SSRF-guard fetches to the validated IP (close DNS-rebinding)Adam Soltys2026-08-271-51/+92
| | | | | | | | | | | | | | | | | | | | | | | | | | The prior guard resolved the target host, checked the IP against the private/loopback/link-local/CGNAT/metadata blocklist, then let got fetch the URL — which re-resolves DNS independently when it connects, leaving a rebinding window where a low-TTL host can pass the check as public and connect as internal. Reimplement safeGot on node http/https with a custom lookup that validates and returns the exact IP the socket then connects to, so the validation and the connection target are one and the same (no resolve/connect gap). Redirects are followed manually and every hop is re-validated the same way; IP-literal hosts (which bypass the lookup hook) are checked up front; the 2MB cap is enforced on the streamed body rather than a spoofable content-length header. Scheme stays restricted to http(s) with an 8s timeout. safeGot's contract is unchanged, so the three lnurl callers are untouched. Verified in-container: every internal target (loopback, docker-internal, 169.254 metadata, CGNAT, ULA, IP-literal, octal-literal) is blocked by the guard, a server-side redirect into the metadata endpoint is blocked at the hop, and legit external resolution (including http->https redirects) still works with correct TLS against the real hostname over the pinned IP. Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_01DKkev76U4YRnRAqM6jqbae
* lnurl: SSRF-guard user-supplied URL fetches + validate zap eventsAdam Soltys2026-06-151-0/+88
The /lnurl/proxy, /decode and /encode handlers fetched an arbitrary user-supplied URL via got() and returned the body — an unauthenticated SSRF reaching internal services. Route those fetches through a new safeGot() that rejects hosts resolving to loopback/private/link-local/ CGNAT/metadata ranges, re-validates on each redirect hop, restricts the scheme to http(s), and caps timeout + response size. Also validate the NIP-57 zap request (kind 9734 + signature) before storing it, instead of trusting the client-supplied event. These endpoints can't be removed — they back lightning-address/LNURL parsing and resolution in the wallet UI. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>