This article shows the steps to report CSP violations in Laravel 12.


The steps

  1. Add a report directive to your CSP policy class and specify where you want the errors to be reported.

    ->add(Directive::REPORT, '/csp-errors')
    
  2. Exclude the route from CSRF checking. Otherwise, you might hit 419 errors.

    // bootstrap/app.php
    
        ->withMiddleware(function (Middleware $middleware) {
            $middleware->validateCsrfTokens(except: [
                '/csp-errors',
            ]);
        })
    
  3. Create a handler for this route, for example, a controller action.

    // Controllers/CspError.php
    
    <?php
    
    namespace App\Http\Controllers;
    
    use Illuminate\Http\Request;
    use Illuminate\Support\Facades\Log;
    
    class CspError extends Controller
    {
        public function __invoke(Request $request)
        {
            $payload = $request->getContent();
            Log::info('CSP Error Reported', [
                'payload' => $payload,
            ]);
    
            // TODO: Send to 3rd party services
    
            return response()->json(['status' => 'ok'], 200);
        }
    }
    
  4. Declare the route.

    // routes/web.php
    
    Route::post('/csp-errors', [\App\Http\Controllers\CspError::class, '__invoke'])
        ->name('csp-errors');
    
  5. (Optional) Make the route applicable for certain environments only.

  6. (Optional) Add a rate limit to the route to prevent the log file from growing due to repetitive errors.


Test the implementation

  1. Produce a CSP violation and check the Laravel log.

    // laravel.log
    
    {
        "payload": {
            "csp-report": {
                "document-uri": "http://localhost:8000",
                "referrer": "http://localhost:8000",
                "violated-directive": "style-src-elem",
                "effective-directive": "style-src-elem",
                "original-policy": "default-src 'none';connect-src 'self';img-src 'self';font-src fonts.gstatic.com;style-src fonts.googleapis.com 'self';script-src 'self';report-uri /csp-errors",
                "disposition": "enforce",
                "blocked-uri": "inline",
                "line-number": 1,
                "source-file": "http://localhost:8000",
                "status-code": 200,
                "script-sample": ""
            }
        }
    }