I Found My Stripe Key in a Public Vercel Preview — Here's How

By: Trove Deck Solution Date: 2026-06-11 Reading time: 8 min

The Slack message landed at 11:47 PM on a Thursday. My client wrote: “Hey, I can see your Stripe key. Should I?” I stared at my screen for three seconds, then opened the preview URL myself. There it was — sk_live_51... — sitting in the browser’s application tab, fully readable, fully spendable.

A Vercel preview deployment had just handed my production payment secret to anyone with the URL. The deployment was public by default, and I had done zero configuration to lock it down.

Why Vercel Preview Deployments Expose Secrets by Default

Vercel creates preview URLs for every push to a non-production branch. These URLs are accessible to anyone who has the link — or who guesses it. If your build process, client-side code, or source maps reference environment variables, those variables become visible in the preview. Vercel does not automatically strip NEXT_PUBLIC_ prefixed variables from preview builds. According to Vercel’s own documentation, preview environments inherit the same environment variable bindings as production unless you explicitly configure branch-level overrides.

This means a single misconfigured NEXT_PUBLIC_STRIPE_KEY or, worse, a NEXT_PUBLIC_API_SECRET lands in the browser’s JavaScript bundle for every visitor.

Definition: A Vercel Preview Deployment = a temporary, publicly accessible copy of your application created from a git branch, sharing environment variable access with production unless restricted.

How I Discovered the Exposure

The discovery was accidental. I had a client review a new feature through the preview URL. They were technically literate enough to open Chrome DevTools and poke around. Most reviewers would never look — which makes this even more dangerous.

Here is the exact three-step process I now use to catch exposed variables before sharing a preview link:

Step 1: Check the Build Output

Before the deployment even goes live, inspect what your build process logged. In the Vercel build logs, search for any output that prints variable names. If you use console.log(process.env) anywhere — even in a test file — it will surface in the build output.

Step 2: Inspect the Client Bundle

Open the preview URL in a browser. Open DevTools → Application → Local Storage. Then check the Sources or Network tab for any .js files that contain strings matching your secret prefixes (sk_live, sk_test, NEXT_PUBLIC_). A quick grep on the bundled JavaScript reveals leaks in seconds:

curl -s https://your-preview.vercel.app/_next/static/chunks/*.js | grep -oE 'sk_live_[A-Za-z0-9]+'

Step 3: Run a Secrets Scan on Source

Tools like gitleaks, trufflehog, or Vercel’s own vercel env ls command can surface variables that should never have been committed. I run gitleaks detect --source . --verbose locally before every push.

What I Found: A Full Inventory of Leaks

When I ran the checklist above, the Stripe key was only the most obvious problem. I found three additional exposures:

Variable Risk Level How It Leaked
NEXT_PUBLIC_STRIPE_KEY High (live key) Hardcoded in a config object read by client code
NEXT_PUBLIC_SENTRY_DSN Medium Included in error tracking initialization
NEXT_PUBLIC_API_URL Low Pointed to a staging endpoint with weaker auth
AWS_ACCESS_KEY_ID Critical Accidentally committed in .env.local and bundled

The AWS key was the one that kept me up that night. It had AdministratorAccess attached because “it was just for testing.” Vercel’s build process had copied it into the build output, and the preview deployment served it via a source map.

How to Fix Vercel Environment Variable Leaks

Here is the fix sequence I followed — and the one our team now applies on every client project at Trove Deck Solution when we deliver a Vercel-hosted application.

1. Separate Public and Private Variables

Vercel distinguishes between variables available on the client (NEXT_PUBLIC_ prefix) and those only accessible server-side. Audit every variable and strip the prefix from anything that does not genuinely need to run in the browser. If a variable contains a key, token, or secret, it should never carry the NEXT_PUBLIC_ prefix.

2. Create Branch-Level Overrides

In the Vercel dashboard, navigate to Settings → Environment Variables. For each variable, set the scope to Production only. Do not allow Preview or Development to inherit production secrets. Use separate test keys (sk_test_...) for preview builds.

3. Add a Pre-Commit Hook

Install gitleaks as a pre-commit hook using the Husky framework:

npm install --save-dev gitleaks husky
npx husky add .husky/pre-commit "gitleaks detect --source . --staged"

This prevents secrets from ever reaching your git history.

4. Rotate Every Exposed Key Immediately

If a secret has been in a preview deployment, rotate it. Do not assume the URL was “probably not seen.” Assume full exposure. I rotated my Stripe key, my AWS credentials, and my Sentry DSN within one hour of discovery.

5. Set Up Vercel Authentication on Preview URLs

Vercel supports password protection and authentication for preview deployments. Enable it under Project Settings → Deployment Protection. Even if you fix the code, this adds a second layer — a visitor who somehow gets the URL still cannot access the app.

What Is the Actual Risk of Exposed Environment Variables?

Exposed secrets in a preview deployment carry the same risk as exposed secrets in production. A Stripe sk_live key allows unauthorized charges. An AWS key with broad permissions allows resource creation, data access, or even cryptomining. According to the 2024 Verizon Data Breach Investigations Report, 68% of breaches involve a human element — including misconfiguration and credential exposure. Your preview URL is public infrastructure with production keys bolted onto it.

Unlike a staging server behind a VPN, a Vercel preview URL has no network boundary. Anyone with the link — or anyone who brute-forces a predictable slug — gets full access to whatever the application serves.

How Does This Compare to Other Hosting Platforms?

Vercel is not uniquely vulnerable. Netlify, Railway, and Render all create preview deployments with environment variable inheritance. The difference is that Vercel’s NEXT_PUBLIC_ convention creates a false sense of security — developers assume the prefix means “safe for public,” when it actually means “will be shipped to the client bundle.” That distinction matters when your client bundle is served from a publicly accessible URL.

Platform Preview Auth by Default Branch-Level Env Overrides Client-Side Secret Risk
Vercel No (free tier) Yes High if NEXT_PUBLIC_ is overused
Netlify No Yes High with client-side JS
Railway Yes (paid) Yes Lower (container-based)
Render Yes Yes Lower (server-rendered default)

What You Should Do Right Now

If you host on Vercel, run the three-step inspection today — build logs, client bundle grep, and source scan. Do not wait for a client to find your secrets for you. Rotate anything exposed. Lock your preview deployments behind authentication. And audit your NEXT_PUBLIC_ prefix usage across every project.

How Can You Prevent Future Exposure in Preview Deployments?

The prevention playbook is simple but requires discipline: never use production secrets in preview environments, scan every commit before it reaches git, and password-protect every preview URL. If your team ships custom software on Vercel and you want a structured security review of your deployment pipeline, Trove Deck Solution can help — we run the same audit process on every client deployment we deliver.

#Vercel#EnvironmentVariables#DevOps#Security#IndieHackers#SaaS#WebDev#Privacy