DEV Community

Jayanta Kumar Nath
Jayanta Kumar Nath

Posted on • Edited on

I Built a Free Threat Detector for Laravel - Here's How It Works

Jayanta Kumar Nath — Updated March 2026

I run a Laravel app that kept getting hit with SQL injection attempts, bot scanners, and random exploit probes. I didn't want to pay for a WAF service, so I built a middleware package that logs everything silently. It doesn't block anything - just watches, logs, and alerts.

After sharing v1.1.0 here and on Reddit, I got some good feedback and spent time hardening it. v1.2.0 is out now with evasion resistance, queue support, and a bunch of fixes.

What It Does

A middleware that sits in your Laravel pipeline, inspects every incoming request against 130+ regex patterns, and logs what it finds. It's a passive detector - it never blocks the request. Think IDS, not IPS.

Detects:

  • SQL injection (UNION, blind, stacked queries)
  • XSS and script injections
  • Remote code execution attempts
  • Directory traversal, LFI/RFI
  • Scanner bots (SQLMap, Nikto, Burp Suite, etc.)
  • DDoS via rate-based detection
  • SSRF, XXE, Log4Shell, LDAP injection

What's New in v1.2.0

Evasion Resistance

This was the big one. Regex-based detection is easy to bypass if you know how. Attackers use tricks like:

  • UNION/**/SELECT - SQL comment insertion to break up keywords
  • %2527 - double URL encoding to sneak past filters
  • CHAR(39) - SQL character encoding instead of literal quotes

v1.2.0 adds a normalization layer that strips these tricks before matching patterns. The evasion attempt itself is also flagged separately as high severity. So you get two log entries: one for the evasion technique, one for the actual attack underneath.

Also removed the old SQL Comment Syntax pattern (--, #, /*) - it was the #1 source of false positives. CSS classes like font--bold and CLI flags like --verbose were getting flagged. Real SQL attacks are still caught by the keyword patterns.

Route Whitelisting

New only_paths config - scan only specific routes instead of everything. Useful if you have a high-traffic app and only care about API endpoints or admin routes. Leave it empty (default) to scan all routes.

Queue Support

DB writes and Slack notifications can now be offloaded to a queue. Detection stays synchronous (so nothing is missed), but the write is deferred. Uses a dedicated StoreThreatLog job with 3 retries and backoff.

THREAT_DETECTION_QUEUE=true
THREAT_DETECTION_QUEUE_NAME=default

Auto-Purge

Old threat logs can be automatically cleaned up on a daily schedule.

THREAT_DETECTION_RETENTION=true
THREAT_DETECTION_RETENTION_DAYS=90

ThreatDetected Event

Every confirmed threat dispatches a ThreatDetected event. Hook into it for custom actions - Telegram alerts, SIEM feeds, blocklists, whatever you need.

Other Additions

  • Minimum confidence threshold - ignore low-confidence noise (THREAT_DETECTION_MIN_CONFIDENCE)
  • API rate limiting - auto-throttle on API routes
  • Expanded LFI detection - added phar://, expect://, input:// protocols
  • Full RFC 1918 private IP range - fixed 172.16.0.0/12 detection (was only matching 172.16.x.x)
  • Localhost SSRF - added 0.0.0.0 to detection

Performance

  • Stats queries reduced from 7-9 separate queries to 1 using CASE WHEN aggregation
  • Fixed N+1 queries in coordinated attack detection
  • Pattern validation cached per process lifecycle
  • Content-type aware - skips binary fields in multipart uploads

Security Hardening

  • CSV export formula injection prevention
  • Log injection prevention (strips control characters)
  • SSRF prevention in geo-enrichment (IP validation before external API calls)
  • Fixed 3 ReDoS-vulnerable regex patterns

Built-in Dashboard

Dark-mode dashboard with stats cards, 7-day timeline, searchable threat table, top offending IPs, and geo grouping. Uses Alpine.js + Tailwind CDN - no build step.

12 API Endpoints

Full REST API for stats, threat lists, IP rankings, country grouping, timelines, and CSV export. Plug into your own frontend or monitoring stack.

Testing

86 tests, 338 assertions. Includes 16 full-cycle feature tests that send real HTTP requests through the middleware, write to the database, and verify the actual rows - not just unit-level pattern matching.

Installation

composer require jayanta/laravel-threat-detection
php artisan vendor:publish --tag=threat-detection-config
php artisan vendor:publish --tag=threat-detection-migrations
php artisan migrate

Add the middleware in bootstrap/app.php (Laravel 11+):

->withMiddleware(function (Middleware $middleware) {
$middleware->append(\JayAnta\ThreatDetection\Middleware\ThreatDetectionMiddleware::class);
})

Limitations

  • Regex-based, not ML - won't catch novel zero-day patterns
  • Passive only - detects but doesn't block
  • No IP reputation database built in

What's Next

Considering for future versions based on community feedback:

  • Fail2ban export format
  • Path-based probe tracking (404 probes to /wp-admin, /.env, etc.)
  • Sensor class architecture for better extensibility

Links

GitHub: https://github.com/jay123anta/laravel-threat-detection
Packagist: https://packagist.org/packages/jayanta/laravel-threat-detection

Feedback welcome.

Top comments (0)