PHPackages                             badbehaviour/badbehaviour - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Security](/categories/security)
4. /
5. badbehaviour/badbehaviour

ActiveLibrary[Security](/categories/security)

badbehaviour/badbehaviour
=========================

Bad Behaviour is a modern bot detection and blocking for PHP applications

2.9.7(2w ago)8651[2 issues](https://github.com/Bad-Behaviour/badbehaviour/issues)1GPL-2.0-or-laterPHPPHP &gt;=8.2

Since Oct 15Pushed 3w ago1 watchersCompare

[ Source](https://github.com/Bad-Behaviour/badbehaviour)[ Packagist](https://packagist.org/packages/badbehaviour/badbehaviour)[ Docs](https://github.com/Bad-Behaviour/badbehaviour)[ RSS](/packages/badbehaviour-badbehaviour/feed)WikiDiscussions master Synced 1w ago

READMEChangelog (7)Dependencies (4)Versions (8)Used By (1)

Bad Behaviour
=============

[](#bad-behaviour)

Bad Behaviour prevents spammers from ever delivering their junk, and in many cases, from ever reading your site in the first place.

Description
-----------

[](#description)

Welcome to a whole new way of keeping your blog, forum, guestbook, wiki, or content management system free of link spam, malicious bots, AI scrapers, and automated attacks. Bad Behaviour is a PHP-based solution for blocking unwanted web traffic and the robots which deliver it.

Thousands of sites large and small trust Bad Behaviour to help reduce incoming link spam, malicious bot traffic, AI scrapers, and automated attacks.

Bad Behaviour complements other security solutions by acting as a gatekeeper, preventing bad actors from ever delivering their payloads, and in many cases, from ever reading your site in the first place. This keeps your site's load down, makes your site logs cleaner, and can help prevent denial of service conditions caused by malicious bots.

Bad Behaviour transcends other solutions by working in a completely different, unique way. Instead of merely looking at the content of potential attacks, Bad Behaviour analyzes the delivery method, TLS fingerprint, HTTP/2 settings, header ordering, behavioral patterns, and the software the attacker is using. In this way, Bad Behaviour can stop attacks even when nobody has ever seen the particular exploit before.

Bad Behaviour is designed to work alongside existing security services to increase their effectiveness and efficiency. Whenever possible, you should run it in combination with a WAF, rate limiter, or traditional spam prevention service.

Bad Behaviour works on, or can be adapted to, virtually any PHP-based Web software package. Bad Behaviour is available for many platforms.

Installing and configuring Bad Behaviour on most platforms is simple and takes only a few minutes. In most cases, no configuration at all is needed. Simply turn it on and stop worrying about spam, scrapers, and automated attacks!

The core of Bad Behaviour is free software released under the GNU Lesser General Public License, version 3, or at your option, any later version.

---

What's New in 3.0 (Complete Modern Rewrite)
-------------------------------------------

[](#whats-new-in-30-complete-modern-rewrite)

Version 3.0 represents a complete rewrite of Bad Behaviour, modernizing the 10+ year old codebase from procedural PHP to a clean, typed PHP 8.2+ architecture with modern bot detection capabilities.

- **Complete Rewrite**: Modern PHP 8.2+ architecture with strict typing, enums, readonly classes, and PSR-4 autoloading
- **AI Crawler Control**: Granular control over GPTBot, ClaudeBot, Google-Extended, PerplexityBot, Meta AI, Applebot-Extended, and more
- **AI/ML-Ready Fingerprinting**: JA3 TLS fingerprinting, HTTP/2 settings analysis, header order analysis (config-driven, zero false positives)
- **Advanced POST Body Inspection**: SQLi, XSS, command injection, Log4Shell, Spring4Shell, SSRF, path traversal, file inclusion
- **Behavioral Analysis**: Rate anomalies, rotating User-Agents/IPs, URL enumeration, missing headers, timing analysis
- **Multi-Tier Rate Limiting**: Global, per-minute, POST, and login endpoints with adapter-backed storage
- **IPv6 Support**: Full CIDR matching with binary comparison fallback (no GMP required)
- **Challenge System**: Builtin proof-of-work, hCaptcha, reCAPTCHA v3, Cloudflare Turnstile

- **Structured JSON Logging**: SIEM-ready logging with semantic result codes
- **Structured Configuration**: INI with sections (\[core\], \[reverse\_proxy\], \[ai\_crawlers\], \[rate\_limits\], etc.)
- **Complete Bot Registry**: 50+ bots across Search, AI, Social, SEO, Archive, Monitoring categories
- **Zero False Positive Fingerprinting**: Only blocks KNOWN bad fingerprints from config
- **Structured Logging**: JSON format for SIEM integration

**BREAKING CHANGES from 2.x:**

- Minimum PHP version now 8.2
- All procedural `.inc.php` files replaced with OOP classes in `src/`
- Hex result codes (e.g. `'17f4e8c8'`) replaced with semantic `ResultCode` enum
- Configuration format changed from flat INI to structured INI with sections
- Adapter interface expanded with new required methods
- Database schema updated with new columns (`bot_category`, `ja3`, `header_order_hash`, `asn`, `country`)
- Custom adapters must implement new `CacheInterface` methods

---

Architecture
------------

[](#architecture)

```
src/
├── BadBehaviour.php              # Main orchestrator
├── Configuration.php             # Typed config with validation
├── Bootstrap.php                 # Single entry point for any PHP app
├── Core/
│   ├── BadBehaviour.php          # Main orchestrator
│   ├── Result.php / ResultCode.php  # Semantic result objects
│   └── Interfaces/
│       ├── AdapterInterface.php  # Host adapter contract
│       ├── LoggerInterface.php   # PSR-3 compatible logging
│       ├── CacheInterface.php    # Rate limit/behavior storage
│       └── GeoIpInterface.php    # MaxMind/ipinfo.io integration
├── Detection/
│   ├── BotDetector.php           # 50+ known bots
│   ├── BlacklistDetector.php     # Malicious UA, attacks
│   ├── BehavioralDetector.php    # Behavioral anomalies
│   ├── FingerprintDetector.php   # JA3, H2, header order (config-only)
│   ├── RateLimitDetector.php     # Multi-tier rate limiting
│   └── DnsblDetector.php         # http:BL, Spamhaus, SpamCop
├── Bot/
│   ├── BotDefinition.php
│   ├── BotCategory.php
│   ├── BotAction.php
│   └── Registry.php              # 50+ known bots
├── Challenge/
│   ├── ChallengeInterface.php
│   ├── BuiltinChallenge.php      # Proof-of-work
│   ├── HCaptchaChallenge.php
│   ├── RecaptchaChallenge.php
│   └── TurnstileChallenge.php
├── Adapter/
│   ├── GenericAdapter.php        # Standalone PHP apps
│   ├── MediaWikiAdapter.php      # MediaWiki integration
│   └── WackoWikiAdapter.php      # WackoWiki integration
├── Util/
│   ├── IpUtil.php                # IPv4/IPv6 CIDR matching
│   ├── HeaderUtil.php            # Header normalization
│   ├── UaParser.php              # Browser/OS/device/bot parsing
│   └── RequestPackage.php        # Immutable request DTO
└── Exception/
    ├── BlockedException.php
    ├── ChallengeRequiredException.php
    └── ConfigurationException.php

```

---

Installation &amp; Usage
------------------------

[](#installation--usage)

### Option 1: Modern Composer Usage (Recommended)

[](#option-1-modern-composer-usage-recommended)

1. Install via Composer:

    ```
    composer require badbehaviour/badbehaviour
    ```
2. Instantiate the library:

**For Generic Applications (Laravel, Symfony, Slim, etc.):**

```
require 'vendor/autoload.php';

use BadBehaviour\Core\BadBehaviour;
use BadBehaviour\Core\Adapter\GenericAdapter;
use BadBehaviour\Configuration;

// Optional custom settings
$custom = [
    'strict' => true,
    'allowed_ai_crawlers' => ['GPTBot', 'ClaudeBot'],
    'block_unverified_ai' => true,
    'strict_ai' => true,
];

$adapter = new GenericAdapter();
$bb = new BadBehaviour($adapter, $custom);

$result = $bb->run();
if (!$result->is_allowed()) {
    $bb->handle_result($result);
    // OR: if ($bb->run()) { exit; } // Legacy style
}
```

**For MediaWiki (e.g. `LocalSettings.php`):**

```
require "$IP/vendor/autoload.php";

use BadBehaviour\Core\BadBehaviour;
use BadBehaviour\Core\Adapter\MediaWikiAdapter;

$db = wfGetDB(DB_MASTER);
$adapter = new MediaWikiAdapter($db, $wgDBprefix, $wgEmergencyContact, $wgScript);
$bb = new BadBehaviour($adapter);
$bb->run();
```

**For WackoWiki:**

```
require 'vendor/autoload.php';

use BadBehaviour\Core\BadBehaviour;
use BadBehaviour\Core\Adapter\WackoWikiAdapter;

$adapter = new WackoWikiAdapter($db);
$bb = new BadBehaviour($adapter);

if (!$bb->run()->is_allowed()) {
    exit;
}
```

### Option 2: Single Entry Point (Any PHP App)

[](#option-2-single-entry-point-any-php-app)

For maximum simplicity, use the single entry point:

```
require 'vendor/autoload.php';

// Optional overrides
$_ENV['BB_STRICT'] = 'true';
$_ENV['BB_ALLOWED_AI_CRAWLERS'] = 'GPTBot,ClaudeBot';

\BadBehaviour\Bootstrap::run();

// Or for middleware-style:
if (!\BadBehaviour\Bootstrap::check(['strict' => true])) {
    exit; // Blocked
}
```

### Option 3: Legacy Drop-In Usage

[](#option-3-legacy-drop-in-usage)

If you maintain an existing site and simply wish to upgrade from 2.x without refactoring your integration, the legacy entry points continue to function exactly as before. They now act as forwarding shims over the new OOP architecture internally.

1. Upload the `badbehaviour` directory to your project.
2. Include the legacy bootstrap file as you always have:
    - MediaWiki: `include( './extensions/Bad-Behaviour/bad-behaviour-mediawiki.php' );`
    - Generic: `require_once 'bad-behaviour-generic.php';`
    - WackoWiki: `require_once 'bad-behaviour-wackowiki.php';`

---

Configuration
-------------

[](#configuration)

Bad Behaviour 3.0 uses a structured INI configuration. Copy `settings.ini.example` to `settings.ini` and customize.

### Core Settings (`settings.ini`)

[](#core-settings-settingsini)

```
[core]
logging = true
verbose = false
strict = false

[reverse_proxy]
enabled = true
header = "CF-Connecting-IP"
addresses[] = "10.0.0.0/8"
addresses[] = "172.16.0.0/12"
; Cloudflare IPs (update regularly via API)
; addresses[] = "173.245.48.0/20"
; addresses[] = "103.21.244.0/22"

[ai_crawlers]
; Add tokens to allow specific AI crawlers (respects robots.txt)
allowed[] = "GPTBot"
allowed[] = "ClaudeBot"
allowed[] = "Google-Extended"
allowed[] = "PerplexityBot"
block_unverified_ai = true
strict_ai = false

[bot_categories]
blocked[] = "malicious"
; blocked[] = "seo_crawler"

[rate_limits]
enabled = true
global_requests = 1000
global_window = 3600
per_minute_requests = 60
per_minute_window = 60
post_requests = 30
post_window = 3600
login_requests = 10
login_window = 900

[challenge]
enabled = false
provider = "builtin"  ; builtin, hcaptcha, recaptcha, turnstile
site_key = ""
secret_key = ""
recaptcha_min_score = 0.5

[performance]
skip_extensions[] = "css"
skip_extensions[] = "js"
skip_paths[] = "/static/"
```

### Whitelist (`whitelist.ini`)

[](#whitelist-whitelistini)

```
[ip]
internal = "10.0.0.0/8"
office = "203.0.113.0/24"
cloudflare = "173.245.48.0/20"

[useragent]
monitoring = "InternalMonitor/1.0"
api_client = "MyApp/2.0 (Internal)"

[url]
health = "/health"
webhook = "/webhook/"
api = "/api/v1/status"

[asn]
google = "AS15169"
cloudflare = "AS13335"

[country]
us = "US"
ca = "CA"
de = "DE"
```

---

Detection Pipeline (Execution Order)
------------------------------------

[](#detection-pipeline-execution-order)

1. **Whitelist** - IP, UA, URL, ASN, Country
2. **Custom Rules** - IP, UA regex, ASN, Country, Header
3. **BotDetector** - 50+ known bots (Search, AI, Social, SEO, Archive, Monitoring)
4. **BlacklistDetector** - Malicious UA, attack payloads, headless browsers
5. **FingerprintDetector** - ONLY known bad fingerprints (config-driven)
6. **DnsblDetector** - http:BL, Spamhaus, SpamCop
7. **BehavioralDetector** - Rate anomalies, rotating UA/IP, enumeration
8. **RateLimitDetector** - Multi-tier (global, per-minute, POST, login)

---

AI Crawler Management
---------------------

[](#ai-crawler-management)

Bad Behaviour 3.0 provides granular control over AI crawlers:

```
[ai_crawlers]
allowed[] = "GPTBot"           ; OpenAI
allowed[] = "ClaudeBot"        ; Anthropic
allowed[] = "Google-Extended"  ; Google Vertex/Bard
allowed[] = "PerplexityBot"    ; Perplexity
allowed[] = "CohereBot"        ; Cohere
allowed[] = "Meta-ExternalAgent" ; Meta
allowed[] = "Applebot-Extended"  ; Apple
allowed[] = "YouBot"           ; You.com
allowed[] = "KagiBot"          ; Kagi Search
block_unverified_ai = true     ; Block spoofed AI crawlers
strict_ai = false              ; true = block even verified unallowed AI
```

CrawlerTokenRobots.txt TokenVerificationGPTBotGPTBotGPTBotDNS (openai.com)ClaudeBotClaudeBotClaudeBotDNS (anthropic.com)Google-ExtendedGoogle-ExtendedGoogle-ExtendedDNS (googlebot.com)PerplexityBotPerplexityBotPerplexityBotIP ranges onlyMeta AIMeta AIMeta-ExternalAgentDNS (facebook.com)Applebot-ExtendedApplebot-ExtendedApplebot-ExtendedDNS (applebot.apple.com)Common CrawlCCBotCCBotIP ranges onlyInternet Archiveia\_archiveria\_archiverIP ranges only---

Challenge System
----------------

[](#challenge-system)

When `challenge_enabled = true`, suspicious requests receive a challenge:

```
[challenge]
enabled = true
provider = "hcaptcha"  ; builtin, hcaptcha, recaptcha, turnstile
site_key = "your-site-key"
secret_key = "your-secret-key"
recaptcha_min_score = 0.5
```

**Providers:**

- `builtin` - Zero-dependency proof-of-work (no external dependencies)
- `hcaptcha` - hCaptcha checkbox/invisible
- `recaptcha` - reCAPTCHA v3 (score-based)
- `turnstile` - Cloudflare Turnstile

---

Rate Limiting
-------------

[](#rate-limiting)

Multi-tier rate limiting with adapter-backed storage:

```
[rate_limits]
enabled = true
global_requests = 1000      ; per hour
global_window = 3600
per_minute_requests = 60
per_minute_window = 60
post_requests = 30          ; per hour
post_window = 3600
login_requests = 10         ; per 15 min
login_window = 900
```

---

Custom Adapters
---------------

[](#custom-adapters)

Implement `HostAdapterInterface` for custom platforms:

```
use BadBehaviour\Core\Interfaces\AdapterInterface;

class MyCustomAdapter implements AdapterInterface
{
    // Required methods:
    public function get_settings(): array;
    public function get_whitelist(): array;
    public function get_email(): string;
    public function get_relative_path(): string;
    public function get_table_schema(string $table_name): string;

    // Database
    public function query(string $sql): bool;
    public function log_request(RequestPackage $package, Result $result): void;

    // Cache/Rate Limiting
    public function increment_counter(string $key, int $window): int;
    public function get_counter(string $key): int;
    public function get_behavior_profile(string $session_id): ?array;
    public function save_behavior_profile(string $session_id, array $profile, int $ttl): bool;
    public function add_to_set(string $key, string $value, int $ttl): bool;
    public function get_set(string $key): array;

    // GeoIP
    public function get_geoip(string $ip): ?array;

    // Challenge
    public function verify_challenge(string $response, string $remote_ip): bool;

    // Logging
    public function log(string $level, string $message, array $context = []): void;
}
```

---

Result Codes (Semantic, Not Hex)
--------------------------------

[](#result-codes-semantic-not-hex)

CodeHTTPDescription`allowed`200Request permitted`blocked.bot`403Known bot blocked`blocked.ai_crawler`403AI crawler blocked`blocked.seo_crawler`403SEO crawler blocked`blocked.malicious_ua`403Malicious User-Agent`blocked.attack_pattern`403Attack payload detected`blocked.dnsbl`403DNSBL match`blocked.httpbl`403http:BL match`blocked.behavioral`403Behavioral anomaly`blocked.fingerprint`403Bad fingerprint`blocked.rate_limit`429Rate limit exceeded`blocked.custom_rule`403Custom rule match`blocked.geoip`403GeoIP block`challenge.required`403Challenge required`challenge.failed`403Challenge failed---

Migration from 2.x
------------------

[](#migration-from-2x)

See [MIGRATION.md](MIGRATION.md) for detailed upgrade instructions.

Key changes:

1. **Config**: Flat INI → Structured INI with sections
2. **Result Codes**: Hex strings → `ResultCode` enum
3. **Adapters**: New interface methods required
4. **Database**: New columns required (`bot_category`, `ja3`, `header_order_hash`, `asn`, `country`)
5. **Entry Points**: Use `Bootstrap::run()` or `new BadBehaviour($adapter, $config)`

---

Requirements
------------

[](#requirements)

- PHP 8.2+
- Extensions: `json`, `mbstring`, `curl`, `gmp` (for IPv6 CIDR)
- Composer 2+

---

Testing
-------

[](#testing)

```
# Run all tests
vendor/bin/phpunit

# Unit tests only
vendor/bin/phpunit --testsuite Unit

# Integration tests
vendor/bin/phpunit --testsuite Integration

# With coverage
vendor/bin/phpunit --coverage-html build/coverage/html
```

---

License
-------

[](#license)

GNU Lesser General Public License v3.0 or later.

---

Support &amp; Documentation
---------------------------

[](#support--documentation)

- [Wiki](https://github.com/Bad-Behaviour/badbehaviour/wiki) - Full documentation
- [Migration Guide](MIGRATION.md) - 2.x to 3.0 upgrade
- [Issues](https://github.com/Bad-Behaviour/badbehaviour/issues) - Bug reports
- [Discussions](https://github.com/Bad-Behaviour/badbehaviour/discussions) - Questions

---

*Bad Behaviour 3.0 - Modern bot detection for the modern web.*

###  Health Score

49

—

FairBetter than 94% of packages

Maintenance91

Actively maintained with recent releases

Popularity19

Limited adoption so far

Community10

Small or concentrated contributor base

Maturity65

Established project with proven stability

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~231 days

Recently: every ~6 days

Total

7

Last Release

15d ago

PHP version history (4 changes)2.2.25PHP 8.0 - 8.1

2.2.26PHP 8.0 - 8.4

2.3.0PHP 8.0 - 8.5

2.9.7PHP &gt;=8.2

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/54716082?v=4)[vendeeglobe](/maintainers/vendeeglobe)[@vendeeglobe](https://github.com/vendeeglobe)

---

Top Contributors

[![vendeeglobe](https://avatars.githubusercontent.com/u/54716082?v=4)](https://github.com/vendeeglobe "vendeeglobe (25 commits)")

---

Tags

botsphpspamspamcommentbotantispamrobotreferrertrackback

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StylePHP\_CodeSniffer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/badbehaviour-badbehaviour/health.svg)

```
[![Health](https://phpackages.com/badges/badbehaviour-badbehaviour/health.svg)](https://phpackages.com/packages/badbehaviour-badbehaviour)
```

###  Alternatives

[gregwar/captcha

Captcha generator

1.8k10.3M166](/packages/gregwar-captcha)[gregwar/captcha-bundle

Captcha bundle

3524.9M36](/packages/gregwar-captcha-bundle)[omines/antispam-bundle

The Swiss Army Knife for protecting your Symfony forms from all kinds of spam

4776.6k](/packages/omines-antispam-bundle)[bbysaeth/typo3-altcha

TYPO3 form element for spam protection by utilizing the proof-of-work mechanism Altcha.

1227.2k1](/packages/bbysaeth-typo3-altcha)[exadium/silverstripe-invisible-spam-protection

Very simple anti spam protection based on principle that automated spammers enter bogus information in all form fields. Field is added to form that is hidden using CSS hiding it from human users. Form is only allowed to be submitted if field is empty. Includes an EditableInvisibleSpamField to integrate with the UserForms module.

112.1k](/packages/exadium-silverstripe-invisible-spam-protection)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
