jeffersongoncalves/filament-scanner-guard
Protect your Filament admin panel from automated vulnerability scanners. Scanner Guard detects suspicious scan attempts, logs malicious traffic, and blocks it before it reaches sensitive routes, with simple configuration and a native Filament settings page for managing rules.
This release (1.2.0) is a maintenance bump — no breaking changes, no new public API, no config or migration changes. The two things worth knowing:
orchestra/testbench ^10.0 || ^11.0, and the CI tests workflow was standardized. Neither affects your application — testbench 11 is the Laravel 12 test harness, so the package's own suite now runs on both.If you are already on 1.1.x, composer update jeffersongoncalves/filament-scanner-guard is safe. There is nothing to republish and no migration to run.
Fresh install:
composer require jeffersongoncalves/filament-scanner-guardvendor:publish --tag="filament-scanner-guard-config") — this is the file you will actually spend time in.php artisan migrate). The package stores ban/hit records in your own database, so the tables land in your app schema.PanelProvider: ->plugin(ScannerGuardPlugin::make()).php artisan config:clear.Look first at: the config file (allowlists, blocked patterns, retention), then the middleware registration in your HTTP kernel/bootstrap/app.php, then the Filament resource for bans in the admin panel.
First realistic use case: let the package watch for the usual noise — /wp-login.php, /.env, /phpmyadmin, /.git/config — and review the resulting bans in the admin UI before you turn on any automatic enforcement. Watch the bans-per-day widget for a week to confirm you are catching scanners and not your own monitoring or health-check traffic.
Start in observation mode, not enforcement. Most painful rollouts happen when the guard is set to block on day one. Log/record first, confirm the allowlist is right, then switch the enforcement flag in config.
Allowlist aggressively and explicitly. Internal RFC1918 ranges, your uptime/monitoring providers, your office egress IPs, your CI runner IPs, and any partner doing bulk API calls. Keep the allowlist in config (not in the DB) so it is version controlled.
Handle proxied traffic properly. The guard bans the IP it sees. Behind Cloudflare or a load balancer, that is your proxy's IP unless TrustProxies is configured — meaning one bad actor bans everyone, or you ban your own CDN. Fix TrustProxies before enabling blocking.
Pair with a scheduled prune. Set retention in config and schedule the prune command; the 1.2.0 chart fix means pruning no longer destroys your trend line, so you can now set a short retention (30–90 days) without losing the visual history.
Use the unban action as an operational workflow. When a legitimate user reports a block, unban from the resource, then add the pattern fix (or IP allowlist entry) that caused the false positive — otherwise they get re-banned on the next matching request.
Decide your response early. A hard 403 is fine for scanners. For anything that might catch real users, prefer a 404 or redirect to a static page — bans that leak "you are blocked" information invite probing.
Layer it under your existing WAF, not instead of it. This is a cheap first-pass filter for application-level noise; it does not replace rate limiting (use Laravel's throttle) or a real WAF.
Testing. Disable the guard in the testing environment via config, or your feature tests will trip it when they hit non-existent routes to assert 404s. Add an explicit test that a known scanner path returns your configured block response.
/up, /health, /favicon.ico, and robots.txt should be allowlisted or excluded from pattern matching — many scanners probe these, and so does your own infrastructure.null at runtime. After editing, always config:clear.migrate --force in CI, make sure the publish step runs before migrate.testbench ^10.0 || ^11.0 widening and the actions-deps updates do not change your installed runtime packages — do not read them as a Laravel 12 support guarantee for the package itself; check the illuminate/* / filament/* constraints in composer.json before upgrading a major Laravel version.curl against a staging allowlist to confirm the rule is what you think it is.How can I help you explore Laravel packages today?