Filament beveiligen begint met één methode: canAccessPanel(). Zonder die check kan in productie niemand inloggen. Mét een slordige return true kan iedereen met een account erin. Daarna volgen policies, MFA, file uploads en updates. In 2026 publiceerde Filament al elf security advisories. Updaten...
Filament beveiligen begint met één methode: canAccessPanel(). Zonder die check kan in productie niemand inloggen. Mét een slordige return true kan iedereen met een account erin. Daarna volgen policies, MFA, file uploads en updates. In 2026 publiceerde Filament al elf security advisories. Updaten is dus geen bijzaak.
Onze eigen backoffice draait op Filament: blog, leads, afspraken, cases en een database met Magento-shops. Deze checklist loop je af vóór elke livegang. Hij geldt voor Filament v4 en v5. Nieuw met Filament? Begin dan bij wat Filament is en wanneer je het inzet.
Waarom is canAccessPanel verplicht in productie?
Buiten de local-omgeving weigert Filament elke gebruiker die het FilamentUser-contract niet implementeert. Volgens de deployment-docs kan dan "niemand inloggen in productie". De echte valkuil is de snelle fix: return true. Dan krijgt elk account in je users-tabel toegang tot het panel.
Dat is extra gevaarlijk als dezelfde tabel ook klanten bevat. Denk aan een webshop-backoffice of een klantportaal. Een klant die zich registreert, logt dan zo in op je admin.
De correcte opzet, volgens de Filament-docs:
use Filament\Models\Contracts\FilamentUser;
use Filament\Panel;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable implements FilamentUser
{
public function canAccessPanel(Panel $panel): bool
{
if ($panel->getId() === 'admin') {
return $this->is_admin && $this->hasVerifiedEmail();
}
return false;
}
}
Drie regels die wij hanteren:
- Check altijd
$panel. Bij meerdere panels (admin, klantportaal) moet elk panel een eigen regel hebben. - Default
false. Een nieuw panel is dan dicht tot je het bewust opent. - Geen e-mail-domeincheck alleen.
str_ends_with($email, '@bedrijf.nl')werkt alleen als registratie uit staat of e-mail geverifieerd is.
Hoe stel je MFA in Filament in?
Filament heeft sinds v4 ingebouwde multi-factor authentication. Je kiest uit een authenticator-app (TOTP, zoals Google Authenticator of Microsoft Authenticator) of een code per e-mail. Er is geen extra package nodig.
use Filament\Auth\MultiFactor\App\AppAuthentication;
use Filament\Auth\MultiFactor\Email\EmailAuthentication;
->multiFactorAuthentication([
AppAuthentication::make()->recoverable(),
EmailAuthentication::make(),
], isRequired: true)
Wat je nog meer nodig hebt:
- App-MFA:
HasAppAuthenticationinterface,InteractsWithAppAuthenticationtrait en een kolomapp_authentication_secret. - Recovery codes:
HasAppAuthenticationRecovery, de bijbehorende trait en een kolomapp_authentication_recovery_codes. - E-mail-MFA:
HasEmailAuthentication, de trait en een booleanhas_email_authentication.
Zet isRequired: true aan voor elk panel met klantdata of orders. Optionele MFA slaan gebruikers in de praktijk vaak over.
De eerlijke versie: Filament zegt zelf dat MFA alleen binnen de Filament-loginflow geldt. Heb je ook een API of andere login-routes? Die vallen er buiten. Daar regel je MFA of token-beveiliging apart, bijvoorbeeld via Sanctum of Passport.
Belangrijk: juist de MFA-code had in 2025-2026 de meeste advisories. Daarover meer bij updates.
Werkt Filament automatisch met Laravel policies?
Ja, voor resources. Filament leest je model policies voor viewAny, view, create, update, delete, deleteAny, restore, forceDelete en reorder. Maar ontbreekt een policy, dan geeft Filament standaard gewoon toegang.
Dat staat letterlijk in de panel-docs: zonder policy "gaat Filament ervan uit dat je authorization nog niet hebt ingesteld" en laat de gebruiker door. Eén vergeten make:policy en een resource staat open voor elke panel-gebruiker.
De oplossing is één regel in je panel provider:
->strictAuthorization()
Daarmee gooit Filament een exception als een policy of policy-methode ontbreekt. Je merkt het dus in development, niet in een incident.
Wat strictAuthorization() níet afdekt, volgens de Filament security-docs:
- Custom pages en widgets. Die gebruiken
canAccess()ofcanView(). Die moet je zelf implementeren. - Custom actions. Gebruik
authorize(),visible()ofhidden(). Een action zonder check is voor iedereen uitvoerbaar. - Inline-editable kolommen.
ToggleColumn,TextInputColumnenSelectColumnchecken géén policy. Alleen dedisabled()-state telt. - Bulk actions. Die gebruiken standaard
deleteAny()en niet per recorddelete(). Wil je per record checken? GebruikauthorizeIndividualRecords().
Werk je met rollen en permissies? Dan is Filament Shield de gangbare route. We schreven er een apart stuk over: rollen en rechten in Filament met Shield.
Hoe zit het met mass assignment en verborgen velden?
Filament slaat alleen velden op die in je form-schema staan. Dat beperkt mass assignment, maar het lost niet alles op. Het grotere risico zit in data die je per ongeluk naar de browser stuurt.
Livewire stuurt alle niet-$hidden model-attributen mee naar de frontend. Volgens de Filament-docs kunnen gebruikers die niet via mass assignment wijzigen. Maar ze kunnen ze wel lezen in de browser. Denk aan API-keys, interne notities of marge-velden.
Concreet:
- Zet gevoelige kolommen in
$hiddenop het model, of filter ze inmutateFormDataBeforeFill(). - Gebruik geen globale
Model::unguard(). Veel Filament-tutorials doen dit voor gemak. Het schakelt$fillablevoor je hele app uit, ook buiten Filament. - Vertrouw niet op
hidden()ofdisabled()in een form als beveiliging. Het is UI. Echte afscherming zit in policies en query scoping. - Scope je queries. Filament scoped alleen automatisch bij ingebouwde tenancy. Custom pages, actions en relation queries scope je zelf via
getEloquentQuery()ofmodifyQueryUsing().
Hoe beveilig je file uploads in Filament?
Het FileUpload-veld accepteert standaard elk bestandstype. De Filament-docs waarschuwen expliciet: op een local of public disk kan een aanvaller een .php-bestand uploaden en uitvoeren. Dat is remote code execution.
Een veilige basis:
use Filament\Forms\Components\FileUpload;
FileUpload::make('invoice')
->disk('s3')
->visibility('private')
->acceptedFileTypes(['application/pdf'])
->maxSize(5120)
->preventFilePathTampering()
->storeFileNamesIn('invoice_original_name');
Waarom elke regel:
acceptedFileTypes()activeert demimetypes-validatie en blokkeert PHP-extensies. Voor afbeeldingen volstaat->image().maxSize()in kilobytes. Stem dit af opupload_max_filesizeenpost_max_sizeinphp.ini.preventFilePathTampering()omdat de waarde van het veld een client-controlled string is. Zonder deze check kan een gebruiker naar andere bestanden op dezelfde disk verwijzen.storeFileNamesIn()in plaats vanpreserveFilenames(). Originele bestandsnamen op disk zijn oplocalofpubliceen RCE-risico.- S3 of een private disk. Bestanden op S3 worden niet door PHP uitgevoerd.
Heb je eigen Livewire-pages met schemas? Voeg dan de trait RestrictsFileUploadsToSchemaComponents toe. Anders kan een aanvaller uploads doen naar willekeurige properties. Voor de bredere Laravel-kant van uploads zie beveiligde file uploads in Laravel.
Moet je het panel-pad /admin veranderen?
Een ander pad via ->path('beheer-x7') stopt geautomatiseerde scans. Het stopt geen gerichte aanval. Zie het als ruisreductie, niet als beveiliging.
Wat wel echt helpt:
->domain('admin.jouwbedrijf.nl')zet het panel op een eigen subdomein. Daarop kun je aparte firewall-regels of een IP-allowlist zetten.- IP-restrictie op webserver- of Cloudflare-niveau voor interne panels. Een backoffice die alleen vanaf kantoor en VPN bereikbaar is, heeft een veel kleiner aanvalsoppervlak.
- Eigen middleware via
->middleware()of->authMiddleware()op het panel, bijvoorbeeld voor een CSP-header.
Heeft Filament rate limiting op de login?
Ja. De loginpagina heeft ingebouwde rate limiting: 5 pogingen per minuut per IP-adres. Het wachtwoord-reset-formulier staat op 2 per minuut. Dat zie je in de broncode van Filament\Auth\Pages\Login en RequestPasswordReset.
De valkuil zit in "per IP". Draai je achter Cloudflare, een load balancer of een andere proxy? Dan moet Laravel's TrustProxies goed staan. Anders ziet Filament alle bezoekers als hetzelfde IP-adres. Gevolg: één aanvaller blokkeert iedereen, of de limiet werkt helemaal niet.
Bovenop de ingebouwde limiet adviseren wij:
- MFA verplicht, zodat een gelekt wachtwoord niet genoeg is.
- Registratie uit (
->registration()niet aanroepen) op interne panels. - Een WAF-regel op het login-pad bij verdachte volumes.
Heeft Filament audit logging?
Nee. Filament logt niet standaard wie wat heeft gewijzigd. Voor elk panel met orders, prijzen of klantdata wil je dat wel. Bij een incident is "wie heeft dit veranderd?" de eerste vraag.
De gangbare route is spatie/laravel-activitylog op je modellen, plus een Filament-plugin of eigen resource om de log te tonen. Log minimaal:
- Create, update en delete op gevoelige modellen, met oude en nieuwe waarden.
- Login-pogingen en MFA-wijzigingen.
- Bulk actions en exports. Een export van je hele klantenbestand is een datalek-risico.
Exports verdienen extra aandacht. In Filament v3 (vóór 3.2.123) kwamen geëxporteerde bestanden standaard op de public disk terecht (advisory GHSA-4hxw-gc2q-f6f3). Controleer waar jouw exports landen. Meer over exports in import en export in Filament.
Welke Filament security advisories zijn er bekend?
Filament publiceert advisories via GitHub Security Advisories op de filamentphp/filament-repository. Wij telden er per 6 oktober 2026 veertien. Elf daarvan verschenen in 2026, de meeste rond MFA en XSS.
| Advisory | Datum | Ernst | Wat | Opgelost in |
|---|---|---|---|---|
| GHSA-7m6h-rg42-m449 | 23-09-2026 | Medium | MFA-beheer vraagt geen wachtwoord opnieuw | 4.13.3 / 5.8.3 |
| GHSA-52xp-w8hr-xv3c | 17-08-2026 | High | MFA (app) te omzeilen met recovery codes aan | 4.12.0 / 5.7.0 |
| GHSA-r3j6-gpjw-qfjr | 17-08-2026 | Medium | Oude MFA-code bruikbaar na nieuwere code | 4.12.6 / 5.7.6 |
| GHSA-xwpv-pqxp-5v36 | 17-08-2026 | Low | Wachtwoord-validiteit lekt bij geweigerde panel-toegang | 4.12.5 / 5.7.5 |
| GHSA-m9cv-24rx-8mv7 | 17-06-2026 | High | XSS via disabled RichEditor (v3) | forms 3.3.53 |
| GHSA-mc5j-f6wx-h9qh | 23-05-2026 | High | Recovery codes meermaals bruikbaar via gelijktijdige requests | 4.11.5 / 5.6.5 |
| GHSA-44wp-g8f4-f4v5 | 23-05-2026 | Medium | Ongeauthenticeerde tijdelijke upload op auth-pagina's | 3.3.52 / 4.11.5 / 5.6.5 |
| GHSA-5w46-g9pq-wh6f | 23-05-2026 | Medium | User enumeration via timing op loginpagina | 4.11.5 / 5.6.5 |
| GHSA-vv3x-j2x5-36jc | 18-03-2026 | High | XSS via Range/Values summarizers | 4.8.5 / 5.3.5 |
| GHSA-9h9q-qhxg-89xr | 27-09-2024 | Critical | XSS via ColorColumn/ColorEntry (v3) | 3.2.115 |
Niet alle veertien staan in de tabel. De volledige lijst staat op github.com/filamentphp/filament/security/advisories.
De rekenstap is simpel. Zit je op v5 en lager dan 5.8.3, of op v4 lager dan 4.13.3? Dan heb je minstens één bekende kwetsbaarheid. De nieuwste release op Packagist is 5.9.0 (26 september 2026). Draai je nog v3? Lees dan Filament 3 upgraden naar 5.
Zo blijf je bij:
composer auditin je CI-pipeline. Die checkt je lockfile tegen bekende advisories.- Dependabot of Renovate op de repository.
- "Watch → Security alerts" op de Filament GitHub-repo.
php artisan filament:upgradein jecomposer.jsonpost-update scripts laten staan, zoals de docs voorschrijven.
Filament security checklist voor productie
| # | Check | Hoe | Prioriteit |
|---|---|---|---|
| 1 | canAccessPanel() met echte logica per panel | FilamentUser-contract, default false | Must |
| 2 | Geen return true in canAccessPanel() | Code review | Must |
| 3 | strictAuthorization() aan | Panel provider | Must |
| 4 | Policy voor elk resource-model | make:policy, test met Pest | Must |
| 5 | Custom actions, pages en widgets geautoriseerd | authorize(), canAccess() | Must |
| 6 | MFA verplicht | multiFactorAuthentication([...], isRequired: true) | Must |
| 7 | Filament op laatste patch-versie | composer audit, Dependabot | Must |
| 8 | acceptedFileTypes() op elke FileUpload | Form-schema | Must |
| 9 | preventFilePathTampering() en geen preserveFilenames() | Form-schema | Must |
| 10 | Gevoelige attributen in $hidden | Model | Should |
| 11 | Geen globale Model::unguard() | AppServiceProvider | Should |
| 12 | Queries gescoped buiten tenancy | getEloquentQuery() | Should |
| 13 | TrustProxies correct achter proxy/CDN | Laravel config | Should |
| 14 | Registratie uit op interne panels | Panel provider | Should |
| 15 | Audit logging op gevoelige modellen | Activitylog | Should |
| 16 | Exports op private disk | Export-config | Should |
| 17 | Panel op eigen (sub)domein of IP-allowlist | domain(), firewall | Could |
| 18 | CSP-header via panel-middleware | ->middleware() | Could |
| 19 | Ander panel-pad dan /admin | path() | Could |
Policies test je het best automatisch. Een test die per rol checkt wie welke resource mag openen, vangt regressies na elke update. Zie Filament testen met Pest.
Samengevat
canAccessPanel()is verplicht en moet per panel echte logica hebben.- Zonder
strictAuthorization()staat een resource zonder policy open. - Inline-editable kolommen en custom actions checken geen policies vanzelf.
- MFA is ingebouwd sinds v4. Zet hem verplicht.
FileUploadaccepteert standaard alles. Beperk types, grootte en paden.- Rate limiting op login is er al (5 per minuut per IP), mits je proxy-config klopt.
- Audit logging moet je zelf toevoegen.
- Er zijn 11 advisories in 2026. Patch naar minimaal 5.8.3 of 4.13.3.
Bouw je een backoffice of portaal op Laravel en wil je dat iemand meekijkt? Dit is precies het werk dat we voor onze eigen Filament-omgeving doen.
Veelgestelde vragen
Is Filament veilig voor productie?
Ja, mits je het goed configureert en bijwerkt. Filament controleert policies, heeft rate limiting op de login en ingebouwde MFA. De meeste risico's zitten in configuratie: een open canAccessPanel(), ontbrekende policies of onbeperkte file uploads. Filament patcht gemelde kwetsbaarheden snel, dus updaten is het tweede halve werk.
Wat gebeurt er als ik canAccessPanel niet implementeer?
Lokaal mag elke gebruiker inloggen. In elke andere omgeving kan niemand inloggen, ook jij niet. Dat is veilig, maar leidt vaak tot een snelle return true. Die fix opent het panel voor elk account in je users-tabel.
Heeft Filament ingebouwde twee-factor-authenticatie?
Ja, sinds Filament v4. Je kiest uit een authenticator-app (TOTP) met optionele recovery codes, of een code per e-mail. Met isRequired: true maak je MFA verplicht voor alle gebruikers. Let op: het geldt alleen voor de Filament-login, niet voor je API.
Zijn er bekende CVE's of kwetsbaarheden in Filament?
Ja. Per 6 oktober 2026 staan er veertien advisories op GitHub, waarvan elf uit 2026. Ze gaan vooral over MFA-omzeiling en XSS. Voor v4 en v5 is alles opgelost vanaf 4.13.3 en 5.8.3; draai composer audit om je eigen project te checken.
Hoe log ik wie wat wijzigt in Filament?
Filament heeft geen ingebouwde audit log. De gangbare oplossing is spatie/laravel-activitylog op je modellen, met een Filament-resource of plugin om de log te bekijken. Log in elk geval wijzigingen op gevoelige data, bulk actions en exports.
Is het veranderen van /admin naar een ander pad zinvol?
Beperkt. Het filtert geautomatiseerde scans uit je logs, maar houdt geen gerichte aanvaller tegen. Een eigen subdomein met IP-allowlist of VPN-toegang levert veel meer op.
Twijfel je of jouw Filament-panel aan deze checklist voldoet? Neem contact op, dan lopen we hem samen door.

Geschreven door Ruthger Idema
15+ jaar ervaring in e-commerce development. Gespecialiseerd in Magento, Shopify en Laravel maatwerk.
Meer over ons team →