# Reverse Account Takeover via Email Rebinding Causing Forced Privilege De-Escalation

When we talk about account takeover, we usually imagine a familiar story: an attacker steals credentials, hijacks a session, or abuses password reset flows to log in as someone else.

This write-up is about something more subtle — and arguably more dangerous.

During a recent assessment, I discovered a vulnerability where a **low-privileged user could force a workspace owner to lose their privileges entirely**, without ever logging in as them. The owner didn’t get hacked in the traditional sense — instead, the application reassigned identity in a way that caused **forced privilege de-escalation** and effective account takeover.

This post walks through how it happened, why it worked, and what developers can learn from it.

## Application overview

The target application is a multi-tenant SaaS platform. Each customer has one or more **workspaces**, and users inside those workspaces are assigned roles:

* **Owner** (super-admin level)
    
* **Manager**
    
* **Member**
    

The owner has full control — user management, configuration, and critical workspace actions. Manager and Member have minimal privileges.

I was authenticated as a **member-level user**, testing normal account functionality with proper authorization from the client.

## The starting point: profile updates

Like most modern SaaS platforms, the application allowed users to update basic profile information such as:

* Display name
    
* Preferred language
    

While updating my profile, I intercepted the request using Burp Suite. The request was sent to:

```bash
PUT /api/users/me
```

The request body looked harmless:

```bash
{
  "displayName": "Member-1",
  "userSystemLanguage": "en-US"
}
```

The response returned my full user object, including some personally identifiable information (PII). While reviewing it, something stood out.

## A small detail that mattered

Inside the response, I noticed two properties:

* `email`
    
* `primaryemail`
    

Both were set to my registered email address.

This raised a simple question:

> What happens if I try to set these fields myself?

The frontend UI never exposed email changes here — but the backend clearly accepted and returned them. That meant the server was likely trusting client-supplied values.

## The experiment

I modified the same request and added the following fields:

```bash
{
  "displayName": "Member-1",
  "userSystemLanguage": "en-US",
  "email": "john.doe@redacted.com",
  "primaryemail": "john.doe@redacted.com"
}
```

[`john.doe@redacted.com`](mailto:jason@custom.com) belonged to the **workspace owner** — the highest-privileged user in that tenant.

I sent the request.

The backend accepted it.

No validation error.  
No ownership check.  
No email verification flow.

The response came back successfully, showing my account now associated with the owner’s email address.

## What happened next

After refreshing the application, my session broke and I started seeing server errors.

At the same time, the workspace owner logged back into their account.

What they saw was alarming:

* Their owner privileges were gone
    
* Their account had been demoted to a lower role (member)
    
* They could no longer manage their own workspace
    

In simple terms:

> My low-privileged account absorbed the owner’s email identity, and the system responded by **de-escalating the real owner’s privileges**.

This was not just account takeover.

This was **forced privilege de-escalation through identity rebinding**.

## Why this works (root cause)

This issue exists at the intersection of **identity**, **authorization**, and **business logic**.

The backend made several critical assumptions:

1. **Email fields were treated as editable profile data**  
    Instead of protected identity attributes.
    
2. **No uniqueness enforcement**  
    The system did not block assigning an email already associated with another user.
    
3. **No email ownership verification**  
    No confirmation link, no challenge, no secondary approval.
    
4. **Implicit trust in client input**  
    If the client sent `primaryemail`, the server accepted it.
    

Once the system allowed email rebinding, the rest of the failure cascaded naturally — identity collision, role confusion, and privilege loss.

## Why this is critical

This vulnerability allows:

* Forced **owner privilege de-escalation**
    
* Effective **reverse** **account takeover without authentication**
    
* Workspace lockout of legitimate administrators
    

From a risk perspective, this is catastrophic in a SaaS environment. A single low-privileged user can disrupt or seize control of an entire tenant.

## Lessons learned

This bug wasn’t about missing authentication or weak crypto. It was about **trust boundaries**.

If a field defines *who a user is*, it must never be treated like *what a user prefers*.

From a testing perspective, this reinforces a key mindset:

> Always test what the backend accepts — not just what the UI exposes.

## Responsible disclosure

This issue was responsibly disclosed to the client, validated by their engineering team, and fixed. No real user data was harmed.

## Final thoughts

Modern applications are complex systems where identity, authorization, and state management intersect. Bugs like this don’t look dangerous at first glance — but their impact can be devastating.

Sometimes, breaking security isn’t about breaking in.

It’s about **changing who the system thinks you are**.
