Part 3 – Defining Proper Exceptions for WordPress
After successfully integrating and testing ModSecurity with the OWASP Core Rule Set (CRS), you’ll quickly run into a common issue when using dynamic applications like WordPress: false positives — legitimate requests incorrectly classified as attacks and blocked.
WordPress uses modern features like the REST API, AJAX, dynamic block editors (Gutenberg), and sometimes specific HTML comments. These mechanisms often trigger security rules when CRS is active — particularly in the areas of XSS, LFI, or anomaly detection. To ensure that these protections don’t interfere with the admin interface, we need to define targeted rule exceptions for WordPress.
How to Properly Configure WordPress Exceptions
To ensure these exceptions apply only to WordPress sites, we place them in a separate file and include it specifically in the nginx.conf
or the corresponding VirtualHost configuration.
1. Create the Exception File
Create (or edit) the following file:
sudo nano /etc/nginx/modsec/wp-admin-exceptions.conf
And insert the following rules:
# WordPress-specific ModSecurity exceptions to reduce false positives
# Disable ModSecurity for admin/editor and REST API requests (to reduce false positives and speed up backend)
SecRule REQUEST_URI "@rx ^/(wp-admin|wp-json|wp-includes|wp-content|wp-cron\.php)" \
"id:1000990,phase:1,pass,nolog,noauditlog,ctl:auditEngine=Off,ctl:requestBodyAccess=Off"
# Global rule to disable audit logging for all WordPress requests
SecRule REQUEST_URI "@rx ^/wp-(admin|json|includes|content)" "id:1001000,phase:1,pass,nolog,noauditlog,ctl:auditEngine=Off"
# Allow REST API (used by Gutenberg and AJAX calls)
SecRule REQUEST_URI "@beginsWith /wp-json/" "id:1001001,phase:1,pass,nolog,noauditlog,ctl:auditEngine=Off,\
ctl:ruleRemoveById=941180,\
ctl:ruleRemoveById=920450,\
ctl:ruleRemoveById=949110,\
ctl:ruleRemoveById=920100,\
ctl:ruleRemoveById=200005,\
ctl:ruleRemoveById=920540,\
ctl:ruleRemoveById=942100,\
ctl:ruleRemoveById=941100,\
ctl:ruleRemoveById=930100,\
ctl:ruleRemoveById=930130,\
ctl:ruleRemoveById=932250"
# Allow wp-admin (editor, dashboard, media, etc.)
SecRule REQUEST_URI "@beginsWith /wp-admin/" "id:1001002,phase:1,pass,nolog,noauditlog,ctl:auditEngine=Off,\
msg:'WordPress REST API Exception',\
ctl:ruleRemoveById=941180,\
ctl:ruleRemoveById=920450,\
ctl:ruleRemoveById=949110,\
ctl:ruleRemoveById=920100,\
ctl:ruleRemoveById=200005,\
ctl:ruleRemoveById=920540,\
ctl:ruleRemoveById=942100,\
ctl:ruleRemoveById=941100,\
ctl:ruleRemoveById=930100,\
ctl:ruleRemoveById=930130,\
ctl:ruleRemoveById=932250"
# Allow HTML comments used by Gutenberg (e.g., <!-- wp:paragraph -->)
SecRule REQUEST_BODY "@rx <!--\s?wp:" "id:1001003,phase:2,pass,nolog,noauditlog,ctl:auditEngine=Off,ctl:ruleRemoveById=941180"
# Optional: Additional CRS rules often triggered by WordPress activity (expand as needed)
SecRuleRemoveById 950901
SecRuleRemoveById 953100
SecRuleRemoveById 958030
SecRuleRemoveById 958057
SecRuleRemoveById 960015
SecRuleRemoveById 973300
SecRuleRemoveById 973333
SecRuleRemoveById 973335
SecRuleRemoveById 973337
SecRuleRemoveById 973340
SecRuleRemoveById 973343
SecRuleRemoveById 981173
SecRuleRemoveById 981176
SecRuleRemoveById 981204
SecRuleRemoveById 981240
SecRuleRemoveById 981243
SecRuleRemoveById 981245
SecRuleRemoveById 981246
SecRuleRemoveById 981248
SecRuleRemoveById 981257
These exceptions only remove specific problematic rules for /wp-admin/
and /wp-json/
without disabling the entire WAF.
2. Include the File in NGINX
Open the server configuration file for your WordPress site (e.g., /etc/nginx/sites-enabled/example.com.conf
) and add the ModSecurity block inside the HTTPS server block as shown:
modsecurity on;
modsecurity_rules_file /etc/nginx/modsec/modsecurity.conf;
modsecurity_rules_file /etc/nginx/modsec/wp-admin-exceptions.conf;
3. Test Configuration and Reload NGINX
Use the following command to test your NGINX configuration and reload the web server if successful:
sudo nginx -t && sudo systemctl reload nginx
Result
With this configuration, ModSecurity reliably protects your WordPress site using the OWASP Core Rule Set — without blocking the admin area or the REST API. At the same time, it avoids disabling entire rule groups and preserves full control over critical security checks.
Leave a Reply
You must be logged in to post a comment.