

Discover more from Securing Laravel
Security Tip: Don't Hardcode Admin Emails
[Tip#17] It's easy to forget to update the admins list when it changes...
Greetings friends! A big welcome to all the new subscribers, it’s great to have you here! 😀 As of the time of writing this, there are over 764 (free and paid) subscribers to Laravel Security in Depth, which is incredible. Thanks for your support and your desire to learn more about Laravel Security!
If you’re a free subscriber, please consider upgrading to a paid subscription to receive weekly security tips (like this one), and our big monthly In Depth emails. Our next In Depth goes out next week, and will cover Content Security Policies, and trust me, you’re going to want to read this one!
One final thing before we move onto our tip. I’ve recently started doing Security Audits and Penetration tests for Laravel apps. If you’re interested in getting me to audit your apps and help you with security, please reach out!
Don’t Hardcode Admin Emails
Hardcoded admin emails (or usernames) are something I’ve seen in almost every codebase I’ve worked on and/or audited. That’s really not surprising though, since the documentation itself basically tells you to do it like this1. However when it comes to security, it’s a terrible idea.
Let’s take Laravel Nova as an example. The Nova documentation tells you to add a Gate definition into your app/Providers/NovaServiceProvider.php
to define admin users.
Consider this Gate:
Gate::define('viewNova', function ($user) {
return in_array($user->email, [
'frodo@example.com',
'samwise@example.com',
'meriadoc@example.com',
'peregrin@example.com',
'fredegar@example.com',
]);
});
It looks simple and easy to update, but it’s 2 levels deep inside a system class, so it’s super easy to forget about. If one of the admins leaves the company (or loses admin access), there is a good chance their email address will be left in the list and retain admin access.
If their account is compromised or given to someone else, that admin access will be available when it shouldn’t be. This potentially opens up admin access to a hacker or someone with malicious intentions. In this example, Nova gives full access to modify the database - which gives the hacker full access to do whatever they want.
Consider the scenario where they are fired and want to get revenge? How quickly can you revoke access, if you need to make a code change, push through a PR, merge and test in CI, and then deploy to your fleet? (Assuming you remember to update the service provider at all!)
Also, if you’re using multiple packages with their own authorization lists, it’s easy to forget some of them when adding/removing admins, leaving lingering access in some areas.
The worst offender is putting the admin list in your javascript. This is sent to the browser, so anyone who discovers it has full access to your list of admins. It’s then trivial to look up credential stuffing lists to find potentially working passwords for a site admin account2. 😱
What To Do Instead
There are some really simple ways to avoid hardcoding admin emails. I usually either store admin permissions in the database, or define emails in configuration files. It doesn’t really matter how you do it as long as it’s not hardcoded, and is easy to change and review securely.
Here are two example solutions:
1. Define an admin
flag on the user models:
Gate::define('viewNova', function ($user) {
return $user->admin;
});
This also solves the Javascript problem, as the user model data passed to the browser can contain the admin flag too.
2. Store the admins list in .env:
// .env
APP_ADMINS="frodo@example.com,samwise@example.com,meriadoc@example.com,peregrin@example.com,fredegar@example.com"
// config/app.php
'admins' => explode(',', env('APP_ADMINS')),
// NovaServiceProvider
Gate::define('viewNova', function ($user) {
return in_array($user->email, config('app.admins'));
});
If you want to scare yourself, go to Have I Been Pwned and check all of your admin emails. I guarantee at least one will have been pwned (if it’s not a newish company domain).
Also, don’t forget to subscribe to alerts for your domain names , to receive alerts if anyone on your team is pwned.