

Discover more from Securing Laravel
Security Tip: Leaking Data After Changes
[Tip#35] It's easy to make innocent changes to one part of your app and forget to check how that flows into other parts of your app
Greetings friends! I’m writing this to you from the foyer at Laracon EU in Lisbon, Portugal! It’s my first in-person Laravel, so it’s incredibly awesome to be here. If you’re attending, you won’t want to miss my talk on Friday at 4pm1!
Following on the conference theme, this week’s security tip was inspired by a talk by Halvor Sakshaug at NDC Security in Oslo, “What happens if I change this URI… oooooh”, which I went to last week. The speaker was using a scenario where new routes are added to an app, which in turn leak data in existing routes. It serves as a helpful reminder for how to avoid leaking data when you make changes to your apps.
💡 Ensure your apps are secure, book in a Laravel Security Audit and Penetration Test! 🕵️
Looking to learn more?
⏩ Security Tip #18: Keep Dependencies Updated
▶️ In Depth #7: Content Security Policy
Leaking Data After Changes
Imagine the following scenario:
Your application has a small number of basic routes and receive and return information. You’ve fully configured your `hidden`
attributes on your models2, and everything is working nicely.
One of your actions looks like this:
public function update(Request $request, Model $model) {
$data = $request->validate([...]);
$model = $model->update($data);
return $model;
}
Now, imagine you come along later and starting adding more complexity to your app. Maybe you add in an admin section, some more columns to your database tables, as well as new routes and features.
But the two bits of code you haven’t touched are: the controller action above and the list of `hidden`
fields on your model… Suddenly your old untouched `update()`
method is leaking sensitive data from the new db columns you added for admin purposes! 😱
Now, you could argue the fix here is easy: “just remember to update the `hidden`
property on your models when you add fields.” But that requires you to remember, and what if your new admin section needs to use those fields and that’s why you didn’t add them to your `hidden`
property?
Ultimately, the problem is you’re relying on model attributes visibility being global across your whole app. This may work in smaller apps, but as your app grows, you’ll start to have sections with different permission levels that need to return and use different values for different users. At this point, global permissions are no longer useful.
A better way to control attribute permissions is on each route that returns data!
Use something like the `only()`
method on models, or `setVisible()`
on controllers, or maybe pass the collection/array through something like `array_map()`
and manually extract the attributes you need.
Something like this would’ve protected our route:
public function update(Request $request, Model $model) {
$data = $request->validate([...]);
$model->update($data);
return $model->only(['field1', 'field2']);
}
This way, changes to other parts of your app won’t risk leaking data in older untouched routes. Keeping your data secure. 🙂
Spoiler alert: You’ll want to bring your phone or laptop with internet… I’ve got some very ambitious plans. 😈 It’ll either go flawlessly, or all go horribly wrong. Either way should be entertaining to watch! 🤣
We’ve covered these before in Security Tip #8: Sensitive Model Attributes.