Skip to content
FormSubmit
Spam & Security

Secure File Upload Forms: How to Accept Files Safely

Build a secure file upload form: validate on the server, cap upload size limits, keep files private behind signed links, and stop malicious file uploads.

FormSubmit Team

6 min read

Diagram of a secure file upload form sending files to private storage with signed download links

A secure file upload form treats every uploaded file as untrusted: it validates type and size on the server, stores files privately, serves them through short-lived signed links, and deletes them when they are no longer needed. The browser-side checks you add are for usability, not protection.

If you need to accept files on your website, such as resumes, photos, invoices or design briefs, the upload field is the most dangerous input on the page. A text field can carry spam. A file field can carry malware, a disguised script, or someone else's personal data that you are now responsible for. This guide covers the main risks and the defenses that actually work.

Why file upload security matters

A form that accepts files is effectively a public write endpoint into your storage. Here is what can go wrong:

  • Malicious file uploads. Executables, macro-laden documents or files carrying exploits that target whoever opens them, usually you or your client.
  • Content-type spoofing. A file named invoice.pdf with a Content-Type: application/pdf header can contain anything. Both the extension and the MIME type are set by the client.
  • Server-side execution. On classic hosting, an uploaded .php or .html file saved into a web-accessible folder can be executed or rendered by the server, turning an upload into a site takeover or a phishing page on your domain.
  • Public URLs. Files stored at predictable public paths can be found, shared or indexed. If those files are CVs or ID scans, that is a data leak.
  • Storage abuse. Bots and bad actors can fill your disk or cloud bucket, raising costs or taking the form down.
  • Personal data. Uploaded documents often contain names, addresses and phone numbers. Keeping them forever creates risk with no benefit.

Defenses for a secure file upload form

1. Treat the accept attribute as UX only

The accept attribute narrows the file picker so honest users pick the right file type. It does not stop anyone. A script can post any file to your endpoint without ever loading your page.

html
<input type="file" name="resume" accept=".pdf,.doc,.docx">

Keep it, because it helps real visitors, but never rely on it.

2. Validate on the server

Every check that matters has to happen where the attacker cannot edit the code:

  • Check the file extension against an allowlist, not a blocklist.
  • Inspect the file's actual bytes (its "magic number" signature) rather than trusting the declared MIME type.
  • Reject double extensions such as photo.jpg.php.
  • Generate your own storage filename instead of reusing the one the user sent. Keep the original name only as metadata.
  • Limit the number of files per submission.

3. Enforce an upload size limit

Size limits protect your storage, your bandwidth and your inbox. Enforce them per file and per request, on the server. Platforms and hosting providers usually impose their own request size limits too, so a very large file may be rejected before your code even sees it. Pick a limit that covers legitimate use and nothing more.

4. Store files privately and use signed URLs

Uploaded files should never sit in a public folder. Store them in private object storage or outside your web root, and hand out access through:

  • An authenticated dashboard for the site owner, and
  • Signed URLs that expire, for links you send by email or to other tools.

Signed links mean a forwarded email or a leaked log line does not give permanent access to the file.

5. Prevent inline execution

When serving a file back, send headers that stop the browser from rendering it as part of your site:

  • Content-Disposition: attachment so files download rather than open inline.
  • X-Content-Type-Options: nosniff so the browser does not guess a more dangerous type.
  • Serve uploads from a separate domain or storage host, never from your main application origin.

6. Scan when the risk justifies it

If files will be opened by many people or processed automatically, consider running them through a malware scanner before anyone downloads them. At minimum, open unknown documents with care, keep office software patched, and be suspicious of macro prompts.

7. Set a retention period

Delete files when their purpose is done. A job application form does not need to keep resumes for years. Short retention reduces both storage costs and the damage from any future breach. See our post on GDPR contact forms for more on data minimization.

A correct HTML file upload form

File inputs only work in a plain HTML form when the form uses POST and multipart/form-data. Without the enctype, the browser sends only the filename.

html
<form action="https://formsubmit.app/f/YOUR_FORM_ID"
      method="POST"
      enctype="multipart/form-data">
  <label for="name">Name</label>
  <input id="name" type="text" name="name" required>

  <label for="email">Email</label>
  <input id="email" type="email" name="email" required>

  <label for="resume">Resume (PDF or Word)</label>
  <input id="resume" type="file" name="resume" accept=".pdf,.doc,.docx" required>

  <input type="text" name="_gotcha" tabindex="-1" autocomplete="off"
         style="display:none" aria-hidden="true">

  <button type="submit">Send application</button>
</form>

The hidden _gotcha field is a honeypot that catches simple bots before they can upload anything. For more layers, see how to stop form spam.

Handling large files with direct uploads

Sending a big file through a normal form post means the whole request passes through your server or serverless function, and many hosts cap request bodies at a few megabytes. The common solution is direct uploads:

  1. The browser asks your backend for permission to upload a specific file.
  2. The backend checks the request (size, type, limits) and returns a short-lived upload token.
  3. The browser uploads the file straight to object storage using that token.
  4. The form then submits normally, sending a reference to the stored file instead of the file itself.

This keeps large payloads off your application server while the backend still decides what is allowed. It does require JavaScript, so it is usually reserved for files above the plain-form request limit.

File upload security checklist

CheckWhy it matters
method="POST" and enctype="multipart/form-data"Files are not sent otherwise
accept attribute on the inputBetter UX, not security
Server-side type allowlist and content inspectionStops spoofed extensions and MIME types
Per-file and per-request size limitsPrevents storage and bandwidth abuse
Random storage filenamesAvoids path tricks and overwrites
Private storage, no public folderPrevents leaks and indexing
Signed, expiring download linksLimits damage from forwarded links
Content-Disposition: attachment and nosniffStops inline rendering and execution
Spam protection before uploadKeeps bots from filling storage
Retention policyMinimizes stored personal data

Using a form backend instead of building it

You can build all of this yourself, but it means writing validation, configuring storage, generating signed URLs and running cleanup jobs. A form backend handles the storage side for you. With FormSubmit, file uploads are stored privately, deleting a submission deletes its files, and per-form retention can purge old submissions automatically. You still choose what to accept and who sees it.

If you want a head start, the file upload form template generates the HTML above with your fields, and the pricing page lists the file size and storage limits for each plan.

Last updated .

Frequently asked questions

Is the HTML accept attribute enough to secure a file upload form?

No. The accept attribute only filters the file picker for convenience. Anyone can bypass it, so the server must check file type, size and content on its own.

What is a reasonable upload size limit for a website form?

Set the smallest limit that covers real use. Resumes and documents rarely need more than a few megabytes; photos and design files may need 10 MB or more. Enforce the limit on the server, not just in the browser.

Should uploaded files be stored in a public folder?

No. Store uploads privately and give access through authenticated downloads or short-lived signed links, so a guessed or leaked URL does not expose personal data.

How long should I keep files uploaded through a form?

Only as long as you need them. Set a retention period that matches the purpose, such as deleting job applications after the hiring process ends.

Related resources

Keep reading

Your form backend is 60 seconds away

Sign up with Google or email, create a form, paste the endpoint. Free forever for small sites — no credit card.