What Is Field-Level Authorization in an API?
Field-level authorization checks each property an API user can read or change. Without it, record access can expose prices, owners and order state.
Field-level authorization is the check that decides whether a user may read or change one specific property of an object, such as a price, owner or status. It sits below the check that decides whether the user can reach the object at all. Without it, anyone allowed to edit a record can potentially edit every field on that record. The exploited Drupal Commerce flaw CVE-2026-118539 is a recent example.
What is field-level authorization?
Field-level authorization is an access rule applied to an individual property of an object instead of the whole object. It answers the question "may this user change this field?" after the application has already answered "may this user touch this record?"
A store order shows why both questions matter. A customer should be able to edit their own cart. That permission covers the shipping address and item quantities. It should not cover the order total, the unit price, the paid amount, the workflow state or the owner. All those values live on the same record, so a rule written only at record level cannot separate them.
How does it differ from object-level authorization?
Object-level authorization decides which records a user can reach, and field-level authorization decides which properties of those records the user can read or change. An application needs both, because passing the first check says nothing about the second.
Think of them as layers. Authentication establishes who the caller is. Route or function checks decide whether the caller may use an endpoint. Object checks stop the caller from opening another customer's record, a failure usually called BOLA. Field checks then limit what the caller can do inside a record they legitimately hold.
Why user interfaces hide the problem
Most web forms show only the fields a user is meant to edit. A customer sees a quantity box and never sees a price box, so the application looks safe during a normal walkthrough. The form is only a presentation choice. If the server accepts a write to any field on the object, a client that talks to the API directly can send fields the form never displayed.
This is why bugs of this type tend to surface through APIs. Generic APIs expose entity types and their fields automatically, which makes them productive and also widens what a client can attempt. Drupal's documentation notes that its JSON:API module exposes all non-internal entity types by default and that it respects field access. In other words, the API is only as strict as the field rules behind it. The same documentation recommends auditing field access, especially when write operations are enabled.
What OWASP calls this weakness
OWASP lists this in its API Security Top 10 for 2023 as API3, Broken Object Property Level Authorization. The category merges two earlier entries:
- Excessive data exposure: an endpoint returns sensitive properties the user should not see.
- Mass assignment: an endpoint lets a user modify, add or delete sensitive properties they should not control.
The read side and the write side have the same cause. The application authorized the object and then trusted everything about it. OWASP lists data disclosure, data loss, data corruption and in some cases privilege escalation or account takeover as possible results.
How the Drupal Commerce case played out
Ostorlab's analysis of the Commerce Core patch describes entity-level access control with no field-level control beneath it. An account allowed to edit its own products, promotions or carts could also change fields linking those objects to things it did not own, and customers could reach restricted order fields on their own carts. The fix adds a per-entity list of restricted fields, checked by access handlers before a write is accepted.
Merchants saw the business effect first: orders with prices such as $0.01, and orders that looked normal on price but had other problems. The lesson for reviewers is that an authorization flaw does not always show up as a data breach. Here it showed up as bad numbers in an order system, so our guide on how to audit Drupal Commerce orders for fraud starts from the order data.
How do you enforce field-level authorization?
Enforce it on the server with an explicit list of the fields each role may write, and reject or ignore everything else. Client-side forms and hidden inputs provide no protection, because a caller can bypass them.
The practical controls, drawn from OWASP's prevention guidance, are:
- Use allow lists for writes. Name the properties a client may update. A new field then starts out protected, instead of open until someone remembers it.
- Avoid automatic binding. Do not map client input straight onto internal objects.
- Compute sensitive values on the server. Totals, paid amounts and workflow states should come from server logic, not from client input.
- Return only what the caller needs. Avoid generic serialization of whole objects, and validate responses against a schema as a second check.
- Check every interface. REST, JSON:API, GraphQL, admin routes and custom controllers may each reach the same object. A rule added to one path does not protect the others.
Third-party extensions need the same attention. Ostorlab points out that contributed Commerce modules adding their own reference fields must lock those fields down separately, because the core fix only covers the fields it lists.
How do you test for missing field checks?
Test on a staging copy with a low-privilege account by attempting to change each sensitive field through the API, then confirm in the database that the value did not change. Never run these tests against production order data.
Checking the response code alone is not enough. An API can return success while ignoring a field, or return an error after a side effect has already happened, so inspect the stored state afterward. Build the test matrix from your data model: list each role down one side and each sensitive field across the top, then record the expected and actual results. Add these cases to your automated regression tests so a later release cannot reopen the gap.
Where to start
Pick the objects that carry money, ownership or workflow state, because that is where a missing check does the most damage. List who can write to each field today, then compare that list with who should. Pair this with a business control that does not trust the record at all: verifying payment before fulfillment limits the loss if a field check ever fails.