From 8dd10ed81cc5d35b0655ed75d77ed2d26ddc7fd5 Mon Sep 17 00:00:00 2001 From: Malin Date: Sat, 22 Aug 2026 14:14:17 +0200 Subject: [PATCH] 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). --- skills/wazuh-soc-alert-triage/SKILL.md | 188 ++++++++++++++++++ .../wazuh-soc-alert-triage/agents/openai.yaml | 4 + 2 files changed, 192 insertions(+) create mode 100644 skills/wazuh-soc-alert-triage/SKILL.md create mode 100644 skills/wazuh-soc-alert-triage/agents/openai.yaml diff --git a/skills/wazuh-soc-alert-triage/SKILL.md b/skills/wazuh-soc-alert-triage/SKILL.md new file mode 100644 index 0000000..11c6014 --- /dev/null +++ b/skills/wazuh-soc-alert-triage/SKILL.md @@ -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. diff --git a/skills/wazuh-soc-alert-triage/agents/openai.yaml b/skills/wazuh-soc-alert-triage/agents/openai.yaml new file mode 100644 index 0000000..d057775 --- /dev/null +++ b/skills/wazuh-soc-alert-triage/agents/openai.yaml @@ -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."