How to Prevent SQL Injection in Laravel

SQL injection vulnerabilities in raw queries and improper Eloquent usage can expose your database. Learn how to write secure queries.

Critical severity Application Security Updated 2026-03-01 Markdown

SQL injection has been the most consistently exploited web vulnerability for over 25 years, appearing at the top of the OWASP Top 10 since the list was first published. The vulnerability exists when user-controlled input is concatenated directly into a SQL query rather than passed as a parameterized binding. The database interpreter cannot distinguish between the SQL the developer wrote and the SQL the attacker injected — both execute. This is a fundamental design flaw that is completely preventable with parameterized queries.

Real-world SQL injection exploits range from reading individual records to complete database dumps. Automated tools like sqlmap can detect and exploit SQL injection with a single command, requiring no deep SQL knowledge from the attacker. A successful injection typically starts with confirming the vulnerability using ' OR '1'='1, then escalates to dumping table structures, extracting user records including password hashes and personal data, and in databases where FILE privileges are granted, reading arbitrary files from the server's filesystem.

The irony for Laravel developers is that the framework's Eloquent ORM handles parameterization automatically for the vast majority of queries. SQL injection in Laravel almost always appears in the escape hatches: DB::raw(), whereRaw(), selectRaw(), orderByRaw(), and DB::statement(). Developers reach for these methods when Eloquent's query builder doesn't support what they need, and the additional power comes with the responsibility to bind parameters carefully. Column and table names cannot be parameterized at all and must be validated against a whitelist.

The Problem

SQL injection allows attackers to execute arbitrary SQL commands on your database by injecting malicious input through your application. While Laravel's Eloquent ORM uses parameterized queries by default, SQL injection vulnerabilities are introduced when developers use raw queries, DB::raw(), whereRaw(), or string concatenation with user input. A successful SQL injection can read, modify, or delete all data in your database.

How to Fix

  1. 1

    Use parameterized queries instead of string concatenation

    Never concatenate user input into SQL queries. Replace:

    // VULNERABLE - never do this
    $users = DB::select("SELECT * FROM users WHERE email = '" . $request->email . "'");

    With parameterized binding:

    // SAFE - use parameter binding
    $users = DB::select('SELECT * FROM users WHERE email = ?', [$request->email]);
    // SAFE - use named bindings
    $users = DB::select('SELECT * FROM users WHERE email = :email', ['email' => $request->email]);
  2. 2

    Secure raw query methods

    When using whereRaw(), orderByRaw(), or DB::raw(), always use bindings:
    // VULNERABLE
    User::whereRaw("email = '" . $request->email . "'")->first();
    // SAFE
    User::whereRaw('email = ?', [$request->email])->first();
    // VULNERABLE - column names cannot be parameterized
    User::orderByRaw($request->sort_column . ' ' . $request->sort_direction)->get();
    // SAFE - whitelist allowed values
    $column = in_array($request->sort_column, ['name', 'email', 'created_at']) ? $request->sort_column : 'created_at';
    $direction = $request->sort_direction === 'desc' ? 'desc' : 'asc';
    User::orderByRaw("$column $direction")->get();
  3. 3

    Validate and sanitize all input

    Use Laravel validation to restrict input before it reaches queries:

    $validated = $request->validate([
        'email' => 'required|email|max:255',
        'id' => 'required|integer',
        'status' => 'required|in:active,inactive,pending',
        'search' => 'nullable|string|max:100',
    ]);
    // Use validated data in queries
    $user = User::where('email', $validated['email'])->first();

    Validation prevents unexpected input types and lengths from reaching your database layer.

  4. 4

    Use Eloquent ORM whenever possible

    Eloquent automatically parameterizes all queries:

    // All of these are safe from SQL injection
    User::find($id);
    User::where('email', $email)->first();
    User::where('status', $status)->where('role', $role)->get();
    User::whereBetween('created_at', [$start, $end])->get();
    Avoid raw queries unless Eloquent genuinely cannot express what you need. For complex queries, use the query builder with bindings rather than raw SQL strings.

How to Verify

Test your forms by submitting SQL injection payloads in input fields:

' OR '1'='1
'; DROP TABLE users; --
1 UNION SELECT * FROM users

Your application should handle these as normal (invalid) input without errors or unexpected behavior. If you see database errors or unexpected data returned, you have a SQL injection vulnerability.

Prevention

Establish a coding standard that prohibits string concatenation in queries. Use static analysis tools like PHPStan or Psalm to detect unsafe query patterns. Code review all uses of DB::raw(), whereRaw(), selectRaw(), and havingRaw(). Run regular security audits of your codebase.

Frequently Asked Questions

Is Eloquent completely safe from SQL injection?

Standard Eloquent methods (where, find, create, update) are safe because they use parameterized queries. However, methods that accept raw SQL (whereRaw, orderByRaw, DB::raw, selectRaw) can be vulnerable if you pass unsanitized user input. Column names and table names cannot be parameterized and must be whitelisted.

Can SQL injection happen through URL parameters?

Yes. Any user-controlled input that reaches a database query is a potential injection point, including URL parameters, query strings, form fields, headers, cookies, and even uploaded file names. Always validate and parameterize regardless of the input source.

How do I audit my existing code for SQL injection?

Search your codebase for DB::raw, whereRaw, selectRaw, orderByRaw, havingRaw, DB::select, DB::statement, and DB::unprepared. Check each usage for user input being concatenated rather than bound. Tools like PHPStan with the Larastan extension can help identify some patterns automatically.

Does MySQL strict mode help prevent SQL injection?

No. Strict mode affects data integrity (rejecting invalid dates, out-of-range values) but does not prevent injection. Parameterized queries are the only effective defense against SQL injection. MySQL strict mode is still recommended for data quality reasons, but it should not be relied on for security.

Are LIKE queries with user input vulnerable to SQL injection?

Standard SQL injection is prevented with parameterized LIKE queries: User::where("name", "like", "%{$search}%") — Eloquent parameterizes the entire value including the % wildcards. However, LIKE queries introduce a separate performance concern: a leading wildcard forces a full table scan. Additionally, special LIKE characters (%, _) in user input can produce unexpected results; use DB::getPdo()->quote() or addcslashes($input, "%_") to escape them.

Related Security Terms

Free security check

Is your Laravel app exposed right now?

34% of Laravel apps we scan have at least one critical issue. Most teams don't find out until something breaks. Our free scan checks your live application in under 60 seconds.

18% have debug mode on
72% missing security headers
12% have exposed .env
Scan My App Free No signup required. Results in 60 seconds.