Most APIs get the first authorization check right. When you ask for record 88213, the server confirms that record is yours before it answers. Broken object property level authorization is the bug that lives one level deeper. The endpoint checks that you may touch the object, then hands back or accepts every field on that object without asking whether you may touch each one. So you read a property you were never meant to see, or you write a property you were never meant to change, just by adding or reading extra keys in the JSON.
Object level versus property level
It helps to put the two side by side, because they are siblings and people mix them up. Broken object level authorization, often called BOLA or IDOR, is about the whole object. You ask for someone else’s note by changing an id, and the server forgets to check ownership, so it hands you their note. The fix is an ownership check on the object.
Broken object property level authorization assumes that check already passed. You are looking at your own note, your own profile, your own order. The failure is that the object has fields with different sensitivity, and the endpoint treats them as one flat blob. Some fields are yours to read and write. Some are internal, or admin only, or set by the system. When the code reads them all out together, or accepts them all in together, the per field rule is missing.
- Object level (BOLA / IDOR): can this user access this object at all?
- Property level (BOPLA): can this user read or write this specific field on an object they are already allowed to access?
OWASP lists this as API3:2023, and it folds together two older names you may know: excessive data exposure on the read side, and mass assignment on the write side. Same root, two directions.
The read side: excessive data exposure
Picture Acme Notes, a typical SaaS app. A user opens their profile, and the front end calls the API to load it. The endpoint checks that the caller owns the profile, which it does, then serializes the whole user row and sends it back:
GET /api/v1/users/me
Authorization: Bearer <user token>
200 OK
{
"id": 4471,
"name": "Dana Ruiz",
"email": "dana@example.com",
"plan": "pro",
"isVerified": true,
"role": "user",
"internalNotes": "flagged by billing, do not refund",
"riskScore": 82,
"referredBy": "partner_ad_channel_7"
}
The user interface only draws the name, email, and plan. The other fields are never shown on screen. But the API sent them anyway, and anyone can open the network tab or call the endpoint directly and read internalNotes, riskScore, and the rest. Nothing was hacked. The server just answered with more than the caller was allowed to see. The object check passed. The property check was never written.
This is easy to ship by accident. A developer returns the model object, or writes SELECT *, and every column the database holds rides along in the response. The UI hides the extra fields, so in a browser it looks correct. The exposure only shows up when you read the raw JSON.
The write side: mass assignment
The same flat handling on the way in gives you mass assignment. The user edits their display name, and the client sends a PATCH. The endpoint confirms the user owns the record, then binds the incoming JSON straight onto the object and saves it:
PATCH /api/v1/users/me
Authorization: Bearer <user token>
{
"name": "Dana R.",
"role": "admin",
"isVerified": true,
"plan": "enterprise"
}
The form on the page only lets you change your name. But the request is just JSON, and you can put anything in it. If the server does something like user.update(request.body), it happily writes role, isVerified, and plan along with the name. You just made yourself an admin, marked yourself verified, and upgraded your own plan, on an object you were allowed to edit. The object level check said yes. No field level check said no.
The endpoint asked whether you could touch the object. It never asked whether you could touch each field on it. That gap is the entire bug.
How to spot broken object property level authorization
You find this bug by comparing what a field is against what the endpoint lets you do with it, one field at a time. A few concrete moves:
- Read the full response, not the rendered page. Call the endpoint directly and look at every key in the JSON. For each one, ask whether this user role should be allowed to see it. Fields like
internalNotes,riskScore,role, or anything that looks system set are the ones to question. - Send fields the form never offered. On any write endpoint, add extra keys to the body:
role,isVerified,ownerId,balance,isAdmin. Then read the object back and check whether the value stuck. - Look for the shape of the code. A response built from a whole model, or a write that binds the entire request body, is the tell. The safe versions name each allowed field explicitly.
This is the kind of check that belongs in any review of your access control logic, right next to the object level ownership checks you already run.
How to prevent it
The fix is the same idea on both sides: decide, per field, what each role may read and write, and enforce it instead of trusting the object level check to cover everything.
- Use explicit output schemas. Do not serialize the raw model. Define a response shape that lists exactly the fields this caller may see, and build the response from that. If a field is not in the schema, it cannot leak.
- Allowlist writable fields. Never bind the whole request body. Accept a named set of fields the user may change, and drop everything else.
roleandisVerifiedshould never be in that set for a normal user. - Separate views by role. An admin may need
internalNotes. A normal user must not. Different roles get different schemas, checked on the server, not hidden by the client. - Test the property level, not just the object level. Add a test that a normal user cannot read the hidden fields and cannot write the privileged ones, even when they own the object.
None of this is exotic. It is the discipline of treating each property as its own access decision, instead of letting one object level check speak for the whole record.
Broken object property level authorization survives because it hides behind a check that already passed. The object was yours, so the code stopped asking questions, and the extra fields slipped through in both directions. This is exactly the kind of assumption based flaw an autonomous security researcher is built to find, because it comes from testing what an app quietly trusts rather than replaying a fixed list of payloads. You can read more about that approach on our about page.
Frequently asked questions
What is broken object property level authorization?
It is an API access control flaw where the server checks that you can reach an object but not each individual property on it, so you can read fields you should not see or change fields you should not control. It is listed as API3 in the OWASP API Security Top 10.
How is BOPLA different from BOLA or IDOR?
BOLA and IDOR are about reaching a whole object that belongs to someone else. BOPLA is about the properties inside an object you can already reach. You own the record, but the app lets you read or write a field on it that should be off limits, like a role or a balance.
What are the two main forms of BOPLA?
Excessive data exposure, where a response returns properties the user should never see, and mass assignment, where a request writes properties the user should never set, such as isAdmin or isVerified.
How do you prevent broken object property level authorization?
Validate every property on both read and write against the caller’s role, use explicit allow lists for which fields can be returned or updated, and never bind a request body straight onto your data model.
Put an autonomous researcher on your own systems
UnboundCompute is an autonomous security researcher that reasons about how an application fits together and proves the access control and injection bugs it finds. We are opening a small number of founding design partner seats: private early access pointed at a staging target you choose, and a say in what it looks for. If your team ships software worth pressure testing, apply to the design partner program.
