keepsuit/laravel-threat-blocker
keepsuit/laravel-threat-blocker is a Laravel package for detecting and blocking malicious or abusive requests. It integrates with middleware and configurable threat rules to reject suspicious traffic before it reaches your application, adding a lightweight layer of protection.
The package is a request-level threat filtering layer for Laravel: it inspects inbound requests, applies a chain of detectors (IP reputation, rate/pattern heuristics, honeypot fields, AI-based spam classification on form payloads), and short-circuits matching requests before they reach your controllers.
Minimum setup:
composer require keepsuit/laravel-threat-blocker
php artisan vendor:publish --tag="threat-blocker-config"
php artisan migrate
config/threat-blocker.php and set the essentials: enabled, block_response (e.g. abort(403) vs redirect vs captcha), the allow list for local/staging IPs, and the honeypot field names your forms will use.web globally:
Route::middleware(['threat-blocker'])->group(function () { ... });
Where to look first: the published config file (it is the real API surface), then the package's middleware class to see detector ordering, then the upgrade guide — 0.2.1's only doc change names the target version in the upgrade guide, which tells you the maintainers expect you to read it before each minor bump.
First use case worth wiring up: the contact/registration form. It's the highest-spam surface, it exercises the honeypot and the AI classifier, and failures there are visible to you immediately rather than silently buried in an API endpoint.
Middleware placement. Prefer route-group or per-form middleware over global registration. Global gives you the broadest coverage but also intercepts health checks, webhooks, and asset routes, all of which you then have to allowlist. A typical layering:
// broad protection, cheap detectors only
Route::middleware(['threat-blocker:light'])->group(...);
// expensive AI classification only where a form is actually submitted
Route::post('/contact', ContactController::class)
->middleware('threat-blocker:strict');
Honeypot in Blade. Render the honeypot fields (a hidden input plus the timestamp the 0.2.1 release explicitly excludes from classification when configured). Always render honeypot server-side; do not reconstruct it in JS, and do not cache the rendered form in a way that reuses a stale timestamp across users.
AI classification as a queueable verdict. Treat the classifier as a scoring step, not a hard gate: let it return a confidence, log the score, and only block above a threshold you control in config. For anything user-facing and latency-sensitive, dispatch classification to a queue and act on the verdict for the next request from that fingerprint, or apply it only to low-frequency forms. 0.2.1 improves classification quality and excludes the configured honeypot timestamp from the model input, so honeypot-driven rejections no longer pollute AI spam signals — this makes the two detectors composable rather than redundant.
Composable detectors via events. Listen for the package's threat-detected event and fan out to your own observability (Slack, Sentry, a threat_events table). This is also the correct extension point for custom logic that doesn't belong in the package: implement a detector/classifier contract, register it in the config's detector array, and keep the package itself unpatched.
Staged rollout after an upgrade. Because this is 0.2.x, ship new detector behavior in log-only mode first: run classification, record the verdict, block nothing. Compare logged verdicts against real traffic for a day or two, then flip block on. This is cheap insurance against a classifier threshold change eating legitimate signups.
StartSession where possible.allow. Add your office/VPN ranges and the health-check path early, and remember CI runners will hit any route your test suite exercises.composer.json and read the upgrade guide (now version-labeled as of 0.2.1) before every bump. Don't assume ^0.2 is safe.How can I help you explore Laravel packages today?