Mass assignment is a critical security vulnerability where attackers inject unauthorized fields into your database. Learn to harden your Laravel models today.
Previously in this course, we explored Defense Against SSRF: Hardening Laravel Outgoing Requests to protect our perimeter from server-side request forgery. While SSRF secures our outbound traffic, we must now turn our attention inward to the data integrity of our Eloquent models.
Mass assignment occurs when an application accepts an array of input directly from an HTTP request and passes it into a model's create() or update() method without sufficient filtering. If your User model is accidentally configured to allow mass assignment on an is_admin column, an attacker can simply pass is_admin=1 in their JSON payload to escalate their privileges.
In a production-grade SaaS, "implicit" is dangerous. Relying on default behavior is the primary driver of mass assignment vulnerabilities. You must transition from a "permit all" mindset to a "deny by default" architecture.
Eloquent provides two primary gates for this: $fillable (the whitelist) and $guarded (the blacklist). In high-traffic systems, I strongly advise against using $guarded = []. Even if you think you are "safe" because you use DTOs, a single developer mistake in a controller can expose your entire schema.
Always define an explicit $fillable array. If a field isn't in that list, it should not be touched by Eloquent's mass assignment methods.
PHPnamespace App\Models; use Illuminate\Database\Eloquent\Model; class User extends Model { #6A9955">// The ONLY fields allowed to be set via mass assignment protected $fillable = [ 'name', 'email', 'password', ]; }
If you find yourself frequently using unguarded() or passing massive arrays into models, you are likely bypassing your domain boundaries. As discussed in Utilizing Data Transfer Objects (DTOs), your models should represent persistent state, not raw HTTP input.
While $fillable provides a safety net at the database layer, it is a reactive measure. We want to be proactive. FormRequests are the first line of defense; they sanitize and validate input before it ever touches your service layer or your models.
By defining a FormRequest, you create a contract for your incoming data. If the input doesn't match the schema, the request is terminated.
Instead of passing $request->all() into an update() call, we define a specific request class to filter out malicious fields.
PHPnamespace App\Http\Requests; use Illuminate\Foundation\Http\FormRequest; class UpdateUserRequest extends FormRequest { public function rules(): array { return [ 'name' => 'required|string|max:255', 'email' => 'required|email|unique:users,email,' . $this->user()->id, #6A9955">// 'is_admin' is intentionally omitted! ]; } }
Now, in your Controller or Action class:
PHPpublic function update(UpdateUserRequest $request, User $user) { #6A9955">// $request->validated() only contains the fields defined in rules() $user->update($request->validated()); }
Even if an attacker sends {"is_admin": 1, "name": "Hacked"}, the is_admin key is stripped away by validated(), and the model's $fillable array acts as a final fail-safe.
$guarded = [].$fillable array containing only the fields intended for user input.FormRequest for a common update endpoint.role or status column) fails to update the database even when sent in the request.$guarded = [] Trap: Never use this in production. It is a "lazy" developer pattern that creates massive security debt.request()->all(): Never pass the entire request object to a model. Always use validated() or map data into a DTO.update() will attempt to save every key in the array. If you are passing an object from a frontend state, ensure you are filtering keys before calling the model.Mass assignment hardening is about reducing the surface area of your models. By combining strictly defined $fillable arrays with the rigorous validation provided by FormRequests, you create a multi-layered defense that prevents unauthorized data manipulation. For more on how this integrates with broader architecture, review Preventing Mass Assignment: A Guide to Secure DTO Implementation.
Up next: We will dive into Automated Security Testing, where we'll implement static analysis tools to catch these vulnerabilities before they ever hit your CI/CD pipeline.
Master multi-tenant security by implementing robust row-level isolation in Laravel. Learn to build tenant-aware Eloquent scopes that prevent cross-tenant leaks.
Read moreLearn to build production-ready integrations by validating webhook signatures and offloading processing to queues to ensure security and system reliability.
Mass Assignment Hardening
Custom Middleware Development
Database Connection Pooling
Handling Large Data Exports
Security Header Configuration
Database Sharding Concepts
Real-time Data Synchronization
Database Deadlock Prevention
Managing Third-Party API Integrations