Mass Assignment
debt(d5/e3/b5/t7)
Closest to 'specialist tool catches it' (d5). The detection_hints list semgrep as the tool, with automated detection possible for the specific pattern `->fill($request->all())` or `->create($request->all())`. Standard linters won't catch this by default — it requires a configured SAST rule — but it won't silently survive production undetected either, since semgrep can flag it in CI.
Closest to 'simple parameterised fix' (e3). The quick_fix is a targeted swap: replace `->fill($request->all())` with `->fill($request->only(['field1','field2']))`. This is a small, repeatable pattern fix rather than a single one-liner, because every affected model call site needs auditing and an explicit allowlist defined, but it remains within a single component or model layer rather than a cross-cutting architectural refactor.
Closest to 'persistent productivity tax' (b5). The vulnerability applies to all web and API contexts in PHP. Every time a new model attribute or database column is added, developers must revisit the fill policy — as called out explicitly in common_mistakes. This creates an ongoing tax on feature development across multiple work streams, but it doesn't reshape the entire system's architecture.
Closest to 'serious trap' (t7). The misconception field reveals the core trap: developers believe mass assignment only matters in frameworks that auto-bind, so they think hand-rolled code passing `$_POST` to a model update is safe. This contradicts how similar concepts (e.g., form binding in other frameworks) are assumed to work, leading competent developers to miss the vulnerability in non-obvious code paths, particularly in APIs handling JSON bodies.
Also Known As
TL;DR
Explanation
Mass assignment occurs when an application automatically maps all HTTP request parameters to object or database fields without an explicit allowlist. An attacker can add extra fields to a form submission — setting is_admin=1, role=admin, or price=0 — and have them silently accepted. Prevention requires an explicit allowlist of permitted fields for each operation. Never pass $_POST or $_REQUEST directly to a constructor or update query.
Common Misconception
Why It Matters
Common Mistakes
- Not defining a $fillable whitelist on Eloquent models — leaving all columns assignable.
- Updating models with array_merge($model->toArray(), $request->all()) instead of validated/filtered input.
- Forgetting that JSON request bodies in APIs are just as exploitable as HTML form submissions.
- Not auditing model attributes when new columns are added — new sensitive fields inherit the existing fill policy.
Code Examples
// Laravel — no $fillable guard
User::create($request->all());
// Attacker sends: POST {"email":"x","role":"admin"}
// Explicitly allow only safe fields
User::create($request->only(['name', 'email', 'password']));
// Or define $fillable on the model
class User extends Model {
protected $fillable = ['name', 'email', 'password'];
// $guarded = ['role', 'is_admin']; // alternative
}