Link Preview SSRF: How Unfurls Become Server-Side Fetches
Paste a URL into chat, tickets, or comments and the product often builds a preview card. Title, image, sometimes a snippet—produced by a backend fetcher, not your browser. That fetcher is an SSRF primitive wearing a friendly UI.
Stop there if you only get a DNS hit? Sometimes. Often the same code path follows redirects into places browsers would never send corporate credentials.
Trigger the unfurl reliably
Find features that render Open Graph data: messaging, link-in-bio fields, CRM notes, markdown previews, and "share URL" assistants. Submit a unique collaborator URL. Confirm the preview worker requests it.
Inspect request headers on your listener. User-Agent strings like Slackbot, Twitterbot, or a custom PreviewBot identify the component. Cookies or authorization headers on that request are a serious extra finding—preview bots should be anonymous.
Try HTTP to HTTPS upgrades, 301 chains across hosts, and a final hop to a dead drop you control. If the worker follows cross-host redirects, you can often pivot from an allowlisted vanity domain to an internal target later. Some products unfurl only after a message is persisted; edit an existing message to re-trigger without spamming channels.
Bypass filters the boring way
Blocklists fail in predictable ways:
- DNS names that resolve to
127.0.0.1after validation - Decimal or IPv6 encodings of loopback
- Nested redirects
- URLs with userinfo (
http://127.0.0.1@your-host/) depending on parser https://metadata.examplestyle hosts that are not the real metadata IP but still internal
Only use encodings and targets permitted by the program. A clean collaborator redirect chain that ends on an internal health check you are allowed to touch beats a noisy scan of the whole RFC1918 space.
Time-of-check issues show up when validation resolves DNS once and the fetch resolves again later. Rebinding labs are advanced; do not run them against production infra you do not understand.
Impact beyond the ping
Partial response bodies reflected into the preview card can disclose internal HTML. Image fetches might hit different egress rules than HTML fetches—test both og:url and og:image. Some workers render PDFs or screenshots; those pipelines can reach file handlers with their own SSRF or XSS stories. Cache headers on the preview object also tell you whether a poisoned card sticks for other users in the same workspace.
Reporting cleanly
Show the message or field used, the collaborator HTTP trace, redirect steps, and any reflected content. Delete the preview artifacts afterward if the product retains them.
CWE-918 is the right label. Remediation is egress allowlists, no link-local ranges, limited redirects, dedicated network namespaces for renderers, and stripping inbound auth headers. Unfurls should decorate links—not extend the trust boundary to whatever hostname a user pasted. Private channels versus public channels sometimes use different workers. Retest the same URL in both if your role allows it; egress rules are not always shared. A preview that only fires for users with a paid plan can still matter if attackers can buy the cheapest seat and unfurl into shared infra.