flawopen.com/Mass Assignment/Explained
What is mass assignment, and how do you prevent it?
Think of a model as a form with both user-editable fields and staff-only controls. Binding the entire request is like letting a customer fill every box—including account ownership, approval, or role. Define editable fields in server-side code, then authorize the requested record and operation separately.
# Rails: request keys reach model attributes User.new(params[:user]) // Node / Mongoose: request object used as update await User.findByIdAndUpdate(id, req.body); // Express + Sequelize: request object used as create values await User.create(req.body); # Django: request keys passed as model fields User.objects.create(**request.POST.dict())
# Rails — permit only user-editable fields attrs = params.require(:user).permit(:name, :email) user = User.new(attrs) // Node — construct an allowlisted update const { name, email } = req.body; await User.findByIdAndUpdate(id, { name, email }); # Django — explicit ModelForm fields class UserForm(ModelForm): class Meta: model = User fields = ["name", "email"] // .NET — bind a DTO, then map explicitly user.Name = input.Name; user.Email = input.Email;
Why server-side field allowlists matter
A denylist such as “accept every field except role” can become unsafe when a new sensitive field is added and the exclusion list is not updated. An allowlist defaults new fields to non-editable until code deliberately exposes them. In Rails, Strong Parameters reject unpermitted attributes when mass-assigning request parameters; the controller must still permit only fields appropriate to that action. A DTO, serializer, or form with an explicit field list provides the same boundary in other frameworks.
Allowlisting controls which attributes a request may set; it does not grant permission to modify a record. Scope the record to the authenticated principal, authorize the operation, and reserve privileged changes for separate server-controlled flows.
Sensitive field categories to check
Review these categories in model attributes, nested serializers, and update endpoints:
- ✓Ownership and tenant keys — user_id, account_id, tenant_id. Enforce ownership in the query and authorization policy; never trust a client-supplied owner.
- ✓Roles, permissions, and workflow state — role, is_admin, email_verified, status. Change these only through the appropriate authorized server-side workflow.
- ✓Financial values and nested/system fields — balances, discounts, credits, nested associations, timestamps, and IDs can affect business rules or widen update scope. Permit and validate each intentionally.
FAQ
They are distinct weaknesses. Mass assignment lets input set unintended attributes on an object being created or updated. Prototype pollution changes properties on an object prototype (often a shared prototype), which can affect property lookup by other objects. An unsafe merge can create a path to prototype pollution; whether that also causes mass assignment depends on how application objects consume the resulting properties. See prototype pollution.
No. A GraphQL mutation can still accept an overly broad input object. Define mutation input types with only caller-editable fields, then enforce authorization on the object and operation in the resolver or service layer.
No. The rendered form does not constrain an HTTP client. Treat every submitted field as attacker-controlled, validate the request shape server-side, and accept only fields intended for that action.