Framework audits/Laravel

Laravel Security Audit

What should a Laravel security audit check?

Laravel's defaults are sound, so an audit concentrates on configuration and on the places where Eloquent's protections are widened. The findings that recur are debug mode enabled in production, an application key that was never rotated after being committed, models with mass assignment left open, and raw expressions in the query builder.

Laravel's error page is unusually informative, which makes debug mode in production more damaging here than in most frameworks — it renders environment values alongside the stack trace.

Where Laravel codebases actually break

These are patterns we look for in code produced this way — not flaws in Laravel itself. Each names the check that finds it.

Debug mode exposing environment values

Laravel's debug error page is detailed by design: it renders the stack trace together with environment configuration. Enabled in production, a single unhandled exception can display database credentials and application keys directly in the browser of whoever triggered it.

Detected by: Unvalidated request input

An application key that was committed and never rotated

The application key encrypts session data and signed cookies. When the environment file has been committed at any point in the project's history — common in older or inherited codebases — that key is in git permanently, and anyone with it can forge encrypted values the application will trust.

Detected by: Private key committed to repository

Mass assignment left open on models

Eloquent will fill any attribute permitted by a model's fillable or guarded configuration. A model that guards nothing lets a crafted request set columns the form never exposed — an administrator flag, an owner id, a balance — because the request is trusted to name its own fields.

Detected by: Unvalidated request input

Raw expressions in the query builder

The query builder parameterises normally, but its raw expression helpers insert the given string into the SQL directly. Where a request value is concatenated into one of those, the protection the builder normally provides is bypassed at exactly that point.

Detected by: Unparameterized database query

Auditing a Laravel codebase: the short list

  • Confirm debug is disabled in production, and check what the error page renders when it is not
  • Check whether the environment file appears anywhere in git history, and rotate the application key if it does
  • Review every Eloquent model for an explicit fillable or guarded list rather than an open default
  • Grep for raw query-builder expressions and confirm no request value is concatenated into one
  • Verify the public directory is the web root, so application code and the environment file are not directly reachable

Scan your Laravel codebase

Every check named above runs automatically. Free on public repositories, no signup, results in under three minutes — with the file and line for each finding.

Frequently asked questions

Is Laravel secure by default?

Its defaults are good: CSRF protection, parameterised queries and escaped Blade output are all standard. The problems come from configuration in production and from widening Eloquent's protections — an open mass-assignment policy is a deliberate choice that is easy to make and hard to notice later.

What is mass assignment and why does it matter?

It is Eloquent filling model attributes directly from request input. It matters because the request decides which fields to send: if a model does not restrict what may be filled, a crafted request can set columns the interface never exposed, such as a role or ownership field.

Do I need to rotate the Laravel app key?

If the environment file has ever been committed, yes. The key encrypts sessions and signed cookies, so anyone who can read it from history can forge values the application will accept as its own. Removing the file from the current tree does not remove it from history.

Related reading