Synchronous vs asynchronous file scanning

Hold the request until you know, or accept it now and find out shortly.

By Ihor Havrysh ยท Last reviewed July 2026

Eaglepedia mascot

Synchronous scanning holds the user's request open while an uploaded file is checked, returning the verdict with the response. Asynchronous scanning accepts the file immediately and checks it in the background, updating its status afterwards. The choice decides where latency, complexity and risk sit in the upload.

The two shapes

Synchronous is the shape most people build first, and it is a single line of reasoning. The file arrives, your code sends it to be checked, waits, and responds according to the answer. Accepted files are stored, rejected files never were.

Its great virtue is that there is no gap. At no point does an unchecked file exist anywhere your application would serve it from, because nothing is stored until the verdict comes back. That property is free rather than engineered, and free properties are worth a lot.

Asynchronous separates acceptance from verification. The file is taken, put somewhere holding, and the user gets an immediate response saying it arrived. Scanning happens on a worker or in response to a storage event, and when the verdict lands the file's status changes: released for use, or rejected with the user informed.

This is how the major cloud providers structure malware scanning for object storage: AWS triggers a scan on upload to a bucket, and Google Cloud publishes the same pattern as a reference architecture. A file lands in a bucket, the write triggers a scan, and the result moves the object or tags it. If your uploads already go to storage before your application sees them, this is the grain of the system rather than a choice you are imposing on it.

Synchronous scanning holding the request open, against asynchronous scanning with a quarantine, scan and release path
The asynchronous shape buys back the wait and pays for it with a window in which an unverified file exists somewhere.

What you are actually trading

Synchronous Asynchronous
User waits Yes, for the whole check No, only for the upload
Unverified file exists Never stored Yes, until the verdict lands
Complexity One path, one verdict States, queues, notifications, retries
Large files Poor, connections held open Good, decoupled from the request
Telling the user it failed In the response Needs a channel that may not exist

The row that catches teams out is the last one. In a synchronous design, rejecting a file is trivial, because the user is still there. In an asynchronous design they may have closed the tab, and you now need somewhere to put the news: a notification, an email, a status that is visible next time they look. Applications frequently build the asynchronous pipeline and discover the feedback problem afterwards.

The second row is the one that matters for security, and it is the reason an asynchronous design has to be built carefully rather than merely built.

The rule that makes asynchronous safe

There is really only one, and everything else follows from it: an unverified file must not be reachable.

Concretely, that means the file lands in a quarantine location that nothing user-facing reads from. Not your public bucket with a status column set to pending, because something will eventually read that bucket without checking the column. A separate location, with the move to the served location being the thing that marks it clean.

Two related habits reinforce it. Do not return a usable URL at upload time, since a URL that works immediately is precisely the window an attacker wants. And make the released state the only one your serving code recognises, so that a file which never completed scanning is invisible by default rather than by an explicit check somebody might omit.

That last point is the difference between a design that is safe and one that is currently safe. If serving requires proof of clearance, a bug in the scanning pipeline fails towards nothing being served. If serving merely avoids files marked bad, the same bug fails towards everything being served.

You also need to decide what happens when the scan never completes at all, which is the fail-open or fail-closed question. An asynchronous design makes the better answer available, because a file can simply stay in quarantine until the backlog clears, rather than being accepted or refused in the moment.

Choosing, and choosing both

Four questions get you most of the way:

  • How big are the files, honestly? Not the limit in your configuration, the sizes users actually send. If almost everything is a few megabytes, synchronous is comfortable
  • What does the user do next? If the following screen depends on the file being accepted, waiting is better than a pending state that complicates the whole flow
  • Where does the file land first? If uploads go directly to object storage, asynchronous already fits the architecture
  • Do you have a way to tell them later? If not, that has to be built before an asynchronous rejection is a usable outcome

And the answer for many applications is both. Handle small files synchronously so the common case stays immediate and simple, and route above a size threshold, or when a batch arrives, to the asynchronous path. Two code paths is a genuine cost, and it usually beats making every user wait for the worst case or putting every upload through a pending state it did not need.

Our guide to file upload security covers how this fits with validation, storage and the rest of the pipeline.

Pick the shape that suits the upload, rather than the one your provider supports. The Red Eagle Tech CDR API offers both synchronous and asynchronous endpoints, so small files can be handled inline and larger ones queued, without running two suppliers. Published per-document pricing, OAuth2, and you can be running in minutes.

Frequently asked questions

Neither, inherently. What matters is whether a file can be reached before it has been checked. A synchronous design gets that property for free, because nothing is stored until the verdict is back. An asynchronous design has to enforce it deliberately, by holding the file somewhere nothing else can read from until scanning completes. Done properly they are equivalent; done carelessly the asynchronous one leaks.

When the user needs an answer straight away and the files are small enough that they can have one. Profile pictures, document attachments in a form, anything where the next screen depends on the file being accepted. It is also much simpler: one request, one verdict, no state to track and no second code path to build.

When waiting is not viable. Large files, batch uploads, or a workload where holding connections open would exhaust your server's capacity. It is also the natural fit when uploads land in object storage first, because the scan is then triggered by the storage event rather than by your application, which is how the major cloud providers structure their own malware scanning for buckets.

Making the file reachable before the verdict arrives. If the upload returns a URL that works immediately, you have built a window in which unverified content is being served, and that window is exactly when an attacker will fetch it. The file needs to be in a location nothing user-facing can read from until it has been cleared.

Yes, and plenty of applications should. Scan small files synchronously so the common case stays simple and immediate, and fall back to the asynchronous path above a size threshold or when a batch arrives. It costs you two code paths, and it usually gives users a better experience than forcing everything through whichever single model you picked.
Ihor Havrysh - Software Engineer at Red Eagle Tech

About the author

Ihor Havrysh

Software Engineer

Software Engineer at Red Eagle Tech with expertise in cybersecurity, Power BI, and modern software architecture. I specialise in building secure, scalable solutions and helping businesses navigate complex technical challenges with practical, actionable insights.

Read more about Ihor

Discovery call

A friendly 15-minute video call with Kat to understand your needs. No preparation needed.

  • Discuss your project
  • Get honest advice
  • No obligation
Kat Korson, Founder of Red Eagle Tech

Kat Korson

Founder & Technical Director

Our team has 10+ years delivering software solutions for growing businesses across the UK.

Send us a message

Your information is secure. See our privacy policy.

Find us