Object Property Assignment (Mass Assignment) Guide

Learn how automatic parameter binding can be exploited to inject hidden properties, escalate privileges, and bypass business logic.

๐ŸŽฏ What is Object Property Assignment?

Object Property Assignment (also called "Mass Assignment" or "Automatic Parameter Binding") is when web frameworks automatically bind HTTP request parameters directly to object properties without validation.

Example Framework Behavior:

// User submits form with: email, password, role Account user = new Account(); user.email = request.getParameter("email"); user.password = request.getParameter("password"); user.role = request.getParameter("role"); // DANGEROUS!

If the user also sends role=admin in the POST data, the framework might automatically bind it โ€” bypassing intended business logic.

๐Ÿ’ฅ How Mass Assignment Exploits Work
Attack 1: Hidden Field Injection

Normal form only shows email and password fields. Attacker opens browser dev tools and adds hidden field:

<input type="hidden" name="accountType" value="admin">

When submitted, the app binds all parameters: email, password, accountType. Attacker becomes admin.

Attack 2: POST Parameter Override

App intended to set discount=0, but attacker sends:

POST /register email=attacker@mail.com password=secret discount=50

Framework binds discount=50. Attacker's account gets 50% off all purchases.

Attack 3: Privilege Escalation via Hidden Properties

App has internal properties the user shouldn't control:

POST /update-profile name=attacker bio=my bio isAdmin=true canDeleteOthers=true accountTier=premium

If the framework binds all of these, attacker gets admin powers.

Attack 4: Nested Object Property Poisoning

Modern frameworks support nested properties via dot or bracket notation:

POST /update name=attacker profile[displayName]=hacker profile[email]=hacker@evil.com permissions[canRefund]=true permissions[canDeleteUsers]=true

If deeply bound, attacker sets internal properties.

Attack 5: API JSON Binding

APIs auto-bind JSON properties to model objects:

POST /api/user/register Content-Type: application/json { "username": "attacker", "password": "secret", "role": "admin", "labAccess": ["all"], "apiKey": "secret-generated-key" }

Framework binds everything. Attacker gets admin role, full lab access, and API key.

๐Ÿ”ง Real-World Examples of Mass Assignment

GitHub (2012): Mass assignment vulnerability allowed attackers to modify repository settings (including making private repos public) by posting hidden parameters.

Stripe (API design): Deliberately avoided mass assignment by whitelisting bindable properties โ€” considered a best practice.

Ruby on Rails (2012): Required developers to explicitly whitelist parameters after a widely-publicized mass assignment hacks.

โš ๏ธ Why is Mass Assignment Dangerous?
  • Privilege Escalation: Become admin, moderator, or VIP without authorization
  • Financial Fraud: Modify prices, discounts, account balances
  • Access Control Bypass: Enable features you shouldn't have (export data, delete records)
  • Data Modification: Change other users' properties (if IDs aren't validated)
  • Business Logic Bypass: Skip verification steps, approval workflows, etc.
  • Authentication Bypass (in some cases): Set verified=true or emailConfirmed=true
๐Ÿ›ก๏ธ How to Prevent Mass Assignment
  • โœ… Whitelist Properties: Only bind explicitly allowed parameters to model properties
  • โœ… Use DTO (Data Transfer Objects): Create separate input objects with only user-safe properties
  • โœ… Separate Read/Write Properties: Mark sensitive properties as read-only
  • โœ… Assignment Guards: Use 'guarded' or 'fillable' arrays to prevent auto-binding
  • โœ… Validate Expected Fields: Check that only expected fields are in the request
  • โœ… Never Auto-Bind to Critical Properties: Manually set sensitive fields (role, isAdmin, permissions)
  • โœ… Separate Endpoints: Use different endpoints for different privilege levels (e.g., /admin/set-role vs /user/update-profile)
๐Ÿ’ก Example Secure Code (PHP)
// โŒ VULNERABLE โ€” binds everything $user = new Account(); $user->fill($_POST); // โœ… SECURE โ€” whitelists properties $user = new Account(); $user->email = $_POST['email'] ?? null; $user->password = $_POST['password'] ?? null; // role, isAdmin, discount NOT bound from user input // โœ… ALSO SECURE โ€” using guard property class Account { protected $guarded = ['role', 'isAdmin', 'discount', 'apiKey']; } $user = Account::create($_POST); // only non-guarded properties bound
๐Ÿงช Lab Progression

Easy: Inject hidden form field to escalate privilege

Medium: Bypass field whitelist by exploiting allowlist logic

Hard: Exploit nested object binding via bracket notation

API: Auto-bind JSON properties to model in REST API