- সারি
- ৩ আগস্ট, ২০২৬ এ ৩:৩৪ AM UTC
- লেখক
- kamo
- মন্তব্য@ info: status
- ae85a8a
remotePatterns was [{ protocol: "https", hostname: "**" }]. That made the image optimizer a general-purpose fetcher: any caller could ask this server to retrieve any URL, with no scheme check, no address check, no redirect limit and no size limit, from a pod that sits beside an unauthenticated Redis on 6379, MinIO with root credentials on 9000, and CockroachDB on 26257. It predated the avatar work and would have become load-bearing the moment images started flowing through it. Enumerating allowed hosts was never the fix. This is a white-label platform — every tenant has its own theme.<domain> asset origin — and next.config is evaluated at build time, so it cannot know them. Naming one tenant would break images for all the others. So foreign URLs no longer reach the optimizer at all. safeImageSrc() rewrites any absolute https source to /api/images/proxy, which fetches it server-side behind the same controls as the Java-side fetcher: DNS pinned via a custom lookup so the socket connects to an address that was actually vetted (closing the rebinding window a naive hostname pre-check leaves open), redirects refused, a streaming size cap counted against bytes received rather than a Content-Length a hostile origin understates, and a content-type allowlist so a soft-404 page of HTML never renders as an image. remotePatterns is now empty apart from localhost. Applied to every call site carrying a foreign origin — email-template image blocks (user-supplied URLs), org and software logos, meet branding, member background wallpapers — and to the raw <img> sites too, which the CSP would otherwise have started blocking. That includes Contact.photoUrl, rendered in seven places from a free-text field any user with contact-create rights can set: proxying it removes the stored tracking pixel, since our server does the fetch and the viewer's IP and read timing never reach the chosen host. Left alone deliberately: sources that are local literals (/img/..., /logo/...). Proxying those would add a round trip and buy nothing. safeImageSrc deliberately does not consult `window`. It runs during SSR and again on hydration, and returning a bare path on one pass and a proxy URL on the other is a hydration mismatch on every absolute same-origin image — worth one redundant hop in a rare case to keep both passes identical. The guard is a deliberate twin of the Java PublicHostGuard, tested against the same bypasses — IPv4-mapped, 6to4, NAT64, CGNAT, link-local metadata — so the two cannot quietly diverge.