Protecting the /livewire/update endpoint from bots with a Laravel middleware
Imagine opening BugSnag on a Monday morning and finding hundreds of errors
hitting the /livewire/update endpoint. Errors like:
Cannot assign array to property App\\Livewire\\ExampleComponent::$exampleName of type bool
Different properties involved, but always the same pattern: someone is sending an array where PHP expects a primitive type. That’s exactly what happened to us at Encodia.
The problem: a flood of type errors on BugSnag
At Encodia we have built more than one web application using Livewire. A few weeks ago, we started receiving reports from BugSnag about errors like this:
POST /livewire/update
Cannot assign array to property App\\Livewire\\ExampleComponent::$exampleName of type bool
Dozens or hundreds of reports, all involving public Livewire properties. The property name and the expected
type varied, but the error was always similar: the payload sent an array to hydrate a specific property,
but since that property was of a different type (bool, string, etc.), PHP threw an error.
How we identified the cause
While inspecting the calls on BugSnag, this header immediately caught my eye:
"user-agent": "python-requests/2.32.4"
A quick search revealed that these are attempts to exploit the vulnerability CVE-2025-54068, present in Livewire 3.x installations up to version v3.6.3. The vulnerability allows an attacker to execute arbitrary code on the server (Remote Code Execution) by manipulating the component hydration payload — hence the type errors we were seeing on BugSnag.
We had already updated the affected applications; however, the type errors kept coming
even on applications running Livewire 4.x.
The reason is that automated scanners don’t check the installed Livewire version before attempting an attack:
they simply hammer every /livewire/update endpoint they find, regardless of the version.
The solution: a Laravel middleware
I added this middleware:
<?php
declare(strict_types=1);
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
/**
* Protects the livewire-xxxxxxxx/update endpoint from requests not sent by Livewire (e.g. BOTs)
*/
final readonly class ProtectLivewireEndpointMiddleware
{
public function handle(Request $request, Closure $next): mixed
{
if (! $request->routeIs('default-livewire.update')) {
return $next($request);
}
if ($request->header('Content-Type') !== 'application/json') {
$this->abort('Missing application/json header');
}
if (! $request->hasHeader('X-Livewire')) {
$this->abort('Missing X-Livewire header');
}
if (! $request->headers->get('referer')) {
$this->abort('Missing Referer');
}
if (! $request->cookies->has(config()->string('session.cookie'))) {
$this->abort('Invalid Laravel session');
}
return $next($request);
}
private function abort(string $reason): never
{
$showDetails = app()->isLocal();
abort(code: 403, message: $showDetails ? $reason : '');
}
}
If the current request does not involve Livewire, it passes through. Otherwise, it checks that:
- the
X-Livewireheader is present - the
Refererheader is present - the session cookie is present
If at least one of these conditions is not met, it returns a 403 (Forbidden) error with no explanatory message.
Only in the local environment — to make debugging easier — it returns the reason why the 403 was issued.
The middleware must be registered so that it runs before \Illuminate\Session\Middleware\StartSession.
This way, BOT requests are blocked before Laravel even initializes the session:
no unnecessary overhead, no database access for requests that will be rejected anyway.
Alternative: blocking bots at the web server level
If you prefer not to use a middleware, you can also configure your web server to block suspicious requests directly at the Nginx level, before PHP is involved at all.
For example, to block all requests to /livewire/update that lack the X-Livewire header:
location /livewire/update {
if ($http_x_livewire = "") {
return 403;
}
# rest of the configuration...
}
The advantage is that Nginx rejects the request without PHP ever being started. The drawback is that the validation logic lives outside the application and must be kept in sync with any future changes to the endpoint.
Conclusion
The middleware does not replace upgrading Livewire, but acts as an upstream filter: requests lacking the expected headers are blocked before PHP even begins to process the payload.
If you use BugSnag or a similar tool, it’s worth checking whether you’re receiving similar errors:
python-requests in the user-agent is an unmistakable signal.