WEB / WEB-14.S04
Object, function and property authorization
Follow capability, resource relationship and writable/readable fields separately through a note rename.
1. Core · Mechanism
Read every scenario without motion
Title rename
- Known note intent
The client carries intent to rename a known owned public note; public read is not rename permission.
- Atlas client
- Rename intent; title pending
- Notes application
- Title=Tea & Bread; no request
- Request prepared
The finite note/context request is prepared; supplied policy booleans are not actual client authority.
- Atlas client
- Rename request ready; fixed title
- Notes application
- Title=Tea & Bread; no request
- Request at app
The selected rename request reached the Application. Title is still Tea & Bread; function, object and property authorization decisions are pending.
- Atlas client
- Rename request ready; fixed title
- Notes application
- Request arrived; Title=Tea & Bread
- Local function gate
The server evaluates explicit business function permission independently of route names or hidden UI.
- Atlas client
- Rename request ready; fixed title
- Notes application
- Function allowed; Title=Tea & Bread
- Local object gate
After function permission passes, resource relationship/tenant context is checked; earlier denial creates no mutation.
- Atlas client
- Rename request ready; fixed title
- Notes application
- Object allowed; Title=Tea & Bread
- Local field/commit
Title write/read projection applies only after all required gates pass, preserving server-owned context.
- Atlas client
- Rename request ready; fixed title
- Notes application
- All gates allowed; Title=Bread & Tea
- Result prepared
The fixed result is prepared with a title-only accepted body or absence of a protected body after denial.
- Atlas client
- Rename request ready; fixed title
- Notes application
- Result response ready; title=Bread & Tea
- Result at client
The result has arrived; protected title data is delivered only on acceptance, without a real DOM or database.
- Atlas client
- Result arrived; title=Bread & Tea
- Notes application
- Result response ready; title=Bread & Tea
Object denied
- Known note intent
The client carries intent to rename a known owned public note; public read is not rename permission.
- Atlas client
- Rename intent; title pending
- Notes application
- Title=Tea & Bread; no request
- Request prepared
The finite note/context request is prepared; supplied policy booleans are not actual client authority.
- Atlas client
- Rename request ready; fixed title
- Notes application
- Title=Tea & Bread; no request
- Request at app
The selected rename request reached the Application. Title is still Tea & Bread; function, object and property authorization decisions are pending.
- Atlas client
- Rename request ready; fixed title
- Notes application
- Request arrived; Title=Tea & Bread
- Local function gate
The server evaluates explicit business function permission independently of route names or hidden UI.
- Atlas client
- Rename request ready; fixed title
- Notes application
- Function allowed; Title=Tea & Bread
- Local object gate
After function permission passes, resource relationship/tenant context is checked; earlier denial creates no mutation.
- Atlas client
- Rename request ready; fixed title
- Notes application
- Object denied; Title=Tea & Bread
- Local field/commit
The object gate denied acceptance, so the title stays Tea & Bread. No mutation or protected response projection is created without all required permissions; another positive gate cannot override this denial.
- Atlas client
- Rename request ready; fixed title
- Notes application
- Acceptance conditions not satisfied; Title=Tea & Bread
- Result prepared
The fixed result is prepared with a title-only accepted body or absence of a protected body after denial.
- Atlas client
- Rename request ready; fixed title
- Notes application
- Result response ready; no protected body
- Result at client
The result has arrived; protected title data is delivered only on acceptance, without a real DOM or database.
- Atlas client
- Result arrived; denied; no body
- Notes application
- Result response ready; no protected body
Function denied
- Known note intent
The client carries intent to rename a known owned public note; public read is not rename permission.
- Atlas client
- Rename intent; title pending
- Notes application
- Title=Tea & Bread; no request
- Request prepared
The finite note/context request is prepared; supplied policy booleans are not actual client authority.
- Atlas client
- Rename request ready; fixed title
- Notes application
- Title=Tea & Bread; no request
- Request at app
The selected rename request reached the Application. Title is still Tea & Bread; function, object and property authorization decisions are pending.
- Atlas client
- Rename request ready; fixed title
- Notes application
- Request arrived; Title=Tea & Bread
- Local function gate
The server evaluates explicit business function permission independently of route names or hidden UI.
- Atlas client
- Rename request ready; fixed title
- Notes application
- Function denied; Title=Tea & Bread
- Local object gate
Function permission was denied, so the object gate does not execute. The title remains unchanged; no allow decision is invented for an unevaluated relationship.
- Atlas client
- Rename request ready; fixed title
- Notes application
- Object not evaluated; Title=Tea & Bread
- Local field/commit
The function gate denied acceptance, so the title stays Tea & Bread. No mutation or protected response projection is created without all required permissions; another positive gate cannot override this denial.
- Atlas client
- Rename request ready; fixed title
- Notes application
- Acceptance conditions not satisfied; Title=Tea & Bread
- Result prepared
The fixed result is prepared with a title-only accepted body or absence of a protected body after denial.
- Atlas client
- Rename request ready; fixed title
- Notes application
- Result response ready; no protected body
- Result at client
The result has arrived; protected title data is delivered only on acceptance, without a real DOM or database.
- Atlas client
- Result arrived; denied; no body
- Notes application
- Result response ready; no protected body
Property denied
- Known note intent
The client carries intent to rename a known owned public note; public read is not rename permission.
- Atlas client
- Rename intent; title pending
- Notes application
- Title=Tea & Bread; no request
- Request prepared
The finite note/context request is prepared; supplied policy booleans are not actual client authority.
- Atlas client
- Rename request ready; fixed title
- Notes application
- Title=Tea & Bread; no request
- Request at app
The selected rename request reached the Application. Title is still Tea & Bread; function, object and property authorization decisions are pending.
- Atlas client
- Rename request ready; fixed title
- Notes application
- Request arrived; Title=Tea & Bread
- Local function gate
The server evaluates explicit business function permission independently of route names or hidden UI.
- Atlas client
- Rename request ready; fixed title
- Notes application
- Function allowed; Title=Tea & Bread
- Local object gate
After function permission passes, resource relationship/tenant context is checked; earlier denial creates no mutation.
- Atlas client
- Rename request ready; fixed title
- Notes application
- Object allowed; Title=Tea & Bread
- Local field/commit
The property gate denied acceptance, so the title stays Tea & Bread. No mutation or protected response projection is created without all required permissions; another positive gate cannot override this denial.
- Atlas client
- Rename request ready; fixed title
- Notes application
- Acceptance conditions not satisfied; Title=Tea & Bread
- Result prepared
The fixed result is prepared with a title-only accepted body or absence of a protected body after denial.
- Atlas client
- Rename request ready; fixed title
- Notes application
- Result response ready; no protected body
- Result at client
The result has arrived; protected title data is delivered only on acceptance, without a real DOM or database.
- Atlas client
- Result arrived; denied; no body
- Notes application
- Result response ready; no protected body
ACTORS · STATE · DATA FLOW
Which operation on which object?
Duru wants to rename public note-A from Tea & Bread to Bread & Tea. Public-read policy may permit reading it, while rename is a separate action requiring an owner/tenant relationship. The server combines subject, object, action and context from trusted sources; the client reference only selects an object. Object-level authorization asks whether this subject can perform this action on this resource. IDOR/BOLA describes insufficient relationship enforcement; choosing an integer, UUID or string supplies no permission. Being logged in also establishes no note-A relationship. The ledger compares one owned note and a supplied object-denied outcome without discovering other notes or generating identifiers.
Function permission differs from object permission
The notes.rename function requires an explicit product-policy grant. Function-level authorization evaluates access to that business capability; the object gate separately checks the selected resource relationship while using it. An administrative-looking URL, hidden button or route name is not enforcement. A role can grant a function without granting access to every tenant object. In the function-denied row objectRelation=true still supplies no action capability. Apply controls at server enforcement points on every relevant request. A shared policy module improves consistency but cannot make client-supplied context trustworthy. Missing actor or policy information has an explicit deny outcome rather than automatic malicious attribution.
Property boundaries operate in both directions
Even after object and function gates pass, the caller cannot necessarily write or read every property. Atlas maps rename input only to title; owner, tenant and publicationState are server-owned context/workflow fields. Type/schema validation establishes an ordinary title string, not permission over publication state. Mass assignment breaks the boundary when generic input binding carries unpermitted internal fields into a business object. Property authorization and explicit input projection constrain that propagation. For output, select fields permitted for this response instead of serializing the entire object. In this all-gates-before-mutation fixture, property denial creates no body or mutation; real transactions, concurrency and side effects must preserve the same decision boundary.
2. Red · Trust & Impact
Read every scenario without motion
Function deny
- The rename-operation scope was selected
Duru wants to rename note-A in tenant-A to Bread & Tea. Public visibility or object ownership does not automatically satisfy every gate for this write operation.
- Rename context
- case=function-denied
- Permission gates
- Gates not evaluated
- Record/projection boundary
- Title: Tea & Bread
- Function and object relationships were separated
Object relation is true, but functionGrant=false. Selecting an owned note does not grant the notes.rename capability.
- Rename context
- case=function-denied
- Permission gates
- Function=false; object=true
- Record/projection boundary
- Title: Tea & Bread
- The property boundary was read separately
propertyGrant=true does not compensate for the failed function gate. A writable title field is not the function capability itself.
- Rename context
- case=function-denied
- Permission gates
- Property=true; function failed
- Record/projection boundary
- Title: Tea & Bread
- All gates were applied before commit
Policy mutationAfterAllGates gives expectedAccepted=false. Regardless of which layer failed, this branch does not apply the title change.
- Rename context
- case=function-denied
- Permission gates
- Accepted=false
- Record/projection boundary
- Mutation=false; Tea & Bread
- Body and delivery were withheld
expectedBody=null and expectedDelivery=false remain. A small denial body is not shown as undoing an earlier side effect; this branch has no mutation in the first place.
- Rename context
- case=function-denied
- Permission gates
- Decision denied
- Record/projection boundary
- Body=null; delivery=false
- Public read was not promoted to write permission
The note being public and owned by Duru does not remove this negative gate. Function, object and property are distinct questions; showing or hiding a UI button adds no authority to the server decision.
- Rename context
- case=function-denied
- Permission gates
- Function denial
- Record/projection boundary
- Title unchanged; no body/delivery
Property deny
- The rename-operation scope was selected
Duru wants to rename note-A in tenant-A to Bread & Tea. Public visibility or object ownership does not automatically satisfy every gate for this write operation.
- Rename context
- case=property-denied
- Permission gates
- Gates not evaluated
- Record/projection boundary
- Title: Tea & Bread
- Function and object relationships were separated
Function grant and object relation are true. These positive gates do not remove separate write/read permission decisions for the property set.
- Rename context
- case=property-denied
- Permission gates
- Function=true; object=true
- Record/projection boundary
- Title: Tea & Bread
- The property boundary was read separately
propertyGrant=false withholds mutation and response projection. JSON typing or ORM binding does not establish property authorization.
- Rename context
- case=property-denied
- Permission gates
- Property=false
- Record/projection boundary
- Title: Tea & Bread
- All gates were applied before commit
Policy mutationAfterAllGates gives expectedAccepted=false. Regardless of which layer failed, this branch does not apply the title change.
- Rename context
- case=property-denied
- Permission gates
- Accepted=false
- Record/projection boundary
- Mutation=false; Tea & Bread
- Body and delivery were withheld
expectedBody=null and expectedDelivery=false remain. A small denial body is not shown as undoing an earlier side effect; this branch has no mutation in the first place.
- Rename context
- case=property-denied
- Permission gates
- Decision denied
- Record/projection boundary
- Body=null; delivery=false
- Public read was not promoted to write permission
The note being public and owned by Duru does not remove this negative gate. Function, object and property are distinct questions; showing or hiding a UI button adds no authority to the server decision.
- Rename context
- case=property-denied
- Permission gates
- Property denial
- Record/projection boundary
- Title unchanged; no body/delivery
ASSUMPTION · BOUNDARY · CONTROL
Overinterpreting references and capabilities
A normal function call carries a known note selection and authenticated context to the server. The broken assumption is that permission to call the function covers every action on the selected object. Failure requires an absent resource relationship or tenant-scope check for the action; impact follows that read, rename or business operation’s scope. Reading a public title is not public rename permission, and an unpredictable UUID does not complete policy enforcement. The object-denied fixture therefore preserves the title even with functionGrant=true. The function-denied fixture separately lacks capability despite an owned object. Action-bound server policy and reliable resource context support both gates independently of UI or route naming.
Trusting every field of an allowed object
Normal rename carries an editable title; object ownership does not establish control over server-owned publishing state. The broken assumption is that validated JSON or an ORM model is automatically an authorized property map. Failure requires unknown/restricted input binding into internal state or output expanding without an authorized read projection. Impact can be incorrect publication state or unnecessary property disclosure for that operation; the note fixture contains no administrative credentials. The property-denied row exposes all gate outcomes while producing neither a write nor a protected response body. Closed input fields, actor/action-specific write allowlists and explicit read DTOs work together; a small denial body alone does not undo transaction side effects.
3. Blue · Secure development & defense
Read every scenario without motion
Title projection
- Normal rename evidence was selected
The normal row has true functionGrant, objectRelation and propertyGrant. Review examines the accepted command and returned field set together, rather than only an allow boolean.
- Permission observation
- Normal rename row
- Projection/context review
- Projection not examined
- Evidence conclusion
- State outcome not examined
- The write-field allowlist was read
inputWritableFields contains only title. Owner, tenant and publicationState are server-owned fields; a caller-supplied title does not make them automatically editable.
- Permission observation
- Input: title only
- Projection/context review
- Owner/tenant/workflow not writable
- Evidence conclusion
- State outcome not examined
- The command projection was compared
Input and command projections carry title=Bread & Tea. The operation’s permitted write fields govern consumption, rather than schema types or the model’s full field list.
- Permission observation
- Input: title only
- Projection/context review
- Command: title=Bread & Tea
- Evidence conclusion
- State outcome not examined
- The response read projection was separated
responseReadableFields and the response projection contain only title. Writing a field and exposing the whole object body are different permission decisions.
- Permission observation
- Input: title only
- Projection/context review
- Response: title only
- Evidence conclusion
- Owner/tenant excluded from response
- The unchanged context was compared
ownerAfter=Duru, tenantAfter=tenant-A and publicationStateAfter=published remain. The title mutation has not spread to these authoritative context fields.
- Permission observation
- Mutation: title changed
- Projection/context review
- Owner/tenant/workflow retained
- Evidence conclusion
- Projection scope consistent
- Projection evidence was scoped
This ledger shows title rename and field-projection outcomes. It adds no evidence of actual ORM execution, transaction concurrency or enforcement across every tenant handler.
- Permission observation
- Known: title rename
- Projection/context review
- Known: limited command/response
- Evidence conclusion
- Runtime enforcement needs separate evidence
Context missing
- The unknown-evidence row was selected
actorMissing=true and policyMissing=true mark missing trusted authorization context. Knowing the object as note-A does not fill that gap.
- Permission observation
- Actor/policy missing
- Projection/context review
- Gate evidence missing
- Evidence conclusion
- Outcome not examined
- Missing and false gates were separated
A functionGrant=false row is a known policy denial. Here actor or policy resolution is missing; unknown evidence is not presented as a known hostile action.
- Permission observation
- Actor/policy missing
- Projection/context review
- Insufficient evidence
- Evidence conclusion
- Attribution unknown
- The deny-default decision was preserved
expectedAccepted=false stops processing on missing context. An unpredictable ID, public title or UI role text is not substituted for trusted actor/policy input.
- Permission observation
- Actor/policy missing
- Projection/context review
- Accepted=false
- Evidence conclusion
- Attribution unknown
- Mutation and body fields were read
expectedMutation=false and expectedBody=null are negative data boundaries. Missing telemetry does not manufacture permission, and this record does not invent an attack that occurred.
- Permission observation
- Actor/policy missing
- Projection/context review
- No mutation; body=null
- Evidence conclusion
- No acceptance evidence
- The correct correlation source was requested
A trusted decision record for the same actor, operation, resource scope and policy revision is required. Adding raw bearer tokens or the full object body to logs does not resolve the gap.
- Permission observation
- Missing context
- Projection/context review
- Trusted decision evidence required
- Evidence conclusion
- UNKNOWN: policy evaluation
- The missing-context conclusion was bounded
The known decision is no acceptance and no mutation. Which actual grant was or was not satisfied, and hostile attribution, remain unknown until source evidence arrives.
- Permission observation
- Known: context missing
- Projection/context review
- Known: mutation/body withheld
- Evidence conclusion
- UNKNOWN: grant/attribution
IMPLEMENTATION · SECURITY CONTROL · VERIFICATION
Correlate all three gates to the same action
Audit context separates actor/session validation alias, policy revision, business operation, resource/tenant, function grant, object relationship and property-set decisions. Permitted field names and reason codes may suffice instead of raw bearer tokens or entire objects. Baseline is Duru renaming the owned public note title; the other rows are finite negative controls. A 403/404 choice depends on product disclosure policy and alone does not prove which gate executed. Correlate the server decision with transaction commit and response projection. Missing telemetry does not establish a failed attack; the unknown-evidence row stops acceptance without inventing hostile activity. Fixture decisions are not endpoint or database audit evidence.
Permission regression measures state consequences
Test state consequences as well as an allow/deny return: title before/after, preserved owner/tenant/publicationState, response keys and absence of denied delivery/body. Reevaluate role or policy-version changes against object relationships rather than assuming equal read/write field grants. The server command DTO separates accepted title data from internal context, using explicit projection rather than spreading arbitrary body fields into a model. If resource version or relationship can change between authorization and mutation, concurrency/transaction design also matters. Fixed native object selection demonstrates projection but not real ORM, persistence transactions or tenant enforcement. Durable controls retain the relevant context across handlers and asynchronous work.
NOW APPLY IT TO THE CASE
How do function and property permissions differ on an owned object?
Renaming Tea & Bread requires function, object-relationship and property policy. Accepted command and response fields are separated from server-owned context.
Separate decisions for verified actor, tenant relation and requested action in the case. Do not substitute authentication or proof success for object permission.
Open the related case file ↗READ THE EXAMPLE TOGETHER
Three permission gates ledger
Select a field and examine what it supports and where the evidence ends.
Read the raw artifact and field explanations
{
"profile": {
"actor": "Duru",
"tenant": "tenant-A",
"operation": "rename-own-note",
"authenticatedDeclared": true,
"expectedFunction": "notes.rename",
"note": {
"id": "note-A",
"owner": "Duru",
"tenant": "tenant-A",
"title": "Tea & Bread",
"visibility": "public",
"publicationState": "published"
},
"desiredTitle": "Bread & Tea",
"inputWritableFields": [
"title"
],
"responseReadableFields": [
"title"
],
"actualEndpoint": false,
"actualStore": false,
"actualNetwork": false
},
"rows": [
{
"case": "normal",
"functionGrant": true,
"objectRelation": true,
"propertyGrant": true,
"expectedAccepted": true,
"expectedMutation": true,
"expectedAfterTitle": "Bread & Tea",
"expectedBody": {
"title": "Bread & Tea"
},
"expectedDelivery": true
},
{
"case": "object-denied",
"functionGrant": true,
"objectRelation": false,
"propertyGrant": true,
"expectedAccepted": false,
"expectedMutation": false,
"expectedAfterTitle": "Tea & Bread",
"expectedBody": null,
"expectedDelivery": false
},
{
"case": "function-denied",
"functionGrant": false,
"objectRelation": true,
"propertyGrant": true,
"expectedAccepted": false,
"expectedMutation": false,
"expectedAfterTitle": "Tea & Bread",
"expectedBody": null,
"expectedDelivery": false
},
{
"case": "property-denied",
"functionGrant": true,
"objectRelation": true,
"propertyGrant": false,
"expectedAccepted": false,
"expectedMutation": false,
"expectedAfterTitle": "Tea & Bread",
"expectedBody": null,
"expectedDelivery": false
}
],
"policy": {
"denyDefault": true,
"functionRequiresExplicitGrant": true,
"objectRequiresActorTenantAndRelationship": true,
"propertyRequiresAllowedWriteAndReadProjection": true,
"mutationAfterAllGates": true,
"publicReadDoesNotGrantRename": true
},
"fieldLedger": [
{
"field": "title",
"input": "caller-provided ordinary string with type/length validation",
"writeAllowed": true,
"responseAllowed": true
},
{
"field": "owner",
"input": "server-owned relationship context",
"writeAllowed": false,
"responseAllowed": false
},
{
"field": "tenant",
"input": "server-owned resource scope",
"writeAllowed": false,
"responseAllowed": false
},
{
"field": "publicationState",
"input": "server-owned publishing workflow state",
"writeAllowed": false,
"responseAllowed": false
}
],
"projections": {
"input": {
"title": "Bread & Tea"
},
"command": {
"title": "Bread & Tea"
},
"response": {
"title": "Bread & Tea"
},
"ownerAfter": "Duru",
"tenantAfter": "tenant-A",
"publicationStateAfter": "published"
},
"unknownEvidence": {
"actorMissing": true,
"policyMissing": true,
"expectedAccepted": false,
"expectedMutation": false,
"expectedBody": null,
"attribution": "insufficient evidence; not automatic hostile activity"
},
"boundaries": {
"unguessableIDGrantsAccess": false,
"publicReadGrantsWrite": false,
"UIHiddenFunctionProtected": false,
"schemaTypeAloneGrantsProperty": false,
"ORMBindingIsAuthorization": false
}
}- profile
- Known actor/action and initial public note.
- rows
- Independent function/object/property outcomes.
- fieldLedger
- Write/read and server-owned field classes.
- projections
- Explicit title command/response preserve context.
- unknownEvidence
- Missing evidence denies without attack attribution.
Supplied policy outcomes and ordinary public note projection; no endpoint, ID enumeration, ORM or database transaction executes.
Two reality checks
A UUID substitutes for object-level authorization.
Selection is not permission; evaluate action and resource relationship at the server.
Schema-valid input can be bound to every object property.
Type validity, field permissions and server-owned context are separate.
YOUR TURN
Work through this story.
Predict the outcome, find the evidence boundary, and explain it in your own words.
Duru targets an owned note and title is writable, but functionGrant=false. Is rename performed?
- Yes. Owning the object grants every function.
- No. There is no mutation; Tea & Bread is retained.
Read the explained answer
No. There is no mutation; Tea & Bread is retained. — The function-denied row has objectRelation=true and propertyGrant=true, yet expectedAccepted=false. Other grants do not supply the missing function grant.
Why does the accepted rename command contain only title while owner and tenant remain unchanged?
Selected lesson artifact fields; teaching example
- fieldLedger[0]
- {"field":"title","input":"caller-provided ordinary string with type/length validation","writeAllowed":true,"responseAllowed":true}
- fieldLedger[1]
- {"field":"owner","input":"server-owned relationship context","writeAllowed":false,"responseAllowed":false}
- fieldLedger[2]
- {"field":"tenant","input":"server-owned resource scope","writeAllowed":false,"responseAllowed":false}
- projections
- {"input":{"title":"Bread & Tea"},"command":{"title":"Bread & Tea"},"response":{"title":"Bread & Tea"},"ownerAfter":"Duru","tenantAfter":"tenant-A","publicationStateAfter":"published"}
- The title projection is permitted; owner and tenant are server-owned context.
- Every string property in the schema is automatically writable.
Read the explained answer
The title projection is permitted; owner and tenant are server-owned context. — The field ledger permits write/read projection only for title. Command and response contain that field alone; ownerAfter and tenantAfter remain unchanged.
When actor and policy evidence are missing, expectedMutation=false and expectedBody=null. Why is that neither proof of hostile activity nor ID-based security?
Read the explained answer
Mutation and delivery are withheld because required actor/policy bindings cannot be established. That does not prove hostile input. An unguessable object ID does not replace function/object/property authorization, and a hidden UI function is not a server control. This artifact explains supplied policy outcomes rather than testing a real endpoint or store.
□ I did not classify missing evidence as hostile activity.
□ I did not substitute IDs or UI visibility for authorization.
Open the application console · request / response / browser
Also open request, URL, cookie and DOM examples
Sources and scope
- OWASP API1:2023 — Broken Object Level AuthorizationIs the API Vulnerable?: requested action on requested object; object versus function distinction; How To Prevent: per-record policy checks
- OWASP API3:2023 — Broken Object Property Level AuthorizationIs the API Vulnerable?: read/write properties; How To Prevent: explicit property selection, avoid generic input binding, update allowlist and response schema
- OWASP API5:2023 — Broken Function Level AuthorizationIs the API Vulnerable?: business function not inferred from path; How To Prevent: explicit function grants and shared deny-default enforcement
- OWASP Authorization Cheat SheetRecommendations: Enforce Least Privileges; Deny by Default; Validate the Permissions on Every Request; attribute/relationship context