Proteggere l'endpoint /livewire/update dai bot con un middleware Laravel
Immagina di aprire BugSnag un lunedì mattina e trovare centinaia di errori
in arrivo sull’endpoint /livewire/update. Errori come:
Cannot assign array to property App\Livewire\ExampleComponent::$exampleName of type bool
Diverse proprietà coinvolte, ma sempre lo stesso schema: qualcuno sta inviando un array dove PHP si aspetta un tipo primitivo. È quello che è capitato a noi in Encodia.
Il problema: errori di tipo a raffica su BugSnag
In Encodia abbiamo realizzato più di un’applicazione web utilizzando Livewire. Qualche settimana fa, abbiamo iniziato a ricevere segnalazioni da BugSnag relative a errori di questo tipo:
POST /livewire/update
Cannot assign array to property App\Livewire\ExampleComponent::$exampleName of type bool
Decine o centinaia di segnalazioni, relative a proprietà pubbliche Livewire, in cui cambia il nome delle proprietà e il
tipo
atteso, ma l’errore è sempre simile: nel payload, viene inviato un array per idratare una specifica proprietà, ma dato
che quella proprietà è di tipo differente (bool, string, ecc.), PHP restituisce un errore.
Come abbiamo identificato la causa
Ispezionando le chiamate su BugSnag, questo header ha attirato subito la mia attenzione:
"user-agent": "python-requests/2.32.4"
Cercando in rete, salta fuori che si tratta di tentativi di sfruttare la vulnerabilità CVE-2025-54068, presente su installazioni Livewire 3.x fino alla versione v3.6.3. La vulnerabilità consente a un attaccante di eseguire codice arbitrario sul server (Remote Code Execution) manipolando il payload di idratazione dei componenti — da qui gli errori di tipo che vedevamo su BugSnag.
Avevamo già aggiornato le applicazioni oggetto delle segnalazioni; tuttavia, gli errori relativi al tipo sono continuati
ad arrivare, anche su applicazioni che usano Livewire 4.x.
Il motivo è che gli scanner automatici non verificano la versione di Livewire installata prima di tentare l’attacco:
semplicemente martellano tutti gli endpoint /livewire/update che trovano, indipendentemente dalla versione.
La soluzione: un middleware Laravel
Ho aggiunto questo middleware:
<?php
declare(strict_types=1);
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
/**
* Protegge l'endpoint livewire-xxxxxxxx/update da richieste non inviate da Livewire (es. BOT)
*/
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('Header application/json mancante');
}
if (! $request->hasHeader('X-Livewire')) {
$this->abort('Header X-Livewire mancante');
}
if (! $request->headers->get('referer')) {
$this->abort('Referer mancante');
}
if (! $request->cookies->has(config()->string('session.cookie'))) {
$this->abort('Sessione Laravel non valida');
}
return $next($request);
}
private function abort(string $reason): never
{
$showDetails = app()->isLocal();
abort(code: 403, message: $showDetails ? $reason : '');
}
}
Se la richiesta corrente non coinvolge Livewire, procede oltre. Viceversa, controlla che
- sia presente l’header
X-Livewire - sia presente il
referer - sia presente il cookie di sessione
Se almeno una di queste condizioni non è soddisfatta, ritorna un errore 403 (Forbidden) senza alcun messaggio di
spiegazione.
Solo in ambiente locale - per rendere più facile un eventuale debug - ritorna il motivo per cui è stato erogato 403.
Il middleware va registrato in modo che venga eseguito prima di \Illuminate\Session\Middleware\StartSession.
In questo modo, le richieste BOT vengono bloccate prima ancora che Laravel inizializzi la sessione:
nessun overhead inutile, nessun accesso al database per richieste che verranno comunque rifiutate.
Alternativa: bloccare i BOT a livello di web server
Se non si vuole utilizzare un middleware, è anche possibile configurare il web server per bloccare le richieste sospette direttamente a livello Nginx, prima che PHP venga coinvolto.
Ad esempio, per bloccare tutte le richieste a /livewire/update prive dell’header X-Livewire:
location /livewire/update {
if ($http_x_livewire = "") {
return 403;
}
# resto della configurazione...
}
Il vantaggio è che Nginx respinge la richiesta senza che PHP venga mai avviato. Lo svantaggio è che la logica di validazione è separata dall’applicazione e va mantenuta in sincronia con eventuali cambiamenti futuri all’endpoint.
Conclusione
Il middleware non sostituisce l’aggiornamento di Livewire, ma agisce come un filtro a monte: richieste prive degli header attesi vengono bloccate prima ancora che PHP cominci a processare il payload.
Se usi BugSnag o un sistema analogo, vale la pena controllare se stai ricevendo errori simili:
python-requests nell’user-agent è un segnale inequivocabile.