A file upload feature touches several distinct risk categories at once — what gets uploaded, where it's stored, and how it's later served back — each needing its own specific handling.
Validate content, not just filename
An extension check (.jpg, .pdf) validates a filename, not the actual file. An attacker can rename anything to have a trusted-looking extension. Validate actual file content — checking magic bytes or using a proper content-sniffing library — before trusting what type of file you've received.
Don't trust the client-supplied filename
User-supplied filenames can contain path traversal sequences (../../etc/passwd) or unexpected characters. Generate your own filename (e.g. a UUID) for storage, and keep the original filename only as metadata if needed for display, never as part of a filesystem path.
Store uploads outside the web root
Uploaded files should generally not be stored somewhere directly executable or accessible via a predictable URL under your application's own domain. Store them in dedicated storage (object storage, or a directory the web server doesn't execute code from) and serve them through a controlled path.
Serve uploads from a separate origin
If a user can upload an HTML file, an SVG (which can contain embedded scripts), or similar content, and it's later served from your main application's domain, it can execute in that origin's security context — effectively a self-inflicted XSS vector. Serving uploaded content from a separate domain or subdomain isolates this risk.
Enforce size and type limits server-side
Client-side validation is a convenience, not a control — it's trivially bypassed. Enforce file size limits and allowed type restrictions on the server, where they can't be skipped.
Scan for malware where relevant
If uploaded files will be shared with or downloaded by other users, scanning uploads for known malware signatures adds a meaningful layer of protection, particularly for platforms accepting a wide range of file types from untrusted users.
Rate limit upload endpoints
Without limits, an upload endpoint can be abused for storage exhaustion or cost abuse, independent of any content-based vulnerability — treat it like any other resource-intensive endpoint from a rate-limiting perspective.