From Just another day in the life of a linux sysadmin
Jump to navigation Jump to search

Simply Put Whitelisting

[root@host /usr/local/apache/logs]# vim /usr/local/apache/conf/modsec2.user.conf

(add this)

# Added per ticket #3542761 by JParks on 11-29-12
<LocationMatch "/~trialcom/panel/productos_f.php">     <-------URI tripping the rule
  SecRuleRemoveById 300016                             <--------Rule ID


ModSecurity is an open source, free web application firewall (WAF) Apache module. With over 70% of all attacks now carried out over the web application level, organizations need all the help they can get in making their systems secure. WAFs are deployed to establish an external security layer that increases security, detects and prevents attacks before they reach web applications. It provides protection from a range of attacks against web applications and allows for HTTP traffic monitoring and real-time analysis with little or no changes to existing infrastructure.

There are other fun things that you can do with modsec that are not covered here but if you need some voodoo performed please ask away. Here are two other good points of reference for modsec related info: and Docs



Mod_sec will show its specific version in the audit log (/usr/local/apache/logs/audit_log or modsec_audit.log). If the log is missing, or empty and hasn't been touched in a long time, chances are ModSec is not installed, or the configs are not included in the httpd.conf.

 Producer: ModSecurity v2.1.3 (Apache 2.x)


Apache 1.X


The main cpanel modsec config is here:


modsec.conf (modsec1)

<IfModule mod_security.c>
SecFilterEngine On
SecFilterCheckURLEncoding On
SecFilterForceByteRange 0 255
SecAuditEngine RelevantOnly
SecAuditLog logs/audit_log
SecFilterDebugLog logs/modsec_debug_log
SecFilterDebugLevel 0
SecFilterDefaultAction "deny,log,status:406"
SecFilterSelective REMOTE_ADDR "^$" nolog,allow
Include "/usr/local/apache/conf/modsec.user.conf"

Our main config is here:


This config includes our other configs located here:


When modsec is triggered the user (or bot) will see 406 (or potentially a 403) error indicating Forbidden or Not Acceptable


cPanel 11 has blessed us with Apache 2 (And Mod Security 2.c).

In order to enable Mod Security, you need to compile Apache2 with UniqueId, and obviously, mod_security needs to be checked as well. If done correctly, you should see these two lines in the httpd.conf

LoadModule security2_module modules/
Include "/usr/local/apache/conf/modsec2.conf"

Can't find the LoadModule statement in the httpd.conf file? Check in the modsec2.conf file.

To install our rules, just do so with lpyum

lpyum install lp-modsec2-rules.noarch

Install our rules on CENT 6

yum install lp-modsec2-rules.noarch

The Log

modsec logs here:


Once per hour (on the hour) cpanel parses the log with /etc/cron.hourly/, puts the contents in mysql and wipes the log.
The info it grabbed will then be located in the WHM interface under Plug-ins -> Mod Security

All (new) rules are now grouped by type with a description and group ID. When a rule is flagged it will show in the audit log with the regex it matched, the rule description and the ID#. Use this to track down the rule getting hit.

The parts of the log that are going to be most relevant (although much of it is helpful) are the "mod_security-message" and "post payload" (if it was a POST). Here is a fine example:

Request: - - [24/Jan/2006:12:42:02 -0500] 
"GET /index.php?_REQUEST[option]=com_content&_REQUEST[Itemid]=1&GLOBALS=&mosConfig_absolute_path=;lwp-download%20;perl%20sess3024_;rm%20-rf%20sess3024*? HTTP/1.0" 403 396 "-" "Mozilla/5.0" - "-" ---------------------------------------- GET /index.php?_REQUEST[option]=com_content&_REQUEST[Itemid]=1&GLOBALS=&mosConfig_absolute_path=;lwp-download%20;perl%20sess3024_;rm%20-rf%20sess3024*? HTTP/1.0 Accept: */* Host: User-Agent: Mozilla/5.0 mod_security-message: Access denied with code 403. Pattern match "/tool\\.(d(ao)t|gif|jpg|bmp|txt)\\?&(cmd|command)=" at THE_REQUEST [msg "rootkit sig. group 2000"] mod_security-action: 403 HTTP/1.0 403 Forbidden Connection: close Content-Type: text/html; charset=iso-8859-1 --5d59c72e--

In this case we know that the request was blocked because it matched a rootkit signature in rule group 2000. We are also going to ACL some IP's just to be safe: (script exploiter) (exploit repo) (exploit repo)


If something needs to be whitelisted simply open the whitelist.conf and add something like one of these:

SecFilter "yourregex" allow,nolog
SecFilterSelective THE_REQUEST "yourregex" allow,nolog
SecFilterSelective REQUEST_URI "yourregex" allow,nolog
SecFilterSelective POST_PAYLOAD "yourregex" allow,nolog
SecFilterSelective HTTP_Referer "yourregex" allow,nolog
SecFilterSelective HTTP_CLIENT_IP "yourregex" allow,nolog
SecFilterSelective HTTP_USER_AGENT "yourregex" allow,nolog

N.B. Both SecFilter and SecFilterSelective are deprecated in favor of SecRule in ModSec2.

Those should cover just about anything getting caught by a filter. You should only need one of those though. Also please note that nolog can be change to log for troubleshooting and that yourregex is to be replaced with whatever expression you are trying to catch and whitelist.

For example if you wanted to whitelist any request containing you would add this:

SecFilterSelective THE_REQUEST "" allow,nolog

However, whitelisting by domain; you may get

Syntax error on line 43 of /usr/local/apache/conf/modsec2/whitelist.conf: Invalid command 'SecFilterSelective', perhaps mis-spelled or defined by a module not included in the server configuration

Try this:

SecRule SERVER_NAME "" phase:1,nolog,allow,ctl:ruleEngine=off

If you want to whitelist by IP, you might try these (replace with the proper IP of course):

SecRule REMOTE_ADDR "^69\.16\.222\.126$" phase:1,log,allow,ctl:ruleEngine=DetectionOnly
SecRule REMOTE_ADDR "^69\.16\.222\.126$" phase:1,log,allow,ctl:ruleEngine=Off

Apache 2


The main cpanel modsec config is here:


modsec2.conf (modsec2)

LoadFile /opt/xml2/lib/
LoadFile /opt/lua/lib/
LoadModule security2_module  modules/
<IfModule mod_security2.c>
SecRuleEngine On
# See 
#  "Add the rules that will do exactly the same as the directives"
# SecFilterCheckURLEncoding On 
# SecFilterForceByteRange 0 255
SecAuditEngine RelevantOnly
SecAuditLog logs/modsec_audit.log 
SecDebugLog logs/modsec_debug_log
SecDebugLogLevel 0
SecDefaultAction "phase:2,deny,log,status:406"
SecRule REMOTE_ADDR "^$" nolog,allow
Include "/usr/local/apache/conf/modsec2.user.conf"

Our main config is here:


You will find additional configs in /usr/local/apache/conf/modsec2/, which are


There should be much of a reason to touch those, but in case, it's pretty straight forward what they do.


cPanel 11 has blessed us with Apache 2 (And Mod Security 2.c).

In order to enable Mod Security, you need to compile Apache2 with UniqueId, and obviously, mod_security needs to be checked as well. If done correctly, you should see these two lines in the httpd.conf

LoadModule security2_module modules/
Include "/usr/local/apache/conf/modsec2.conf"

Can't find the LoadModule statement in the httpd.conf file? Check in the modsec2.conf file.

To install our rules, just do so with lpyum

lpyum install lp-modsec2-rules.noarch

If Cent 6 is running on the box, use

 yum install lp-modsec2-rules.noarch

The Log

modsec logs here:


For now, the logs are pretty basic. It's pretty obvious what triggered the rule in the example below. This will help you trouble shoot whats going on if you get a 406 Not Acceptable.

Message: Access denied with code 406 (phase 2). Pattern match "mkdir" at REQUEST_URI.
Action: Intercepted (phase 2)
Stopwatch: 1191523307325575 2609 (1105 1654 -)
Producer: ModSecurity v2.1.3 (Apache 2.x)
Server: Apache/2.0.61 (Unix) mod_ssl/2.0.61 OpenSSL/0.9.7a mod_auth_passthrough/2.1 mod_bwlimited/1.4 PHP/5.2.4


Rules are rules for a reason. Don't just remove them...


ModSecurity Phases and Variables

Whitelisting is a lot different with modsec2. You'll want to add the rules to


or for CentOS 6.2

/etc/httpd/modsecurity.d/lwrules/whitelist.conf for Plesk.

The first issue to realize is that in ModSecurity 2.0, the allow action is only applied to the current phase. This means that if a rule matches in a subsequent phase it may still take a disruptive action.

You can get very specific with what gets filtered and what doesn't. But this should get the errors out of the customers face. If they need something more specific, direct them to Steven Collins (tread lightly), or visit Mod Security for more information.

The easiest way to whitelist a rule is to add a LocationMatch directive to the whitelist.conf. Alternately, to whitelist a single rule for a single domain, you will need to use an include file for the domain. See below, or see Customize httpd.conf for setting up custom vhost includes.


Using CMC

CMC is Configserver's ModSec Control plugin for WHM. Its free, and makes whitelisting problem ModSec rules easy. It does require that all of the ModSec rule files be located in /usr/local/apache/conf/modsec* and/or are named beginning with the word "modsec" and that each rule has an ID number to identfy it. Thus it will not help with some of the "generic" rules (which don't have rule IDs) from our old modsec1 and 2 rpm's. For those you will want to either modify the modsec2.user.conf file and give the problem rule an ID, or use one of the other methods outlined below.

Download and install CMC

cd /usr/src
tar xvfz cmc.tgz
cd cmc

The plugin automagically adds these lines to /usr/local/apache/modsec2.user.conf at the top:

# ConfigServer ModSecurity whitelist file
Include /usr/local/apache/conf/modsec2.whitelist.conf

If you need to whitelist something, go to "WHM > Plugins > ConfigServer ModSec Control" - the interface is pretty self-explanatory. You'll need the ID number of the problem rule, and/or the domain having issues. It can also be used to turn ModSec on and off server wide, or on an account- or domain-level basis.


To whitelist a specific rule, you need to add an entry to the whitelist.conf.

In the following examples, the beginning / is the path as seen from the account's DocumentRoot (aka public_html directory on most cPanel servers).

So "/private/" will match all domains thusly:


The syntax is as follows:

<LocationMatch "/URI/From/Error">
  SecRuleRemoveById <rule id goes here>

The Id needs to be the Id listed in /usr/local/apache/conf/modsec2.user.conf.

You can also whitelist more than one rule, just separate them with a space

<LocationMatch "/private/">
  SecRuleRemoveById 950910 950013

You can also whitelist whole directories in the same manner.

<LocationMatch "/private/*">
  SecRuleRemoveById 950910 950013

You can get pretty specific with this, for example:

<LocationMatch "/index.php=?sdjkLhfasdj">

Below is a simple temporary function that allows for the user to plug in various values to create the modsec whitelisting rule, using the SecRuleRemoveById method.

addmswl () { uri=$1;ruleids="$3 $4 $5 $6 $7 $8 $9"; file=$2;echo Adding entry to $file; echo '<LocationMatch' \"$uri\"'>' >> $file; echo SecRuleRemoveById $ruleids >> $file; echo '</LocationMatch>' >> $file; }

After running the above, you can use the function during that terminal session in the following manner, calling the function by name, entering the uri to be whitelisted exactly as it is shown in the modsec error, listing the file to be used as the whitelist, and then up to 7 rule id's separated by spaces. Example of usage syntax shown below.

addmswl index.php /usr/local/apache/conf/modsec2/whitelist.conf 9990001 8836799

You can also turn off mod_security entirely for a specific URI:

SecRule REQUEST_URI  "/blog/wp-admin/async-upload.php" phase:1,nolog,allow,ctl:ruleEngine=Off 

Placing that in /usr/local/apache/conf/modsec2/whitelist.conf turns modsec off for any domain on the server with that in the url. DO NOT DO THIS FOR /index.php IN THE MAIN WHITELIST.

Whitelistling When Creating the Rule ID; Whitelisting a Flash Uploader

    credit goes to Alex Kwiecinski for the information

Error found when tail -f /usr/local/apache/logs/error_log

Shockwave Flash

ModSecurity: Access denied with code 406 (phase 2). Pattern match "^Shockwave Flash" at REQUEST_HEADERS:User-Agent. [file "/usr/local/apache/conf/modsec2.user.conf"] [line "203"] [hostname ""] [uri "/designonline/php/upload.php"] [unique_id "byevW0Wnsx4AAGyHtncAAAA-"]

1) In this example we have to ID the rule for Adobe Shockwave Flash.

    vim /usr/local/apache/conf/modsec2.user.conf

2) Search for 'Shockwave' Note you have to ID this rule to whitelist it.

3) Make the line with 'Shockwave' read: SecRule HTTP_User-Agent "^Shockwave Flash" "id:1000001"

    Note - all user created unique id errors are assigned numbers above 1000000.

4) Then edit /usr/local/apache/conf/modsec2/whitelist.conf to add the location match.

    Example below (in reference to the ModSec rule violation from the Apache error_log)
 <LocationMatch "/designonline/php/upload.php*">
   SecRuleRemoveById 1000001

5) Restart Apache - service httpd restart

Whitelist A Specific IP Address

To whitelist a single ip address (Customers IP address), use the following format :

 SecRule REMOTE_ADDR "^111\.222\.333\.444" phase:1,nolog,allow,ctl:ruleEngine=off

Where 111.222.333.444 is the IP address you'd like to whitelist.

Whitelist An Entire Domain

Template:Warning Template:Warning

It's best to do this through a userdata include on a cPanel server. Simply add this in:

/usr/local/apache/conf/userdata/(1 or 2)/std/user/domain/whitelist.conf

Continue the chain to completion. Then, create a conf and put in the rule to disable modsec. You could disable particular rules with this, or disable it entirely. You would use a rule like:

To exclude a domain from being filtered by modesec:
Hint: only change, leave SERVER_NAME as it is.

SecRule SERVER_NAME "" phase:1,nolog,allow,ctl:ruleEngine=Off

The same can be done with the ip, rather than the domain name:

SecRule SERVER_ADDR "^192\.168\.1\.100$" phase:1,nolog,allow,ctl:ruleEngine=Off

In general however, turning off Modsec on an entire domain or on an entire server is a bad idea on someone's server. And you can NOT do this on any of our shared servers.

Whitelist Rule(s) For Specific Domain(s)

Whitelisting rules for specific domains can be done using includes files. You could also use this method to do a locationmatch for only one domain.

  • *Note for sites that use SSL and Non-SSL, you'll have to do this in a couple of folders.*

First, back up and rebuild httpd.conf to make sure there are no errors;

cd /usr/local/apache/conf
cp -p httpd.conf httpd.conf.lwbak

[OUTPUT] Built /usr/local/apache/conf/httpd.conf OK

Now, we have to make an includes file, since cPanel doesn't like having httpd.conf edited directly. You can open up httpd.conf and look for the path where we need to make the file, or just issue a command like this one to find the line(s) we need:

egrep -i 'DOMAIN.TLD' /usr/local/apache/conf/httpd.conf |grep -i include

[OUTPUT] # Include "/usr/local/apache/conf/userdata/std/2/USERNAME/DOMAIN.TLD/*.conf"

It is ideal to register that account's includes with cPanel data; this will avoid loosing the include during updates to that account's vhost.

The ensure_vhost_includes and verify_vhost_includes scripts add and test this. Please see the below wiki's subsection for directions:

'Customize_httpd.conf' # 'Changes that ARE Contained in a <VirtualHost>'

Notice the line in the output is commented out. That's OK, because if we make an includes file at that location and rebuild httpd.conf again, it will uncomment that line for us. Note on newer servers, the above line may not be there at all. Make the file in the right location, and it should add it upon rebuild. So, time to make the folder, change to it, and make our includes file:

mkdir -p /usr/local/apache/conf/userdata/std/2/USERNAME/DOMAIN.TLD/
cd /usr/local/apache/conf/userdata/std/2/USERNAME/DOMAIN.TLD/ 
vim modsecexclude.conf

Note: Due to cPanel updates, this might not work. In this case, try:

mkdir -p /usr/local/apache/conf/userdata/std/2/USERNAME/
cd /usr/local/apache/conf/userdata/std/2/USERNAME/
vim modsecexclude.conf

For example, if your customer has a lot of forum and blogging software tripping these rules, put in the following to remove these rules site-wide:

<IfModule mod_security2.c>
  <LocationMatch .*>
    SecRuleRemoveById 300016
    SecRuleRemoveById 300013
    SecRuleRemoveById 300015
    SecRuleRemoveById 300017

BE SURE TO INCLUDE THE IFMODULE STATEMENTS. Not including it in these files can cause EA not to complete, as it can try to parse these files before realizing that modsec is compiled in.

Save and quit. Now to check our includes file and restart apache:

cd /usr/local/apache/conf
cat httpd.conf |egrep -i 'DOMAIN.TLD'|grep -i include

[OUTPUT] Include "/usr/local/apache/conf/userdata/std/2/USERNAME/DOMAIN.TLD/*.conf"

[notice the output has the line uncommented, and we can make anything.conf in that directory and have it work]

/etc/init.d/httpd restart

Make sure apache starts. If you made a mistake in an includes file, or manually uncommented the line in httpd.conf for the includes directory but did not make an includes file there, apache may not start.

Can't Find Rule ID

Some rules are 'generic' meaning that they aren't covered by a specific rule ID.

#SecFilterSignatureAction "msg:'Generic remote include Injection. group 1051'"
SecRule REQUEST_URI "\.php\?.*CONF_CONFIG_PATH=(http|https|ftp)\:\/"
SecRule REQUEST_URI "\.php\?.*xcart_dir=(http|https|ftp)\:\/"
SecRule REQUEST_URI "\.php\?.*cat=(http|https|ftp)\:\/"
SecRule REQUEST_URI "\.php\?.*admindir=(http|https|ftp)\:\/"
SecRule REQUEST_URI "\.php\?.*option=(http|https|ftp)\:\/"
SecRule REQUEST_URI "\.php\?.*mosConfig_live_site=(http|https|ftp)\:\/"
SecRule REQUEST_URI "\.php\?.*mainframe=(http|https|ftp)\:\/"
SecRule REQUEST_URI "\.php\?.*ROOTDIR=(http|https|ftp)\:\/"
SecRule REQUEST_URI "\.php\?.*Config_absolute_path=(http|https|ftp)\:\/"
SecRule REQUEST_URI "\.php\?.*CONFIG_EXT\[ADMIN_PATH\]=(http|https|ftp)\:\/"
SecRule REQUEST_URI "\.php\?.*area=(http|https|ftp)\:\/"
SecRule REQUEST_URI "\.php\?.*loc=(http|https|ftp)\:\/"
SecRule REQUEST_URI "\.php\?.*baseDir=(http|https|ftp)\:\/"
SecRule REQUEST_URI "\.php\?.*dialang=(http|https|ftp)\:\/"
SecRule REQUEST_URI "\.php\?.*config\[root_dir\]=(http|https|ftp)\:\/"
SecRule REQUEST_URI "\.php\?.*baseDir=(http|https|ftp)\:\/"
SecRule REQUEST_URI "\.php\?.*dialang=(http|https|ftp)\:\/"
SecRule REQUEST_URI "\.php\?.*config\[root_dir\]=(http|https|ftp)\:\/"

You can just add the rule ID to /etc/httpd/conf/modsec2.user.conf. For instance:

SecRule REQUEST_URI "\.php\?.*config\[root_dir\]=(http|https|ftp)\:\/"


SecRule REQUEST_URI "\.php\?.*config\[root_dir\]=(http|https|ftp)\:\/" "id:1001986"    

All user created unique id errors are assigned numbers above 1000000.

When creating a rule ID a good rule of thumb would be using the date, year first. So today is Apr 19 2012, the rule ID created would be 20120419 and if more than one needs to be created then 201204191, 201204192, etc.

Restart Apache. Just make sure you assign unique rule ID's. - The problem with this is that modsec2.user.conf will get overwritten when its updated. Its better to add whitelisting to custom.conf and/or whitelist.conf, as these are not modified.

Chain Rules Without ID's If you get an error when restarting apache that you cant put an ID on a chain, then you will need to add the chain into the quotes of the id, like so:

SecRule REQUEST_URI "!/mt\.cgi" "chain,id:1000001"

Another example:

 #Generic XSS filter
 #please report false positives
 SecRule REQUEST_URI "!/mt\.cgi" chain
 SecRule REQUEST_URI|REQUEST_BODY "<space:*(script|about|applet|activex|chrome)*>.*(script|about|applet|activex|chrome)space:*>, id:1000002"

Preferred method:

<LocationMatch "/private/path/to/script.php">
  SecRuleRemoveById RULEID


<LocationMatch "/private/path/to/script.php">
  SecRuleEngine Off

Be careful with this, as with whitelisting a domain it turns off ModSecurity for that script entirely, and may make it vulnerable to remote inclusion or SQL injection.
If a script is catching on one of these rules it is likely poorly coded.

WHM Whitelist Specific Rule Server Wide

To do this easily in WHM:

First, determine which rule it is catching...

Step 1: Find the page and error you need, copy the [id xxxxxx] code.

Step 2: In the WHM menu , "Apache Setup" (you can type apache in top search box to go faster)

Step 3: Select "Include Editor"

Step 4: Select "Pre Virtual Host Include" and "All Versions"

Step 5: Copy/Paste the similar configs and replace the mod sec rule ID number

Step 6: Update, then Restart Apache.

Step 7: Recheck problem... it might hit more rules after that one, they can be slightly similar.

Plesk White Listing

To do this you use the normal LocationMatch syntaxes but in a specific location

Step 1: Find the rule in the vhost error_log file /var/www/vhosts/<domain name>/statistics/logs/error_log

Step 2: In /var/www/vhosts/<domain name>/conf see if a vhost.conf file exists

  1. If it does Append to it
  2. If it doesn't create it

Step 3: Add the normal mod security white listing syntax as shown below in this wiki in the vhost.conf file. You may need to add extra lines:

 <LocationMatch ".*">
   <IfModule mod_security2.c>
    SecRuleRemoveById 970901

Step 4: Run The command /usr/local/psa/admin/sbin/websrvmng -u --vhost-name=<domain name>

(This command may give an error that it is obsoleted...if so, use the following...) ( /usr/local/psa/admin/sbin/httpdmng --reconfigure-domain <domain_name> )

Step 5: Restart Apache on the server

Step 6: Check your work

Global way on Plesk

Just like on a cPanel server edit the whitelist.conf here:


Other files also exist in this same location for say adding a rule ID for shockwave flash and are similar to that of those on a cPanel server:



If the ModSec error is happening on a subdomain in Plesk you will need to add the vhost.conf file to the following location:


Add the vhost.conf file to that folder like normal, and enter the standard whitelisting. Then, it's helpful to run the Plesk rebuild command for both the domain and the subdomain as follows:

 /usr/local/psa/admin/sbin/websrvmng -u
 /usr/local/psa/admin/sbin/websrvmng -u


ModSecParse in WHM makes this unnecessary, however if you need to get a look at what is in the current audit log without waiting for it to be parsed this is useful.

To list all sites that have mod sec errors and the rule number and location:

echo;printf "hostname                         ruleid  uri\n";echo;\
IFS=$'\n';for i in $(cat /usr/local/apache/logs/error_log |grep -i modsecurity|grep -e '\[id\ ');\
do id=$(echo -n $i | sed 's/^.*\[id\ "//g' | sed 's/".*$//'); host=$(echo -n $i | sed 's/^.*\[hostname\ "//g' | sed 's/".*$//');\
loc=$(echo -n $i | sed 's/^.*\[uri\ "//g' | sed 's/".*$//');printf "%-30s%9s%2s%-29s\n" $host $id "  " $loc;done;IFS=$' '

You can also output to a report for sorting:

IFS=$'\n';for i in $(cat /usr/local/apache/logs/error_log |grep -i modsecurity|grep -e '\[id\ ');\
do id=$(echo -n $i | sed 's/^.*\[id\ "//g' | sed 's/".*$//'); host=$(echo -n $i | sed 's/^.*\[hostname\ "//g' | sed 's/".*$//');\
loc=$(echo -n $i | sed 's/^.*\[uri\ "//g' | sed 's/".*$//');printf "%-30s%9s%2s%-29s\n" $host $id "  " $loc >> modsecrep.txt;done;IFS=$' '

The you can sort it out

cat modsecrep.txt | sort | uniq -c | sort -nr


cat modsecrep.txt | grep | sort | uniq -c | sort -nr


(Edit eammons 06-01-2009 - I'm not sure who originally added this to the wiki. I run wordpress 2.7.1 on my personal site along with Modsec2/Apache2 with SuPhp and open_basedir protection on. I've never had to whitelist anything to get posting to work with wordpress. If support is getting issues like these, secteam needs to be notified. Thank you!)


There seems to be some bugs with Apache 2 WordPress and mod_security2 playing nicely with each other. After much research I have found the fix.

Add the following line to the httpd.conf file at the end of the <VirtualHost> entry for the domain

SecRuleInheritance Off

So it should read something like this

<VirtualHost IP:80>

SecRuleInheritance Off

Don't forget to do this to any SSL enabled sites as well in the <VirtualHost IP:443> entry as well. Otherwise it won't work for the site when in SSL mode.

After all that is added run the following to make the changes permanent:

/usr/local/cpanel/bin/apache_conf_distiller --update
/etc/init.d/httpd restart

PCRE Limits Exceeded

PCRE limits prevent Modsec RegExs from being exploited in the form of a ReDoS


If you see a lot of these errors, you may need to increase the recursion limit to allow our ruleset to work properly.

Add these two options to php.ini:

pcre.backtrack_limit = 10000000
pcre.recursion_limit = 10000000

Then, add these two directives right under the first line of /usr/local/apache/conf/modsec2.user.conf

SecPcreMatchLimit 150000
SecPcreMatchLimitRecursion 150000

Restart apache, and you're done.

Request body (Content-Length) is larger than the configured limit

When trying to upload a large file, a customer may get this error:

[Wed Oct 13 19:48:02 2010] [error] [client] ModSecurity: Request body (Content-Length) is larger than the configured limit (134217728). [hostname ""] [uri "/upload/ft2.php"] [unique_id "TLZFMkUQ5mIAAEa0PiAAAAAB"]

Theoretically a locationmatch with "SecRequestBodyLimit 0" or "SecRuleEngine Off" should fix this, however I've found at times it does not. To fix the above error put this into whitelist.conf, replacing only the /upload/ft2.php with the appropriate path:

SecRule REQUEST_FILENAME "^/upload/ft2.php$" "phase:1,t:none,allow,nolog,ctl:requestBodyAccess=Off"

You can also just set "SecRequestBodyLimit 1047483647" in modsec2.user.conf to set it to the max hard limit of 1GB. Not the most recommend solution, but it will work.

Modsec Database Issues

If you encounter an error that looks something like this from your cron.daily:

DBI connect('modsec:localhost','modsec',...) failed: Access denied for user 'modsec'@'localhost' (using password: YES) at /etc/cron.hourly/ line 19 Unable to connect to mysql database at /etc/cron.hourly/ line 19.

Look to see what the modsec user's password is in this file first:


Then open up PHPmyadmin from WHM (as root), go to the privileges tab, click M for modsec and "edit privileges" for the modsec user. From here, go down to the New Password area, enter it twice and click Go!

The mysql syntax for this is:

 SET PASSWORD FOR 'modsec'@'localhost' = PASSWORD( '************' );

run this to confirm working, no errors will show if all is well:

 perl /etc/cron.hourly/

Upload tmpdir issues

Seeing this?

<source lang='php'> [Fri Nov 18 14:49:50 2011] [error] [client] mod_security: Access denied with code 406. read_post_payload: Failed to create file "/root/tmp/20111118-144950-" because 13("Permission denied") [severity "EMERGENCY"] [hostname ""] [uri "/wp-cron.php?doing_wp_cron"] [unique_id "TsbhJkg0jtcAACYIFDk"] </source>

This actually happens because PHP's being set to use /root/tmp and the upload tmp dir. Let's set a few things then! Yay!

Make sure these are all set in /usr/local/lib/php.ini (session.save_path will probably already be set)

upload_tmp_dir = /tmp
session.save_path = /tmp

Make sure these are all set in /usr/local/apache/conf/modsec2.user.conf (or the applicable file for your system)

SecUploadDir /tmp
SecTmpDir /tmp

Restart the apachies.

It also seems it has worked adding the above to modsec.conf corrects this issue. per ~awilson


Turtle Rules


To install Turtle rules, see

This is not much different than a modsec whitelisting. You will find an error as normal in the apache error_log like the following:

[Thu Jan 20 09:53:57 2011] [error] [client] ModSecurity: Access denied with code 403 (phase 2). Pattern match "(< ?(?:(?:java|vb)?script|about|applet|activex|chrome) ?>|> ?< ?(img ?src|a ?href) ?= ?(ht|f)tps?:/|" ?> ?<|" ?[a-z]+ ?<.*>|> ?"? ?(>|<)|< ?/?i?frame|\\%env)" at ARGS:_qf_Settings_next. [file "/usr/local/apache/conf/turtle-rules/modsec/10_asl_rules.conf"] [line "903"] [id "340147"] [rev "81"] [msg " - FREE UNSUPPORTED DELAYED FEED - WAF Rules: Generic XSS filter"] [data "189"] [severity "CRITICAL"] [hostname ""] [uri "/civicrm/mailing/send"] [unique_id "TThMhUWnkgUAAHTaKlEAAAGV"]

The error tells you where the turtle rules are located: /usr/local/apache/conf/turtle-rules/modsec/

This is where you will find both the rules (10_asl_rules.conf) as well as the whitelist


Whitelisting works the same for this as it does for a regular modsec whitelisting.

Disable Mod_security on a global URL


Step 1) Create a global exclude file

vim /usr/local/apache/conf/modsec/00_asl_custom_exclude.conf

Step 2) Add the LocationMatch for the url to exclude. Example: /server.php

<LocationMatch /server.php>
  <IfModule mod_security2.c>
    SecRuleEngine Off 

Step 3) Restart apache

service httpd restart


Given the almost constant issues one will see with a newer server without whitelisting in regards to wordpress (can't post/edit a message using the words from, select, record and so on, or upload using the flash uploader within wordpress) Below is a very good set of rules that should fix most default wordpress issues with modsec.

For posting/editing issues:

<LocationMatch "/wp-admin/page.php">
SecRuleRemoveById 300013 300014 300015 300016 300017
<LocationMatch "/wp-admin/post.php">
SecRuleRemoveById 300013 300014 300015 300016 300017
<LocationMatch "/wp-admin/admin-ajax.php">
SecRuleRemoveById 300013 300014 300015 300016 300017

Or you can use the following:

<LocationMatch "/wp-admin/(post|admin-ajax|page).php">
SecRuleRemoveById 300013 300014 300015 300016 300017

For uploading issues:

SecRule REQUEST_URI  "/wp-admin/async-upload.php" phase:1,nolog,allow,ctl:ruleEngine=Off
SecRule REQUEST_URI  "/wp-admin/async-upload.php" phase:2,nolog,allow,ctl:ruleEngine=Off

If the customer is having way too many issues, do check with them that they have a strong wp-admin password. If so, one could, with proper respect paid to security, use this rather heavy-handed method (don't be a jerkstore and use this first!):

SecRule REQUEST_URI  "/wp-admin/" phase:1,nolog,allow,ctl:ruleEngine=Off
SecRule REQUEST_URI  "/wp-admin/" phase:2,nolog,allow,ctl:ruleEngine=Off

The above should whitelist ALL of the wp-admin area. It is password protected, and as long as it is a strong and safe username/password, it 'should' be alright. Use judgement.

Add these rules to the default whitelist location which is typically:


Save, and restart apache afterwards to make the rules go into effect.

Now, as stated, this is for posting/editing/upload issues. Do your due diligence and check the apache error logs to make sure these rules do relate to the issue, (the path might be in a sub-directory, for instance, thus the URI could have /blog/ before wp-admin. Or, could be Theme related, to which most of these rules will not apply to) then whitelist accordingly:

cat /usr/local/apache/logs/error_log | grep -i modsec


modsec db missing

Problem: Cpanel didn't create the modsec database, and there was an error in the WHM > Mod Security section.

You can manually create the database and user, the settings are in this file:


This might be able to be fixed by upcp or perhaps running EA also, probably would be the more elegant solution. This isn't necessary for modsecurity to function at all.

Whitelisting Common WordPress Mod Sec Errors

Open the file /usr/local/apache/conf/modsec2/whitelist.conf

Add the following:

<LocationMatch "/wp-admin/post.php">
SecRuleRemoveById 300015 300016 300017
<LocationMatch "/wp-admin/admin-ajax.php">
SecRuleRemoveById 300015 300016 300017
<LocationMatch "/wp-admin/page.php">
SecRuleRemoveById 300015 300016 300017

Restart apache

Memory limit per connection

grep memory_limit /usr/local/lib/php.ini

Whitelisting Wordpress

Commonly wordpress sites have modsec issues here as an example of how to shut off modsec for a certain area or site in wordpress

SecRule REQUEST_URI "/wp/wp-admin/admin-ajax.php"
in /usr/local/apache/conf/modsec2/whitelist.conf