All posts

January 23, 2026 · 5 min read

The Share Link That Almost Showed Someone Else's Data

I built a small internal tool last year to fix a boring problem. Clients kept emailing to ask where things stood, and I kept manually checking a spreadsheet-like database and typing out an answer. So I had an AI coding tool build me a lightweight dashboard on top of that data. One table per client, statuses, notes, a few dates. Nothing fancy. It took an afternoon.

The feature I was proudest of was the share link. Instead of making every client log in, I added a button that generated a unique URL. Click it, get a link, send the link, the client sees their own status page with no password required. It felt like good product design. I tested it, it worked, I moved on to the next thing.

It worked. That was the problem.

For months, nothing went wrong. Clients used their links. I never thought about the feature again, which is exactly the risk with anything you build once and never look at twice.

Then I was setting up two new client records back to back, testing a filter I'd just added, and I had both share links open in different browser tabs. Out of habit, I edited the record ID in one tab's URL to match a pattern I'd noticed in the other. The page loaded. Wrong client's data, right in front of me.

The page loaded fine. That was the whole bug.

The lock that almost fit

Here's what had actually happened. The main app was scoped correctly. If a client logged in, they only ever saw their own record, because the underlying table had proper access rules and I'd tested that path carefully since it was the 'real' login. But the share link was a separate feature, built specifically to skip login. When I'd asked the AI tool to build 'a link anyone can open to view a record,' it built exactly that: a link that opens a record. It checked that the record existed. It never checked that the record matched the link it was supposed to belong to, versus any other record with a similar ID.

That's a quieter bug than the ones that make headlines. In May 2025, researcher Matt Palmer found something much louder in Lovable-built apps connected to Supabase: the row-level security meant to separate one user's data from another's was missing or inverted across a wide sample of live projects, over 170 production apps affected and 303 vulnerable endpoints found across roughly 1,645 scanned projects. That's a door left wide open at the database layer. Mine wasn't that. My table-level security was fine. The bug lived in one feature bolted on top, with its own separate and unchecked path to the same data.

Why sharing features are the blind spot

A share link exists to do the one thing your normal permission system is built to prevent: let someone see data without being logged in as its owner. That means it needs its own explicit rule about who it's allowed to show data to, and that rule doesn't come for free just because the rest of the app is locked down properly. An AI coding tool will happily build the feature you describe. It won't stop and ask whether the feature you described has a hole in it, because from its side the code did exactly what I asked for. I asked for a link that shows a record. It showed a record.

  • Does opening this link check who it belongs to, or just whether the record exists?
  • Are the IDs in the link guessable, sequential, or easy to swap into a similar-looking link?
  • Does the link expire, or does it work forever for anyone who ever gets hold of it?
  • If someone changed one character in this URL, what would they see?

I fixed mine by adding an explicit check: the link now carries a signed token tied to that one record, not just the record's raw ID, and the backend confirms the token matches before it renders anything. I also went back through every other feature in that tool that generates a URL, exports a file, or skips the login screen, because 'share' isn't the only word that means 'this feature intentionally bypasses the normal rules.' Export buttons, print views, public previews, guest access. Same shape, same blind spot.

The part that stuck with me wasn't the bug itself. It was how ordinary the moment was when I found it: two tabs open, one character changed out of habit, no scanner, no alert, just a page that loaded when it should have refused. Every convenience feature you build to skip a login is a small door cut into a wall you already trusted was solid. Worth going back and checking what's actually guarding that door, not what you assumed was guarding it when you built it in an afternoon.

Related reading

Harbova is a security service for apps built with AI tools. Start with a free scan, and if it finds something serious, we can fix it and prove it is closed.