> Triage Elastic Security alerts — gather context, classify threats, create cases, and acknowledge. Use when triaging alerts, performing SOC analysis, or investigating detections.
npx skills add https://github.com/elastic/agent-skills --skill security-alert-triage
Analyze Elastic Security alerts one at a time: gather context, classify, create a case, and acknowledge. This skill
depends on the case-management skill for case creation.
Install dependencies before first use from the skills/security directory:
cd skills/security && npm install
Set the required environment variables (or add them to a .env file in the workspace root):
export ELASTICSEARCH_URL="https://your-cluster.es.cloud.example.com:443"
export ELASTICSEARCH_API_KEY="your-api-key"
export KIBANA_URL="https://your-cluster.kb.cloud.example.com:443"
export KIBANA_API_KEY="your-kibana-api-key"
All commands from workspace root. Always fetch → investigate → document → acknowledge. Call the tools directly — do not
read the skill file or explore the workspace first.
node skills/security/alert-triage/scripts/fetch-next-alert.js
node skills/security/case-management/scripts/case-manager.js find --tags "agent_id:<id>"
node skills/security/alert-triage/scripts/run-query.js --query-file query.esql --type esql
node skills/security/case-management/scripts/case-manager.js create --title "..." --description "..." --tags "classification:..." "agent_id:<id>" --severity <level> --yes
node skills/security/case-management/scripts/case-manager.js attach-alert --case-id <id> --alert-id <id> --alert-index <index> --rule-id <uuid> --rule-name "<name>" --yes
node skills/security/alert-triage/scripts/acknowledge-alert.js --related --agent <id> --timestamp <ts> --window 60 --yes
| Task | Tools to call (in order) |
| ------------------------------------ | ----------------------------------------------------------------------------------------------- |
| End-to-end triage | fetch_next_alert → run_query (context) → case_manager create (case) → acknowledge_alert |
| Gather context | run_query (process tree, network, related alerts) |
| Create case after classification | case_manager create → case_manager attach-alert |
| Acknowledge after triage | acknowledge_alert (related mode for batch) |
Always complete the full workflow: fetch → investigate → document → acknowledge. Do not stop after gathering context —
create or update a case with findings before acknowledging.
Critical execution rules:
.esql file then pass it via --query-file. Do not use edit_file— use a single shell call with echo "..." > query.esql && node ... --query-file query.esql.
"critical" are NOT evidence.
suspicious API calls.
round numbers, abbreviate IDs, or paraphrase error messages.
When triaging multiple alerts, group first, then triage each group:
- [ ] Step 0: Group alerts by agent/host and time window
- [ ] Step 1: Check existing cases
- [ ] Step 2: Gather full context (DO NOT SKIP)
- [ ] Step 3: Create or update case (only AFTER context gathered)
- [ ] Step 4: Acknowledge alert and all related alerts
- [ ] Step 5: Fetch next alert group and repeat
When the user asks about multiple open alerts, group them first to avoid redundant investigation: query open alerts,
group by agent.id, sub-group by time window (~5 min = likely one incident), triage each group as a single unit.
Use ES|QL for an overview (write to file first for PowerShell):
FROM .alerts-security.alerts-*
| WHERE kibana.alert.workflow_status == "open" AND @timestamp >= "<start>"
| STATS alert_count=COUNT(*), rules=VALUES(kibana.alert.rule.name) BY agent.id
| SORT alert_count DESC
For full query templates, see references/classification-guide.md.
Before creating a new case, check if this alert belongs to an existing one. Use the case-management skill:
node skills/security/case-management/scripts/case-manager.js find --tags "agent_id:<agent_id>"
node skills/security/case-management/scripts/case-manager.js cases-for-alert --alert-id <alert_id>
Look for cases with the same agent ID, user, or related detection rule within a similar time window.
> Note: find --search may return 500 errors on Serverless. Use find --tags or list instead.
This is the most important step. Do not skip or shortcut it. Complete ALL substeps before forming any classification
opinion.
Time range warning: Alerts may be days or weeks old. NEVER use relative time like NOW() - 1 HOUR. Extract the
alert's @timestamp and build queries around that time with +/- 1 hour window.
Substeps: (2a) Related alerts on same agent/user; (2b) Rule frequency across env (high = FP-prone); (2c) Entity
context — process tree, network, registry, files; (2d) Behavior investigation — persistence, C2, lateral movement,
credential access.
Example — process tree (use ES|QL with KEEP; avoid --full which produces 10K+ lines):
FROM logs-endpoint.events.process-*
| WHERE agent.id == "<agent_id>" AND @timestamp >= "<alert_time - 5min>" AND @timestamp <= "<alert_time + 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 | LIMIT 80
| Data type | Index pattern |
| --------- | -------------------------------- |
| Alerts | .alerts-security.alerts-* |
| Processes | logs-endpoint.events.process-* |
| Network | logs-endpoint.events.network-* |
| Logs | logs-* |
For full query templates and classification criteria, see
references/classification-guide.md.
After gathering context, create a case and attach alert(s). Use --rule-id and --rule-name (required; 400 error
without them):
node skills/security/case-management/scripts/case-manager.js create \
--title "<concise summary>" \
--description "<findings, IOCs, attack chain, MITRE techniques>" \
--tags "classification:<benign|unknown|malicious>" "confidence:<0-100>" "mitre:<technique>" "agent_id:<id>" \
--severity <low|medium|high|critical>
node skills/security/case-management/scripts/case-manager.js attach-alert \
--case-id <case_id> --alert-id <alert_id> --alert-index <index> \
--rule-id <rule_uuid> --rule-name "<rule name>"
# Multiple alerts: attach-alerts --alert-ids <id1> <id2>
# Add notes: add-comment --case-id <id> --comment "Findings..."
Case description: Summary (1-2 sentences); Attack chain; IOCs (hashes, IPs, paths); MITRE techniques; Behavioral
findings; Response context (remediation, credentials at risk).
Acknowledge ALL related alerts together. Use --dry-run first to confirm scope, then run without it:
# By host name — preferred when triaging a host
node skills/security/alert-triage/scripts/acknowledge-alert.js --query --host <hostname> --dry-run
node skills/security/alert-triage/scripts/acknowledge-alert.js --query --host <hostname> --yes
# By agent ID — preferred when agent.id is known
node skills/security/alert-triage/scripts/acknowledge-alert.js --related --agent <id> --timestamp <ts> --window 60 --dry-run
node skills/security/alert-triage/scripts/acknowledge-alert.js --related --agent <id> --timestamp <ts> --window 60 --yes
Increase --window for longer attack chains (e.g., 300 for 5 minutes). Report the exact count of acknowledged alerts
from the tool output. Pass --yes to skip the confirmation prompt (required when called by an agent).
node skills/security/alert-triage/scripts/fetch-next-alert.js
Fetches the oldest unacknowledged Elastic Security alert.
node skills/security/alert-triage/scripts/fetch-next-alert.js [--days <n>] [--json] [--full] [--verbose]
Runs KQL or ES|QL queries against Elasticsearch.
PowerShell warning: ES|QL queries contain pipe characters (|) which PowerShell interprets as shell pipes. ALWAYS
use --query-file for ES|QL:
# Write query to file, then run
node skills/security/alert-triage/scripts/run-query.js --query-file query.esql --type esql
KQL queries without pipes can be passed directly:
node skills/security/alert-triage/scripts/run-query.js "agent.id:<id>" --index "logs-*" --days 7
| Arg | Description |
| -------------------- | -------------------------------------------------------- |
| query | KQL query (positional) |
| --query-file, -q | Read query from file (required for ES\|QL on PowerShell) |
| --type, -t | kql or esql (default: kql) |
| --index, -i | Index pattern (default: logs-*) |
| --size, -s | Max results (default: 100) |
| --days, -d | Limit to last N days |
| --json | Raw JSON output |
| --full | Full document source |
Acknowledges alerts by updating workflow_status to acknowledged.
| Mode | Command |
| ------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| Single | node skills/security/alert-triage/scripts/acknowledge-alert.js <alert_id> --index <index> --yes |
| Related | node skills/security/alert-triage/scripts/acknowledge-alert.js --related --agent <id> --timestamp <ts> [--window 60] --yes |
| By host | node skills/security/alert-triage/scripts/acknowledge-alert.js --query --host <hostname> [--time-start <ts>] [--time-end <ts>] --yes |
| Query | node skills/security/alert-triage/scripts/acknowledge-alert.js --query --agent <id> [--time-start <ts>] [--time-end <ts>] --yes |
| Dry run | Add --dry-run to any mode (no confirmation needed) |
| Confirm | All write modes prompt for confirmation; pass --yes to skip |
acknowledge-alert.js) prompt for confirmation. Pass --yes or -y to skip when called by anagent.
--dry-run before bulk acknowledgments to preview scope without modifying data.deployments.
| Variable | Required | Description |
| ----------------------- | -------- | ------------------------------------ |
| ELASTICSEARCH_URL | Yes | Elasticsearch URL |
| ELASTICSEARCH_API_KEY | Yes | Elasticsearch API key |
| KIBANA_URL | Yes | Kibana URL (for case management) |
| KIBANA_API_KEY | Yes | Kibana API key (for case management) |
Expert in secure backend coding practices specializing in input validation, authentication, and API security. Use PROACTIVELY for backend security implementations or security code reviews.
This skill should be used when the user asks to "perform cloud penetration testing", "assess Azure or AWS or GCP security", "enumerate cloud resources", "exploit cloud misconfigurations", "test O365 security", "extract secrets from cloud environments", or "audit cloud infrastructure". It provides comprehensive techniques for security assessment across major cloud platforms.
You are a dependency security expert specializing in vulnerability scanning, license compliance, and supply chain security. Analyze project dependencies for known vulnerabilities, licensing issues, outdated packages, and provide actionable remediation strategies.
Comprehensive Flow Nexus platform management - authentication, sandboxes, app deployment, payments, and challenges
This skill should be used when the user asks to "escalate privileges on Linux", "find privesc vectors on Linux systems", "exploit sudo misconfigurations", "abuse SUID binaries", "exploit cron jobs for root access", "enumerate Linux systems for privilege escalation", or "gain root access from low-privilege shell". It provides comprehensive techniques for identifying and exploiting privilege escalation paths on Linux systems.
Expert malware analyst specializing in defensive malware research, threat intelligence, and incident response. Masters sandbox analysis, behavioral analysis, and malware family identification. Handles static/dynamic analysis, unpacking, and IOC extraction. Use PROACTIVELY for malware triage, threat hunting, incident response, or security research.
This skill should be used when the user asks to "use Metasploit for penetration testing", "exploit vulnerabilities with msfconsole", "create payloads with msfvenom", "perform post-exploitation", "use auxiliary modules for scanning", or "develop custom exploits". It provides comprehensive guidance for leveraging the Metasploit Framework in security assessments.
Expert in secure mobile coding practices specializing in input validation, WebView security, and mobile-specific security patterns. Use PROACTIVELY for mobile security implementations or mobile security code reviews.
Take elastic/security-alert-triage from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.
The instructions reference npm.
Without those the skill loads but fails at the first command.