Skip to content

Exposed API keys in your vibe-coded app: how to check before you ship

AI coding tools paste API keys straight into the frontend by default. What actually leaks, a five-minute way to check your own app, and how to fix it without rewriting anything.

· Rampa

You vibe-coded your way to a working app in a weekend, pasted a snippet from a tutorial or let an AI coding assistant wire up Stripe, OpenAI, or Supabase for you, and shipped it. It worked, so you moved on to the next feature. Somewhere in that process, a key that was supposed to stay on a server may have ended up in the code your browser downloads every time someone opens your site. Nobody warns you, because the app still works fine either way.

This is the same review Rampa Solutions runs before you ship anything built with AI: accessible, secure, private, legal, and no surprise bills. This piece is about the security light specifically, and about the one gap that shows up in vibe-coded apps more than any other: keys that were never meant to leave your server.

Why this happens by default

The fastest way to call an API from a frontend app is to paste the key straight into the code, and that is the version most tutorials show first, because it is the one that actually runs without setting up a backend. A prompt that says "connect this to Stripe" or "add OpenAI to this form" rarely also says "and keep the secret key off the browser", so that part is simply not part of what gets built. A public key and a secret key also look identical to someone moving fast: both are just a long string of letters and numbers with no label saying which is which.

What is actually meant to be public, and what is not

Some keys are designed to sit in the browser. Stripe's publishable key and a Supabase project's anon key are built to be seen, and they are safe on their own only if the rest of the setup is correct. What is not meant to be public: a Stripe secret key, an OpenAI or Anthropic API key, an AWS access key, a Supabase service_role key (the key that skips every permission check), a raw database connection string, or a webhook signing secret. If any of those show up in the JavaScript a browser loads, anyone who opens dev tools on your site can read them, copy them, and use them as if they were you.

How to check your own app in five minutes

  • Open your live site and open your browser's developer tools (F12 on most browsers).
  • Go to the Network or Sources tab and search the loaded JavaScript files for the start of a key: sk_ or sk- (secret keys), service_role, or the words key, secret, or token sitting next to a long random string.
  • If your code is on a public GitHub repository, search the repository itself for the exact text of one of your real keys. A key that appears anywhere in the commit history stays exposed even after you delete it from the latest version; deleting it does not undo the earlier commit.
  • Check whether a .env file (where these values are supposed to live, outside the code that ships to the browser) was ever committed. "I removed it later" does not undo a commit that is still sitting in the public history.

What it actually costs you if you miss one

  • An OpenAI or Anthropic key gets used by someone else, and the bill lands on your card overnight while you are asleep: exactly the surprise-bill risk a passive security check looks for.
  • A Supabase service_role key with Row Level Security (RLS, the setting that decides which rows a request is allowed to touch) turned off lets anyone read or delete every row in every table.
  • A Stripe secret key lets someone issue refunds, read customer records, or move money through your account.

None of this needs a sophisticated attacker. Scanners that crawl public code and public sites for exposed keys run all the time, and they do not care how new your app is or how few people have signed up.

How to fix it without rewriting the app

  • Move the call that uses the secret key to a server route: your framework's API route, an edge function, or a small serverless function. The secret key lives only there; the browser only ever talks to your own server.
  • Rotate the exposed key first, before anything else. The old one keeps working, for whoever found it, until you replace it.
  • For a Supabase anon key, the fix is usually not moving it: it is turning on RLS on every table and checking the policy, since the anon key is meant to be public and is only safe once RLS backs it up.
  • Add .env to .gitignore before your next commit, not after. If a key is already in your repository's history, rotating it matters more than trying to scrub the old commit.

A weekend build does not buy extra time here. This check covers the most common gap, and a passive scan of what your site already shows in public catches the same thing automatically, along with the headers, cookies, and public files that travel with it, without ever guessing at your database or trying to log in.

Run a free check before you post the link anywhere: https://rampa.solutions/?de=blog-vibe-coded-app-exposed-api-keys

Sources

Find out where your site stands, now

Enter your address. In about a minute: every failure on the page explained without jargon, and the corrected code for what we can fix. Free, no account.

Free scan, right here · no account

Keep reading

Automated testing covers roughly half of WCAG criteria; a full conformance claim also requires manual review. Technical information, not legal advice.