ASVS 5.0 V8.1.2 (Level 2) requires authorization documentation that defines field level read and write restrictions, based on who is asking and on attributes of the object, such as its status.
Why it matters
Mass assignment and excessive data exposure live at the field level. If nobody wrote down that a customer may read an order total but never write it, nobody can test for it, and a client sending extra JSON properties may change it.
How to implement it
Build a matrix per resource. For each field list the read and write rules and any state conditions:
| Field | Customer read | Customer write | Support read | Support write | State rule |
|---|---|---|---|---|---|
| shipping_address | yes | yes | yes | no | write only while status is pending |
| total | yes | no | yes | no | never writable by clients |
| internal_notes | no | no | yes | yes | none |
Keep it in the repository and link it from the API schema. Then enforce it in code with explicit allow lists:
CUSTOMER_WRITABLE = {"shipping_address"}
def apply_update(order, payload, actor):
allowed = CUSTOMER_WRITABLE if actor.role == "customer" else set()
unknown = set(payload) - allowed
if unknown:
raise PermissionError("Fields not writable: " + ", ".join(sorted(unknown)))
if "shipping_address" in payload and order.status != "pending":
raise PermissionError("Order is locked")
order.shipping_address = payload["shipping_address"]
How to test it
For each row, send a request as a role that should be denied and confirm a rejection, not a silent drop. Check responses for fields the role may not read.
Common mistakes
- Binding request bodies straight onto models.
- Documenting reads but not writes.
- Forgetting state dependent rules.
Quick check
Is a schema enough documentation?
Only if it encodes permissions and state conditions per role. A plain type schema does not.