Home / Guides

Exposed .env file or API key? How to check and rotate

How to find leaked API keys and committed .env files in your repo, JavaScript bundle or live site, rotate them safely, and stop it happening again.

Updated 2026-10-15 · ShipCheck guides

Leaked secrets are the most expensive mistake in vibe-coded apps. Bots scan public GitHub commits and popular hosting domains around the clock for strings like sk- and AKIA, and a working OpenAI or AWS key can be abused within minutes. Here is how to find out if you are exposed, and what to do if you are.

Where secrets leak

  1. A committed .env file. .gitignore was missing, or was added after the first commit.
  2. Hardcoded in source. The AI pasted the key straight into openai.ts to "make it work".
  3. The frontend bundle. Variables prefixed NEXT_PUBLIC_, VITE_, REACT_APP_ or EXPO_PUBLIC_ are inlined into JavaScript that every visitor downloads. Putting a secret in one of these publishes it.
  4. A publicly served .env. A misconfigured server or static export serves /.env as a file.
  5. Git history. You removed the key in a later commit, but the old commit is still there.
  6. Logs, screenshots, issue trackers and chats you shared while debugging.

How to check

Your repository and its history

# Is a .env tracked right now?
git ls-files | grep -i "\.env"

# Was one ever committed?
git log --all --oneline -- .env '*.env' '.env.*'

# Scan the entire history for secrets
npx gitleaks detect --source . -v
# or
docker run --rm -v "$PWD:/repo" trufflesecurity/trufflehog git file:///repo

On GitHub, also turn on Secret scanning and Push protection (Settings → Code security). They are free for public repos.

Your live site

curl -s -o /dev/null -w "%{http_code}\n" https://yourapp.com/.env   # should be 404
curl -s https://yourapp.com | grep -oE 'src="[^"]+\.js"'            # list bundles
curl -s https://yourapp.com/assets/index-abc123.js | grep -oE "sk-[A-Za-z0-9_-]{20,}|sk_live_[A-Za-z0-9]+|AKIA[0-9A-Z]{16}|service_role"

Or let ShipCheck do it. Paste your URL or public repo and it checks for exposed .env files, scans the HTML and JavaScript you ship plus repo files for common key formats, and masks anything it finds so the report doesn't leak it again.

Found one? Rotate first, clean up second

Order matters. Removing the key from code does nothing to stop someone who already copied it. Make the old key useless first.

  1. Create a new key in the provider's dashboard.
  2. Update it everywhere it is used: your host's environment variables (Vercel, Netlify, Railway, Supabase Edge Function secrets), CI, and local .env. Redeploy.
  3. Revoke the old key. Do this right away for high-risk keys, even if it causes a few minutes of downtime.
  4. Check usage and billing for activity you don't recognise, and contact the provider if there was abuse.

Where to rotate common keys:

Optional: purge it from history

After rotating, you can rewrite history with git filter-repo --path .env --invert-paths or BFG Repo-Cleaner and then force-push. This is cosmetic once the key is dead, and it breaks other people's clones, so coordinate with collaborators. Never skip rotation because you rewrote history.

Prevent it next time

Scan your app free

Paste your live URL or public GitHub repo. ShipCheck checks for leaked keys, committed .env files, missing security headers, HTTPS issues and slow pages, then gives you copy-paste fixes. No signup.

FAQ

If I delete the .env file from my repo, am I safe?

No. The file is still in git history, in forks and clones, and possibly in bot caches that scrape GitHub within minutes. Treat any key that was ever committed or shipped to a browser as compromised and rotate it.

Which keys are OK to expose in the browser?

Keys designed to be public: the Supabase anon or publishable key (with RLS on), Stripe publishable keys (pk_), Firebase web config, and public analytics IDs. Secret keys such as sk_, service_role, OpenAI and database URLs must never reach the client.

How do I check if my live site exposes .env?

Request https://yoursite.com/.env and check that the response is a 404, not your variables. Also search your built JavaScript files for key patterns. ShipCheck does both checks for free.

More guides

Is my Lovable app secure?

How to check whether your Lovable app is secure: Supabase Row Level Security, exposed keys, security headers, auth and storage. A step-by-step checklist with fixes.

How to add security headers on Vercel

Copy-paste vercel.json to add CSP, HSTS, X-Frame-Options, X-Content-Type-Options, Referrer-Policy and Permissions-Policy on Vercel, plus how to test them.

How to add security headers on Netlify

Add CSP, HSTS, X-Frame-Options and other security headers on Netlify using a _headers file or netlify.toml. Copy-paste examples, framework tips and testing.

The vibe-coded app launch checklist

A practical pre-launch checklist for apps built with Lovable, Cursor, Bolt, v0 or Replit: security, secrets, database rules, performance, SEO, legal and monitoring.