Free workshop: build with AI without losing control of your project View the workshop →
vibebusters

← Full glossary

// glossary

Exposed secret: when a private key becomes readable by anyone

In short

An exposed secret is private access information (payment key, email key, database password, API token) that has become readable outside the place where it should live: code sent to the browser, a Git repository, a screenshot or a log. Once exposed, a secret must be treated as compromised and replaced.

A secret is a key that grants a power: charging a card, sending emails on behalf of your domain, reading your whole database, calling a pay-per-use AI model. As long as it stays on a server, it does its job quietly. As soon as it shows up anywhere else, whoever reads it inherits the same power.

The three places where a secret escapes

Code sent to the browser. Everything the interface runs is downloaded by every visitor, in plain text. The documentation for Vite, the build tool used by Lovable, Bolt and many others, puts it plainly: variables prefixed with VITE_ are bundled into the code sent to the client and should not contain sensitive information such as API keys. Next.js applies the same logic to the NEXT_PUBLIC_ prefix.

The Git repository. A versioned .env file, a key hard-coded in a configuration file or a test script. Deleting the line is not enough: the history keeps every version. GitHub blocks pushes of many secret types to public repositories by default, through push protection, but that net does not cover every format or every private repository.

The side channels. A screenshot shared in a ticket, an error log that prints the configuration, a prompt pasted into a third-party tool, a file sent to a freelancer. These leaks are less spectacular and harder to trace.

Why it is common in AI-built apps

The AI tool aims to make the request work. If you ask it to "send a welcome email with Resend" or "add an OpenAI summary", the shortest route is to call the service directly from the interface, with the key close at hand. The feature works, the demo convinces, and the key travels with every page.

Platforms have improved. Lovable offers a deep scan that looks for leaked secrets, among other things, and steers sensitive calls towards server functions. These safeguards are valuable. They do not replace a complete inventory, especially on a project that has gone through several tools, several exports or several people.

How to check your app

  1. Search for known prefixes in the browser code (developer tools, Sources tab) and in the repository: sk_live_ and rk_live_ (Stripe), sb_secret_ or service_role (Supabase), re_ (Resend), sk- (OpenAI and others), AKIA (AWS)
  2. List the VITE_ or NEXT_PUBLIC_ variables and ask for each one: is this a value any visitor can know without risk?
  3. Comb through the Git history with a dedicated tool such as gitleaks or trufflehog, which recognise hundreds of formats
  4. Check the .gitignore file: .env, .env.local and *.local should be listed
  5. Look at the logs and the error messages shown to users: they must never contain configuration

A concrete example

A note-taking tool built with v0 offers an AI summary of each note. The model call goes straight from the browser, with the provider key in a NEXT_PUBLIC_ variable. Nobody notices for three months. Then the monthly bill jumps from 40 to several thousand euros: the key has been extracted and is powering other projects.

The fix has three steps: a new key with the provider, the call moved to a server function that checks the user is signed in, and a spending cap set with the provider. The old key is revoked last, once the new one is in place, to avoid any downtime.

The most common mistakes

  • Assuming a private repository protects secrets: it is shared with every tool, collaborator and integration that has access
  • Removing the key without replacing it, leaving the old one active
  • Mixing up public and secret keys from the same provider (Stripe pk_ and sk_, Supabase publishable and secret)
  • Using the same key in test and production, which multiplies the places it travels
  • Setting no cap on spend or volume with pay-per-use providers

The takeaway

An exposed secret is very fixable, as long as you handle it in order: new key, move it server-side, revoke the old one, then clean up. These steps are part of the pre-launch checklist. The vibebusters Scan looks for secrets in the served code, the repository and its history, and delivers a key-by-key replacement plan that the Production Upgrade can carry out for you.

// faq

The questions we keep hearing

How do I know if a secret is exposed in my app?

Open your app in the browser, then the developer tools, and search the JavaScript files for typical prefixes such as sk_live_, sb_secret_ or re_. Run the same search on the Git repository, history included. Any secret found in those places is exposed.

Is removing the key from the code enough?

No. A key removed from the code stays readable in the Git history and may already have been copied. The only reliable fix is to generate a new key with the provider, store it server-side, then revoke the old one.

Is every key visible in the browser an exposed secret?

No. Some keys are public by design, such as the Supabase publishable key or the Stripe publishable key (pk_). They only grant what the rules allow. An exposed secret is a key designed to stay on the server.

Take stock of your app's secrets

The Scan looks for secrets in the served code, the repository and its history, then delivers a replacement plan, key by key.

See what the Scan covers