Broken Access Control: Forging the Admin Role from a Client-Supplied Parameter
Le défi
Voici la requête que l'app envoie pour charger votre panneau de compte. Remarquez qu'elle indique au serveur votre propre rôle, juste là dans la requête. Le serveur l'a cru. Changez le rôle, envoyez, et lisez la note réservée aux admins que la réponse laisse fuiter.
Ce que tu vas apprendre
- Recognize broken access control when a server reads a user's role from a request parameter instead of the authenticated session
- Understand how editing a client-controlled privilege field leads to vertical privilege escalation
- Identify which parts of an HTTP request are attacker-controlled and therefore untrustworthy as authorization input
- Explain why authorization decisions must be derived server-side from the session, never echoed back from client input
- Connect this pattern to related issues like insecure direct object references and mass assignment
Compétences testées
Prérequis
- Basic understanding of HTTP requests, query parameters, and cookies
- Familiarity with the idea of user roles and access levels (customer, support, admin)
Comment ça marche
Broken access control is the failure to enforce what an authenticated user is actually allowed to do. It is consistently one of the most common and damaging classes of web vulnerability. In this challenge the application asks the server to load an account panel, and it puts the user's own role directly into the request as a query parameter. The server reads that parameter and uses it to decide which panels and data to return - it treats a value the user controls as the source of truth for authorization.
This is a textbook privilege escalation. A role is an authorization decision, not a piece of user input. When the server trusts a client-set role, support, or privilege field, any user can simply rewrite it to claim a higher tier. The request travels through the browser and any proxy the user runs, so every byte in the URL, headers, and cookies is attacker-controlled. Echoing that value back into an access decision means the lock is on the wrong side of the door.
The same root cause appears under several names: vertical privilege escalation when a low-privilege user gains a higher role, insecure direct object reference when an identifier picks a resource that should be off limits, and mass assignment when a request quietly sets a field like is_admin that the user was never meant to touch. In every case the fix is the same idea - the server must derive authority from the authenticated session, never from data the client can edit.
Erreurs fréquentes
- Assuming the role shown in the request is fixed by the server, when it is just text in a URL that anyone can rewrite before sending.
- Trying obscure injection payloads first instead of reading the request and noticing that an authorization value is sitting in plain sight, fully editable.
- Reaching for the highest-sounding tier without reading the responses - the top option here is rejected because it demands a second factor, so it is a dead end.
- Treating the bug as a bad parameter value rather than the real flaw: the server should never have accepted a role from the client at all.
Comment s'en protéger
Never read a user's role, permission level, or any authorization attribute from a request parameter, cookie, hidden form field, or request body. Look up the caller's identity from the authenticated session on the server, fetch their role from your trusted store, and enforce it there. The request should describe what the user wants to do, never what they are allowed to do.
- Resolve the role from the server-side session, then check it against the requested action with a deny-by-default policy.
- Ignore and never trust any client-supplied role, permission, or privilege field - drop it rather than honoring it.
- Apply object-level and function-level access checks on every endpoint, including ones the UI does not expose, since attackers call the API directly.
- Log and alert when a request attempts to claim a higher role than the session holds, so abuse is visible.