Skip to main content

ATK Rule Doctor Lite: why do my custom Wazuh rules never fire?

A free, read-only check for Wazuh 4.x. It lists every custom rule that did not fire and tells you the most likely reason, including rules that Wazuh silently threw away while loading them.

One Python 3 file, standard library only. It reads files; it changes nothing on your manager and sends nothing anywhere.

curl -sLO https://github.com/xuxu298/rule-doctor-lite/releases/latest/download/rule-doctor-lite.py
sudo python3 rule-doctor-lite.py                 # on the manager, reads /var/ossec
python3 rule-doctor-lite.py --ossec-dir ./copy   # or on a copy of /var/ossec

Manager in docker? Copy the four things it reads, then point --ossec-dir at the copy:

C=single-node-wazuh.manager-1; mkdir -p copy/ruleset copy/etc copy/logs/alerts
docker cp $C:/var/ossec/ruleset/rules copy/ruleset/ && docker cp $C:/var/ossec/etc/rules copy/etc/
docker cp $C:/var/ossec/logs/ossec.log copy/logs/ && docker cp $C:/var/ossec/logs/alerts/alerts.json copy/logs/alerts/

What the labels mean

label meaning
DROPPED-AT-LOAD Wazuh ignored the rule at load time: its if_sid parent was not loaded yet (the file name sorts before the parent's file) or does not exist. The manager still starts and wazuh-analysisd -t still exits 0; only ossec.log shows warnings 7617/7619. Read from ossec.log when present, otherwise predicted from the load order. Chains are followed: a rule whose parent was itself dropped is dropped too, however deep.
SHADOW-CANDIDATE a sibling that Wazuh evaluates first (higher level, or same level and loaded earlier) did fire. A candidate, not a finding: it proves the sibling matched something, not that your rule would have matched the same event.
NEVER-REACHES-MANAGER no related rule fired and the manager logged event loss (rules 203/204). Only loss that raised 203/204 is seen: an agent with its client buffer off, or a manager dropping events at its EPS limit, raises neither, and Lite then says NO-MATCH.
NO-MATCH a related rule fired but this one did not, or nothing suggests event loss.

The shadowed / never-reaches-the-manager / no-match split is Kislley Rodrigues's.

Every result is printed with the time window it was measured over. A rule written for a quarterly event is not dead after a day.

What it reads by default (0.2.1): the current logs/alerts/alerts.json plus the rotated alert files of the last 7 days (logs/alerts/<year>/<Mon>/ossec-alerts-<dd>.json, plain or .gz, as Wazuh writes them); change the window with --days N. From ossec.log it takes the 7617/7619 warnings of the latest rule load only (the block before the last Total rules enabled), so a rule you already fixed is not reported from an older load, and lines from wazuh-analysisd -t are ignored.

Tested on a real manager

wazuh/wazuh-manager:4.14.7, 27/09/2026. Two identical custom rules on if_sid 5715, one in 0094-test.xml (sorts before the stock 0095-sshd_rules.xml), one in 0500-ok.xml. A real sshd "Accepted password" event fired 100081 from 0500-ok.xml; 100080 in 0094-test.xml never fired. Rule Doctor Lite reported:

100080   level 10  0094-test.xml   DROPPED-AT-LOAD   ossec.log 7617: parent 5715 not found when the rule loaded

and, with ossec.log withheld, the same verdict from the load order alone:

100080   level 10  0094-test.xml   DROPPED-AT-LOAD   predicted: parent 5715 is in 0095-sshd_rules.xml, which loads after 0094-test.xml

Chains (0.2.0, 28/09/2026)

Same image. Anchor 910010 on if_sid 5715 in 0094-early.xml, child 910012 on if_sid 910010 and grandchild 910013 on if_sid 910012 in 0500-chain.xml. wazuh-analysisd -t exited 0; ossec.log had 7617 + 7619 for all three, each naming the rule above it as the missing parent. Lite, with ossec.log withheld:

910010   level 10  0094-early.xml   DROPPED-AT-LOAD   predicted: parent 5715 is in 0095-sshd_rules.xml, which loads after 0094-early.xml
910012   level 10  0500-chain.xml   DROPPED-AT-LOAD   predicted: parent 910010 is itself dropped at load
910013   level 12  0500-chain.xml   DROPPED-AT-LOAD   predicted: parent 910012 is itself dropped at load

The prediction matters because ossec.log can miss warnings: analysisd buffers the warnings of each rules file in a list capped at 50 (ERRORLIST_MAXSIZE) and flushes it after the file, so a file that produces more than 50 warnings loses the oldest ones (src/analysisd/analysisd.c L708-750 on v4.14.7).

tests/run.sh runs the fixture checks without docker.

Limits

  • Wazuh 4.x rule syntax. Only if_sid parents are read; if_group, if_matched_sid and if_matched_group are not followed yet.
  • NEVER-REACHES-MANAGER only sees loss that raised rule 203 or 204 (see the table above).
  • SHADOW-CANDIDATE needs a replay to confirm or clear. Lite does not replay.
  • "Never fired" means never fired in the alerts it read (7 days by default). Older alerts need --days or --alerts.

Guides

Step-by-step notes for what Lite points at, each with a one-minute check you can run yourself (measured on Wazuh 4.14.7):

Full version and done-for-you fixes

  • ATK Rule Doctor (USD 490 per cluster per year) replays the real events behind every SHADOW-CANDIDATE through a throwaway manager of your version to confirm or clear it, and fixes alerts the indexer rejects with mapper_parsing_exception: https://vct.atkvn.com/rule-doctor.html
  • Rule Fix Pack: we fix a silent rule or a mapping conflict on your version, fixed price, and you pay only after the fix fires on your cluster. Write to dongnx@atkvn.com.

Licence: Apache-2.0. Made by ATK New Technology, Hanoi.

Release files for rule-doctor-lite 0.2.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for rule-doctor-lite 0.2.1
File Size Uploaded
rule_doctor_lite-0.2.1.tar.gz 12.5 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for rule-doctor-lite 0.2.1
File Interpreter ABI Platform
rule_doctor_lite-0.2.1-py3-none-any.whl Python 3 none any Details

Total release size: 26.0 kB

Release files / rule_doctor_lite-0.2.1.tar.gz

Download URL rule_doctor_lite-0.2.1.tar.gz
Size 12.5 kB
Tags Source
SHA-256 checksum
How to use checksums
5ac78eb234bfe1d0a21f2349d4c5ae63589ae2d004a450dba378790bba4083bb
BLAKE2b-256 checksum
How to use checksums
fc46ad712c44d6be2c2b4107a96a79272c24edb28c87b8bb3d725bc4c68f9baa
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 28, 2026.

Transparency log

Release files / rule_doctor_lite-0.2.1-py3-none-any.whl

Download URL rule_doctor_lite-0.2.1-py3-none-any.whl
Size 13.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
1f875ca07a03c7d1f30f951bc03a5f55edbdbdf76f240fe4063220e408d50f5b
BLAKE2b-256 checksum
How to use checksums
d54822a689d556c9afa6adee61f0996c468f70b4ad98699cad1bebf11e3bfe8d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 28, 2026.

Transparency log

Release history Release notifications | RSS feed

0.2.2

2 release files

This release

0.2.1 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page