Privilege Escalation

Priv EscVertical Access ControlRole Bypass

Privilege Escalation at a glance

What it is: Vulnerabilities that allow users to gain higher privileges than intended, such as regular users performing admin actions or accessing restricted functionality.
Why it happens: Allows attackers to gain administrative control
How to fix: Enforce role checks at every privileged endpoint; Use centralized authorization middleware; Never trust client-provided role information; Implement least privilege principle throughout

Overview

Privilege escalation occurs when a user can perform actions or access resources beyond their assigned role or permission level. This can be vertical (gaining admin rights) or horizontal (accessing another user's account with same privilege level).

Common causes include missing role validation on privileged endpoints, accepting role information from client requests, inconsistent authorization checks across the application, and relying on obscurity rather than enforcement.

sequenceDiagram participant User as Regular User participant App as Application participant DB User->>App: POST /admin/delete-user?userId=123 App->>DB: DELETE FROM users WHERE id=123 DB-->>App: User deleted App-->>User: 200 OK Note over App: Missing: Role validation<br/>Missing: Authorization middleware
A potential flow for a Privilege Escalation exploit

Where it occurs

Privilege escalation vulnerabilities arise from endpoints missing role validation, accepting user_role or permissions from request parameters, authorization middleware not applied to all routes, client-side only access control checks, and predictable URLs to admin functions.

Impact

Privilege escalation enables complete system compromise, unauthorized data access and manipulation, ability to create or delete users and resources, compliance violations, and can serve as a stepping stone for further attacks.

Prevention

Implement centralized authorization that checks roles and permissions for every request. Never accept role or permission information from the client. Apply authorization middleware by default to all routes. Use deny-by-default policies. Test role boundaries with automated tests.

Examples

Switch tabs to view language/framework variants.

Admin routes accessible without role validation

Admin endpoints lack authorization middleware, allowing any authenticated user to perform privileged operations.

Vulnerable
JavaScript • Express.js — Bad
// Vulnerable: No role check on admin route
const express = require('express');
const app = express();

// Authentication middleware (only checks if user is logged in)
function requireAuth(req, res, next) {
  if (!req.session.userId) {
    return res.status(401).json({ error: 'Not authenticated' });
  }
  // Fetch user from DB
  req.user = getUserById(req.session.userId);
  next();
}

// Admin route - only checks authentication, not role!
app.delete('/api/admin/users/:id', requireAuth, (req, res) => {
  const userIdToDelete = req.params.id;
  
  // Missing: Check if req.user.role === 'admin'
  
  deleteUser(userIdToDelete);
  res.json({ success: true, message: 'User deleted' });
});

// Any authenticated user can call this!
app.get('/api/admin/analytics', requireAuth, (req, res) => {
  const revenue = getTotalRevenue();
  const userStats = getAllUserStats();
  
  res.json({ revenue, userStats });
});
  • Line 14:
  • Line 23:

The vulnerable code only verifies that a user is authenticated (logged in) but never checks their role or permissions. The requireAuth middleware confirms a valid session exists but doesn't validate authorization for privileged operations.

Admin routes are protected only by authentication, meaning any user with a valid session cookie can access sensitive business analytics, delete users, and perform other administrative actions.

This violates the principle of least privilege - users should only have access to resources and operations necessary for their role.

Secure
JavaScript • Express.js — Good
// Secure: Centralized role-based authorization
const express = require('express');
const app = express();

// Authentication middleware
function requireAuth(req, res, next) {
  if (!req.session.userId) {
    return res.status(401).json({ error: 'Not authenticated' });
  }
  req.user = getUserById(req.session.userId);
  next();
}

// Authorization middleware - reusable role checker
function requireRole(role) {
  return (req, res, next) => {
    if (!req.user) {
      return res.status(401).json({ error: 'Not authenticated' });
    }
    
    if (req.user.role !== role) {
      // Log unauthorized access attempt
      logger.warn('Unauthorized access attempt', {
        userId: req.user.id,
        userRole: req.user.role,
        requiredRole: role,
        endpoint: req.path
      });
      
      return res.status(403).json({ 
        error: 'Forbidden',
        message: 'Insufficient privileges' 
      });
    }
    
    next();
  };
}

// Protected admin routes
app.delete('/api/admin/users/:id', 
  requireAuth, 
  requireRole('admin'),  // ← Role check enforced
  (req, res) => {
    const userIdToDelete = req.params.id;
    
    // Additional check: prevent self-deletion
    if (userIdToDelete === req.user.id) {
      return res.status(400).json({ error: 'Cannot delete own account' });
    }
    
    deleteUser(userIdToDelete);
    
    // Audit log
    auditLog.record({
      action: 'USER_DELETED',
      adminId: req.user.id,
      targetUserId: userIdToDelete
    });
    
    res.json({ success: true, message: 'User deleted' });
  }
);

app.get('/api/admin/analytics', 
  requireAuth,
  requireRole('admin'),  // ← Role check enforced
  (req, res) => {
    const revenue = getTotalRevenue();
    const userStats = getAllUserStats();
    
    res.json({ revenue, userStats });
  }
);
  • Line 16:
  • Line 25:
  • Line 50:

The secure implementation introduces a requireRole() middleware factory that generates role-specific authorization checks. This middleware verifies both authentication and the user's role before allowing access.

Authorization is enforced at the route level by chaining middleware: requireAuthrequireRole('admin') → handler. This ensures no admin operation can be performed without proper role validation.

Failed authorization attempts are logged with context (user ID, required role, endpoint) enabling security teams to detect and respond to potential privilege escalation attempts.

Additional safeguards like preventing self-deletion and audit logging of sensitive operations provide defense in depth.

Engineer Checklist

  • Require explicit role checks on all privileged endpoints

  • Use centralized authorization middleware

  • Never accept role/permission data from client

  • Apply authorization by default (deny-by-default)

  • Test role boundaries with automated tests

  • Log all privilege changes and admin actions

  • Implement least privilege for all accounts

  • Regularly audit privileged operations

End-to-End Example

A regular user accesses admin functionality by directly calling privileged API endpoints without proper authorization checks.

Vulnerable
JAVASCRIPT
# Vulnerable: No role check on admin endpoint
from django.http import JsonResponse
from django.contrib.auth.decorators import login_required
from .models import User

@login_required
def delete_user(request, user_id):
    # Missing role authorization check!
    user = User.objects.get(id=user_id)
    user.delete()
    return JsonResponse({'status': 'deleted'})
Secure
JAVASCRIPT
# Secure: Enforce role-based access control
from django.http import JsonResponse, HttpResponseForbidden
from django.contrib.auth.decorators import login_required
from functools import wraps
from .models import User

def require_role(role):
    def decorator(view_func):
        @wraps(view_func)
        def wrapper(request, *args, **kwargs):
            if not request.user.is_authenticated:
                return HttpResponseForbidden('Authentication required')
            if request.user.role != role:
                return HttpResponseForbidden('Insufficient privileges')
            return view_func(request, *args, **kwargs)
        return wrapper
    return decorator

@login_required
@require_role('admin')
def delete_user(request, user_id):
    # Only admins can reach this code
    user = User.objects.get(id=user_id)
    user.delete()
    return JsonResponse({'status': 'deleted'})

Discovery

Test if role/privilege fields can be manipulated in requests or if authorization checks are missing for privileged operations.

  1. 1. Test mass assignment on user update

    http

    Action

    Include role field in profile update to test for mass assignment

    Request

    PUT https://api.example.com/api/users/me
    Headers:
    Authorization: Bearer regular-user-token
    Content-Type: application/json
    Body:
    {
      "name": "Alice",
      "email": "alice@example.com",
      "role": "admin",
      "is_superuser": true
    }

    Response

    Status: 200
    Body:
    {
      "id": 1042,
      "name": "Alice",
      "email": "alice@example.com",
      "role": "admin",
      "is_superuser": true,
      "message": "Profile updated successfully"
    }

    Artifacts

    mass_assignment_vuln privilege_escalation admin_access_granted
  2. 2. Test unprotected admin endpoint

    http

    Action

    Access admin-only endpoint without admin role

    Request

    GET https://api.example.com/api/admin/users
    Headers:
    Authorization: Bearer regular-user-token

    Response

    Status: 200
    Body:
    [
      {
        "id": 1,
        "username": "admin",
        "email": "admin@company.com",
        "role": "admin"
      },
      {
        "id": 2,
        "username": "alice",
        "email": "alice@example.com",
        "role": "user"
      },
      "... (full user directory exposed)"
    ]

    Artifacts

    missing_authorization admin_endpoint_accessible user_enumeration

Exploit steps

Attacker escalates privileges by manipulating role fields or accessing unprotected admin endpoints, gaining full administrative control.

  1. 1. Escalate to admin via mass assignment

    Grant admin role through profile update

    http

    Action

    Update profile with role='admin' to gain elevated privileges

    Request

    PUT https://api.example.com/api/users/me
    Headers:
    Authorization: Bearer attacker-token
    Content-Type: application/json
    Body:
    {
      "role": "admin",
      "permissions": [
        "users:read",
        "users:write",
        "users:delete",
        "system:admin"
      ]
    }

    Response

    Status: 200
    Body:
    {
      "id": 9999,
      "username": "attacker",
      "role": "admin",
      "permissions": [
        "users:read",
        "users:write",
        "users:delete",
        "system:admin"
      ],
      "message": "You now have admin access"
    }

    Artifacts

    admin_privileges full_system_access mass_assignment_exploit
  2. 2. Delete other user accounts

    Use new admin privileges to delete users

    http

    Action

    Delete competitor admin accounts

    Request

    DELETE https://api.example.com/api/admin/users/1
    Headers:
    Authorization: Bearer attacker-token-now-admin

    Response

    Status: 200
    Body:
    {
      "message": "User admin (ID: 1) deleted successfully",
      "deleted_user": {
        "username": "admin",
        "email": "admin@company.com"
      }
    }

    Artifacts

    account_deletion admin_account_removed system_takeover

Specific Impact

Complete system compromise through elevated privileges, unauthorized administrative actions.

Fix

Implement centralized authorization decorators that verify user roles before allowing access to privileged operations. Never trust client-provided role information. Apply authorization checks by default using middleware, with explicit opt-out only for public endpoints. Use deny-by-default policies and log all privileged operations.

Detect This Vulnerability in Your Code

Sourcery automatically identifies privilege escalation vulnerabilities and many other security issues in your codebase.

Scan Your Code for Free