Understanding and Optimizing PCRE Match Limits and Recursion in ModSecurity for Web Application Firewalls


2 views

When dealing with ModSecurity's PCRE limits exceeded errors, we're essentially hitting the computational boundaries set for Perl-Compatible Regular Expressions (PCRE) processing. These limits exist to prevent potential denial-of-service (DoS) attacks through malicious regex patterns.

ModSecurity implements two distinct protective measures:

SecPcreMatchLimit 1000
SecPcreMatchLimitRecursion 1000

These default values represent:

  • MatchLimit: The maximum number of internal matching function calls PCRE can perform
  • MatchLimitRecursion: The maximum stack depth for recursive pattern matching

Complex web applications might require higher limits for legitimate traffic:

# Example for high-traffic e-commerce site
SecPcreMatchLimit 150000
SecPcreMatchLimitRecursion 80000

Common scenarios requiring adjustment:

  • Processing multi-part form data with complex validation rules
  • Scanning large XML/JSON payloads
  • Implementing sophisticated attack pattern detection

Increasing these values does introduce potential risks:

  • Higher CPU utilization during regex processing
  • Increased vulnerability to ReDoS (Regex Denial of Service) attacks
  • Potential for longer request processing times

Instead of blindly increasing limits, consider:

# More efficient approach than blanket limit increase
SecRule REQUEST_URI "@beginsWith /api/" \
    "phase:1,id:1001,\
    ctl:ruleEngine=On,\
    ctl:pcreMatchLimit=200000,\
    ctl:pcreMatchLimitRecursion=100000"

Additional optimization strategies:

  • Profile your regex patterns with tools like pcretest
  • Implement regex complexity limits in development
  • Use atomic grouping and possessive quantifiers where possible

Implement monitoring for PCRE-related metrics:

# Example logging rule
SecRule WEBSERVER_ERROR_LOG "@contains PCRE limits exceeded" \
    "phase:5,id:1002,log,auditlog,msg:'PCRE limit warning'"

Key metrics to track:

  • PCRE execution time per request
  • Percentage of requests approaching limits
  • Patterns triggering limit warnings

When ModSecurity encounters complex regular expressions, it relies on PCRE (Perl Compatible Regular Expressions) library for pattern matching. Two critical parameters govern this matching process:

SecPcreMatchLimit 150000
SecPcreMatchLimitRecursion 150000

The SecPcreMatchLimit defines the maximum number of matching function calls PCRE will perform before aborting. Meanwhile, SecPcreMatchLimitRecursion controls the maximum stack depth during recursive pattern matching.

Example of a problematic regex that would hit these limits:

SecRule REQUEST_URI "@rx ^/(a+)+$" "id:1000,deny"

Increasing these values introduces potential attack vectors:

  • Regular expression denial-of-service (ReDoS) vulnerabilities
  • Increased memory consumption per request
  • Potential CPU exhaustion attacks

Instead of blindly increasing limits, consider these optimizations:

# Optimized regex version
SecRule REQUEST_URI "@rx ^/a+$" "id:1001,deny"

# Alternative approach with length check
SecRule REQUEST_URI "@rx ^/a{1,100}$" "id:1002,deny"

Implement logging to track PCRE usage:

SecAction "id:9000,phase:1,nolog,pass,setvar:tx.pcre_limit=150000,setvar:tx.pcre_recursion_limit=150000"

Analyze your ModSecurity audit logs regularly for PCRE limits exceeded entries to identify problematic rules.

Consider implementing rate limiting for expensive regex patterns:

SecRule REQUEST_URI "@rx ^/(a+)+$" \
    "id:1003,phase:2,deny,log,msg:'Potential ReDoS attack',\
    setvar:ip.regex_attempts=+1,expirevar:ip.regex_attempts=60"