Tuning Wazuh is a budget exercise before it is a rule exercise. Decide how many findings a shift can genuinely triage, measure what you actually produce over a week, and close the gap from the top of the list downwards. In Wazuh 5.0 the tools are different from 4.x: rules are Sigma YAML, they live in spaces with a promotion flow, the Standard space is read-only, and correlation-based noise reduction is gone. What has not changed is that the top ten rules will account for most of your volume.

What you need

  • Seven days of findings in the indexer. Less than that and you will tune around one incident or one quiet weekend.
  • Read access to the findings data streams, through Indexer management > Dev Tools or the indexer API on port 9200.
  • Permission to create content in the Draft space and promote it. Detector lifecycle changes are reserved to the administrator role, which is a role design decision as much as a tuning one.
  • A place to record exceptions that is not a chat thread.

Measure first

Aggregate findings by rule over seven days. The two numbers that matter are the count and how many distinct endpoints contributed to it.

GET /wazuh-findings-v5-*/_search
{
  "size": 0,
  "query": {
    "range": { "@timestamp": { "gte": "now-7d", "lt": "now" } }
  },
  "aggs": {
    "by_rule": {
      "terms": { "field": "wazuh.rule.id", "size": 50, "order": { "_count": "desc" } },
      "aggs": {
        "title": { "terms": { "field": "wazuh.rule.title", "size": 1 } },
        "level": { "terms": { "field": "wazuh.rule.level", "size": 5 } },
        "distinct_agents": { "cardinality": { "field": "wazuh.agent.id" } },
        "top_agents": { "terms": { "field": "wazuh.agent.name", "size": 5 } }
      }
    }
  }
}

Aggregate on wazuh.rule.level with a terms aggregation, not a range. It is a string in 5.0. If you see a monitor in your deployment comparing wazuh.rule.level > 3, that is the shipped sample monitor carrying a numeric comparison over from 4.x, and it is worth checking what it actually matches.

Two shapes come out of that query, and they lead to different fixes:

Shape Reading Usual fix
High count, few distinct agents One or two endpoints are misbehaving Fix the endpoint or its collection scope
High count, most of the estate The rule does not suit your environment Exclusion in the rule, or a level change
Moderate count, steady, never actioned Real but low value Keep it, drop it out of the notification path
Sudden new entry in the top ten A change somewhere, not a tuning problem Find the change before you tune anything

Sort by count, take the top ten, and stop there for the first pass. The tail is not where your triage time goes.

Classify before you touch anything

Four buckets, and the bucket decides the lever.

True noise. The activity is expected, benign and will recur forever. A scheduled task, a monitoring probe, a service account doing its job. Exclude it narrowly, in the rule.

Misconfigured source. The finding is correct and the source should not be producing that activity at all, or should not be sending it. A debug log left on, a job retrying because a credential expired, an agent re-reading a rotated file. Fix the source. Tuning this in the rule hides a real fault.

Real but low value. The detection is accurate and you will never act on it alone. It has value as context in an investigation and no value as a notification. Keep the finding, take it out of the alerting path, and stop counting it against the triage budget.

Genuinely wrong. The rule matches things it was not written to match, usually because your field values differ from the author’s assumptions. Fix the detection logic, and if it is a standard rule, say so upstream as well as fixing it locally.

Put the classification in writing per rule as you go. It is the difference between a tuning exercise and a tuning habit.

Tune in the right place

Five levers, in the order you should reach for them. Earlier ones are cheaper and lose less visibility.

1. Collect less at the source

The cheapest finding is the one never generated. Agent-side collection scope lives in the group’s shared agent.conf in 5.0, so narrowing a file integrity scope or dropping a log source is a group change, not a per-host one. See agent groups and centralised configuration.

2. Filter before decoding

Filters are engine-level content in YAML, stored in the wazuh-threatintel-filters index and passed to the normalisation engine. A pre-filter is evaluated before decoding and discards events that do not meet its conditions immediately, avoiding the decoding work. A post-filter runs after enrichment or decoding and discards before the outputs.

This is powerful and blunt: a filtered event does not exist downstream, so you lose it for hunting as well as for alerting. Use it for traffic with no investigative value at all, and never for something you might want to search for later.

3. Add an exclusion to the rule

This is the documented standard pattern for reducing false positives. A named selection combined into the condition with not:

detection:
  selection:
    event.action: authentication-failure
  filter_service_accounts:
    user.name|startswith: "svc-"
  filter_scanner:
    source.ip|cidr: 10.42.99.0/24
  condition: selection and not (filter_service_accounts or filter_scanner)

The modifiers that make exclusions precise are contains, startswith, endswith, re with the i, m and s submodifiers, cidr, exists, and the numeric comparisons lt, lte, gt and gte. all turns a list from OR into AND. Use the narrowest one that works: a cidr exclusion for a scanner subnet is defensible for years, a contains on a substring of a hostname is a trap the day somebody renames a server.

Every field you reference is validated against the Wazuh Common Schema when the rule is created, and a rule referencing a field that does not exist is rejected with a structured error naming the field. That is a feature: it stops you shipping an exclusion that silently never matches.

4. Change the severity

level is a string: informational, low, medium, high or critical. Dropping a rule from high to low keeps the finding and takes it out of the notification path, if your monitors select on severity. That is the right answer for the “real but low value” bucket, and the wrong answer for the other three, because it hides a problem rather than resolving it.

5. Disable, or take it out of the detector

Two ways, and they are not the same.

enabled: false on the rule stops it being active at all. It is the honest option for a rule that has no place in your environment.

Removing the rule from a detector is narrower. A detector connects rules to a data source and runs on a schedule, and when you create one you select which rules are active for it and can include or exclude individual rules. That lets you run a rule against one data source and not another, which is often exactly what you want when a rule is correct for servers and useless for laptops.

The Standard space is read-only

You cannot edit a built-in rule. Content lives in four spaces: Draft and Test and Custom are user-managed, Standard is read-only content synced from Wazuh CTI. Custom is the space whose content the data analysis engine actively uses.

To quieten a standard rule, the sequence is:

  1. Create your version in the Draft space, under the same integration, with the exclusion added.
  2. Promote Draft to Test and validate with the Log test tool, which validates decoders, KVDBs, detectors and rules in the Test, Custom and Standard spaces.
  3. Promote Test to Custom, which makes it active. On each promotion the content manager deploys the content to the engine, validates the configuration, triggers a reload and updates the target space.
  4. Stop the detector running the original, by editing the detector’s rule selection.

Step four is the one people forget, and the symptom is two findings where you expected one tuned finding. While you are looking at duplicates, check how many policies are active: each active policy receives its own copy of every incoming event, so a single event can generate multiple findings when several policies are enabled.

Promotion moves an integration’s decoders and rules together. Promoting an integration from Draft to Test, or Test to Custom, promotes all of its associated decoders and rules with it.

What you cannot do in 5.0, and what to use instead

4.x pattern 5.0 status Replacement
if_sid override of a parent rule Not supported Author your own rule; exclude the original from the detector
frequency and timeframe Not supported A bucket-level alerting monitor on the indexer, which evaluates aggregation buckets and can alert per host or per user
same_source_ip and similar correlation Not supported Bucket-level monitors, or a workflow combining monitors
<list> CDB allowlist Not supported A KVDB, referenced from decoder or rule logic
<time> and <weekday> conditions Not supported Handle in the monitor or downstream in automation

The threshold case deserves a note. Bucket-level monitors evaluate aggregation buckets rather than whole query results, and each bucket can generate its own alert, which is how you get “more than N failures on one host” behaviour in 5.0. They are documented for exactly this: monitoring authentication failures per host, detecting excessive network activity by users, identifying the top systems generating security events.

Record every exception with an expiry

An exclusion with no owner and no review date becomes a permanent blind spot. The rule format gives you places to put the record, and using them means the exception travels with the rule rather than living in a spreadsheet somebody leaves behind.

metadata:
  title: Failed authentication, excluding service accounts
  author: Security Operations <secops@example.com>
  date: "2026-09-22"
  modified: "2026-09-22"
  description: Local copy of the standard rule with two exclusions.
  documentation: https://internal.example/wazuh/exceptions/EX-2026-014
falsepositives:
  - Scheduled service accounts prefixed svc-
  - Authenticated vulnerability scanning from 10.42.99.0/24

falsepositives is a first-class field listing known sources of false positives. documentation is free-form text or a URL providing additional triage context for analysts investigating a finding, which makes it the right place for the exception reference. modified is auto-managed when the rule’s content changes, so it tells you when someone last touched the exclusion.

Keep the register itself outside Wazuh, with four columns: rule, what is excluded, who approved it, and the review date. Review quarterly. An exception that nobody can justify at review gets removed, and the finding count goes up for a week while you find out whether it mattered.

Common errors

The detection engine rejects the rule with a structured error naming a field

Cause: a field in the detection block does not exist in the Wazuh Common Schema. Field names are validated at creation on purpose, to prevent rules that appear active but never match. Fix: check the field against a real document in Discover. The usual case is a 4.x name such as data.srcip instead of source.ip, or full_log instead of event.original.

The tuned rule is active but the noise continues

Cause: the original standard rule is still selected in the detector. Fix: edit the detector’s rule selection and remove it, then confirm which rules the detector runs.

Two findings per event after tuning

Cause: either both the original and the tuned copy are running, or more than one policy is active, since each active policy receives its own copy of every event. Fix: check the detector’s rule list first, then how many policies are enabled.

The exclusion matches more than intended

Cause: an over-broad modifier. A contains on a short string, or a match-style comparison on a value containing hyphens, will catch neighbours. Fix: tighten to startswith, endswith, cidr or an exact value. Prefer cidr for address ranges and re with an anchored pattern for names.

A rule referenced by identifier stops matching after an update

Cause: you filtered on wazuh.rule.sigma_id, which changes when the rule identifier changes. The documentation notes that event.action is more stable because it does not change when the rule identifier changes. Fix: key monitors and dashboards on event.action where a stable handle is needed.

Changes in Draft have no effect

Cause: Draft content is not active in the engine. Only content promoted to Custom is used to decode and process live events. Fix: promote Draft to Test, validate with the Log test tool, then promote Test to Custom.

Where to go next

The rule format, including the full modifier list and the not exclusion pattern, is on the official Wazuh rules documentation, and the promotion flow is on the spaces page beside it.

If the aggregation shows volume rather than noise as the problem, the lesson to read is performance tuning, because the fix is retention and collection scope rather than rule content. Writing the replacement rule itself is covered in custom detection rules, and once the noise floor is low enough to automate on, the intake design is in SOAR with Wazuh.

Next: SOAR with Wazuh: n8n, Shuffle and TheHive.

Files for this lesson

Every file this lesson refers to, exactly as used. Open a file to read it in the browser, or download the set as a zip. Download wazuh-false-positives.zip. The full set for all lessons is at wazuh-tutorial-files.zip.

Frequently asked questions

How do I find the noisiest rules in Wazuh 5.0?

Run a terms aggregation on wazuh.rule.id over the findings data streams for a week, with a sub-aggregation counting distinct agents. Rules with a high count across very few agents are usually a misconfigured source; rules with a high count across most of the estate are usually a rule that does not suit your environment.

Can I edit a built-in Wazuh rule to make it less noisy?

Not in place. The Standard space is read-only content synced from Wazuh CTI. You either exclude the rule from the detector that runs it, or author your own version in the Draft space with the exclusion added, promote it through Test to Custom, and stop the detector running the original.

Does Wazuh 5.0 still support if_sid and frequency for tuning?

No. Rules are Sigma YAML in 5.0 and if_sid, if_matched_sid, frequency and timeframe correlation, CDB lists and time or weekday conditions are not supported. Threshold behaviour moves to bucket-level alerting monitors on the indexer, and lookup lists move to KVDBs.

What is the right way to suppress a noisy Wazuh alert?

Add a named exclusion to the rule's detection block and reference it in the condition with not, which the documentation calls the standard pattern for reducing false positives. Lowering the severity or disabling the rule are blunter options and should be recorded with an owner and a review date.

Why am I seeing two findings for the same event?

Each active policy receives its own copy of every incoming event, so a single event can generate multiple findings when several policies are enabled. Check how many policies are active before treating duplicates as a rule problem.