Strengthening Your Laravel 12 App Against Modern Threats
Laravel 12 offers developers a powerful and expressive framework with a solid foundation for secure application development. However, even with these strong defaults, real-world applications remain vulnerable when security is overlooked or poorly implemented.
This post outlines practical, actionable security practices to help you harden your Laravel app against common threats — including input validation, secure file uploads, HTTPS, and more. Whether you're maintaining a legacy app or launching something new, these steps will guide you towards a secure-by-default mindset.

1. Input Validation and Sanitisation
Never trust incoming data — even if it originates from your own frontend or API consumers.
Laravel makes validation straightforward using Form Request classes and the Validator facade. Always validate all incoming data, regardless of the source.
$request->validate([
'email' => 'required|email|exists:users,email',
'age' => 'nullable|integer|min:18',
]);
To sanitise data before validation, use prepareForValidation() in Form Requests:
protected function prepareForValidation(): void
{
$this->merge([
'email' => strtolower($this->email),
]);
}
For larger applications, consider using Data Transfer Objects (DTOs) to structure and sanitise validated data consistently.
2. Authentication and Authorisation
Always implement robust access control — and for most Laravel applications, the Spatie Laravel Permission package is the industry standard.
Define roles and permissions centrally and attach them to users:
$user->assignRole('editor');
$user->givePermissionTo('edit articles');
Protect routes with middleware:
Route::post('/admin')->middleware('permission:access admin panel');
Use Blade directives in views:
@can('edit articles')
Edit Article
@endcan
For sensitive actions like login or password reset, apply rate-limiting:
Route::post('/login')->middleware('throttle:5,1');
You may also wish to implement Multi-Factor Authentication (MFA) using Laravel Fortify or a custom solution for high-privilege accounts.
3. Enforce HTTPS and Secure Headers
Securing data transmission over HTTPS is essential for protecting sensitive user information. Beyond that, modern browsers support several security-related HTTP headers that can further reduce your application's exposure to common web vulnerabilities.
Force HTTPS
Redirect all HTTP traffic to HTTPS to ensure encrypted connections:
public function handle($request, Closure $next)
{
if (!$request->secure()) {
return redirect()->secure($request->getRequestUri());
}
return $next($request);
}
Key HTTP Security Headers
Here’s a breakdown of the most important headers you should consider adding:
- Strict-Transport-Security (HSTS)
Tells the browser to only access the site via HTTPS — even if a user types in "http://". Helps prevent protocol downgrade attacks.
Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
Restricts where resources like scripts, styles, or images can be loaded from. Helps mitigate Cross-Site Scripting (XSS) and data injection attacks.
Example (restrict scripts to self and CDN only):
Content-Security-Policy: default-src 'self'; script-src 'self' cdn.example.com;
Prevents your app from being embedded in an <iframe>, reducing the risk of clickjacking attacks.
X-Frame-Options: DENY
Stops browsers from trying to "guess" the content type and forces them to follow the declared MIME type. Helps prevent MIME-type sniffing attacks.
X-Content-Type-Options: nosniff
Controls how much referrer information is sent with requests.
Referrer-Policy: no-referrer-when-downgrade
Replaces Feature-Policy. Lets you opt in/out of browser features like camera, geolocation, or autoplay.
Permissions-Policy: geolocation=(), camera=()
Applying Headers
You can set these headers globally using custom middleware or use a package like bepsvpt/secure-headers to manage them with a config file:
composer require bepsvpt/secure-headers
Then publish the config and adjust:
php artisan vendor:publish --provider="Bepsvpt\SecureHeaders\SecureHeadersServiceProvider"
These headers work together to strengthen client-side security, reduce browser-based threats, and demonstrate to users (and search engines) that your site is serious about protecting data.
4. Database Security and Mass Assignment
Avoid mass-assignment vulnerabilities by never blindly assigning request data:
// Risky
$user->update($request->all());
// Safer
$user->update($request->only(['name', 'email']));
Protect model properties using $fillable or $guarded:
protected $fillable = ['name', 'email'];
Use parameter binding in raw queries to prevent SQL injection:
DB::select('SELECT * FROM users WHERE email = ?', [$email]);
5. Secure File Uploads
File uploads are a common attack vector and must be tightly controlled.
Validate file type and size before storing:
$request->validate([
'photo' => 'required|image|mimes:jpeg,png|max:2048',
]);
Rename files to avoid malicious filenames or collisions:
$filename = Str::uuid() . '.' . $file->getClientOriginalExtension();
Store sensitive files in non-public disks and serve via signed URLs:
URL::temporarySignedRoute('download', now()->addMinutes(10), ['file' => $id]);
6. CSRF, XSS, and SQL Injection
Laravel automatically protects against CSRF via tokens. Ensure you use @csrf in all Blade forms.
To prevent XSS attacks:
- Escape all dynamic output using
{{ $var }}
- Only use
{!! $var !!}
when the content is explicitly sanitised
Avoid SQL injection by never interpolating input into queries. Use bindings:
DB::select('SELECT * FROM users WHERE email = ?', [$email]);
7. Cookies and Session Security
In config/session.php, enforce strict security settings:
'secure' => env('SESSION_SECURE_COOKIE', true),
'http_only' => true,
'same_site' => 'lax',
Use Redis or database drivers in production instead of file-based sessions:
SESSION_DRIVER=redis
These settings help mitigate session hijacking and CSRF.
8. Production Security Checklist
Before going live, review the following:
- HTTPS enforced and all HTTP routes redirect correctly
- Security headers applied consistently
- CSRF protection enabled and used on all forms
- Input validated and sanitised at all entry points
- Uploads validated, renamed, and stored on private disks
- Session and cookie flags set (secure, httpOnly, same_site)
- All raw SQL queries parameterised
- Roles and permissions enforced via middleware or guards
Conclusion
Laravel 12 provides strong security defaults, but it’s your responsibility to make informed decisions when writing application logic. Secure apps come from conscious habits: validate data, reduce surface area, restrict access, and monitor sensitive areas.
When security is prioritised from the beginning, your application becomes easier to defend and scale. Build securely — by default.