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 Markdown

Debug and test routes are temporary endpoints developers create during development to inspect application state, test functionality, or quickly verify a fix. Common examples include routes that call phpinfo(), dump environment variables, display database contents, trigger test emails, or show session data. These routes solve immediate development needs and are typically created quickly in routes/web.php without thought about their lifecycle.

Attackers specifically target debug-style URL paths because they are found so frequently. Automated scanners maintain wordlists of thousands of common debug path patterns: /phpinfo, /info.php, /test, /debug, /_dev, /.env.bak, /api/debug. These scans run against every domain discovered on the internet, continuously. A phpinfo() page reveals your PHP version, all loaded extensions, environment variables (including those from .env), server configuration, compilation options, and full file paths — everything an attacker needs to tailor further exploits.

The mechanism by which debug routes survive to production is straightforward: they get committed to routes/web.php during development and are never removed. Deployment pipelines typically have no way to detect their presence. Feature branches with debug routes get merged to main. Even when a developer adds if (env('APP_ENV') === 'local') guards, the route may still register before the environment check. The only reliable prevention is automated testing that verifies debug-pattern routes do not exist in the registered route list.

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.

What specific information does a phpinfo() route expose?

A phpinfo() page exposes: PHP version and compiled-in extensions (useful for targeting known CVEs), all environment variables including those from .env (leaking APP_KEY, database credentials, API keys), the full path to every PHP file loaded (helping attackers navigate the filesystem), php.ini settings, and loaded PHP modules. This is equivalent to handing an attacker a blueprint of your server configuration.

How do debug routes survive the development-to-production deployment process?

They typically get committed to version-controlled route files during development and merged without code review. Even when a developer adds if (app()->environment("local")) guards, the route may still register in route caches before the environment check. The most reliable prevention is a test that explicitly checks that no route URIs match a blocklist of debug patterns, failing the CI build if they exist.

Should I use Laravel Pulse or Telescope instead of creating debug routes?

Yes. Laravel Pulse provides real-time application performance monitoring with proper authentication controls. Telescope provides request, query, and log inspection behind an authorization gate. Both are purpose-built for the production debugging use case and include access controls. Creating ad-hoc debug routes bypasses all safeguards and leaves sensitive data publicly accessible.

Related Security Terms

Free security check

Is your Laravel app exposed right now?

34% of Laravel apps we scan have at least one critical issue. Most teams don't find out until something breaks. Our free scan checks your live application in under 60 seconds.

18% have debug mode on
72% missing security headers
12% have exposed .env
Scan My App Free No signup required. Results in 60 seconds.