There's a specific bug that shows up in AI-built apps more than almost anything else, and it has a name that sounds far more complicated than the actual problem: insecure direct object reference, usually shortened to IDOR. All it means is this: a logged-in user can see or change data that isn't theirs, just by changing a number or an ID somewhere in a URL or a request. The test for it takes about ten minutes and needs nothing more than two free accounts on your own app.
Why this happens so often
Most apps store records with an ID: an order number, a document ID, a profile ID. A page like /orders/482 usually means "show me order 482." The question that has to get answered somewhere in the code is: does order 482 actually belong to whoever is asking. When an app checks that you're logged in, but never checks that the specific record you're requesting belongs to you specifically, that question never gets asked. AI coding tools are very good at building the "show me order 482" part. Whether they also add the "and confirm this order belongs to the current user" part depends entirely on whether that was described clearly enough to build in the first place, and it's easy to forget to say out loud.
The test, step by step
- Create two separate accounts on your own app. Not two browser tabs logged into the same account, two genuinely different accounts.
- Log in as account one, and find any page that shows a piece of data tied to that account: an order, a document, a saved item, a message, anything with an ID visible in the URL or the network request.
- Note that ID. Then note what a similar ID would look like for a different record (often just one number off, or a similar-looking string).
- Log in as account two, in a separate browser or an incognito window so the sessions don't mix, and try to load account one's specific record by changing the ID in the URL or in a request you send directly.
- Watch what comes back. If you get account one's real data while logged in as account two, that's the bug, in its simplest form.
Don't stop at the page you can see
A lot of apps get the visible pages right, they check ownership before rendering a page in the browser, but forget to add the same check on the underlying API route the page calls. Open your browser's dev tools, find the actual API request the page makes to load that data, and try firing that same request directly, with account two's session but account one's ID. If the page redirected you correctly but the raw API request still hands back the data, the check exists in the wrong layer. It's protecting what you see, not what the server is willing to send.
What a real fix looks like
The fix is almost always the same shape: every query that fetches a specific record needs to filter by both the record's ID and the current user's ID together, not the ID alone. If your database supports row-level rules (Supabase, Firebase, and similar tools all do), that check belongs there too, so it holds even if a future feature forgets to add it again in application code. Run this test on every kind of record your app has, not just the first one you tried. Each one is a separate place the same mistake can hide.