// Vulnerability and fix
Secure file upload in SaaS
Why upload is a dangerous surface
Upload accepts user data and stores it in your environment. If you trust the name, the declared type, or the destination, you open the door to file execution, overwriting another record, reading someone else’s data, and even SSRF when "upload by URL" fetches an internal address.
Common risks
Every shortcut in upload becomes a vector.
- An executable file served back and executed (RCE/stored XSS).
- Path traversal: a name with ../ writes outside the expected folder.
- File IDOR: downloading another customer’s file by swapping the id.
- SSRF in "import by URL" pointing at an internal/metadata service.
- No size limit becoming a cost and availability abuse.
How to fix it
Treat the file as untrusted from start to finish. Validate on the server, store outside the web root, serve via signed URL, and never let the client choose the write path.
- Validate real type (magic bytes) and size on the backend.
- Generate the name/path on the server; never use the client name directly.
- Store isolated (private bucket) and serve via a temporary signed URL.
- Block SSRF: destination allowlist, no access to internal IP/metadata.
- Tenant scope on file access.
When to validate with a manual test
Upload that accepts customer documents, ticket attachments, or paid media is a sensitive flow. When impact touches customer data or execution in your environment, a scoped Manual Pentest proves what actually breaks, without touching what was not authorized.
Frequently asked questions
Is checking the file extension enough?
No. Extension and content-type are declared by the client and forgeable. Validate the real type by magic bytes on the server and define an allowlist of what is accepted.
What is SSRF in upload?
It happens in "import by URL": the server fetches the address the user sent. Without an allowlist, it can fetch an internal service or the cloud metadata endpoint and leak credentials.
Can I serve the file straight from the public folder?
Avoid it. Store in a private bucket and serve via a temporary signed URL, with tenant scope. A public folder invites file IDOR and improper execution.