Mass Assignment
Learn how mass assignment vulnerabilities allow attackers to modify protected object properties through API requests. Understand detection and prevention methods.
What is Mass Assignment?
Mass Assignment is a vulnerability that occurs when an API endpoint automatically binds client-supplied request parameters to internal object properties or database fields without adequately filtering which properties can be modified. This allows attackers to update object properties that they should not have access to by simply including additional fields in their API request body, potentially modifying security-sensitive fields such as user roles, account status, pricing, or ownership attributes.
This vulnerability arises from the convenience features of modern web frameworks that automatically map HTTP request bodies to data model objects. Frameworks like Ruby on Rails, Django, Express.js with body-parser, and Spring Boot provide mechanisms that bind JSON or form-encoded request data directly to model attributes. While this reduces boilerplate code, it creates a dangerous default behavior where any property that exists on the server-side model can be set by a client if the developer does not explicitly restrict which properties are bindable.
Mass Assignment is particularly insidious because the vulnerable code often appears correct—it handles the expected input fields properly. The vulnerability lies in what happens with unexpected fields that the attacker adds to the request. The API may silently accept and persist properties that were never intended to be client-modifiable, such as isAdmin, accountBalance, subscriptionTier, or organizationId.
How It Works
Attackers exploit mass assignment by first observing the normal API request-response cycle to understand the data model. For example, if a user profile update endpoint accepts {"name": "John", "email": "john@example.com"}, the attacker examines the response object for additional fields that are returned but not editable through the UI, such as role, credits, or isVerified. The attacker then crafts a modified request that includes these additional fields: {"name": "John", "email": "john@example.com", "role": "admin", "credits": 99999}.
At the code level, the vulnerability typically looks like this: the endpoint handler receives the request body, passes it directly to an ORM update method (e.g., User.update(req.body) or Object.assign(user, req.body)), and saves the result. The ORM dutifully updates every field present in the request body, including the attacker-supplied role and credits fields. Without an explicit allow-list of updateable fields, the ORM has no way to distinguish between legitimate and malicious field updates.
Advanced mass assignment exploitation includes modifying foreign key relationships to reassign resources between accounts (changing organizationId to move resources to an attacker-controlled organization), setting timestamp fields to manipulate audit trails, modifying nested object properties in APIs that support deep object binding, and exploiting polymorphic associations to change object types. In APIs that use JSON Merge Patch (RFC 7396), attackers can also null out security-critical fields by sending {"securityFlag": null}.
Impact
- Privilege escalation by modifying role or permission fields, allowing regular users to gain administrative access
- Financial manipulation by altering pricing, credit, or balance fields in e-commerce, billing, or financial applications
- Account takeover by modifying email or phone number fields used for password recovery without proper verification
- Bypassing business logic by modifying status, verification, or approval fields that gate access to features or content
- Data integrity compromise by modifying ownership or association fields that control resource access and tenant isolation
- Audit trail manipulation by modifying timestamp or audit fields to conceal malicious activity
Remediation Steps
- Implement explicit allow-lists (also called permit-lists or strong parameters) that define exactly which request body fields each endpoint will process. Reject or ignore any fields not in the allow-list. Never use deny-lists as they fail to protect against newly added model properties.
- Use Data Transfer Objects (DTOs) or request schema validation to strictly define the shape of accepted input for each endpoint. Libraries like Zod, Joi, class-validator, or Pydantic provide runtime type validation that rejects requests with unexpected properties.
- Separate read models from write models: the object schema returned by GET endpoints should not dictate which fields are writable on PUT/PATCH endpoints. Define distinct input and output schemas for each endpoint in your OpenAPI specification.
- Configure your ORM or data access layer to use explicit field assignments rather than mass assignment. In Rails, use strong parameters; in Django, use serializer fields; in Sequelize/TypeORM, specify updateable fields explicitly in update operations.
- Implement pre-save hooks or middleware that validate field modifications against business rules. Security-critical fields (role, permissions, ownership) should only be modifiable through dedicated administrative endpoints with appropriate authorization checks.
- Add automated testing that sends requests with additional properties (role, isAdmin, balance, etc.) to every writable endpoint and verifies these properties are not persisted. Include these tests in your CI/CD pipeline.
- Enable strict mode in your JSON schema validation to reject requests containing properties not defined in the schema (additionalProperties: false in JSON Schema).
Testing Guidance
Start by documenting all writable API endpoints (POST, PUT, PATCH) and their expected input schemas. For each endpoint, capture a normal request and examine the response to identify all properties of the target object. Create an augmented request that includes every property from the response object, setting security-sensitive fields to attacker-advantageous values (e.g., "role": "admin", "isVerified": true, "balance": 999999).
Use Burp Suite's Intruder or a custom script to systematically test mass assignment across all writable endpoints. For each endpoint, send the augmented request and then retrieve the object via a GET request to verify whether any of the additional properties were persisted. Tools like Param Miner can help discover hidden parameters that the API accepts but does not document. For GraphQL APIs, test mutation inputs with additional fields discovered through schema introspection.
Automate mass assignment testing by generating test cases from your OpenAPI specification. For each writable endpoint, extract the response schema to identify all model properties, then generate test requests that include non-writable properties. Use property-based testing frameworks like Hypothesis (Python) or fast-check (TypeScript) to generate random combinations of additional fields. Integrate these tests into your CI/CD pipeline to catch regressions when new model properties are added without corresponding input validation updates.
References
Related Vulnerabilities
Frequently Asked Questions
What is Mass Assignment?
Mass Assignment is a vulnerability that occurs when an API endpoint automatically binds client-supplied request parameters to internal object properties or database fields without adequately filtering which properties can be modified.
How does Mass Assignment work?
Attackers exploit mass assignment by first observing the normal API request-response cycle to understand the data model. For example, if a user profile update endpoint accepts {"name": "John", "email": "john@example.com"}, the attacker examines the response object for additional fields that are returned but not editable through the UI, such as role, credits, or isVerified.
How do you test for Mass Assignment?
Start by documenting all writable API endpoints (POST, PUT, PATCH) and their expected input schemas. For each endpoint, capture a normal request and examine the response to identify all properties of the target object. Create an augmented request that includes every property from the response object, setting security-sensitive fields to attacker-advantageous values (e.g., "role": "admin", "isVerified": true, "balance": 999999).
How do you remediate Mass Assignment?
Implement explicit allow-lists (also called permit-lists or strong parameters) that define exactly which request body fields each endpoint will process. Reject or ignore any fields not in the allow-list. Never use deny-lists as they fail to protect against newly added model properties.