You asked AI for an endpoint that returns a user’s profile. The profile loads, you shipped. What you actually shipped sends the entire database row to the browser — password hash, email, payment IDs, internal flags and all.
What you shipped
The handler fetches the user and returns the object as-is:

Whatever columns the row has, the API hands over. The UI only shows a name and an avatar, so it looks fine — but the data is all there.
How anyone exploits it
No attack needed. Open the browser’s network tab on your own site and read the response:
{ "id": 42, "name": "Jin", "email": "...", "password_hash": "$2b$...", "stripe_id": "cus_...", "is_admin": false }
Hashes to crack offline, emails to phish, payment IDs, and the exact field name to target for privilege escalation — all handed over for free.
Why you won’t catch it
The page renders correctly because the UI just ignores the extra fields. Nothing looks wrong on screen; the leak lives in the response body, which you only see if you look.
Why AI does it
“Return the user” most directly becomes “return the user object.” Selecting a safe subset of fields is an extra decision the happy path doesn’t need — the page works either way.
The fix is one line
Return only the fields the client should see:

res.json({ id: u.id, name: u.name, avatar: u.avatar })
Better still, select only those columns from the database so the secrets never load at all.
Check your app
- Every endpoint returns an explicit field list, never the raw row or
select *. - Sensitive columns (password hash, tokens, payment IDs, internal flags) are excluded by default.
- Check list/search endpoints too — they leak the same fields in bulk.
The bigger problem
A senior dev shapes API responses by habit and never lets a hash near the wire. But if nobody senior reads the code, the raw object ships — it works in every test, because the UI hides the extra fields. The author and reviewer are the same model with the same blind spot.
That’s the gap Velify is built to close: it reads your project and flags exactly this, in plain language, no terminal.
