Stop Lovable shipping your postgres connection string in the Vite bundle
Direct database access with the embedded password — reads and writes every row, bypassing every application-level check.
Why Lovable does this
Lovable builds a Vite single-page app with no server of its own. When you ask it to call an API that needs a key, the only place it can put that key is the browser — so it adds a `VITE_`-prefixed variable, and Vite substitutes the literal value into the bundle at build time.
Confirm it first
Before rotating anything, check whether the key is actually being served. Paste your deployed URL — KeyDrift downloads the same JavaScript a visitor gets and tells you what is in it.
Rotate the key
Do this before changing any code. The key has been served to browsers, cached by CDNs and very likely scraped already — removing it from the source does not un-publish it.
- 1Change the password on the database user immediately.
- 2Check for tables you do not recognise and rows you did not write.
- 3Put the database behind an API. A browser should never hold a connection string.
Move the call to a server
The replacement key must not follow the old one into the bundle, which means the code that uses it cannot live in the browser. Any variable named VITE_… is inlined at build time by design — the prefix is the mechanism, not a mistake.
Before — shipped to the browser
// src/components/Chat.tsx
// Vite substitutes the literal value here at build time.
const key = import.meta.env.VITE_DATABASE_URL;
const result = await sql`select * from ${table}`;After — stays on a Supabase Edge Function
// supabase/functions/query/index.ts — runs on a Supabase Edge Function
Deno.serve(async (request) => {
const key = Deno.env.get('DATABASE_URL')!; // never sent to the browser
const result = await sql`select * from ${table}`;
return Response.json(result);
});
// src/components/Chat.tsx
const result = await fetch('/functions/v1/query', { method: 'POST' }).then((r) => r.json());How KeyDrift detects it
Matches a `postgres://` or `postgresql://` URL carrying a password. Strings using well-known tutorial credentials, or pointing at localhost, are reported lower — the password is still exposed, but the database probably is not.
It will happen again
Lovable builds a Vite single-page app with no server of its own. That has not changed because you fixed this one file — the next feature request produces the same shape of code. Continuous monitoring re-scans every deploy and tells you the moment a key comes back.