Mass Assignment in APIs: Privilege Escalation via Extra JSON Fields
Mass assignment (CWE-915 vibes) happens when the server binds request JSON straight onto a model. You send {"email":"you@x.com"} and quietly add "role":"admin" or "balance":99999. If the ORM updates those columns, congratulations — the UI never showed the control, but the binder did not care.
I hunt this on profile update, signup, cart, and admin-looking PATCH endpoints that accept broad objects.
Diff the client vs the model
Capture a legitimate update. Note fields the UI sends. From JS bundles, OpenAPI, or GraphQL types, collect field names the server knows: is_admin, verified, plan, credits, organization_id, price_cents.
Add one exotic field per request. Read the response and re-fetch the resource. Blind trust shows up as the field echoing back or behavior changing (admin nav appears, price drops).
High-value extras
- Role / permission flags
- User IDs on create (attach resource to another tenant)
- Payment and discount fields
email_verified/ SSO linkage booleans- Feature flags stored on the user row
Frameworks where this is traditional
Ruby on Rails strong parameters exist because of this bug class. Node apps with Object.assign(user, req.body) recreate it. Java @JsonIgnore mistakes too. You do not need the source — behavioral testing is enough.
Proof hygiene
Escalate only your account. Prefer a harmless flag (newsletter → then role) to show binder openness before touching billing. Include request body diff and the privileged effect.
Fixes to suggest
Allowlist fields per endpoint (deny-by-default). Separate DTOs for write models. Never bind roles from the client; derive from server-side grants. Add tests that assert extra properties are ignored.
A short flow I reuse
- PATCH profile as normal user.
- Inject
"role":"admin"(or program-relevant equivalent). - Call an admin-only route.
- If blocked on route but role persisted, still report persistence + attempt.
Mass assignment is IDOR’s cousin: you do not swap someone else’s ID — you upgrade your own object. Extra JSON keys remain one of the cheapest elevators in API bounty work.