ENABLE LEAKED PASSWORD PROTECTION IN LOVABLE
Lovable apps use Supabase auth. Supabase can block passwords that appear in known breach corpora — but it's off by default. Here's the 2-minute fix.
Why This Matters for Lovable Apps
Lovable’s default Supabase auth ships without leaked-password protection. That means a user can sign up with password123 or qwerty or — worse — a password they reused from a breached service. Attackers don’t guess; they replay credentials from public dumps.
In apps scanned by VibeEval, roughly 40% of user accounts could be accessed via credential stuffing against known-leaked passwords.
What credential stuffing actually looks like
A credential-stuffing attack isn’t a person guessing. It’s a botnet running through a CSV:
- The attacker downloads or buys a “combo list” — typically tens of millions of
email:passwordpairs scraped from previous breaches (LinkedIn 2012, Adobe 2013, Collection #1, the rolling RockYou2024 file, etc.). - The botnet hits your
/auth/v1/tokenendpoint with rotating IPs at modest volume per IP — say 1 attempt every 30 seconds per IP, across thousands of IPs. - Roughly 0.1% to 2% of attempts succeed, depending on your user base’s password hygiene. On a 10,000-user app that’s 10 to 200 compromised accounts in one run.
- Compromised accounts are sold ($1 to $50 each depending on the app’s category) or used directly for fraud.
The defence isn’t “make passwords stronger” — users will still reuse. The defence is to refuse passwords that are already in the list. That’s exactly what HaveIBeenPwned’s k-anonymity API does, and that’s what Supabase’s leaked-password setting wires up for you.
The Fix (2 Minutes)
- Open the Supabase dashboard for your Lovable project
- Navigate to Authentication → Policies (or Providers → Email)
- Find “Password policy” or “Leaked password protection”
- Toggle Enable leaked password protection on
- Save
- (Optional) Set minimum password length (recommend 10+)
That’s it. Every new signup and password change is now checked against HaveIBeenPwned at the API level.
How the check actually works (k-anonymity)
Supabase doesn’t send the password to HaveIBeenPwned. The flow is privacy-preserving:
- User submits a password at signup.
- Supabase computes the SHA-1 of the password locally.
- Supabase sends only the first 5 hex characters of the hash to HIBP’s range API:
GET https://api.pwnedpasswords.com/range/<5chars>. - HIBP returns ~500–1000 hash suffixes that share that prefix.
- Supabase checks locally whether the full hash is in the list. If yes, signup is rejected.
Net result: HIBP never sees the password, never sees the full hash, and can’t even tell which user the prefix belongs to. The password leaves the user’s machine exactly once — to your auth backend, the same as any signup.
What Happens at Signup
CLEAN PASSWORD
Accepted. User proceeds through signup normally.
LEAKED PASSWORD
Rejected with clear error: "Password found in known breach. Choose another."
WEAK BUT UNLEAKED
Accepted if it meets min length — length + leak check is the policy.
API ERROR
Signup fails safe. User sees retry prompt.
Verify the setting from the client
After enabling, confirm by attempting a signup with a known-leaked password (use password123 or qwerty):
import { createClient } from '@supabase/supabase-js';
const supabase = createClient(URL, ANON_KEY);
const { data, error } = await supabase.auth.signUp({
email: 'test+pwned@example.com',
password: 'password123',
});
console.log({ data, error });
// Expected: error.message includes "Password is known to be weak and easy to guess"
If the call succeeds, the toggle didn’t save (or you’re hitting a stale Supabase client). Re-check the dashboard and refresh.
Custom error UX
The default Supabase error message is functional but blunt. Catch it and rewrite for your audience:
const { error } = await supabase.auth.signUp({ email, password });
if (error?.message?.toLowerCase().includes('weak')) {
showError(
'That password has appeared in known data breaches and isn\'t safe to reuse. ' +
'Try a unique password — a password manager helps.'
);
return;
}
A clear message reduces support tickets — users who hit this are often confused because the password “worked everywhere else” (which is exactly the problem).
Pair With These Other Settings
A leaked-password check is one layer. Pair with:
- Minimum password length: 10+ characters. Length beats complexity rules; don’t bother with the “1 uppercase + 1 number + 1 symbol” theatre.
- Require email verification: prevents bot signups and limits credential-stuffing damage to verified addresses.
- Rate limits on signup and password-reset: 5/minute/IP at the Edge Function or proxy layer. Supabase’s built-in limits are loose by default.
- Rate limits on
/auth/v1/token: the actual login endpoint — credential stuffing hits this, not signup. Add a Cloudflare rule or Edge Function in front. - Passkeys or OTP: offer passwordless alongside password. Users who choose passkeys are immune to credential stuffing entirely.
- MFA / TOTP: for higher-value accounts (admin, paid tier). Even a leaked password fails without the second factor.
- Anomaly notification: email the user on first login from a new device/IP. Doesn’t prevent compromise, but cuts dwell time from weeks to hours.
What this guide does NOT cover
- Migrating existing weak passwords. Supabase only checks new passwords and password changes. Existing users keep whatever they signed up with. To force rotation, ship an “update password to continue” gate the next time vulnerable users log in — but you can’t selectively detect them without re-checking on login (which Supabase doesn’t currently do automatically). The pragmatic move is a one-shot “we updated our password policy, please reset” email campaign.
- Server-side credential stuffing detection. Even with leaked-password protection on, attackers will try unleaked-but-common passwords. Detect via failed-login spikes and IP velocity — Supabase doesn’t ship this; you’ll need a log pipeline (Logflare, Datadog) and an alerting rule.
- OAuth / social-login accounts. Users who signed in with Google/GitHub never set a password in your system. Their security depends on the provider’s policies, not yours.
- Account-recovery social engineering. Leaked-password protection has nothing to do with “I forgot my password” flows being abused. That’s a separate, equally important hardening pass.
Related tools and guides
- Supabase RLS Checker — even with auth locked down, missing RLS makes the data behind it readable anyway.
- Lovable Safety Guide — the full set of Lovable defaults that need flipping.
- Vibe Code Scanner — verifies the whole auth stack end to end on your live app.
Run a full VibeEval scan after enabling to verify auth coverage end to end.
COMMON QUESTIONS
SCAN THE WHOLE APP, NOT JUST AUTH
After you fix this setting, run the VibeEval scan for the 242 other things that need attention.