Wazuh notes · custom rules

Wazuh custom rules: where they go, and six measured traps

This is a summary page. Each item below is something we measured on Wazuh 4.14.7, in one line, with a link to the full measurement. In five of them the configuration check passes or the manager starts, and the rule still does not do what you wrote; in the sixth the manager does not start at all.

Dong Nguyen, ATK New Technology · 3 October 2026 · Wazuh 4.14.7

Stuck on this right now? Email your custom rules or decoders, one sample log line and your Wazuh version to dongnx@atkvn.com. We run them on that exact version and reply within 24 hours with what we find. Free. Remove hostnames, IPs and usernames first. Rather not send them? Run the free pre-check in your browser; your files never leave your machine. Rather have it fixed? USD 149 fixed price per problem, reproduced on your version, and you pay only after it works on your system. Our first three customers pay USD 49 for one fix, in exchange for an anonymised write-up we can publish.


Where custom rules load from

Custom rules go in /var/ossec/etc/rules/. Those files are not loaded after the stock ruleset: they are merged with /var/ossec/ruleset/rules/ and loaded in order of the full file name. On 4.14.7 the image has 168 stock rule files, all starting with a digit, the last being 0999-malicious-ioc-rules.xml, so local_rules.xml loads after all of them. We measured the same child rule of stock rule 5715 in five file names: 0094-test.xml and 0095-aaa.xml were ignored; 0095-zzz.xml, 0096-test.xml and local_rules.xml fired. Full measurement.

How to check in one minute

/var/ossec/bin/wazuh-analysisd -t 2>&1 | grep -E 'WARNING|ERROR|CRITICAL'

The exit code is 0 even when rules are ignored, so read the lines. Each will be ignored line names a rule that is not running.

Six ways, measured

1. The parent rule is in a file that loads later

A child rule in a file that sorts before its if_sid parent's file is read before the parent exists. Wazuh logs 7617 and 7619, ignores the rule, and the config check still exits 0:

WARNING: (7617): Signature ID '5715' was not found and will be ignored in the 'if_sid' option of rule '100080'.
WARNING: (7619): Empty 'if_sid' value. Rule '100080' will be ignored.

Rule dropped at load: 7617 / 7619

2. A static field written as <field>

action is a static field with its own <action> tag. Writing <field name="action"> instead logged ERROR: Failure to read rule 100210. Field 'action' is static. and the manager did not start: no alerts at all, not only for FortiGate.

FortiGate note, with the measurement

3. More than 50 load warnings

wazuh-analysisd -t and ossec.log keep at most 50 load messages; anything beyond that is dropped, oldest first, with no line anywhere. In our test 60 rules were ignored: 50 lines were printed, naming the last 25, and the first 35 were never mentioned. A public community ruleset printed 52 warnings where a static check found 55.

The 50-warning limit, measured

4. An if_group the load check cannot match

At load time, 4.14.7 accepted an upper-case, partial group name and a | list, and rejected a name starting with ^ that does not begin any group:

<rule id="100715" level="5"><if_group>AUTHENTICATION_FAI</if_group>...</rule>
<rule id="100716" level="5"><if_group>zzz_nope|authentication_success</if_group>...</rule>
<rule id="100717" level="5"><if_group>^uthentication</if_group>...</rule>
WARNING: (7610): Group '^uthentication' was not found. Invalid 'if_group'. Rule '100717' will be ignored.

Rules 100715 and 100716 loaded with no warning. This is the load check only; we did not test which events these rules then match.

5. JSON logs behind a syslog header

A line that is only JSON decodes on its own. The same JSON behind a standard syslog header matched no decoder, and behind a plain date it was claimed by the stock windows-date-format decoder with no fields, so rules on the JSON keys never see them.

JSON logs not decoded

6. A CDB list rule under load

A rule with lookup="not_match_key" fed only values that were in the list gave no false alerts at 1,000 events per second, 10 at 5,000, and 24 and 27 in two 50,000-event bursts; with a single rule-matching thread, or a negated <field> in place of the list, the same bursts gave none.

CDB list not_match_key false positives

Limits of what we measured

Each item measured on 4.14.7; details on the linked page. Item 4 was measured for this page with wazuh-analysisd -t only. Other versions, clusters and the Wazuh 5.0 engine (which does not load XML rules) were not covered here.

Check yours

Not sure your custom rules all load? Run the free pre-check in your browser; your files never leave your machine. Or send your rule files and Wazuh version to the address below and we run them on that exact version within 24 hours. Free. Rather have it fixed for you? USD 149 fixed price per problem, paid after it works on your system.