Skip to main content
2 min read Intermediate API

Mass Assignment (API3:2023)

Mass Assignment happens when an API binds client-supplied JSON directly to an internal object or database model. If the binding is not filtered by an allowlist, an attacker can set fields they were never meant to control, such as role, isAdmin, verified, balance, account_id, or price. This is OWASP API Security Top 10 entry API3:2023 - Broken Object Property Level Authorization.

Where to look

  • Registration, profile update, and "create resource" endpoints (POST/PUT/PATCH).
  • Responses that expose more fields than the form sends (read the GET response to learn hidden field names).
  • Frameworks prone to auto-binding: Rails (update_attributes), Spring (@ModelAttribute), Django (ModelForm/serializers), Laravel ($fillable/$guarded), Node/Mongoose, NestJS DTOs.

How to test

Capture a normal request, then add sensitive fields and replay.

PATCH /api/v1/users/me HTTP/1.1
Content-Type: application/json

{ "name": "alice", "role": "admin", "isAdmin": true, "verified": true }

Steps:

  1. GET the object first and note every returned property, including ones not in the UI form.
  2. Add those properties (and guesses like is_admin, accountBalance, userId) to the write request.
  3. Confirm the change took effect (re-read the object or check the new privilege).
  4. Try nested objects and arrays: "owner": {"id": 1} or "roles": ["admin"].
  5. Combine with IDOR: set "userId": <victim> to write to another user's object.

Useful checks with curl:

# baseline
curl -s -H "Authorization: Bearer $TOK" https://api.target.com/v1/users/me | jq

# attempt privilege escalation
curl -s -X PATCH https://api.target.com/v1/users/me \
-H "Authorization: Bearer $TOK" -H 'Content-Type: application/json' \
-d '{"role":"admin","isAdmin":true}' | jq

Tools: Burp Suite (Repeater + Param Miner to guess hidden JSON keys), Postman, jq, and the API's own schema/Swagger (/swagger.json, /openapi.json) to enumerate model fields.

Mitigation

  • Bind input to an explicit allowlist (DTO with only client-editable fields); never bind straight to the DB model.
  • Mark sensitive properties read-only server-side and ignore them if supplied.
  • Validate object-property-level authorization: who is allowed to set this field, not just this endpoint.
  • Keep request and response schemas separate and reviewed.

References