Laravel Unsafe Deserialization: How to Eliminate unserialize() and Prevent Object Injection

PHP unserialize() with user-controlled data enables remote code execution through object injection. Replace with json_decode() or add allowed_classes restrictions.

Critical severity Application Security Updated 2026-05-01

The Problem

PHP's unserialize() function reconstructs objects from serialized strings. If an attacker can control the serialized data, they can instantiate arbitrary classes and trigger their __wakeup() or __destruct() methods — leading to remote code execution, file deletion, or database manipulation. This is called PHP Object Injection and is rated critical because it often leads to full server compromise. Laravel internally uses serialization for queued jobs and cache, but these are protected by encryption. The danger is when your code calls unserialize() on user-supplied input.

How to Fix

  1. 1

    Find all unserialize() calls

    Search your codebase:

    grep -rn 'unserialize(' app/ routes/ --include='*.php'

    Also search for related functions:

    grep -rn 'unserialize\|deserialize\|object_decode' app/ --include='*.php'

    For each occurrence, trace whether the input could originate from a user request, database field populated by users, cache, or external API.

  2. 2

    Replace with json_decode() where possible

    Most serialized data can use JSON instead:
    // BEFORE — unsafe
    $data = unserialize($request->input('data'));
    // AFTER — safe
    $data = json_decode($request->input('data'), true);

    JSON cannot instantiate PHP objects, eliminating the object injection vector entirely. Update both the serialization and deserialization sides:

    // Saving
    $encoded = json_encode($data);
    // Loading
    $decoded = json_decode($encoded, true);
  3. 3

    If unserialize() is unavoidable, restrict allowed classes

    PHP 7+ supports an allowed_classes option:

    // Only allow specific classes
    $data = unserialize($serialized, [
        'allowed_classes' => [MyDTO::class, Collection::class],
    ]);
    // Or allow no classes at all (safest)
    $data = unserialize($serialized, [
        'allowed_classes' => false,
    ]);

    With allowed_classes set to false, any serialized objects are converted to __PHP_Incomplete_Class, preventing method execution.

How to Verify

Run the scanner:

php artisan stackshield:scan --check=SS043

Manually test: if your application accepts serialized data via any input, try sending a crafted payload and verify the application rejects it or handles it safely.

Prevention

Default to JSON for all data serialization. Never call unserialize() on user input. If you must deserialize, always use the allowed_classes option. Laravel's queue system and cache use signed/encrypted serialization — these are safe. Focus on custom code.

Frequently Asked Questions

Is Laravel's queue serialization vulnerable?

No. Laravel encrypts and signs serialized queue payloads using your APP_KEY. Attackers cannot modify the serialized data without the key. However, if your APP_KEY is compromised, queue payloads become a potential attack vector.

What about serialize() — is that dangerous too?

serialize() itself is not dangerous — it just converts data to a string. The danger is on the deserialization side with unserialize(). However, if you serialize data that will later be deserialized from an untrusted source, the full chain is vulnerable.

Detect This Automatically with StackShield

StackShield continuously monitors your Laravel application from the outside and alerts you when security issues are found. No installation required.

Start Free Trial