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.
|
||||
Reference in New Issue
Block a user