How to handle untrusted file uploads with size limits, content validation, safe storage, malware scanning and asynchronous processing boundaries.
Bound the upload before buffering it, inspect content rather than names, store it outside the application path and make scanning state explicit.
Bound the input early
Reject requests above a documented size before the service allocates unbounded memory or consumes expensive downstream bandwidth. Enforce limits at the proxy and application layer because either boundary can be bypassed or misconfigured.
Treat filenames as display metadata, not storage paths. Generate identifiers, normalise metadata and prevent path traversal, archive bombs and decompression surprises.
Validate content and storage
MIME headers and extensions are hints. Inspect magic bytes and, where the risk requires it, scan the content before making it available for download or processing. Keep uploads in private object storage with short-lived, authorised access URLs.
Never serve untrusted content from the application origin with an executable content type. Set download headers and a content security policy appropriate to the file class.
Model scanning as a state machine
Large files and malware scans should not block a request while holding a database transaction. Persist an upload record with states such as received, scanning, accepted and rejected, then let a worker advance it with idempotent transitions.
Test interrupted uploads, duplicate notifications, scanner timeouts and an accepted file that later becomes unavailable. Security evidence includes recovery behaviour, not just the happy upload.
Evidence to take into review
- Size and rate limits apply before unbounded buffering.
- Names and MIME types are never treated as proof of safety.
- Files use private storage and generated identifiers.
- Scanning and availability are explicit states.
- Interrupted, duplicate and scanner-failure paths are tested.
Explore all engineering notes.
Use PRODUCTION-7 to connect this concern with the other dimensions of a trustworthy backend.
View all articles Get the checklist