Security 15 min read

The Complete Laravel Security Checklist for 2026

A comprehensive, 30-point security checklist covering every layer of your Laravel application. From .env protection and security headers to debug mode detection and DNS security.

Matt King
Matt King
March 11, 2026
Last updated: March 11, 2026
The Complete Laravel Security Checklist for 2026

A Laravel security checklist is a structured set of checks that verify your application is protected against common vulnerabilities, misconfigurations, and attack vectors. This checklist covers 30 items across six categories, each with specific actions you can take today to harden your Laravel application.

According to the OWASP Foundation, security misconfiguration is consistently one of the top 10 web application security risks. Laravel applications are particularly susceptible because they ship with powerful development tools (Telescope, Ignition, Horizon) that can expose sensitive data if left accessible in production.

Key takeaways:

  • 30 actionable security checks organized by category
  • Each item includes what to check, why it matters, and how to fix it
  • Covers application, infrastructure, authentication, file security, DNS, and email
  • Designed for teams that deploy frequently and need continuous verification

Application Security

1. Disable debug mode in production

Laravel's debug mode (APP_DEBUG=true) exposes stack traces, environment variables, database credentials, and internal paths. According to a 2024 study by Detectify, exposed debug pages are among the top 5 most common web application misconfigurations.

How to fix it:

APP_DEBUG=false
APP_ENV=production

Verify by visiting your application and triggering a 404. You should see your custom error page, not a stack trace.

2. Protect your .env file from public access

The .env file contains your application's most sensitive secrets: database passwords, API keys, mail credentials, and encryption keys. If your web server is misconfigured, this file can be downloaded directly via https://yourapp.com/.env.

How to fix it:

Ensure your web server's document root points to the /public directory, not the project root. In Nginx:

root /var/www/yourapp/public;

Add an explicit block as a safety net:

location ~ /\.env {
    deny all;
    return 404;
}

3. Set security headers

Security headers instruct the browser how to handle your content and are one of the most effective defenses against XSS, clickjacking, and data injection attacks. Many Laravel applications ship without them.

Required headers and what they prevent:

Header Prevents
Content-Security-Policy Cross-site scripting (XSS)
Strict-Transport-Security Protocol downgrade attacks
X-Frame-Options Clickjacking
X-Content-Type-Options MIME-type sniffing
Referrer-Policy Referrer data leakage
Permissions-Policy Unauthorized browser feature access

How to fix it:

Add a middleware to set headers on every response:

// app/Http/Middleware/SecurityHeaders.php
public function handle($request, Closure $next)
{
    $response = $next($request);

    $response->headers->set('X-Frame-Options', 'SAMEORIGIN');
    $response->headers->set('X-Content-Type-Options', 'nosniff');
    $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');

    return $response;
}

Register it in your bootstrap/app.php or Kernel.php for all web routes.

4. Block access to Laravel Telescope in production

Laravel Telescope is a debugging assistant that logs every request, query, job, mail, notification, and cache operation. If accessible in production, it exposes your entire application's behavior to anyone who finds the /telescope endpoint.

How to fix it:

In app/Providers/TelescopeServiceProvider.php, restrict access:

protected function gate()
{
    Gate::define('viewTelescope', function ($user) {
        return in_array($user->email, [
            'admin@yourapp.com',
        ]);
    });
}

Or disable Telescope entirely in production by setting TELESCOPE_ENABLED=false in your .env.

5. Block access to Laravel Ignition error pages

Ignition is Laravel's error page handler. In production, it can expose file paths, environment variables, and database queries in stack traces. Attackers use this information to map your application's internals.

How to fix it:

Ensure APP_DEBUG=false in production (this disables Ignition's detailed error pages). For additional safety, set a custom error handler that shows generic error pages.

6. Block access to Laravel Horizon

Laravel Horizon provides a dashboard for monitoring your Redis queues. If publicly accessible, it reveals job payloads, failure data, and queue throughput, which can contain user data and business logic.

How to fix it:

Use the HorizonServiceProvider to restrict access:

protected function gate()
{
    Gate::define('viewHorizon', function ($user) {
        return in_array($user->email, [
            'admin@yourapp.com',
        ]);
    });
}

7. Check for CORS misconfiguration

An overly permissive CORS policy (Access-Control-Allow-Origin: *) allows any website to make authenticated requests to your API on behalf of your users.

How to fix it:

In config/cors.php, explicitly define allowed origins:

'allowed_origins' => ['https://yourfrontend.com'],

Never use * for applications that handle authenticated requests.

8. Implement CSRF protection on all forms

Laravel includes CSRF protection by default, but it only works if you use it. Every form must include the @csrf directive, and every AJAX request must send the X-CSRF-TOKEN header.

How to verify:

<form method="POST" action="/submit">
    @csrf
    <!-- form fields -->
</form>

Check that the VerifyCsrfToken middleware is applied to all web routes and that no routes are unnecessarily excluded.


Infrastructure Security

9. Enforce SSL/TLS with a valid certificate

All traffic to your application must be encrypted. An expired or misconfigured SSL certificate allows man-in-the-middle attacks and causes browsers to display security warnings that drive users away.

What to check:

  • Certificate is valid and not expired
  • Certificate covers all subdomains (wildcard or SAN)
  • Strong cipher suites are used (TLS 1.2+ minimum)
  • HSTS header is set (see item 3)

How to fix it:

Use Let's Encrypt for free automated certificates, or your hosting provider's SSL management. Force HTTPS in Laravel:

// app/Providers/AppServiceProvider.php
public function boot()
{
    if (app()->environment('production')) {
        URL::forceScheme('https');
    }
}

10. Run a port scan on your server

Open ports expose services to the internet. Common issues include exposed database ports (3306 for MySQL, 5432 for PostgreSQL), Redis (6379), and debug services.

What should be open:

  • Port 80 (HTTP, redirects to 443)
  • Port 443 (HTTPS)
  • Port 22 (SSH, ideally restricted by IP)

Everything else should be firewalled. Use ufw on Ubuntu:

sudo ufw default deny incoming
sudo ufw allow 22/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable

11. Check your IP reputation

If your server's IP address appears on abuse blacklists, your emails will be blocked and your application may be flagged by security tools. This can happen if a previous tenant used the IP for spam, or if your server has been compromised.

How to check:

Use services like AbuseIPDB or MXToolbox to verify your server IP is clean.

12. Implement API rate limiting

Without rate limiting, attackers can brute-force login endpoints, scrape data, or overwhelm your application with requests. Laravel provides built-in rate limiting.

How to fix it:

// routes/api.php
Route::middleware('throttle:60,1')->group(function () {
    // API routes limited to 60 requests per minute
});

For login endpoints, use stricter limits:

Route::middleware('throttle:5,1')->post('/login', [AuthController::class, 'login']);

13. Perform a web vulnerability scan

Automated vulnerability scanners (like OWASP ZAP) test your application for common attack patterns: SQL injection, XSS, directory traversal, and more. Running these scans regularly catches vulnerabilities that code review alone might miss.

14. Check for technology fingerprinting

Attackers use tools like WhatWeb to identify your framework version, server software, and installed packages. Each exposed version number helps them find known vulnerabilities to exploit.

How to reduce your fingerprint:

  • Remove the X-Powered-By header
  • Don't expose Laravel or PHP version in responses
  • Use generic error pages in production

Authentication and Session Security

15. Implement brute force protection on login

Without brute force protection, an attacker can attempt thousands of password combinations against your login endpoint. Laravel provides rate limiting per IP on authentication routes.

How to fix it:

If using Laravel Breeze or Fortify, brute force protection is built in. If using custom auth:

Route::middleware('throttle:5,1')->post('/login', [LoginController::class, 'store']);

Consider adding account lockout after repeated failures.

16. Use secure session configuration

Session hijacking allows an attacker to impersonate a logged-in user. Proper session configuration prevents this.

What to check in config/session.php:

'secure' => true,        // Only send cookies over HTTPS
'http_only' => true,     // Prevent JavaScript access to session cookie
'same_site' => 'lax',   // Prevent CSRF via cross-site requests
'lifetime' => 120,       // Session timeout in minutes

17. Secure your JWT tokens (if applicable)

If your application uses JWT authentication, weak tokens or missing expiration can lead to unauthorized access that persists indefinitely.

What to check:

  • Tokens have a reasonable expiration time (15-60 minutes for access tokens)
  • Refresh tokens are stored securely
  • The signing algorithm is RS256 (not HS256 with a weak secret)
  • Tokens are invalidated on logout

File and Directory Security

18. Block access to sensitive Laravel files

Several files in a Laravel project should never be publicly accessible:

File/Directory Risk if exposed
.env Database credentials, API keys, app key
.git/ Entire source code and commit history
storage/logs/ Error logs with stack traces and user data
composer.json Dependency versions for targeted exploits
database/ Migration files revealing schema

How to fix it:

Ensure your web server only serves files from the public/ directory. Add explicit deny rules:

location ~ /\.(env|git) {
    deny all;
    return 404;
}

location ~ ^/(storage|database|bootstrap) {
    deny all;
    return 404;
}

19. Secure file upload handling

Insecure file uploads can lead to remote code execution if an attacker uploads a PHP file disguised as an image.

How to fix it:

$request->validate([
    'file' => 'required|file|mimes:jpg,png,pdf|max:10240',
]);

// Store outside the public directory
$path = $request->file('file')->store('uploads', 's3');

Never store uploads in a publicly executable directory. Validate MIME types on the server side, not just file extensions.

20. Prevent directory listing

If directory listing is enabled on your web server, anyone can browse your file structure by navigating to a directory URL.

How to fix it in Nginx:

autoindex off;

In Apache:

Options -Indexes

21. Check for exposed cloud storage buckets

Misconfigured AWS S3, Google Cloud Storage, or DigitalOcean Spaces buckets can expose user files, backups, and application data to the public internet.

What to check:

  • No public read/write access on buckets containing sensitive data
  • Bucket policies restrict access to your application's IAM role
  • No sensitive data in publicly accessible buckets

DNS Security

22. Audit your DNS records

Stale or misconfigured DNS records create security risks. Unused subdomains pointing to decommissioned services are prime targets for subdomain takeover attacks.

What to check:

  • Remove DNS records for services you no longer use
  • Verify all A/CNAME records point to infrastructure you control
  • Check for wildcard records that could be exploited

23. Prevent subdomain takeover

A subdomain takeover occurs when a DNS record points to an external service (like Heroku, S3, or GitHub Pages) that you no longer control. An attacker can claim that service and serve content on your subdomain, potentially phishing your users.

How to fix it:

Audit all CNAME records. If a subdomain points to a third-party service, verify you still own that service. Remove DNS records for any decommissioned services immediately.

24. Configure DNS security features

Modern DNS providers offer security features that protect against cache poisoning, unauthorized transfers, and spoofing.

What to enable:

  • DNSSEC (DNS Security Extensions) to prevent cache poisoning
  • Disable zone transfers to unauthorized servers
  • Use reputable DNS providers with DDoS protection

Email Security

25. Set up SPF records

Sender Policy Framework (SPF) tells receiving mail servers which IP addresses are authorized to send email for your domain. Without it, attackers can spoof emails from your domain.

How to fix it:

Add a TXT record to your DNS:

v=spf1 include:_spf.google.com include:sendgrid.net -all

Replace the include values with your actual email providers.

26. Configure DKIM signing

DomainKeys Identified Mail (DKIM) adds a cryptographic signature to your emails, proving they haven't been tampered with in transit.

How to fix it:

Your email provider (SendGrid, Mailgun, AWS SES, etc.) will provide DKIM keys. Add the provided CNAME or TXT records to your DNS.

27. Implement DMARC policy

Domain-based Message Authentication, Reporting, and Conformance (DMARC) tells receiving servers what to do when SPF or DKIM checks fail. Without DMARC, even properly configured SPF and DKIM can be bypassed.

How to fix it:

Start with a monitoring policy, then move to enforcement:

// Start with monitoring
v=DMARC1; p=none; rua=mailto:dmarc-reports@yourapp.com

// Move to enforcement after reviewing reports
v=DMARC1; p=reject; rua=mailto:dmarc-reports@yourapp.com

Monitoring and Maintenance

28. Audit dependencies with Composer

Run composer audit regularly to check for known vulnerabilities in your dependencies. A single vulnerable package can compromise your entire application.

composer audit

Add this to your CI/CD pipeline to block deployments with known vulnerabilities.

29. Keep Laravel and packages updated

Each Laravel release includes security patches. Running outdated versions means known vulnerabilities remain exploitable. Track Laravel security releases at the Laravel News security tag.

30. Set up continuous external monitoring

Internal security tools and CI/CD checks only see your code and development pipeline. They miss what attackers see: your live application from the outside. Continuous external monitoring scans your running application and alerts you when your attack surface changes.

What external monitoring catches that internal tools miss:

  • Debug mode accidentally enabled after a deployment
  • Security headers removed during an infrastructure change
  • Development tools (Telescope, Ignition) left accessible
  • DNS records pointing to decommissioned services
  • SSL certificate approaching expiration
  • New open ports from infrastructure changes

StackShield runs 30+ external security checks against your Laravel application continuously, alerting your team via Slack, email, or webhooks when something changes.


Using This Checklist

This checklist is most effective when used continuously, not as a one-time audit. Your attack surface changes with every deployment, dependency update, and infrastructure change.

Recommended approach:

  1. Run through this checklist manually once to establish your baseline
  2. Fix any issues you find, prioritizing items that expose sensitive data
  3. Set up automated monitoring to continuously verify these items
  4. Re-audit after every significant deployment or infrastructure change

For automated verification of most items on this checklist, start a free 14-day trial of StackShield.

Frequently Asked Questions

How often should I run a Laravel security audit?

You should run security checks continuously, not just once. Your attack surface changes with every deployment, dependency update, and infrastructure change. Automated tools like StackShield run 30+ checks on every scan, so you catch issues within minutes rather than discovering them weeks later during a manual review.

What are the most common Laravel security vulnerabilities?

The most common Laravel security vulnerabilities include exposed .env files, debug mode left enabled in production, missing security headers (CSP, HSTS, X-Frame-Options), exposed development tools like Telescope and Ignition, weak CSRF protection, insecure file upload handling, and SQL injection through unparameterized queries.

Is Laravel secure by default?

Laravel provides strong security foundations including CSRF protection, Eloquent ORM (which prevents SQL injection), Bcrypt password hashing, and encrypted cookies. However, these defaults only protect you if configured correctly. Misconfigurations, exposed debug tools, missing security headers, and insecure deployment practices can override these built-in protections.

What is the difference between internal security testing and external security monitoring?

Internal security testing (SAST, dependency scanning, CI/CD gates) analyzes your source code and development pipeline. External security monitoring scans your live, running application from the outside, the same way an attacker would. Internal tools catch code-level issues before deployment. External monitoring catches configuration drift, exposed endpoints, and infrastructure issues that only appear in production.

Do I need a security checklist if I use a WAF?

Yes. A Web Application Firewall (WAF) blocks known attack patterns, but it does not detect configuration issues like debug mode being enabled, exposed .env files, missing security headers, or accessible development tools. A WAF and a security checklist serve different purposes and should be used together for comprehensive protection.

Related Security Terms