Skip to content

From screenshots to full sessions

Start your free trial with WonderProxy today—then use these resources to guide you through every step of the process.

Request free trial How does WonderProxy work?

How to test file uploads

Start testing today.
For free.

Start for free

File uploads look like one of the easiest things to test. It’s as simple as selecting a file. Click upload. Check whether it appears. Move on. Simple right? Maybe not. 

I think file uploads are one of those features where the obvious test is usually the least interesting. That’s because an upload isn’t just a single action. It’s a flow. Before a file appears in the application, it goes through validation. It has to be stored somewhere. Maybe it has to be processed, scanned, or sent to some other service. The application has to decide permissions for who can access it. Or maybe what happens if it fails halfway through. If it’s a multiple-user platform letting multiple users access a file, concurrency might become a problem too.

So when you’re testing a file upload, you’re not just testing whether a file can be uploaded. You test how the application deals with the file.

That’s why the easiest way I have found to test file uploads is to follow the file through the application and keep asking questions about what could go wrong.

Start with what the application says it supports

First, do exactly what a normal user would do. If the application says it accepts JPG, PNG and PDF uploads, upload one of each. Initially, I just want to know whether the application actually enforces what it claims to support. Start creating a few tests around this. 

  • Check whether the upload succeeds
  • Whether the correct file appears afterwards
  • Whether you can actually open or download it.

Then start testing the boundaries.

  • If the maximum file size is 10MB, don’t just upload a 5MB file. Try something just below 10MB, exactly 10MB and just above it.
  • Do the same with file types. Try an unsupported file. Try a file without an extension. Try capitalising the extension. If photo.jpg works, what happens with photo.JPG?
  • If the browser prevents me from selecting a particular file, will the backend also reject it?

At this point, you’re mostly checking whether the application behaves according to its own rules. Then next comes the interesting part. Working through all the rules and variations that are not immediately obvious.

Where are those rules actually being enforced?

If the browser prevents me from selecting a particular file, is the backend also going to reject it?

A client-side restriction is useful for the user experience, but it shouldn’t be the thing protecting the server. So instead of only using the file picker, intercept the upload request and see what happens when you change what the browser sends.

Now you’ve moved from testing the UI to testing the actual application. Here you start to mimic the developer who built it to find the loopholes. And this is my favourite part.

What does the application think the file is?

Suppose the application only accepts images. How does it know that something is an image? It might look at the extension. It might look at the Content-Type sent with the request. It might inspect the actual contents of the file, or it might do some combination of these.

That’s worth testing. Take a file that isn’t actually an image and see what happens when you give it an image extension. Try changing the Content-Type in the request. If the application accepts whatever the client tells it, you’ve found a validation weakness.

This is why I won’t just “try random extensions”. The better question would be:

What does the application trust when deciding whether to accept my file?

Once you ask that, the tests become much easier to come up with. Rather than random, be specific about what extensions and why. 

Now try to break the normal flow

Let’s start thinking about how a real user can accidentally interrupt the flow. 

What if:

  • The same file is uploaded twice, or even five times?
  • Select ten files at once?
  • Start uploading a large file and close the browser?
  • The network disappears halfway through?
  • The connection is extremely slow?
  • The upload is cancelled and immediately started again?
  • The page is refreshed while the upload is still running?

These tests are less about the file itself and more about the state of the application, because testing is not just about success. It is also about the experience it develops. For example, imagine the upload request reaches the server, and the server starts storing the file. Then the user’s internet connection disappears before the browser receives the response.

What does the application think happened? The user might see “upload failed”. But the file might actually be sitting in storage, and the user retries. You could end up having 2 files even if the first one is usable. Here, there are 2 problems. Unwanted storage and a user without the correct information. Because the message "upload failed" isn’t fully accurate, users don’t know what to do next. They guess. So now I’m not only testing whether the upload failed. I’m testing whether the application knows that it failed. Because of that, notifications also become part of your testing. 

Follow what happens after the upload succeeds

A successful upload response doesn’t necessarily mean you are done testing. See what happens next.

  • Maybe the application stores the file in the cloud.
  • Maybe it creates a database record
  • Maybe it generates a thumbnail
  • Maybe it scans the file
  • Maybe it sends it to another service
  • Or maybe a background worker processes it.

Every one of these steps gives you another place where things can go wrong. Imagine these areas. 

Upload > Storage > Database > Image processing > Thumbnail > Display 

Now start to break it down. Ask yourself.

  • What happens if the file is successfully stored but the database update fails?
  • What happens if the database record exists but the file doesn't?
  • What happens if thumbnail generation fails?
  • Does the original file remain?
  • Does the user see an error?
  • Does the application retry the processing?
  • Does it create duplicate thumbnails?
  • Does a failed upload leave files behind that nobody can ever access?

This is where understanding the application architecture starts helping you test file upload better. You don’t need to know every implementation detail before testing. But once you discover that an uploaded file goes through a flow, that whole flow becomes part of your test scope.

What if the file is corrupted?

A file can have the right extension and still be broken. Try uploading a file like that and see when the application notices it. Immediately after uploading, later or never? This would also raise other questions, such as. 

  • “Does the upload succeed but the preview fail?” 
  • “Does a background job fail later?” 
  • “Does the application return a useful error?”  
  • “Does something completely unrelated break?” 

This distinction matters because many applications don’t actually inspect the file during upload. They store it first and process it later. So you might get a successful upload response for a file that causes problems five seconds later, and you have ended up using many resources for it. Once during testing, I uploaded a corrupted image file. The application accepted and stored it successfully, then showed me “Uploaded successfully”. But when it later tried to generate a thumbnail so the image could be displayed, it showed me a generic thumbnail image because the file was corrupt.

Now the upload technically succeeded, but the file can't be used properly. The application has already spent storage and processing resources on it, only to discover later that image can’t be displayed.

What happens when users delete things?

Most upload features also allow users to replace or delete files. This would give you a completely different flow to test. Upload a file, view it, download it, replace it and delete it. Then see what “delete” actually means. Is it the physical file deleted, or is a database record deleted? Can the old URL still be accessed? You can also see what happens if you delete a file while it is being processed. You can also try replacing a file while another request is downloading it.

The point isn't to come up with increasingly weird actions for the sake of it. You're trying to understand whether the application keeps all of its different representations of the file in sync.

Now think about other users

So far, we've been testing whether the person who uploaded the file can use it. But what about everyone else? Create two users. User A uploads a file. Now use User B to see whether you can access it. Don't only check the UI. Look at the actual URLs and API requests involved. 

Can User B view the file? Download it? Delete it? Replace it? Access the API endpoint directly? Guess another file's URL? What happens if User A loses permission to the record after uploading the file?

This is where an upload test turns into testing authorization. Consider the following. 

  • An application may carefully validate whether someone has permission to upload a file, but might miss that the same checks are needed when that file is retrieved later.
  • The user may not be allowed to upload a file to someone else's record, but can they access another user's file once they know the URL? 
  • The risk is that upload permissions are validated, while retrieval and access permissions are treated as a separate problem and missed completely

Now start questioning the security assumptions

At this point, you've learned quite a lot about the application's upload flow. You know what it accepts, how it validates files, where the file goes, how it gets processed, how it is retrieved and deleted. Now you have enough context to start looking for security problems.

Instead of blindly trying a collection of “malicious files,” ask what assumption the application is making.

  • Does it trust the filename?
  • Does it trust the extension?
  • Does it trust the content type?
  • Does it assume an uploaded file is safe because it has passed validation?
  • Does it store files somewhere they can be executed?
  • Does it serve user-uploaded content from the application's own domain?
  • Does it allow uploaded content to be rendered in the browser?
  • Does it serve user-uploaded content from the application's own domain
  • Does it let one user access another user's files?
  • Does it allow uploaded files to overwrite existing files?
  • Does processing an uploaded file consume an unreasonable amount of CPU, memory, or storage?

The answers tell you what to test next. Once, while I was doing a file-upload check somewhere (legally, btw), I was able to achieve remote code execution and control their server without accessing it. You can read about that in a post called  How I hacked 3 websites in 15 mins, but we’re not diving into that here. 

For example, 

  • If the application lets users upload HTML and then serves those files directly from its own domain, I would want to understand whether the browser renders that content and whether it can execute in the application's origin.
  • If the application accepts ZIP files and extracts them, I would want to understand what happens when the archive expands into a much larger amount of data.
  • If the application uses an image-processing library, I would want to know what happens when that library receives a malformed or unusual image.

The important part is that you're not randomly throwing files at the application anymore. You're testing an assumption you've discovered.

Don't forget the boring limits

Security testing can be interesting, but some of the most useful upload bugs are still boring.

  • What happens when a user uploads 1,000 files?
  • What happens when the total storage limit is reached?
  • What happens when a single file is huge?
  • What happens when the filename is extremely long?
  • What happens when thousands of tiny files are uploaded?
  • Does the application calculate storage usage correctly?
  • Does deleting a file free the quota?
  • Can users bypass the quota by uploading files concurrently?
  • Can repeated failed uploads consume storage?

These are especially interesting when the application has limits. You might not need to test everything, but just those that fit. A limit that works perfectly for one request may completely fail when several requests happen at the same time.

And then there are race conditions

This is where I have seen the most bugs. Once you've understood the basic flow, try doing two things at once.

  • Upload the same file twice.
  • Upload and delete the file at the same time.
  • Replace a file while it is being processed.
  • Start multiple uploads for the same record.
  • Try two users modifying the same file simultaneously.

You're looking for assumptions like, “This will always happen before that.” Real applications don't always get that luxury. Two requests can arrive at almost exactly the same time, and if the backend isn't prepared for that, you can get duplicate records, incorrect permissions, orphaned files, overwritten files, or inconsistent states.

The question I keep coming back to

When I am testing a file upload, I don’t really think, “What file should I upload?” I think, 

“What does the application know about the file?”

I challenge the system's understanding when testing. This is where file upload testing gets interesting. That's why I haven’t shared a checklist, but an approach. You won't always need to test all of them. The application, its architecture, and its users will tell you what to look at next.

The upload button is just the beginning. The real feature is everything the application does with the file after you hand it over.

One of my colleagues told me something early in my testing career that has stuck with me.  

“When you have to choose between a user and a developer, never choose the developer.”

The developer already knows how the feature is supposed to work. Your job as a tester is to find out how it actually works. 

Share article

Hanisha Arora

Sep 9, 2026 9 min read

Test your website from real IP locations.

Start for free

The newsletter for localization testing

Get testing resources, tips, and inspiring stories in your inbox.

See our privacy policy for how we use your data. Your information is shared with our marketing email platform Mailchimp, view their privacy policy for details.

Test your production site the way your infrastructure sees it.

Stop guessing based on browser settings. Start validating behavior from real in-country IP addresses.