Security Tip: Disable Debug Mode on World-accessible Apps

[Tip#59] It may seem obvious, you'd be surprised just how often I come across websites where debug mode is enabled!

Security Tip: Disable Debug Mode on World-accessible Apps

🕵️ There is one slot left in December for a Laravel Security Audit and Penetration Test, get in quick for an audit before the end of the year!


One of the first (and most important!) things you should do when deploying code into a world-accessible location is to disable debug mode. It’s something I discover all the time on random websites, and I’ve often heard arguments that it’s useful for debugging, but none of that outweighs the massive security risk of having debug mode enabled. So make it the first thing you do when deploying your code!

In Laravel, this is as simple as setting the `APP_DEBUG` environment variable to `false` within your `.env` file:

APP_DEBUG=false

Setting `APP_DEBUG` to `false` disables the fancy error page that displays a significant amount of sensitive information about your app. This error page, and the information it contains, can leak all sorts of information, and is a gold mine for anyone trying to hack into your app or steal your user’s data.

Error messages themselves can also leak information - such as the full SQL query, or file paths, both of which are incredibly useful when trying to exploit a vulnerability, such as SQL Injection (SQLi), or Local File Inclusion (LFI).

While you’re at it, don’t forget to update `APP_ENV` to `production`, to instruct the app that it’s world-accessible and disable any other debugging features1.

APP_ENV=production

My Recommendation

I recommend you update your `.env.example` to have `APP_DEBUG=false` and `APP_ENV=production` set by default. This does mean you need to modify it any time you’re setting up a local dev, but it prevents you from deploying your code online, copying `.env.example → .env`, and forgetting to disable debug mode.

Trust me, a little pain in local dev is worth it to prevent a breach in production!

As an example, here’s the top of my `.env.example` for my Practical Laravel Security course:

APP_NAME="Practical Laravel Security"
APP_ENV=production
APP_KEY=
APP_DEBUG=false
APP_URL=https://practicallaravelsecurity.app

What do I mean by “world-accessible”?

If the app can be accessed by anyone on the internet, then it’s world-accessible.

This doesn’t just mean production, but also staging, testing, and QA sites too. If a random person can discover the URL somehow and visit it, then it’s world-accessible.

If someone can break into your staging site - which is likely to be buggy and may have security vulnerabilities due to active development - they can then use this to pivot into your production site2, or directly attack your developers. Having debug mode on these sites makes it even easier to compromise them, and in turn, makes it easier to attack production too.

As a side note, I recommend keeping staging, testing, QA, etc, sites on separate root domains and locked behind firewalls or Basic Auth. This makes them harder to find, less exploitable3, and if auth is required before any code is touched, any weaknesses in dev code can’t be easily exploited.


Looking to learn more?
Security Tip #40: Retrieving Request Values
▶️ In Depth #13: Stealing Password Tokens with Forwarded Host Poisoning

  1. Do I need to write a dedicated article about this too?

  2. Through things like shared credentials, bypassing same-site productions if the sites share the same root domain, etc. Or maybe you have prod data on staging? There are a lot of options…

  3. As being on the same-site as production is no longer a concern.