Generated banner for Security Alert Analysis
Generated logo for Security Alert Analysis

Security Alert Analysis

ElasticOfficialCreated by elastic

  • Skill
  • Workflow
  • Security
  • Apache-2.0
  • No issues found

From the author

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.
— the description by elastic

AutoGineer summary

Written by AutoGineer from the skill’s own files, not by the author

This skill provides a rigorous, evidence-based process for triaging Elastic Security alerts. It guides the user through gathering context, checking for related activity, assessing entity risk, and determining a final disposition (True Positive, Benign, False Positive, or Unknown). By enforcing a strict methodology that prioritizes corroborating evidence over alert severity or rule names, it helps SOC analysts reduce noise and focus on genuine threats while maintaining consistent documentation.

What it does

  • Retrieves and filters unacknowledged security alerts from Elastic.
  • Identifies related alerts on the same agent or user to group incidents.
  • Performs focused context gathering on process trees and network activity.
  • Evaluates entity risk scores and asset criticality to prioritize investigations.
  • Provides a classification framework to categorize alerts based on evidence.
  • Supports safe, irreversible alert acknowledgement via the Detection Engine API.

When to use it

  • When triaging a single known security alert.
  • During SOC investigations to determine if an alert is malicious or benign.
  • When following up on alert groups identified by other triage processes.
  • When you need to document findings and justify a security disposition.

Advantages

  • Reduces premature classification by requiring comprehensive context gathering.
  • Standardizes the investigation process across different analysts.
  • Minimizes false positives by checking rule frequency and environment context.
  • Ensures safe acknowledgement by requiring a count preview before execution.
  • Uses the official CLI for consistent and reliable data retrieval.

Usage examples

“Fetch the next unacknowledged alert and triage it.”
The agent retrieves the oldest unacknowledged alert, gathers related context, and presents the findings for classification.
“Investigate alert ID abc-123 — gather context, classify, and create a case if malicious.”
The agent performs a deep dive on the specific alert, assesses the risk, and prepares a summary for case creation.
“Triage the alert group on host WIN-SRV01 from 2025-09-14.”
The agent identifies all related alerts for the specified host and time, providing a consolidated view for triage.

Install

  1. Download the skill as a ZIP:

    https://autogineer.com/agent-skills/elastic/security-alert-analysis/download
  2. Unzip it into the cross-client skills folder of your project:

    mkdir -p .agents/skills && unzip security-alert-analysis.zip -d .agents/skills

Documentation by elastic

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 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 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 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.

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 typeIndex pattern
Alerts.alerts-security.alerts-*
Processeslogs-endpoint.events.process-*
Networklogs-endpoint.events.network-*
Logslogs-*

Substeps to complete before classifying:

  • (a) Related alerts on the same agent or user (Step 2)

  • (b) Rule frequency across the environment — high frequency is false-positive-prone

  • (c) Process tree and parent-child relationships

  • (d) Network activity: DNS, connections, lateral movement indicators

  • (e) Behavioral investigation: persistence, C2, lateral movement, credential access

Data needed: enough corroborating evidence to justify a classification, or a clear finding that evidence is insufficient (→ classify unknown).

Step 4 — Assess entity risk

Before querying Entity Analytics, preflight each index with GET /_resolve/index/{pattern}. If an index is absent, skip that lookup and continue.

Check the Risk Engine and asset criticality for the involved hosts and users with POST /_query:

FROM risk-score.risk-score-latest-*
| WHERE host.name IN ("<host>") OR user.name IN ("<user>")
| KEEP host.name, host.risk.calculated_level, host.risk.calculated_score_norm,
       user.name, user.risk.calculated_level, user.risk.calculated_score_norm
| LIMIT 10
FROM .asset-criticality.asset-criticality-*
| WHERE (id_field == "host.name" AND id_value IN ("<host>"))
     OR (id_field == "user.name" AND id_value IN ("<user>"))
| KEEP id_field, id_value, criticality_level
| LIMIT 10

High entity risk scores (normalized >80) or extreme_impact / high_impact criticality on an involved entity are strong prioritization signals. Skip the lookups for any index the preflight reports as absent.

Data needed: entity risk level and asset criticality for the primary host or user.

Step 5 — Determine disposition

Only after all context is gathered, decide one of:

  • True Positive — strong corroborating evidence (persistence plus C2, credential theft, lateral movement, known malware hash). Escalate and recommend containment.

  • Benign True Positive — the alert is technically correct but the activity is known-good (for example, an IT admin running PSExec). Create an exception to reduce noise.

  • False Positive — the rule needs tuning to avoid this class of alerts.

  • Unknown — insufficient evidence. This is an acceptable and often correct outcome. Document what was found and what is missing.

Use the evidence-weighting criteria in references/classification-guide.md to support the disposition call.

Summarize findings for case documentation:

  • 1–2 sentence summary

  • Attack chain (what happened and in what order)

  • IOCs: hashes, IPs, file paths

  • MITRE techniques observed

  • Behavioral findings

  • Response context: remediation steps, credentials at risk

For case creation and alert attachment, use the kibana-cases skill (the canonical cross-solution cases skill). Name the case-management operation you need.

Data needed: classification and evidence summary for documentation.

Before acknowledging, preview the exact scope: run POST /{index}/_count with the same match criteria (agent ID, host, rule name, and time window) to confirm the count. Report the count and confirm with the analyst before writing. If the count exceeds 10,000, acknowledge in batches.

To acknowledge, collect matching alert _ids with POST /.alerts-security.alerts-*/_search (use _source: false and size: 10000), then set their workflow status with POST kbn:/api/detection_engine/signals/status (see the Operations table for the CLI equivalent). Pass the alert IDs and target status in the request body:

{ "signal_ids": ["<id1>", "<id2>"], "status": "acknowledged" }

Use the Detection Engine API rather than writing to the alert index directly — direct writes are rejected on Serverless. Widen the time window for longer attack chains. Report the exact number acknowledged from the response. There is no undo for an acknowledgement — confirm scope first.

Guidelines

  • Do not classify prematurely. All five substeps in Step 3 must complete before any opinion is formed.

  • Report only tool output. Do not invent IDs, hostnames, IPs, or details not in the tool response.

  • Preserve identifiers. Use exact values the analyst provides; copy _ids, timestamps, and hostnames verbatim.

  • Distinguish facts from inference. Label conclusions beyond tool output explicitly as your assessment.

  • Keep context gathering focused. Run 2–4 targeted queries per alert group, not 10+. Use KEEP to limit columns.

  • Acknowledgement is irreversible. Always preview with a count and prefer a narrow, well-scoped match. Pass the count to the analyst and wait for confirmation before writing.

  • Absolute timestamps only. Extract @timestamp from the alert and build all queries around it. Never use NOW() - 1 HOUR or other relative expressions on old alerts.

Examples

  • "Fetch the next unacknowledged alert and triage it."

  • "Investigate alert ID abc-123 — gather context, classify, and create a case if malicious."

  • "Process the top 5 critical alerts from the last 24 hours."

  • "Triage the alert group on host WIN-SRV01 from 2025-09-14."

References

Operations

HTTP API (shorthand)elastic CLI command
POST /.alerts-security.alerts-*/_searchelastic es search --index '.alerts-security.alerts-*' --input-file '<query.json>'
POST /{index}/_searchelastic es search --index '<index>' --input-file '<query.json>'
POST /{index}/_countelastic es count --index '<index>' --input-file '<query.json>'
POST /_queryelastic es esql query --format tsv --query '<esql>'
GET /_resolve/index/{pattern}elastic es indices resolve-index --name '<pattern>'
POST kbn:/api/detection_engine/signals/statuselastic kb security-detections-api set-alerts-status --signal-ids '<ids>' --status 'acknowledged'

Files

references/classification-guide.md

Alert Classification Guide

Detailed criteria for classifying alerts as benign, unknown, or malicious.

Contents

  • Fundamental principle

  • Pre-classification checklist

  • Classification: Benign

  • Classification: Unknown

  • Classification: Malicious

  • Behavioral weight table

  • Common false positive sources

  • Sandbox and testing environments

Fundamental principle

Most alerts are false positives. Your job is to find EVIDENCE, not to confirm suspicions. When in doubt, classify as "unknown" -- this is better than a wrong malicious classification that wastes IR resources, or a wrong benign classification that misses a threat.

Pre-classification checklist

Before making ANY classification, confirm you have:

  • [ ] Searched for related alerts on the same agent/user

  • [ ] Checked rule frequency across the environment

  • [ ] Investigated process tree and parent-child relationships

  • [ ] Reviewed network activity (DNS, connections, lateral movement)

  • [ ] Checked for persistence mechanisms (registry, scheduled tasks, services)

  • [ ] Looked for defense evasion behaviors

  • [ ] Verified code signing status of executables involved

  • [ ] Identified environment context (production vs sandbox/test)

  • [ ] Considered if this matches a known false positive pattern

If you cannot check most of the above, either gather more context or classify as "unknown."

Classification: Benign (score 0-19)

Confirmed false positive or legitimate activity.

Use when you have positive evidence of legitimacy:

  • Recognized enterprise software performing expected functions

  • Known IT management/deployment activity (SCCM, Group Policy, Intune)

  • Security testing with clear test environment indicators

  • User-initiated installation of legitimate software

  • Rule known to have high FP rate for this specific scenario

  • No malicious behaviors observed (no persistence, no C2, no credential theft)

Examples:

  • SCCM pushing software update via PowerShell

  • User installing Discord (large Electron app) from official source

  • Atomic Red Team test in designated testing environment

  • IT admin using PSExec for legitimate remote management

Classification: Unknown (score 20-60)

Insufficient information to determine. Needs further investigation.

Use when:

  • Suspicious indicators BUT lack corroborating evidence of malicious INTENT

  • Activity COULD be malicious OR legitimate, and you can't tell which

  • Need more context that isn't available in the current data

  • First time seeing this pattern with no baseline

Examples:

  • Unsigned installer running from Temp folder, but no C2/persistence observed

  • PowerShell script with obfuscation, but no malicious payload identified

  • Process injection APIs used, but target is a child process it spawned itself

  • Large binary with WriteProcessMemory, but appears to be Electron/Node.js app

Classification: Malicious (score 61-100)

Confirmed or highly suspected malicious activity.

Requires at least ONE high-confidence indicator:

  • Confirmed C2 communication (beaconing to known bad IP/domain)

  • Persistence mechanisms established (registry Run keys, scheduled tasks, services)

  • Credential theft (LSASS access, credential file access, keylogging)

  • Lateral movement (RDP/SMB/WinRM to other internal hosts)

  • Active defense evasion (disabling AV, clearing logs, timestomping)

  • Known malware hash match

  • Data exfiltration observed

NOT sufficient alone (these require corroboration):

  • Unsigned binary (many legitimate apps are unsigned)

  • Large file size (Electron apps are routinely 100MB+)

  • Running from Temp folder (installers commonly do this)

  • WriteProcessMemory API (used by legitimate apps for child process creation)

  • VirtualAlloc RWX (used by JIT compilers in .NET, Java, Node.js)

  • Alert severity is "critical" (severity is rule author's opinion, not evidence)

  • Rule name contains "Malicious" (rule names are often sensationalized)

Behavioral weight table

Strong indicators (can support MALICIOUS)
BehaviorScore range
Persistence + C2 together75+
Credential access (actual LSASS memory read)80+
Confirmed C2 beaconing to known-bad infrastructure75+
Lateral movement (connections to other internal hosts)75+
Active AV/EDR disabling80+
Known malware hash match90+
Weak indicators (alone = UNKNOWN)
BehaviorScore range
Process injection APIs without confirmed malicious target35-50
Binary padding / large file alone25-40
WriteProcessMemory to own child process20-30
VirtualAlloc RWX20-35
Unsigned executable25-40
Running from Temp/AppData25-40
PowerShell execution20-35
Network connection alone (without C2 indicators)30-45

Rule: Single suspicious behaviors without corroborating evidence = UNKNOWN, not MALICIOUS.

Common false positive sources

Enterprise management tools

Legitimate IT management often looks suspicious. Examples: SCCM/MECM, Group Policy, Intune/MDM, Ansible/Puppet/Chef, remote monitoring tools (ConnectWise, Datto, NinjaRMM).

Legitimacy indicators: Parent process is a known management agent; activity correlates with IT maintenance windows; same activity seen across many managed endpoints.

Security software

Security tools use techniques that look like malware. Examples: DLP agents, EDR agents themselves, vulnerability scanners, password managers, PAM tools.

Legitimacy indicators: Signed by known security vendor; running from Program Files with proper installation; part of approved security stack.

Software protection and DRM

Copy protection uses evasive techniques by design. Examples: Denuvo, VMProtect, Themida, game anti-cheat (EasyAntiCheat, BattlEye, Vanguard), license enforcement.

Legitimacy indicators: Associated with known commercial software; no network C2 activity; no persistence beyond the protected application.

Large application frameworks

Modern apps are often large and spawn many processes. Examples: Electron apps (Slack, Discord, VS Code, Teams at 100MB+), Node.js apps, game launchers, IDEs.

Legitimacy indicators: User intentionally installed; from known vendor; process tree shows normal application behavior.

Security testing

Intentional tests trigger real alerts. Examples: Atomic Red Team, Caldera, penetration testing tools, phishing simulations, malware detonation sandboxes.

Legitimacy indicators: Running in designated test environment; parent process is test harness; policy name includes "test", "detonate", "simulation".

Sandbox and testing environments

How to identify
  • Policy names containing "detonate", "sandbox", "test", "simulation"

  • Parent process patterns like "detonate.py", "sandbox.exe"

  • data_stream.namespace values like "benign", "test", "simulation"

  • Hostnames matching "sandbox-", "detonation-", "test-*"

Classification rules for sandboxes

Apply the SAME evidence standards as production:

  1. MALICIOUS requires strong evidence: actual C2, persistence created, credentials stolen

  2. UNKNOWN when behavior is suspicious but lacks corroborating evidence

  3. BENIGN when no malicious indicators observed

  4. Document the sandbox context in case notes

Being in a sandbox does NOT mean everything detonated is malicious. Many samples are benign/grayware. Suspicious-looking behavior without outcomes is not malicious.

Requirements and compatibility

Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta

“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.

The author says: 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.

Security

No issues found by our static scan· No issues found

A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.

Attribution and licence

Created by
elastic
Publisher
Elastic (Official)
Source
elastic/agent-skills · skills/security/alert-analysis · commit 09d879d
Licence
Apache License 2.0 (redistribution allowed)
  • LICENSE (added by AutoGineer from LICENSE)
  • ATTRIBUTION.md (written by AutoGineer)
Synced
Also distributed in
elastic/agent-skills

AutoGineer is not affiliated with or endorsed by elastic or Elastic.

Download ZIP

The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download security-alert-analysis.zip