A preview URL is a public link, not a private staging environment
The concrete risk is simple: by default, a Vercel preview deployment is reachable by anyone who has the URL. There is no login wall in front of it. When you push a branch or open a pull request, Vercel builds a preview and gives you a generated address, and that address answers requests from the open internet the same way your production domain does. Vercel preview deploy security starts with accepting that "preview" describes the build lifecycle, not an access control.
This matters because of how the link gets used. A preview deploy looks and feels like a private staging environment, so people paste it into a group chat, a shared doc, a screen recording, or a pull request comment. Each of those is a place the URL can be copied, forwarded, or indexed. The deploy is often running against the same real database, the same payment keys, and the same third-party services as the eventual launch, just at a different address.
Separate what is observable from what is only possible. Observable: the preview URL returns your app to an anonymous request, the same headers and client bundle ship there as anywhere else, and a search engine that finds the link can crawl it. Possible, but not proven by the URL alone: that the data behind it is sensitive, or that a specific route lets an anonymous caller act on it. The point of this note is to check the observable surface before the link spreads, and to flag where you still need to look deeper.
Why AI-built apps land here
AI build tools and the platform defaults push you toward sharing a preview link early. The generated workflow is: describe the app, get a working build, push it, and receive a URL you can show someone in minutes. That speed is the selling point, and it is also why the access question gets skipped.
A few patterns stack up:
- The preview is unauthenticated by default. Vercel offers Deployment Protection (such as Vercel Authentication or password protection) to put a wall in front of preview deploys, but it is something you turn on, and an AI-generated setup rarely turns it on for you.
- Preview environments often inherit environment variables. If a variable is scoped to the Preview environment, the preview build gets it, including keys that point at real services. Anything exposed to the browser still ships in the client bundle here exactly as it would in production.
- "Staging" is a habit, not a setting. Calling the link staging in conversation does not make it private. The word implies an access boundary that the default deploy does not have.
- The app works on first load, so it looks finished. A working preview hides the fact that nobody reviewed which routes, headers, or data surfaces are reachable without auth.
What to check on your own preview URL before sharing
You can confirm all of this on your own deployment with no attack and no third-party target. Open your own preview URL and work through the public surface.
Check whether the link is protected at all. Open the preview URL in a private or logged-out browser window, or on a device that is not signed in to your Vercel account. If the app loads with no challenge, the deploy is public. If you hit a Vercel login or a password prompt first, Deployment Protection is on. Loading straight into the app is the suspicious result for anything you consider non-public; a protection prompt is the safer result.
Check the client bundle for secrets. Open DevTools, go to the Sources or Network tab, and look at the JavaScript that ships to the browser. Search it for secret-shaped strings: prefixes like sk_, sk-ant-, sk-proj-, service_role, or any token that is meant to stay server-side. A publishable or anon key (for example pk_ or a Supabase anon key) is designed to be public and is expected here; a secret server key is the suspicious result and means a misscoped environment variable reached the front end.
Check the response headers and source maps. In the Network tab, click the document request and read the response headers. Missing security headers (for example no Content-Security-Policy, no X-Frame-Options or frame-ancestors, no Strict-Transport-Security) are worth noting before launch. Also look for .map files loading next to your bundles; published source maps hand a reader your readable source, which is fine if intended and a giveaway if not.
Check for exposed deploy and build artifacts. Request paths that should never answer on a deployed app, against your own URL only: GET /.env, /.git/HEAD, and common backup or config filenames. A 404 or a redirect is the safer result. A 200 that returns file contents is the suspicious result and a direct exposure.
Check whether real data comes back unauthenticated. Browse the app logged out and watch the Network tab. If list or detail endpoints return real records to an anonymous session, that is an authorization gap on top of a public URL, and the preview link has effectively published that data. Note that a clean look here is not proof of safe authorization; it only covers what you exercised in the browser.
How to lock it down, and what that does not cover
The fastest reduction is to stop serving the preview to anonymous visitors at all.
Be clear about the limit of each control. Deployment Protection stops casual access to the preview URL, but it does not fix an endpoint that returns data without auth once someone is past the wall, and it does not change anything about your production domain, which is public by design. Authentication (proving who the caller is) and authorization (deciding what that caller may do) are different problems; protecting the preview link is an authentication-style gate on the front door, not a guarantee that each route checks permissions correctly. Lock the door and still fix the rooms.
- Turn on Deployment Protection in your Vercel project so preview deploys require Vercel Authentication or a shared password. This puts an access wall in front of every preview URL, so a leaked link no longer loads your app for a stranger.
- Scope environment variables deliberately. Keep secret keys out of the Preview environment unless the preview genuinely needs them, and keep every secret out of any variable that reaches the browser. A server secret in the client bundle is exposed the moment the page loads, on preview and production alike.
- Disable source map publishing for production-style builds unless you have a reason to ship maps.
- Add the security headers you want enforced (for example a Content-Security-Policy and HSTS) in your Vercel config so previews and production carry them.
- Treat the data layer as the real boundary. The URL being public means the access control has to live in your backend: row-level authorization, auth checks on every endpoint, and no privileged action reachable by an anonymous caller.
Where VibeCodeGuard fits, and what it does not prove
VibeCodeGuard's Launch Check runs against the public URL, and a Vercel preview link is exactly that. Before you share the link, the scan looks at the same surface this note walks through: exposed security headers, published source maps, secret-shaped strings in the client bundle, reachable build and deploy artifacts, and openly readable data surfaces. It returns each finding with a severity and a fix direction, so an exposure shows up in your scan instead of in whoever the link gets forwarded to next. For the broader pre-share routine, see the AI-built app launch security checklist; the same exposure pattern on other hosts is covered in the Netlify branch deploy and Cloudflare Pages headers notes.
What it does not do is decide whether your data should be private, read your authorization logic, or confirm that a route enforces the permissions you intended. That is a code and design question. The scan reports what an outside visitor can reach from the preview URL; it does not prove the app is safe behind that surface.
Next step: open your preview URL in a logged-out window. If it loads with no challenge, either turn on Deployment Protection or run a focused Launch Check against that URL before you paste it anywhere.
A clean Launch Check on a preview URL does not mean the preview is safe to share widely. It means the public surface it inspected looked clean at scan time. It does not verify that endpoints check authorization, that Deployment Protection is on, or that the data behind the link is meant to be public. Treat a flagged item as a reason to hold the link back.
> launch check
Scan the public surface before launch.
Get severity, evidence, and practical fix guidance for the checks VibeCodeGuard can run from the outside.