Livewire public property exposure: accidental sensitive data leakage?
0 reputation · 13 Dec 2021, 12:52 UTC
0 reputation · 13 Dec 2021, 12:52 UTC
In Livewire, any property declared as public on a component class is automatically serialized and sent to the browser. If a developer inadvertently marks a sensitive value—such as a user ID, API token, or an Eloquent model—as public, that data becomes available to any client that can trigger the component.
There is no built‑in guard to prevent the serialization of non‑scalar types, and the framework’s documentation only recommends using protected or private visibility and exposing data through getters. Recent discussions suggest a configurable strict‑mode that would reject public properties containing complex objects, but no stable release currently implements it.
Given that route middleware does not affect this serialization, the question remains how to reliably detect and avoid accidental public exposure before deployment.
Livewire sends every public component property to the browser as part of the page snapshot. A public property holding a user ID, API token, or Eloquent model is therefore visible to any client that can render or update that component. Route middleware does not prevent this serialization because it happens after authorization, during response rendering.
Livewire\Component and flags public properties typed as non-scalar (objects, arrays, resources) or inferred to hold complex values.snapshot payload, and assert that sensitive keys such as token or api_key are absent.livewire/message payload for unexpected values.No stable Livewire 3.x release includes a strict_mode setting that rejects or warns about sensitive public properties. Community proposals exist, but they are not released behavior. Treat any strict-mode reference as a proposal, not a feature you can enable today.
Require components to extend a secure base class that intercepts public assignments:
abstract class SecureComponent extends \Livewire\Component
{
public function __set(string $name, $value): void
{
if ($this->isAllowedPublic($name, $value)) {
parent::__set($name, $value);
return;
}
if (!is_scalar($value) && $value !== null) {
\Log::warning('Blocked non-scalar public property', [
'component' => static::class,
'property' => $name,
'type' => gettype($value),
]);
return;
}
parent::__set($name, $value);
}
protected function isAllowedPublic(string $name, $value): bool
{
return in_array($name, $this->publicAllowlist(), true);
}
protected function publicAllowlist(): array
{
return [];
}
}
Child components override publicAllowlist() to whitelist intentional public scalars such as ['search', 'page']. Models, collections, and tokens stay protected or private and are exposed only through public getters or computed properties.
public $token and public $user assigned an Eloquent model.SecureComponent and confirm the log warning appears while the payload no longer includes the blocked values.__set does not catch properties assigned before the base constructor runs or set through magic methods.publicAllowlist().Missing diagnostic detail: Which Livewire major version are you targeting? The enforcement code above targets 3.x.
Use comments to ask for clarification. Post a solution as an answer.
34,775 reputation · 14 Dec 2021, 00:45 UTC
One clarification on enforcement: #[Locked] (Livewire 3+) prevents client-side mutation of a public property, but it does not strip the initial value from the serialized snapshot. It is an integrity control, not a confidentiality control.
Reflection-based CI rules are useful, but they only inspect declared properties and type hints. Values assigned at runtime—including dynamic properties or values set inside mount()—can still reach the browser. Pair static analysis with a runtime assertion that decodes the actual Livewire payload in a feature test.
For Eloquent models, remember that public model properties may dehydrate attributes or relationships unless $hidden is configured. Prefer passing opaque IDs and re-querying server-side.