You asked the model for a route that returns the current user. It wrote `return user`. That one line is both sides of the bug: every property on the row flows out on GET, and every property on the row flows in on PATCH. Attackers read the fields they shouldn't see and write the fields they shouldn't touch.
API3 covers two sides of the same mistake: exposing properties the caller shouldn't see, and letting them write properties they shouldn't touch. The database row and the API contract are not the same thing. Bugs happen when developers treat them as if they are.
What your AI actually built
The model spread the user record into the response. Email, name, avatar — but also passwordHash, stripeCustomerId, internal notes, isAdmin, role, and an internal twoFactorSecret field somebody added last week. The API sends all of it, because nothing filters.
On the write side, the update route does `db.user.update({ where: { id }, data: req.body })`. Whatever the client POSTs lands in the database. Send `{ role: "admin" }` in the body and congratulations, you are one.
Both halves come from the same root cause: the API treats the database row as the API contract. There is no separate shape for 'what this caller is allowed to read' or 'what this caller is allowed to write.'
How it gets exploited
A normal user signs up, logs in, and loads their profile page with the dev tools open.