File upload endpoints are a common attack vector if not implemented carefully — this guide covers the key security considerations for handling user-uploaded files safely.
Why File Uploads Are High-Risk
An upload endpoint accepts arbitrary user-controlled content, potentially including malicious files (malware, scripts disguised as innocuous file types) or content designed to exploit processing vulnerabilities — treat every upload as untrusted input requiring careful validation.
Validating File Type Correctly (Not Just Trusting the Extension)
const fileType = require('file-type');
const type = await fileType.fromBuffer(uploadedBuffer);
if (!['image/jpeg', 'image/png'].includes(type?.mime)) {
throw new Error('Invalid file type');
}
Never trust a file's claimed extension or client-provided MIME type alone — verify actual file content/magic bytes match the expected type, since a malicious file can easily be renamed to appear as an allowed type.
Enforcing a File Size Limit
app.use(express.json({ limit: '5mb' }));
Prevent excessively large uploads that could exhaust disk space or memory — set a reasonable limit based on your genuine use case's needs.
Never Execute or Directly Serve Uploaded Files from the Same Domain
Storing and serving uploaded files from the same domain/origin as your application creates risk (a malicious uploaded HTML/SVG file could execute in a browser under your domain's origin) — serve user uploads from a separate domain/subdomain, or object storage (see How to Use Object Storage for Application File Uploads) with appropriate content-type headers preventing execution.
Generating New Filenames, Never Trusting User-Provided Names
const crypto = require('crypto');
const newFilename = crypto.randomUUID() + path.extname(originalFilename);
Never use a user-supplied filename directly for storage — risks path traversal attacks (a filename like ../../etc/passwd) and filename collisions; generate a new, safe filename server-side.
Scanning Uploads for Malware
clamdscan /path/to/uploaded/file
See How to Scan for Malware with ClamAV — for applications accepting uploads from untrusted users, scanning uploaded files before storage/processing adds a meaningful additional protection layer.
Storing Uploads Outside the Web Root
If storing locally (rather than object storage), ensure uploaded files aren't stored directly within a web-server-served directory where they could be directly requested/executed — store outside the web root and serve through application logic with appropriate access control.
Setting Appropriate Content-Disposition Headers
Content-Disposition: attachment; filename="download.pdf"
For files that shouldn't be rendered inline in a browser (particularly anything user-uploaded), setting attachment disposition forces download rather than inline rendering, reducing certain content-based attack vectors.
Rate Limiting Upload Endpoints
See How to Rate Limit an API with Nginx — upload endpoints are a natural target for abuse (storage exhaustion, resource consumption); apply appropriate rate limiting specific to this endpoint.
Common Errors
Uploaded image processing crashes or hangs — image/file processing libraries have historically had vulnerabilities exploitable via crafted malicious files; keep processing libraries updated, and consider processing uploads in an isolated/sandboxed context given this risk.
Continue Reading
- How to Use Object Storage for Application File Uploads
- How to Scan for Malware with ClamAV
- Understanding and Mitigating the OWASP Top 10 Vulnerabilities
Browse more articles in Object Storage, Messaging & APIs.