
Table of Contents
By Khimananda Oli | Last reviewed: August 2026
Shipping a Laravel application without addressing the OWASP Top 10 exposes your users and business to preventable breaches, from injection attacks to broken access control. Secure Laravel: OWASP Top 10 in Practice means moving beyond theoretical checklists to implement framework-native defenses that actually hold up under audit and attack. This guide translates each vulnerability category into concrete Laravel configurations, middleware patterns, and infrastructure controls you can deploy today.
How do you prevent injection and broken access control in Laravel?
Injection flaws (A03:2021) and Broken Access Control (A01:2021) remain the most critical risks because they directly enable data exfiltration or privilege escalation. In Laravel, Eloquent’s query builder uses PDO prepared statements by default, which neutralizes SQL injection when used correctly. The danger arises when developers bypass this safety with raw expressions or string concatenation.
Eliminating SQL injection vectors
Never interpolate user input into raw queries. Even seemingly safe contexts like orderBy or column names can be exploited if not validated against an allowlist. Use Eloquent’s built-in methods whenever possible:
<?php
// SAFE: Parameterized binding via Eloquent
$users = User::where('email', $request->input('email'))
->where('status', 'active')
->get();
// UNSAFE: Raw expression with unvalidated input
// DB::select("SELECT * FROM users WHERE email = '" . $request->input('email') . "'");
// SAFE: Validated column allowlist for dynamic sorting
$allowedSorts = ['name', 'created_at', 'email'];
$sortColumn = in_array($request->input('sort'), $allowedSorts, true)
? $request->input('sort')
: 'created_at';
$users = User::orderBy($sortColumn, 'asc')->paginate(25); Enforcing authorization with policies and gates
Broken access control often stems from missing ownership checks rather than authentication failures. Laravel Policies bind authorization logic directly to models, making it impossible to forget a permission check in controllers. Register policies in AuthServiceProvider and always call $this->authorize() or the @can Blade directive:
<?php
// app/Policies/PostPolicy.php
public function update(User $user, Post $post): bool
{
return $user->id === $post->user_id || $user->hasRole('editor');
}
// In controller — fails with 403 if unauthorized
public function update(Request $request, Post $post)
{
$this->authorize('update', $post);
// ... validated update logic
} This pattern ensures every mutation passes through centralized authorization. For API resources using Sanctum, pair policies with token-scoped abilities to enforce least-privilege access at both the token and model level.
What are the essential cryptographic and session security configurations?
Cryptographic Failures (A02:2021) and Insecure Design (A04:2021) frequently manifest as weak password hashing, exposed secrets, or misconfigured sessions. Laravel ships with secure defaults, but production deployments require explicit verification and hardening.
Password hashing and secret management
Laravel 11+ uses Argon2id as the default hashing algorithm, which resists GPU-based cracking better than bcrypt. Verify your config/hashing.php specifies 'driver' => 'argon2id'. Never store API keys, database passwords, or third-party tokens in code or .env files committed to version control. Use environment variables injected at deploy time, or integrate with a dedicated secrets manager like HashiCorp Vault for rotation and audit trails as outlined in secrets management best practices.
Session and cookie hardening
Sessions are a prime target for hijacking. Configure these values explicitly in config/session.php and config/services.php:
- SameSite: Set to
'lax'or'strict'to prevent CSRF via cross-site requests - Secure: Always
truein production (requires HTTPS) - HttpOnly: Always
trueto block JavaScript access to session cookies - Lifetime: Reduce to 120 minutes or less for sensitive applications
- Encrypt: Enable
'encrypt' => trueto protect session payload confidentiality
For applications handling financial or health data, consider rotating session IDs after authentication and privilege changes to prevent fixation attacks. Laravel’s $request->session()->regenerate() handles this automatically during login when using the built-in auth scaffolding.
How do you configure HTTP security headers and frontend protections?
Security Misconfiguration (A05:2021) and Vulnerable Components (A06:2021) account for many breaches that originate outside application code. HTTP security headers instruct browsers to enforce isolation, prevent MIME sniffing, and restrict resource loading. Laravel does not set these by default, so you must add them via middleware.
Implementing a security headers middleware
Create app/Http/Middleware/SecurityHeaders.php and register it globally in bootstrap/app.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', 'SAMEORIGIN');
$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');
// CSP tailored to your app — start restrictive, relax as needed
$response->headers->set('Content-Security-Policy',
"default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; frame-ancestors 'self'"
);
return $response;
}
} Test your headers with Mozilla Observatory or Security Headers scanner after deployment. A common mistake is setting an overly permissive CSP that includes unsafe-eval or wildcard sources, which defeats XSS protection entirely.
Keeping dependencies patched
Run composer audit weekly and integrate it into your CI pipeline as shown in GitLab CI for Laravel. Subscribe to GitHub Security Advisories for Laravel and key packages. Pin major versions in composer.json and test upgrades in staging before production. Outdated packages with known CVEs are low-hanging fruit for attackers and auditors alike.
What logging and monitoring practices satisfy compliance requirements?
Logging Failures (A09:2021) and SSRF (A10:2021) round out the Top 10 because they enable undetected exploitation and internal network pivoting. Compliance frameworks like SOC 2 and ISO 27001 require demonstrable audit trails, not just log files sitting on disk.
Structured logging for security events
Configure Laravel to write structured JSON logs to stdout/stderr so container orchestrators and log aggregators can parse them reliably. In config/logging.php, use the stderr channel with the json formatter. Log authentication attempts, authorization failures, password resets, and sensitive data access with consistent fields (event, user_id, ip, outcome). Never log passwords, tokens, or PII.
Monitoring and alerting on anomalies
Ship logs to a centralized stack like ELK or Grafana Loki as detailed in centralized logging setup. Create alerts for: brute-force login attempts (>5 failures/min), unexpected admin actions, large data exports, and outbound requests to unknown hosts (SSRF indicators). Pair this with Prometheus metrics tracking error rates and latency spikes that may signal active exploitation.
| OWASP Category | Laravel Native Defense | Infrastructure Complement | Audit Evidence |
|---|---|---|---|
| A01: Broken Access Control | Policies, Gates, Middleware | WAF rule sets, IAM roles | Policy test coverage, access logs |
| A02: Cryptographic Failures | Argon2id, Encrypter | TLS 1.3, KMS/Vault | Hash config, cert expiry alerts |
| A03: Injection | Eloquent ORM, Validation | DB firewall, parameterized RDS | Query logs, SAST reports |
| A05: Security Misconfiguration | Headers middleware, env separation | Hardened AMIs, VPC segmentation | Config scans, CIS benchmarks |
| A09: Logging Failures | Structured JSON logging | Centralized SIEM, retention policies | Log integrity checks, alert tests |
Secure Laravel: OWASP Top 10 in Practice as Continuous Discipline
Security is not a feature you ship once; it is a continuous discipline embedded in your development workflow, infrastructure provisioning, and incident response. The controls outlined here — parameterized queries, policy-based authorization, hardened headers, structured logging, and dependency auditing — form the baseline for any Laravel application handling real user data. Revisit them quarterly, test them with automated tools and manual penetration testing, and treat every new feature as an opportunity to verify your defenses still hold. If your team needs help implementing these controls or preparing for a compliance audit, reach out to discuss your specific architecture.