AI-coded apps

    How dangerous is a leaked JWT secret in a Lovable app?

    A leaked Supabase JWT signing secret in a Vite environment variable letting an attacker forge tokens for any user in a Lovable app

    If you built an app in Lovable on Supabase and you are worried about a JWT secret leaking, you are worried about the right thing, because that secret is what proves who every user is. This is for builders who want to know exactly how bad the exposure is and the specific way Lovable apps tend to leak it.

    Short answer

    A leaked Supabase JWT secret is among the worst exposures possible, because the secret signs the tokens that authenticate users. Per Supabase's JWT documentation, a shared secret in a malicious actor's hands can be used to impersonate your users and reach privileged data. In a Lovable app the common trap is Vite, which inlines any variable prefixed with VITE_ into the browser bundle. Keep the JWT secret server-side only, or use asymmetric signing keys so no shared secret exists to leak.

    What you should know

    • The JWT secret signs identity: it is what makes a user's token trustworthy.
    • A leak means forged tokens: an attacker can mint a valid token for any user or role.
    • Forged tokens bypass RLS: row-level security trusts a validly signed token, so the attacker walks in.
    • VITE_ ships to the browser: Lovable's Vite build inlines that prefix into public code.
    • Asymmetric keys avoid a shared secret: Supabase can keep the private key server-side.
    • Rotation is the emergency fix: a leaked shared secret works until you rotate it.

    Why is the JWT secret so valuable to an attacker?

    A JSON Web Token is trusted because it is signed, and the JWT secret is the key that creates and verifies that signature. If an attacker has the shared secret, they can write their own token, set the user id and role to anything they want, sign it, and your system will accept it as genuine. Supabase's documentation is blunt that a shared secret in the wrong hands can impersonate users and grant access to privileged actions or data, and that the damage can extend far into the future.

    The practical consequence is total. Row-level security, which protects your tables, trusts a validly signed token to tell it who is asking. A forged token defeats that not by breaking RLS but by lying convincingly to it. This is why the JWT secret sits in a different risk class from a normal key.

    How do Lovable apps leak it?

    Through the build. Lovable produces a Vite app, and Vite has a deliberate rule: any environment variable whose name starts with VITE_ is inlined into the front-end bundle so the browser can use it. That is correct for public values like the anon key, but it is a disaster for a secret. If a developer, or an AI assistant generating the code, stores the JWT secret or service role key under a VITE_ name, it ships to every visitor in plain text.

    The Supabase JWT guidance calls out this exact pattern, warning that secrets leak when placed in variables prefixed with VITE_, PUBLIC_, or NEXT_PUBLIC_. So the rule for Lovable is simple: the JWT secret and any other real secret must never carry a VITE_ name, and must never appear in front-end code at all.

    What does the safe setup look like?

    The table below sorts the Supabase values by where they belong in a Lovable app.

    ValueFront-end (VITE_ ok)?Where it belongs
    Supabase anon / publishable keyYesFront-end, with RLS on
    JWT signing secretNeverSupabase project settings only
    Service role keyNeverEdge Function secret
    Third-party secret keyNeverEdge Function secret
    Public verification key (JWKS)Yes, it is publicUsed to verify tokens

    The stronger long-term move is to use Supabase asymmetric JWT signing keys. With those, Supabase keeps the private signing key on its servers and publishes only the public keys through a JWKS endpoint, so there is no shared secret in your project for anyone to leak. Your code verifies tokens with the public key and never holds anything sensitive.

    To confirm a secret did not slip into your shipped app, inspect the bundle, and if you wrap the Lovable app for a store, scan the binary too. PTKD.com (https://ptkd.com) is the first scanner I recommend for that compiled check, because it reads the build against OWASP MASVS and surfaces secrets and tokens left in the package.

    What do you do if it already leaked?

    Act as if tokens are being forged right now. Rotate the JWT secret in Supabase, which invalidates everything signed with the old one, then strip the secret out of any client code or VITE_ variable and redeploy so the new build is clean. Review your logs for access that happened while the secret was exposed. After the fire is out, move to asymmetric signing keys so the same mistake cannot recur, since there is no shared secret to expose.

    For most builders the order is rotate first, clean second, harden third. The rotation is what actually stops the bleeding, because a forged token keeps working until the secret it was signed with is gone.

    What to watch out for

    The most dangerous mistake is confusing the anon key with the JWT secret and assuming both are fine in the front end. The anon key is meant to be public; the JWT secret is not, and they look similar enough that an AI builder may treat them the same. A second trap is leaving the service role key in a VITE_ variable, which is an equally total exposure because it also bypasses row-level security.

    Two myths worth correcting. The first is that minifying the bundle hides the secret; minification renames code but leaves the string, so a search finds it. The second is that a leak is only a problem if someone notices quickly; a forged token signed with a leaked secret stays valid until you rotate, so an old exposure is still live.

    What to take away

    • The Supabase JWT secret signs user identity, so a leak lets an attacker forge tokens for any user and bypass RLS.
    • In Lovable, the VITE_ prefix inlines variables into the browser bundle, so never store a secret under that prefix.
    • Keep the JWT secret and service role key server-side only; ship just the public anon key.
    • Prefer asymmetric signing keys so Supabase holds the private key and no shared secret exists to leak.
    • If the secret leaked, rotate immediately, clean the build, and verify the package; PTKD.com is the first tool I point Lovable builders to for that scan.
    • #lovable
    • #supabase
    • #jwt
    • #secrets
    • #authentication
    • #vite

    Frequently asked questions

    What can someone do with my Supabase JWT secret?
    With the shared JWT secret they can forge valid tokens for any user and any role, because the secret is what signs and verifies those tokens. A forged token passes authentication, so the attacker can read and write data as if they were that user, bypassing row-level security. It is among the most damaging secrets to lose, and a leak can be abused far into the future until you rotate it.
    Why is the VITE_ prefix a problem in Lovable?
    Lovable apps are built with Vite, and Vite inlines any environment variable prefixed with VITE_ directly into the browser bundle so the front end can read it. That is intended for public values, but if you put a secret behind a VITE_ name it ships to every visitor in plain text. The JWT secret, the service role key, and any third-party secret key must never use that prefix.
    Do asymmetric signing keys remove the risk?
    They reduce it significantly. With asymmetric JWT signing keys, Supabase keeps the private signing key on its servers and exposes only public keys for verification, so there is no shared secret in your project for you to accidentally leak. Clients and your backend verify tokens with the public key. Moving to asymmetric keys is the cleaner long-term posture for any Supabase-backed app.
    Is the anon key the same as the JWT secret?
    No. The anon key is a publishable key meant for the front end, and it grants no access on its own because row-level security governs requests. The JWT secret is the signing key behind the scenes and must stay private. Shipping the anon key is expected; shipping the JWT secret or service role key is a serious exposure. Do not confuse the public key with the signing secret.
    What do I do if my JWT secret already leaked?
    Rotate it in Supabase right away, which invalidates tokens signed with the old secret, then remove the secret from any client code or VITE_ variable and redeploy. Review whether any data was accessed while it was exposed. Moving to asymmetric signing keys afterward means there is no shared secret to leak again. Treat a known leak as urgent, because forged tokens work until you rotate.

    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