Use an allow-list of writable fields for every write endpoint, ideally through a data transfer object that holds only what the client is permitted to edit. A block-list of dangerous fields fails the day someone adds a new sensitive column and forgets to update it.
What mass assignment is
Mass assignment happens when a framework automatically binds request parameters to an object and an attacker sends extra fields the developer never intended to be settable. The OWASP cheat sheet uses a signup form: add isAdmin=true to the request and, if the model has that field, it may be set.
The attacker does not need source code. Field names can be guessed from responses, documentation, error messages or a quick look at the client app.
Three ways to defend
Data transfer objects. Define a separate input type with only the fields a user may edit. Sensitive properties such as role or owner are not in the type, so they cannot be bound.
Framework allow-lists. Many frameworks let you name bindable fields. The OWASP page points to examples such as Spring's setAllowedFields, picking fields in Mongoose and the fillable list in Laravel.
Block-lists. You name the fields that must not be bound. This is the weakest option.
Why block-lists fail
A block-list is correct on the day it is written. Then a developer adds a column called is_verified or discount_tier. Unless they also update the block-list, the field is bindable. OWASP's cheat sheet makes this point and cites CWE-915, which prefers allow-lists.
With an allow-list the failure goes the safe way. A new field is not writable until someone deliberately adds it.
Decision guide
- New endpoint: Choice: DTO with only editable fields
- Legacy handler that binds a whole model: Choice: Add a framework allow-list now, move to a DTO later
- Different roles edit different fields: Choice: One DTO or allow-list per role
- You can only add a block-list this week: Choice: Do it as a stopgap and ticket the allow-list
Do not mistake it for authorization
An allow-list limits which fields are writable. It does not decide who may edit the object. The OWASP cheat sheet says to keep authorization separate: you still need to check that the caller may modify that record. For that part, see the guide to broken object level authorization.
A simple test
For each write endpoint, send the normal request plus extra fields: role, owner id, price, status, verified flags. Read the object back. Anything that changed and was not meant to is a finding.
Run this in CI against a test tenant. It is cheap and it catches regressions when a model gains a field.
Quick check
Can input validation replace an allow-list?
Not on its own. Validation checks that a value is well formed. An allow-list decides whether the field may be set at all. A perfectly valid admin flag is still an attack.
Does using a DTO fix the whole problem?
It fixes which fields are bindable. You still need object level checks for who can edit the record.
Safeguard's policies and gates can enforce checks in pull requests, and the free scan at gold.safeguard.sh/scan covers dependency and SBOM issues, though handler design remains a code review matter.
Sources
Last reviewed: 19 October 2026.