Defensible detection-tuning with Kibana Cases: a DFIR how-to

How to standardize, audit, and automate detection-tuning requests in Elastic using Kibana Cases, custom fields, runtime/ES|QL queries, an...

Elastic Security Labs published a workflow on December 5, 2025 that shows how to automate detection-tuning requests with Kibana Cases, using custom fields, a detection to watch for toggled requests, and a webhook to create tickets and add links back to the case (Elastic Security Labs, 2025-12-05).

Overview

Kibana Cases lets you open, track, and enrich investigations with alerts, comments, files, visualizations, and external tickets via connectors such as ServiceNow, Jira, Slack, and webhooks (Cases overview, connector catalog). Custom fields for Cases (text/toggle) were added in Elastic 8.15, enabling standardized “tuning requested?” switches captured directly in the case form (custom fields in settings, Security app settings). You can attach alerts to cases from the Alerts UI or create a case from an alert, ensuring the detection context travels with the request (create/manage cases and attach alerts).

Behind the scenes, alert documents live in hidden indices named .alerts-security.alerts-<space-id> in 8.x (replacing legacy .siem-signals-*), and include rich rule metadata under kibana.alert.rule.*-including version and an edit-incrementing revision-useful for change tracking and regression checks (alert schema 8.x). Kibana’s saved objects (including Cases) are stored in split indices since 8.8, with a dedicated .kibana_alerting_cases alias for case objects (saved object migrations, 8.8+). For analytics, you can optionally enable “cases as data,” which creates documented internal indices (for example, .internal.cases.securitysolution-<space>) with fields for status, severity, custom_fields, and attachments for dashboards/queries (cases as data, case analytics schema).

Acquisition and Extraction (platform-specific)

Use the APIs below to collect a defensible set of artifacts for each tuning request. Favor API key auth, add kbn-xsrf: true, and pin exact space paths (/s/<space>).

  • Case record
    • Get a case: GET /api/cases/{caseId} (Cases API).
    • Case activity (audit trail of edits/comments): GET /api/cases/{caseId}/user_actions/_find (find case activity).
  • Alerts linked to the case
    • Get alert links for a case: GET /api/cases/{caseId}/alerts (returns alert ids and indices) (Cases API list).
    • Fetch each alert document (single GET): GET /{index}/_doc/{id} using the returned index and id, or search the alerts index prefix .alerts-security.alerts-* (alert schema and indices).
  • Rule metadata and current state
    • Retrieve rule by id or by stable rule_id: GET /api/detection_engine/rules?id=<id> or ?rule_id=<rule_id> (retrieve a detection rule).
    • Update rule (for remediation, if approved): PUT /api/detection_engine/rules (note: id is immutable; use rule_id to address stably) (update rule).
    • Export rules and attached exception lists to NDJSON for evidence: POST /api/detection_engine/rules/_export (export rules).
  • Exceptions
  • Audit logs (change provenance)

Artifact Locations and Paths

  • Case saved objects: .kibana_alerting_cases* (via alias) since 8.8, managed by Kibana migrations (saved object indices, 8.8+).
  • Case analytics (optional feature): .internal.cases.* and related attachments/activity indices; create a data view (allow hidden) against .internal.cases* (cases as data, schema).
  • Alerts: .alerts-security.alerts-<space-id>; legacy .siem-signals-* applies to 7.x only (alert schema and index naming).
  • Rule fields in alerts: e.g., kibana.alert.rule.rule_id, kibana.alert.rule.name, kibana.alert.rule.version, kibana.alert.rule.revision (increments on edit) (alert schema fields).
  • Connectors for external systems (ServiceNow, Jira, Slack, Webhook, etc.) to push or link tuning tickets (connector catalog, ServiceNow ITSM).

Analysis and Correlation

Link the tuning request to its precise detection context and any changes you make.

  1. Build a Cases data view and custom fields
  • Use the Cases Settings UI to add your standard toggles/text fields for tuning (for example, Open tuning request? toggle + Tuning details text) (custom fields, 8.15+).
  • If you enabled “cases as data,” query custom fields directly from .internal.cases.* via the documented schema (custom_fields.type/label/value) (case analytics schema).
  • If you need runtime extraction from saved objects, add runtime fields in the Kibana data view and parse params._source via Painless; runtime fields can be defined in a data view or via runtime_mappings in a search request (Kibana data-view runtime fields, Elasticsearch runtime fields).
  1. Retrieve attached alerts and map to rules
  • GET /api/cases/{caseId}/alerts → iterate returned {index,id}GET /{index}/_doc/{id} and read kibana.alert.rule.* to resolve the rule_id and current revision (Cases alerts API, alert schema).
  • Pull the rule object for evidence and potential fix: GET /api/detection_engine/rules?rule_id=<value> (retrieve rule).
  1. ES|QL/KQL queries for triage and metrics
  • ES|QL in Kibana is first-class and works well for cases/alerts dashboards and suppression reviews (ES|QL in Kibana).
  • Example: find open Cases flagged for tuning in analytics indices and aggregate by rule name from attached alerts (join on the alerts index after collecting alert IDs from attachments):
FROM .internal.cases.securitysolution-* 
| WHERE status == "open" AND custom_fields.label == "Open tuning request?" AND custom_fields.value == "true"
| KEEP title, created_at, updated_at

Use the attachments index (payload.alerts.id/payload.alerts.index) to join back to .alerts-security.alerts-* as needed for rule-level aggregates (case analytics schema, alert schema).

  1. Track and justify changes
  • The Cases user-actions API provides a per-case audit of edits and status transitions; export it alongside the case body for your evidence bundle (find case activity).
  • When a rule is edited, kibana.alert.rule.revision increases on subsequent alerts-use that field to confirm the tuned rule is actually what fired later (alert schema: revision).
  • Rules execute under the API key of the last editor; if a low-privilege user updates a rule, execution and actions can break. Capture and review the editor and API-key behavior before and after changes (rule auth behavior).
  1. Optional: Sigma to Elastic

Validation and Pitfalls

  • Index/field drift across versions: in 8.x the alert index is .alerts-security.alerts-*; older docs and screenshots may still reference .siem-signals-*. Validate your data view patterns before bulk queries (8.x alert index).
  • Saved objects vs analytics indices: analytics indices are purpose-built for dashboards and have a public schema (including custom_fields), but require enabling the feature; saved objects exist regardless (enable cases as data, analytics schema).
  • Runtime fields performance: runtime evaluation happens at query time; prefer indexing key fields and use runtime fields where you can’t reindex (runtime fields guidance).
  • Rule execution identity: rules run with the API key of the last editor; changing editors can inadvertently change privileges/behavior-record editor identity in the case before/after tuning (rule auth).
  • Case templates are in technical preview in some apps; don’t rely on them as a control without validating behavior in your deployed version (templates tech preview).

Reporting Notes (chain of custody, reproducibility)

For each tuning request, export:

  • Case JSON (GET /api/cases/{caseId}) and Case activity (GET /api/cases/{caseId}/user_actions/_find) (Cases API, find activity).
  • All attached alerts (GET /api/cases/{caseId}/alerts then fetch documents from .alerts-security.alerts-*) (alert schema).
  • The rule object before and after edits (GET/PUT /api/detection_engine/rules) and an NDJSON export of the rule plus exceptions (POST /api/detection_engine/rules/_export) (rule read/update, update, export).
  • Kibana and ES audit logs covering the change window, stored as JSON with timestamps and users (Kibana audit, ES audit).

Tools

Takeaways

  • Put a repeatable “tuning request” path into Cases with custom fields and attach the exact alerts that justify the change (custom fields, attach alerts).
  • Query Cases/attachments and .alerts-security.alerts-* with ES|QL to quantify noise and prove post-change impact; use kibana.alert.rule.revision to confirm you’re evaluating the tuned rule (alert schema, ES|QL).
  • Capture provenance: export Case + user actions, rule object(s), exceptions, and Kibana/ES audit logs for an evidence-grade record of who approved what and when (Cases API, audit logging).

Sources / References