All posts

February 10, 2026 · 4 min read

The Checklist for Any Feature That Lets Someone Upload a File

File uploads show up in almost every app eventually: a profile picture, a resume, a receipt, an attachment on a support ticket. It's also one of the features I see built fastest and checked least, because the happy path, someone uploads a normal image and it shows up correctly, works on the first try almost every time, which makes it feel done.

What actually needs checking

What kind of file is this, really

Checking a file's extension, confirming it ends in .jpg, tells you almost nothing. A file's actual content can be completely different from what its name claims. A properly built upload handler checks the file's real content type, not just its extension, and rejects anything that doesn't match what the feature is supposed to accept.

How big is too big

Without an explicit size limit, nothing stops someone from uploading an enormous file, repeatedly, either to run up your storage costs or to simply take your upload endpoint down by overwhelming it. A sensible size cap, checked server-side and not just suggested in the frontend, is a five-minute fix that closes an easy door.

Where does the filename actually go

If your app uses any part of the uploaded filename to decide where to save the file, check what happens if that filename contains something like a path meant to escape the intended folder. This is an old, well-documented class of bug, and it's exactly the kind of thing that's easy to miss when a feature was scaffolded quickly, because a normal filename never reveals the problem.

Can an uploaded file execute as code

If uploaded files ever get served back out from the same domain as the rest of your app, check whether someone could upload a file crafted to run as a script when opened, rather than being treated as a plain, inert document. Serving uploads from a separate domain or subdomain with no execution permissions closes this off cleanly.

Who can actually see an uploaded file afterward

This is the same question that shows up everywhere else on this blog, just applied to storage instead of a database. If uploads land in cloud storage, confirm the bucket isn't publicly listable, and that reading a specific file actually requires the right permission rather than just an unguessable-feeling URL. An URL that's hard to guess is not the same thing as a URL that's actually protected.

The five-minute version

  • Check real file content, not just the extension.
  • Enforce a size limit on the server, not just in the upload widget.
  • Never use a raw, user-supplied filename to build a file path.
  • Serve uploaded files from a location that can't execute them as code.
  • Confirm storage permissions actually restrict who can read a file, not just who can guess its URL.

None of this is exotic, and none of it requires a security background to check for yourself. It requires treating a file upload as its own small feature with its own small checklist, rather than a solved problem the moment the demo upload works.

Related reading

Harbova is a security service for apps built with AI tools. Start with a free scan, and if it finds something serious, we can fix it and prove it is closed.