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:
- 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.
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)
- 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.
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:
- 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.
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
- Toggle leaked password protection in Supabase Auth settings; save.
- From the Lovable app (or a minimal script),
signUpwithpassword123→ expect failure. signUpwith a long unique password → expect success (or email confirmation pending).- Confirm min length ≥ 10 in the same policy panel.
- Confirm email confirmation required for production.
- Hit
/auth/v1/tokenwith repeated failures from one IP — add rate limiting if unlimited. - Run Vibe Code Scanner — auth is only one surface.
- 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
- Enable leaked-password protection + min length for all new passwords.
- Announce a password refresh; force reset on next login for accounts older than the policy change if you can flag them.
- Offer passkeys/MFA for high-value roles.
- Monitor failed logins per IP; block or CAPTCHA after threshold.
- 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.
- 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"
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.
- Lovable tech stack — where Auth sits in the architecture.
- Vibe Code Scanner — verifies the whole auth stack end to end on your live app.
- Auth flows: magic / OTP / reset — related auth failure modes.
- Is Supabase Safe? — platform-level RLS and key model.
Run a full VibeEval scan after enabling to verify auth coverage end to end.
COMMON QUESTIONS
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