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:

  1. The attacker downloads or buys a “combo list” — typically tens of millions of email:password pairs scraped from previous breaches (LinkedIn 2012, Adobe 2013, Collection #1, the rolling RockYou2024 file, etc.).
  2. The botnet hits your /auth/v1/token endpoint with rotating IPs at modest volume per IP — say 1 attempt every 30 seconds per IP, across thousands of IPs.
  3. 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.
  4. 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)

  1. Open the Supabase dashboard for your Lovable project
  2. Navigate to AuthenticationPolicies (or ProvidersEmail)
  3. Find “Password policy” or “Leaked password protection”
  4. Toggle Enable leaked password protection on
  5. Save
  6. (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:

  1. User submits a password at signup.
  2. Supabase computes the SHA-1 of the password locally.
  3. Supabase sends only the first 5 hex characters of the hash to HIBP’s range API: GET https://api.pwnedpasswords.com/range/<5chars>.
  4. HIBP returns ~500–1000 hash suffixes that share that prefix.
  5. 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.

Run a full VibeEval scan after enabling to verify auth coverage end to end.

COMMON QUESTIONS

01
What is leaked password protection?
Supabase checks new passwords against the HaveIBeenPwned database of breached credentials. If a user tries to sign up (or change password) using a known-leaked password, the signup is blocked with a clear error.
Q&A
02
Does enabling this break existing users?
No. It only checks passwords on *new* signups and *new* password changes. Existing passwords are not re-validated.
Q&A
03
Do I lose usability?
Slightly — maybe 1% of attempted passwords are in the leaked corpus. But those are the exact passwords that get credential-stuffed. Net: big security win, tiny UX cost.
Q&A

SCAN THE WHOLE APP, NOT JUST AUTH

After you fix this setting, run the VibeEval scan for the 242 other things that need attention.

RUN FULL SCAN