Sometimes the most interesting vulnerabilities don't require complex payloads or advanced exploitation chains. Sometimes, all it takes is changing one field in a JSON request.
While testing a team-based SaaS platform, I noticed something simple:
The UI strictly limited how many privileged roles (Admins and Creators) a team could have.
Naturally, I wondered:
Is that restriction actually enforced on the server… or just in the frontend?
Here's exactly how I found out.
— -
## Step 1 — Understanding the Role Model
The platform allowed multiple user roles:
- Admin - Creator - Observer
Admins and Creators were limited to a fixed number of seats.
Observers were unlimited.
The UI blocked adding more Admins/Creators once the seat limit was reached.
However, Observer invitations continued to work without restriction.
This suggested the possibility that:
- Seat limits might only be enforced client-side. - Backend validation might be incomplete.
So I started by inviting several users as Observers through the normal interface.
Everything worked as expected.
— -
## Step 2 — Direct Role Manipulation via API (Successful Exploit)
After intercepting a role update request:
- I located the "role" field in the JSON body. - I modified: — "observer" → "admin" — "observer" → "creator" - I forwarded the request. - The server returned success. - The user's role was upgraded. - The seat limit was exceeded. - No backend validation blocked the change.
This confirmed:
- Seat limits were not enforced during role updates. - The backend trusted the modified role value. - Privileged users could be created beyond the allowed quota.

— -
## Step 3 — Testing Race Condition Variants (Mixed Results)
After the initial finding, I explored timing-based scenarios to test enforcement depth.
### Scenario A — Upgrade Joined Observer + Invite Creator (Failed)
- One Creator seat remaining. - Upgrade an existing joined Observer to Creator. - Simultaneously invite a new Creator. - Result: ❌ Failed.
— -
### Scenario B — Downgrade Joined User + Invite Two Creators (Failed)
- Downgrade one joined Creator. - Attempt to invite two new Creators quickly. - Result: ❌ Failed.
— -
### Scenario C — Upgrade Two Invited Users Simultaneously (Failed)
- Invite two Observers. - Attempt to upgrade both to Creator at the same time. - Result: ❌ Failed.
— -
### Scenario D — Upgrade Two Joined Observers Simultaneously (Succeeded)
- Two joined Observers exist. - One Creator seat remaining. - Send two upgrade requests simultaneously. - Result: ✅ Both upgraded successfully. - Seat limit bypassed.
This indicated:
- The lock did not properly wrap updates to existing users.
— -
### Scenario E — Upgrade Joined User + Invite New Creator (Succeeded)
- Upgrade one joined user to Creator. - Simultaneously invite a new Creator. - Result: ✅ Both succeeded. - Seat limit bypassed again.
This revealed:
- Invitation creation and role update operations were not protected under a unified lock. - Quota validation was not atomic.
— -
### Scenario F — Invite Observers + Upgrade with Race Condition (Succeeded)
- Invite multiple Observers. - Immediately send parallel role update requests. - With proper timing (3–4 attempts required): — Role escalation succeeded. — Seat limits were bypassed. - Result: ✅ Timing-sensitive success.
This confirmed:
- The race condition was real. - Exploitation required precision but was reproducible.
