---
title: "Protecting the /livewire/update endpoint from bots with a Laravel middleware"
date: 2026-02-21
updated: 2026-02-26
lang: en
translationKey: proteggere-livewire-update-con-un-middleware-laravel
tags: [Laravel, Livewire, Security]
description: "How to block bots attacking the /livewire/update endpoint using a Laravel middleware that validates Content-Type, X-Livewire, Referer, and the session cookie."
---

<div class="callout callout-success">
<strong>Update — February 26, 2026:</strong> Livewire <strong>4.2.0</strong> ships a built-in <code>RequireLivewireHeaders</code> middleware that validates the presence of the <code>X-Livewire</code> and <code>Content-Type: application/json</code> headers on every update request (<a href="https://github.com/livewire/livewire/pull/9965">PR #9965</a>). <strong>If you are on Livewire 4.2.0 or later, you no longer need a custom middleware.</strong> The approach described in this article remains valid for Livewire 3.x installations and as an explanation of the same defence mechanism now adopted by the Livewire team itself.
</div>

Imagine opening [BugSnag](https://www.bugsnag.com/) 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](https://www.encodia.it/).

## The problem: a flood of type errors on BugSnag

At [Encodia](https://www.encodia.it/) we have built more than one web application
using [Livewire](https://livewire.laravel.com/).
A few weeks ago, we started receiving reports from [BugSnag](https://www.bugsnag.com/) 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](https://www.synacktiv.com/en/publications/livewire-remote-command-execution-through-unmarshaling),
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 showLineNumbers
<?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-Livewire` header is present
* the `Referer` header 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:

```nginx showLineNumbers
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.

The fact that the Livewire team adopted exactly this approach in version 4.2.0 —
a dedicated middleware validating the same headers — confirms the direction was right.
If you are already on Livewire 4.2.0+, the protection is included with no extra code needed.
If upgrading is not immediately possible, the middleware described in this article remains an effective solution.
