← All articles

Why APP_DEBUG=true in production is dangerous (and how to catch it)

· 4 min read

APP_DEBUG=true is the right setting on your laptop. On a public server it is a standing invitation: every unhandled error renders a detailed debug page to whoever caused it, including people who caused it on purpose.

What debug mode exposes

When an exception happens with debug on, Laravel shows a detailed error page instead of a plain "Server Error". The Laravel documentation is blunt about it: in production the value should always be false, because otherwise "you risk exposing sensitive configuration values to your application's end users."

Typically the page includes the stack trace with absolute file paths on your server, the code around the failing line, request details and, for database errors, the SQL involved. Each piece is useful to an attacker. File paths and versions narrow down which known exploits apply, and query text reveals your schema.

Debug mode has also been the precondition for serious bugs. The best-known example is CVE-2021-3129, a critical (CVSS 9.8) remote code execution flaw in Ignition, the debug error page used by older Laravel versions. It affected Ignition before 2.5.2 on sites running with debug mode enabled, and it appears in CISA's catalog of vulnerabilities exploited in the wild. A site with APP_DEBUG=false did not expose that code path.

The point is not one specific vulnerability. Debug mode widens what an attacker can see and reach, on every error, for every visitor.

Check your app

On the server, in the app directory:

php artisan config:show app.debug
php artisan config:show app.env

You want false and production. This reads the values Laravel actually uses, which matters because of the next section.

The config cache trap

If you run php artisan config:cache during deploys, the framework stops loading your .env file at runtime. The docs put it this way: once the configuration is cached, the .env file "will not be loaded", so changes to it have no effect until you rebuild. Editing APP_DEBUG=false and seeing no change is a classic way to believe you fixed it when you did not.

After changing .env, rebuild:

php artisan config:clear
php artisan config:cache

Then run config:show again to confirm what the app really sees.

Fix it

In the production .env:

APP_ENV=production
APP_DEBUG=false

Rebuild the config cache as above, then reload PHP-FPM so a stale OPcache does not keep serving old code:

sudo systemctl reload php8.4-fpm

Use the unit name that matches your PHP version. With debug off, users see a generic error page. You still get the details where they belong: in storage/logs/laravel.log or in an error tracker such as Sentry or Flare, not in the browser.

Why it keeps happening

Debug gets turned on to chase a production bug at 11 pm and never turned off. Or a .env is copied from a staging server. Or a new server is set up from an old template. None of these are exotic, and none of them announce themselves.

That is why it is worth checking automatically instead of remembering to. PHPGuard's agent reads each Laravel app on your server and raises a critical finding when it sees APP_DEBUG=true in a production environment, then emails you when it first turns red. You can also try the free external scan for the issues visible from outside.

Checklist

  • APP_ENV=production and APP_DEBUG=false on every production server.
  • Rebuild the config cache after every .env change, then confirm with php artisan config:show.
  • Send errors to logs or an error tracker, not to the browser.
  • Check after each deploy or server change, not only once.

Check your own site

The free PHPGuard scan checks for exposed .env and .git files, missing security headers and SSL problems in seconds. For continuous monitoring from inside your server, start the 14-day free trial (no card required).

More articles