Laravel Debug Routes in Production: How to Find and Remove Test Endpoints

Debug and test routes left in production expose phpinfo(), database dumps, and internal application state to anyone who finds them.

High severity Application Security Updated 2026-05-01

The Problem

Developers often create temporary routes during development for testing — routes that dump phpinfo(), display database contents, test email sending, or expose internal state. If these routes reach production, they become an information disclosure vulnerability. Attackers routinely scan for common debug paths like /test, /debug, /phpinfo, /info, and /_dev. A single phpinfo() route reveals your PHP version, extensions, environment variables, and server configuration.

How to Fix

  1. 1

    Find debug routes in your route files

    Search for common debug patterns:

    grep -rn 'phpinfo\|dd(\|dump(\|var_dump\|print_r' routes/ --include='*.php'
    grep -rn 'test\|debug\|tmp\|temp\|_dev' routes/ --include='*.php'

    Also list all registered routes and look for suspicious ones:

    php artisan route:list | grep -i 'test\|debug\|info\|dump'
  2. 2

    Remove or protect debug routes

    Delete debug routes entirely, or if they are needed for development, wrap them in an environment check:

    // REMOVE completely — preferred
    // Route::get('/phpinfo', fn() => phpinfo());
    // Or restrict to local environment only
    if (app()->environment('local')) {
        Route::get('/debug-info', function () {
            return response()->json([
                'php' => phpversion(),
                'laravel' => app()->version(),
            ]);
        });
    }
  3. 3

    Add a CI check to prevent debug routes in production

    Add a test that fails if debug routes exist:
    // tests/Feature/NoDebugRoutesTest.php
    public function test_no_debug_routes_exist(): void
    {
        $debugPatterns = ['phpinfo', 'debug', '_test', '_dev'];
        $routes = collect(Route::getRoutes())->map(fn ($r) => $r->uri());
    foreach ($debugPatterns as $pattern) {
            $matches = $routes->filter(fn ($uri) => str_contains($uri, $pattern));
            $this->assertEmpty($matches, "Debug route found: {$matches->implode(', ')}");
        }
    }

How to Verify

Check common debug paths return 404:

curl -s -o /dev/null -w '%{http_code}' https://yourapp.com/phpinfo
curl -s -o /dev/null -w '%{http_code}' https://yourapp.com/test
curl -s -o /dev/null -w '%{http_code}' https://yourapp.com/debug

All should return 404. Run php artisan stackshield:scan --check=SS051 to verify.

Prevention

Never create debug routes in main route files. Use php artisan tinker for ad-hoc debugging. Add the CI test above to catch debug routes before deployment. Use StackShield to scan for debug routes continuously.

Frequently Asked Questions

Is it safe to use dd() in controllers?

dd() (dump and die) should never exist in production code. It halts execution and outputs internal data to the browser. Use proper logging (Log::debug()) instead, and remove dd() calls before committing.

What about Laravel Telescope routes?

Telescope registers routes at /telescope by default. In production, either disable Telescope entirely (TELESCOPE_ENABLED=false) or restrict access using the gate in TelescopeServiceProvider. Stackshield check SS013 specifically monitors for this.

Related Security Terms

Detect This Automatically with StackShield

StackShield continuously monitors your Laravel application from the outside and alerts you when security issues are found. No installation required.

Start Free Trial