The Hacker News ran the story on September 15: a mass-scanning campaign is pulling AWS and Azure credentials out of exposed Vite dev servers. The bug is CVE-2026-39364. Vite published it on April 6 and shipped the fix the same day. Five months later the exploitation curve is going up, not down.

My first reaction was to check my own machine, and that turned out to be the more interesting half of the story.

Four Advisories in a Day

April 6 was a bad day for Vite’s dev server. Three advisories landed together, and a fourth followed on June 1.

  • CVE-2026-39364, the query bypass. The access check ran against the full URL, query string included. So /@fs/.env got a 403, and /@fs/.env?raw got a 200. Affects 7.1.0 to 7.3.1 and 8.0.0 to 8.0.4. Fixed in 7.3.2 and 8.0.5.
  • CVE-2026-39363, the WebSocket read. The HMR socket exposed a fetchModule call that skipped the server.fs checks entirely. Connect without an Origin header, ask for a file:// URL with ?raw, and you get the file back as a JavaScript string. Affects 6.0.0 onwards. Same fix versions.
  • CVE-2026-39365, source maps for optimized deps. Path traversal through .map requests. Moderate. Same fix versions.
  • CVE-2026-53571, Windows alternate paths. /.env::$DATA?raw and 8.3 short names got past the deny list on NTFS. Fixed in 6.4.3, 7.3.5 and 8.0.16.

Every one of them carries the same clause: only apps that expose the server with --host or server.host are affected. That clause is true. It is also the part of the advisory doing the most work, and it deserves a closer look.

The Wordlist Knows Where You Are

F5 Labs published the telemetry. In the three months before August, its sensors saw 1,732 events. In August alone: 807 grouped attacks and about 32,000 raw events. The traffic comes mostly from Google Cloud ranges, the User-Agent strings claim to be Googlebot, ClaudeBot, GPTBot, PerplexityBot and Amazonbot, and the X-Forwarded-For headers are forged.

The requests look like this:

GET /@fs/.env?raw??
GET /@fs/..%252f..%252f..%252f..%252froot/.env?raw??
GET /@fs/..%252f..%252f..%252f..%252fproc/self/environ?raw??

Then the wordlist. It asks for .env and its .local, .production and .staging variants. It asks for .aws/credentials under /root, /home/ec2-user, /home/ubuntu, /home/node, /usr/src/app and /app. It asks for terraform.tfstate, serverless.yml, .azure/accessTokens.json, /etc/passwd and /proc/1/environ.

Read those paths as a description of the victim. /home/node is the default user in the official Node Docker image. /usr/src/app and /app are the two most-copied WORKDIR lines on the internet. /home/ec2-user is an AWS VM. /proc/1/environ only pays off when PID 1 is your process, which means a container. Nobody is scanning for laptops.

The scanner’s focus on cloud credentials, IaC states, and process memory files indicates threat actors prioritize rapid access to cloud provider infrastructure over application-level compromise.

— F5 Labs, September 2026

That is the reframe. The --host clause reads as reassurance: the default is localhost, so most people are safe. But --host is not a choice people make carelessly. It is the flag you must set the moment the dev server runs anywhere but your own machine, because a container’s localhost is unreachable from outside it. Every Docker dev setup, every cloud dev box, every agent sandbox that hands you a preview URL has set it. The advisory’s exception is the deployment pattern of the decade.

Auditing My Own Machine

One command finds every installed copy:

find ~/Projects -path '*/node_modules/vite/package.json' \
  -exec grep -H '"version"' {} +

The results, across everything I have cloned:

  • 47 repos pin Vite in a lockfile.
  • 28 pin a version with at least one 2026 CVE. The most common stale pins were 7.3.1 and 6.4.1, both one patch release short.
  • 10 have that version installed in node_modules, ready to run. Four of those are checkouts of the same project.
  • 0 dev servers were listening when I looked, and none of the stale repos passes --host in its dev script.
  • 6 repos deliberately reach past localhost through ngrok, Tailscale or a custom domain for remote work. All six were already on patched versions.

So the honest answer is: not exposed, by default and by luck rather than by process. Two things in the audit bothered me anyway.

The tunnel setting I forgot to revert

One personal project had server.allowedHosts: true in its Vite config. I set it months ago to test through a tunnel and never removed it. That setting disables Vite’s Host header check, which is the defence against DNS rebinding: a malicious page in your browser resolves its own domain to 127.0.0.1 and talks to your localhost dev server. With a patched Vite that gets you nothing. With the 7.3.1 that repo was pinned to, it gets you ?raw on every file the dev server can see, without --host ever being set. The advisory’s exception did not cover that case. My config did.

The second is Vitest. Several repos had Vite patched at the top level and a second, older Vite nested under node_modules/vitest. Vitest runs its own Vite server, and a bun update vite does not touch it.

What This Doesn’t Settle

  • Vite’s defaults are right. Localhost bind, a deny list that covers .env and certificates, and a Host allowlist that ships on. The bugs were in the enforcement, and the team fixed them the day they published.
  • F5 sees its own customers, not the internet. 32,000 events is the view from one vendor’s sensors. The real number is larger and unknown.
  • Only the query bypass has a public campaign. The WebSocket bug is arguably worse, since it ignores server.fs entirely, but nobody has published exploitation numbers for it.
  • Lockfile counts overstate risk. A stale pin in a side project with no node_modules cannot serve anything. The ten installed copies are the number that matters, and the one with allowedHosts: true is the number that matters most.

The Takeaway

  • Read the wordlist, not the CVSS. The attacker’s file paths tell you who they expect to hit. These expect containers with cloud credentials mounted next to the source.
  • The “only with —host” clause describes the target, not the exception. Every remote dev environment sets it. If your agent sandbox or dev container gives you a preview URL, assume it is set.
  • Audit config, not just versions. allowedHosts: true and host: 0.0.0.0 are one-line changes made for a tunnel one afternoon. They outlive the afternoon.
  • Check nested copies. Vitest, Astro and the framework plugins carry their own Vite. Patch the pin at the top and you may have patched nothing.
  • Then rotate. F5’s advice for anyone who ran an unpatched, exposed server is not “update”. It is “update, then rotate every secret the server could read”. The scanners had five months.