In Depth: Mass-Assignment Vulnerabilities
[InDepth#15] There is a false confidence about mass-assignment vulnerabilities that hides how easy it is for them to occur and be exploited...
Greetings my friends! Last week we started our new series on the Top 10 security issues I’ve found during audits. Here’s the list so far:
#10 → Insufficient Input Validation
#9 → Missing Subresource Integrity (SRI)
As it turns out, we’ve covered SRI back in January 2022, so head over to Security Tip #14: Subresource Integrity to learn more about it. So rather than rehashing an old topic, this week we’re going to focus on another aspect of Insufficient Input Validation, specifically Mass-Assignment Vulnerabilities. This is a topic which is easily misunderstood and there is a false confidence that hides how easy it is for them to occur and be exploited…
But before we get into our topic, I want to briefly mention Substack Notes, which is a new space for us to share content, ideas, links, and generally do other social media-y type stuff. It looks cool, and I’m posting my Top 10 up there (#10, #9, #8, #7), plus other things, but there are also some big questions about moderation that the Substack team needs to answer. This is something I’m working through, and I’ll keep you updated.
👉 Security Audits: Worried about my Top 10 Laravel security issues? Book a security audit and make sure you’re covered! 🕵️
Looking to learn more?
⏩ Security Tip #28: Composer Audit
▶️ In Depth #11: Insecure Direct Object References (IDOR
Please consider becoming a paid subscriber to support Laravel Security in Depth.
You’ll receive weekly security tips and monthly In Depth articles, covering every aspect of building secure applications in Laravel.
Mass-Assignment Vulnerabilities
When you think of Mass-Assignment vulnerabilities on Laravel, I guarantee you’ll immediately think of the humble `$fillable`
Eloquent property. That’s definitely what the Laravel Docs teach you…
If you’re not familiar with the `$fillable`
Eloquent property, this is how it works:
First, you define the property on your model:
class User extends Model
{
protected $fillable = ['name', 'email'];
}
Next, when creating or updating the model, only the allowed attributes can be filled.
$input = [
'name' => 'Bilbo Baggins',
'email' => 'bilbo@example.com',
'admin' => true
];
$user = User::create($input);
// $user->name -> 'Bilbo Baggins'
// $user->email -> 'bilbo@example.com'
// $user->admin -> false
In the above example, the `admin = true`
flag is ignored when creating the `User`
model, protecting against a mass-assignment exploit to escalate the privileges of the newly created user.
And this is where many people stop learning about mass-assignment vulnerabilities and assume they are covered.
But are they?
I would argue that `$fillable`
is the lesser, or possibly even optional, protection against mass-assignment. Great to use if you can, but not essential and definitely not my first choice.
In fact, I often allow mass-assignment across all fields of a Model using `$guarded = [];`
, or even `Model::unguard()`
across the entire app in `AppServiceProvider`
. As controversial as that may be, I find `$fillable`
gets in my way more often than it protects me. Disabling the protection actually makes the code cleaner and more maintainable.
So what do I do instead?
Keep reading with a 7-day free trial
Subscribe to Securing Laravel to keep reading this post and get 7 days of free access to the full post archives.