Files
wazuh/configs/RULES.md
T
2026-07-31 16:44:09 +00:00

14 KiB

Custom Rules Reference

Detailed reference for every rule in local_rules.xml, organized by service. Includes rule purpose, dependencies, and expected firing behavior.

Table of contents


SSH

100001 - SSH failed auth from specific IP (example)

<rule id="100001" level="5">
    <if_sid>5716</if_sid>
    <srcip>1.1.1.1</srcip>
    <description>sshd: authentication failed from IP 1.1.1.1.</description>
    <group>authentication_failed,pci_dss_10.2.4,pci_dss_10.2.5,</group>
</rule>

Example rule inherited from the Wazuh default local_rules.xml. Fires when shipped rule 5716 (SSH auth failure) matches AND source IP is exactly 1.1.1.1. Placeholder; replace or delete when the SSH ruleset is actually built out.


pfSense

Note: rule IDs 87699, 87761, 87762 are below the standard user range (100000+). These override or extend Wazuh's shipped pfSense correlation to work with the wrapped log format arriving from the homelab pfSense box.

87699 - pfSense wrapped parent (bridge rule)

<rule id="87699" level="0">
    <decoded_as>pfsense-wrapped</decoded_as>
    <description>pfSense wrapped syslog parent rule.</description>
</rule>

Level 0 (no alert). Exists so downstream rules can chain off if_sid>87699</if_sid> and get evaluated against wrapped pfSense logs.

87761 - pfSense firewall drop event

<rule id="87761" level="5">
    <if_sid>87699</if_sid>
    <action>block</action>
    <description>pfSense firewall drop event (wrapped).</description>
    <group>pfsense,firewall_block,...</group>
</rule>

Level 5. Fires on any pfSense firewall block action. Sets up correlation for 87762.

87762 - Multiple pfSense blocks from same source

<rule id="87762" level="10" frequency="18" timeframe="45" ignore="240">
    <if_matched_sid>87761</if_matched_sid>
    <same_srcip />
    <description>Multiple pfSense firewall block events from same source (wrapped).</description>
    <mitre><id>T1110</id></mitre>
    <group>pfsense,</group>
</rule>

Level 10. Fires when 18 firewall drops from the same source IP occur within 45 seconds. ignore="240" prevents re-firing on the same source for 240 seconds after triggering. Mapped to MITRE T1110 (brute force).


Reputation / attack lookups

100100 - AlienVault reputation match

<rule id="100100" level="10">
    <if_group>web|attack|attacks</if_group>
    <list field="srcip" lookup="address_match_key">etc/lists/blacklist-alienvault</list>
    <description>IP address found in AlienVault reputation database.</description>
</rule>

Level 10. Fires when any web-related or attack-tagged event has a source IP that matches the AlienVault OTX blacklist CDB. Requires the AlienVault list to be maintained and rebuilt periodically via wazuh-makelists.


Dovecot: suppression and recon

Rules 100200-100206 handle Dovecot-related events. Most are level 0 suppressions for expected internal traffic; 100205/100206 detect port scanning against IMAP.

100200 - Suppress mailcow watchdog auth attempts

<rule id="100200" level="0">
    <if_sid>9705</if_sid>
    <match>watchdog@invalid</match>
    <description>Dovecot: mailcow watchdog health check (ignored)</description>
</rule>

Mailcow's internal watchdog attempts to auth as watchdog@invalid to verify Dovecot is responsive. This suppresses those alerts.

100201 - Suppress internal Docker IMAP probes

<rule id="100201" level="0">
    <if_sid>9707</if_sid>
    <match>rip=172.22.1.</match>
    <description>Dovecot: mailcow watchdog IMAP probe disconnect (ignored)</description>
</rule>

Suppresses disconnect events originating from the mailcow Docker network (172.22.1.x). These are watchdog probes and inter-container health checks.

100202 - Suppress own-mailbox routine disconnects

<rule id="100202" level="0">
    <if_sid>9706</if_sid>
    <match>imap(chris@wittenberger.us)</match>
    <description>Dovecot: own-mailbox routine session disconnect (ignored)</description>
</rule>

Suppresses routine IMAP session disconnects for the administrator's own mailbox. Prevents noise from Chris's own mail clients.

100203 - Suppress managesieve health checks

<rule id="100203" level="0">
    <if_sid>9706</if_sid>
    <match>managesieve-login: Disconnected: Connection closed (no auth attempts</match>
    <description>Mailcow watchdog managesieve healthcheck - suppressed</description>
</rule>

Suppresses managesieve-login disconnects that occur without auth attempts. These are internal health checks against the sieve rules service.

100205 - No-auth disconnect primitive

<rule id="100205" level="0">
    <if_sid>9700</if_sid>
    <match>no auth attempts</match>
    <description>Dovecot: connection with no auth attempt from $(srcip)</description>
    <group>dovecot,recon,</group>
</rule>

Level 0 primitive rule. Fires on Dovecot disconnects where the client never attempted authentication. This is a port scan or reconnaissance signature. Level 0 keeps individual events from alerting; correlation happens in 100206.

100206 - Aggressive port scanning correlation

<rule id="100206" level="8" frequency="20" timeframe="300">
    <if_matched_sid>100205</if_matched_sid>
    <same_srcip />
    <description>Dovecot: aggressive port scanning from $(srcip) - possible attack precursor</description>
    <group>dovecot,recon,attack,</group>
</rule>

Level 8. Fires when a single IP triggers 20 no-auth-disconnect events within 5 minutes. Distinguishes legitimate one-off scanners (Shodan, Censys, Onyphe) from aggressive reconnaissance that typically precedes actual attacks.


Dovecot: successful login primitive

100204 - Successful Dovecot login (suppressed for alerting)

<rule id="100204" level="0" overwrite="no">
    <if_sid>9701</if_sid>
    <description>Dovecot successful login - suppressed (routine IMAP polling)</description>
</rule>

Level 0. Fires on any successful Dovecot login (matches shipped rule 9701). Suppressed from alerting because successful logins are constant background traffic. Critically, this rule STILL FIRES INTERNALLY when 9701 matches, which is what rule 100311 needs for compromise correlation.

Do not delete this rule. Rule 100311 references it via if_sid>100204</if_sid>. Removing it breaks the compromise correlation chain.


Gitea

Rules 100400-100470 cover Gitea authentication, account lifecycle, SSH key management, and repository events.

100400 - Gitea event parent

<rule id="100400" level="0">
    <decoded_as>gitea</decoded_as>
    <description>Gitea event (parent)</description>
</rule>

Level 0. Gates all Gitea-specific child rules. Fires on any event decoded by the gitea decoder.

100401, 100402 - Router polling / HTTP request suppression

Suppress Gitea's high-volume "router polling" and "router completed" HTTP request logs. These are routine background traffic and would flood the alert log.

100410 - Failed Gitea auth

<rule id="100410" level="5">
    <if_sid>100400</if_sid>
    <match>Failed authentication attempt</match>
    <description>Gitea: failed authentication attempt</description>
    <mitre><id>T1110</id></mitre>
</rule>

Level 5. Fires on individual failed Gitea login attempts.

100411 - Gitea brute force

<rule id="100411" level="10" frequency="5" timeframe="120">
    <if_matched_sid>100410</if_matched_sid>
    <description>Gitea: possible brute force (5+ failed logins in 2 min)</description>
</rule>

Level 10. Fires when 5 or more failed Gitea logins occur within 2 minutes. Note: does NOT use same_srcip currently. Consider adding it if distributed attacks against Gitea become an issue.

100420, 100421 - Account lifecycle

  • 100420 (level 5): New user account created
  • 100421 (level 7): User account deleted (higher severity because account deletion is unusual and worth investigating)

100430, 100431 - SSH key management

  • 100430 (level 5): SSH key added to a Gitea account
  • 100431 (level 3): SSH key removed from a Gitea account (routine)

Track key changes because SSH keys grant repo access; unauthorized key additions could indicate account takeover.

100440 - Access token activity

Level 5. Fires on access token creation or use. Access tokens are alternate auth for Gitea and worth monitoring for unusual patterns.

100450 - Password reset / recovery

Level 5. Fires on password reset flows. Unusual reset patterns can indicate account takeover attempts.

100460 - Repository deleted

Level 7. Higher severity because repo deletion is destructive and worth immediate attention.

100470 - 2FA event

Level 5. Fires on 2FA setup, disable, or use events. Monitoring 2FA state changes helps detect account-security downgrade attacks.


Postfix mail correlation

Rules 100310-100316 detect various brute force patterns against the mailcow SMTP submission service. All key off shipped rule 3332 (Postfix SASL failure) with srcip populated by the mailcow-postfix-sasl-fail decoder.

100310 - Single-source brute force

<rule id="100310" level="10" frequency="5" timeframe="120">
    <if_matched_sid>3332</if_matched_sid>
    <same_srcip />
    <description>Postfix SASL: brute force login attempt from $(srcip)</description>
    <group>authentication_failed,brute_force,</group>
</rule>

Level 10. Fires when 5 SASL failures come from the same source IP within 2 minutes. Classic single-source brute force.

100311 - Account compromise (brute force followed by successful login)

<rule id="100311" level="14" timeframe="120">
    <if_matched_sid>100310</if_matched_sid>
    <if_sid>100204</if_sid>
    <same_srcip />
    <description>Mail: successful login after brute force from $(srcip) - ACCOUNT COMPROMISED</description>
</rule>

Level 14. Fires when a Dovecot successful login (rule 100204) occurs from the same source IP that just triggered a brute force alert (100310), within 2 minutes. Indicates a successful compromise.

100312 - Distributed brute force targeting one user

<rule id="100312" level="10" frequency="5" timeframe="300">
    <if_matched_sid>3332</if_matched_sid>
    <same_user />
    <different_srcip />
    <description>Postfix SASL: distributed brute force targeting user $(dstuser)</description>
</rule>

Level 10. Fires when 5 SASL failures target the same username from different source IPs within 5 minutes. Catches credential stuffing that rotates IPs.

100313 - Persistent single-source brute force

<rule id="100313" level="12" frequency="3" timeframe="86400">
    <if_matched_sid>100310</if_matched_sid>
    <same_srcip />
    <description>Postfix SASL: persistent brute force from $(srcip) - 3+ bursts in 24h</description>
</rule>

Level 12. Fires when the same IP triggers 100310 three or more times in 24 hours. Confirms a persistent adversary rather than a one-off scan.

100314 - Subnet-coordinated brute force

<rule id="100314" level="12" frequency="15" timeframe="3600">
    <if_matched_sid>3332</if_matched_sid>
    <same_field>src_subnet</same_field>
    <description>Postfix SASL: coordinated brute force from subnet $(src_subnet).0/24</description>
</rule>

Level 12. Fires when 15 SASL failures come from the same /24 subnet within 1 hour. Uses the src_subnet field extracted by the mailcow-postfix-sasl-fail decoder. Catches botnets rotating through hosting provider ranges.

100315 - Confirmed credential stuffing

<rule id="100315" level="10" frequency="10" timeframe="600">
    <if_matched_sid>3332</if_matched_sid>
    <same_user />
    <different_srcip />
    <description>Postfix SASL: credential stuffing against user $(dstuser) from multiple IPs</description>
</rule>

Level 10. Higher-confidence version of 100312. Requires 10 attempts against the same username from 10 different IPs within 10 minutes. Very low false positive rate.

100316 - High volume attack detection

<rule id="100316" level="8" frequency="50" timeframe="3600">
    <if_matched_sid>3332</if_matched_sid>
    <description>Postfix SASL: high volume of authentication failures (50+ in 1h)</description>
</rule>

Level 8. Volume alarm. Fires on 50 SASL failures in an hour regardless of source or target. Catches attacks that rotate both IPs and usernames.


Rule interaction summary

Rule Triggers when Correlates with
100310 5 failures, same IP, 2min Base for 100311, 100313
100311 100310 + 100204 success Terminal alert (compromise)
100312 5 failures, same user, different IPs, 5min Standalone
100313 100310 3x in 24h Persistence signal
100314 15 failures from same /24, 1h Subnet coordination
100315 10 failures, same user, different IPs, 10min High-confidence credential stuffing
100316 50 failures / hour Volume alarm

Detection coverage matrix by attack shape:

Attack pattern Rule that catches it
Single-IP brute force 100310
Compromise after brute force 100311
Distributed against one user 100312, 100315
Same attacker returning repeatedly 100313
Botnet in same subnet range 100314
High-volume general attack 100316

Testing rules

For any new correlation rule, remember: wazuh-logtest does NOT test rule correlation (frequency counters don't accumulate between separate logtest invocations). Test correlation rules by:

  1. Injecting real events at the appropriate rate into the log path
  2. Watching alerts.log for the rule to fire

For simple field-match rules, wazuh-logtest works fine.

Last updated: 2026-07-31