AI-coded apps

    Vibe-Coding Risks: Leaking API Keys via bolt.new Client Architecture

    A client-side JavaScript bundle from an AI-built app with an exposed API key highlighted.

    Vibe-coding tools like bolt.new build full-stack apps fast, but the speed hides a boundary that matters for security: anything in the frontend is public. When an AI builder wires an API key into client-side code or a bundled environment variable, that key ships to every visitor's browser, where anyone can read it. The fix depends on which key leaked. A Supabase anon key is meant to be public and is safe when Row Level Security is correct, but a service_role key or a third-party secret must be rotated immediately and moved to the server.

    Short answer

    bolt.new is a browser-based AI app builder from StackBlitz that generates full-stack code, and the common risk is a secret ending up in the client, where it is public. Bolt's own guidance is to never put API keys in client-side code and to use your host's environment variables instead. Which secret leaked decides the severity: a Supabase anon key is low risk when Row Level Security is correct, while a service_role key or a third-party secret is a full breach you must rotate now. Verify by confirming no secret ships in the bundle and testing access.

    Why bolt.new and vibe-coding leak keys

    The root cause is the frontend and backend boundary, which is easy to blur when an AI generates a whole app at once. Code that runs in the browser is downloadable by anyone: view source, open the network tab, or read the JavaScript bundle, and every string in it, including any key, is visible. A secret is only secret if it stays on a server the user cannot read.

    Vibe-coding tools make this easy to get wrong because they scaffold the client and the data layer together and wire them up for you. If the generated code calls a service directly from the browser using a secret key, or reads a secret from an environment variable that gets bundled into the client, that secret is exposed the moment you deploy. This is not unique to bolt.new; it is a property of any client-side app, and it is exactly why Bolt tells you to keep keys in host environment variables rather than client code.

    Which secret was exposed, and is it dangerous?

    The severity depends entirely on which key leaked, so identify it first. Some keys are designed to be public and are low risk, while others grant full access and are a breach. The table below sorts the common ones.

    Key or secretSafe in the client?If it leaks
    Supabase anon / publishableYes, when RLS is correctLow risk alone; exposes data if RLS is missing
    Supabase service_role / secretNeverFull database read and write, bypasses RLS; rotate now
    Third-party secret (OpenAI, Stripe secret, etc.)NeverAn attacker runs up your bill or reaches your account
    Publishable third-party key (Stripe publishable, etc.)Yes, by designLow risk; meant to be public

    The pattern is consistent: publishable and anon keys are built to ship in the client, while anything labeled secret or service is meant only for a server. A named study makes the stakes concrete. In CVE-2025-48757, security researcher Matt Palmer found that 170 AI-built projects exposed data because the client relied on a public key while Row Level Security was missing, showing how this class of mistake scales across generated apps.

    What can an attacker do with it?

    What an attacker can do maps directly to the key's power. With a Supabase service_role key, they get full read and write access to your database and bypass every Row Level Security policy, which means they can dump user records, alter data, or delete tables. With a third-party secret such as an OpenAI or Stripe secret key, they can spend your credits, run up a large bill, or reach account functions that key controls.

    With only a public anon or publishable key, the damage is bounded by your policies. If Row Level Security is set up correctly, the anon key does exactly what it should and nothing more. If RLS is missing, that same public key lets anyone query your tables directly, which is how a low-risk key becomes a data leak. That is why the anon key alone is not the vulnerability; shipping it without RLS is.

    How do RLS and policies change the risk?

    Row Level Security is what makes a public Supabase key safe, and its absence is what makes a leak dangerous. RLS decides, per row, what a given request is allowed to see, so a correctly configured policy means the anon key returns only what each user should access. Without RLS, the database trusts the key alone, and a public key plus no policies equals an open database.

    The critical exception is the service_role key, which carries the BYPASSRLS attribute and ignores every policy by design, according to Supabase. No amount of RLS protects you if that key leaks, because it is built to skip the checks. So the risk model is two-layered: RLS protects data reached with the anon key, and key hygiene keeps the service_role key and third-party secrets off the client entirely. You need both, and neither covers for the other.

    Rotate and contain, step by step

    Rotate first, investigate second, because every minute a leaked secret works is a minute an attacker can use it. The checklist below contains the leak and closes the hole.

    StepAction
    1. Identify the keyDetermine exactly which secret shipped in the client
    2. Rotate the secretRotate or revoke it in the provider dashboard immediately
    3. Move it server-sidePut secrets in host environment variables or an edge function
    4. Fix RLS if SupabaseEnable and enforce RLS so the anon key is genuinely safe
    5. Check logs and usageReview provider logs and billing for unfamiliar activity
    6. VerifyConfirm the old secret is dead and no secret ships in the build

    Two cautions matter. First, if the secret was committed to a git repository, rotating is necessary but not enough, because the old value stays in the history; treat a key pushed to a public repo as found within minutes. Second, keep an inventory of everything that uses the key before you revoke it, so you rotate cleanly instead of taking down your own backend.

    How do you verify the fix?

    Verification turns a hopeful fix into a confirmed one, and it is the step people skip. Start by confirming that no secret ships in the client: rebuild the app and search the deployed bundle and network requests for the old and new secret values, which should not appear. Any secret key that still shows up in the client means the move to the server is incomplete.

    Then test access as an outsider. If you use Supabase, send a direct request to each sensitive table using only the anon key and confirm you get nothing back when you should not, then repeat for writes. For third-party secrets, check the provider dashboard for the rotated key's status and review recent usage for anything you did not do. If any anonymous request succeeds when it should not, RLS is still off or a policy is missing on that table.

    Where a build scan fits

    Many vibe-coded apps are wrapped and shipped as mobile apps, and the same secret can end up baked into the .ipa or .apk, an Expo or EAS build, an Xcode project, or a CI/CD secret printed to a log. Once it ships inside an app a user can download, it is public, and the web-side care does not undo that. Scanning what you actually ship catches these before release.

    A scanner like PTKD.com analyzes your built .ipa or .apk and returns a graded report mapped to OWASP MASVS, flagging embedded secrets and exposed keys. It is worth being clear about the limit: a build scanner cannot rotate a key, read your provider logs, or fix your Row Level Security, and it will not undo a leak that already happened. What it does is catch a service_role key or other secret in the app before it reaches users, which is the step that would have prevented most of these incidents.

    What to take away

    • Anything in the frontend is public, so a secret in client code or a bundled env var is exposed the moment you deploy.
    • The anon or publishable key is meant to ship in the client; the service_role key and third-party secrets must never be there.
    • Severity depends on the key: a service_role key or a third-party secret is a full breach and must be rotated immediately.
    • RLS makes the anon key safe but never protects against a leaked service_role key, which bypasses policies by design.
    • Rotate, move secrets server-side, fix RLS, and verify; and scan the built app with PTKD.com to catch secrets before they ship.
    • #bolt.new
    • #api key exposure
    • #vibe coding
    • #supabase
    • #row level security

    Frequently asked questions

    Which secret does bolt.new usually expose?
    Whichever one the generated code puts in the client. Commonly it is a Supabase key or a third-party API key read from a bundled environment variable. A Supabase anon or publishable key is meant to be public, but a service_role key or a third-party secret must never ship in the client. Identify exactly which key leaked before deciding how urgent the fix is.
    Is the Supabase anon key a problem if it leaks?
    On its own, no; it is designed to ship in the client. The danger is shipping it while Row Level Security is missing, because then anyone can query your tables directly with that public key. Fix RLS and the anon key does only what your policies allow. The vulnerability is the missing policy, not the key itself.
    How do I rotate a leaked key?
    Rotate or revoke it in the provider dashboard immediately, then move it to host environment variables or an edge function so it never ships in the client again. Update every service that uses it and check provider logs and billing for unfamiliar activity. If the key was committed to git, treat the history as compromised, because rotating does not remove the old value from past commits.
    How do RLS policies change the risk?
    Row Level Security makes a public anon key safe by limiting, per row, what each request can read or write. Without it, a public key plus no policies means an open database. The exception is the service_role key, which carries BYPASSRLS and ignores every policy, so no amount of RLS protects you if that key leaks. RLS and key hygiene are two separate defenses.
    How do I verify the fix?
    Rebuild the app and confirm no secret value appears in the deployed bundle or network requests. Then test access as an outsider: with Supabase, send a direct request to each sensitive table using only the anon key and confirm it returns nothing it should not, for reads and writes. For third-party secrets, check the provider dashboard and recent usage for anything you did not do.
    How do I catch this in a mobile-wrapped app?
    Scan the built app. A scanner like PTKD.com (https://ptkd.com) analyzes your .ipa or .apk and flags embedded secrets and exposed keys before release, including a service_role key or a third-party secret baked into an Expo, EAS, Xcode, or CI build. It does not rotate keys or fix RLS, but it catches secrets in the shipped app, which is where mobile vibe-coded apps most often leak them.

    Keep reading

    Scan your app in minutes

    Upload an APK, AAB, or IPA. PTKD returns an OWASP-aligned report with copy-paste fixes.

    Try PTKD free