Access Control — Vertical, Horizontal & Context-Dependent
What is Access Control?
Access control is the application of constraints on who or what is authorized to perform actions or access resources. In web applications it depends on three things:
- Authentication — confirms the user is who they say they are
- Session management — identifies which HTTP requests belong to that user
- Access control — determines whether the user is allowed to perform the action
Broken access controls are common and often critical. Design decisions are made by humans — the potential for errors is high.
Types of Access Control
1. Vertical Access Control
Restricts access based on privilege level:
| Role | Level | Permissions |
|---|---|---|
| Owner | High | Everything — settings, delete, manage users |
| Admin | Mid-High | Manage users and content, no ownership changes |
| Editor | Mid-Low | Create and edit content, no user management |
| Viewer | Low | Read only |
Attack — Vertical Privilege Escalation:
Attacker is logged in as a viewer. They observe an admin endpoint in network traffic:
POST /admin/updateUser
Body: {"user_id": 12, "role": "editor"}
They replay it with their own payload:
POST /admin/updateUser
Body: {"user_id": 1, "role": "admin"}
The backend checks authentication but not role. Returns 200 OK. Viewer is now admin.
Impact: Low-privilege users performing admin-level operations — role changes, user management, content deletion.
2. Horizontal Access Control
Prevents users with the same privilege level from accessing each other’s data. A failure here = horizontal privilege escalation.
Attack:
User A loads their own profile:
GET /user/profile?id=10
They modify the ID:
GET /user/profile?id=11
The backend doesn’t check ownership — returns User B’s data:
{"username": "userB", "email": "userb@example.com"}
Impact: PII leakage, user-to-user attacks, account takeover if write actions are also unprotected.
3. Context-Dependent Access Control
Restricts actions based on state, workflow, or sequence — even if the user has permission, the action must happen in the correct context.
Examples:
- Must create a draft before submitting it
- Must verify email before enabling features
- Must add item to cart before checkout
Attack:
Normal workflow:
1. POST /content/createDraft
2. POST /content/submitDraft
Attacker skips step 1 and calls directly:
POST /content/submitDraft
Server doesn’t verify whether a draft exists, whether it belongs to the user, or whether the sequence was followed. Returns 200 OK.
Impact: Business logic bypass, invalid submissions, abuse of features, inconsistent system states.