Skip to main content
Stackbastion

Draft, not yet published

My Lovable app got hacked: what to do in the first hour

7 July 2026· 6 min read · by Stackbastion

You noticed something wrong. Strange rows in your database, a login you don’t recognize, a bill that spiked overnight, or a message from someone who says they got into your app. Your heart’s racing and you want to fix everything at once. Don’t. The first hour has an order, and doing it in the wrong order can destroy the evidence you’ll need later or lock you out of your own fix.

Here’s the calm version of what to do.

Why this happens on Lovable apps

Lovable builds real apps fast, and most of them ship on top of Supabase for the database and auth. That combination is powerful, but it moves two dangerous things very close to the surface: your database and your keys. Two mistakes cause the majority of Lovable app breaches.

The first is a leaked key. A service-role key or another privileged secret ends up in the frontend bundle, where anyone who opens the page can read it. With a service-role key, an attacker bypasses every row-level security rule you have and reads or writes your whole database directly.

The second is row-level security that was never turned on. Supabase tables are only protected once you write policies for them. A table with RLS disabled, reachable through the public anon key, is readable by anyone who finds the endpoint. AI code generators are good at building features and bad at remembering this step, because the app works perfectly in a demo either way.

So when a Lovable app gets hit, it’s usually not some exotic zero-day. It’s one of these two, and both are fixable.

How to fix it

Work top to bottom. Don’t skip ahead.

Minute 0 to 5: stop the bleeding, but keep evidence.

Your instinct is to delete the bad data. Resist it for five minutes. First take a snapshot of the current state so you have a record of what happened.

# Dump the current database before you change anything.
# Replace the connection string with your Supabase pooler URL.
pg_dump "postgresql://postgres:[PASSWORD]@[HOST]:5432/postgres" \
  --no-owner --format=custom --file=incident-snapshot-$(date +%Y%m%d-%H%M).dump

If you can’t run pg_dump, at minimum go to the Supabase dashboard and note the timestamp, screenshot the suspicious rows, and check the Auth logs for unfamiliar sign-ins. Evidence first, cleanup later.

Minute 5 to 15: rotate every key.

Assume every secret the app has ever used is now public. In the Supabase dashboard, under Settings then API, roll the service-role key. Then rotate anything else the app touches: Stripe secret keys, any third-party API keys, SMTP credentials, and the database password itself under Settings then Database. A rotated key is the only key you can trust after a breach.

While you’re there, if you use Stripe, log into the Stripe dashboard and check for new API keys or webhook endpoints you didn’t create. Attackers add their own so they keep access after you rotate yours.

Minute 15 to 30: lock the front door.

Now close the two common holes. Check whether row-level security is on for every table:

-- Any row where rowsecurity is false is exposed to the anon key.
select schemaname, tablename, rowsecurity
from pg_tables
where schemaname = 'public'
order by rowsecurity asc, tablename;

For any table showing rowsecurity = false, turn it on and add a policy. If you’re not sure what the right policy is yet, the safe move under attack is to enable RLS with no permissive policy, which denies all access through the public key until you write the real rules:

alter table public.your_table enable row level security;
-- With RLS on and no policy, the anon key gets nothing. Lock first, refine later.

Then re-run the exposed-key check. Fetch your own frontend bundle and grep it for secret shapes, the same way you would in the 5-minute exposed-keys check.

Minute 30 to 45: force everyone to re-authenticate.

If an attacker stole a session or created an account, you want them out. In Supabase, revoke refresh tokens so active sessions die, and reset passwords for any account you can’t vouch for. If your user table is small, a forced password reset for everyone is the blunt but safe choice.

Minute 45 to 60: assess the damage and decide on disclosure.

Now open your incident snapshot and figure out what was actually reached. What tables were readable? Did they contain personal data, names, emails, anything covered by GDPR? If personal data of EU users was exposed, the clock on your 72-hour breach-notification duty may already be running. Write down the timeline while it’s fresh: when you noticed, what you saw, what you changed.

Or, we do it for you

If you’re staring at a live breach and don’t want to make the wrong call under pressure, that’s exactly what our Rescue service is for: we contain it, rotate keys, close the holes, and give you a written timeline you can hand to anyone who asks. If the dust has settled and you just want to know where else you’re exposed, get a free production audit.

FAQ

Should I take the app offline the moment I notice?

Usually no, not as the first move. Pulling it offline before you snapshot the state can destroy evidence you’ll want, and it doesn’t help if the attacker already has your keys. Snapshot first, rotate keys second, and only take it fully offline if the attack is actively causing damage you can’t stop any other way.

The attacker only read data, they didn’t change anything. Is that still a breach?

Yes. Under GDPR, unauthorized access to personal data counts as a breach even if nothing was altered or deleted. Read-only access to a table of user emails is still a reportable event. Don’t talk yourself out of the timeline because “they only looked.”

How do I know if they left a way back in?

Check three places: new database users or roles you didn’t create, new API keys or webhooks in Stripe and other services, and any new admin accounts in your own app’s user table. Rotating keys closes the front door, but a patient attacker plants a spare. The database dump you took in minute 0 helps you compare before and after.

Can this happen again after I fix it?

Only if you leave the root cause in place. A rotated key that gets re-committed to the frontend is exposed again within a day. The permanent fix is moving privileged calls to a server you control and keeping RLS on for every table, so the same mistake can’t reopen the same hole.