The model binder does not know which field is sensitive
IDOR is reading the wrong record. Mass assignment is writing the wrong field — and it shares a root: the server trusts something the client sent without asking whether the client may set it.
The mechanism is almost too simple: you declare an action that accepts a User and ASP.NET Core does exactly what it was designed to do — assign every field in the JSON to every matching property. It has no way to know that Role differs from DisplayName in severity. To it, both are just strings.
The result is a bug class with a very recognisable shape: a valid request, no unusual payload, and one extra field.
PATCH /api/users/meContent-Type: application/json { "displayName": "Thong", "role": "Admin" }API3's full name is Broken Object Property Level Authorization, and that long name says the right thing: authorisation is not only per object but per property. Same user, same record, and there are still fields they may read but not write.
Two directions, and both are API3:
| Direction | Name | Example |
|---|---|---|
| Writing a field you may not set | Mass assignment | {"role":"Admin"}, {"isVerified":true}, {"balance":9999} |
| Reading a field you may not see | Excessive data exposure | Returning passwordHash, internalNotes, stripeCustomerId because the DTO is the entity |
The second direction deserves attention because it is quieter: nothing errors, the response is still 200, and the surplus data sits in JSON the UI never renders — so nobody sees it, except whoever opens DevTools.
Comments
Commenting needs an account with at least one completed lesson. That condition is what keeps this thread worth reading: every point belongs to someone who can be asked back, and reputation accrues over time.
You can still read every comment below without an account. Signing in brings you back to this exact spot, not to the top of the page.
Loading comments…