How to test file upload validation
File upload is one of the highest-risk surfaces in most applications: it accepts arbitrary bytes from outside, and it usually hands them to a parser, a converter or a storage layer that was never written defensively.
This is the checklist worth working through, ordered so that the cases most likely to find something come first. Every case below can be produced on this site in a few seconds.
1. Size boundaries, not size guesses
If the documented limit is 10 MB, the interesting files are 10 MB exactly, one byte under, and one byte over. Off-by-one errors in limit checks are common and invisible to a test that uploads a 3 MB file and a 40 MB file.
Exact sizes are the hard part of this test to arrange by hand, which is why this generator produces a file at precisely the byte count you name rather than approximately.
- Exactly at the limit, must be accepted.
- One byte over, must be rejected, with a message naming the limit.
- Far over the limit, must be rejected quickly, ideally without buffering the whole upload first.
- Zero bytes, must be rejected or handled as empty, never crash.
2. Type checks: extension, MIME and content disagree
Three separate things claim to identify an uploaded file: its extension, the Content-Type the browser reports, and the bytes themselves. An attacker controls the first two. Only the third is evidence.
Test each disagreement independently: a valid PNG named .pdf, a valid PDF named .png, and a file whose reported MIME type matches neither. A validator that trusts the extension will accept things it should not; one that trusts only the magic bytes may reject legitimate files whose type it does not recognize.
3. Hostile filenames
More upload failures come from the name than from the bytes. Names travel through your web server, your application, your database column, your storage backend and eventually someone's filesystem, and each of those has different rules.
Worth trying: spaces and punctuation, a 255-character name, non-ASCII characters and emoji, a leading dot, several extensions in a row, and a Windows reserved device name such as CON. This site can attach any of these to a generated file so you can send them through your own stack.
4. Broken content that passes the front door
Once a file is accepted, something usually parses it. That parser is where the interesting failures live, so send files that are the right type and size but wrong inside: corrupted headers, invalid structure, and truncated uploads.
The truncated case is the one to insist on, because it is what a real interrupted upload produces and because it is where partially-committed state comes from.
5. Volume and repetition
Finally, the cases that only appear at scale: many files at once, the same filename twice, two uploads racing for the same name, and a large batch of mixed formats. The bulk download here produces a directory of many formats in one ZIP, which makes a realistic fixture set for an importer.
What to assert throughout
- Rejections are explicit and specific, not a generic 500.
- Nothing partial persists after a rejected upload, no stored file, no database row, no queue message.
- The original filename is never used directly as a filesystem path.
- Errors shown to users contain no paths, stack traces or internal identifiers.
- Limits are enforced on the server, and the client-side check is treated as a convenience rather than a control.
Common questions
What file size should I use to test an upload limit?
Three: exactly the limit, one byte under, and one byte over. Off-by-one mistakes in limit comparisons are common, and only an exact-size file can find them.
Is checking the file extension enough?
No. The extension and the browser-reported MIME type are both supplied by the client and can be anything. Only the file's own bytes are evidence of its type, so validate content and treat the other two as hints.
How do I test an interrupted upload?
Use a truncated file, a genuine prefix of a valid one. It reproduces what a dropped connection delivers, and it is the case most likely to leave partially-processed data behind.
Formats mentioned here: PDF test files · DOCX test files · XLSX test files · PNG test files · ZIP test files · CSV test files
More guides
How to create a very large test file · How to create an invalid JSON file for testing · How to make a corrupted file for testing · Filename test cases that break real systems · Encoding test files: UTF-16, BOM and Latin-1