Object, function, and property authorization
Turn identities, tenants, objects, roles, and lifecycle transitions into a reproducible permission matrix.
- 01Establish permission rule
- 02Seed two controlled identities
- 03Replay one changed dimension
- 04Verify durable effect
- 05Revoke and repeat
- 06Record smallest violation
At each step: retain the control → record the observation → continue only while the next boundary is understood.
Used in these playbooks#
Setup and invariant
Use accounts A and B, two private tenants, and one synthetic document per tenant. Create a viewer role only if the product supports it. Record the exact build, API version, actor, tenant membership, document visibility, and expected permission rule. The invariant is: the server authorizes the actor, action, object, and each protected property together. UI visibility is supporting context; product policy establishes the boundary. Horizontal, vertical, and context-dependent authorization are separate dimensions. Access-control models.
Numbered test procedure
- Capture a working baseline. As A, create private O1 containing
BB-A-ONLY-01; as B create O2 containingBB-B-ONLY-01. Save each normal read response and a normal reversible rename. Keep separate browser profiles and credentials. Confirm anonymous access to O1 fails. - Test the object dimension. Replay A's O1 read using B's credentials, changing nothing else. Then keep B's identity and replace O1 with O2 as a positive control. Substitute only known controlled identifiers, including parent tenant IDs, child IDs, attachment IDs, and export-job IDs. A nonexistent synthetic ID is the negative control for error handling; it does not replace the cross-account test.
- Test the function dimension. Give B a documented viewer role in A's test tenant. Capture an owner-only operation as A, such as renaming a private test folder, and replay it as B. If the product permits viewer renames, select an actually restricted operation. Inspect durable state from A's browser after the request completes.
- Test the property dimension. Start with a permitted profile update. Add exactly one known server-controlled property from schema or source, such as a role field in the isolated tenant. Read back the stored object, then test one corresponding restricted action. Repeat separately for unauthorized response properties. Automatic binding of request fields can create mass-assignment issues; read-side property disclosure is a different mechanism. OWASP mass assignment.
- Test lifecycle and alternate delivery. Remove B's membership, replay the previously successful request, and check an existing subscription or queued export. Repeat the same permission rule at list/search, download, batch, and versioned endpoints where present. Use two-item batches containing O1 and O2; do not enumerate identifiers.
- Interpret and clean up. Match markers, object IDs, committed changes, and resulting permissions. A 200 with an empty list, a 202 for a rejected job, or a redirect without private content is not proof. Remove synthetic records and memberships after preserving minimal evidence.
Command card
These illustrative routes require your local replica. Create A.header and B.header containing each test account's complete Authorization: Bearer … header; protect the files and exclude them from reports. curl can load headers from a file. curl manual.
mkdir -p evidence/authz
chmod 600 A.header B.header
curl -q --noproxy '*' --max-time 10 --header @A.header \
-D evidence/authz/a.h -o evidence/authz/a.json \
http://127.0.0.1:8000/api/documents/O1
curl -q --noproxy '*' --max-time 10 --header @B.header \
-D evidence/authz/b.h -o evidence/authz/b.json \
http://127.0.0.1:8000/api/documents/O1
curl -q --noproxy '*' --max-time 10 --header @B.header \
-o evidence/authz/control.json \
http://127.0.0.1:8000/api/documents/O2
Report threshold and checklist
Report a demonstrated unauthorized read, action, or protected-property change. Attach the intended rule, both actors' roles, minimal request difference, and independent state verification. UUID disclosure, shared objects, intentionally public exports, stale UI state, and identical status codes are common false positives.
- Ownership and visibility confirmed before testing.
- Object, function, and property decisions tested separately.
- Positive and negative controls captured.
- Background output and revoked membership checked.
- No unrelated customer records accessed.
Local curl examples use --noproxy '*' to bypass inherited proxy variables; -q alone only disables the default curl configuration file. Configure intentional interception separately. curl manual.
Vulnerability reverse references#
- Broken object-level authorization (BOLA / IDOR) — An actor can access another owner’s protected object by supplying its identifier.
- Broken function-level authorization (BFLA) — A lower-privilege actor invokes a function reserved for another role.
- Broken property authorization: private response fields — An otherwise permitted object response includes fields the actor is not entitled to read.
- Mass assignment of server-controlled properties — Automatic request binding lets a user modify a property that should be set only by trusted server logic.
- Residual access after explicit session revocation — A revoked credential or removed membership retains access beyond the product’s applicable revocation guarantee.
- Workflow order or approval bypass — An actor can complete a protected workflow without its required prior approval or immutable conditions.
- GraphQL resolver or field authorization failure — A GraphQL path or protected field bypasses the permission enforced for the same object elsewhere.
- WebSocket message or subscription authorization failure — A valid connection performs unauthorized per-message actions or receives a private subscription.
- Mobile link handler trusts routing as authorization — An externally supplied custom or universal/app link reaches a protected client operation without validating the route input and current security context.
- Agent tool accepts unauthorized object or tenant parameters — A tool trusts caller-supplied object or workspace identifiers instead of enforcing the authenticated principal’s authority.
- RAG retrieval or citation resolver crosses tenant boundaries — Search filters, chunk retrieval or citation download omit an ownership decision required for the effective caller.
- RAG cache or fresh retrieval ignores revoked access — A new retrieval or cache response exposes protected content after its applicable permission revocation has taken effect.
- Contract initializer permits unauthorized ownership or configuration — A reachable initialization path lets an ordinary actor establish or replace privileged state outside the intended deployment lifecycle.
- Contract upgrade authority can be bypassed — An actor outside the upgrade policy can change a proxy’s execution target or equivalent privileged configuration.
- Parameter or JSON parser disagreement crosses a security check — Validation or authorization uses one interpretation of a request value while the protected operation uses another.
- Authentic integration event applied to the wrong tenant or object — A valid provider event is misbound to a local tenant, installation, mode or resource the event is not authorized to modify.
- Agent conversation, checkpoint or memory crosses ownership boundaries — Persisted agent state or its resume/export path is accessible or mutable by a principal outside its intended owner or sharing grant.
Nearby shared procedures#
Authentication, recovery, federation, and session lifecycle · Trace input into queries, commands, and templates · Server-side fetching and network trust boundaries · Browser execution, cross-origin reads, and forged actions · Uploads, downloads, paths, archives, and XML · Workflow invariants, replay, idempotency, and races · REST, GraphQL, gRPC, WebSocket, and SSE permission parity · Proxy normalization, cache isolation, and request boundaries