# wazuh-false-positives

Companion files for the lesson **Cutting Wazuh False Positives Without Going Blind**:
<https://maheshtata.com/wazuh/wazuh-false-positives/>

Tested against: Wazuh 5.0 (beta5 documentation, Sep 2026), Ubuntu 24.04.
Not yet validated in a lab; treat every value as a starting point.

## Files

| File | What it is |
| --- | --- |
| `top-findings-7d.json` | Noise budget query: top 50 rules by finding count over 7 days, with distinct-agent counts and a daily histogram per rule. |
| `noise-exclusion-rule.yml` | A tuned Sigma rule with two narrow exclusions, using the documented `condition: selection and not (...)` pattern. |
| `exception-register.csv` | Four-column exception register with an approver and a review date. |

## Use them in this order

1. **Measure.** Paste `top-findings-7d.json` (minus its `_comment` key) into
   **Indexer management > Dev Tools** after `GET /wazuh-findings-v5-*/_search`.
   Take the top ten. Ignore the tail on the first pass.
2. **Classify** each of the ten: true noise, misconfigured source, real but
   low value, or genuinely wrong. The classification decides the lever.
3. **Tune.** For true noise, adapt `noise-exclusion-rule.yml`. For a
   misconfigured source, fix the source instead. For real-but-low-value,
   change the level rather than the logic.
4. **Record.** One row per exception in `exception-register.csv`, with an
   approver and a review date.

## The promotion step people skip

The Standard space is read-only, so you cannot edit a built-in rule. You
create a copy in **Draft**, promote it to **Test**, validate it with the Log
test tool, promote it to **Custom**, and then **remove the original rule from
the detector that runs it**.

Skip that last step and you get two findings per event rather than one tuned
finding. While you are there, check how many policies are active: each active
policy receives its own copy of every incoming event, so several policies also
produce several findings.

## Reading the measurement

| Shape in the result | What it means | Lever |
| --- | --- | --- |
| High count, few `distinct_agents` | One or two endpoints 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, steady, never actioned | Real but low value | Keep the finding, drop it from alerting |
| New entry at the top | Something changed | Find the change before tuning |

## 4.x patterns with no 5.0 equivalent

| 4.x | 5.0 replacement |
| --- | --- |
| `if_sid` override | Your own rule, plus removing the original from the detector |
| `frequency` / `timeframe` | A bucket-level alerting monitor on the indexer |
| `same_source_ip` correlation | Bucket-level monitors, or a workflow combining monitors |
| `<list>` CDB allowlist | A KVDB referenced from decoder or rule logic |
| `<time>` / `<weekday>` | Handle in the monitor or downstream |

## Two things to change before promoting the rule

- **The `id`.** It ships as a placeholder UUID. Generate your own UUIDv4.
- **The `compliance` block.** The framework keys are real; the values are
  placeholders. Use the control references your own audit scope uses, or
  delete the block.
