Your Vite Dev Server Is Not a Security Boundary
A mass-scanning campaign is probing exposed Vite dev servers via CVE-2026-39364 for .env files, cloud credentials and Terraform state. Here's what I'd check across a team's repos and hosts.
Umut Korkmaz
Published: 4 min read
On this page6
On September 11, F5 Labs published a report on a mass-scanning campaign aimed at exposed Vite development servers. The scanners probe for CVE-2026-39364, a server.fs.deny bypass disclosed in April, and go after .env files, AWS and Azure credentials and Terraform state on machines that were never supposed to face the internet. The bug is not what worries me here. The habit it depends on does: someone runs vite --host on a cloud VM or in a container because it was the quickest option that afternoon.
What the flaw does
According to the GitHub advisory, the Vite dev server keeps a server.fs.deny list that should block files like .env and *.crt. On affected versions, a direct request for a denied file correctly gets a 403. If you append ?raw, ?import&raw or ?import&url&inline, you get the file back with a 200. GitHub classifies it as CWE-180: validate before canonicalize.
- Affected: 7.1.0 through 7.3.1, and 8.0.0 through 8.0.4
- Fixed: 7.3.2 and 8.0.5
- Severity: High. GitHub scores it 8.2 under CVSS 4.0 and F5 lists 7.5. No authentication is needed.
The preconditions matter. The dev server has to be exposed to the network with --host or server.host, and the file has to sit inside server.fs.allow while matching a deny pattern. By default Vite binds to localhost, so exploiting this only works where a person already chose to expose the dev server.
What F5 actually saw
F5 Labs' write-up counts roughly 32,000 raw events, grouped into 807 attack sessions, in August 2026. The previous three months had 1,732. F5 reports attempts, not confirmed thefts. A few details stood out:
- Requests go through
/@fs/and use trailing??delimiters and double-encoded%252ftraversal to climb well outside the project root. - The target list is basically a cloud-takeover checklist:
.envvariants for every stage,.aws/credentialsunder/root,/home/ubuntu,/home/ec2-user,/home/node,/appand more,.aws/sso/cache/, AzureaccessTokens.json,terraform.tfstate,terraform.tfvars,serverless.yml, and/proc/self/environ. - User-agents pretended to be Googlebot, ClaudeBot, GPTBot, PerplexityBot, OAI-SearchBot and Amazonbot, alongside forged
X-Forwarded-ForandX-Real-IPheaders. - The top source ranges were Google Cloud Platform addresses. By volume, the US led, followed by Belgium and the Netherlands.
I'd pay the most attention to /proc/self/environ. In a container, environment variables are often where the real secrets end up, put there on purpose to keep them out of files. A file-read bug turns that good practice against you.
"It's just the dev server"
F5 names --host, server.host and misconfigured Docker port mappings, and tells teams to audit Kubernetes ingress rules and cloud security groups too. None of these are unusual. They're the normal shortcuts a team takes so a teammate, a QA tester or a phone can reach the dev build.
A dev server is built to be fast and helpful. It serves source, transforms files on request and exposes a filesystem endpoint. On a laptop, those are features. On a public IP, they are attack surface. F5's report also lists three earlier Vite file-access bypasses from 2024 and 2025. That track record is why I treat server.fs.deny as a guardrail, not an access-control layer.
Containers make this easy to get wrong. Inside the container, Vite has to listen on 0.0.0.0 for port mapping to work, which is why --host ends up in so many Dockerfiles. The real problem is ports: "5173:5173", which Docker publishes on every interface of the host.
What I'd check on Monday
- Versions. Run
npm ls vite --all(orpnpm why vite) in every repo, including ones that pull Vite in through a framework. Move to 7.3.2 or 8.0.5 or later. - Exposure. Grep scripts,
vite.config.*, Dockerfiles, compose files and Helm values for--host,host: true,0.0.0.0and5173. - Port binding. On shared or cloud hosts, publish dev ports on loopback only and reach them through an SSH tunnel or VPN.
- Secrets in dev. A dev
.envshould hold dev-scoped keys only. A box running a dev server should not have long-lived~/.aws/credentialswith production access. Terraform state belongs in a remote backend, not the working directory. - Previews. Never ship the dev server as a preview environment. Build the app and serve the static output from nginx or a CDN.
- Edge rules. F5 recommends a WAF rule that denies any request containing
/@fs/. Nothing legitimate in production needs that path. - Crawler trust. As F5 advises, if any rule lets "Googlebot" or an AI crawler skip a check, verify the source IP by reverse DNS instead of trusting the header.
npm ls vite --all
grep -rnE -- '--host|host:\s*true|0\.0\.0\.0|5173' \
package.json vite.config.* Dockerfile* *compose*.yml 2>/dev/null
services:
web:
ports:
- "127.0.0.1:5173:5173"
My take
Upgrading is the easy part. The harder rule is in F5's recommendations: if an unpatched Vite dev server was reachable from external networks during August 2026, treat its .env values, AWS credentials, Azure access tokens and Terraform state as potentially compromised, and rotate the keys. I agree. Rotating costs less than proving you weren't hit.
The spoofed user-agents are the part I keep coming back to. If a team allowlists AI crawlers by name, attackers are already using those names. The ethical hacking material I'm working through spends a lot of time on reconnaissance, and this campaign is recon at scale: cheap, broad, and aimed at whatever someone left open for a quick demo.
Sources
Primary references used for this post.