If you’ve built an app with AI tools, there’s a real chance one of your secret API keys is readable by anyone who visits your site. It’s one of the most common problems we find, and one of the most expensive to ignore.
What is an API key, and why does it matter?
An API key is like a password your app uses to talk to another service: Stripe for payments, OpenAI for AI features, Resend for email, Supabase for your database.
Whoever has the key can act as you. With a leaked payments key they can see your customers and issue refunds. With a leaked AI key they can run up thousands in usage on your card. With a leaked database “service” key they can read and delete everything.
Why AI tools leak them
Modern apps have two halves:
- The front end: the code that runs in your visitor’s browser. Anyone can read it. Your browser downloads it to show the page.
- The back end: code that runs on a server you control. Visitors can’t see it.
Secret keys must only ever live in the back end. But when you ask an AI tool to “add Stripe payments” or “connect to OpenAI”, the quickest way to make it work is often to call the service straight from the front end, with the key right there in the code. The feature works, the demo looks great, and the key is now public.
It also happens when:
- A key gets pasted into a chat with the AI and ends up in a code file.
- A
.envfile with secrets is committed to GitHub. - The tool uses a powerful “admin” key where a limited, public one would do. In Supabase, using the
service_rolekey instead of theanonkey in the browser is a classic.
How to check if it happened to you
- Search your code for things like
sk_live,sk-,service_role,secret,API_KEY, andBearer. - Check your live site. Open it in Chrome, press F12, go to the Sources tab and search (Ctrl/Cmd+Shift+F) for the same words. If a secret key shows up there, it’s public.
- Check your Git history. A key that was committed and later deleted is still in the history. Tools like
gitleaksor GitHub’s secret scanning will find them.
How to fix it
Step 1: Rotate the key. Go to the service’s dashboard, create a new key, and delete the old one. Do this first. Once a key has been public, assume someone has it. Deleting it from your code is not enough.
Step 2: Move the call to the server. Instead of the browser calling Stripe or OpenAI directly, the browser calls your server (a small “server function” or API route), and your server calls the service using the key. Most platforms (Vercel, Netlify, Cloudflare, Supabase Edge Functions) make this straightforward.
Step 3: Store keys as environment variables. Put the key in your hosting provider’s settings, not in a code file, and make sure .env files are listed in .gitignore.
Step 4: Use the least powerful key that works. Many services offer restricted keys that can only do specific things. Use them.
Step 5: Add a safety net. Set billing alerts and spending limits on every paid service, so if a key does leak, the damage is capped.
Want a second pair of eyes?
Checking for leaked keys is part of every free audit we run. In 30 minutes we’ll look at your app with you and send a short written summary of what we found. Book yours here.