v2.5.0
Changelog v2.5.0
🎉 Major Features
Production-Ready Presets
Three new comprehensive security presets have been added to the presets/ directory for immediate deployment:
1. Malicious Request Detection (presets/malicious-requests.yml)
Advanced vulnerability scoring system that detects and blocks malicious requests based on multiple risk factors:
- 50+ Attack Pattern Signatures: SQL injection, XSS, command injection, path traversal, RCE, web shells, XXE, SSRF, template injection
- 20+ User Agent Rules: Detects automated attack tools (SQLMap, Nikto, Nmap, Metasploit, etc.)
- Multi-Factor Risk Scoring: Combines HTTP method, attack patterns, user agents, and optional GeoIP data
- Progressive Penalties: Escalating ban durations (1 hour → 7 days) based on threat severity
- 5 Risk Levels: Low, medium, high, critical, and extreme with configurable thresholds
- Optional GeoIP Integration: Country and ASN-based scoring when GeoIP databases are configured
2. Rate Limiting (presets/rate-limiting.yml)
Production-ready rate limiting configuration protecting against abuse and resource exhaustion:
- 48 Pre-configured Rules: Covering authentication, APIs, WordPress, forms, static assets, webhooks, and more
- 4 Storage Backends: Redis (recommended), Database, File, or PSR-6 Cache
- Graduated Limits: Different rate limits for different endpoint types
- Login: 5 attempts per 5 minutes
- API: 100 requests per minute
- Static Assets: 500 requests per minute
- Health Checks: 1000 requests per minute
- Smart Defaults: 60 requests per minute for general traffic
- HTTP 429 Status: Proper "Too Many Requests" response
3. Malicious URL Blocking (presets/malicious-urls.yml)
Blocks common malicious PHP files, attack patterns, and suspicious URLs:
- 30+ Regex Patterns: Known backdoor files, web shells, and attack files
- Query/POST Protection: Blocks code execution attempts via parameters
- Generic PHP Blocking: Optional catch-all to block all PHP files except index.php
- WordPress Protection: Specific protections for WordPress installations
New Documentation
Example Directory (example/README.md)
Comprehensive 400+ line guide covering:
- Docker environment setup and usage
- Testing with X-Forwarded-For headers for remote IP simulation
- Complete GeoIP database setup instructions (MaxMind GeoLite2)
- Configuration examples for all major plugins
- Troubleshooting guide
Presets Documentation (presets/README.md)
Extensive 650+ line documentation including:
- Detailed description of all presets
- Quick start guides for each preset
- GeoIP enablement instructions
- Rate limiting storage configuration for all backends
- Customization examples
- Testing commands and scenarios
- Common false positives and solutions
- Layered security approach combining multiple presets
Rate Limiting Reference (presets/RATE-LIMITING-REFERENCE.md)
Quick reference guide with:
- Complete table of all 48 rate limits
- Storage backend comparison matrix
- Common customization examples
- Troubleshooting guide
- Best practices
- Performance benchmarks
Example Configurations
presets/example-malicious-requests-usage.yml: 10 usage scenariospresets/example-rate-limiting-usage.yml: API-only, e-commerce, WordPress-specific configspresets/example-usage.yml: General preset usage examples
🔧 Configuration System Enhancements
Plugin Configuration Merging
Enhanced ConfigLoader::mergeConfigs() with intelligent plugin-specific merging:
Preserve Priority: When merging plugin configs, the priority from the first config is preserved
# base.yml
block:
Plugin:
priority: -100
config: [rule1]
# override.yml
block:
Plugin:
priority: 50 # This will be IGNORED
config: [rule2]
# Result: priority=-100, config=[rule1, rule2]Append Config Arrays: Plugin config arrays are merged (appended) instead of replaced
# Before: Second config replaced first config
# After: Configs are combined [rule1, rule2, rule3]Enable Flag Handling: Smart 4-way logic for enable: false
- Both enabled → Merge configurations
- Base disabled, override enabled → Replace entirely with override
- Override disabled → Ignore override completely
- Both disabled → Remove plugin from final config
Path Tracking: Internal path tracking for intelligent merging decisions
Environment Variable Enhancements
Added _SERVER superglobal support to token substitution:
storage:
file: '%env(_SERVER.DOCUMENT_ROOT)%/firewall.data'🛡️ Security & Validation
Regex Pattern Validation
Complete rewrite of regex pattern handling to eliminate warnings and improve security:
New Validation Method (EvaluateTrait::isValidRegexMatch())
- Validates delimiter format (must be non-alphanumeric)
- Checks delimiter matching (opening/closing delimiters must match)
- Validates minimum pattern length (at least 3 characters)
- Detects all PCRE errors (backtrack limit, recursion limit, UTF-8 errors, etc.)
- Returns false gracefully instead of throwing warnings
- Logs detailed error messages for debugging
Error Handling: Comprehensive error detection and logging
- Internal PCRE errors
- Backtrack limit exhausted
- Recursion limit exhausted
- Malformed UTF-8 data
- Bad UTF-8 offset
- JIT stack limit exhausted
All Presets Updated: All 30+ regex patterns in presets now use proper delimiters
# Before (invalid):
- path@regex:^/test\.php$
# After (valid):
- path@regex:#^/test\.php$#Regex Pattern Documentation
Added comprehensive regex delimiter documentation in both example/README.md and presets/README.md:
- Valid vs invalid pattern examples
- Delimiter selection guidance
- Error handling instructions
- Support for multiple delimiters (#, /, @, ~)
🐛 Bug Fixes
PHPStan Boolean Logic Issue (ConfigLoader.php:288)
Issue: Redundant condition !$baseEnabled && $overEnabled where right side was always true
Fix: Simplified to !$baseEnabled since the case where both are false is already handled earlier
Impact: Cleaner code, passes PHPStan static analysis
Regex Comma Splitting Issue
Issue: Regex patterns with commas in quantifiers (e.g., {1,2}) were incorrectly split into arrays
Fix: Removed 'regex' from multi-value operators list in EvaluateTrait::parseSimpleStringRule()
Impact: Patterns like path@regex:#/[a-z]{1,2}\.php$# now work correctly
Matches Mode Extraction
Issue: Simple explode('#') on patterns was breaking regex patterns using # as delimiter
Fix: Changed to regex pattern match /#(any|all|none|some)$/i to only match valid modes at end of string
Impact: Patterns like #^/test# with # delimiter now work correctly
📝 Testing
New Test Coverage
- 3 new URL plugin tests: Invalid regex handling, different delimiters, modifiers
- 5 new ConfigLoader tests: Plugin config merging scenarios
- Total Tests: 526 unit tests (all passing)
- Total Assertions: 969 assertions
Test Categories
- Invalid regex patterns handled gracefully
- Regex with different delimiters (/, #, @, ~)
- Regex with modifiers (case-insensitive, multiline)
- Plugin config merging (priority preservation, config appending, enable flag logic)
📦 New Files
Presets
presets/malicious-requests.yml(495 lines)presets/rate-limiting.yml(371 lines)presets/malicious-urls.yml(170 lines)presets/wordpress.yml(124 lines)presets/storage-pantheon.yml(10 lines)presets/logging-pantheon.yml(5 lines)
Documentation
presets/README.md(665 lines)presets/RATE-LIMITING-REFERENCE.md(280 lines)example/README.md(406 lines)
Examples
presets/example-malicious-requests-usage.yml(149 lines)presets/example-rate-limiting-usage.yml(287 lines)presets/example-usage.yml(141 lines)presets/config.yml(3 lines)
🔄 Modified Files
Core Changes
src/Traits/EvaluateTrait.php: Added regex validation, fixed comma splittingsrc/Utility/ConfigLoader.php: Enhanced plugin merging, added _SERVER supporttests/Unit/Plugins/UrlTest.php: Added regex validation teststests/Unit/Utility/ConfigLoaderTest.php: Added plugin merging tests
Configuration
example/config.yml: Updated with comprehensive examplesexample/index.php: Enhanced with better error handling and metrics
📊 Statistics
- 3,756 lines added across 22 files
- 76 lines removed
- 526 unit tests (all passing)
- 969 assertions
- 0 PHPStan errors
- 3 new production-ready presets
- 1,350+ lines of new documentation
🚀 Upgrade Guide
From v2.4.0
No Breaking Changes: This release is fully backward compatible with v2.4.0.
New Features to Try:
-
Use presets for instant protection:
configs: - presets/malicious-requests.yml - presets/rate-limiting.yml
-
Enable GeoIP scoring (optional):
Download GeoIP databases and uncomment the country/ASN sections inmalicious-requests.yml -
Configure rate limiting storage:
Update the storage section inrate-limiting.ymlto use Redis or your preferred backend -
Fix regex patterns: If you have custom regex patterns without delimiters, add them:
# Update from: - path@regex:^/test$ # To: - path@regex:#^/test$#
📚 Resources
- Presets README - Complete guide to using presets
- Example README - Docker setup, testing, and GeoIP configuration
- Rate Limiting Reference - Quick reference for all rate limits
Full Changelog: v2.4.0...v2.5.0