July 20, 2026
# From “users” to “admin”: How a Simple Response Copy-Paste Led to Privilege Escalation
While updating my profile as a normal user, the API response included a `role` field set to `”users”`. I copied that exact value into the…
By Pankaj Kumar Yadav
4 min read
While updating my profile as a normal user, the API response included a role field set to "users". I copied that exact value into the request body, changed it to "admin", and the server happily promoted me. No signature checks. No server-side validation. Just a broken trust model.
— -
The Target
Let's call the target Orbita — a SaaS platform for team collaboration. They run a private bug bounty program, and I was invited to test their staging environment. They gave me a standard user account: [testuser@example.com](mailto:testuser@example.com) with the role users (lowercase, plural — already a red flag).
The app had two main sections:
- User Dashboard — accessible to everyone.
- Admin Panel — supposedly restricted to
adminroles only.
My goal was simple: see if I could reach that Admin Panel.
— -
Step 1: Login & Recon
I logged in and started clicking around. The first thing I noticed: every page load triggered a GET /api/v1/me request to fetch the current user's profile.
Here is the login request and response:
![Login Request and Response]
The response contained the user object with role: "users". Nothing special yet. But I kept Burp Suite running to catch everything.
— -
Step 2: Normal Profile Update
I navigated to Profile Settings → Update Profile and changed my display name. Burp Suite caught the outgoing request:
![Normal Profile Update]
The server responded with the full updated user object — including role: "users". That's when it clicked. The response contained the role field. What if the server trusted whatever role I sent back in the request?
— -
Step 3: Copy, Paste, and Tamper
I intercepted the PUT /api/v1/me request in Burp Suite. I copied the entire JSON response from the server — including the role field — and pasted it into the request body. Then I changed "role": "users" to "role": "admin":
![Role Tampering — Admin Escalation]
The server responded with 200 OK and the updated profile showing role: "admin". No error. No "unauthorized." Just a clean update.
— -
Step 4: The Payoff — Admin Dashboard
I refreshed the page. The UI now showed an "Admin Panel" link in the navigation bar that wasn't there before. I clicked it.
The Admin Panel loaded fully:
![Admin Dashboard After Normal User Login]
I could now:
- View all user accounts
- Modify other users' roles
- Access audit logs
- Manage workspace settings
I had complete administrative access — all because the server accepted a client-supplied role value without validation.
— -
Root Cause Analysis
This is a classic case of Broken Function Level Authorization (BFLA) — OWASP API Security Top 10, #5.
The application made three critical mistakes:
- The
rolefield was writable by the client. ThePUT /api/v1/meendpoint acceptedroleas a user-controllable parameter. - No server-side validation. The backend never checked whether the requesting user was authorized to change their own role.
- The frontend trusted the backend response for UI rendering. Once the server returned
role: "admin", the frontend immediately exposed admin-only navigation and features.
— -
Why This Worked (The Technical Angle)
The app was using a JWT-based session. But here's the kicker: the server wasn't reading the role from the JWT for authorization decisions. Instead, it was querying the database for the user's role on every request — and since I had just updated my database record to role: "admin", the server now treated me as an admin everywhere.
The JWT was only used for authentication (who are you?), not authorization (what can you do?). The role escalation persisted because the database — not the token — was the source of truth.
— -
Impact
| Vector | Severity | | — — — — | — — — — — | | Privilege Escalation | Critical | | Account Takeover (via admin panel) | Critical | | Data Exfiltration | High | | User Management Abuse | High |
Any authenticated user could self-promote to admin. No special tools needed — just Burp Suite and a text editor.
— -
Remediation
If you're a developer, here's how to prevent this:
- Never allow clients to set their own role. The
rolefield should be read-only in profile update endpoints. - Enforce server-side RBAC checks. Before processing any privileged action, verify the user's actual role from a trusted source (JWT claims or a secure session store), not the request body.
- Use immutable claims in JWTs. If the role is in the token, validate it. If the database role changes, invalidate the old token.
- Log and alert on role changes. Any role modification should be an admin-only action, heavily audited, and trigger security alerts.
— -
Disclosure Timeline
| Date | Event | | — — — | — — — -| | 2026–07–15 | Initial discovery | | 2026–07–16 | Report submitted via HackerOne | | 2026–07–18 | Triaged as P1 — Critical | | 2026–07–19 | Fix deployed to staging | | 2026–07–20 | Bounty awarded: $4,500 |
— -
Final Thoughts
This bug was almost embarrassingly simple. No JWT algorithm confusion, no signature bypass, no SQL injection. Just a server that blindly trusted whatever the client told it.
The lesson? Never trust the client. If your API accepts a role field from a normal user's profile update request, you're one PUT request away from a total compromise.
— -
All names, domains, and identifiers in this post are fictionalized for responsible disclosure. The vulnerability class and exploitation technique are real and widely documented in security literature.
— -
Tags: #bugbounty #privilegeescalation #api-security #owasp #cybersecurity #infosec #writeup