Social & feeds
Link previews - fetching a stranger's page safely
Why unfurling a pasted URL is a server-side request forgery problem first and a caching problem second.
What this board gets wrong on purpose
The tension
The board defends the network properly and then trusts the content completely. A preview is the page owner's own description of their page, fetched by a client they can recognise - a shared egress range and a fixed user agent - so a phishing page can serve a harmless "Shared document" card to the fetcher and a fake bank login to the humans who click it. The cache makes it worse: it is keyed by URL for 24 hours and the first unfurl wins, so a link that was benign when first shared and swapped afterwards keeps its benign card for every one of the next day's shares. Unfurling on paste, before send, also tells the site that somebody is typing its link right now. And the guard is one implementation: if its URL parser and the HTTP client's parser ever disagree about what host "http://a@b:80@c/" means - the classic parser differential - the guard approves one address and the client connects to another, and only the egress proxy stands between that and the metadata endpoint.
Practise this as an interview
Take Link previews - fetching a stranger's page safely as a timed system design interview on a blank board - on your own, with the requirements to check yourself against, or with a candidate you invite.
Start here
Why this design
Every chat and social product turns a pasted URL into a card with a title, a description and a picture. It looks like a scraping exercise and is really a security boundary: the feature lets any user aim your servers at any address, and the most valuable address on a cloud network - the instance metadata endpoint - answers anyone who can reach it with credentials. Interviewers like it because a candidate who starts with caching has walked past the actual question.
What you will learn
- What server-side request forgery is, concretely: which addresses must never be fetched and why "block 127.0.0.1" is not a defence.
- Why the check and the connection must use one pinned IP, and why every redirect hop is checked again.
- Network isolation as the primary control: a fetcher subnet that can reach nothing, behind an egress proxy that refuses private ranges.
- Why a fetch has hard caps - 5 seconds, 1 MB, 5 redirects, text/html only - and what each one stops.
- Caching by normalised URL, why the recipient must never contact the site, and what a URL-keyed cache gets wrong.
How to read this board
- Press Play: the walkthrough follows one pasted link through the cache, the guard and the fetch, then shows the two requests that must be refused.
- THE PASTE (left) is the product; THE FETCH (middle) is a box that can reach only the public internet; THE INTERNET (right) holds the site and the two things that must never be reached.
- 1 · Requirements, 2 · Capacity and 3 · Storage - including why thumbnails are 92% of the bytes.
- 4 · Availability - why a preview is the most optional thing in the product, and must be treated that way.
- 5 · How it works in prose, then 6 · Deployment - including how to test that the guard actually guards.
- Finally the DATA MODEL, then argue with the weakness: the board trusts the page's own description of itself, and the first unfurl wins for a day.
1 · Requirements
Ask these before drawing anything
- Unfurl on paste or on send? On paste feels instant and leaks to the site that someone is composing; on send is private and the card arrives a second after the message.
- Does the sender see and approve the card before sending? If yes, the sender can remove a misleading preview; if no, the card is the site's statement in the sender's voice.
- Do we unfurl links in private messages, or only public channels? End-to-end encrypted products cannot unfurl server-side at all - the sender's device has to.
- Should we fetch images, or only text? Images are 92% of the bytes and every one is an untrusted file going through a decoder.
- Are there first-party providers (video sites, maps) with oEmbed endpoints we should prefer over scraping?
- Can a domain owner opt out, and can our trust-and-safety team block a domain from unfurling within minutes?
Functional
- Given a URL, return a card: canonical URL, title, description, site name, thumbnail.
- Never fetch a private, loopback, link-local or internal address, including via redirects or DNS changes.
- Cap every fetch: 5 s total, 1 MB read, 5 redirects, text/html only for the page.
- Proxy and re-encode thumbnails; the recipient never contacts the original site.
- Cache cards by normalised URL; negative-cache failures.
- Let senders remove a card and let moderators block a domain.
Non-functional
- Cache hit: p95 under 50 ms. Miss: card visible within 3 s at p95, or the message goes without one.
- Zero successful requests from the fetcher to any non-public address - measured at the egress proxy, not asserted in code.
- A preview failure never delays or fails a message.
- A malicious page or image must not crash, hang or exhaust a fetcher worker.
Out of scope
- Client-side unfurling for end-to-end encrypted chats.
- Malicious-URL classification (safe browsing lookups) - a separate check the card could carry a warning from.
- Full-page archiving or screenshots.
The rest of this board
Available on Tier Slate
This page publishes the question. The answer — 5 more written pages, an 8-step narrated walkthrough and a 5-table schema — is the board itself, and it opens in Tierslate.
- 5written pages
- 8walkthrough steps
- 5tables37 columns
5 pages behind this one
- Capacity estimation
- Storage estimation
- Availability
- How it works
- Deployment plan
More boards
Timelines, follows, fan-out - the read-heavy classics.
- Social news feed - fan-out on write or on read
- Media feed - the feed serves URLs, the edge serves bytes
- The professional graph - degrees, and why it is not a join
- Comment trees - one range scan, and four writes per vote
- The social graph - one edge, written twice
- Home timeline - materialise it, then keep it honest
- Blog platform - write once, cache everywhere
- Reviews and ratings - the average that must not be gamed
- Content moderation - deciding before everyone sees it
- Stories - posts that delete themselves in 24 hours