Table of contents of the article:
Over the past few months, while optimizing web performance for Managed Server SRL clients , we encountered some unusual behavior that initially puzzled us. We've been using HTTP/3 with the QUIC protocol and ZSTD (Zstandard) compression for over two years, with excellent results in terms of connection speed, efficiency, and stability. Throughout this time, the implementations have always worked flawlessly: browsers negotiated HTTP/3 correctly, ZSTD compression was enabled for HTML, CSS, and JavaScript, and site performance was in line with expectations.
But suddenly, something changed. During some routine testing, we began to notice that connections that had previously been handled correctly via HTTP/3 were now almost always falling back to HTTP/2 , while text resources we'd configured to be compressed in ZSTD were suddenly being served with Brotli or even gzip . It was as if, overnight, our optimizations were gone.
This situation was both unusual and frustrating. Considering that our stack had been configured in a stable and functional manner for years, it didn't make sense for it to suddenly behave differently. This led to a rather in-depth technical investigation to understand what was happening.
The Initial Investigation: Suspicions About NGINX
The first step was the most natural one for those who work in infrastructure and web performance: verify the behavior of our NGINX web server . Logic suggested that a recent update or some change to the compilation flags might have changed the way the server handled QUIC and ZSTD. We analyzed the configurations in detail, verified the loaded modules, and even double-checked the compatibility of the versions in use.
To eliminate any doubt, we also created a completely clean test environment, installing NGINX from scratch with our minimal necessary settings, without any customization. The idea was simple: eliminate any possible external interference and observe the protocol and compression behavior in an isolated context.
The result, however, was surprising. Even on a clean, minimal installation, HTTP/3 wasn't negotiated , and ZSTD was still not being used . At that point, it was clear that the problem wasn't related to NGINX, nor to our server configurations.
The Red Herring: Network and MTU Issues
Having ruled out the possibility that our web server was the cause, we began to look elsewhere. Since HTTP/3 relies on the QUIC protocol , which uses UDP instead of TCP , we hypothesized that the issue might be related to some network parameter. In particular, we suspected that the MTU (Maximum Transmission Unit) might be affecting protocol negotiation.
We tested several configurations: first the default value of 1500 bytes, then more conservative settings, such as 1400 and even 1300 bytes, to see if smaller packets would facilitate the transition to QUIC. Even in this case, however, the results remained unchanged: the connection continued to fall back to HTTP/2, and compression remained stuck on Brotli or gzip.
It was clear that the problem was neither with our stack nor with the network. But the strangest thing was that, comparing historical logs, we discovered that negotiations had been working perfectly until a few weeks earlier. From that point, we began to suspect that something external to our infrastructure was influencing the connection behavior.
The discovery: even the big ones have the same problem
To understand whether the phenomenon was limited to our servers or had a broader scope, we decided to run tests on the websites of large international corporations . We analyzed the behavior of giants like Amazon, Google, Microsoft , and even some prominent newspapers. The discovery was surprising: even on those platforms, connections were almost never negotiated in HTTP/3 and ZSTD was not used.
This allowed us to definitively rule out the server-side problem. If large companies with multi-million dollar infrastructure, dedicated engineering teams, and advanced optimization processes were unable to properly negotiate HTTP/3 and ZSTD, it was clear that the cause had to be on the client side.
The decisive insight: the suspicion about the antivirus
When you eliminate everything under your control, you start to look at the components you usually take for granted. In this case, the focus shifted to locally installed software. We knew that ESET NOD32 Antivirus was present on the test systems.
To analyze HTTPS traffic, modern antivirus programs employ a strategy unfamiliar to many users: they set up a local proxy that intercepts all browser connections, analyzes their content, and only then forwards them to the remote server. In other words, the browser never communicates directly with the site, but with an intermediary that can modify, filter, or reinterpret the connection.
If this proxy doesn't support the latest versions of the protocols or compression algorithms, the browser is forced to automatically fallback to older, compatible technologies. This is why connections suddenly dropped to HTTP/2 and compression reverted to using Brotli or gzip : it wasn't the server's fault, but rather client-side interference.
Confirmation: Uninstall your antivirus
To confirm this hypothesis, we decided to perform a drastic experiment. We removed ESET NOD32 Antivirus from the test systems, rebooted the machines, and repeated the tests. The results were immediate: browsers began negotiating HTTP/3 / QUIC correctly again, and ZSTD compression returned to working exactly as it had before.
After weeks of testing, exclusions, and verification, we finally found the cause. The antivirus, with its local proxy, was interfering with connection negotiation and preventing the optimizations we had implemented long ago.
Why it happens and why it's not just about ESET
What we found wasn't an isolated bug, but a direct consequence of how modern Windows antivirus programs work. Many of them, not just ESET, use the same interception strategy via a local HTTPS proxy. This means that software like Avast, Kaspersky, Bitdefender, McAfee , and many others could cause the exact same behavior.
Whenever an antivirus program comes between the browser and the network, it takes control of the connection and partially manages its features. If the proxy isn't updated to support modern protocols like HTTP/3 or more efficient compression like ZSTD , the browser is forced to negotiate legacy protocols. This results in poorer performance, slower loading times, and, in our case, the failure of the optimizations designed for our customers.
Conclusions
This experience taught us an important lesson. When we encountered missing HTTP/3 connections and inactive ZSTD compression , our first reaction was to think the problem was ours: a misconfiguration, an untested update, an incorrect parameter. The reality, however, was completely different.
Our stack was configured correctly and had been working for years. The real cause was external software, which was acting silently, altering the browser's behavior without it being immediately apparent. In our specific case, the culprit was ESET NOD32 , but the same dynamic can occur with many other antivirus programs.
The next time you find yourself debugging features like HTTP/3 , QUIC , or ZSTD , before questioning servers, CDNs, proxies, and configurations, ask yourself whether an antivirus program is interfering with protocol negotiation. Sometimes, the solution is much simpler than it seems: simply identifying the real culprit can save hours of wasted analysis.
mbri: just identify the real culprit to save hours of useless analysis.