Login
ChallengesLearn
Scoreboard
Teams
Profile

Preferences

Truesapiens

LearnAccess ControlPrivilege Escalation
Access Control·Lesson 3 of 12

Privilege Escalation

Horizontal: see another user data. Vertical: become an admin. Both happen when the server trusts a client-supplied role flag or fails to enforce per-action checks.

Intermediate12 min
Access ControlPrivEscWeb
Loading lesson…
PreviousPath TraversalNextMass Assignment

© 2026 Truesapiens.

Terms of ServicePrivacy PolicyCookie Policy

Privilege escalation occurs when a user gains access to resources or functionality that their role should not permit. It comes in two flavours: horizontal— accessing another user's data at the same privilege level — and vertical — elevating to a higher role such as admin or super-user.

What you'll be able to do
  • Distinguish between horizontal and vertical privilege escalation.
  • Demonstrate how changing a user ID or role parameter in a request can bypass access controls.
  • Examine the 2021 GitLab GraphQL IDOR incident as a real-world horizontal escalation.
  • Apply server-side role checks and object-level access controls to prevent escalation.
Key terms
Horizontal escalation
Accessing another user's data or resources at the same privilege level — for example, viewing another customer's invoice by changing an invoice ID parameter.
Vertical escalation
Gaining access to functionality reserved for higher-privilege roles — for example, changing a role field from "user" to "admin" in a profile update request.
IDOR
Insecure Direct Object Reference — a specific type of horizontal escalation where the application exposes internal object references without verifying authorisation.
What is it?

Horizontal and vertical privilege escalation

Horizontal escalation is about scope— the attacker stays at their privilege level but accesses data that belongs to someone else. A support agent viewing another agent's tickets by changing ?ticket_id=45 to ?ticket_id=46 is a horizontal escalation.

Vertical escalation is about level — the attacker performs an action that requires a higher privilege. A standard user adding role=admin to their profile update request and gaining access to the admin panel is a vertical escalation. Both stem from the same root cause: the server trusts the client to declare who they are or what they can access.

Horizontal escalation data flow
Mini Map
Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.
Try it

Explore the support ticket system

The sandbox below simulates a helpdesk support portal. You are logged in as Alice (Support Agent). Try changing the ticket ID in the URL to see other agents' tickets (horizontal escalation), or change your role parameter to access the admin panel (vertical escalation). Toggle the auth check to see how server-side validation blocks both vectors.

prod/dashboard/tickets/45
Support Portal
Logged in as Alice — auth check disabled
/tickets/
Real-world relevance

GitLab 2021: Horizontal escalation via GraphQL IDOR

In 2021, GitLab patched a critical vulnerability in their GraphQL API that allowed any authenticated user to access private project data belonging to other users. The bug was a classic horizontal escalation: the GraphQL resolver accepted a project ID without verifying that the requesting user was a member of that project. Attackers could iterate through project IDs and exfiltrate source code, CI/CD variables, and issue tracker data from private repositories.

The incident demonstrates how privilege escalation vulnerabilities can exist even in modern API patterns like GraphQL. The resolver was the authorisation boundary, but it lacked an ownership check. GitLab fixed it by adding project membership verification in the resolver layer.

Mitigation

Enforce authorisation at every access point

The fix for privilege escalation is simple in concept but requires discipline: every endpoint that accesses a resource must verify that the authenticated user is authorised for that specific resource and action. Never derive privilege from client-supplied parameters.

javascriptvulnerable
// VULNERABLE - trusts user-supplied role and ID
app.get('/api/tickets/:id', async (req, res) => {
  const ticket = await db.query(
    'SELECT * FROM tickets WHERE id = $1',
    [req.params.id],
  );
  res.json(ticket.rows[0]);
});

app.patch('/api/profile', async (req, res) => {
  // Accepts role from request body!
  await db.query(
    'UPDATE users SET name = $1, role = $2 WHERE id = $3',
    [req.body.name, req.body.role, req.session.userId],
  );
  res.json({ ok: true });
});

// SAFE - enforce ownership and role from session
app.get('/api/tickets/:id', async (req, res) => {
  const ticket = await db.query(
    `SELECT * FROM tickets
     WHERE id = $1 AND assigned_agent_id = $2`,
    [req.params.id, req.session.userId],
  );
  if (!ticket.rows[0]) return res.status(403).end();
  res.json(ticket.rows[0]);
});

app.patch('/api/profile', async (req, res) => {
  // Role is never read from the body
  const { name, email } = req.body;
  await db.query(
    'UPDATE users SET name = $1, email = $2 WHERE id = $3',
    [name, email, req.session.userId],
  );
  res.json({ ok: true });
});

Use a centralised authorisation middleware that maps each route to the required permissions. Avoid checking roles inline — a reusable gate function (like requireRole('admin')) makes it harder to miss a check when new endpoints are added.

Further reading
  • CWE-269: Improper Privilege Management(MITRE)
  • Privilege Escalation (OWASP)(OWASP)
  • GitLab Critical Security Release (2021)(GitLab)
Key takeaways

What to remember

  • Horizontal escalation = accessing another user's data at the same privilege level. Vertical escalation = gaining a higher privilege.
  • Both are caused by the server trusting client-supplied identifiers or role values instead of using session data.
  • Every resource-accessing endpoint must verify ownership and role permissions — missing even one endpoint creates a hole.
  • Never accept privilege-defining fields (role, is_admin, group_id) from the request body.
  • Centralised authorisation middleware reduces the risk of missing checks when the codebase grows.

Knowledge check

0/3 answered · 0 correct
  1. 1.What is the difference between horizontal and vertical privilege escalation?

  2. 2.A profile update endpoint accepts { name, email, role } in the request body. What is the risk?

  3. 3.A developer adds a new API endpoint but forgets to include the authorisation check. What is the likely outcome?