bdsa/wafy

A Laravel package to automatically ban IP addresses and detect malicious requests.

Maintainers

Package info

github.com/tomakakwark/wafy

pkg:composer/bdsa/wafy

Transparency log

Statistics

Installs: 52

Dependents: 0

Suggesters: 0

Stars: 1

Open Issues: 0

1.2.6 2026-07-02 09:00 UTC

This package is not auto-updated.

Last update: 2026-07-02 09:01:36 UTC


README

License PHP Laravel

Wafy is a robust Laravel package developed by Bdsa designed to automatically ban IP addresses and detect malicious requests, including SQL Injection, XSS, and more.

Features

  • 🛡️ IP Banning: Automatically block IPs engaging in suspicious activity.
  • 🕵️ Malicious Request Detection: Detects SQLi, XSS, LFI, and RCE attempts.
  • ⏱️ Temporary & Permanent Bans: Configurable ban durations.
  • ⚙️ Customizable Patterns: Define your own regex patterns for detection.
  • 🖥️ Artisan Commands: Easily manage banned IPs via CLI.

Installation

1. Require with Composer

Add the package to your project:

composer require bdsa/wafy

2. Publish Configuration

Publish the configuration file and migrations:

php artisan vendor:publish --provider="Bdsa\Wafy\WafyServiceProvider"

3. Run Migrations

Create the banned_ips table:

php artisan migrate

Usage

Middleware

Wafy provides two key middlewares : BlockBannedIp & DetectMaliciousRequests.

Protecting Routes

Apply the middleware to your routes or groups:

use Bdsa\Wafy\Middleware\BlockBannedIp;
use Bdsa\Wafy\Middleware\DetectMaliciousRequests;

Route::group(['middleware' => ['block.banned.ip', 'detect.malicious.requests']], function () {
    Route::get('/', function () {
        return view('welcome');
    });
    
    // Your protected routes
});

Artisan Commands

Manage banned IPs directly from the terminal:

  • Ban an IP manually:

    php artisan wafy:ban {ip_address} [--reason="Your reason"]
  • Unban an IP:

    php artisan wafy:unban {ip_address}
  • List all banned IPs:

    php artisan wafy:list
  • Enable/Disable WAF:

    php artisan wafy:mode {enable|disable}
  • Set Action Mode (Block or Log-Only):

    php artisan wafy:action {block|log}

ℹ️ Note — wafy:mode and wafy:action are temporary runtime overrides. These two commands store their state in the cache, so they are meant for momentary situations (testing, incident response). Any cache flush (php artisan cache:clear, config:cache, a deploy, a Redis restart…) resets them, and Wafy falls back to the values in config/wafy.php. To change the behaviour permanently, edit config/wafy.php (or the matching WAFY_* environment variables) — that is the source of truth.

⚠️ Running behind a reverse proxy / CDN (read this first)

Wafy identifies clients by IP ($request->ip()) and can ban them. If your application runs behind a reverse proxy, load balancer or CDN (Nginx, Traefik, Cloudflare, AWS ALB…), you must configure Laravel's TrustProxies middleware so that $request->ip() returns the real client IP.

  • If you don't configure trusted proxies, every request appears to come from the proxy. The first malicious request then bans your own proxy, cutting off all traffic.
  • If you trust proxies with a blanket *, the X-Forwarded-For header becomes attacker-controlled: an attacker can spoof a clean IP to bypass bans, or forge a victim's IP to get it banned. Only trust the specific proxy ranges you use.

Also add your proxy / CDN ranges and any critical infrastructure to wafy.allowed_ips (CIDR ranges are supported) so they can never be banned.

Configuration

The configuration file is located at config/wafy.php. Besides the detection patterns, the following options control how bans are applied:

Key Default Description
ban_threshold 1 Number of detections from one IP (within strike_window minutes) before it is banned. Raising this above 1 is strongly recommended so a single false positive doesn't lock out a legitimate (shared/NAT/mobile) IP. The offending request is always blocked regardless.
strike_window 60 Minutes over which strikes accumulate.
ban_duration 1440 Automatic ban lifetime in minutes (24h). Set to null for permanent bans. Manual wafy:ban bans are always permanent.
max_scan_length 16384 Max characters inspected per field — caps regex CPU cost (ReDoS protection).
fail_open true If the ban database is unreachable, let requests through (true) instead of returning 503 for everyone (false).
scan_headers ['User-Agent', 'Referer'] Request headers inspected for patterns.
sensitive_keys passwords, tokens, card fields… Input keys whose values are redacted before a request is stored or notified.
allowed_ips [] IPs / CIDR ranges (IPv4 & IPv6) that bypass Wafy entirely.

Default protection covers:

  • SQL Injection (SQLi): UNION SELECT, common SQL verbs, hex encoding.
  • Local File Inclusion (LFI): Directory traversal (../), system files (/etc/passwd).
  • Cross-Site Scripting (XSS): Script tags, event handlers (onload, onerror).
  • Remote Code Execution (RCE): Shell commands (cat, wget), PHP execution functions.

Example config/wafy.php:

return [
    'enabled' => env('WAFY_ENABLED', true),
    'patterns' => [
        '/(union(\s+all)?\s+select)/i',
        '/(select\s+.*\s+from|delete\s+from|update\s+.*\s+set)/i',
        '/(<script.*?>.*?<\/script>)/is',
        // Add your custom patterns here
    ],
    'allowed_ips' => [
        '127.0.0.1', // Localhost
        '192.168.1.1', // Office IP
    ],
    'notifications' => [
        'enabled' => env('WAFY_NOTIFICATIONS_ENABLED', false),
        'channels' => ['mail'], // Choose 'mail', 'slack' or both
        'email' => env('WAFY_NOTIFICATION_EMAIL', 'admin@example.com'),
        'slack_webhook' => env('WAFY_SLACK_WEBHOOK', ''),
    ],
];

Testing

To run the package tests:

vendor/bin/phpunit

License

This project is licensed under the MIT License.