Debug mode
Laravel's debug error page, Ignition. Displays the stack trace, the code around the error, and environment variables including database credentials and API keys. To anyone who triggers an error.
This is the single most damaging misconfiguration in a Laravel app and it's common, because it's true by default in a fresh install and easy to leave that way.
Mass assignment
Without $fillable or $guarded, that assigns every submitted field, including ones your form never showed. Sending is_admin=1 gets assigned.
Prefer $fillable over $guarded, an allowlist beats a blocklist, and a new column added later is safe by default rather than exposed by default.
Better still, validate first and assign the validated set:
Route model binding needs scoping
The auth middleware confirms someone is logged in. Binding then resolves whatever ID was in the URL.
Policies are the durable version of this. Generate one per model, register it, and call authorize in the controller. That way the check lives with the model rather than being remembered per route.
Laravel also supports scoped bindings, resolving the child through the parent relationship, which prevents the mismatch by construction.
Queries
Eloquent and the query builder parameterise. DB::raw and whereRaw don't:
Blade
{{ $value }} escapes. {!! $value !!} doesn't. Any unescaped directive applied to user content is potential XSS.
The rest
CSRF middleware is on by default, check what's been added to the $except array in VerifyCsrfToken, since exemptions accumulate.
Storage: uploads go to a disk outside the public directory, served through a controller that checks authorisation, not by symlinking everything into public.
php artisan config:cache in production, and confirm .env isn't web-accessible.
Tooling
Larastan and Enlightn both cover Laravel-specific issues, and composer audit covers known CVEs in packages. As elsewhere, none of them reliably catch a missing ownership check, because the vulnerable code is indistinguishable from correct code without knowing the intent.