Wazuh 4.14 Detection Rules - Syntax and Logic
Wazuh rules define the threat detection logic: which events are security-relevant, what severity level to assign, and what metadata to attach to the alert. Each rule is described in XML and contains trigger conditions, a description, and a classification. This guide provides a detailed look at rule syntax, the severity level system, composite rules, and testing tools.
XML Rule Structure
Every rule is enclosed in a <rule> element within a <group> container:
<group name="syslog,sshd,">
<rule id="100001" level="5">
<decoded_as>sshd</decoded_as>
<match>Failed password</match>
<description>SSH authentication failure.</description>
<mitre>
<id>T1110</id>
</mitre>
<group>authentication_failed,pci_dss_10.2.4,</group>
</rule>
</group>Rule Element Attributes
| Attribute | Required | Description |
|---|---|---|
id | Yes | Unique numeric identifier (1-999999) |
level | Yes | Alert severity level (0-15) |
frequency | No | Number of matches required to trigger |
timeframe | No | Time window in seconds for frequency |
ignore | No | Suppression duration for repeated alerts (seconds) |
maxsize | No | Maximum event size |
noalert | No | If 1, the rule triggers without generating an alert |
overwrite | No | If yes, overwrites the rule with the same id |
Trigger Condition Elements
Content Matching
match - searches for a substring or pattern in the log body:
<match>Failed password</match>Supports negate="yes" (inversion) and type (osmatch, osregex, pcre2) attributes:
<match type="pcre2" negate="yes">successful|accepted</match>regex - searches using a regular expression:
<regex>Failed password for (\S+) from (\S+)</regex>decoded_as - triggers when the event matches a specific decoder:
<decoded_as>sshd</decoded_as>category - triggers by decoder category:
<category>firewall</category>Extracted Field Matching
field - checks the value of a field extracted by a decoder:
<field name="log_type">error</field>srcip / dstip - matches source or destination IP (supports CIDR notation):
<srcip>192.168.1.0/24</srcip>
<srcip negate="yes">10.0.0.0/8</srcip>srcport / dstport - source or destination port:
<dstport>22</dstport>user - username:
<user>root</user>hostname - source hostname:
<hostname>web-server-01</hostname>program_name - program name from the syslog header:
<program_name>sshd</program_name>action - action extracted by the decoder:
<action>blocked</action>status - event status:
<status>403</status>url - URL from the event:
<url type="pcre2">/admin|/wp-login\.php</url>protocol - transport protocol:
<protocol>TCP</protocol>Time Filters
time - time-of-day range (format hh:mm-hh:mm):
<time>22:00-06:00</time>weekday - day of the week:
<weekday>weekend</weekday>Metadata and Description
description - human-readable rule description (required):
<description>Multiple SSH authentication failures from same source.</description>info - supplementary information:
<info type="link">https://attack.mitre.org/techniques/T1110/</info>
<info type="text">Possible brute force attack detected.</info>group - tags for grouping and filtering (comma-separated, trailing comma required):
<group>authentication_failed,brute_force,pci_dss_10.2.4,</group>mitre - MITRE ATT&CK technique mapping:
<mitre>
<id>T1110</id>
<id>T1078</id>
</mitre>options - additional behavioral flags:
<options>no_log</options>
<options>alert_by_email</options>Rule Classification Levels (0-15)
Wazuh uses 16 severity levels. Assigning the correct level is critical for alert prioritization.
| Level | Title | Description |
|---|---|---|
| 0 | Ignored | Event is ignored, no alert generated. Used to suppress false positives |
| 2 | System low priority notification | Status messages with no security significance |
| 3 | Successful/Authorized events | Legitimate actions such as successful logins or firewall permits |
| 4 | System low priority error | Configuration issues, minor system problems |
| 5 | User generated error | Authentication errors (failed login, wrong password) |
| 6 | Low relevance attack | Ineffective attacks, frequent IDS triggers with no real threat |
| 7 | Bad word matching | Events containing suspicious keywords but lacking clear classification |
| 8 | First time seen | Action performed for the first time (first login, new process) |
| 9 | Error from invalid source | Actions from unknown or suspicious sources |
| 10 | Multiple user generated errors | Repeated authentication failures (possible brute-force attack) |
| 11 | Integrity checking warning | Binary modifications, rootkit detection |
| 12 | High importance event | Critical system warnings, application-level attacks |
| 13 | Unusual error (high importance) | Patterns matching common attack methodologies |
| 14 | High importance security event | Correlation-driven alerts, probable attacks |
| 15 | Severe attack | Confirmed attack, immediate response required. No chance of false positives |
Rules at level 12 and above trigger real-time notifications (when alert integrations are configured).
Rule Ordering and Overwriting
Load Order
Wazuh loads rules in the following order:
- Default rules from
/var/ossec/ruleset/rules/(in alphabetical file order) - Custom rules from
/var/ossec/etc/rules/(includinglocal_rules.xml)
Custom rules are processed after default rules and can override them.
Overwriting Default Rules
To modify the behavior of a default rule, use the overwrite attribute:
<!-- Overwrite default rule 5710 (change the level) -->
<rule id="5710" level="10" overwrite="yes">
<decoded_as>sshd</decoded_as>
<match>illegal user|invalid user</match>
<description>SSH: attempt to login using a non-existent user.</description>
<mitre>
<id>T1110.001</id>
</mitre>
<group>authentication_failed,pci_dss_10.2.4,</group>
</rule>An overwritten rule must contain the complete definition, not just the changed fields.
Suppressing False Positives
To suppress a false positive, create a child rule with level 0:
<rule id="100100" level="0">
<if_sid>5710</if_sid>
<srcip>10.0.0.50</srcip>
<description>Suppress SSH invalid user alert from monitoring system.</description>
</rule>Composite Rules (Correlation)
Composite rules detect patterns based on event sequences or frequencies.
Parent Rule Linkage (if_sid)
if_sid - the rule triggers only if the specified rule has already fired:
<rule id="100010" level="10">
<if_sid>5710</if_sid>
<same_source_ip />
<description>Multiple SSH invalid user attempts from same source.</description>
</rule>if_group - triggers on group membership:
<rule id="100011" level="8">
<if_group>authentication_failed</if_group>
<match>root</match>
<description>Authentication failure for root account.</description>
</rule>if_level - triggers based on the level of a preceding event:
<rule id="100012" level="12">
<if_level>10</if_level>
<same_source_ip />
<description>High severity event followed by another from same source.</description>
</rule>Frequency Rules (frequency + timeframe)
if_matched_sid - triggers when the specified rule fires frequency times within timeframe seconds:
<rule id="100020" level="10" frequency="5" timeframe="120">
<if_matched_sid>5710</if_matched_sid>
<same_source_ip />
<description>SSH brute force: 5 invalid user attempts in 2 minutes.</description>
<mitre>
<id>T1110.001</id>
</mitre>
<group>brute_force,pci_dss_11.4,</group>
</rule>if_matched_group - same concept, but by rule group:
<rule id="100021" level="10" frequency="8" timeframe="300">
<if_matched_group>authentication_failed</if_matched_group>
<same_source_ip />
<description>Multiple authentication failures from same IP in 5 minutes.</description>
</rule>Field Correlation Elements
| Element | Description |
|---|---|
<same_source_ip /> | Source IP matches across correlated events |
<different_source_ip /> | Source IP differs |
<same_dst_ip /> | Destination IP matches |
<different_dst_ip /> | Destination IP differs |
<same_user /> | Username matches |
<different_user /> | Username differs |
<same_id /> | Identifier matches |
<same_location /> | Log source matches |
<same_protocol /> | Protocol matches |
<different_protocol /> | Protocol differs |
CDB Lists (Constant Database)
CDB lists enable field value lookups against external reference tables (IP lists, IoCs, allowed processes).
List Format
A list file contains key:value pairs (the value is optional):
192.168.1.100:known_scanner
10.0.0.50:monitoring_system
172.16.0.0/12:Usage in Rules
<rule id="100030" level="12">
<if_sid>5710</if_sid>
<list field="srcip" lookup="address_match_key">etc/lists/malicious-ips</list>
<description>SSH login attempt from known malicious IP.</description>
</rule>Lookup types:
| Type | Description |
|---|---|
match_key | Exact key match |
not_match_key | Key is absent from the list |
address_match_key | IP address match (with CIDR support) |
not_address_match_key | IP address is absent from the list |
match_key_value | Key and value match |
Registering Lists
Lists must be registered in ossec.conf:
<ruleset>
<list>etc/lists/malicious-ips</list>
</ruleset>After adding or modifying a list, reload the manager:
/var/ossec/bin/wazuh-control reloadDefault Ruleset Overview
Default Wazuh rules are organized by category into separate files.
| File | Category | Example Rules |
|---|---|---|
0015-ossec_rules.xml | Wazuh internal | Agent status, manager errors |
0095-sshd_rules.xml | SSH | Authentication, brute force, invalid user |
0100-syslog_rules.xml | Syslog | Linux system events |
0200-attack_rules.xml | Attacks | Common attack detection |
0210-pam_rules.xml | PAM | PAM authentication |
0230-postfix_rules.xml | Postfix mail server | |
0240-apache_rules.xml | Apache | Apache web server |
0250-nginx_rules.xml | Nginx | Nginx web server |
0350-amazon_rules.xml | AWS | CloudTrail, GuardDuty |
0470-windows_rules.xml | Windows | Windows Event Log |
0575-win-firewall_rules.xml | Windows Firewall | Windows Defender Firewall |
0620-win-security_rules.xml | Windows Security | Windows security auditing |
0800-sysmon_rules.xml | Sysmon | Windows process monitoring |
0840-docker_rules.xml | Docker | Container events |
A complete listing of rule files is available in /var/ossec/ruleset/rules/.
MITRE ATT&CK Mapping
Wazuh supports mapping rules to MITRE ATT&CK techniques and tactics, enabling ATT&CK matrix coverage visualization in the Dashboard.
<rule id="100050" level="12">
<if_sid>5710</if_sid>
<frequency>10</frequency>
<timeframe>60</timeframe>
<same_source_ip />
<description>SSH brute force attack detected.</description>
<mitre>
<id>T1110.001</id> <!-- Brute Force: Password Guessing -->
</mitre>
</rule>Technique identifiers must be verified against the official MITRE ATT&CK matrix .
Compliance Standard Groups
Rules may include tags that map to regulatory standards:
<group>pci_dss_10.2.4,gdpr_IV_32.2,hipaa_164.312.b,nist_800_53_AU.14,tsc_CC6.1,</group>Testing Rules with wazuh-logtest
The wazuh-logtest utility enables interactive rule testing.
Interactive Mode
/var/ossec/bin/wazuh-logtestEnter a log line and receive the analysis result:
Type one log per line
Mar 5 10:15:01 server sshd[12345]: Failed password for invalid user admin from 192.168.1.100 port 22 ssh2
**Phase 1: Completed pre-decoding.
full event: 'Mar 5 10:15:01 server sshd[12345]: Failed password for invalid user admin from 192.168.1.100 port 22 ssh2'
timestamp: 'Mar 5 10:15:01'
hostname: 'server'
program_name: 'sshd'
**Phase 2: Completed decoding.
name: 'sshd'
parent: 'sshd'
srcip: '192.168.1.100'
srcport: '22'
srcuser: 'admin'
**Phase 3: Completed filtering (rules).
id: '5710'
level: '5'
description: 'sshd: Attempt to login using a non-existent user.'
groups: '['syslog', 'sshd', 'invalid_login', 'authentication_failed']'Batch Mode
To test a set of logs from a file:
cat test-logs.txt | /var/ossec/bin/wazuh-logtest -qVerifying a Specific Rule
To confirm that a specific rule triggers on a specific log, use the -U flag:
echo "test log line" | /var/ossec/bin/wazuh-logtest -U 100001:5:sshdThe command returns exit code 0 if the rule with id=100001, level=5, and decoder sshd fired.
Verbose Output
For debugging, use the -v flag:
/var/ossec/bin/wazuh-logtest -vRule ID Ranges
When creating custom rules, use identifiers in the 100000-999999 range to avoid conflicts with default rules.
| Range | Purpose |
|---|---|
| 100000-109999 | General security detections |
| 110000-119999 | Application-specific rules |
| 120000-129999 | AI/ML pipeline monitoring |
| 147000-147999 | File integrity and YARA |
| 191000-191999 | Privilege escalation |
Rule Authoring Checklist
When creating a new rule, verify that all items are addressed:
- Rule identifier (
id) is within the correct range - Level (
level) matches the event severity - Description (
description) is clear and actionable - MITRE ATT&CK mapping (
mitre/id) is specified and verified - The decoder extracts the required fields before the rule fires
- The rule has been tested with
wazuh-logtest - No catastrophic backtracking risk in regular expressions
- Group tags (
group) are populated and end with a comma
Related Sections
- Wazuh Decoders - log data extraction
- Log Analysis - log collection and processing
- Active Response - actions triggered by rules
- Troubleshooting - diagnosing rule issues