Why is my API key exposed?
A key is exposed when it is readable by anyone: bundled into browser JavaScript, committed to a repository, or returned by an endpoint. Rotation comes first, then the code fix, because the old value is already copied and cached wherever it appeared.
The problem
A secret key appears somewhere the public can read it. You may have found it yourself, or received an automated warning from the provider or a repository scanner.
What it means
Anyone can now act as your application against that service — spending quota, sending mail, reading data — until the key is revoked. Publishable keys are a different matter: they are meant to be visible and are not an incident.
Common causes
- A secret used in a component, which ships to the browser.
- A public prefix added to a secret so that a component could use it.
- A configuration file with real values committed to the repository.
- A debug endpoint or error response that echoes configuration.
- A screenshot or a pasted snippet in a public place.
How to diagnose it
- 1Open the live site's bundled JavaScript and search for the key's first characters.
- 2Search the whole repository history, not just current files.
- 3Check any endpoint that returns configuration or verbose errors.
- 4Review the provider's usage log for requests you did not make.
rg -n "sk_live|service_role|BEGIN PRIVATE KEY" --hiddenHow to fix it
- 1Rotate the key at the provider immediately. This is the only action that stops the exposure.
- 2Add the new key to your server environment only.
- 3Move the code that uses it into a server function.
- 4Redeploy and confirm the new bundle contains no key.
- 5Review the provider's log for unauthorised use while the old key was live.
What AI may have done
Written the integration in the place where the data was needed — a component — because that produces working code fastest. It may also have added a public prefix when the build tool refused to supply the value, which is the exact moment a secret becomes public.
How to verify the fix
- 1Search the newly deployed bundle for the old and new keys; both should be absent.
- 2Confirm the feature still works, now going through your own endpoint.
- 3Confirm the old key is revoked by calling the provider with it and receiving a rejection.
- 4Check that repository scanning is enabled so the next one is caught automatically.
How to prevent it
- Never prefix a secret to make it available in the browser.
- Keep all secret use inside server functions.
- Ignore environment files in version control from the first commit.
- Review any AI change that adds a new integration.
- Scope keys to the minimum permissions the provider offers.
Frequently asked questions
- Is deleting the commit enough?
- No. Rewriting history is unreliable and the value may already be cached or cloned. Rotate.
- My anon key is visible — is that a problem?
- No, it is designed to be. Confirm your database access rules are doing the protecting.
- How would I know if it was used?
- The provider's usage and audit logs. Look for unfamiliar times, volumes or regions.
Practice this in MessyDev
Reading it once helps. Doing it once sticks. These are the hands-on parts of MessyDev that cover the same ground.
Keep going
- How to keep API keys out of your frontendA practical method for moving secret-using code to the server, checking what actually shipped to the browser, and proving a key is no longer exposed.
- API keys explainedWhat an API key is, what it proves, why some keys are safe in a browser and others are not, and how to handle one without leaking it.
- Common security mistakes in AI-generated appsThe handful of issues that show up repeatedly in generated code — what each one looks like, why it happens, and the check that catches it.