FlawOpen

flawopen.com/Mass Assignment/Explained

What is mass assignment, and how do you prevent it?

CWE-915: Improperly Controlled Modification of Dynamically-Determined Object AttributesReference page
Short answer

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.

VULNERABLE
# 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())
FIXED
# 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:

FAQ

Is this the same as prototype pollution?

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.

Does GraphQL avoid the problem?

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.

Do server-rendered forms protect me?

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.

References

See also Serverless State Bleed: Keep User Data Request-Scoped PHP == and Magic Hash Comparisons Is Rust's unsafe block still memory safe? Is strncpy() safer than strcpy()? CWE vs. CVE: What's the Difference?