The health app that served a stranger its patient's medication list
This is the second in a series where we take apart a real data exposure we found in the wild, with the app anonymized, so the pattern is clear and the next person avoids it. This one is a symptom-tracking health app, and its own backend handed a logged-out visitor real medical data about a real person.
What was exposed
Logged out, with no account and no password, the app's public data API returned one patient's medication list (the names and doses they were tracking), a running log of their symptoms and flare-ups, and the details of upcoming appointments including clinic specialty and location.
We confirmed the payload was real patient data, not demo seed data, and then stopped. Any one of these is a serious privacy failure. Together they are the kind of profile that should never leave a signed-in session, because a clinic specialty next to a medication list is enough to infer someone's diagnosis.
The anatomy: a public app ID is not public data
Apps built fast with an AI assistant on a backend-as-a-service store their data in named entities (think tables, like Profile, Appointment, or MedicationLog) that the frontend reads directly from the browser. To do that, every app has a public application ID that ships in its own frontend code. That ID is meant to be visible. Anyone can read it in developer tools.
The public ID is safe only if one thing is true: each entity has a rule that says who may read which records. The platform supports exactly that, so a signed-in user reads only their own records. The trap is that the permissive setting, anyone can read, is the path of least resistance while you are building, and it is the setting an AI assistant will leave in place unless someone asks it not to.
There is no bug here and no attack. The backend did exactly what it was configured to do. The configuration was simply wrong, on data that happens to be someone's health record.
How we found it, and what we did not do
We loaded the app the way any visitor does and noted its public application ID from its own frontend. We asked the public entity API, logged out, for the smallest response that proves the data is real: enough to confirm a live record, then stop.
We kept nothing, paged through nothing, and downloaded no one's records. No credentials were guessed, no rate limit was tripped, no vulnerability was exploited. The finding is the readability. You do not need to harvest a patient's history to prove the door is open.
Why this is everywhere right now
The platforms that let one person ship a real product in a weekend are genuinely good. But they make the database the first thing you build and the last thing you secure, and their most permissive access setting is the one that keeps you moving fastest. Turning on per-user access for every entity that holds personal data is exactly the safe-by-launch step an AI assistant will skip if nobody asks.
So the same misconfiguration shows up again and again, and when the app happens to be a health tracker, the leak is a medication list instead of a mailing list. We saw the identical pattern beyond health in the same sweep: one app exposed its account, profile, and transaction records to logged-out requests, and another handed over a directory of people's names, education, and employment. Same root cause, different blast radius.
The sixty-second fix
If you built on a backend-as-a-service, this is quick to close.
- Open every entity that holds personal data and set its read access to the record's owner only, not anyone, and not any logged-in user.
- Remove any anonymous or public read rule on those entities entirely.
- Re-check the way an attacker would: make the same request logged out. It should come back empty or forbidden, not full.
If an AI built it, ask it directly
Paste this to your assistant: list every entity whose read access is public or all-users, and change each one to owner-only. It will do it in a minute. The gap was never skill. It is that nobody thought to ask.
What we did about this one
Because this is health data, the responsible path is to notify the team that runs the app privately, in plain language, with the exact fix, no bounty demand and nothing retained, and to say nothing that could identify them. We are not naming them, and we will not. The point of this series is not to embarrass a small team who missed a setting. It is to show, concretely, how one default turns a working health app into a privacy breach, so the next builder changes the setting before a stranger reads a patient's medication list.
One permissive default, left as it ships, is the difference between a working health app and a privacy breach. If your app reads its database from the browser, set every personal-data entity to owner-only and re-check with a logged-out request.
Is your database open right now?
Run the free database exposure check, or a full scan, no signup. Where it finds an open table, it proves it with the exact request and a screenshot.