CVE-2026-23524: Laravel Reverb RCE via Insecure Deserialization (CVSS 9.8)
Laravel Reverb versions 1.6.3 and below have a critical insecure deserialization vulnerability. When horizontal scaling is enabled, Reverb passes Redis channel data directly into unserialize() without class restrictions. If your Redis is unauthenticated, attackers can achieve full remote code execution. Here is how to check and fix it.
A critical vulnerability has been disclosed in Laravel Reverb, the official WebSocket server for Laravel applications. Tracked as CVE-2026-23524 with a CVSS score of 9.8, this flaw allows an unauthenticated attacker to execute arbitrary code on your server by sending a specially crafted payload through Redis when horizontal scaling is enabled. If you are running Reverb 1.6.3 or below with REVERB_SCALING_ENABLED=true, you should treat this as urgent. The fix is a single version bump, but understanding what went wrong is worth your time.
What Is Laravel Reverb?
Laravel Reverb is the first-party WebSocket server for Laravel, introduced to give Laravel developers a native, self-hosted alternative to third-party services like Pusher. It integrates tightly with Laravel Echo and Laravel's broadcasting system, making it easy to add real-time features like notifications, live dashboards, and presence channels to any Laravel application.
Because it is an official Laravel package, it sees wide adoption. Estimates put roughly 7 million applications in the potentially affected range, which is part of what makes this CVE particularly significant.
When horizontal scaling is required (for example, running Reverb across multiple nodes behind a load balancer), Reverb uses Redis as a pub/sub backend to synchronise state between nodes. That Redis integration is exactly where the vulnerability lives.
How the Vulnerability Works
When REVERB_SCALING_ENABLED=true, Reverb subscribes to Redis channels to share WebSocket state across nodes. As messages arrive from Redis, Reverb needs to reconstruct PHP objects from the channel data. In versions 1.6.3 and below, it did this with a direct call to PHP's native unserialize() function, passing in raw Redis payload data without any class restriction.
The relevant behaviour, simplified, looks like this:
// Reverb <= 1.6.3 (simplified illustration of the vulnerable pattern)
$data = $redis->get($channel);
$object = unserialize($data); // No allowed_classes restriction
unserialize() without an allowed_classes option will happily instantiate any class that exists in the PHP runtime, including classes from Laravel itself, Symfony components, Guzzle, or any other package in your vendor/ directory. Attackers exploit this by crafting serialized payloads that chain together existing classes in unexpected ways, a technique known as PHP Object Injection or a "property-oriented programming" (POP) chain.
The attack chain looks like this:
- The attacker gains write access to your Redis instance. Because Redis is commonly deployed on internal networks without authentication (and sometimes exposed publicly), this step is often the easiest part.
- The attacker writes a malicious serialized PHP payload to the Redis channel that Reverb is subscribed to.
- Reverb deserializes the payload. During deserialization, PHP executes magic methods like
__wakeup()or__destruct()on the instantiated objects. - By chaining the right classes together, the attacker triggers code execution, typically landing a shell or exfiltrating environment variables.
This is a textbook remote code execution path. No authentication is required against Reverb itself. If Redis is reachable and unauthenticated (which is a very common misconfiguration), exploitation is straightforward.
Am I Affected?
You are potentially affected if all three of the following are true:
- You are running
laravel/reverbversion 1.6.3 or below - Horizontal scaling is enabled in your environment
- Your Redis instance is accessible from an untrusted network, or is unauthenticated
Check your Reverb version:
composer show laravel/reverb
Look for the versions line in the output. If it shows 1.6.3 or lower, you are running a vulnerable version.
Check whether scaling is enabled:
grep REVERB_SCALING_ENABLED .env
If this returns REVERB_SCALING_ENABLED=true, the vulnerable code path is active.
Check whether Redis requires authentication:
redis-cli ping
If you get PONG without supplying a password, your Redis instance is unauthenticated. Combine that with a network-accessible Redis and you have a critical exposure.
How to Fix It
Step 1: Upgrade Reverb to 1.7.0
composer update laravel/reverb
Then verify the installed version:
composer show laravel/reverb | grep versions
Confirm you are on 1.7.0 or above before redeploying.
Step 2: Secure your Redis instance
Even after upgrading, running an unauthenticated Redis accessible beyond localhost is a bad posture. Add a strong password to your Redis configuration:
# /etc/redis/redis.conf
requirepass your-strong-password-here
Then update your Laravel environment to match:
# .env
REDIS_PASSWORD=your-strong-password-here
Step 3: Restrict Redis network exposure
Redis should only be reachable by the services that need it. Bind it to a private interface, not 0.0.0.0:
# /etc/redis/redis.conf
bind 127.0.0.1 10.0.0.5
Use firewall rules to block external access to port 6379.
Step 4: Rotate secrets
If you have any reason to believe your Redis instance was accessible and unprotected before you applied these fixes, treat your application secrets as compromised. Rotate your APP_KEY, database credentials, API keys, and any other secrets stored in your environment.
Why Insecure Deserialization Is So Dangerous
Insecure deserialization consistently earns a place in the OWASP Top 10 for a reason. PHP's unserialize() is a powerful function that reconstructs complex object graphs from a string. When you give it a string from a trusted source, like a signed cookie you control, that is fine. When you give it arbitrary input from an external system like Redis, you are handing an attacker a loaded weapon.
The danger is not that unserialize() runs arbitrary code directly. It is that PHP automatically calls magic methods (__construct, __wakeup, __destruct, __toString, and others) during the deserialization process. By carefully constructing a serialized string that chains together existing classes from your vendor directory, an attacker can build a sequence of method calls that ultimately executes a system command or writes a file.
These chains, called POP chains, do not require any application-specific code. They exploit legitimate classes doing legitimate things in the wrong order and context. Tools like PHPGGC exist specifically to generate these chains for common PHP frameworks and libraries.
The defence is simple in principle: never call unserialize() on data you do not fully control. PHP 7.0 added an allowed_classes option to restrict which classes can be instantiated during deserialization. Passing ['YourExpectedClass'] or false dramatically reduces the attack surface.
What Changed in Reverb 1.7.0
The fix in Reverb 1.7.0 addresses the root cause directly. Rather than using PHP's native unserialize() with unrestricted class instantiation, Reverb now passes an explicit allowed_classes option:
// Reverb 1.7.0 (simplified illustration of the fix)
$data = $redis->get($channel);
$object = unserialize($data, ['allowed_classes' => [ReverbChannelPayload::class]]);
With allowed_classes set to a specific list, PHP will throw an error rather than instantiate any class outside that list. This breaks every known POP chain because the attacker can no longer introduce arbitrary classes into the object graph during deserialization.
The fix is tracked under GitHub Advisory GHSA-m27r-m6rx-mhm4 and is a minimal, targeted change. There is no reason to delay the upgrade.
Protect Your Laravel Application
CVE-2026-23524 is a good example of how a well-intentioned architectural decision (horizontal scaling via Redis) introduces a critical attack surface when one implementation detail is overlooked. The vulnerable code was not careless. It was just missing one option on one function call. That is how most real-world vulnerabilities work.
Run a free StackShield scan on your application to check for exposed Redis instances, insecure configurations, and the kinds of infrastructure weaknesses that make exploits like this one trivial to chain together.
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.
Frequently Asked Questions
What is CVE-2026-23524?
CVE-2026-23524 is a critical remote code execution vulnerability in Laravel Reverb versions 1.6.3 and below. It has a CVSS score of 9.8. When horizontal scaling is enabled via Redis, Reverb passes channel data into PHP's unserialize() function without restricting which classes can be instantiated, allowing attackers to inject malicious objects and execute arbitrary code.
Am I affected by the Reverb vulnerability?
You are affected if you are running laravel/reverb version 1.6.3 or below AND have REVERB_SCALING_ENABLED=true in your .env file. Run "composer show laravel/reverb" to check your version. If horizontal scaling is not enabled, the vulnerable code path is not active.
How do I fix CVE-2026-23524?
Upgrade Laravel Reverb to version 1.7.0 or later by running "composer update laravel/reverb". Additionally, secure your Redis instance with authentication (requirepass in redis.conf) and restrict it to private network interfaces only. If Redis was previously unauthenticated, rotate all application secrets.
What is insecure deserialization in PHP?
Insecure deserialization occurs when PHP's unserialize() function processes untrusted data without restricting which classes can be instantiated. Attackers craft serialized payloads that chain together existing classes (called POP chains) to trigger arbitrary code execution through magic methods like __wakeup() and __destruct(). The fix is to always pass an allowed_classes option to unserialize().
Related Security Terms
Related Articles
Laravel Session Security: Cookies, Hijacking & config/session.php
A deep dive into Laravel session security. Learn how cookie flags, session drivers, and config/session.php settings protect against hijacking, fixation, and sidejacking attacks.
SecurityAutomated Security Testing in Laravel CI/CD Pipelines
How to add security gates to your Laravel CI/CD pipeline with GitHub Actions. Covers dependency scanning, static analysis, secret detection, and automated security monitoring.
SecurityLaravel Content Security Policy: Configure CSP Without Breaking Your App
Only 22% of Laravel apps have a Content Security Policy. Learn how to implement CSP with spatie/laravel-csp, handle Livewire and Vite nonces, and avoid the mistakes that break production.
Compare StackShield
Security Checklists
Laravel Production Deployment Security Checklist
A comprehensive security checklist for deploying Laravel applications to production. Covers environment config, server hardening, access control, and monitoring.
20 itemsLaravel API Security Checklist
Secure your Laravel API endpoints against common vulnerabilities. Covers authentication, input validation, rate limiting, and response security.
Stay Updated on Laravel Security
Get actionable security tips, vulnerability alerts, and best practices for Laravel apps.