`resizeAvatar` previously called `node-fetch` on any string input with
no validation. When OIDC providers surface a user-controllable
`picture` claim, this could be used to make blind SSRF requests to
internal services on every social login.
Wrap the URL fetch with:
- An allowlist on the URL protocol (http/https only).
- The shared `createSSRFSafeAgents` utility, which blocks resolution to
private, loopback, and link-local IPs at TCP connect time
(TOCTOU-safe; works equally for hostname targets that DNS-resolve
privately and for IP-literal targets, since Node's `net.Socket`
always dispatches through the agent's `lookup` hook).
- `redirect: 'error'` so a public-IP redirect target cannot be used to
bypass the agent check on a subsequent hop.
- A 5-second total request budget (node-fetch v2's `timeout` covers
request initiation through full body receipt, bounding slow-loris
exposure rather than just the TCP connect).
- A 10 MB response cap (`size` option + `Content-Length` pre-check +
post-read length assertion) so a hostile payload cannot exhaust
memory before `sharp()` rejects it.
Fetch the canonicalized `parsed.href` rather than the raw input string
to eliminate any future parser-differential between `new URL()` and
the underlying fetch implementation.
Per-call agent construction is intentional: the avatar path runs once
per social login per user, so pooling adds complexity without a
measurable benefit. Documented inline.
Comprehensive test coverage in `avatar.spec.js`:
- Rejects malformed URLs, non-http(s) schemes (file://, data:,
javascript:).
- Asserts the happy-path canonicalization (`fetch` is called with
`parsed.href`) and the SSRF-safe agent factory routing
(https→httpsAgent, http→httpAgent).
- Rejects non-2xx HTTP status.
- Rejects an oversized Content-Length before reading the body, and
asserts `.buffer()` is never invoked in that case.
- Rejects an oversized body even when the server lies about / omits
Content-Length.
- Surfaces ESSRF, redirect, and `size` overflow errors thrown by the
fetch layer.
- Confirms Buffer inputs bypass the fetcher entirely.