ONE FEATURE, ONE REGRESSION: HOW LOVABLE APPS DRIFT AFTER LAUNCH

A clean Lovable app at launch is not durable. Incremental feature additions reliably introduce new authorization gaps — most often a new table without an RLS policy, a new API route without an ownership check, or a new integration with an inlined secret. This catalog documents the regression shapes, the feature types that trigger them, and the structural fix.

This is a longitudinal-shape catalog, not a snapshot. The structural finding is that a clean scan at launch is not durable on Lovable: incremental feature additions reliably introduce new authorization gaps because the generator’s table-creation step does not consistently emit the matching RLS policy. The same logic applies to API routes (missing ownership check) and new integrations (inlined secret).

The point is structural — a one-time pre-launch audit does not protect a Lovable app over time. Continuous scanning on deploy is the only defense that survives the regression curve.

Catalog scope

Field Value
Window Feb 2026 – Apr 2026
Source Anonymized builder-consented tracking of Lovable apps post-launch + gapbench reproducible scenarios
Pattern observed in Both production (with paying users) and demo/pre-launch cohorts
Reproducibility anchor supabase-clone (new table without RLS), multi-tenant-saas (new route without scope), agent-app (new integration with leaked key), ref-rls (clean control)

We do not publish a cohort N, regression-rate percentages, or a weekly attrition curve because the underlying tracking is anonymized and not a uniform random sample of all Lovable apps. The regression shapes themselves — what regresses, why, and how to detect it — are reproducible against gapbench in seconds.

What regresses

The classes of new finding we observe in re-scans, ranked by relative frequency.

Regression class Relative frequency Why
New table without RLS Most common Generator adds the table, does not emit alter table … enable row level security or a base policy
New API route without ownership check (BOLA) Common New handler matches authentication boilerplate but skips the ownership scope
New integration with leaked secret Common New service requires a key; AI inlines VITE_*/NEXT_PUBLIC_* env without warning
New form without input validation Less common Reflected XSS or unsafe SQL where allow-list/parameterization was skipped
Other (CSRF on new mutator, CORS opened on new route) Less common Middleware reapplied inconsistently across new routes

The modal shape is “a new table is added, and the RLS policy that was correct on the existing tables is not added to the new one.” The Supabase dashboard shows the new table without an “RLS Enabled” badge, but no warning is surfaced to the builder.

What features cause regressions

Feature additions ranked by how reliably they introduce a new regression, based on what we observe across the tracked cohort. Some changes add risk; some are neutral.

Feature type Regression risk on next scan
New resource type (new table) Highest
New permission tier (admin role, team plan) High
New integration (Stripe, OpenAI, third-party API) Moderate
File upload Moderate
New page or view (no new data) Low
Cosmetic changes (style, copy) None observed

Adding a new resource type (a new table) is the highest-risk change a builder can make on Lovable. New permission tiers — adding an admin role to an app that previously had only one user type — are the second-highest risk because they introduce a new field that the existing RLS policies do not understand.

The pattern in detail

Across the modal regression shape, the sequence is consistent:

  1. App launches clean. RLS is enabled on every table; policies restrict reads to the row owner.
  2. Builder asks the AI to add a new feature: “let users add line items to invoices”.
  3. The AI creates a line_items table with a foreign key to invoices.
  4. The AI does not add RLS or any policy to the new table.
  5. The Supabase dashboard shows the new table with no RLS badge.
  6. The next deploy ships an app where every line item is publicly readable.

The fix is structural — Lovable’s generator could trivially add alter table line_items enable row level security and a default policy on every table-creation step. As of April 2026, it does not consistently do so.

CWE / OWASP mapping per regression class

Each regression class has a distinct CWE / OWASP fingerprint. Triage and fix are different per class.

Regression class CWE OWASP Fix shape
New table without RLS CWE-862 Missing Authorization A01 · API1 BOLA alter table X enable row level security + base policy in the same migration
New API route without ownership check CWE-639 Auth Bypass via Key · CWE-284 A01 · API1 BOLA Scope the query by auth.uid() = owner_id server-side; return 404 not 403
New integration with leaked secret CWE-798 Hard-coded Credentials A02 · A05 Server-only env; route through backend handler
New form without input validation CWE-20 Improper Input Validation · CWE-79 / CWE-89 A03 Injection Allow-list fields; parameterized queries; output-encode reflected values
Other (CSRF on new mutator, CORS opened on new route) CWE-352 / CWE-942 A05 / A01 Middleware reapplied; cross-origin allow-list scoped

The CWE-862 → CWE-639 split matters operationally: the modal regression is missing authorization (the new table has no policy at all, easy to find with one anon-key probe) while the next-most-common is bypassed authorization (the route exists but does not check the right thing, which requires a two-session cross-account probe to detect). The reason missing-authorization dominates is that adding a table is usually a single AI prompt away, while adding a route handler frequently invokes “authentication boilerplate” that gives the false impression of authorization.

The fix patterns per regression class

The mechanical fix per class is short. The trap is doing the fix once (on the table that surfaced the regression) instead of systemically (on the generator step that creates the pattern).

-- Class 1: every new table needs RLS + a base policy at creation time.
-- Wrap this into a Supabase migration template the generator always emits.
alter table line_items enable row level security;
create policy "owner_select" on line_items for select using (auth.uid() = (select user_id from invoices where invoices.id = line_items.invoice_id));
create policy "owner_modify" on line_items for all using (auth.uid() = (select user_id from invoices where invoices.id = line_items.invoice_id));
// Class 2: every new route handler scopes by the authenticated user.
// Wrap this into a helper or framework convention so it is harder to forget.
const session = await getSession(req);
if (!session) return new Response(null, { status: 401 });
const project = await db.project.findFirst({
  where: { id: req.params.id, owner_id: session.userId, tenant_id: session.tenantId },
});
if (!project) return new Response(null, { status: 404 });
# Class 3: every new integration has its key in server-only env.
# A pre-commit check that scans for VITE_*_KEY / NEXT_PUBLIC_*_KEY catches the
# moment the AI suggests it.
grep -rE 'VITE_[A-Z_]*KEY|NEXT_PUBLIC_[A-Z_]*KEY' src/ && exit 1 || exit 0

The structural fix — and the one that breaks the regression curve entirely — is to put the check itself into a generator template, a helper, or a CI rule, so the AI’s next “add a feature” prompt cannot skip it. Telling the builder to “remember to add RLS” does not work; the regression rate measures exactly how reliably the human-in-the-loop forgets.

The apps that stay clean

The apps in the tracked cohort that did not regress have one of three things in common:

  • They have not added new features after launch (effectively static apps).
  • Their builder manually writes RLS policies after every Lovable iteration and runs a re-scan before each deploy.
  • They have only added cosmetic changes — style updates, copy changes, no new tables.

We have not observed a Lovable app actively adding features over a multi-month window without manual intervention and remaining clean.

What this means

For Lovable builders: assume your app will regress. The cheapest defense is automated re-scanning on deploy. Do not rely on a one-time pre-launch audit.

For Lovable: the longitudinal regression shape is a stronger signal than any snapshot benchmark. If the platform’s marketing says “secure by default”, the empirical test is what happens to a clean app after three feature additions, not what happens at the moment of launch.

For other AI builders: the pattern is structural and likely applies wherever generators incrementally extend a schema. Bolt’s main regression class is secrets-in-bundle on new integrations rather than RLS gaps (because most Bolt apps don’t use Supabase). Cursor’s main regression class is missing ownership checks on newly-added API routes.

Methodology

Source. Anonymized builder-consented tracking of Lovable apps post-launch between Feb 2026 and Apr 2026, plus the deliberately vulnerable scenarios on the gapbench public benchmark that mirror each regression shape. We do not publish a cohort N or regression-rate percentages because the engagement portion is anonymized by design and not a uniform random sample of all Lovable apps.

Snapshots. Periodic automated scan using the same probe set as the main catalog. Findings de-duplicated against the previous snapshot to identify new (regressed) findings.

Feature classification. Surface-level diffs between snapshots — new pages, new forms, new resource types — clustered into discrete “features” by manual review. We acknowledge this is approximate without access to commit logs.

Limits. The regression-shape ranking is directionally meaningful; absolute frequencies would have wide confidence intervals if we tried to publish them with the underlying engagement sizes.

Calibration via gapbench. The regression shapes in this catalog — new table without RLS, new route without ownership check, new integration with leaked key — each map to a deliberately vulnerable scenario on gapbench.vibe-eval.com. A reader can verify the detection (against the public benchmark) without needing access to the tracked cohort URLs. The clean control (ref-rls) demonstrates what “added a table without regressing” looks like when the policy is added in the same migration step.

Reproduce on the public benchmark

The longitudinal cohort apps are not public for builder-privacy reasons. The reproducibility anchor for each regression class is the matched gapbench scenario:

Regression class Equivalent scenario URL
New table without RLS Supabase clone (RLS off on multiple tables) /site/supabase-clone/
New API route without ownership check Multi-tenant SaaS /site/multi-tenant-saas/
New integration with leaked secret Indie SaaS, Agent app /site/indie-saas/, /site/agent-app/
New form without input validation LLM-rendered HTML /site/llm-rendered-html-markdown/
Clean control (added tables without regression) ref-rls /site/ref-rls/

For the structural argument behind why generator-driven schemas regress on every iteration unless the access-control step is templated, see The Supabase service-role key in your frontend bundle and BOLA in AI-generated CRUD.

Sources and references

Citations

VibeEval. One Feature, One Regression: How Lovable Apps Drift After Launch. May 2026. https://vibe-eval.com/data-studies/lovable-regression-longitudinal-study/

RUN IT YOURSELF

Each scenario below is live on the public benchmark. The commands are copy-paste ready. Outputs may evolve as we tune the scenarios; the bug stays.

Modal regression — new table without RLS
curl -s 'https://gapbench.vibe-eval.com/site/supabase-clone/rest/v1/line_items?select=*' -H 'apikey: ANON_KEY'
expected 200 with rows — generator added the table, did not add a policy
BOLA regression — new API route without ownership check
curl -s https://gapbench.vibe-eval.com/site/multi-tenant-saas/api/projects/1 -H 'Authorization: Bearer USER_B_TOKEN'
expected 200 with another user's project — added route, missing scope
Secret regression — new integration ships its key
curl -s https://gapbench.vibe-eval.com/site/agent-app/ | grep -oE 'sk-(proj-)?[A-Za-z0-9_-]{40,}'
expected OpenAI key inlined when the AI-summary feature was added
Clean baseline — ref-rls stays clean across iterations
curl -s 'https://gapbench.vibe-eval.com/site/ref-rls/rest/v1/line_items?select=*' -H 'apikey: ANON_KEY'
expected 200 with [] — adding tables on a properly-RLSed schema does not regress

COMMON QUESTIONS

01
What counts as a 'regression' in this study?
A new critical or high-severity finding present in a later scan that was not present in an earlier scan of the same app. Findings that existed at launch and persist do not count as regressions — only new exposures introduced by changes after baseline.
Q&A
02
How was 'feature addition' measured?
By visible changes to the app's surface — a new page, a new form, a new resource type, a new integration. We did not have access to commit logs or AI-prompt history; we relied on weekly snapshots of the live app and clustered changes into discrete 'features'. The methodology section discusses the limits of this approach.
Q&A
03
Why only Lovable for this study?
Because Lovable is the platform where the longitudinal pattern is most pronounced — its generator adds tables incrementally as features are added, and the policy-creation step does not always run on new tables. Bolt and Cursor have different incrementality patterns we will measure in follow-up studies.
Q&A
04
Were the apps real production apps with real users?
The pattern we describe is observed across both live production apps with paying users and demo/pre-launch apps that builders shared with us for tracking. The regression shape does not appear to be an artifact of demo-app neglect — production apps with paying users regress at a similar rate to non-production apps in the same window.
Q&A
05
What can builders do to prevent regression?
Two things. First, treat every new table or resource as needing its own RLS policy explicitly — do not rely on the AI to add it. Second, run a re-scan on every deploy. The cheap automation here closes the loop: the scanner catches regressions the same day they ship, before they reach users.
Q&A
06
Where can I see the regression shape on a live URL?
https://gapbench.vibe-eval.com/site/supabase-clone/ has the canonical 'new table without RLS' shape — a generator added a table and did not add a policy, so the anon key reads everything. https://gapbench.vibe-eval.com/site/multi-tenant-saas/ has the 'new API route without ownership check' shape. ref-rls is the clean control: same shape, policy added at table-creation time, no leak.
Q&A
07
What CWE numbers does each regression class map to?
New table without RLS: CWE-862 Missing Authorization (OWASP A01 / API1). New API route without ownership check: CWE-639 Authorization Bypass Through User-Controlled Key (A01 / API1). New integration with leaked secret: CWE-798 Hard-coded Credentials (A02 / A05). New form without input validation: CWE-20 Improper Input Validation, often paired with CWE-79 (XSS) or CWE-89 (SQLi). Each class has a different fix surface.
Q&A
08
Does this regression rate apply to Bolt and Cursor?
We expect the *shape* of the pattern to apply (any incremental generator that adds resources without a corresponding access-control step will regress over time) but the *rate* differs because Bolt and Cursor route incremental changes differently. Bolt's main regression class is secrets-in-bundle on new integrations rather than RLS gaps, because most Bolt apps don't use Supabase. Cursor's main regression class is missing ownership checks on newly-added API routes. We will publish per-platform measurements in a follow-up study.
Q&A

DETECT REGRESSIONS AS THEY HAPPEN

VibeEval re-scans on every deploy and alerts on new findings. Catch the regression before users do.

ENABLE CONTINUOUS SCANS