Fix note · OpenSearch Security Analytics

OpenSearch Sigma threshold rule fails with “index_name is missing”. The rule is fine, and the count has no time window.

What you see: saving a Sigma rule with condition: selection | count(*) by dst_endpoint.hostname > 5 fails with Validation Failed: 1: index_name is missing;, and changing the group-by field does not help. Your rule is not the problem: the Security Analytics API created that rule as written. The same error text comes from the rule validate API when the request has no index_name. Before you rely on it: the threshold did fire (6 failed logons on one host gave a finding, 3 on another gave none), but the query it generates has no time filter. The same 6 events produced a new finding every minute: 67 findings in 66 minutes, and adding Sigma timeframe: 5m did not add a time range to it. For “more than 5 in 5 minutes”, an Alerting bucket-level monitor with a time range did what the rule should.

Dong Nguyen, ATK New Technology · 28 October 2026 · measured on stock OpenSearch 3.8.0 (opensearchproject/opensearch:3.8.0, Security Analytics 3.8.0.0), our test container

One node, security plugin off, REST API only: there was no OpenSearch Dashboards in our test, so we did not see the editor you used. Test events were written by us, not real Windows logs.

Stuck on a detection rule right now? Email the rule YAML, two or three sample events and your OpenSearch version to support@atkvn.com. We load them on a test node and reply within 24 hours with what it actually does. Free. Remove hostnames, IPs and usernames first.


This note comes from a question on the OpenSearch forum: a Windows rule for failed logons (EventID|all: '4625') with a threshold per destination host would not save. We created the same rule on stock OpenSearch 3.8.0 and answered three questions in order: is the rule wrong, does a threshold rule fire, and what to use if it does not do what you mean.

How to check yours

All three are read-only. Set these first:

IDX=http://localhost:9200   # your cluster. Ours had the security plugin off: plain HTTP, no login.
CURL="curl -s"              # with security on: CURL="curl -sk -u admin:YOUR_PASSWORD" and IDX=https://...

1. Does the rule validate against your index?

$CURL -XPOST "$IDX/_plugins/_security_analytics/rules/validate" -H 'Content-Type: application/json' \
  -d '{"index_name":"YOUR-INDEX","rules":["RULE_ID"]}'

In our test this returned {}. The same request without "index_name" returned the error from the forum, word for word.

2. Are your fields mapped for Security Analytics?

$CURL "$IDX/_plugins/_security_analytics/mappings/view?index_name=YOUR-INDEX&rule_topic=windows" | python3 -m json.tool | head -40

Look at unmapped_index_fields. Without a mapping for the rule's fields, our detector created no monitor and produced no finding at all (details below).

3. Is the same finding coming back every run?

$CURL -XGET "$IDX/_plugins/_security_analytics/findings/_search?detector_id=DETECTOR_ID&size=100" | python3 -c '
import json,sys
for f in json.load(sys.stdin).get("findings",[]):
    print(f["timestamp"], len(f.get("related_doc_ids",[])), sorted(f.get("related_doc_ids",[]))[:3])'

If you see a new finding each run with the same document ids, you are looking at the time-window problem below, not at new attacks.

1. Is the rule wrong? No.

We created the rule through POST /_plugins/_security_analytics/rules?category=windows with this body, and it was accepted:

title: Repeated failed logons to one host
id: 5f0e3a3e-1111-4c2b-9b1a-000000028362
status: test
description: lab reproduction of forum t/28362
author: lab
date: 2026/10/28
logsource:
  product: windows
detection:
  selection:
    EventID|all:
      - '4625'
  condition: selection | count(*) by dst_endpoint.hostname > 5
level: informational

So changing dst_endpoint.hostname to other fields was changing the wrong thing.

Where “index_name is missing” comes from

We sent POST /_plugins/_security_analytics/rules/validate with only the rule id:

{"rules":["RULE_ID"]}
→ 400 {"type":"action_request_validation_exception","reason":"Validation Failed: 1: index_name is missing;"}

{"index_name":"winlog-28362","rules":["RULE_ID"]}
→ {}

That is the exact text from the forum. In the plugin, the string index_name appears only in this validate request and in the field-mapping APIs. We did not measure which API the Dashboards rule editor calls, because our test had no Dashboards. What we can say is that the API takes the rule, and that the error is what the validate API returns when it is not told which index to check against. If the editor gives you no way to pick an index, creating the rule through the API, as above, is a way round it.

2. Does a threshold rule fire? Yes, but read this first.

It needs field mappings first

Our first detector on a plain index created no monitor and produced no finding. Security Analytics reads the Windows rule's EventID as winlog.event_id, so the index needs an alias. We created the index with EventID (integer), dst_endpoint.hostname (keyword) and @timestamp, then:

$CURL -XPOST "$IDX/_plugins/_security_analytics/mappings" -H 'Content-Type: application/json' -d '{
  "index_name": "winlog-28362",
  "rule_topic": "windows",
  "partial": true,
  "alias_mappings": { "properties": { "winlog.event_id": { "type": "alias", "path": "EventID" } } }
}'

Then the detector, with the custom rule, a 1-minute schedule and no triggers. If your index already has a real winlog.event_id field, the alias fails: on an earlier index of ours the mapping call returned mapper [winlog.event_id] cannot be changed from type [integer] to [FieldAliasMapper].

The threshold fired on the right host

At 05:09 UTC we wrote 6 events with EventID 4625 for host dc01 and 3 for ws07. The first finding came at 05:10:20: 6 documents, all dc01. ws07, with 3, produced no finding. So the count(*) by … > 5 part works.

But the count has no time window

We wrote no more events. The detector kept producing a new finding for the same 6 documents on every run, once a minute:

finding time (UTC)documentshost
05:10:206dc01
05:11:206dc01
05:12:206dc01
… one every minute …6dc01
total at 06:16:5167 findings, none from new events

The reason is in the monitor Security Analytics generated for the rule. Its search, read back from the Alerting API, has the event-id query and the per-host aggregation, and no @timestamp range:

"query": { "query_string": { "query": "winlog.event_id: \"4625\"" } },
"aggregations": { "result_agg": { "terms": { "field": "dst_endpoint.hostname", "size": 10 } } }
trigger: params._cnt > 5.0

Our detector had no triggers, so we counted findings, not alerts or notifications. We did not test what a detector trigger sends when the same finding comes back every minute.

3. What to use for “more than 5 in 5 minutes” (tested)

An Alerting bucket-level monitor, where you write the time range yourself: event id 4625, @timestamp from 5 minutes before the run, grouped by dst_endpoint.hostname, trigger _count > 5, run every minute.

This is the body we sent, with only the index name replaced. It has no actions: we read the result from the alert list, not from a notification. Add your own action, and set its execution policy as described in the notes linked below.

$CURL -XPOST "$IDX/_plugins/_alerting/monitors" -H 'Content-Type: application/json' -d '{
  "type": "monitor",
  "monitor_type": "bucket_level_monitor",
  "name": "bf-4625-by-host-5m",
  "enabled": true,
  "schedule": {
    "period": {
      "interval": 1,
      "unit": "MINUTES"
    }
  },
  "inputs": [
    {
      "search": {
        "indices": [
          "YOUR-INDEX"
        ],
        "query": {
          "size": 0,
          "query": {
            "bool": {
              "filter": [
                {
                  "term": {
                    "EventID": 4625
                  }
                },
                {
                  "range": {
                    "@timestamp": {
                      "gte": "{{period_end}}||-5m",
                      "lte": "{{period_end}}",
                      "format": "epoch_millis"
                    }
                  }
                }
              ]
            }
          },
          "aggregations": {
            "by_host": {
              "terms": {
                "field": "dst_endpoint.hostname",
                "size": 100
              }
            }
          }
        }
      }
    }
  ],
  "triggers": [
    {
      "bucket_level_trigger": {
        "name": "gt-5",
        "severity": "3",
        "condition": {
          "buckets_path": {
            "_count": "_count"
          },
          "parent_bucket_path": "by_host",
          "script": {
            "source": "params._count > 5",
            "lang": "painless"
          }
        },
        "actions": []
      }
    }
  ]
}'
checkevents in the indexresult
06:18:26 UTConly the 6 dc01 events from 05:09, outside the 5-minute window0 alerts
06:19:43 UTCplus 6 new dc01 and 3 new ws07 written at 06:18:271 alert, ACTIVE, bucket dc01, 6 documents; nothing for ws07

Old events stopped counting once they were outside the window, which is the behaviour the Sigma rule did not give us. To keep one notification per burst instead of one per run, see repeated notifications for one burst; for one notification per matching line, see one notification per matching document.

Limits of what we measured

Stock OpenSearch 3.8.0 (opensearchproject/opensearch:3.8.0, Security Analytics 3.8.0.0), one node, security plugin off, plain HTTP, in our test container, 28 October 2026. No OpenSearch Dashboards: everything went through the REST API, so we cannot say what the Dashboards rule editor sends. One rule shape (one event id, one group-by field), synthetic events with three fields, 9 events and then 9 more. The detector had no triggers; we counted findings, not alerts or notifications. We did not test more than 10 hosts, a cluster, the security plugin's permissions, prebuilt Windows log integrations, or Sigma correlation rules. The Security Analytics plugin bundled with the Wazuh 5.0.0-rc1 indexer did not accept POST /_plugins/_security_analytics/rules at all (no handler found), so none of this was measured there.

Free check

Send us the detection rule that is not doing what you expect. The rule YAML, two or three sample events with hostnames and IPs removed, and your OpenSearch version. We load them on a test node and reply within 24 hours with what the rule actually does: whether it fires, on what, and how often. Free.

Send it

Free answer within 24 hours.

Paste the rule and a few sample events below, with hostnames and IPs removed, and say what you expected it to do. We reply within 24 hours with what it actually does.

Or email support@atkvn.com.