Skip to main content

Ingestion policy

Every environment has an ingestion policy: the rules Mobius applies on your Wazuh indexer to decide which alerts it fetches and triages. It is the first gate in the pipeline. An alert the policy filters out never leaves your Wazuh, is never analysed, and is never billed.

Filtered alerts cannot be recovered later

The policy runs as the query against your indexer, not as a filter inside Mobius. An alert that does not match stays in Wazuh only. If you narrow the policy and later widen it, the alerts that arrived in between are not back-filled. Test a change before saving it.

Open it from Management > Environments: each environment card shows the Ingestion policy summary, with View policy to open the editor and History for every saved version. Only users in the admins group can edit a policy; anyone can read it.

What the defaults are​

A newly connected environment starts with the recommended policy:

SettingDefault
Minimum severityHigh+ (Wazuh 4.x rule.level >= 12, Wazuh 5.x high or critical)
Manager alertsIgnored (alerts from an agent named wazuh-manager-* are dropped)
Include rulesnone, so every alert at or above the floor is a candidate
Exclude rulesnone
Advanced queryoff
Rate limit5 events per second, hard limit 50 per second

Environments connected before version 3.0.0 were migrated automatically. Their policy reproduces exactly what they ingested before: the floor those versions applied (Medium+ on 4.x, High+ on 5.x), manager alerts ignored, and any former ingestion scope rules translated one-for-one into include rules named Migrated scope rule N. Nothing changed in what those environments ingest; it is now visible and editable.

How the parts combine​

The editor's Policy logic box shows the exact sentence, but the order is always the same. An alert is sent to Mobius only when all of these hold:

  1. Severity floor. It is at or above the minimum severity. Alerts below the floor are never fetched, whatever the rules say.
  2. Manager alerts. It is not a manager self-alert, unless you turned that filter off.
  3. Exclude rules. It matches no exclude rule. Exclusions always win, even over an include rule or an advanced query.
  4. Include rules or the advanced query. With no include rules and advanced mode off, every remaining alert is a candidate. With include rules, it must match at least one of them. With advanced mode on, it must match your query instead.
  5. Rate limit. Above the events-per-second cap, alerts are deferred to the next poll in order, never dropped, up to a six-hour backlog.

A narrow policy can stop most or all ingestion for an environment. Use Test policy to see the real effect on the last 24 hours before you save.

1. Minimum severity​

Alerts below this level are never retrieved. The presets are defined once and mapped to each Wazuh version, so the same policy means the same thing on a 4.x and a 5.x environment. The editor shows the effective clause for both.

PresetWazuh 4.xWazuh 5.x
Low+rule.level >= 1 (all alerts)low, medium, high, critical
Medium+rule.level >= 7medium, high, critical
High+ (recommended)rule.level >= 12high, critical
Criticalrule.level >= 15critical
Custom levelrule.level >= n, any value 1 to 15not available

Wazuh 5.x reports severity as a keyword rather than a number, so Custom level is refused on a 5.x environment. Pick the nearest preset instead.

2. Manager alerts​

Ignore manager self-alerts drops every alert whose agent name starts with wazuh-manager-. Manager housekeeping rarely needs AI triage, so this is on by default and recommended. Turn it off only if you want the manager's own alerts triaged; they then pass through the same floor and rules as any other agent.

3. Include rules: keep alerts matching any of these​

Include rules are optional. With none, every alert at or above the floor is a candidate. Add them to narrow ingestion to what you care about.

  • Rules are ORed: an alert is kept when it matches any rule.
  • Conditions inside a rule are ANDed: every condition must match.
  • A rule can be switched off with its toggle and kept for later. A disabled rule is stored but not applied.
  • Name a rule so the history and the Check an alert tool can refer to it.

Limits: 20 rules across include and exclude combined, 6 conditions per rule, and 6 custom-field conditions per policy.

Fields and operators​

Each condition is a field, an operator and a value. The operators offered depend on the field, and both are checked against the field catalogue for your Wazuh version before anything is saved.

FieldOperatorsNotes
Rule IDis, is one of, is not, is not one ofNumbers such as 5710
Rule groupscontains any, contains all, contains noneCase-sensitive, as Wazuh emits them
Descriptioncontains, not contains, starts with, isFree text
Agent IDis, is one of, is not, is not one of
Agent nameis, is one of, is not, is not one of, starts with, ends with, contains
Agent groupscontains any, contains all, contains none
MITRE tacticcontains any, contains all, contains noneNames such as Execution
MITRE techniquecontains any, contains all, contains noneIDs such as T1059
Source IP / Destination IPis, is one of, in CIDR, not in CIDRCIDR operators need Wazuh 5.x
Source port / Destination porteq, gt, gte, lt, lte, between, is one ofNumeric range needs Wazuh 5.x
Protocolis, is one of, is not
Decoder nameis, is one of, is not, is not one of
Field existsexists, not existsNames another catalogue field

Fields that are lists in the alert, such as rule groups and MITRE tactics, use the contains operators; single-valued fields use is. An operator that does not fit the field is not offered.

Seen here. Click into a value box to see the values this environment's recent alerts actually carry, with counts, and pick from them instead of typing. This reads Mobius's own stored alerts for the last 30 days, so a brand-new environment shows nothing yet.

Custom field​

For a field not in the catalogue, choose Custom field and give the literal dotted path from the original Wazuh alert, for example data.win.eventdata.image, plus a type hint. The hint picks the operators:

TypeOperators
keywordis, is one of, is not, starts with, ends with, contains
textcontains, starts with
numbereq, gt, gte, lt, lte, between
ipis, is one of, in CIDR, not in CIDR
arraycontains any, contains all, contains none

Exists and not exists are always offered, because the hint is a guess.

A custom path is accepted by Validate but flagged unverified: Mobius cannot check it against your index mapping. Run Test policy before relying on one. Paths starting with _source, _index, _id, _score or script are refused.

4. Exclude rules: then drop alerts matching any of these​

Exclude rules use the same fields and operators as include rules and are the right place for known noise: a chatty rule ID, a lab agent, a scanner you run on purpose. An alert matching any exclude rule is dropped, even if it matched an include rule or the advanced query.

Excluded alerts never reach Mobius. For noise you still want recorded but not analysed, use a known behavior rule instead; that keeps the alert and skips the model.

Advanced query mode​

For patterns the visual rules cannot express, switch on Advanced query mode and write the query yourself as an OpenSearch bool clause in JSON.

  • Advanced mode replaces the include rules only. The severity floor, the manager filter and your exclude rules still apply on top.
  • Turning it on clears the include rules; turning it off restores the visual builder.

What the query may contain​

Only this subset of OpenSearch is accepted, and it is checked before saving:

AllowedDetail
bool keysfilter, must, should, must_not, minimum_should_match
Leaf queriesterm, terms, range, prefix, wildcard, match_phrase, match_phrase_prefix, exists
range keysgt, gte, lt, lte
wildcardmust not start with * or ?, at most 2 wildcard characters
Fieldsmust be catalogue fields for this environment's Wazuh version, by their real index path
Sizeat most 40 leaf conditions, 6 levels of nesting, 4 wildcards per policy, 8 KB

Anything else, including query_string, script, regexp, nested, aggregations, or a field outside the catalogue, is rejected with the reason and the JSON path of the offending clause.

Field paths by Wazuh version​

The query uses real index paths, and they differ between versions. A query written for 4.x is rejected on a 5.x environment, and the other way round.

FieldWazuh 4.xWazuh 5.x
Rule IDrule.idwazuh.rule.id
Rule groupsrule.groupswazuh.rule.tags or wazuh.integration.category
Descriptionrule.descriptionwazuh.rule.title
Agent IDagent.idwazuh.agent.id
Agent nameagent.namewazuh.agent.name
Agent groupsagent.groupswazuh.agent.groups
MITRE tacticrule.mitre.tacticwazuh.rule.mitre.tactic.name
MITRE techniquerule.mitre.idwazuh.rule.mitre.technique.id
Source IP / portdata.srcip, data.srcportsource.ip, source.port
Destination IP / portdata.dstip, data.dstportdestination.ip, destination.port
Protocoldata.protocolnetwork.protocol
Decoderdecoder.namewazuh.integration.name

Severity is not a query field. rule.level and wazuh.rule.level are rejected in the advanced query because the Minimum severity setting owns the floor and is applied on top of your query.

Writing the query​

The shape is one bool. Put what to keep in filter (all must match) or in should with "minimum_should_match": 1 (any may match). Put what to drop in must_not. This 4.x example keeps security-relevant alerts and drops known noise:

{
"bool": {
"filter": [
{
"bool": {
"minimum_should_match": 1,
"should": [
{ "terms": { "rule.groups": ["authentication", "attack", "intrusion_detection", "sshd"] } },
{ "terms": { "rule.mitre.tactic": ["Initial Access", "Execution", "Credential Access", "Lateral Movement"] } },
{ "prefix": { "rule.mitre.id": "T1" } }
]
}
}
],
"must_not": [
{ "terms": { "rule.groups": ["vulnerability-detector"] } },
{ "prefix": { "agent.name": "test-" } }
]
}
}

The same policy on a 5.x environment uses the 5.x paths:

{
"bool": {
"filter": [
{
"bool": {
"minimum_should_match": 1,
"should": [
{ "terms": { "wazuh.rule.tags": ["authentication", "attack", "intrusion_detection", "sshd"] } },
{ "terms": { "wazuh.rule.mitre.tactic.name": ["Initial Access", "Execution", "Credential Access", "Lateral Movement"] } },
{ "prefix": { "wazuh.rule.mitre.technique.id": "T1" } }
]
}
}
],
"must_not": [
{ "terms": { "wazuh.rule.tags": ["vulnerability-detector"] } },
{ "prefix": { "wazuh.agent.name": "test-" } }
]
}
}

Exclusions written inside the query as must_not and exclusions added as visual exclude rules both become must_not in the final query. Use whichever reads more clearly; you can mix them.

Validate, then test​

Validate checks the query against the rules above and against the field catalogue for your Wazuh version, and reports Query is valid with the clause count, or Query rejected with the reason and path. It runs automatically as you type and on demand with the button.

Validate is a static check: it proves the query is well-formed and permitted. It cannot know your index mapping. A query can pass Validate and still fail on the indexer, most often when a text-only operator such as match_phrase_prefix is used on a field your mapping stores as keyword. That is what Test policy is for: it runs the real query against your environment and surfaces the indexer's own error if there is one.

View effective query shows the complete _search body Mobius will send every poll, with the floor, the manager filter, your query and your exclude rules combined, exactly as it is stored.

Test before you save​

Test policy runs the candidate policy read-only against the environment's alerts from the last 24 hours (1 hour and 7 days are also available) and reports how many alerts would be sent to Mobius, what gets filtered out at each stage and why, and the estimated change in AI token use. Nothing is saved and nothing is ingested. The environment's connector must be online; if it is not, the test reports connector offline instead of a count.

One test runs at a time per organization. A test takes a few seconds to about a minute.

Check an alert answers "would this specific alert be ingested, and why?" for a candidate policy without touching the indexer. It walks the same order as the pipeline and names the rule that decided: Below the minimum severity, Manager self-alert (excluded), Matched exclude rule X, Matched include rule Y, or Matched no include rule.

The footer shows Not tested yet until you run a test on the current draft. You can still save without testing.

Save, versions and history​

Every save creates an immutable version and makes it active immediately. Changes apply to alerts that arrive from then on. History lists every version with who saved it and a summary of what changed, and Restore creates a new version with an older version's content, so the trail is never rewritten. If someone else saved while you were editing, your save is refused with the current version number rather than silently overwriting theirs.

Rate limit and backpressure​

Rate limit is the maximum number of alerts per second Mobius triages for the environment. It defaults to 5 per second, about 300 alerts per one-minute poll, and only billing admins can change it. Above the cap, alerts are deferred to the next poll, in order, and never dropped. If a storm keeps the backlog above six hours, the oldest part is shed deliberately and recorded as a gap on the environment page, so a storm can never build an unbounded queue. An Ingestion backlog building notification fires when a backlog forms and Ingestion backlog cleared when it drains; see notifications.

When a policy cannot run​

If your indexer rejects the saved policy, for example after a Wazuh upgrade changes a mapping, Mobius does not stop ingesting. It falls back to the last version that worked, or, if there is none, to a conservative Critical-only policy with manager alerts ignored, and notifies you: Ingestion policy rejected by Wazuh, then Ingestion running a fallback policy, and Ingestion policy recovered once a save works again. The environment card's runtime banner shows which version is actually running and why.