> ## Content Index
> Fetch the complete content index at: https://securinglaravel.com/llms.txt
> Use this file to discover other available public pages before exploring further.

# Security Tip: Please Stop Hardcoding Admin Domains!
- URL: https://securinglaravel.com/security-tip-please-stop-hardcoding-admin-domains/
- Published: 2024-12-11T03:01:58.000Z
- Updated: 2024-12-11T03:01:57.000Z
- Description: [Tip #99] Let me tell you a story about a time when a single missing character allowed me to escalate my privileges and gain admin access, despite all the protections designed to stop me! 😈
- Author: Stephen Rees-Carter
- Tags: Security Tips, Audits Top 10, Privilege Escalation, Authorisation

💡

**We're digging into the weaknesses identified in the updated* [**Laravel Security Audits Top 10*](https://securinglaravel.com/in-depth-laravel-security-audits-top-10-2024/) *list for 2024\. This week we're looking at* ***#2 - Committed Credentials & Admin Emails!**

Something I come across a lot when conducting [security audits](https://valorinsecurity.com/?ref=securinglaravel.com) is hardcoded credentials and API keys. They'll usually be sitting directly in the code where they are used, scattered throughout the app and duplicated every time the app needs them. I'll also typically find hardcoded admin email addresses or admin wildcard domains in policies and gates too - all of which inside the code itself.

I've talked this issue a [few times](https://securinglaravel.com/tag/secrets/) [before](https://securinglaravel.com/tag/privilege-escalation/), but since it's still sitting at #2 in my [Top 10](https://securinglaravel.com/tag/audits-top-10/), a reminder is clearly needed, so let me tell you a story about a recent security audit I did...

One of the steps in my [audit process](https://securinglaravel.com/tag/pentesting-laravel/) is to check Service Providers for any interesting-looking code, such as hardcoded credentials and authorisation gates. As is pretty typical, this site did not disappoint, and I discovered the following authorisation gate in the Nova service provider. 

```php
Gate::define('viewNova', function ($user) {
    $allowedDomain = 'company.com';
    $allowedEmails = ['user@gmail.com'];

    if (str_ends_with($user->email, '@' . $allowedDomain)) {
        return true;
    }

    if (in_array($user->email, $allowedEmails)) {
        return true;
    }

    return false;
});
```

`\App\Providers\NovaServiceProvider`

As you would expect, this code got me rather excited for the possibilities - could I exploit this to access Nova?

The `str_ends_with()` method requires the email to end in `@company.com`, which means all I had to do was change my email address to something like `hacker@company.com`... in theory.

I headed over to my Profile edit page, tried to update my email address to `hacker@company.com`, and saw a very disappointing validation error:

```
The email address cannot end in @company.com.
```

I then proceeded to look for other forms where I could submit an email address, such as:

- User Registration Page
- Admin User Creation (tenant level, outside Nova)
- Admin User Edit (tenant level, outside Nova)

All three (plus the profile edit) had the same validation rule blocking email addresses that ended in `@company.com`. 😭

I kept digging and started to look for other areas the `User` model was used, to see if there were other forms that allow for email to be set, and discovered this method on the `User` model itself:

```php
public function isSystemAdmin(): bool
{
    return str_ends_with($this->email, 'company.com');
}
```

`\App\Models\User`

Which is very similar to the Nova gate, but with one massive difference: **it's missing the `@` prefix.** Which means an email address of `hacker@evilcompany.com` will be considered a *System Admin*! 🎉

A few seconds of digging later and I find the `UserIsSystemAdmin` Middleware uses this method internally, which protects a bunch of non-Nova system admin controls. **I'm in! 😈**

## Summary

This story really demonstrates the risks involved in hardcoding admin domains in your code. 

While the Nova Authorisation Gate and Form Validation were functioning correctly, preventing emails with `@company.com` from being used, the fact that the company domain was duplicated within the code meant a subtle difference (in this case, a missing `@`) left the app vulnerable. Although I wasn't able to gain access to Nova directly, I was still able to escalate my access well beyond what my account was supposed to have.

**My recommendation is:**

Don't use [domain wildcards](https://securinglaravel.com/security-tip-privilege-escalation-through-domain-wildcards/) for authorisation controls, define every admin manually, and eitherdefine your admin emails in a `.env` variable, or define your admins through a database flag.

This allows you to be intentional about who has admin access, easily review the list, and update it in a central location.

---

***If you found this security tip useful,*** [***subscribe***](#/portal/signup) ***to get weekly*** [***Security Tips***](https://securinglaravel.com/tag/tips/) **straight to your inbox.* Upgrade to a* [*premium subscription*](#/portal/signup) *for exclusive monthly* [*In Depth articles*](https://securinglaravel.com/tag/in-depth/)*, or drop a coin in the* [*tip jar*](#/portal/support) *to show your support.*

*Looking for a* [*Laravel Security Audit / Penetration Test*](https://stephenreescarter.net/laravel-security-audits-and-pentesting/?utm%5Fsource=securinglaravel.com)*, or a budget-friendly* [*Security Review*](https://stephenreescarter.net/laravel-security-reviews/?utm%5Fsource=securinglaravel.com)*? Feel free to reach out! You can also connect with me on* [*Bluesky*](https://bsky.app/profile/valorin.bsky.social?ref=securinglaravel.com)*, or* [*other socials*](https://pinkary.com/@valorin?ref=securinglaravel.com)*. And don’t miss* [*Practical Laravel Security*](https://practicallaravelsecurity.com/?utm%5Fsource=securinglaravel.com)*, my interactive course designed to boost your Laravel security skills.*