Measured in your browserWe advise on speed. We practice it.Loaded just now · real numbers from this visit, not a lab score.
Page loaded
First byte
DOM ready
First paint
Largest paint
DNS lookup
TLS handshake
Transferred
Saved by compression
Requests

The moment your platform accepts uploads, your CDN is serving files an adversary authored — on infrastructure carrying your name, your cookies and your users’ trust. UGC delivery is therefore a security pipeline with a CDN at the end: every safe platform runs the same four stages — isolated ingest, normalization, isolated serving, and a takedown path that verifiably works — and every UGC incident traces to a skipped stage.

The threat model: hostile authors, your domain

Name what an uploaded file can be: an HTML page wearing a .jpg extension, waiting for a browser to sniff it into executing scripts on your origin; a polyglot valid as two formats at once; a decompression bomb aimed at your thumbnailer; malware using your trusted domain as its distribution host; or simply illegal content, making takedown speed a legal property of your delivery. Two consequences shape everything. First, serving user bytes from your application domain is the root vulnerability — scripts executing there inherit your users’ sessions — so isolation by hostname is structural, not optional. Second, you cannot validate your way to safety by inspecting uploads; the reliable move is to never serve the uploaded bytes at all, which is section three’s job.

Ingest: signed uploads, quarantined storage

Uploads should go directly to quarantine storage via short-lived signed upload URLs — your application authorizes (per user, per size, per declared type), storage receives, and the upload stream never transits your app servers; the signing pattern is the upload-direction twin of signed URLs. Enforce limits at the door: size caps in the signed policy, count and rate limits per account (upload abuse is an abuse vector of its own, and the rate-limiting budgets apply). Everything lands in a quarantine bucket that no serving hostname can reach — scanned, but not trusted because it was scanned. The invariant to build and then audit: there exists no URL, signed or otherwise, that serves a byte from quarantine to a browser.

Normalize: transcode everything, trust nothing

The safety transform is re-encoding: decode every upload and re-encode it into your canonical formats — images to your chosen sizes and formats, video through your transcode ladder, audio likewise — so what reaches the serving bucket are bytes your pipeline authored. Polyglots, embedded scripts, malformed containers and steganographic payloads do not survive an honest decode-encode cycle, which is a stronger guarantee than any scanner’s signature list. Run the transcoders themselves as disposable sandboxes with strict resource ceilings, because decoders are historically where crafted-file exploits land, and a decompression bomb should kill one container, not one pipeline. Strip metadata deliberately — location EXIF is a user-privacy leak your platform should not republish — and write outputs to the serving bucket under content-addressed or otherwise unguessable paths, with the original retained in quarantine only as long as moderation and law require.

Serve: the separate domain and its headers

Serve UGC from a dedicated, cookieless hostname — ideally a separate registrable domain (the usercontent pattern), never a subdomain sharing cookies with your app — fronted by the CDN with caching as generous as any static estate, since normalized objects are immutable. Belt-and-braces the responses at the edge: exact Content-Type from your pipeline’s knowledge (never derived from the file), X-Content-Type-Options: nosniff, a restrictive Content-Security-Policy (a sandboxing policy on anything that could render as a document), and Content-Disposition: attachment for anything users download rather than view — the header machinery from security headers at the edge, tightened for hostile content. Private UGC (DMs, restricted posts) adds token authentication on this hostname; public UGC should stay tokenless and fully cacheable. The edge is also your enforcement point for hotlink policy and per-object kill switches, which brings us to takedowns.

Moderation, takedowns and purge reality

Moderation architecture is a publish-gate decision: hold-then-publish (nothing serves until checks pass) for higher-risk surfaces, publish-then-scan for velocity, most platforms landing on a risk-tiered mix — but whichever you choose, the delivery requirement is identical: removal must actually remove. A takedown is a database flag plus a purge, and the purge must be verified — request the object through the CDN after purging and confirm the 404/410, because cached copies at the edge are precisely the copies that matter legally; the mechanics and their per-platform propagation quirks are in purging without pain. Design object paths so one identity’s content can be purged as a group (per-user prefixes or tags), keep the moderation-to-purge pipeline automated and measured in seconds-to-minutes, and log takedown timestamps end to end — the interval between report and unreachable-at-edge is the number regulators and rights-holders will ask about. UGC delivery done right is boring: hostile bytes never serve, normalized bytes cache forever, and removal is one verified operation.

Get the free assessmentMore analysis