skill: add wazuh-soc-alert-triage
Codex-evaluated agentic-soc-platform (github.com/FunnyWolf/agentic-soc-platform) against this fleet's Wazuh deployment and informatiq-dashboard monitoring integration. Adopted the reusable architecture only (evidence-preserving normalization, deterministic correlation, approval-gated playbooks, shadow-mode rollout) - not the platform itself. Rejected BagelHole/DevOps- Security-Agent-Skills (163 skills, all duplicate/out-of-scope/unsafe) and guillaumemeyer/watermarks-remover (narrow, no reusable technique beyond existing c2patool/ExifTool).
This commit is contained in:
@@ -0,0 +1,188 @@
|
|||||||
|
---
|
||||||
|
name: wazuh-soc-alert-triage
|
||||||
|
description: Use when designing, implementing, reviewing, or operating a Wazuh alert-to-case triage pipeline or guarded SOC automation for this fleet—ingesting alert events, suppressing noise, correlating cases, enriching from fleet data sources, adding evidence-bound LLM analysis, or executing approval-gated response playbooks. Covers queue reliability, idempotency, auditability, rollout, and the boundary between the existing InformatiQ status dashboard and a real SOC workflow.
|
||||||
|
---
|
||||||
|
|
||||||
|
# Wazuh SOC Alert Triage
|
||||||
|
|
||||||
|
Build an evidence-preserving pipeline, not an autonomous incident responder.
|
||||||
|
Provenance: adapted from
|
||||||
|
[`FunnyWolf/agentic-soc-platform`](https://github.com/FunnyWolf/agentic-soc-platform)
|
||||||
|
at commit `be3e9b48a5f32069df9f0eeb6175b5ec5443fb69`, reviewed 2026-08-22.
|
||||||
|
The source's reusable patterns are typed alert normalization, deterministic
|
||||||
|
correlation, transactional case creation, queued analysis, structured LLM
|
||||||
|
output, and risk-labelled playbooks. This skill does not adopt its full Django
|
||||||
|
platform, ELK/Splunk assumptions, automatic analysis on every alert, or Redis
|
||||||
|
`NOACK` delivery behavior.
|
||||||
|
|
||||||
|
## Respect the current fleet boundary
|
||||||
|
|
||||||
|
The existing `informatiq-dashboard` is a read-only status board. Its Wazuh
|
||||||
|
integration authenticates to the manager API and polls agent status plus
|
||||||
|
manager-level event/alert counts. It does not ingest individual alerts, own
|
||||||
|
cases, or execute remediation.
|
||||||
|
|
||||||
|
Before changing it:
|
||||||
|
|
||||||
|
1. Read the current `informatiq-dashboard` source and relevant
|
||||||
|
`/home/malin/granja/docs/server-*.md`; do not infer capabilities from UI
|
||||||
|
labels.
|
||||||
|
2. Identify the authoritative event source. Manager summary endpoints are
|
||||||
|
suitable for health widgets, not alert triage. Use an authorized event
|
||||||
|
stream/index/query surface that returns individual Wazuh alert records.
|
||||||
|
3. Keep case state and automation out of the status dashboard unless there is
|
||||||
|
an explicit decision to turn that application into a stateful SOC system.
|
||||||
|
4. Treat Kuma, PowerDNS, Pi-hole, Proxmox/PBS/PMG, proxy, honeypot, bot, and WAF
|
||||||
|
data as bounded enrichment. A failed enrichment must not erase or block the
|
||||||
|
original alert.
|
||||||
|
5. Store credentials outside source. Validate the real certificate chain where
|
||||||
|
possible; never copy the dashboard's process-wide TLS-verification disable
|
||||||
|
into an internet-facing or action-capable service.
|
||||||
|
|
||||||
|
## Define the alert contract first
|
||||||
|
|
||||||
|
Store the immutable raw event separately from normalized fields. Require:
|
||||||
|
|
||||||
|
- source system, source event ID, rule ID/name, event time, ingest time, and
|
||||||
|
schema/parser version;
|
||||||
|
- affected asset and actor identifiers with explicit types;
|
||||||
|
- severity, confidence, action/outcome, tactics/techniques, and labels;
|
||||||
|
- raw payload hash plus a protected reference to the raw payload;
|
||||||
|
- normalization warnings and unmapped fields rather than silently dropping
|
||||||
|
unknown data.
|
||||||
|
|
||||||
|
Parse timestamps defensively. Preserve the original value and record a parse
|
||||||
|
error when falling back to ingest time. Redact secrets from operator-visible
|
||||||
|
messages, but retain authorized forensic evidence in access-controlled storage.
|
||||||
|
|
||||||
|
Version normalizers and replay captured fixtures before deployment. A plausible
|
||||||
|
normalized record is not proof that nested Wazuh fields mapped correctly.
|
||||||
|
|
||||||
|
## Separate deterministic stages
|
||||||
|
|
||||||
|
Use this flow:
|
||||||
|
|
||||||
|
```text
|
||||||
|
individual alert -> validate/normalize -> suppress/routable decision
|
||||||
|
-> correlate/idempotently attach to case -> bounded enrichment
|
||||||
|
-> evidence-bound analysis -> human decision -> guarded playbook
|
||||||
|
```
|
||||||
|
|
||||||
|
Keep every transition observable and replayable. Do not let an LLM decide
|
||||||
|
whether an event is accepted, deduplicated, or attached to an existing case.
|
||||||
|
|
||||||
|
### Suppress and route before analysis
|
||||||
|
|
||||||
|
- Start with rule allowlists, minimum severities, maintenance windows, known
|
||||||
|
scanners, service accounts, and exact fleet-specific exclusions.
|
||||||
|
- Record the rule and reason for every suppressed event. Retain counts and a
|
||||||
|
sampled audit trail so an overbroad rule is visible.
|
||||||
|
- Rate-limit repeated noise without discarding the first and last event,
|
||||||
|
occurrence count, or time span.
|
||||||
|
- Keep detection disposition separate from response action: observed, denied,
|
||||||
|
and successful malicious actions require different urgency.
|
||||||
|
|
||||||
|
### Correlate without merging unrelated incidents
|
||||||
|
|
||||||
|
Build a versioned correlation key from the rule family plus stable typed
|
||||||
|
identifiers such as host, account, user, source IP, process, or destination.
|
||||||
|
Add a documented time window only after choosing the identifiers.
|
||||||
|
|
||||||
|
Do not use a time bucket alone. It merges unrelated alerts and splits an event
|
||||||
|
at bucket boundaries. Prefer a database uniqueness constraint on source event
|
||||||
|
ID for ingestion and an atomic lock/upsert on correlation key for case
|
||||||
|
attachment. Store the correlation algorithm version so cases can be explained
|
||||||
|
after rules change.
|
||||||
|
|
||||||
|
## Make delivery at-least-once and processing idempotent
|
||||||
|
|
||||||
|
For each queue consumer:
|
||||||
|
|
||||||
|
1. Claim a message without acknowledging it.
|
||||||
|
2. Validate and process inside a transaction.
|
||||||
|
3. Commit the alert, case link, artifacts, and scheduled follow-up job.
|
||||||
|
4. Acknowledge only after commit.
|
||||||
|
5. Retry transient failures with a bound; send poison messages to a dead-letter
|
||||||
|
queue with sanitized error metadata.
|
||||||
|
|
||||||
|
Use a stable idempotency key at every side-effect boundary. Recover jobs left
|
||||||
|
`running` after a worker restart by lease expiry or explicit startup recovery;
|
||||||
|
do not leave them permanently running or blindly rerun non-idempotent actions.
|
||||||
|
Expose queue depth, oldest age, retry/DLQ counts, worker heartbeat, last success,
|
||||||
|
failure rate, and processing latency.
|
||||||
|
|
||||||
|
## Enrich evidence, do not manufacture certainty
|
||||||
|
|
||||||
|
Run independent enrichments concurrently with per-source timeouts and cache
|
||||||
|
limits. Record provider, query, retrieval time, result, and error. Useful fleet
|
||||||
|
joins include asset identity/health, expected DNS role, proxy exposure, backup
|
||||||
|
state, and recent availability changes.
|
||||||
|
|
||||||
|
Never infer compromise merely because a related service is down or an IP
|
||||||
|
appears in a honeypot feed. Label enrichment as observation, inference, or
|
||||||
|
unknown, and preserve contradictory evidence.
|
||||||
|
|
||||||
|
## Constrain LLM analysis
|
||||||
|
|
||||||
|
Run analysis after deterministic case assembly, preferably on demand or after a
|
||||||
|
severity/noise gate. Require a typed result containing:
|
||||||
|
|
||||||
|
- verdict, severity, confidence, and a short digest;
|
||||||
|
- affected assets;
|
||||||
|
- evidence findings with source-field references;
|
||||||
|
- timeline and attack-chain hypotheses;
|
||||||
|
- indicators with context;
|
||||||
|
- recommended actions and explicit unknowns.
|
||||||
|
|
||||||
|
Make the model cite only supplied evidence. Reject invalid schemas and invented
|
||||||
|
identifiers. Store prompt/profile version, model identifier, generation time,
|
||||||
|
input evidence references, and output. Present model severity separately from
|
||||||
|
rule severity. LLM output may prioritize investigation; it must not authorize a
|
||||||
|
response action.
|
||||||
|
|
||||||
|
## Gate playbooks by effect, not by label
|
||||||
|
|
||||||
|
Classify each concrete step:
|
||||||
|
|
||||||
|
| Effect | Default gate |
|
||||||
|
|---|---|
|
||||||
|
| Query, summarize, collect read-only evidence | Automatic after validation |
|
||||||
|
| Notify or create an internal ticket | Automatic if deduplicated and rate-limited |
|
||||||
|
| Temporary narrow block or session revocation | Named human approval |
|
||||||
|
| Credential rotation, firewall/DNS changes, jail/container stop, deletion, restore | Explicit target-specific approval and rollback plan |
|
||||||
|
|
||||||
|
A `risk_level` field is metadata, not enforcement. Before execution, resolve
|
||||||
|
exact targets, show blast radius, require the applicable approval, capture the
|
||||||
|
requester/approver, and generate an idempotency key. Implement dry-run where the
|
||||||
|
underlying system supports it. Log sanitized progress messages and the final
|
||||||
|
verification result. Never feed credentials, authorization headers, or raw
|
||||||
|
secrets into progress logs or model context.
|
||||||
|
|
||||||
|
## Roll out in measured phases
|
||||||
|
|
||||||
|
1. Replay sanitized historical fixtures and assert normalization,
|
||||||
|
deduplication, correlation, and suppression outcomes.
|
||||||
|
2. Run shadow mode: ingest and build proposed cases without notifications or
|
||||||
|
actions.
|
||||||
|
3. Compare against a human-reviewed sample; measure false merges, duplicate
|
||||||
|
cases, missed high-severity alerts, and analyst correction rate.
|
||||||
|
4. Enable notifications with rate limits.
|
||||||
|
5. Add read-only enrichment and analysis.
|
||||||
|
6. Add one narrow, reversible playbook only after approval and rollback tests.
|
||||||
|
|
||||||
|
Define stop conditions before each phase. Verify the real end-to-end path from
|
||||||
|
Wazuh event to operator-visible case; a healthy manager API widget proves only
|
||||||
|
that summary polling works.
|
||||||
|
|
||||||
|
## Report decisions explicitly
|
||||||
|
|
||||||
|
For a design or review, state:
|
||||||
|
|
||||||
|
- authoritative event source and what was actually tested;
|
||||||
|
- accepted/suppressed rules and correlation-key version;
|
||||||
|
- delivery, retry, DLQ, and idempotency behavior;
|
||||||
|
- enrichment dependencies and failure behavior;
|
||||||
|
- LLM boundary and provenance fields;
|
||||||
|
- playbook approvals, blast radius, rollback, and verification;
|
||||||
|
- rollout phase, metrics, unresolved gaps, and the cleanup-script context if it
|
||||||
|
becomes available.
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
interface:
|
||||||
|
display_name: "Wazuh SOC Alert Triage"
|
||||||
|
short_description: "Build guarded Wazuh alert-to-case automation"
|
||||||
|
default_prompt: "Use $wazuh-soc-alert-triage to design a safe alert-to-case triage workflow for this Wazuh fleet."
|
||||||
Reference in New Issue
Block a user