The 1-in-4 Report · November 2026
We rebuilt 318 AI-built apps. About 1 in 4 let strangers read personal data.
We took public Lovable and Supabase repos, rebuilt each app’s database from its own migrations in a disposable lab, and read it as an anonymous visitor and as a signed-in stranger. Then we let our pipeline fix 20 more apps on its own, and checked every fix. Here is everything we found, including what didn’t work.
01 · Summary
Five things we found.
- PatchLabs lab study, Nov 2026. 500 public repos sampled, 436 run, 318 built a working database in the lab.
- 106 of 318: 70 (22%) readable by anyone with the app’s public key, 36 (11%) by anyone who signs up.
- Removing businesses’ own public contact details, using the false-alarm rate from the fix study (4 of 24 flagged apps, n=24, 5 Nov 2026).
- Autonomous pipeline on 20 new apps from the study, 9 Nov 2026, n=20. The other 2 went to a person.
- 01
About 1 in 4 public AI-built apps expose personal data to people who shouldn’t see it. Emails, phone numbers, addresses and dates of birth, readable with nothing more than the key every visitor already has, or a throwaway account.
- 02
A third of the leaks need a sign-up, and outside scans can’t see them. 36 of the 106 apps leaked only to signed-in users. The public studies we reviewed test only as a logged-out visitor, so they miss this group entirely.
- 03
The cause is a handful of access-rule patterns. Row level security never switched on, or read rules that say yes to everyone (
using (true)) or to anyone signed in. Each has a stable ID in our finding index. - 04
Most fixes can be written and proven by machine, cheaply. 18 of 20 passed a strict three-identity lab proof with no human; 15 needed only the smallest model. Median model cost $0.46 and 3.5 minutes per app.
- 05
Proven isn’t the same as safe to ship blind. Closing a leak can break a page or needs a business decision. In an earlier study only 4 of 20 fixes were safe to apply with no human review. That’s why an engineer approves every change.
02 · The funnel
From 500 sampled repos to 106 exposing personal data.
We drew a random sample of 500 public GitHub repos with a Lovable/Supabase project layout and ran 436 of them through the lab. In 318 the migrations built a working database; those 318 are the denominator for every exposure number in this report. The 118 that didn’t build are excluded, not counted as safe.
Figure 1 · n=500 sampled
Each stage of the exposure study
Bars to scale. Red means personal data a stranger can read.
- Sampled and run
- Rebuilt (the denominator)
- Readable by anyone
- Readable after signing up
Show the numbers as a table
| Stage | Repos | Share of 318 |
|---|---|---|
| Sampled | 500 | – |
| Run through the lab | 436 | – |
| Built a working database | 318 | 100% |
| Personal data readable by the wrong people | 106 | 33% |
| …by anyone with the public key | 70 | 22% |
| …only by people who sign up | 36 | 11% |
Not every hit is a person’s private data. When fix agents examined 24 flagged apps closely, 4 (about 1 in 6) were a business’s own public contact details, such as a shop’s phone number on its own listing. Applied to the 106, that leaves about 88 apps, or 28%. We quote 25–28% rather than one figure because the false-alarm rate comes from a small sample. Either way it rounds to about 1 in 4.
03 · Who could read it
Two thirds leaked to anyone. One third leaked to anyone who signs up.
Every Supabase app ships a public key inside its pages; access rules decide what that key can read. We tested each rebuilt database as two outsiders: an anonymous visitor holding only that key, and a signed-in stranger, a second test user who owns none of the rows.
Figure 2 · n=318 rebuilt apps
Who could read personal data
Each app counted once, by the widest audience that could read its personal data.
- Anyone with the public key · 70 (22%)
- Only after signing up · 36 (11%)
- Neither · 212 (67%)
Show the numbers as a table
| Who could read personal data | Apps | Share |
|---|---|---|
| Anyone on the internet, with the public key | 70 | 22% |
| Anyone who signs up (and not anonymous visitors) | 36 | 11% |
| Neither | 212 | 67% |
Why the signed-in group matters. If an app lets anyone create an account, “signed in” is not a security boundary: a stranger signs up with a throwaway email and reads everything. These 36 apps look closed from the outside. They are only visible to a test that actually signs in as a second user. See PL-002.
04 · What leaked
Profiles, other people’s records and private messages.
We counted a table as leaking when an outsider could read at least one seeded row with a personal column: email, phone, address or date of birth (and similar names such as dob, ssn or passport). For the 20 apps in the autonomous run we can say what kind of table leaked. They had 37 leaking tables between them.
Figure 3 · n=37 tables in 20 apps, 9 Nov 2026
What the leaking tables held
Grouped by what each table was for. Table names are not published.
Show the numbers as a table
| Kind of table | Tables |
|---|---|
| Other people’s records (staff, sellers, suppliers, players) | 9 |
| User profiles and accounts | 8 |
| Messages, chat logs and notifications | 6 |
| Leads, sign-ups, waitlists and requests | 5 |
| Orders, bookings, sessions and events | 3 |
| Settings and contact configuration | 3 |
| Listings, places and stores | 3 |
The pattern is consistent: the table everyone thinks of (users) is only part of it. Apps also expose the people their users deal with: suppliers, staff rosters, sellers’ contact details, and logs of private conversations.
05 · Why it happens
Four patterns behind the leaks.
AI builders write access rules quickly and make the app work first. The rules that make a permissions error disappear are the same rules that open the table. These are the patterns we see, each with a page showing the vulnerable SQL, a self-check and the fix.
Row level security never switched on
No rules at all. With API access granted, the public key reads and writes everything.
create table public.leads (…); -- no "enable row level security"
A read rule that says yes to everyone
Usually added to fix an error. With no to clause it covers logged-out visitors too.
create policy "Viewable by everyone" on public.profiles for select using (true);
A read rule that only checks “signed in”
Looks careful, isn’t: anyone can sign up.
create policy "Logged in users can view" on public.bookings for select using (auth.uid() is not null);
A public table carrying private columns
The rows are meant to be public (a directory, a listing), but the same table holds emails and phone numbers.
-- public by design: name, city, photo -- leaking: email, phone
Supabase’s own linter deliberately does not flag public read rules, because they are often intended. That is a reasonable choice for a linter, and it is exactly why these leaks survive: only knowing what the table holds, and who should see it, tells you whether using (true) is a feature or a leak. All findings
06 · Mistake or intended?
Most leaks were mistakes. Some were public tables leaking private columns.
Before writing a fix, the agent reads the app’s code to judge intent: which pages read the table, whether they are logged-out pages, and which columns they use. Across the 37 tables in the autonomous run, it reached these verdicts:
Figure 4 · n=37 tables, 9 Nov 2026
Agent verdicts on leaking tables
The verdict decides the shape of the fix.
- Real bug · 28
- Public by design, leaking personal columns · 7
- False alarm · 2
Show the numbers as a table
| Verdict | Tables | What the fix does |
|---|---|---|
| Real bug | 28 | Close the table to everyone but the owner (or staff) |
| Public by design, leaking personal columns | 7 | Keep the rows public, withhold the personal columns |
| False alarm | 2 | Leave it open, and ask the owner to confirm |
In the earlier fix study the agents caught 4 false alarms in 24 apps on their own, all of them a business’s own public contact details (5 Nov 2026, n=24). A pure rules-based scanner can’t make that call. It either flags every public read, and drowns you in noise, or flags none, and misses the leaks above.
07 · The fixes
18 of 20 fixes passed a strict lab proof with no human involved.
On 9 Nov 2026 we gave the pipeline 20 leaking apps from the study that had never been through a fix agent (14 readable by anyone, 6 by any signed-up user). It rebuilt each database, wrote a fix with the smallest Claude model, and ran an independent proof. A fix passes only if the anonymous visitor and the signed-in stranger can read neither the private rows nor the personal columns, and the owner still reads their own row and its personal columns. If the proof fails, the attempt is discarded and the next model tries.
Figure 5 · n=20 apps, 9 Nov 2026
Which model produced the passing fix
Cheapest first: Haiku, then Sonnet, then Opus, escalating only when the proof fails.
- Proven: 15 on the smallest model, 2 on Sonnet, 1 on Opus
- Needs a person · 2
Show the numbers as a table
| Outcome | Apps |
|---|---|
| Passed on the smallest model (Haiku), first try | 15 |
| Escalated to Sonnet, passed | 2 |
| Escalated to Opus, passed | 1 |
| Failed on all three, sent to a person | 2 |
What the fixes looked like
Three shapes, matching the verdicts. These are synthetic examples of each shape, not code from any studied app.
drop policy "Profiles are viewable by everyone" on public.profiles;
create policy "Users can view own profile" on public.profiles
for select to authenticated using ((select auth.uid()) = id);
-- The directory stays public; contact details don't.
revoke select on public.sellers from anon;
grant select (id, shop_name, city, avatar_url) on public.sellers to anon;
-- No SQL. The flagged column is the business's own public phone number.
-- Question for the owner: keep it visible on the listing page? Recommended: yes.
The agent also judged the risk that each fix changes how the site behaves: low for 18 of the 20 apps, medium for 2. It wrote 18 plain-English questions for owners across the 20 apps, each with options and a recommended answer, for the decisions code can’t make.
A separate study on 5 Nov 2026 had already re-run every agent fix by hand: 19 of 20 real fixes worked first time and applied cleanly (n=20).
08 · Cost and time
Median $0.46 and 3.5 minutes per app. Here is the whole spread.
Medians hide tails, so here is every app. Cost is the model spend reported for each fix attempt, summed per app. Time is the agents’ working time, summed across attempts; rebuilding the database and each re-verification added seconds on top (a median of 2 and 3 seconds in this run).
Figure 6 · n=20 apps, 9 Nov 2026
Model cost per app
Log scale, from $0.12 to $15.65. Green: proven. Amber: sent to a person.
- Fix proven
- Needs a person
Show the numbers as a table
| Model cost | Apps |
|---|---|
| under $0.50 | 14 |
| $0.50 to $1 | 1 |
| $1 to $3 | 3 |
| $3 to $10 | 1 |
| over $10 | 1 |
Figure 7 · n=20 apps, 9 Nov 2026
Agent working time per app
Log scale, from 0.8 to 66.7 minutes.
- Fix proven
- Needs a person
Show the numbers as a table
| Agent time | Apps |
|---|---|
| under 2 min | 4 |
| 2 to 4 min | 8 |
| 4 to 10 min | 3 |
| 10 to 30 min | 4 |
| over 30 min | 1 |
14 of 20 apps cost under $0.50. The 15 apps fixed by the smallest model had a median cost of $0.41 and never exceeded $0.76. The tail comes from escalation: the most expensive app went through all three models and cost $15.65 over 67 minutes. That is why every check now has a spend cap: a free check can’t run away.
Why smallest first? In a trial on 3 apps the same fixes cost an average of $2.26 per app on Opus, $0.83 on Sonnet and $0.25 on Haiku (9 Nov 2026, n=3). In that trial Haiku’s first attempts failed 2 of 3 until the verifier’s verdict was made explicit, which is the point: a cheap model is only safe behind an independent proof that refuses to pass a fix that locks the owner out or leaves strangers a way in.
Every run
Ordered by cost. No table names, repos or owners.
| Run | Who could read | Tables | Models tried | Result | Cost | Minutes | Questions | Break risk |
|---|---|---|---|---|---|---|---|---|
| 01 | anyone | 1 | haiku ✓ | proven | $0.12 | 0.8 | 0 | low |
| 02 | signed-in | 1 | haiku ✓ | proven | $0.15 | 1.1 | 0 | low |
| 03 | anyone | 3 | haiku ✓ | proven | $0.25 | 1.9 | 0 | low |
| 04 | anyone | 1 | haiku ✓ | proven | $0.28 | 2.9 | 0 | low |
| 05 | anyone | 2 | haiku ✓ | proven | $0.33 | 1.6 | 0 | low |
| 06 | signed-in | 1 | haiku ✓ | proven | $0.34 | 2.3 | 0 | low |
| 07 | anyone | 1 | haiku ✓ | proven | $0.37 | 2.5 | 0 | low |
| 08 | anyone | 2 | haiku ✓ | proven | $0.41 | 3.4 | 1 | low |
| 09 | anyone | 3 | haiku ✓ | proven | $0.42 | 2.8 | 3 | low |
| 10 | anyone | 2 | haiku ✓ | proven | $0.46 | 9.9 | 1 | low |
| 11 | signed-in | 7 | haiku ✓ | proven | $0.47 | 3.8 | 2 | low |
| 12 | anyone | 1 | haiku ✓ | proven | $0.48 | 4.2 | 1 | low |
| 13 | signed-in | 2 | haiku ✓ | proven | $0.48 | 3.5 | 1 | low |
| 14 | signed-in | 1 | haiku ✓ | proven | $0.48 | 3.5 | 0 | low |
| 15 | signed-in | 2 | haiku ✓ | proven | $0.76 | 5.1 | 0 | low |
| 16 | anyone | 2 | proven | $1.59 | 12.7 | 1 | low | |
| 17 | anyone | 1 | proven | $2.13 | 13.9 | 1 | low | |
| 18 | anyone | 1 | needs a person | $2.85 | 12.0 | 1 | low | |
| 19 | anyone | 1 | needs a person | $6.97 | 29.4 | 2 | medium | |
| 20 | anyone | 2 | proven | $15.65 | 66.7 | 4 | medium | |
| All | 14 anyone · 6 signed-in | 37 | 15 · 2 · 1 · 2 failed | 18 proven | $0.46 med. | 3.5 med. | 18 | 18 low · 2 med. |
Cost is model spend only. It excludes the lab machine and any human time. Prices are those in effect in November 2026.
09 · The two failures
Two apps went to a person. Both for good reasons.
In both cases no model produced a fix that passed the proof, so the pipeline made no fix branch and the report said “needs a person”. That is the behaviour we want: a fix that can’t be proven isn’t presented as one.
A public place, not a private person
The only flagged column was the street address of public sports venues on a map. The agent judged it a false alarm: nothing personal. But the only change that would satisfy the proof was to hide the addresses, which would break the map. So it changed nothing and asked the owner one question, with a recommendation to leave the map as it is.
- Verdict
- False alarm
- Models
- Haiku → Sonnet → Opus
- Cost
- $2.85, 12 minutes
- Lesson
- A strict proof needs an “intended” path. Owners can now mark a table as meant to be public.
Guest orders with no owner
Anyone could read every order, with delivery details. Closing it was easy, but guests could check out without an account, so their orders had no owner to keep access, and the confirmation page re-read the order from the database. A safe fix needed a frontend change plus a business decision: should guests be able to look up an order later?
- Verdict
- Real bug
- Models
- Haiku → Sonnet → Opus
- Cost
- $6.97, 29 minutes
- Lesson
- Some fixes are SQL plus code plus a decision. The report now asks the question and lists the code change.
10 · Where people are still needed
A proven fix still needs an engineer’s yes.
Passing the lab proof means the leak is closed and the owner keeps access, on the database the migrations build. It does not mean the change is safe to deploy with nobody looking. In the 5 Nov study (n=20 real fixes), only 4 of 20 (20%) were safe to apply with no human review. The reasons were rarely the agent’s skill:
Closing the hole breaks a page
A booking form re-reads its own insert; an admin page runs without a real login. The SQL must ship with a small code change.
It’s a business decision
Should sellers’ emails be visible to every buyer? Should new sign-ups see the staff list before approval? Only the owner can answer.
The login is fake
5 of 20 apps checked passwords in the browser (hard-coded users, a PIN in the page). Fixing that properly means adding real sign-in, a small project rather than a patch.
The repo doesn’t match production
Missing migrations or missing frontend code mean someone has to confirm what is actually live.
Most of these are questions for the app’s owner, not engineering work. So PatchLabs writes them as plain-English questions with a recommended answer, and the owner’s engineer approves the final change. Nothing reaches the live app until they do.
11 · Other studies
Why our number is higher than outside scans.
Other public studies of AI-built apps probe live sites from the outside, as a logged-out visitor. That is a useful, different measurement. Ours rebuilds the database and reads it as each kind of user, so it sees two things outside scans can’t: read rules that are open by design (using (true)) and leaks that need a sign-up.
| Study | Method | Tests as | Result |
|---|---|---|---|
| This reportPatchLabs, Nov 2026 | 318 public repos rebuilt from migrations, fake rows | Anonymous visitor and signed-in stranger | 106 of 318 (33%); about 25–28% real personal data |
| Our earlier text scanPatchLabs, 4 Nov 2026 | Static reading of migration files | n/a (no database) | 51 of 493 repos (10.3%) |
| securityscanner.devApr 2026 | Live apps found via certificate logs; 476 Lovable apps among others | Anonymous visitor only | 7.1% of Lovable apps with RLS off on user-data tables |
Third-party figures as published by their authors, checked Nov 2026 (source). The studies use different samples and definitions, so the figures are not directly comparable. Our own text scan undercounted for the same reason outside scans do: it reads rules as written, not what the final database allows.
12 · Limitations
What this study can’t tell you.
Read these before quoting the numbers.
- Public repos only. The sample is public GitHub repos with a Lovable/Supabase layout. Private and commercial apps may be better or worse.
- The lab is only as complete as the migrations. 118 of 436 repos didn’t build and are excluded. Changes made in a dashboard but never saved as a migration are invisible to us, so a repo can differ from the live app in either direction.
- Personal data is detected by column name (email, phone, address, date of birth and similar). Oddly named columns can be missed; public business contacts can be counted, which is why we adjust.
- The 25–28% adjustment comes from a small sample (4 false alarms in 24 apps). Treat it as an estimate.
- Fix results are small samples: n=20 on 5 Nov and n=20 on 9 Nov, one run each. Costs depend on model prices at the time.
- The proof covers reads by three identities. Write rules, functions and storage were checked statically, not proven in the lab.
- Readable is not the same as read. We never touched live apps, so we can’t say whether anyone actually took this data.
- We sell a product that fixes this. The study was designed and run by PatchLabs and has not been peer reviewed. That is why the method and the aggregate data are public.
13 · Disclosure
How we handled other people’s apps.
Code only, never live systems. Every test ran on a copy of the database rebuilt from the repo’s migrations, seeded with fake rows. We never connected to any app’s live site or database, and never saw a real user’s data.
Keys untouched. Where the key scan found secrets in code or history, we recorded only that they existed. We never used, tested or stored a working key.
No app is named. This report and the CSV contain aggregate numbers and anonymised runs only: no repo, owner, app name or table name that could identify an app. We won’t publish a list of affected apps.
If you think your app was in the sample, run a free check on your repo: it repeats the same test and gives you the fix and the proof. To report an error in this research, or to ask that your public repo be left out of future studies, email manraj@patchlabs.dev with the subject “Research”.
14 · Data and citation
Take the data. Check our working.
Cite this report
Dhillon, M. S. (2026). The 1-in-4 Report: personal-data exposure in AI-built apps. PatchLabs, 10 November 2026. https://patchlabs.dev/research/1-in-4
@techreport{patchlabs2026onein4,
author = {Dhillon, Manraj Singh},
title = {The 1-in-4 Report: personal-data exposure in AI-built apps},
institution = {PatchLabs},
year = {2026},
month = nov,
url = {https://patchlabs.dev/research/1-in-4}
}
Quoting a number? Please keep its sample size: “about 1 in 4 of 318 rebuilt public apps (PatchLabs, Nov 2026)”. Journalists and researchers can reach the author at manraj@patchlabs.dev.
Free check
Is your app one of the 1 in 4?
Paste your public repo. We run the same test as this study, then write the fix and prove it.