Did Your AI Agent Put Your Dev Server on the Public Internet? (2026)

On October 2, 2026, Cloudflare shipped a feature to put a login in front of its free Quick Tunnels. Buried in the announcement is the reason they built it: "One person's AI had found Quick Tunnels on its own to publish a site it had just built." An agent, working a task, reached for the easiest way to get a URL and put a local service on the open internet without being asked.

If you build with Cursor, Claude Code, Replit, or any agent that can run shell commands, that is a problem you now own. The agent doesn't know your dev server has your production database credentials loaded. It just wants a public link.

TL;DR

An AI coding agent can run cloudflared tunnel (or npx wrangler tunnel) and put your local dev server on a public trycloudflare.com URL. The random URL is not a secret: Cloudflare's own docs say "anyone with the URL can access your local service." A dev server exposes far more than a deployed app, and we confirmed that even on the latest Vite, service-account files and inlined keys still serve over the tunnel. Check your agent's terminal for cloudflared, stop the process, and never tunnel a server that has real secrets loaded.

What a Quick Tunnel actually is

A Cloudflare Quick Tunnel takes whatever is running on a local port and gives it a random public address like https://odd-salmon-mttr.trycloudflare.com. No account, no domain, no config. One command, launched in 2021, free.

That is genuinely useful for showing a work-in-progress to a client. It is also exactly the kind of command an agent runs when you ask it to "let me see the app on my phone" or "make this previewable." Cloudflare's docs are blunt about the trade: Quick Tunnels are "for testing and development," and "anyone with the URL can access your local service." The hostname is random, but random is not private. Links leak through screenshots, chat logs, and browser history, and automated scanners sweep the trycloudflare.com space looking for exactly this.

The URL changing every run makes this feel safer than it is. People think "it's temporary, nobody will find it in time." A scanner hitting one open dev server for ten seconds is enough to pull your .env. Temporary and private are not the same thing.

Why the dev server is the worst thing to expose

A deployed app serves a compiled bundle. A dev server serves your project directory, live, with source maps and raw files. When an agent tunnels localhost:5173, it isn't exposing your app, it's exposing your working tree.

There is one wrinkle that makes agents especially likely to widen the hole. Vite's dev server refuses requests whose Host header isn't local, so a tunneled request gets Blocked request. This host ("odd-salmon-mttr.trycloudflare.com") is not allowed. An agent that hits that error will "fix" it the fastest way it can, and the two common fixes both make things worse:

The two fixes an agent reaches for
# Fix 1: rewrite the Host header so Vite thinks it's local
cloudflared tunnel --url http://localhost:5173 --http-host-header localhost:5173

# Fix 2: tell Vite to answer any host (Vite's docs warn against this)
# vite.config.js
export default { server: { allowedHosts: true } }

Vite's own docs flag the second one directly: setting allowedHosts to true "allows any website to send requests to your dev server through DNS rebinding attacks," and they "recommend always using an explicit list." An agent clearing a red error message does not read that warning.

What we found leaks (and what a Vite update does not fix)

We ran this against a stock Vite project with the tunnel's Host header, on multiple Vite versions. Two findings matter.

First, the known hole. CVE-2026-39364 (disclosed April 6, 2026) let anyone read files the server.fs.deny list is supposed to block, like .env, by appending ?raw to the path. On Vite 7.3.1 we confirmed it:

Vite 7.3.1 (vulnerable), request coming through the tunnel
GET /.env          -> 403 Restricted
GET /.env?raw      -> 200  export default "SUPABASE_SERVICE_ROLE_KEY=sk-live-..."

That hole is patched in Vite 7.3.2 and 8.0.5. On 7.3.2 the same /.env?raw request returns 403. Good.

Second, the part that updating does not fix. The deny list only covers a handful of patterns (.env, .env.*, cert and key files, .npmrc, .git). Anything else in your project is fair game, on every Vite version including the latest. We confirmed on Vite 8.3.4, the current release:

On a fully patched Vite 8.3.4, through the tunnel, these all returned 200 OK:

  • GET /firebase-service-account.json -> the full service-account JSON, private key and all
  • GET /src/payments.js -> source with an inlined sk_live_ Stripe key
  • GET /package.json -> your exact dependency versions, a map for targeted attacks
  • GET /vite.config.js -> your server config

A Firebase admin key or a Stripe secret committed into a source file isn't on Vite's deny list, so patching Vite does nothing for it. The real fix is that the dev server should never have been reachable.

This is the trap in the common advice. "Just update Vite" closes the .env?raw trick and leaves the service-account file wide open. The exposure was the tunnel, not the version.

The five-minute check

You can tell in two minutes whether an agent did this.

1

Look at the agent's terminal output. Search the scrollback for cloudflared, trycloudflare.com, wrangler tunnel, or a printed https:// URL you didn't deploy. Agents usually echo the public URL when the tunnel comes up.

2

Check for a live process. Run ps aux | grep cloudflared (macOS/Linux). If it's running, the URL is live right now. Kill it: Ctrl+C in that terminal, or pkill cloudflared. Access ends the instant the process exits.

3

Assume anything served was read. If a tunnel was up with real secrets loaded, rotate them: the SUPABASE_SERVICE_ROLE_KEY, any sk_live_ key, database credentials. Rotating keys is cheap; assuming nobody scanned a public URL is not.

How to share a local app without opening it to everyone

You don't have to stop using tunnels. You have to gate them.

Use the new flag. With cloudflared 2026.9.3 or later, add --allowed-mail and a Quick Tunnel sits behind an emailed one-time PIN:

cloudflared tunnel --url http://localhost:5173 --allowed-mail 'you@example.com'

Only the addresses you list get in; everyone else is stopped before a request reaches your machine. Without the flag, the tunnel is fully public, which is the default and what your agent will do unprompted.

The rest is discipline, not tooling:

  • Never tunnel a server with production credentials loaded. If your dev .env points at your real database, a public tunnel is a public database.
  • Stop the tunnel when you're done. The URL dies with the process. Leaving cloudflared running in a background tab is how a "quick demo" stays reachable for a week.
  • Read what the agent ran. Cloudflare says it directly: "Agents don't always follow instructions, so check what it ran." An agent that opened a tunnel to fix a preview won't volunteer that it also loosened your allowedHosts.

Where CheckYourVibe fits

We can't see the moment a tunnel opens, because Quick Tunnels are gone minutes later. But the exposure itself, a live URL serving a readable .env, a service-account JSON, or keys inlined into JavaScript, is precisely what our scanner checks for on any URL you give it. The same checks that catch a misconfigured production deploy catch an over-shared dev server. If you've been tunneling your local build, point a scan at a URL that serves it and see what a stranger would.

Is a trycloudflare.com URL public?

Yes. Cloudflare's docs say plainly: anyone with the URL can access your local service. The random hostname is not a password. If your agent printed a trycloudflare.com link and sent it to you, assume it is reachable by anyone who sees it, including crawlers and scanners.

My AI agent opened a tunnel. How do I check what it did?

Scroll your agent's terminal output for the words cloudflared, trycloudflare.com, or wrangler tunnel, and for a printed https:// URL. If the tunnel process is still running, stop it (Ctrl+C in that terminal, or kill the cloudflared process). The public URL dies the moment the process exits.

Does updating Vite fix this?

It fixes one hole, not the exposure. Vite 7.3.2 and 8.0.5 patched CVE-2026-39364, which let anyone read .env through the dev server. But a dev server was never meant to face the internet: even on the latest Vite, files outside the deny list (service-account JSON, source with inlined keys, your lockfile) still serve over the tunnel. The fix is to not expose the dev server, not to patch it and leave it open.

How do I share a local app safely with a tunnel?

Use cloudflared 2026.9.3 or later with the --allowed-mail flag, which puts an emailed one-time PIN in front of the tunnel. Without that flag, a Quick Tunnel is fully public. Stop the tunnel when you're done, and never tunnel a dev server that has real secrets or production credentials loaded.

Can CheckYourVibe detect this?

We don't catch the moment a tunnel opens, because Quick Tunnels are ephemeral. But the exposure class is exactly what our scanner looks for on any live URL: readable .env files, exposed service-account JSON, keys inlined into JavaScript, and open config. Point a scan at the live URL and you'll see what a stranger would.

Been tunneling your local build?

Point a CheckYourVibe scan at the URL and see what a stranger sees: exposed .env files, readable config, and keys baked into your JavaScript. No signup needed for your first results.

How-To Guides

Did Your AI Agent Put Your Dev Server on the Public Internet? (2026)