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.

Lovable optimizes for “auth works in the preview.” The Supabase project is created, email provider is on, and the AI wires signUp / signInWithPassword. The security toggles that live only in the Supabase dashboard — leaked passwords, minimum length, confirm email — are easy to skip because the generated UI never mentions them. This page is the missing step between “login works” and “login is not a free credential-stuffing target.”

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.

For Lovable apps specifically, stuffing is more valuable when RLS is also weak. A stuffed account that can select * every row via a bad policy is a full data breach, not a single-account incident. Enable leaked-password protection and still run the Supabase RLS Checker.

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.

If you manage Auth via config as code, also confirm the project you edited is the same project URL embedded in your Lovable app (VITE_SUPABASE_URL / NEXT_PUBLIC_SUPABASE_URL). Editing a leftover dev project leaves production unprotected.

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.

You do not need to call HIBP from your Lovable frontend. Client-side HIBP checks are optional UX; the dashboard toggle is the control that cannot be bypassed by skipping your React form.

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.

Also test password change flows if your app has them:

const { error } = await supabase.auth.updateUser({ password: 'password123' });
// Expect failure once leaked-password protection is on

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).

In Lovable-generated UIs, the default error toast often shows the raw API string. Prompt the generator (or edit once) to map auth errors to friendly copy so users do not retry the same breached password five times and then abandon signup.

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.
  • Session lifetime: shorter refresh windows for apps with sensitive data; force re-auth for billing changes.

Cloudflare / edge sketch for token rate limits

# Conceptual — implement as WAF rate rule on
# POST https://<project>.supabase.co/auth/v1/token*
# e.g. 10 requests / minute / IP for grant_type=password

Without something in front, stuffing still burns auth CPU and finds the rare unleaked-but-common password (Summer2024!) that HIBP has not (yet) labeled.

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.
  • Lovable share password. The preview gate is unrelated; see the comparison table below.

Site password vs account password (do not confuse them)

Control What it does What it does not do
Lovable / host share password Blocks casual visitors from a preview URL Does not secure APIs, RLS, or production users
Supabase leaked password protection Blocks breached passwords at signup/change Does not fix missing RLS or open tables
Strong session + MFA Hardens logged-in accounts Does not stop anon key table dumps

Attackers who never use your UI — only curl against PostgREST — ignore the Lovable share password entirely. Enable leaked-password protection for real user accounts, then still run RLS and key scans.

Password reset and invite flows

Lovable apps often generate “forgot password” and invite links via Supabase. Review:

  • Reset links expire (Supabase defaults are usually fine; do not lengthen to weeks).
  • Reset pages do not reflect tokens into analytics query strings.
  • After reset, the new password is subject to leaked-password rules (good — confirm with a test).
  • Invite flows do not pre-create accounts with a shared temporary password in the Lovable chat history or email template.
  • Redirect URLs for recovery are allowlisted in Supabase Auth URL config so open redirects cannot steal tokens.
// Recovery should land on your domain only
await supabase.auth.resetPasswordForEmail(email, {
  redirectTo: 'https://yourapp.com/reset-password',
});

How to verify end-to-end

  1. Toggle leaked password protection in Supabase Auth settings; save.
  2. From the Lovable app (or a minimal script), signUp with password123 → expect failure.
  3. signUp with a long unique password → expect success (or email confirmation pending).
  4. Confirm min length ≥ 10 in the same policy panel.
  5. Confirm email confirmation required for production.
  6. Hit /auth/v1/token with repeated failures from one IP — add rate limiting if unlimited.
  7. Run Vibe Code Scanner — auth is only one surface.
  8. Run Supabase RLS Checker — password policy does not hide open tables.

Common mistakes on Lovable + Supabase auth

  • Enabling the toggle in a dev Supabase project but shipping a different prod project.
  • Relying on client-side password strength meters only (trivial to bypass).
  • Leaving Confirm email off so stuffed accounts are immediately usable.
  • No rate limit on token endpoint → stuffing still burns CPU and finds rare unleaked passwords.
  • Assuming OAuth users are “safe” while password users remain on Password1! forever with no reset campaign.
  • Shipping admin accounts with shared passwords in the Lovable prompt history.
  • Disabling leaked-password protection after a user complains once — better to improve error UX.
  • Testing only in the Lovable preview while production points at another Supabase ref.

Rollout for existing user bases

  1. Enable leaked-password protection + min length for all new passwords.
  2. Announce a password refresh; force reset on next login for accounts older than the policy change if you can flag them.
  3. Offer passkeys/MFA for high-value roles.
  4. Monitor failed logins per IP; block or CAPTCHA after threshold.
  5. Keep RLS and service_role hygiene on the same launch checklist — credential stuffing into an account that can read everyone’s rows via bad RLS is worse than stuffing into a well-scoped account.
  6. After 30 days, sample whether support tickets about password rejection dropped after UX copy improvements (not by turning the feature off).

Common AI-generator mistakes on lovable-password-protection (1)

Generators optimize for demos: open data paths, client-trusted roles, missing rate limits, and secrets in env files that ship to browsers. On lovable-password-protection, re-check those classes after every feature prompt. Search diffs for deleted middleware, new admin routes, and dependency adds. Reject ’temporarily disable auth’ comments without a tracking ticket and expiry.

# smoke verification sketch for lovable-password-protection
curl -s -o /dev/null -w '%{http_code}\n' "$PREVIEW_URL/healthz"

Verification commands and proofs (2)

Proof beats intention. For lovable-password-protection, keep a script or checklist that demonstrates deny paths: anonymous access fails, user A cannot read user B, webhooks reject bad signatures, and bundles lack server secrets. Store the last run date next to the checklist. If the date is older than your release cadence, you are flying blind.

// deny-by-default sketch used near lovable-password-protection
export function assertOwner(userId: string, ownerId: string) {
  if (userId !== ownerId) throw new Error('forbidden');
}

CI and release gates (3)

Encode the minimum bar in CI so humans do not renegotiate under launch pressure: secret scan, dependency audit, unit tests including authz negatives, preview deploy, live security scan failing on criticals. For lovable-password-protection-related paths, add CODEOWNERS so reviews land on people who understand the threat model.

Environment separation (4)

Production credentials must not appear in previews or local agent sandboxes. Separate projects or branches for data stores, separate OAuth redirect allowlists, and separate Stripe test vs live keys. Document the matrix where coding agents can read it so ‘make preview work’ does not copy prod secrets again.

# smoke verification sketch for lovable-password-protection
curl -s -o /dev/null -w '%{http_code}\n' "$PREVIEW_URL/healthz"

Logging, monitoring, and abuse (5)

Log authentication failures, authorization denials, and high-cost endpoints with request ids. Alert on spikes. Rate limit auth and AI proxy routes. For lovable-password-protection, define what ‘abnormal’ looks like before an attacker teaches you under load.

Dependency and supply chain (6)

Lockfiles, immutable CI installs, pinned GitHub Actions, and verification of packages the model suggests. Hallucinated package names are a real path. On lovable-password-protection changes that touch package manifests, require a human to open the registry page once.

// deny-by-default sketch used near lovable-password-protection
export function assertOwner(userId: string, ownerId: string) {
  if (userId !== ownerId) throw new Error('forbidden');
}

Human process and training (7)

New engineers should break a demo app on purpose, fix it, and rescan. That training beats a PDF policy. For lovable-password-protection, keep one golden path example of a secure change and one of a rejected insecure change in internal docs.

# smoke verification sketch for lovable-password-protection
curl -s -o /dev/null -w '%{http_code}\n' "$PREVIEW_URL/healthz"

Operational checklist for lovable-password-protection (8)

Treat lovable-password-protection as a production surface with an owner, a review cadence, and a verification step after every AI-assisted change. Write the owner name in the repo SECURITY.md. Schedule a monthly re-read of controls that touch authentication, secrets, and data access. When an agent opens a PR against this area, require dual-user tests and a preview scan before merge. Keep a short incident appendix: which keys to rotate, which dashboards to check, who communicates with users.

Common AI-generator mistakes on lovable-password-protection (9)

Generators optimize for demos: open data paths, client-trusted roles, missing rate limits, and secrets in env files that ship to browsers. On lovable-password-protection, re-check those classes after every feature prompt. Search diffs for deleted middleware, new admin routes, and dependency adds. Reject ’temporarily disable auth’ comments without a tracking ticket and expiry.

Verification commands and proofs (10)

Proof beats intention. For lovable-password-protection, keep a script or checklist that demonstrates deny paths: anonymous access fails, user A cannot read user B, webhooks reject bad signatures, and bundles lack server secrets. Store the last run date next to the checklist. If the date is older than your release cadence, you are flying blind.

# smoke verification sketch for lovable-password-protection
curl -s -o /dev/null -w '%{http_code}\n' "$PREVIEW_URL/healthz"
// deny-by-default sketch used near lovable-password-protection
export function assertOwner(userId: string, ownerId: string) {
  if (userId !== ownerId) throw new Error('forbidden');
}

CI and release gates (11)

Encode the minimum bar in CI so humans do not renegotiate under launch pressure: secret scan, dependency audit, unit tests including authz negatives, preview deploy, live security scan failing on criticals. For lovable-password-protection-related paths, add CODEOWNERS so reviews land on people who understand the threat model.

Environment separation (12)

Production credentials must not appear in previews or local agent sandboxes. Separate projects or branches for data stores, separate OAuth redirect allowlists, and separate Stripe test vs live keys. Document the matrix where coding agents can read it so ‘make preview work’ does not copy prod secrets again.

Logging, monitoring, and abuse (13)

Log authentication failures, authorization denials, and high-cost endpoints with request ids. Alert on spikes. Rate limit auth and AI proxy routes. For lovable-password-protection, define what ‘abnormal’ looks like before an attacker teaches you under load.

# smoke verification sketch for lovable-password-protection
curl -s -o /dev/null -w '%{http_code}\n' "$PREVIEW_URL/healthz"

Dependency and supply chain (14)

Lockfiles, immutable CI installs, pinned GitHub Actions, and verification of packages the model suggests. Hallucinated package names are a real path. On lovable-password-protection changes that touch package manifests, require a human to open the registry page once.

// deny-by-default sketch used near lovable-password-protection
export function assertOwner(userId: string, ownerId: string) {
  if (userId !== ownerId) throw new Error('forbidden');
}

Human process and training (15)

New engineers should break a demo app on purpose, fix it, and rescan. That training beats a PDF policy. For lovable-password-protection, keep one golden path example of a secure change and one of a rejected insecure change in internal docs.

Operational checklist for lovable-password-protection (16)

Treat lovable-password-protection as a production surface with an owner, a review cadence, and a verification step after every AI-assisted change. Write the owner name in the repo SECURITY.md. Schedule a monthly re-read of controls that touch authentication, secrets, and data access. When an agent opens a PR against this area, require dual-user tests and a preview scan before merge. Keep a short incident appendix: which keys to rotate, which dashboards to check, who communicates with users.

# smoke verification sketch for lovable-password-protection
curl -s -o /dev/null -w '%{http_code}\n' "$PREVIEW_URL/healthz"

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
04
Is this the same as Lovable's site password gate?
No. Lovable/share password protection is a simple gate on the preview URL. Leaked password protection is a Supabase Auth setting that blocks weak/breached user account passwords. You usually want both for different reasons — and neither replaces RLS.
Q&A
05
Does this work with magic links and OAuth?
Leaked password checks apply when a password is set or changed. Magic-link-only and pure OAuth users never set a password in your project, so this toggle does not affect them. Still enable email verification and monitor OAuth redirect URLs.
Q&A
06
Can I enforce this only in production?
The Auth setting is per Supabase project. Use separate Supabase projects (or branches) for dev/staging/prod and enable the control on production at minimum. Do not share one project across environments with mixed policies.
Q&A
07
What error does the client see when a password is rejected?
Supabase returns an auth error whose message typically references a weak or compromised password. Catch it in your signup UI and show a human explanation — users often think the form is broken because the same password works elsewhere.
Q&A
08
Is leaked-password protection enough for production auth?
No. Pair it with minimum length, email confirmation, rate limits on token endpoints, MFA for privileged roles, and RLS on every table. It blocks a common credential class; it does not authorize data access.
Q&A

PASSWORD GATE IS NOT APP SECURITY

A share password only blocks casual visitors. Scan RLS, keys, and auth on the real app surface behind the gate.

14-day free trial · No credit card · Cancel anytime

RUN FULL SCAN