Home / Blog / OWASP Top 10 in Laravel: How to Actually Defend Against Each Vulnerability
Web Development

OWASP Top 10 in Laravel: How to Actually Defend Against Each Vulnerability

AJAjish Stephen August 8, 2026 9 min read
OWASP Top 10 in Laravel: How to Actually Defend Against Each Vulnerability

The OWASP Top 10 is the industry-standard list of the most critical web application security risks. Laravel protects against several of these by default — but "by default" only holds if you use the framework's tools correctly. Here's how each risk actually shows up in a Laravel codebase, and the specific code that defends against it.

1. SQL Injection

Eloquent and the query builder parameterize queries automatically. The vulnerability appears when raw SQL is built with string concatenation instead:

// ✗ Vulnerable — raw string concatenation
$users= DB::select("SELECT * FROM users WHERE email = '".$email."'");

// ✓ Safe — parameterized binding
$users= DB::select('SELECT * FROM users WHERE email = ?', [$email]);

// ✓ Better — use Eloquent/query builder, which does this for you
$users= User::where('email',$email)->get();

2. Cross-Site Scripting (XSS)

Blade's double-curly-brace output syntax escapes output automatically. The danger is the unescaped raw-output syntax:

{{-- ✗ Vulnerable — raw output, no escaping --}}
@{!!$comment->body@!!}

{{-- ✓ Safe — auto-escaped --}}
@{{$comment->body@}}

Only use the raw-output tag for content you've explicitly sanitized (e.g. with an HTML purifier package) or content your own system generated — never for raw user input.

3. Cross-Site Request Forgery (CSRF)

Laravel's VerifyCsrfToken middleware checks every state-changing request automatically — as long as your forms actually include the token:

<formmethod="POST"action="/comments">
  @@csrf
  <!-- form fields -->
</form>

For AJAX/fetch requests, pull the token from the meta tag and send it as an X-CSRF-TOKEN header — the same pattern used throughout this site's own contact and appointment forms.

4. Mass Assignment

Without a whitelist, a malicious request could inject fields you never intended to be user-editable:

// ✗ Dangerous if $fillable includes 'is_admin' or it's not set at all
$user->update($request->all());

// ✓ Explicitly whitelist what's actually editable
protected$fillable= ['name','email'];

$user->update($request->only(['name','email']));

5. Broken Authentication

Always hash passwords with Hash::make() — never store or compare plaintext passwords
Rate-limit login attempts with the built-in throttle middleware to slow down brute-force attacks
Set short, sensible session lifetimes and re-authenticate for sensitive actions like changing a password or email

6. Security Misconfiguration

The single most common production mistake I still see:

# .env — production
APP_DEBUG=false
APP_ENV=production

Leaving APP_DEBUG=true in production exposes full stack traces — including file paths, environment variables, and query details — to anyone who triggers an error. This alone has leaked database credentials on real production sites.

7. Vulnerable and Outdated Components

Check your dependencies for known vulnerabilities as part of your regular workflow:

composeraudit

Run this in CI (the same GitHub Actions pipeline from an earlier post is a natural place to add it) so outdated dependencies with known CVEs get caught before they reach production, not discovered after an incident.

Want a real security review of your Laravel application, not just a checklist? I offer this as part of DevOps services engagements, covering both application-layer and infrastructure-layer hardening.

Common questions

Does Laravel protect against SQL injection automatically?
Eloquent and the query builder use parameterized queries automatically. The risk reappears the moment you write raw SQL with string concatenation instead of bindings.
Is Blade's double-curly-brace syntax enough to prevent XSS?
Yes, for output — Blade's double-curly-brace syntax escapes HTML entities automatically. The danger is the unescaped raw-output syntax, which outputs raw HTML with no protection.
Do I need to manually add CSRF tokens to every form?
For standard HTML forms, Laravel's CSRF directive inside the form tag is enough. For AJAX requests, send the token manually via a header, typically pulled from the meta tag Laravel generates.
What's the actual risk of mass assignment vulnerabilities?
A malicious user could pass extra fields — like is_admin=1 — and have them saved directly if your controller blindly passes all request input into create() or update(). Whitelisting fillable fields prevents this.
Not sure your application is actually secure?
I review real Laravel applications for exactly these kinds of gaps.
Explore DevOps Services →
© Copyright 2024 Ajish Stephen