Vulnerability
Laravel

Missing Security Headers in Laravel

Laravel does not set security headers like Content-Security-Policy or Strict-Transport-Security by default. While Laravel includes some cookie security settings and CSRF protection out of the box, HTTP response headers must be configured through custom middleware or packages like spatie/laravel-csp.

Scan Your Laravel App

How Missing Security Headers Manifests in Laravel

Laravel responses include X-Powered-By: PHP by default (from PHP itself, not Laravel), which leaks technology information. Laravel does not add Content-Security-Policy, Strict-Transport-Security, X-Content-Type-Options, Referrer-Policy, or Permissions-Policy headers. Developers often assume that Laravel's built-in CSRF protection covers all browser-based attacks, but CSRF tokens do not prevent XSS, clickjacking, or MIME sniffing — those require separate HTTP headers. Laravel Sanctum and Passport handle API authentication but do not set security headers on responses. API responses are just as susceptible to missing HSTS and X-Content-Type-Options as web responses. When using Laravel with Inertia.js or Livewire, the rendered HTML pages need CSP headers, but the default scaffold does not include them. Livewire requires specific CSP configuration because it uses inline scripts for its hydration mechanism.

Real-World Impact

A Laravel e-commerce application was deployed without HSTS. A customer connected through a hotel Wi-Fi network where an attacker performed SSL stripping, intercepting the session cookie on the initial HTTP request before the server redirected to HTTPS. Another Laravel app used Blade templates with {!! !!} unescaped output for rich text content. Without CSP headers, a stored XSS payload in a product description executed on every page view, redirecting users to a phishing site that mimicked the checkout page.

Step-by-Step Fix

1

Create a security headers middleware

Build a Laravel middleware that adds all essential security headers to every response.

// app/Http/Middleware/SecurityHeaders.php
<?php
namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;

class SecurityHeaders
{
    public function handle(Request $request, Closure $next)
    {
        $response = $next($request);

        $response->headers->set('X-Content-Type-Options', 'nosniff');
        $response->headers->set('X-Frame-Options', 'DENY');
        $response->headers->set('Referrer-Policy', 'strict-origin-when-cross-origin');
        $response->headers->set('Permissions-Policy', 'camera=(), microphone=(), geolocation=()');
        $response->headers->set(
            'Strict-Transport-Security',
            'max-age=31536000; includeSubDomains; preload'
        );
        $response->headers->remove('X-Powered-By');

        return $response;
    }
}
2

Register the middleware globally

Add the middleware to the global middleware stack so it applies to all routes.

// bootstrap/app.php (Laravel 11+)
use App\Http\Middleware\SecurityHeaders;

return Application::configure(basePath: dirname(__DIR__))
    ->withMiddleware(function (Middleware $middleware) {
        $middleware->append(SecurityHeaders::class);
    })
    ->create();

// Or in app/Http/Kernel.php (Laravel 10 and below)
protected $middleware = [
    \App\Http\Middleware\SecurityHeaders::class,
    // ... other global middleware
];
3

Add CSP with spatie/laravel-csp

Install the spatie/laravel-csp package for robust Content-Security-Policy management.

// composer require spatie/laravel-csp
// php artisan vendor:publish --tag=csp-config

// config/csp.php
return [
    'enabled' => true,
    'report_only' => false,
    'policy' => App\Support\CspPolicy::class,
];

// app/Support/CspPolicy.php
<?php
namespace App\Support;

use Spatie\Csp\Directive;
use Spatie\Csp\Policies\Policy;

class CspPolicy extends Policy
{
    public function configure()
    {
        $this
            ->addDirective(Directive::DEFAULT, 'self')
            ->addDirective(Directive::SCRIPT, 'self')
            ->addDirective(Directive::STYLE, ['self', 'unsafe-inline'])
            ->addDirective(Directive::IMG, ['self', 'data:', 'https:'])
            ->addDirective(Directive::FONT, 'self')
            ->addDirective(Directive::FRAME_ANCESTORS, 'none');
    }
}

Prevention Best Practices

1. Create a custom middleware to set all security headers on every response. 2. Use spatie/laravel-csp for Content-Security-Policy management. 3. Remove X-Powered-By by disabling expose_php in php.ini. 4. Configure Strict-Transport-Security once HTTPS is confirmed. 5. If using Livewire, configure CSP nonces for its inline scripts. 6. Apply security headers to both web and API route groups.

How to Test

1. Run curl -I https://your-laravel-app.com/ and check for missing security headers. 2. Verify headers on web routes, API routes, and error pages (404, 500). 3. Check that X-Powered-By is removed from responses. 4. Test CSP by attempting to inject an inline script through a form field. 5. Use Vibe App Scanner to automatically detect missing security headers in your Laravel application.

Frequently Asked Questions

Does Laravel set any security headers by default?

No. Laravel does not set CSP, HSTS, X-Content-Type-Options, or Permissions-Policy headers by default. It does include CSRF protection middleware and secure cookie settings, but these are separate from HTTP security headers. You must add headers through custom middleware.

Will CSP break Laravel Livewire?

Livewire injects inline scripts for component hydration. A strict CSP that blocks inline scripts (without nonces) will break Livewire. Use nonce-based CSP and configure Livewire to use the nonce. The spatie/laravel-csp package supports nonces that integrate with Livewire.

Should I set security headers in Laravel or in Nginx?

Set them in both for defense in depth. Laravel middleware ensures headers are present regardless of the server configuration. Nginx or Apache headers provide a safety net if the application middleware fails. If they conflict, the last one set typically wins, so ensure they are consistent.

Is Your Laravel App Vulnerable to Missing Security Headers?

VAS automatically scans for missing security headers vulnerabilities in Laravel applications and provides step-by-step remediation guidance with code examples.

Scans from $5, results in minutes. Get actionable fixes tailored to your Laravel stack.