Skip to content
Operations
Skill

/alert-analysis

Investigate a specific Elastic Security detection alert: gather context, assess entity risk, classify the threat, document findings, and optionally acknowledge. Use when triaging a single known alert, performing SOC investigation, or following up after the security-alert-triage

From plugin
elastic-agent-skills
60330 skills

Claude Code

$ npx -y skills add elastic/agent-skills --skill alert-analysis --agent claude-code

SKILL.md

alert-analysis.SKILL.md
name: security-alert-analysis
description: >
  Investigate a specific Elastic Security detection alert: gather context, assess
  entity risk, classify the threat, document findings, and optionally acknowledge.
  Use when triaging a single known alert, performing SOC investigation, or following
  up after the security-alert-triage skill identifies a group to investigate.
metadata:
  author: elastic
  version: 0.1.0
  universal: true
compatibility: Kibana 8.x or 9.x with matching Elasticsearch — self-managed, Elastic
  Cloud Hosted, or Elastic Cloud Serverless. Acknowledgement uses the Detection Engine
  API so it works on Serverless where direct writes to alert data streams are rejected.
  Requires the `elastic` CLI with `es` and `kb` support.

Alert Analysis

Investigate one Elastic Security alert (or one group of related alerts) end to end: gather context, classify the threat, document findings, and — after confirming scope with the analyst — acknowledge.

<!-- begin-partial: preamble -->

Environment Configuration

This skill executes Elasticsearch operations through the `elastic` CLI. If the [`elastic` CLI](https://github.com/elastic/cli#configuration) is not installed, tell the user what it is needed for. Do not guess credentials, call the HTTP API directly, or attempt other workarounds.

This skill references operations in HTTP-shorthand form (e.g., `GET /`, `GET /_cat/indices`, `GET /{index}/_mapping`, `GET /{index}/_settings/index.mode`, `POST /_query`). The [Operations](#operations) table at the end of this document maps each shorthand to the equivalent `elastic` CLI command — always use the CLI rather than calling the HTTP API directly.

<!-- end-partial: preamble -->

Critical principles

  • **Do not classify prematurely.** Gather ALL context before deciding benign, unknown, or malicious.
  • **Most alerts are false positives**, even when they look alarming. Rule names such as "Malicious Behavior" and

severity "critical" are NOT evidence.

  • **"Unknown" is an acceptable outcome** and is often the correct one when evidence is insufficient.
  • **Malicious requires strong corroborating evidence** — persistence plus C2, credential theft, or lateral movement —

not a single suspicious API call.

  • **Report tool output verbatim.** Copy IDs, hostnames, timestamps, and counts exactly as returned. Do not round

numbers, abbreviate IDs, or paraphrase error messages.

See [references/classification-guide.md](references/classification-guide.md) for detailed evidence-weighting criteria, the behavioral weight table, and common false positive sources.

Process

Step 1 — Fetch the alert

Retrieve the alert document with `POST /.alerts-security.alerts-*/_search`. Filter to `kibana.alert.workflow_status` not in (`acknowledged`, `closed`), sort by `@timestamp` ascending, and take `size: 1` for the oldest unacknowledged alert — or filter by `_id` when the analyst provides a specific alert.

Capture:

  • `_id`, `_index`, `@timestamp`
  • `agent.id`, `host.name`, `user.name`
  • `kibana.alert.rule.name`, `kibana.alert.rule.uuid`
  • `kibana.alert.reason`, `kibana.alert.severity`
  • `kibana.alert.rule.threat.tactic.name`, `kibana.alert.rule.threat.technique.name`
  • Key entity fields: `source.ip`, `destination.ip`, `file.hash.*`, `process.name`

Data needed: alert core fields and key entities to anchor the investigation.

Step 2 — Find related alerts

Before gathering entity context, check whether other alerts share the same agent, user, or time window. Run a `POST /_query` against `.alerts-security.alerts-*`:

FROM .alerts-security.alerts-* METADATA _id
| WHERE kibana.alert.workflow_status == "open"
    AND agent.id == "<agent_id>"
    AND @timestamp >= "<alert_timestamp - 2h>" AND @timestamp <= "<alert_timestamp + 2h>"
| KEEP _id, @timestamp, kibana.alert.rule.name, kibana.alert.severity, kibana.alert.workflow_status
| SORT @timestamp ASC
| LIMIT 50

Group related alerts by `agent.id` and a ~5-minute time window (one incident). Triage each group as a unit.

Also run a frequency check to assess false-positive risk:

FROM .alerts-security.alerts-*
| WHERE kibana.alert.rule.name == "<rule_name>"
    AND @timestamp >= NOW() - 7 days
| STATS alert_count = COUNT(*) BY kibana.alert.workflow_status

A very high rule frequency (hundreds of alerts per day) is a strong false-positive signal.

Data needed: related alerts on the same entity and an environment-wide frequency count for the triggering rule.

Step 3 — Gather entity context

**This is the most important step. Do not skip or shortcut it.** Complete all substeps before forming any classification opinion.

**Time-range rule:** alerts can be days or weeks old. NEVER use relative time such as `NOW() - 1 HOUR`. Extract the alert's `@timestamp` and anchor every context query with a roughly ±1 hour window around that timestamp.

Run 2–4 focused queries with `POST /_query` (not 10+). Use `KEEP` to limit columns and avoid dumping full documents.

**Process tree** — who spawned what:

FROM logs-endpoint.events.process-*
| WHERE agent.id == "<agent_id>"
    AND @timestamp >= "<alert_timestamp - 5min>"
    AND @timestamp <= "<alert_timestamp + 10min>"
    AND process.parent.name IS NOT NULL
    AND process.name NOT IN ("svchost.exe", "conhost.exe", "agentbeat.exe")
| KEEP @timestamp, process.name, process.command_line, process.pid,
       process.parent.name, process.parent.pid
| SORT @timestamp ASC
| LIMIT 80

**Network activity** — outbound connections, DNS:

FROM logs-endpoint.events.network-*
| WHERE agent.id == "<agent_id>"
    AND @timestamp >= "<alert_timestamp - 15min>"
    AND @timestamp <= "<alert_timestamp + 30min>"
| KEEP @timestamp, process.name, destination.ip, destination.port, dns.question.name
| SORT @timestamp ASC
| LIMIT 50

**Index pattern reference:**

| Data type | Index pattern | | --------- | -------------------------------- | | Alerts | `.alerts-sec

Read more
@elastic
Ships withelastic-agent-skills

Elastic Agent Skills — built by the people who built Elastic — deliver native platform expertise directly to your AI coding agent.

Stars on GitHub

Momentum

stars in total
603
Star history of elastic/agent-skills on GitHub, a chart by star-history.com

Other skills on elastic-agent-skills.

More skills from other plugins.

Questions about alert-analysis.

Which coding agents can use alert-analysis?
alert-analysis installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.